diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-clocks.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-clocks.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone-clocks.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-clocks.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Device Tree Source for Keystone 2 clock tree * - * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/ */ clocks { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone.dtsi b/arch/arm/boot/dts/ti/keystone/keystone.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/ */ #include diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2e-clocks.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2e-clocks.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone-k2e-clocks.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2e-clocks.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Keystone 2 Edison SoC specific device tree * - * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2014-2017 Texas Instruments Incorporated - https://www.ti.com/ */ clocks { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2e.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2e.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone-k2e.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2e.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Keystone 2 Edison soc device tree * - * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/ */ #include diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2e-evm.dts b/arch/arm/boot/dts/ti/keystone/keystone-k2e-evm.dts --- a/arch/arm/boot/dts/ti/keystone/keystone-k2e-evm.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2e-evm.dts 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Keystone 2 Edison EVM device tree * - * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/ */ /dts-v1/; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Device Tree Source for Keystone 2 Edison Netcp driver * - * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/ */ qmss: qmss@2a40000 { @@ -36,9 +36,9 @@ qpend { qpend-0 { qrange = <658 8>; - interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04 - 0 43 0xf04 0 44 0xf04 0 45 0xf04 - 0 46 0xf04 0 47 0xf04>; + interrupts = <0 40 0xf04 0 41 0xf04 0 42 0xf04 + 0 43 0xf04 0 44 0xf04 0 45 0xf04 + 0 46 0xf04 0 47 0xf04>; }; qpend-1 { qrange = <528 16>; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2g.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2g.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone-k2g.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2g.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Device Tree Source for K2G SOC * - * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2016-2017 Texas Instruments Incorporated - https://www.ti.com/ */ #include @@ -256,11 +256,6 @@ pmmc: system-controller@2921c00 { compatible = "ti,k2g-sci"; - /* - * In case of rare platforms that does not use k2g as - * system master, use /delete-property/ - */ - ti,system-reboot-controller; mbox-names = "rx", "tx"; mboxes = <&msgmgr 5 2>, <&msgmgr 0 0>; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts b/arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts --- a/arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts 2024-07-07 20:37:34.620306429 -0400 @@ -2,14 +2,14 @@ /* * Device Tree Source for K2G EVM * - * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2016-2017 Texas Instruments Incorporated - https://www.ti.com/ */ /dts-v1/; #include "keystone-k2g.dtsi" / { - compatible = "ti,k2g-evm", "ti,k2g", "ti,keystone"; + compatible = "ti,k2g-evm", "ti,k2g", "ti,keystone"; model = "Texas Instruments K2G General Purpose EVM"; memory@800000000 { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2g-ice.dts b/arch/arm/boot/dts/ti/keystone/keystone-k2g-ice.dts --- a/arch/arm/boot/dts/ti/keystone/keystone-k2g-ice.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2g-ice.dts 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Device Tree Source for K2G Industrial Communication Engine EVM * - * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/ */ /dts-v1/; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Device Tree Source for K2G Netcp driver * - * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ */ qmss: qmss@4020000 { @@ -37,9 +37,9 @@ qpend { qpend-0 { qrange = <77 8>; - interrupts =<0 308 0xf04 0 309 0xf04 0 310 0xf04 - 0 311 0xf04 0 312 0xf04 0 313 0xf04 - 0 314 0xf04 0 315 0xf04>; + interrupts = <0 308 0xf04 0 309 0xf04 0 310 0xf04 + 0 311 0xf04 0 312 0xf04 0 313 0xf04 + 0 314 0xf04 0 315 0xf04>; qalloc-by-id; }; }; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-clocks.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-clocks.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-clocks.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-clocks.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Keystone 2 Kepler/Hawking SoC clock nodes * - * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/ */ clocks { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2hk.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2hk.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone-k2hk.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2hk.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Keystone 2 Kepler/Hawking soc specific device tree * - * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/ */ #include diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts --- a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Keystone 2 Kepler/Hawking EVM device tree * - * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/ */ /dts-v1/; @@ -10,7 +10,7 @@ #include "keystone-k2hk.dtsi" / { - compatible = "ti,k2hk-evm", "ti,k2hk", "ti,keystone"; + compatible = "ti,k2hk-evm", "ti,k2hk", "ti,keystone"; model = "Texas Instruments Keystone 2 Kepler/Hawking EVM"; reserved-memory { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Device Tree Source for Keystone 2 Hawking Netcp driver * - * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/ */ qmss: qmss@2a40000 { @@ -49,9 +49,9 @@ qpend { qpend-0 { qrange = <658 8>; - interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04 - 0 43 0xf04 0 44 0xf04 0 45 0xf04 - 0 46 0xf04 0 47 0xf04>; + interrupts = <0 40 0xf04 0 41 0xf04 0 42 0xf04 + 0 43 0xf04 0 44 0xf04 0 45 0xf04 + 0 46 0xf04 0 47 0xf04>; }; qpend-1 { qrange = <8704 16>; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2l-clocks.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2l-clocks.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone-k2l-clocks.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2l-clocks.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Keystone 2 lamarr SoC clock nodes * - * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/ */ clocks { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2l.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2l.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone-k2l.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2l.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Keystone 2 Lamarr SoC specific device tree * - * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2014-2017 Texas Instruments Incorporated - https://www.ti.com/ */ #include diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2l-evm.dts b/arch/arm/boot/dts/ti/keystone/keystone-k2l-evm.dts --- a/arch/arm/boot/dts/ti/keystone/keystone-k2l-evm.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2l-evm.dts 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Keystone 2 Lamarr EVM device tree * - * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2014-2017 Texas Instruments Incorporated - https://www.ti.com/ */ /dts-v1/; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi --- a/arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -2,7 +2,7 @@ /* * Device Tree Source for Keystone 2 Lamarr Netcp driver * - * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/ */ qmss: qmss@2a40000 { @@ -36,9 +36,9 @@ qpend { qpend-0 { qrange = <658 8>; - interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04 - 0 43 0xf04 0 44 0xf04 0 45 0xf04 - 0 46 0xf04 0 47 0xf04>; + interrupts = <0 40 0xf04 0 41 0xf04 0 42 0xf04 + 0 43 0xf04 0 44 0xf04 0 45 0xf04 + 0 46 0xf04 0 47 0xf04>; }; qpend-1 { qrange = <528 16>; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-bbb-bone-buses.dtsi b/arch/arm/boot/dts/ti/omap/am335x-bbb-bone-buses.dtsi --- a/arch/arm/boot/dts/ti/omap/am335x-bbb-bone-buses.dtsi 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/am335x-bbb-bone-buses.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Deepak Khatri + * Copyright (C) 2021 Robert Nelson + * See Cape Interface Spec page for more info on Bone Buses + * https://elinux.org/Beagleboard:BeagleBone_cape_interface_spec + * https://docs.beagleboard.io/latest/boards/capes/cape-interface-spec.html + */ + +#include +#include + +// For dummy refrence when peripheral is not available. +&{/} { + not_available: not_available { + // Use ¬_available when required. + // This node is responsible to create these entries, + // /sys/firmware/devicetree/base/__symbols__/not_available + // /sys/firmware/devicetree/base/not_available + }; +}; + +// For compatible bone pinmuxing +bone_pinmux: &am33xx_pinmux { + bborg_comms_can_pins: pinmux_comms_can_pins { + pinctrl-single,pins = < + 0x184 (PIN_INPUT_PULLUP | MUX_MODE2) /* P9_24: uart1_txd.d_can1_rx */ + 0x180 (PIN_OUTPUT_PULLUP | MUX_MODE2) /* P9_26: uart1_rxd.d_can1_tx */ + >; + }; + + bborg_comms_rs485_pins: pinmux_comms_rs485_pins { + pinctrl-single,pins = < + 0x074 (PIN_OUTPUT | MUX_MODE6) /* P9_13: gpmc_wpn.uart4_txd_mux2 */ + 0x070 (PIN_INPUT | MUX_MODE6) /* P9_11: gpmc_wait0.uart4_rxd_mux2 */ + >; + }; +}; + +// ADC +bone_adc: &tscadc { + +}; + +// UART +// https://docs.beagleboard.io/latest/boards/capes/cape-interface-spec.html#uart +bone_uart_4: &uart4 { + symlink = "bone/uart/4"; + status = "disabled"; + pinctrl-names = "default"; + pinctrl-0 = <&bborg_comms_rs485_pins>; + //rs485-rts-delay = <0 0>; + //rts-gpio = <&gpio3 19 1>; /* GPIO_ACTIVE_HIGH>; */ + //rs485-rts-active-high; + //linux,rs485-enabled-at-boot-time; +}; + +// CAN +// https://docs.beagleboard.io/latest/boards/capes/cape-interface-spec.html#can +bone_can_1: &dcan1 { + symlink = "bone/can/1"; + status = "disabled"; + pinctrl-names = "default"; +// pinctrl-0 = < +// &P9_26_can_pin /* tx */ +// &P9_24_can_pin /* rx */ +// >; + pinctrl-0 = <&bborg_comms_can_pins>; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-boneblack.dts b/arch/arm/boot/dts/ti/omap/am335x-boneblack.dts --- a/arch/arm/boot/dts/ti/omap/am335x-boneblack.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-boneblack.dts 2024-07-07 20:37:34.620306429 -0400 @@ -12,6 +12,11 @@ / { model = "TI AM335x BeagleBone Black"; compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + + chosen { + base_dtb = "am335x-boneblack.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; }; &cpu0_opp_table { @@ -35,7 +40,7 @@ "P9_18 [spi0_d1]", "P9_17 [spi0_cs0]", "[mmc0_cd]", - "P8_42A [ecappwm0]", + "P9_42A [ecappwm0]", "P8_35 [lcd d12]", "P8_33 [lcd d13]", "P8_31 [lcd d14]", diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-boneblack-uboot.dts b/arch/arm/boot/dts/ti/omap/am335x-boneblack-uboot.dts --- a/arch/arm/boot/dts/ti/omap/am335x-boneblack-uboot.dts 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/am335x-boneblack-uboot.dts 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ +/dts-v1/; + +#include "am33xx.dtsi" +#include "am335x-bone-common.dtsi" +#include "am335x-bbb-bone-buses.dtsi" + +/ { + model = "TI AM335x BeagleBone Black"; + compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + + chosen { + base_dtb = "am335x-boneblack-uboot.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x20000000>; /* 512 MB */ + }; +}; + +&cpu0_opp_table { + /* + * All PG 2.0 silicon may not support 1GHz but some of the early + * BeagleBone Blacks have PG 2.0 silicon which is guaranteed + * to support 1GHz OPP so enable it for PG 2.0 on this board. + */ + oppnitro-1000000000 { + /* OPP Nitro */ + opp-supported-hw = <0x06 0x0100>; + }; +}; + +&ldo3_reg { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; +}; + +&mmc1 { + vmmc-supply = <&vmmcsd_fixed>; +}; + +&gpio0 { + gpio-line-names = + "[mdio_data]", + "[mdio_clk]", + "P9_22 [spi0_sclk]", + "P9_21 [spi0_d0]", + "P9_18 [spi0_d1]", + "P9_17 [spi0_cs0]", + "[mmc0_cd]", + "P9_42A [ecappwm0]", + "P8_35 [lcd d12]", + "P8_33 [lcd d13]", + "P8_31 [lcd d14]", + "P8_32 [lcd d15]", + "P9_20 [i2c2_sda]", + "P9_19 [i2c2_scl]", + "P9_26 [uart1_rxd]", + "P9_24 [uart1_txd]", + "[rmii1_txd3]", + "[rmii1_txd2]", + "[usb0_drvvbus]", + "[hdmi cec]", + "P9_41B", + "[rmii1_txd1]", + "P8_19 [ehrpwm2a]", + "P8_13 [ehrpwm2b]", + "NC", + "NC", + "P8_14", + "P8_17", + "[rmii1_txd0]", + "[rmii1_refclk]", + "P9_11 [uart4_rxd]", + "P9_13 [uart4_txd]"; +}; + +&gpio1 { + gpio-line-names = + "P8_25 [mmc1_dat0]", + "[mmc1_dat1]", + "P8_5 [mmc1_dat2]", + "P8_6 [mmc1_dat3]", + "P8_23 [mmc1_dat4]", + "P8_22 [mmc1_dat5]", + "P8_3 [mmc1_dat6]", + "P8_4 [mmc1_dat7]", + "NC", + "NC", + "NC", + "NC", + "P8_12", + "P8_11", + "P8_16", + "P8_15", + "P9_15A", + "P9_23", + "P9_14 [ehrpwm1a]", + "P9_16 [ehrpwm1b]", + "[emmc rst]", + "[usr0 led]", + "[usr1 led]", + "[usr2 led]", + "[usr3 led]", + "[hdmi irq]", + "[usb vbus oc]", + "[hdmi audio]", + "P9_12", + "P8_26", + "P8_21 [emmc]", + "P8_20 [emmc]"; +}; + +&gpio2 { + gpio-line-names = + "P9_15B", + "P8_18", + "P8_7", + "P8_8", + "P8_10", + "P8_9", + "P8_45 [hdmi]", + "P8_46 [hdmi]", + "P8_43 [hdmi]", + "P8_44 [hdmi]", + "P8_41 [hdmi]", + "P8_42 [hdmi]", + "P8_39 [hdmi]", + "P8_40 [hdmi]", + "P8_37 [hdmi]", + "P8_38 [hdmi]", + "P8_36 [hdmi]", + "P8_34 [hdmi]", + "[rmii1_rxd3]", + "[rmii1_rxd2]", + "[rmii1_rxd1]", + "[rmii1_rxd0]", + "P8_27 [hdmi]", + "P8_29 [hdmi]", + "P8_28 [hdmi]", + "P8_30 [hdmi]", + "[mmc0_dat3]", + "[mmc0_dat2]", + "[mmc0_dat1]", + "[mmc0_dat0]", + "[mmc0_clk]", + "[mmc0_cmd]"; +}; + +&gpio3 { + gpio-line-names = + "[mii col]", + "[mii crs]", + "[mii rx err]", + "[mii tx en]", + "[mii rx dv]", + "[i2c0 sda]", + "[i2c0 scl]", + "[jtag emu0]", + "[jtag emu1]", + "[mii tx clk]", + "[mii rx clk]", + "NC", + "NC", + "[usb vbus en]", + "P9_31 [spi1_sclk]", + "P9_29 [spi1_d0]", + "P9_30 [spi1_d1]", + "P9_28 [spi1_cs0]", + "P9_42B [ecappwm0]", + "P9_27", + "P9_41A", + "P9_25", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC"; +}; + +&baseboard_eeprom { + vcc-supply = <&ldo4_reg>; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-boneblack-uboot-univ.dts b/arch/arm/boot/dts/ti/omap/am335x-boneblack-uboot-univ.dts --- a/arch/arm/boot/dts/ti/omap/am335x-boneblack-uboot-univ.dts 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/am335x-boneblack-uboot-univ.dts 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ +/dts-v1/; + +#include "am33xx.dtsi" +#include "am335x-bone-common.dtsi" +#include "am335x-bone-common-univ.dtsi" + +/ { + model = "TI AM335x BeagleBone Black"; + compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + + chosen { + base_dtb = "am335x-boneblack-uboot-univ.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x20000000>; /* 512 MB */ + }; +}; + +&cpu0_opp_table { + /* + * All PG 2.0 silicon may not support 1GHz but some of the early + * BeagleBone Blacks have PG 2.0 silicon which is guaranteed + * to support 1GHz OPP so enable it for PG 2.0 on this board. + */ + oppnitro-1000000000 { + opp-supported-hw = <0x06 0x0100>; + }; +}; + +&ldo3_reg { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; +}; + +&mmc1 { + vmmc-supply = <&vmmcsd_fixed>; +}; + +&gpio0 { + gpio-line-names = + "[mdio_data]", + "[mdio_clk]", + "P9_22 [spi0_sclk]", + "P9_21 [spi0_d0]", + "P9_18 [spi0_d1]", + "P9_17 [spi0_cs0]", + "[mmc0_cd]", + "P8_42A [ecappwm0]", + "P8_35 [lcd d12]", + "P8_33 [lcd d13]", + "P8_31 [lcd d14]", + "P8_32 [lcd d15]", + "P9_20 [i2c2_sda]", + "P9_19 [i2c2_scl]", + "P9_26 [uart1_rxd]", + "P9_24 [uart1_txd]", + "[rmii1_txd3]", + "[rmii1_txd2]", + "[usb0_drvvbus]", + "[hdmi cec]", + "P9_41B", + "[rmii1_txd1]", + "P8_19 [ehrpwm2a]", + "P8_13 [ehrpwm2b]", + "NC", + "NC", + "P8_14", + "P8_17", + "[rmii1_txd0]", + "[rmii1_refclk]", + "P9_11 [uart4_rxd]", + "P9_13 [uart4_txd]"; +}; + +&gpio1 { + gpio-line-names = + "P8_25 [mmc1_dat0]", + "[mmc1_dat1]", + "P8_5 [mmc1_dat2]", + "P8_6 [mmc1_dat3]", + "P8_23 [mmc1_dat4]", + "P8_22 [mmc1_dat5]", + "P8_3 [mmc1_dat6]", + "P8_4 [mmc1_dat7]", + "NC", + "NC", + "NC", + "NC", + "P8_12", + "P8_11", + "P8_16", + "P8_15", + "P9_15A", + "P9_23", + "P9_14 [ehrpwm1a]", + "P9_16 [ehrpwm1b]", + "[emmc rst]", + "[usr0 led]", + "[usr1 led]", + "[usr2 led]", + "[usr3 led]", + "[hdmi irq]", + "[usb vbus oc]", + "[hdmi audio]", + "P9_12", + "P8_26", + "P8_21 [emmc]", + "P8_20 [emmc]"; +}; + +&gpio2 { + gpio-line-names = + "P9_15B", + "P8_18", + "P8_7", + "P8_8", + "P8_10", + "P8_9", + "P8_45 [hdmi]", + "P8_46 [hdmi]", + "P8_43 [hdmi]", + "P8_44 [hdmi]", + "P8_41 [hdmi]", + "P8_42 [hdmi]", + "P8_39 [hdmi]", + "P8_40 [hdmi]", + "P8_37 [hdmi]", + "P8_38 [hdmi]", + "P8_36 [hdmi]", + "P8_34 [hdmi]", + "[rmii1_rxd3]", + "[rmii1_rxd2]", + "[rmii1_rxd1]", + "[rmii1_rxd0]", + "P8_27 [hdmi]", + "P8_29 [hdmi]", + "P8_28 [hdmi]", + "P8_30 [hdmi]", + "[mmc0_dat3]", + "[mmc0_dat2]", + "[mmc0_dat1]", + "[mmc0_dat0]", + "[mmc0_clk]", + "[mmc0_cmd]"; +}; + +&gpio3 { + gpio-line-names = + "[mii col]", + "[mii crs]", + "[mii rx err]", + "[mii tx en]", + "[mii rx dv]", + "[i2c0 sda]", + "[i2c0 scl]", + "[jtag emu0]", + "[jtag emu1]", + "[mii tx clk]", + "[mii rx clk]", + "NC", + "NC", + "[usb vbus en]", + "P9_31 [spi1_sclk]", + "P9_29 [spi1_d0]", + "P9_30 [spi1_d1]", + "P9_28 [spi1_cs0]", + "P9_42B [ecappwm0]", + "P9_27", + "P9_41A", + "P9_25", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC"; +}; + +&baseboard_eeprom { + vcc-supply = <&ldo4_reg>; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-boneblack-wireless.dts b/arch/arm/boot/dts/ti/omap/am335x-boneblack-wireless.dts --- a/arch/arm/boot/dts/ti/omap/am335x-boneblack-wireless.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-boneblack-wireless.dts 2024-07-07 20:37:34.620306429 -0400 @@ -14,6 +14,11 @@ model = "TI AM335x BeagleBone Black Wireless"; compatible = "ti,am335x-bone-black-wireless", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + chosen { + base_dtb = "am335x-boneblack-wireless.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; + wlan_en_reg: fixedregulator@2 { compatible = "regulator-fixed"; regulator-name = "wlan-en-regulator"; @@ -64,6 +69,9 @@ }; &mac_sw { + /delete-property/pinctrl-names; + /delete-property/pinctrl-0; + /delete-property/pinctrl-1; status = "disabled"; }; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-boneblue.dts b/arch/arm/boot/dts/ti/omap/am335x-boneblue.dts --- a/arch/arm/boot/dts/ti/omap/am335x-boneblue.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-boneblue.dts 2024-07-07 20:37:34.620306429 -0400 @@ -14,6 +14,8 @@ chosen { stdout-path = &uart0; + base_dtb = "am335x-boneblue.dts"; + base_dtb_timestamp = __TIMESTAMP__; }; leds { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi b/arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi --- a/arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -3,6 +3,8 @@ * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ */ +#include "am335x-bbb-bone-buses.dtsi" + / { cpus { cpu@0 { @@ -26,14 +28,14 @@ compatible = "gpio-leds"; led2 { - label = "beaglebone:green:heartbeat"; + label = "beaglebone:green:usr0"; gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; default-state = "off"; }; led3 { - label = "beaglebone:green:mmc0"; + label = "beaglebone:green:usr1"; gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>; linux,default-trigger = "mmc0"; default-state = "off"; @@ -63,9 +65,6 @@ }; &am33xx_pinmux { - pinctrl-names = "default"; - pinctrl-0 = <&clkout2_pin>; - user_leds_s0: user-leds-s0-pins { pinctrl-single,pins = < AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a5.gpio1_21 */ @@ -96,12 +95,6 @@ >; }; - clkout2_pin: clkout2-pins { - pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_OUTPUT_PULLDOWN, MUX_MODE3) /* xdma_event_intr1.clkout2 */ - >; - }; - cpsw_default: cpsw-default-pins { pinctrl-single,pins = < /* Slave 1 */ @@ -193,6 +186,7 @@ pinctrl-0 = <&uart0_pins>; status = "okay"; + symlink = "bone/uart/0"; }; &usb0 { @@ -211,6 +205,7 @@ status = "okay"; clock-frequency = <400000>; + symlink = "bone/i2c/0"; tps: tps@24 { reg = <0x24>; @@ -235,6 +230,7 @@ status = "okay"; clock-frequency = <100000>; + symlink = "bone/i2c/2"; cape_eeprom0: cape_eeprom0@54 { compatible = "atmel,24c256"; @@ -289,8 +285,8 @@ * For details, see linux-omap mailing list May 2015 thread * [PATCH] ARM: dts: am335x-bone* enable pmic-shutdown-controller * In particular, messages: - * http://www.spinics.net/lists/linux-omap/msg118585.html - * http://www.spinics.net/lists/linux-omap/msg118615.html + * https://www.spinics.net/lists/linux-omap/msg118585.html + * https://www.spinics.net/lists/linux-omap/msg118615.html * * You can override this later with * &tps { /delete-property/ ti,pmic-shutdown-controller; } @@ -418,3 +414,12 @@ &wkup_m3_ipc { firmware-name = "am335x-bone-scale-data.bin"; }; + +&tscadc { + adc { + ti,adc-channels = <0 1 2 3 4 5 6 7>; + ti,chan-step-avg = <16 16 16 16 16 16 16 16>; + ti,chan-step-opendelay = <0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98>; + ti,chan-step-sampledelay = <0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0>; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-bone-common-univ.dtsi b/arch/arm/boot/dts/ti/omap/am335x-bone-common-univ.dtsi --- a/arch/arm/boot/dts/ti/omap/am335x-bone-common-univ.dtsi 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/am335x-bone-common-univ.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,2289 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include + +&am33xx_pinmux { + +/* macro: BONE_PIN( , , */ +#define BONE_PIN(XX,ZZ,QQ) \ + XX##_##ZZ##_pin: pinmux_##XX##_##ZZ##_pin { pinctrl-single,pins = < QQ >; }; + + /************************/ + /* P8 Header */ + /************************/ + + /* P8_01 GND */ + + /* P8_02 GND */ + + + /* P8_03 (ZCZ ball R9) gpmc_ad6 (emmc) */ + BONE_PIN(P8_03, default, P8_03(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_03, gpio, P8_03(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_03, gpio_pu, P8_03(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_03, gpio_pd, P8_03(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_04 (ZCZ ball T9) gpmc_ad7 (emmc) */ + BONE_PIN(P8_04, default, P8_04(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_04, gpio, P8_04(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_04, gpio_pu, P8_04(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_04, gpio_pd, P8_04(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_05 (ZCZ ball R8) gpmc_ad2 (emmc) */ + BONE_PIN(P8_05, default, P8_05(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_05, gpio, P8_05(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_05, gpio_pu, P8_05(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_05, gpio_pd, P8_05(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_06 (ZCZ ball T8) gpmc_ad3 (emmc) */ + BONE_PIN(P8_06, default, P8_06(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_06, gpio, P8_06(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_06, gpio_pu, P8_06(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_06, gpio_pd, P8_06(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_07 (ZCZ ball R7) gpmc_advn_ale (gpio2_2) */ + BONE_PIN(P8_07, default, P8_07(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_07, gpio, P8_07(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_07, gpio_pu, P8_07(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_07, gpio_pd, P8_07(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_07, timer, P8_07(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_08 (ZCZ ball T7) gpmc_oen_ren (gpio2_3) */ + BONE_PIN(P8_08, default, P8_08(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_08, gpio, P8_08(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_08, gpio_pu, P8_08(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_08, gpio_pd, P8_08(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_08, timer, P8_08(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_09 (ZCZ ball T6) gpmc_be0n_cle (gpio2_5) */ + BONE_PIN(P8_09, default, P8_09(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_09, gpio, P8_09(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_09, gpio_pu, P8_09(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_09, gpio_pd, P8_09(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_09, timer, P8_09(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_10 (ZCZ ball U6) gpmc_wen (gpio2_4) */ + BONE_PIN(P8_10, default, P8_10(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_10, gpio, P8_10(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_10, gpio_pu, P8_10(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_10, gpio_pd, P8_10(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_10, timer, P8_10(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_11 (ZCZ ball R12) gpmc_ad13 (gpio1_13) */ + BONE_PIN(P8_11, default, P8_11(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_11, gpio, P8_11(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_11, gpio_pu, P8_11(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_11, gpio_pd, P8_11(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_11, eqep, P8_11(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P8_11, pruout, P8_11(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6)) + + /* P8_12 (ZCZ ball T12) gpmc_ad12 (gpio1_12) */ + BONE_PIN(P8_12, default, P8_12(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_12, gpio, P8_12(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_12, gpio_pu, P8_12(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_12, gpio_pd, P8_12(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_12, eqep, P8_12(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P8_12, pruout, P8_12(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6)) + + /* P8_13 (ZCZ ball T10) gpmc_ad9 (gpio0_23) */ + BONE_PIN(P8_13, default, P8_13(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_13, gpio, P8_13(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_13, gpio_pu, P8_13(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_13, gpio_pd, P8_13(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_13, pwm, P8_13(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE4)) + + /* P8_14 (ZCZ ball T11) gpmc_ad10 (gpio0_26) */ + BONE_PIN(P8_14, default, P8_14(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_14, gpio, P8_14(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_14, gpio_pu, P8_14(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_14, gpio_pd, P8_14(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_14, pwm, P8_14(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE4)) + + /* P8_15 (ZCZ ball U13) gpmc_ad15 (gpio1_15) */ + BONE_PIN(P8_15, default, P8_15(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_15, gpio, P8_15(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_15, gpio_pu, P8_15(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_15, gpio_pd, P8_15(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_15, eqep, P8_15(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P8_15, pru_ecap_pwm, P8_15(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_15, pruin, P8_15(PIN_INPUT | MUX_MODE6)) + + /* P8_16 (ZCZ ball V13) gpmc_ad14 (gpio1_14) */ + BONE_PIN(P8_16, default, P8_16(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_16, gpio, P8_16(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_16, gpio_pu, P8_16(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_16, gpio_pd, P8_16(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_16, eqep, P8_16(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P8_16, pruin, P8_16(PIN_INPUT | MUX_MODE6)) + + /* P8_17 (ZCZ ball U12) gpmc_ad11 (gpio0_27) */ + BONE_PIN(P8_17, default, P8_17(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_17, gpio, P8_17(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_17, gpio_pu, P8_17(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_17, gpio_pd, P8_17(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_17, pwm, P8_17(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE4)) + + /* P8_18 (ZCZ ball V12) gpmc_clk (gpio2_1) */ + BONE_PIN(P8_18, default, P8_18(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_18, gpio, P8_18(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_18, gpio_pu, P8_18(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_18, gpio_pd, P8_18(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_19 (ZCZ ball U10) gpmc_ad8 (gpio0_22) */ + BONE_PIN(P8_19, default, P8_19(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_19, gpio, P8_19(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_19, gpio_pu, P8_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_19, gpio_pd, P8_19(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_19, pwm, P8_19(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE4)) + + /* P8_20 (ZCZ ball V9) gpmc_csn2 (emmc) */ + BONE_PIN(P8_20, default, P8_20(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_20, gpio, P8_20(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_20, gpio_pu, P8_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_20, gpio_pd, P8_20(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_20, pruout, P8_20(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_20, pruin, P8_20(PIN_INPUT | MUX_MODE6)) + + /* P8_21 (ZCZ ball U9) gpmc_csn1 (emmc) */ + BONE_PIN(P8_21, default, P8_21(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_21, gpio, P8_21(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_21, gpio_pu, P8_21(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_21, gpio_pd, P8_21(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_21, pruout, P8_21(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_21, pruin, P8_21(PIN_INPUT | MUX_MODE6)) + + /* P8_22 (ZCZ ball V8) gpmc_ad5 (emmc) */ + BONE_PIN(P8_22, default, P8_22(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_22, gpio, P8_22(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_22, gpio_pu, P8_22(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_22, gpio_pd, P8_22(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_23 (ZCZ ball U8) gpmc_ad4 (emmc) */ + BONE_PIN(P8_23, default, P8_23(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_23, gpio, P8_23(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_23, gpio_pu, P8_23(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_23, gpio_pd, P8_23(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_24 (ZCZ ball V7) gpmc_ad1 (emmc) */ + BONE_PIN(P8_24, default, P8_24(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_24, gpio, P8_24(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_24, gpio_pu, P8_24(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_24, gpio_pd, P8_24(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_25 (ZCZ ball U7) gpmc_ad0 (emmc) */ + BONE_PIN(P8_25, default, P8_25(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_25, gpio, P8_25(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_25, gpio_pu, P8_25(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_25, gpio_pd, P8_25(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_26 (ZCZ ball V6) gpmc_csn0 (gpio1_29) */ + BONE_PIN(P8_26, default, P8_26(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_26, gpio, P8_26(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_26, gpio_pu, P8_26(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_26, gpio_pd, P8_26(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_27 (ZCZ ball U5) lcd_vsync (hdmi) */ + BONE_PIN(P8_27, default, P8_27(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_27, gpio, P8_27(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_27, gpio_pu, P8_27(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_27, gpio_pd, P8_27(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_27, pruout, P8_27(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_27, pruin, P8_27(PIN_INPUT | MUX_MODE6)) + + /* P8_28 (ZCZ ball V5) lcd_pclk (hdmi) */ + BONE_PIN(P8_28, default, P8_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_28, gpio, P8_28(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_28, gpio_pu, P8_28(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_28, gpio_pd, P8_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_28, pruout, P8_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_28, pruin, P8_28(PIN_INPUT | MUX_MODE6)) + + /* P8_29 (ZCZ ball R5) lcd_hsync (hdmi) */ + BONE_PIN(P8_29, default, P8_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_29, gpio, P8_29(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_29, gpio_pu, P8_29(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_29, gpio_pd, P8_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_29, pruout, P8_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_29, pruin, P8_29(PIN_INPUT | MUX_MODE6)) + + /* P8_30 (ZCZ ball R6) lcd_ac_bias_en (hdmi) */ + BONE_PIN(P8_30, default, P8_30(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_30, gpio, P8_30(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_30, gpio_pu, P8_30(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_30, gpio_pd, P8_30(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_30, pruout, P8_30(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_30, pruin, P8_30(PIN_INPUT | MUX_MODE6)) + + /* P8_31 (ZCZ ball V4) lcd_data14 (hdmi) */ + BONE_PIN(P8_31, default, P8_31(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_31, gpio, P8_31(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_31, gpio_pu, P8_31(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_31, gpio_pd, P8_31(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_31, eqep, P8_31(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + BONE_PIN(P8_31, uart, P8_31(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P8_32 (ZCZ ball T5) lcd_data15 (hdmi) */ + BONE_PIN(P8_32, default, P8_32(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_32, gpio, P8_32(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_32, gpio_pu, P8_32(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_32, gpio_pd, P8_32(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_32, eqep, P8_32(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_33 (ZCZ ball V3) lcd_data13 (hdmi) */ + BONE_PIN(P8_33, default, P8_33(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_33, gpio, P8_33(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_33, gpio_pu, P8_33(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_33, gpio_pd, P8_33(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_33, eqep, P8_33(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_34 (ZCZ ball U4) lcd_data11 (hdmi) */ + BONE_PIN(P8_34, default, P8_34(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_34, gpio, P8_34(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_34, gpio_pu, P8_34(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_34, gpio_pd, P8_34(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_34, pwm, P8_34(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE2)) + + /* P8_35 (ZCZ ball V2) lcd_data12 (hdmi) */ + BONE_PIN(P8_35, default, P8_35(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_35, gpio, P8_35(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_35, gpio_pu, P8_35(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_35, gpio_pd, P8_35(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_35, eqep, P8_35(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_36 (ZCZ ball U3) lcd_data10 (hdmi) */ + BONE_PIN(P8_36, default, P8_36(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_36, gpio, P8_36(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_36, gpio_pu, P8_36(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_36, gpio_pd, P8_36(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_36, pwm, P8_36(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE2)) + + /* P8_37 (ZCZ ball U1) lcd_data8 (hdmi) */ + BONE_PIN(P8_37, default, P8_37(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_37, gpio, P8_37(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_37, gpio_pu, P8_37(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_37, gpio_pd, P8_37(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_37, pwm, P8_37(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE2)) + BONE_PIN(P8_37, uart, P8_37(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P8_38 (ZCZ ball U2) lcd_data9 (hdmi) */ + BONE_PIN(P8_38, default, P8_38(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_38, gpio, P8_38(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_38, gpio_pu, P8_38(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_38, gpio_pd, P8_38(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_38, pwm, P8_38(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE2)) + BONE_PIN(P8_38, uart, P8_38(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P8_39 (ZCZ ball T3) lcd_data6 (hdmi) */ + BONE_PIN(P8_39, default, P8_39(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_39, gpio, P8_39(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_39, gpio_pu, P8_39(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_39, gpio_pd, P8_39(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_39, eqep, P8_39(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_39, pruout, P8_39(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_39, pruin, P8_39(PIN_INPUT | MUX_MODE6)) + + /* P8_40 (ZCZ ball T4) lcd_data7 (hdmi) */ + BONE_PIN(P8_40, default, P8_40(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_40, gpio, P8_40(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_40, gpio_pu, P8_40(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_40, gpio_pd, P8_40(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_40, eqep, P8_40(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_40, pruout, P8_40(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_40, pruin, P8_40(PIN_INPUT | MUX_MODE6)) + + /* P8_41 (ZCZ ball T1) lcd_data4 (hdmi) */ + BONE_PIN(P8_41, default, P8_41(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_41, gpio, P8_41(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_41, gpio_pu, P8_41(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_41, gpio_pd, P8_41(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_41, eqep, P8_41(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_41, pruout, P8_41(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_41, pruin, P8_41(PIN_INPUT | MUX_MODE6)) + + /* P8_42 (ZCZ ball T2) lcd_data5 (hdmi) */ + BONE_PIN(P8_42, default, P8_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_42, gpio, P8_42(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_42, gpio_pu, P8_42(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_42, gpio_pd, P8_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_42, eqep, P8_42(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_42, pruout, P8_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_42, pruin, P8_42(PIN_INPUT | MUX_MODE6)) + + /* P8_43 (ZCZ ball R3) lcd_data2 (hdmi) */ + BONE_PIN(P8_43, default, P8_43(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_43, gpio, P8_43(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_43, gpio_pu, P8_43(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_43, gpio_pd, P8_43(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_43, pwm, P8_43(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_43, pruout, P8_43(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_43, pruin, P8_43(PIN_INPUT | MUX_MODE6)) + + /* P8_44 (ZCZ ball R4) lcd_data3 (hdmi) */ + BONE_PIN(P8_44, default, P8_44(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_44, gpio, P8_44(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_44, gpio_pu, P8_44(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_44, gpio_pd, P8_44(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_44, pwm, P8_44(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_44, pruout, P8_44(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_44, pruin, P8_44(PIN_INPUT | MUX_MODE6)) + + /* P8_45 (ZCZ ball R1) lcd_data0 (hdmi) */ + BONE_PIN(P8_45, default, P8_45(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_45, gpio, P8_45(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_45, gpio_pu, P8_45(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_45, gpio_pd, P8_45(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_45, pwm, P8_45(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_45, pruout, P8_45(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_45, pruin, P8_45(PIN_INPUT | MUX_MODE6)) + + /* P8_46 (ZCZ ball R2) lcd_data1 (hdmi) */ + BONE_PIN(P8_46, default, P8_46(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_46, gpio, P8_46(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_46, gpio_pu, P8_46(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_46, gpio_pd, P8_46(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_46, pwm, P8_46(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_46, pruout, P8_46(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_46, pruin, P8_46(PIN_INPUT | MUX_MODE6)) + + /************************/ + /* P9 Header */ + /************************/ + + /* P9_01 GND */ + + /* P9_02 GND */ + + /* P9_03 3V3 */ + + /* P9_04 3V3 */ + + /* P9_05 VDD_5V */ + + /* P9_06 VDD_5V */ + + /* P9_07 SYS_5V */ + + /* P9_08 SYS_5V */ + + /* P9_09 PWR_BUT */ + + /* P9_10 RSTn */ + + /* P9_11 (ZCZ ball T17) gpmc_wait0 (gpio0_30) */ + BONE_PIN(P9_11, default, P9_11(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_11, gpio, P9_11(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_11, gpio_pu, P9_11(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_11, gpio_pd, P9_11(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_11, uart, P9_11(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE6)) + + /* P9_12 (ZCZ ball U18) gpmc_be1n (gpio1_28) */ + BONE_PIN(P9_12, default, P9_12(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_12, gpio, P9_12(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_12, gpio_pu, P9_12(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_12, gpio_pd, P9_12(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P9_13 (ZCZ ball U17) gpmc_wpn (gpio0_31) */ + BONE_PIN(P9_13, default, P9_13(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_13, gpio, P9_13(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_13, gpio_pu, P9_13(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_13, gpio_pd, P9_13(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_13, uart, P9_13(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE6)) + + /* P9_14 (ZCZ ball U14) gpmc_a2 (gpio1_18) */ + BONE_PIN(P9_14, default, P9_14(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_14, gpio, P9_14(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_14, gpio_pu, P9_14(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_14, gpio_pd, P9_14(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_14, pwm, P9_14(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6)) + + /* P9_15 (ZCZ ball R13) gpmc_a0 (gpio1_16) */ + BONE_PIN(P9_15, default, P9_15(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_15, gpio, P9_15(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_15, gpio_pu, P9_15(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_15, gpio_pd, P9_15(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_15, pwm, P9_15(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6)) + + /* P9_16 (ZCZ ball T14) gpmc_a3 (gpio1_19) */ + BONE_PIN(P9_16, default, P9_16(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_16, gpio, P9_16(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_16, gpio_pu, P9_16(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_16, gpio_pd, P9_16(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_16, pwm, P9_16(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6)) + + /* P9_17 (ZCZ ball A16) spi0_cs0 (gpio0_5) */ + BONE_PIN(P9_17, default, P9_17(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_17, gpio, P9_17(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_17, gpio_pu, P9_17(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_17, gpio_pd, P9_17(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_17, spi_cs, P9_17(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE0)) + BONE_PIN(P9_17, i2c, P9_17(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + BONE_PIN(P9_17, pwm, P9_17(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_17, pru_uart, P9_17(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P9_18 (ZCZ ball B16) spi0_d1 (gpio0_4) */ + BONE_PIN(P9_18, default, P9_18(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_18, gpio, P9_18(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_18, gpio_pu, P9_18(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_18, gpio_pd, P9_18(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_18, spi, P9_18(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE0)) + BONE_PIN(P9_18, i2c, P9_18(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + BONE_PIN(P9_18, pwm, P9_18(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_18, pru_uart, P9_18(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P9_19 (ZCZ ball D17) uart1_rtsn (i2c2_scl) */ + BONE_PIN(P9_19, default, P9_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_19, gpio, P9_19(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_19, gpio_pu, P9_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_19, gpio_pd, P9_19(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_19, timer, P9_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_19, can, P9_19(PIN_INPUT_PULLUP | MUX_MODE2)) + BONE_PIN(P9_19, i2c, P9_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_19, spi_cs, P9_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P9_19, pru_uart, P9_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE5)) + + /* P9_20 (ZCZ ball D18) uart1_ctsn (i2c2_sda) */ + BONE_PIN(P9_20, default, P9_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_20, gpio, P9_20(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_20, gpio_pu, P9_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_20, gpio_pd, P9_20(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_20, timer, P9_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_20, can, P9_20(PIN_OUTPUT_PULLUP | MUX_MODE2)) + BONE_PIN(P9_20, i2c, P9_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_20, spi_cs, P9_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P9_20, pru_uart, P9_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE5)) + + /* P9_21 (ZCZ ball B17) spi0_d0 (gpio0_3) */ + BONE_PIN(P9_21, default, P9_21(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_21, gpio, P9_21(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_21, gpio_pu, P9_21(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_21, gpio_pd, P9_21(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_21, spi, P9_21(PIN_INPUT_PULLUP | MUX_MODE0)) + BONE_PIN(P9_21, uart, P9_21(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_21, i2c, P9_21(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + BONE_PIN(P9_21, pwm, P9_21(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_21, pru_uart, P9_21(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P9_22 (ZCZ ball A17) spi0_sclk (gpio0_2) */ + BONE_PIN(P9_22, default, P9_22(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_22, gpio, P9_22(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_22, gpio_pu, P9_22(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_22, gpio_pd, P9_22(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_22, spi_sclk, P9_22(PIN_INPUT_PULLUP | MUX_MODE0)) + BONE_PIN(P9_22, uart, P9_22(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_22, i2c, P9_22(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + BONE_PIN(P9_22, pwm, P9_22(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_22, pru_uart, P9_22(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P9_23 (ZCZ ball V14) gpmc_a1 (gpio1_17) */ + BONE_PIN(P9_23, default, P9_23(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_23, gpio, P9_23(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_23, gpio_pu, P9_23(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_23, gpio_pd, P9_23(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_23, pwm, P9_23(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6)) + + /* P9_24 (ZCZ ball D15) uart1_txd (gpio0_15) */ + BONE_PIN(P9_24, default, P9_24(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_24, gpio, P9_24(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_24, gpio_pu, P9_24(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_24, gpio_pd, P9_24(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_24, uart, P9_24(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE0)) + BONE_PIN(P9_24, can, P9_24(PIN_INPUT_PULLUP | MUX_MODE2)) + BONE_PIN(P9_24, i2c, P9_24(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_24, pru_uart, P9_24(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_24, pruin, P9_24(PIN_INPUT | MUX_MODE6)) + + /* P9_25 (ZCZ ball A14) mcasp0_ahclkx (audio) */ + BONE_PIN(P9_25, default, P9_25(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_25, gpio, P9_25(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_25, gpio_pu, P9_25(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_25, gpio_pd, P9_25(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_25, eqep, P9_25(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_25, pruout, P9_25(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_25, pruin, P9_25(PIN_INPUT | MUX_MODE6)) + + /* P9_26 (ZCZ ball D16) uart1_rxd (gpio0_14) */ + BONE_PIN(P9_26, default, P9_26(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_26, gpio, P9_26(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_26, gpio_pu, P9_26(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_26, gpio_pd, P9_26(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_26, uart, P9_26(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE0)) + BONE_PIN(P9_26, can, P9_26(PIN_OUTPUT_PULLUP | MUX_MODE2)) + BONE_PIN(P9_26, i2c, P9_26(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_26, pru_uart, P9_26(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_26, pruin, P9_26(PIN_INPUT | MUX_MODE6)) + + /* P9_27 (ZCZ ball C13) mcasp0_fsr (gpio3_19) */ + BONE_PIN(P9_27, default, P9_27(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_27, gpio, P9_27(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_27, gpio_pu, P9_27(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_27, gpio_pd, P9_27(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_27, eqep, P9_27(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_27, pruout, P9_27(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_27, pruin, P9_27(PIN_INPUT | MUX_MODE6)) + + /* P9_28 (ZCZ ball C12) mcasp0_ahclkr (audio) */ + BONE_PIN(P9_28, default, P9_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_28, gpio, P9_28(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_28, gpio_pu, P9_28(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_28, gpio_pd, P9_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_28, pwm, P9_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_28, spi_cs, P9_28(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_28, pwm2, P9_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE4)) + BONE_PIN(P9_28, pruout, P9_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_28, pruin, P9_28(PIN_INPUT | MUX_MODE6)) + + /* P9_29 (ZCZ ball B13) mcasp0_fsx (audio) */ + BONE_PIN(P9_29, default, P9_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_29, gpio, P9_29(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_29, gpio_pu, P9_29(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_29, gpio_pd, P9_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_29, pwm, P9_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_29, spi, P9_29(PIN_INPUT_PULLUP | MUX_MODE3)) + BONE_PIN(P9_29, pruout, P9_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_29, pruin, P9_29(PIN_INPUT | MUX_MODE6)) + + /* P9_30 (ZCZ ball D12) mcasp0_axr0 (gpio3_16) */ + BONE_PIN(P9_30, default, P9_30(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_30, gpio, P9_30(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_30, gpio_pu, P9_30(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_30, gpio_pd, P9_30(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_30, pwm, P9_30(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_30, spi, P9_30(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_30, pruout, P9_30(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_30, pruin, P9_30(PIN_INPUT | MUX_MODE6)) + + /* P9_31 (ZCZ ball A13) mcasp0_aclkx (audio) */ + BONE_PIN(P9_31, default, P9_31(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_31, gpio, P9_31(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_31, gpio_pu, P9_31(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_31, gpio_pd, P9_31(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_31, pwm, P9_31(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_31, spi_sclk, P9_31(PIN_INPUT_PULLUP | MUX_MODE3)) + BONE_PIN(P9_31, pruout, P9_31(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_31, pruin, P9_31(PIN_INPUT | MUX_MODE6)) + + /* P9_32 VADC */ + + /* P9_33 (ZCZ ball C8) AIN4 */ + + /* P9_34 AGND */ + + /* P9_35 (ZCZ ball A8) AIN6 */ + + /* P9_36 (ZCZ ball B8) AIN5 */ + + /* P9_37 (ZCZ ball B7) AIN2 */ + + /* P9_38 (ZCZ ball A7) AIN3 */ + + /* P9_39 (ZCZ ball B6) AIN0 */ + + /* P9_40 (ZCZ ball C7) AIN1 */ + + /* P9_41 (ZCZ ball D14) xdma_event_intr1 (gpio0_20) */ + BONE_PIN(P9_41, default, P9_41(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_41, gpio, P9_41(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_41, gpio_pu, P9_41(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_41, gpio_pd, P9_41(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_41, timer, P9_41(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P9_41, pruin, P9_41(PIN_INPUT | MUX_MODE5)) + + /* P9_41.1 */ + /* P9_91 (ZCZ ball D13) mcasp0_axr1 (gpio3_20) */ + BONE_PIN(P9_91, default, P9_91(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_91, gpio, P9_91(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_91, gpio_pu, P9_91(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_91, gpio_pd, P9_91(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_91, eqep, P9_91(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_91, pruout, P9_91(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_91, pruin, P9_91(PIN_INPUT | MUX_MODE6)) + + /* P9_42 (ZCZ ball C18) eCAP0_in_PWM0_out (gpio0_7) */ + BONE_PIN(P9_42, default, P9_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_42, gpio, P9_42(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_42, gpio_pu, P9_42(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_42, gpio_pd, P9_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_42, pwm, P9_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE0)) + BONE_PIN(P9_42, uart, P9_42(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_42, spi_cs, P9_42(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + BONE_PIN(P9_42, pru_ecap_pwm, P9_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_42, spi_sclk, P9_42(PIN_INPUT_PULLUP | MUX_MODE4)) + + /* P9_42.1 */ + /* P9_92 (ZCZ ball B12) mcasp0_aclkr (gpio3_18) */ + BONE_PIN(P9_92, default, P9_92(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_92, gpio, P9_92(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_92, gpio_pu, P9_92(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_92, gpio_pd, P9_92(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_92, eqep, P9_92(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_92, pruout, P9_92(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_92, pruin, P9_92(PIN_INPUT | MUX_MODE6)) + + /* P9_43 GND */ + + /* P9_44 GND */ + + /* P9_45 GND */ + + /* P9_46 GND */ +}; + +&i2c1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + + clock-frequency = <100000>; + symlink = "bone/i2c/1"; +}; + +&i2c2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + + clock-frequency = <100000>; + symlink = "bone/i2c/2"; +}; + +&uart1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/uart/1"; +}; + +&uart2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/uart/2"; +}; + +&uart3 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/uart/3"; +}; + +&uart4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/uart/4"; +}; + +&uart5 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/uart/5"; +}; + +&dcan0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/can/0"; +}; + +&dcan1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/can/1"; +}; + +&eqep0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/eqep/0"; +}; + +&eqep1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/eqep/1"; +}; + +&eqep2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/eqep/2"; +}; + +&epwmss0 { + status = "okay"; +}; + +&epwmss1 { + status = "okay"; +}; + +&epwmss2 { + status = "okay"; +}; + +&ehrpwm0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; +}; + +&ehrpwm1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; +}; + +&ehrpwm2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; +}; + +&ecap0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; +}; + +&ecap1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; +}; + +&ecap2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; +}; + +&spi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + + channel@0 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "rohm,dh2228fv"; + symlink = "bone/spi/0.0"; + + reg = <0>; + spi-max-frequency = <16000000>; + spi-cpha; + }; + + channel@1 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "rohm,dh2228fv"; + symlink = "bone/spi/0.1"; + + reg = <1>; + spi-max-frequency = <16000000>; + }; +}; + +&spi1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + + channel@0 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "rohm,dh2228fv"; + symlink = "bone/spi/1.0"; + + reg = <0>; + spi-max-frequency = <16000000>; + spi-cpha; + }; + + channel@1 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "rohm,dh2228fv"; + symlink = "bone/spi/1.1"; + + reg = <1>; + spi-max-frequency = <16000000>; + }; +}; + +/**********************************************************************/ +/* Pin Multiplex Helpers */ +/* */ +/* These provide userspace runtime pin configuration for the */ +/* BeagleBone cape expansion headers */ +/**********************************************************************/ + +&ocp { + /************************/ + /* P8 Header */ + /************************/ + + /* P8_01 GND */ + + /* P8_02 GND */ + + + /* P8_03 (ZCZ ball R9) emmc */ + P8_03_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_03_default_pin>; + pinctrl-1 = <&P8_03_gpio_pin>; + pinctrl-2 = <&P8_03_gpio_pu_pin>; + pinctrl-3 = <&P8_03_gpio_pd_pin>; + }; + + /* P8_04 (ZCZ ball T9) emmc */ + P8_04_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_04_default_pin>; + pinctrl-1 = <&P8_04_gpio_pin>; + pinctrl-2 = <&P8_04_gpio_pu_pin>; + pinctrl-3 = <&P8_04_gpio_pd_pin>; + }; + + /* P8_05 (ZCZ ball R8) emmc */ + P8_05_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_05_default_pin>; + pinctrl-1 = <&P8_05_gpio_pin>; + pinctrl-2 = <&P8_05_gpio_pu_pin>; + pinctrl-3 = <&P8_05_gpio_pd_pin>; + }; + + /* P8_06 (ZCZ ball T8) emmc */ + P8_06_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_06_default_pin>; + pinctrl-1 = <&P8_06_gpio_pin>; + pinctrl-2 = <&P8_06_gpio_pu_pin>; + pinctrl-3 = <&P8_06_gpio_pd_pin>; + }; + + /* P8_07 (ZCZ ball R7) */ + P8_07_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer"; + pinctrl-0 = <&P8_07_default_pin>; + pinctrl-1 = <&P8_07_gpio_pin>; + pinctrl-2 = <&P8_07_gpio_pu_pin>; + pinctrl-3 = <&P8_07_gpio_pd_pin>; + pinctrl-4 = <&P8_07_timer_pin>; + }; + + /* P8_08 (ZCZ ball T7) */ + P8_08_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer"; + pinctrl-0 = <&P8_08_default_pin>; + pinctrl-1 = <&P8_08_gpio_pin>; + pinctrl-2 = <&P8_08_gpio_pu_pin>; + pinctrl-3 = <&P8_08_gpio_pd_pin>; + pinctrl-4 = <&P8_08_timer_pin>; + }; + + /* P8_09 (ZCZ ball T6) */ + P8_09_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer"; + pinctrl-0 = <&P8_09_default_pin>; + pinctrl-1 = <&P8_09_gpio_pin>; + pinctrl-2 = <&P8_09_gpio_pu_pin>; + pinctrl-3 = <&P8_09_gpio_pd_pin>; + pinctrl-4 = <&P8_09_timer_pin>; + }; + + /* P8_10 (ZCZ ball U6) */ + P8_10_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer"; + pinctrl-0 = <&P8_10_default_pin>; + pinctrl-1 = <&P8_10_gpio_pin>; + pinctrl-2 = <&P8_10_gpio_pu_pin>; + pinctrl-3 = <&P8_10_gpio_pd_pin>; + pinctrl-4 = <&P8_10_timer_pin>; + }; + + /* P8_11 (ZCZ ball R12) */ + P8_11_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout"; + pinctrl-0 = <&P8_11_default_pin>; + pinctrl-1 = <&P8_11_gpio_pin>; + pinctrl-2 = <&P8_11_gpio_pu_pin>; + pinctrl-3 = <&P8_11_gpio_pd_pin>; + pinctrl-4 = <&P8_11_eqep_pin>; + pinctrl-5 = <&P8_11_pruout_pin>; + }; + + /* P8_12 (ZCZ ball T12) */ + P8_12_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout"; + pinctrl-0 = <&P8_12_default_pin>; + pinctrl-1 = <&P8_12_gpio_pin>; + pinctrl-2 = <&P8_12_gpio_pu_pin>; + pinctrl-3 = <&P8_12_gpio_pd_pin>; + pinctrl-4 = <&P8_12_eqep_pin>; + pinctrl-5 = <&P8_12_pruout_pin>; + }; + + /* P8_13 (ZCZ ball T10) */ + P8_13_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P8_13_default_pin>; + pinctrl-1 = <&P8_13_gpio_pin>; + pinctrl-2 = <&P8_13_gpio_pu_pin>; + pinctrl-3 = <&P8_13_gpio_pd_pin>; + pinctrl-4 = <&P8_13_pwm_pin>; + }; + + /* P8_14 (ZCZ ball T11) */ + P8_14_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P8_14_default_pin>; + pinctrl-1 = <&P8_14_gpio_pin>; + pinctrl-2 = <&P8_14_gpio_pu_pin>; + pinctrl-3 = <&P8_14_gpio_pd_pin>; + pinctrl-4 = <&P8_14_pwm_pin>; + }; + + /* P8_15 (ZCZ ball U13) */ + P8_15_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pru_ecap_pwm", "pruin"; + pinctrl-0 = <&P8_15_default_pin>; + pinctrl-1 = <&P8_15_gpio_pin>; + pinctrl-2 = <&P8_15_gpio_pu_pin>; + pinctrl-3 = <&P8_15_gpio_pd_pin>; + pinctrl-4 = <&P8_15_eqep_pin>; + pinctrl-5 = <&P8_15_pru_ecap_pwm_pin>; + pinctrl-6 = <&P8_15_pruin_pin>; + }; + + /* P8_16 (ZCZ ball V13) */ + P8_16_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruin"; + pinctrl-0 = <&P8_16_default_pin>; + pinctrl-1 = <&P8_16_gpio_pin>; + pinctrl-2 = <&P8_16_gpio_pu_pin>; + pinctrl-3 = <&P8_16_gpio_pd_pin>; + pinctrl-4 = <&P8_16_eqep_pin>; + pinctrl-5 = <&P8_16_pruin_pin>; + }; + + /* P8_17 (ZCZ ball U12) */ + P8_17_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P8_17_default_pin>; + pinctrl-1 = <&P8_17_gpio_pin>; + pinctrl-2 = <&P8_17_gpio_pu_pin>; + pinctrl-3 = <&P8_17_gpio_pd_pin>; + pinctrl-4 = <&P8_17_pwm_pin>; + }; + + /* P8_18 (ZCZ ball V12) */ + P8_18_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_18_default_pin>; + pinctrl-1 = <&P8_18_gpio_pin>; + pinctrl-2 = <&P8_18_gpio_pu_pin>; + pinctrl-3 = <&P8_18_gpio_pd_pin>; + }; + + /* P8_19 (ZCZ ball U10) */ + P8_19_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P8_19_default_pin>; + pinctrl-1 = <&P8_19_gpio_pin>; + pinctrl-2 = <&P8_19_gpio_pu_pin>; + pinctrl-3 = <&P8_19_gpio_pd_pin>; + pinctrl-4 = <&P8_19_pwm_pin>; + }; + + /* P8_20 (ZCZ ball V9) emmc */ + P8_20_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin"; + pinctrl-0 = <&P8_20_default_pin>; + pinctrl-1 = <&P8_20_gpio_pin>; + pinctrl-2 = <&P8_20_gpio_pu_pin>; + pinctrl-3 = <&P8_20_gpio_pd_pin>; + pinctrl-4 = <&P8_20_pruout_pin>; + pinctrl-5 = <&P8_20_pruin_pin>; + }; + + /* P8_21 (ZCZ ball U9) emmc */ + P8_21_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin"; + pinctrl-0 = <&P8_21_default_pin>; + pinctrl-1 = <&P8_21_gpio_pin>; + pinctrl-2 = <&P8_21_gpio_pu_pin>; + pinctrl-3 = <&P8_21_gpio_pd_pin>; + pinctrl-4 = <&P8_21_pruout_pin>; + pinctrl-5 = <&P8_21_pruin_pin>; + }; + + /* P8_22 (ZCZ ball V8) emmc */ + P8_22_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_22_default_pin>; + pinctrl-1 = <&P8_22_gpio_pin>; + pinctrl-2 = <&P8_22_gpio_pu_pin>; + pinctrl-3 = <&P8_22_gpio_pd_pin>; + }; + + /* P8_23 (ZCZ ball U8) emmc */ + P8_23_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_23_default_pin>; + pinctrl-1 = <&P8_23_gpio_pin>; + pinctrl-2 = <&P8_23_gpio_pu_pin>; + pinctrl-3 = <&P8_23_gpio_pd_pin>; + }; + + /* P8_24 (ZCZ ball V7) emmc */ + P8_24_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_24_default_pin>; + pinctrl-1 = <&P8_24_gpio_pin>; + pinctrl-2 = <&P8_24_gpio_pu_pin>; + pinctrl-3 = <&P8_24_gpio_pd_pin>; + }; + + /* P8_25 (ZCZ ball U7) emmc */ + P8_25_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_25_default_pin>; + pinctrl-1 = <&P8_25_gpio_pin>; + pinctrl-2 = <&P8_25_gpio_pu_pin>; + pinctrl-3 = <&P8_25_gpio_pd_pin>; + }; + + /* P8_26 (ZCZ ball V6) */ + P8_26_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_26_default_pin>; + pinctrl-1 = <&P8_26_gpio_pin>; + pinctrl-2 = <&P8_26_gpio_pu_pin>; + pinctrl-3 = <&P8_26_gpio_pd_pin>; + }; + + /* P8_27 (ZCZ ball U5) hdmi */ + P8_27_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin"; + pinctrl-0 = <&P8_27_default_pin>; + pinctrl-1 = <&P8_27_gpio_pin>; + pinctrl-2 = <&P8_27_gpio_pu_pin>; + pinctrl-3 = <&P8_27_gpio_pd_pin>; + pinctrl-4 = <&P8_27_pruout_pin>; + pinctrl-5 = <&P8_27_pruin_pin>; + }; + + /* P8_28 (ZCZ ball V5) hdmi */ + P8_28_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin"; + pinctrl-0 = <&P8_28_default_pin>; + pinctrl-1 = <&P8_28_gpio_pin>; + pinctrl-2 = <&P8_28_gpio_pu_pin>; + pinctrl-3 = <&P8_28_gpio_pd_pin>; + pinctrl-4 = <&P8_28_pruout_pin>; + pinctrl-5 = <&P8_28_pruin_pin>; + }; + + /* P8_29 (ZCZ ball R5) hdmi */ + P8_29_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin"; + pinctrl-0 = <&P8_29_default_pin>; + pinctrl-1 = <&P8_29_gpio_pin>; + pinctrl-2 = <&P8_29_gpio_pu_pin>; + pinctrl-3 = <&P8_29_gpio_pd_pin>; + pinctrl-4 = <&P8_29_pruout_pin>; + pinctrl-5 = <&P8_29_pruin_pin>; + }; + + /* P8_30 (ZCZ ball R6) hdmi */ + P8_30_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin"; + pinctrl-0 = <&P8_30_default_pin>; + pinctrl-1 = <&P8_30_gpio_pin>; + pinctrl-2 = <&P8_30_gpio_pu_pin>; + pinctrl-3 = <&P8_30_gpio_pd_pin>; + pinctrl-4 = <&P8_30_pruout_pin>; + pinctrl-5 = <&P8_30_pruin_pin>; + }; + + /* P8_31 (ZCZ ball V4) hdmi */ + P8_31_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "eqep"; + pinctrl-0 = <&P8_31_default_pin>; + pinctrl-1 = <&P8_31_gpio_pin>; + pinctrl-2 = <&P8_31_gpio_pu_pin>; + pinctrl-3 = <&P8_31_gpio_pd_pin>; + pinctrl-4 = <&P8_31_uart_pin>; + pinctrl-5 = <&P8_31_eqep_pin>; + }; + + /* P8_32 (ZCZ ball T5) hdmi */ + P8_32_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep"; + pinctrl-0 = <&P8_32_default_pin>; + pinctrl-1 = <&P8_32_gpio_pin>; + pinctrl-2 = <&P8_32_gpio_pu_pin>; + pinctrl-3 = <&P8_32_gpio_pd_pin>; + pinctrl-4 = <&P8_32_eqep_pin>; + }; + + /* P8_33 (ZCZ ball V3) hdmi */ + P8_33_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep"; + pinctrl-0 = <&P8_33_default_pin>; + pinctrl-1 = <&P8_33_gpio_pin>; + pinctrl-2 = <&P8_33_gpio_pu_pin>; + pinctrl-3 = <&P8_33_gpio_pd_pin>; + pinctrl-4 = <&P8_33_eqep_pin>; + }; + + /* P8_34 (ZCZ ball U4) hdmi */ + P8_34_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P8_34_default_pin>; + pinctrl-1 = <&P8_34_gpio_pin>; + pinctrl-2 = <&P8_34_gpio_pu_pin>; + pinctrl-3 = <&P8_34_gpio_pd_pin>; + pinctrl-4 = <&P8_34_pwm_pin>; + }; + + /* P8_35 (ZCZ ball V2) hdmi */ + P8_35_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep"; + pinctrl-0 = <&P8_35_default_pin>; + pinctrl-1 = <&P8_35_gpio_pin>; + pinctrl-2 = <&P8_35_gpio_pu_pin>; + pinctrl-3 = <&P8_35_gpio_pd_pin>; + pinctrl-4 = <&P8_35_eqep_pin>; + }; + + /* P8_36 (ZCZ ball U3) hdmi */ + P8_36_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P8_36_default_pin>; + pinctrl-1 = <&P8_36_gpio_pin>; + pinctrl-2 = <&P8_36_gpio_pu_pin>; + pinctrl-3 = <&P8_36_gpio_pd_pin>; + pinctrl-4 = <&P8_36_pwm_pin>; + }; + + /* P8_37 (ZCZ ball U1) hdmi */ + P8_37_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "pwm"; + pinctrl-0 = <&P8_37_default_pin>; + pinctrl-1 = <&P8_37_gpio_pin>; + pinctrl-2 = <&P8_37_gpio_pu_pin>; + pinctrl-3 = <&P8_37_gpio_pd_pin>; + pinctrl-4 = <&P8_37_uart_pin>; + pinctrl-5 = <&P8_37_pwm_pin>; + }; + + /* P8_38 (ZCZ ball U2) hdmi */ + P8_38_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "pwm"; + pinctrl-0 = <&P8_38_default_pin>; + pinctrl-1 = <&P8_38_gpio_pin>; + pinctrl-2 = <&P8_38_gpio_pu_pin>; + pinctrl-3 = <&P8_38_gpio_pd_pin>; + pinctrl-4 = <&P8_38_uart_pin>; + pinctrl-5 = <&P8_38_pwm_pin>; + }; + + /* P8_39 (ZCZ ball T3) hdmi */ + P8_39_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P8_39_default_pin>; + pinctrl-1 = <&P8_39_gpio_pin>; + pinctrl-2 = <&P8_39_gpio_pu_pin>; + pinctrl-3 = <&P8_39_gpio_pd_pin>; + pinctrl-4 = <&P8_39_eqep_pin>; + pinctrl-5 = <&P8_39_pruout_pin>; + pinctrl-6 = <&P8_39_pruin_pin>; + }; + + /* P8_40 (ZCZ ball T4) hdmi */ + P8_40_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P8_40_default_pin>; + pinctrl-1 = <&P8_40_gpio_pin>; + pinctrl-2 = <&P8_40_gpio_pu_pin>; + pinctrl-3 = <&P8_40_gpio_pd_pin>; + pinctrl-4 = <&P8_40_eqep_pin>; + pinctrl-5 = <&P8_40_pruout_pin>; + pinctrl-6 = <&P8_40_pruin_pin>; + }; + + /* P8_41 (ZCZ ball T1) hdmi */ + P8_41_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P8_41_default_pin>; + pinctrl-1 = <&P8_41_gpio_pin>; + pinctrl-2 = <&P8_41_gpio_pu_pin>; + pinctrl-3 = <&P8_41_gpio_pd_pin>; + pinctrl-4 = <&P8_41_eqep_pin>; + pinctrl-5 = <&P8_41_pruout_pin>; + pinctrl-6 = <&P8_41_pruin_pin>; + }; + + /* P8_42 (ZCZ ball T2) hdmi */ + P8_42_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P8_42_default_pin>; + pinctrl-1 = <&P8_42_gpio_pin>; + pinctrl-2 = <&P8_42_gpio_pu_pin>; + pinctrl-3 = <&P8_42_gpio_pd_pin>; + pinctrl-4 = <&P8_42_eqep_pin>; + pinctrl-5 = <&P8_42_pruout_pin>; + pinctrl-6 = <&P8_42_pruin_pin>; + }; + + /* P8_43 (ZCZ ball R3) hdmi */ + P8_43_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P8_43_default_pin>; + pinctrl-1 = <&P8_43_gpio_pin>; + pinctrl-2 = <&P8_43_gpio_pu_pin>; + pinctrl-3 = <&P8_43_gpio_pd_pin>; + pinctrl-4 = <&P8_43_pwm_pin>; + pinctrl-5 = <&P8_43_pruout_pin>; + pinctrl-6 = <&P8_43_pruin_pin>; + }; + + /* P8_44 (ZCZ ball R4) hdmi */ + P8_44_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P8_44_default_pin>; + pinctrl-1 = <&P8_44_gpio_pin>; + pinctrl-2 = <&P8_44_gpio_pu_pin>; + pinctrl-3 = <&P8_44_gpio_pd_pin>; + pinctrl-4 = <&P8_44_pwm_pin>; + pinctrl-5 = <&P8_44_pruout_pin>; + pinctrl-6 = <&P8_44_pruin_pin>; + }; + + /* P8_45 (ZCZ ball R1) hdmi */ + P8_45_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P8_45_default_pin>; + pinctrl-1 = <&P8_45_gpio_pin>; + pinctrl-2 = <&P8_45_gpio_pu_pin>; + pinctrl-3 = <&P8_45_gpio_pd_pin>; + pinctrl-4 = <&P8_45_pwm_pin>; + pinctrl-5 = <&P8_45_pruout_pin>; + pinctrl-6 = <&P8_45_pruin_pin>; + }; + + /* P8_46 (ZCZ ball R2) hdmi */ + P8_46_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P8_46_default_pin>; + pinctrl-1 = <&P8_46_gpio_pin>; + pinctrl-2 = <&P8_46_gpio_pu_pin>; + pinctrl-3 = <&P8_46_gpio_pd_pin>; + pinctrl-4 = <&P8_46_pwm_pin>; + pinctrl-5 = <&P8_46_pruout_pin>; + pinctrl-6 = <&P8_46_pruin_pin>; + }; + + /************************/ + /* P9 Header */ + /************************/ + + /* P9_01 GND */ + + /* P9_02 GND */ + + /* P9_03 3V3 */ + + /* P9_04 3V3 */ + + /* P9_05 VDD_5V */ + + /* P9_06 VDD_5V */ + + /* P9_07 SYS_5V */ + + /* P9_08 SYS_5V */ + + /* P9_09 PWR_BUT */ + + /* P9_10 RSTn */ + + /* P9_11 (ZCZ ball T17) */ + P9_11_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart"; + pinctrl-0 = <&P9_11_default_pin>; + pinctrl-1 = <&P9_11_gpio_pin>; + pinctrl-2 = <&P9_11_gpio_pu_pin>; + pinctrl-3 = <&P9_11_gpio_pd_pin>; + pinctrl-4 = <&P9_11_uart_pin>; + }; + + /* P9_12 (ZCZ ball U18) */ + P9_12_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P9_12_default_pin>; + pinctrl-1 = <&P9_12_gpio_pin>; + pinctrl-2 = <&P9_12_gpio_pu_pin>; + pinctrl-3 = <&P9_12_gpio_pd_pin>; + }; + + /* P9_13 (ZCZ ball U17) */ + P9_13_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart"; + pinctrl-0 = <&P9_13_default_pin>; + pinctrl-1 = <&P9_13_gpio_pin>; + pinctrl-2 = <&P9_13_gpio_pu_pin>; + pinctrl-3 = <&P9_13_gpio_pd_pin>; + pinctrl-4 = <&P9_13_uart_pin>; + }; + + /* P9_14 (ZCZ ball U14) */ + P9_14_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P9_14_default_pin>; + pinctrl-1 = <&P9_14_gpio_pin>; + pinctrl-2 = <&P9_14_gpio_pu_pin>; + pinctrl-3 = <&P9_14_gpio_pd_pin>; + pinctrl-4 = <&P9_14_pwm_pin>; + }; + + /* P9_15 (ZCZ ball R13) */ + P9_15_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P9_15_default_pin>; + pinctrl-1 = <&P9_15_gpio_pin>; + pinctrl-2 = <&P9_15_gpio_pu_pin>; + pinctrl-3 = <&P9_15_gpio_pd_pin>; + pinctrl-4 = <&P9_15_pwm_pin>; + }; + + /* P9_16 (ZCZ ball T14) */ + P9_16_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P9_16_default_pin>; + pinctrl-1 = <&P9_16_gpio_pin>; + pinctrl-2 = <&P9_16_gpio_pu_pin>; + pinctrl-3 = <&P9_16_gpio_pd_pin>; + pinctrl-4 = <&P9_16_pwm_pin>; + }; + + /* P9_17 (ZCZ ball A16) */ + P9_17_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_cs", "i2c", "pwm", "pru_uart"; + pinctrl-0 = <&P9_17_default_pin>; + pinctrl-1 = <&P9_17_gpio_pin>; + pinctrl-2 = <&P9_17_gpio_pu_pin>; + pinctrl-3 = <&P9_17_gpio_pd_pin>; + pinctrl-4 = <&P9_17_spi_cs_pin>; + pinctrl-5 = <&P9_17_i2c_pin>; + pinctrl-6 = <&P9_17_pwm_pin>; + pinctrl-7 = <&P9_17_pru_uart_pin>; + }; + + /* P9_18 (ZCZ ball B16) */ + P9_18_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "i2c", "pwm", "pru_uart"; + pinctrl-0 = <&P9_18_default_pin>; + pinctrl-1 = <&P9_18_gpio_pin>; + pinctrl-2 = <&P9_18_gpio_pu_pin>; + pinctrl-3 = <&P9_18_gpio_pd_pin>; + pinctrl-4 = <&P9_18_spi_pin>; + pinctrl-5 = <&P9_18_i2c_pin>; + pinctrl-6 = <&P9_18_pwm_pin>; + pinctrl-7 = <&P9_18_pru_uart_pin>; + }; + + /* P9_19 (ZCZ ball D17) i2c */ + P9_19_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_cs", "can", "i2c", "pru_uart", "timer"; + pinctrl-0 = <&P9_19_default_pin>; + pinctrl-1 = <&P9_19_gpio_pin>; + pinctrl-2 = <&P9_19_gpio_pu_pin>; + pinctrl-3 = <&P9_19_gpio_pd_pin>; + pinctrl-4 = <&P9_19_spi_cs_pin>; + pinctrl-5 = <&P9_19_can_pin>; + pinctrl-6 = <&P9_19_i2c_pin>; + pinctrl-7 = <&P9_19_pru_uart_pin>; + pinctrl-8 = <&P9_19_timer_pin>; + }; + + /* P9_20 (ZCZ ball D18) i2c */ + P9_20_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_cs", "can", "i2c", "pru_uart", "timer"; + pinctrl-0 = <&P9_20_default_pin>; + pinctrl-1 = <&P9_20_gpio_pin>; + pinctrl-2 = <&P9_20_gpio_pu_pin>; + pinctrl-3 = <&P9_20_gpio_pd_pin>; + pinctrl-4 = <&P9_20_spi_cs_pin>; + pinctrl-5 = <&P9_20_can_pin>; + pinctrl-6 = <&P9_20_i2c_pin>; + pinctrl-7 = <&P9_20_pru_uart_pin>; + pinctrl-8 = <&P9_20_timer_pin>; + }; + + /* P9_21 (ZCZ ball B17) */ + P9_21_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "uart", "i2c", "pwm", "pru_uart"; + pinctrl-0 = <&P9_21_default_pin>; + pinctrl-1 = <&P9_21_gpio_pin>; + pinctrl-2 = <&P9_21_gpio_pu_pin>; + pinctrl-3 = <&P9_21_gpio_pd_pin>; + pinctrl-4 = <&P9_21_spi_pin>; + pinctrl-5 = <&P9_21_uart_pin>; + pinctrl-6 = <&P9_21_i2c_pin>; + pinctrl-7 = <&P9_21_pwm_pin>; + pinctrl-8 = <&P9_21_pru_uart_pin>; + }; + + /* P9_22 (ZCZ ball A17) */ + P9_22_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_sclk", "uart", "i2c", "pwm", "pru_uart"; + pinctrl-0 = <&P9_22_default_pin>; + pinctrl-1 = <&P9_22_gpio_pin>; + pinctrl-2 = <&P9_22_gpio_pu_pin>; + pinctrl-3 = <&P9_22_gpio_pd_pin>; + pinctrl-4 = <&P9_22_spi_sclk_pin>; + pinctrl-5 = <&P9_22_uart_pin>; + pinctrl-6 = <&P9_22_i2c_pin>; + pinctrl-7 = <&P9_22_pwm_pin>; + pinctrl-8 = <&P9_22_pru_uart_pin>; + }; + + /* P9_23 (ZCZ ball V14) */ + P9_23_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P9_23_default_pin>; + pinctrl-1 = <&P9_23_gpio_pin>; + pinctrl-2 = <&P9_23_gpio_pu_pin>; + pinctrl-3 = <&P9_23_gpio_pd_pin>; + pinctrl-4 = <&P9_23_pwm_pin>; + }; + + /* P9_24 (ZCZ ball D15) */ + P9_24_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "can", "i2c", "pru_uart", "pruin"; + pinctrl-0 = <&P9_24_default_pin>; + pinctrl-1 = <&P9_24_gpio_pin>; + pinctrl-2 = <&P9_24_gpio_pu_pin>; + pinctrl-3 = <&P9_24_gpio_pd_pin>; + pinctrl-4 = <&P9_24_uart_pin>; + pinctrl-5 = <&P9_24_can_pin>; + pinctrl-6 = <&P9_24_i2c_pin>; + pinctrl-7 = <&P9_24_pru_uart_pin>; + pinctrl-8 = <&P9_24_pruin_pin>; + }; + + /* P9_25 (ZCZ ball A14) audio */ + P9_25_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P9_25_default_pin>; + pinctrl-1 = <&P9_25_gpio_pin>; + pinctrl-2 = <&P9_25_gpio_pu_pin>; + pinctrl-3 = <&P9_25_gpio_pd_pin>; + pinctrl-4 = <&P9_25_eqep_pin>; + pinctrl-5 = <&P9_25_pruout_pin>; + pinctrl-6 = <&P9_25_pruin_pin>; + }; + + /* P9_26 (ZCZ ball D16) */ + P9_26_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "can", "i2c", "pru_uart", "pruin"; + pinctrl-0 = <&P9_26_default_pin>; + pinctrl-1 = <&P9_26_gpio_pin>; + pinctrl-2 = <&P9_26_gpio_pu_pin>; + pinctrl-3 = <&P9_26_gpio_pd_pin>; + pinctrl-4 = <&P9_26_uart_pin>; + pinctrl-5 = <&P9_26_can_pin>; + pinctrl-6 = <&P9_26_i2c_pin>; + pinctrl-7 = <&P9_26_pru_uart_pin>; + pinctrl-8 = <&P9_26_pruin_pin>; + }; + + /* P9_27 (ZCZ ball C13) */ + P9_27_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P9_27_default_pin>; + pinctrl-1 = <&P9_27_gpio_pin>; + pinctrl-2 = <&P9_27_gpio_pu_pin>; + pinctrl-3 = <&P9_27_gpio_pd_pin>; + pinctrl-4 = <&P9_27_eqep_pin>; + pinctrl-5 = <&P9_27_pruout_pin>; + pinctrl-6 = <&P9_27_pruin_pin>; + }; + + /* P9_28 (ZCZ ball C12) audio */ + P9_28_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_cs", "pwm", "pwm2", "pruout", "pruin"; + pinctrl-0 = <&P9_28_default_pin>; + pinctrl-1 = <&P9_28_gpio_pin>; + pinctrl-2 = <&P9_28_gpio_pu_pin>; + pinctrl-3 = <&P9_28_gpio_pd_pin>; + pinctrl-4 = <&P9_28_spi_cs_pin>; + pinctrl-5 = <&P9_28_pwm_pin>; + pinctrl-6 = <&P9_28_pwm2_pin>; + pinctrl-7 = <&P9_28_pruout_pin>; + pinctrl-8 = <&P9_28_pruin_pin>; + }; + + /* P9_29 (ZCZ ball B13) audio */ + P9_29_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P9_29_default_pin>; + pinctrl-1 = <&P9_29_gpio_pin>; + pinctrl-2 = <&P9_29_gpio_pu_pin>; + pinctrl-3 = <&P9_29_gpio_pd_pin>; + pinctrl-4 = <&P9_29_spi_pin>; + pinctrl-5 = <&P9_29_pwm_pin>; + pinctrl-6 = <&P9_29_pruout_pin>; + pinctrl-7 = <&P9_29_pruin_pin>; + }; + + /* P9_30 (ZCZ ball D12) */ + P9_30_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P9_30_default_pin>; + pinctrl-1 = <&P9_30_gpio_pin>; + pinctrl-2 = <&P9_30_gpio_pu_pin>; + pinctrl-3 = <&P9_30_gpio_pd_pin>; + pinctrl-4 = <&P9_30_spi_pin>; + pinctrl-5 = <&P9_30_pwm_pin>; + pinctrl-6 = <&P9_30_pruout_pin>; + pinctrl-7 = <&P9_30_pruin_pin>; + }; + + /* P9_31 (ZCZ ball A13) audio */ + P9_31_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_sclk", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P9_31_default_pin>; + pinctrl-1 = <&P9_31_gpio_pin>; + pinctrl-2 = <&P9_31_gpio_pu_pin>; + pinctrl-3 = <&P9_31_gpio_pd_pin>; + pinctrl-4 = <&P9_31_spi_sclk_pin>; + pinctrl-5 = <&P9_31_pwm_pin>; + pinctrl-6 = <&P9_31_pruout_pin>; + pinctrl-7 = <&P9_31_pruin_pin>; + }; + + /* P9_32 VADC */ + + /* P9_33 (ZCZ ball C8) AIN4 */ + + /* P9_34 AGND */ + + /* P9_35 (ZCZ ball A8) AIN6 */ + + /* P9_36 (ZCZ ball B8) AIN5 */ + + /* P9_37 (ZCZ ball B7) AIN2 */ + + /* P9_38 (ZCZ ball A7) AIN3 */ + + /* P9_39 (ZCZ ball B6) AIN0 */ + + /* P9_40 (ZCZ ball C7) AIN1 */ + + /* P9_41 (ZCZ ball D14) */ + P9_41_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer", "pruin"; + pinctrl-0 = <&P9_41_default_pin>; + pinctrl-1 = <&P9_41_gpio_pin>; + pinctrl-2 = <&P9_41_gpio_pu_pin>; + pinctrl-3 = <&P9_41_gpio_pd_pin>; + pinctrl-4 = <&P9_41_timer_pin>; + pinctrl-5 = <&P9_41_pruin_pin>; + }; + + /* P9_41.1 */ + /* P9_91 (ZCZ ball D13) */ + P9_91_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P9_91_default_pin>; + pinctrl-1 = <&P9_91_gpio_pin>; + pinctrl-2 = <&P9_91_gpio_pu_pin>; + pinctrl-3 = <&P9_91_gpio_pd_pin>; + pinctrl-4 = <&P9_91_eqep_pin>; + pinctrl-5 = <&P9_91_pruout_pin>; + pinctrl-6 = <&P9_91_pruin_pin>; + }; + + /* P9_42 (ZCZ ball C18) */ + P9_42_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_cs", "spi_sclk", "uart", "pwm", "pru_ecap_pwm"; + pinctrl-0 = <&P9_42_default_pin>; + pinctrl-1 = <&P9_42_gpio_pin>; + pinctrl-2 = <&P9_42_gpio_pu_pin>; + pinctrl-3 = <&P9_42_gpio_pd_pin>; + pinctrl-4 = <&P9_42_spi_cs_pin>; + pinctrl-5 = <&P9_42_spi_sclk_pin>; + pinctrl-6 = <&P9_42_uart_pin>; + pinctrl-7 = <&P9_42_pwm_pin>; + pinctrl-8 = <&P9_42_pru_ecap_pwm_pin>; + }; + + /* P9_42.1 */ + /* P9_92 (ZCZ ball B12) */ + P9_92_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P9_92_default_pin>; + pinctrl-1 = <&P9_92_gpio_pin>; + pinctrl-2 = <&P9_92_gpio_pu_pin>; + pinctrl-3 = <&P9_92_gpio_pd_pin>; + pinctrl-4 = <&P9_92_eqep_pin>; + pinctrl-5 = <&P9_92_pruout_pin>; + pinctrl-6 = <&P9_92_pruin_pin>; + }; + + /* P9_43 GND */ + + /* P9_44 GND */ + + /* P9_45 GND */ + + /* P9_46 GND */ + + cape-universal { + compatible = "gpio-of-helper"; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + + P8_03 { + gpio-name = "P8_03"; + gpio = <&gpio1 6 0>; + input; + dir-changeable; + }; + + P8_04 { + gpio-name = "P8_04"; + gpio = <&gpio1 7 0>; + input; + dir-changeable; + }; + + P8_05 { + gpio-name = "P8_05"; + gpio = <&gpio1 2 0>; + input; + dir-changeable; + }; + + P8_06 { + gpio-name = "P8_06"; + gpio = <&gpio1 3 0>; + input; + dir-changeable; + }; + + P8_07 { + gpio-name = "P8_07"; + gpio = <&gpio2 2 0>; + input; + dir-changeable; + }; + + P8_08 { + gpio-name = "P8_08"; + gpio = <&gpio2 3 0>; + input; + dir-changeable; + }; + + P8_09 { + gpio-name = "P8_09"; + gpio = <&gpio2 5 0>; + input; + dir-changeable; + }; + + P8_10 { + gpio-name = "P8_10"; + gpio = <&gpio2 4 0>; + input; + dir-changeable; + }; + + P8_11 { + gpio-name = "P8_11"; + gpio = <&gpio1 13 0>; + input; + dir-changeable; + }; + + P8_12 { + gpio-name = "P8_12"; + gpio = <&gpio1 12 0>; + input; + dir-changeable; + }; + + P8_13 { + gpio-name = "P8_13"; + gpio = <&gpio0 23 0>; + input; + dir-changeable; + }; + + P8_14 { + gpio-name = "P8_14"; + gpio = <&gpio0 26 0>; + input; + dir-changeable; + }; + + P8_15 { + gpio-name = "P8_15"; + gpio = <&gpio1 15 0>; + input; + dir-changeable; + }; + + P8_16 { + gpio-name = "P8_16"; + gpio = <&gpio1 14 0>; + input; + dir-changeable; + }; + + P8_17 { + gpio-name = "P8_17"; + gpio = <&gpio0 27 0>; + input; + dir-changeable; + }; + + P8_18 { + gpio-name = "P8_18"; + gpio = <&gpio2 1 0>; + input; + dir-changeable; + }; + + P8_19 { + gpio-name = "P8_19"; + gpio = <&gpio0 22 0>; + input; + dir-changeable; + }; + + P8_20 { + gpio-name = "P8_20"; + gpio = <&gpio1 31 0>; + input; + dir-changeable; + }; + + P8_21 { + gpio-name = "P8_21"; + gpio = <&gpio1 30 0>; + input; + dir-changeable; + }; + + P8_22 { + gpio-name = "P8_22"; + gpio = <&gpio1 5 0>; + input; + dir-changeable; + }; + + P8_23 { + gpio-name = "P8_23"; + gpio = <&gpio1 4 0>; + input; + dir-changeable; + }; + + P8_24 { + gpio-name = "P8_24"; + gpio = <&gpio1 1 0>; + input; + dir-changeable; + }; + + P8_25 { + gpio-name = "P8_25"; + gpio = <&gpio1 0 0>; + input; + dir-changeable; + }; + + P8_26 { + gpio-name = "P8_26"; + gpio = <&gpio1 29 0>; + input; + dir-changeable; + }; + + P8_27 { + gpio-name = "P8_27"; + gpio = <&gpio2 22 0>; + input; + dir-changeable; + }; + + P8_28 { + gpio-name = "P8_28"; + gpio = <&gpio2 24 0>; + input; + dir-changeable; + }; + + P8_29 { + gpio-name = "P8_29"; + gpio = <&gpio2 23 0>; + input; + dir-changeable; + }; + + P8_30 { + gpio-name = "P8_30"; + gpio = <&gpio2 25 0>; + input; + dir-changeable; + }; + + P8_31 { + gpio-name = "P8_31"; + gpio = <&gpio0 10 0>; + input; + dir-changeable; + }; + + P8_32 { + gpio-name = "P8_32"; + gpio = <&gpio0 11 0>; + input; + dir-changeable; + }; + + P8_33 { + gpio-name = "P8_33"; + gpio = <&gpio0 9 0>; + input; + dir-changeable; + }; + + P8_34 { + gpio-name = "P8_34"; + gpio = <&gpio2 17 0>; + input; + dir-changeable; + }; + + P8_35 { + gpio-name = "P8_35"; + gpio = <&gpio0 8 0>; + input; + dir-changeable; + }; + + P8_36 { + gpio-name = "P8_36"; + gpio = <&gpio2 16 0>; + input; + dir-changeable; + }; + + P8_37 { + gpio-name = "P8_37"; + gpio = <&gpio2 14 0>; + input; + dir-changeable; + }; + + P8_38 { + gpio-name = "P8_38"; + gpio = <&gpio2 15 0>; + input; + dir-changeable; + }; + + P8_39 { + gpio-name = "P8_39"; + gpio = <&gpio2 12 0>; + input; + dir-changeable; + }; + + P8_40 { + gpio-name = "P8_40"; + gpio = <&gpio2 13 0>; + input; + dir-changeable; + }; + + P8_41 { + gpio-name = "P8_41"; + gpio = <&gpio2 10 0>; + input; + dir-changeable; + }; + + P8_42 { + gpio-name = "P8_42"; + gpio = <&gpio2 11 0>; + input; + dir-changeable; + }; + + P8_43 { + gpio-name = "P8_43"; + gpio = <&gpio2 8 0>; + input; + dir-changeable; + }; + + P8_44 { + gpio-name = "P8_44"; + gpio = <&gpio2 9 0>; + input; + dir-changeable; + }; + + P8_45 { + gpio-name = "P8_45"; + gpio = <&gpio2 6 0>; + input; + dir-changeable; + }; + + P8_46 { + gpio-name = "P8_46"; + gpio = <&gpio2 7 0>; + input; + dir-changeable; + }; + + P9_11 { + gpio-name = "P9_11"; + gpio = <&gpio0 30 0>; + input; + dir-changeable; + }; + + P9_12 { + gpio-name = "P9_12"; + gpio = <&gpio1 28 0>; + input; + dir-changeable; + }; + + P9_13 { + gpio-name = "P9_13"; + gpio = <&gpio0 31 0>; + input; + dir-changeable; + }; + + P9_14 { + gpio-name = "P9_14"; + gpio = <&gpio1 18 0>; + input; + dir-changeable; + }; + + P9_15 { + gpio-name = "P9_15"; + gpio = <&gpio1 16 0>; + input; + dir-changeable; + }; + + P9_16 { + gpio-name = "P9_16"; + gpio = <&gpio1 19 0>; + input; + dir-changeable; + }; + + P9_17 { + gpio-name = "P9_17"; + gpio = <&gpio0 5 0>; + input; + dir-changeable; + }; + + P9_18 { + gpio-name = "P9_18"; + gpio = <&gpio0 4 0>; + input; + dir-changeable; + }; + + P9_19 { + gpio-name = "P9_19"; + gpio = <&gpio0 13 0>; + input; + dir-changeable; + }; + + P9_20 { + gpio-name = "P9_20"; + gpio = <&gpio0 12 0>; + input; + dir-changeable; + }; + + P9_21 { + gpio-name = "P9_21"; + gpio = <&gpio0 3 0>; + input; + dir-changeable; + }; + + P9_22 { + gpio-name = "P9_22"; + gpio = <&gpio0 2 0>; + input; + dir-changeable; + }; + + P9_23 { + gpio-name = "P9_23"; + gpio = <&gpio1 17 0>; + input; + dir-changeable; + }; + + P9_24 { + gpio-name = "P9_24"; + gpio = <&gpio0 15 0>; + input; + dir-changeable; + }; + + P9_25 { + gpio-name = "P9_25"; + gpio = <&gpio3 21 0>; + input; + dir-changeable; + }; + + P9_26 { + gpio-name = "P9_26"; + gpio = <&gpio0 14 0>; + input; + dir-changeable; + }; + + P9_27 { + gpio-name = "P9_27"; + gpio = <&gpio3 19 0>; + input; + dir-changeable; + }; + + P9_28 { + gpio-name = "P9_28"; + gpio = <&gpio3 17 0>; + input; + dir-changeable; + }; + + P9_29 { + gpio-name = "P9_29"; + gpio = <&gpio3 15 0>; + input; + dir-changeable; + }; + + P9_30 { + gpio-name = "P9_30"; + gpio = <&gpio3 16 0>; + input; + dir-changeable; + }; + + P9_31 { + gpio-name = "P9_31"; + gpio = <&gpio3 14 0>; + input; + dir-changeable; + }; + + P9_41 { + gpio-name = "P9_41"; + gpio = <&gpio0 20 0>; + input; + dir-changeable; + }; + + P9_91 { + gpio-name = "P9_91"; + gpio = <&gpio3 20 0>; + input; + dir-changeable; + }; + + P9_42 { + gpio-name = "P9_42"; + gpio = <&gpio0 7 0>; + input; + dir-changeable; + }; + + P9_92 { + gpio-name = "P9_92"; + gpio = <&gpio3 18 0>; + input; + dir-changeable; + }; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-bone.dts b/arch/arm/boot/dts/ti/omap/am335x-bone.dts --- a/arch/arm/boot/dts/ti/omap/am335x-bone.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-bone.dts 2024-07-07 20:37:34.620306429 -0400 @@ -10,6 +10,11 @@ / { model = "TI AM335x BeagleBone"; compatible = "ti,am335x-bone", "ti,am33xx"; + + chosen { + base_dtb = "am335x-bone.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; }; &ldo3_reg { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-bonegreen-common.dtsi b/arch/arm/boot/dts/ti/omap/am335x-bonegreen-common.dtsi --- a/arch/arm/boot/dts/ti/omap/am335x-bonegreen-common.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-bonegreen-common.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -34,6 +34,7 @@ pinctrl-names = "default"; pinctrl-0 = <&uart2_pins>; status = "okay"; + symlink = "bone/uart/2"; }; &rtc { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-bonegreen.dts b/arch/arm/boot/dts/ti/omap/am335x-bonegreen.dts --- a/arch/arm/boot/dts/ti/omap/am335x-bonegreen.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-bonegreen.dts 2024-07-07 20:37:34.620306429 -0400 @@ -11,4 +11,157 @@ / { model = "TI AM335x BeagleBone Green"; compatible = "ti,am335x-bone-green", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + + chosen { + base_dtb = "am335x-bonegreen.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; }; + +&gpio0 { + gpio-line-names = + "[mdio_data]", + "[mdio_clk]", + "P9_22 [spi0_sclk]", + "P9_21 [spi0_d0]", + "P9_18 [spi0_d1]", + "P9_17 [spi0_cs0]", + "[mmc0_cd]", + "P9_42A [ecappwm0]", + "P8_35 [lcd d12]", + "P8_33 [lcd d13]", + "P8_31 [lcd d14]", + "P8_32 [lcd d15]", + "P9_20 [i2c2_sda]", + "P9_19 [i2c2_scl]", + "P9_26 [uart1_rxd]", + "P9_24 [uart1_txd]", + "[rmii1_txd3]", + "[rmii1_txd2]", + "[usb0_drvvbus]", + "[hdmi cec]", + "P9_41B", + "[rmii1_txd1]", + "P8_19 [ehrpwm2a]", + "P8_13 [ehrpwm2b]", + "NC", + "NC", + "P8_14", + "P8_17", + "[rmii1_txd0]", + "[rmii1_refclk]", + "P9_11 [uart4_rxd]", + "P9_13 [uart4_txd]"; +}; + +&gpio1 { + gpio-line-names = + "P8_25 [mmc1_dat0]", + "[mmc1_dat1]", + "P8_5 [mmc1_dat2]", + "P8_6 [mmc1_dat3]", + "P8_23 [mmc1_dat4]", + "P8_22 [mmc1_dat5]", + "P8_3 [mmc1_dat6]", + "P8_4 [mmc1_dat7]", + "NC", + "NC", + "NC", + "NC", + "P8_12", + "P8_11", + "P8_16", + "P8_15", + "P9_15A", + "P9_23", + "P9_14 [ehrpwm1a]", + "P9_16 [ehrpwm1b]", + "[emmc rst]", + "[usr0 led]", + "[usr1 led]", + "[usr2 led]", + "[usr3 led]", + "[hdmi irq]", + "[usb vbus oc]", + "[hdmi audio]", + "P9_12", + "P8_26", + "P8_21 [emmc]", + "P8_20 [emmc]"; +}; + +&gpio2 { + gpio-line-names = + "P9_15B", + "P8_18", + "P8_7", + "P8_8", + "P8_10", + "P8_9", + "P8_45", + "P8_46", + "P8_43", + "P8_44", + "P8_41", + "P8_42", + "P8_39", + "P8_40", + "P8_37", + "P8_38", + "P8_36", + "P8_34", + "[rmii1_rxd3]", + "[rmii1_rxd2]", + "[rmii1_rxd1]", + "[rmii1_rxd0]", + "P8_27", + "P8_29", + "P8_28", + "P8_30", + "[mmc0_dat3]", + "[mmc0_dat2]", + "[mmc0_dat1]", + "[mmc0_dat0]", + "[mmc0_clk]", + "[mmc0_cmd]"; +}; + +&gpio3 { + gpio-line-names = + "[mii col]", + "[mii crs]", + "[mii rx err]", + "[mii tx en]", + "[mii rx dv]", + "[i2c0 sda]", + "[i2c0 scl]", + "[jtag emu0]", + "[jtag emu1]", + "[mii tx clk]", + "[mii rx clk]", + "NC", + "NC", + "[usb vbus en]", + "P9_31 [spi1_sclk]", + "P9_29 [spi1_d0]", + "P9_30 [spi1_d1]", + "P9_28 [spi1_cs0]", + "P9_42B [ecappwm0]", + "P9_27", + "P9_41A", + "P9_25", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC", + "NC"; +}; + +&baseboard_eeprom { + vcc-supply = <&ldo4_reg>; +}; \ No newline at end of file diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-bonegreen-gateway.dts b/arch/arm/boot/dts/ti/omap/am335x-bonegreen-gateway.dts --- a/arch/arm/boot/dts/ti/omap/am335x-bonegreen-gateway.dts 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/am335x-bonegreen-gateway.dts 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ +/dts-v1/; + +#include "am33xx.dtsi" +#include "am335x-bone-common.dtsi" +#include "am335x-bonegreen-common.dtsi" +#include + +/ { + model = "SeeedStudio BeagleBone Green Gateway"; + compatible = "ti,am335x-bone-green-gateway", "ti,am335x-bone-green", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + + aliases { + rtc0 = &extrtc; + rtc1 = &rtc; + }; + + chosen { + base_dtb = "am335x-bonegreen-gateway.dts"; + base_dtb_timestamp = __TIMESTAMP__; + wl1835_bt = "S3-texas-300000"; + }; + + wlan_en_reg: fixedregulator@2 { + compatible = "regulator-fixed"; + regulator-name = "wlan-en-regulator"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + startup-delay-us= <70000>; + + /* WL_EN */ + gpio = <&gpio3 9 0>; + enable-active-high; + }; + + leds { + pinctrl-names = "default"; + //pinctrl-0 = <&user_leds_s0>; + pinctrl-0 = <&user_leds_s0 &bt_pins>; + + compatible = "gpio-leds"; + + led2 { + label = "beaglebone:green:usr0"; + gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + + led3 { + label = "beaglebone:green:usr1"; + gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc0"; + default-state = "off"; + }; + + led4 { + label = "beaglebone:green:usr2"; + gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "cpu0"; + default-state = "off"; + }; + + led5 { + label = "beaglebone:green:usr3"; + gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc1"; + default-state = "off"; + }; + + led6 { + label = "beaglebone:green:usr4"; + gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "netdev"; + default-state = "off"; + }; + + wl18xx_bt_en: led7 { + label = "wl18xx_bt_en"; + gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; +}; + +&cpu0_opp_table { + /* + * Octavo Systems: + * The EFUSE_SMA register is not programmed for any of the AM335x wafers + * we get and we are not programming them during our production test. + * Therefore, from a DEVICE_ID revision point of view, the silicon looks + * like it is Revision 2.1. However, from an EFUSE_SMA point of view for + * the HW OPP table, the silicon looks like it is Revision 1.0 (ie the + * EFUSE_SMA register reads as all zeros). + */ + oppnitro-1000000000 { + opp-supported-hw = <0x06 0x0100>; + }; +}; + +&am33xx_pinmux { + pinctrl-names = "default"; + pinctrl-0 = <&usbhost_pins>; + + user_leds_s0: user-leds-s0-pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a5.gpio1_21 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_a6.gpio1_22 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a7.gpio1_23 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_a8.gpio1_24 */ + AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_OUTPUT_PULLUP, MUX_MODE7) /* WL_Active_LED / USR4 */ + >; + }; + + bt_pins: bt-pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gmii1_txd0.gpio0_28 - BT_EN */ + >; + }; + + mmc3_pins: mmc3-pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLUP, MUX_MODE6 ) /* (L15) gmii1_rxd1.mmc2_clk */ + AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLUP, MUX_MODE6 ) /* (J16) gmii1_txen.mmc2_cmd */ + AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (J17) gmii1_rxdv.mmc2_dat0 */ + AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (J18) gmii1_txd3.mmc2_dat1 */ + AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (K15) gmii1_txd2.mmc2_dat2 */ + AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (H16) gmii1_col.mmc2_dat3 */ + >; + }; + + uart2_grove_pins: pinmux_uart2_grove_pins { + pinctrl-single,pins = < + AM33XX_IOPAD(0x90c, PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE6) + AM33XX_IOPAD(0x910, PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE6) + >; + }; + + uart3_pins: uart3-pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLUP, MUX_MODE1) /* gmii1_rxd3.uart3_rxd */ + AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE1) /* gmii1_rxd2.uart3_txd */ + AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT, MUX_MODE3) /* mdio_data.uart3_ctsn */ + AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLDOWN, MUX_MODE3) /* mdio_clk.uart3_rtsn */ + >; + }; + + usbhost_pins: pinmux_usbhost_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gmii1_txd1.gpio0[21] */ + >; + }; + + wl18xx_pins: wl18xx-pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gmii1_txclk.gpio3_9 WL_EN */ + AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7) /* rmii1_refclk.gpio0_29 WL_IRQ */ + AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gmii1_rxclk.gpio3_10 LS_BUF_EN */ + >; + }; +}; + +&mac_sw { + /delete-property/pinctrl-names; + /delete-property/pinctrl-0; + /delete-property/pinctrl-1; + status = "disabled"; +}; + +&mmc3 { + dmas = <&edma_xbar 12 0 1 + &edma_xbar 13 0 2>; + dma-names = "tx", "rx"; + status = "okay"; + vmmc-supply = <&wlan_en_reg>; + bus-width = <4>; + non-removable; + cap-power-off-card; + keep-power-in-suspend; + pinctrl-names = "default"; + pinctrl-0 = <&mmc3_pins &wl18xx_pins>; + + #address-cells = <1>; + #size-cells = <0>; + wlcore: wlcore@2 { + compatible = "ti,wl1835"; + reg = <2>; + interrupt-parent = <&gpio0>; + interrupts = <29 IRQ_TYPE_EDGE_RISING>; + }; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_grove_pins>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; + //pinctrl-0 = <&uart3_pins &bt_pins>; + status = "okay"; + + //bluetooth { + // compatible = "ti,wl1835-st"; + // enable-gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + //}; +}; + +&i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + extrtc: rtc@68 { + compatible = "dallas,ds1340"; + reg = <0x68>; + }; +}; + +// (K16) gmii1_txd1.gpio0[21] +&gpio0 { + usb-reset-hog { + gpio-hog; + gpios = <21 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "usb_reset"; + }; +}; + +&gpio3 { + ls-buf-en-hog { + gpio-hog; + gpios = <10 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "LS_BUF_EN"; + }; +}; + +&usb1 { + #address-cells = <1>; + #size-cells = <0>; + + hub@1 { + compatible = "usb424,9512"; + reg = <1>; + + #address-cells = <1>; + #size-cells = <0>; + + ethernet: ethernet@1 { + compatible = "usb424,ec00"; + reg = <1>; + }; + }; +}; + +&baseboard_eeprom { + vcc-supply = <&ldo4_reg>; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-bonegreen-wireless-common-univ.dtsi b/arch/arm/boot/dts/ti/omap/am335x-bonegreen-wireless-common-univ.dtsi --- a/arch/arm/boot/dts/ti/omap/am335x-bonegreen-wireless-common-univ.dtsi 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/am335x-bonegreen-wireless-common-univ.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,2197 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include + +&am33xx_pinmux { + +/* macro: BONE_PIN( , , */ +#define BONE_PIN(XX,ZZ,QQ) \ + XX##_##ZZ##_pin: pinmux_##XX##_##ZZ##_pin { pinctrl-single,pins = < QQ >; }; + + /************************/ + /* P8 Header */ + /************************/ + + /* P8_01 GND */ + + /* P8_02 GND */ + + + /* P8_03 (ZCZ ball R9) gpmc_ad6 (emmc) */ + BONE_PIN(P8_03, default, P8_03(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_03, gpio, P8_03(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_03, gpio_pu, P8_03(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_03, gpio_pd, P8_03(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_04 (ZCZ ball T9) gpmc_ad7 (emmc) */ + BONE_PIN(P8_04, default, P8_04(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_04, gpio, P8_04(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_04, gpio_pu, P8_04(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_04, gpio_pd, P8_04(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_05 (ZCZ ball R8) gpmc_ad2 (emmc) */ + BONE_PIN(P8_05, default, P8_05(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_05, gpio, P8_05(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_05, gpio_pu, P8_05(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_05, gpio_pd, P8_05(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_06 (ZCZ ball T8) gpmc_ad3 (emmc) */ + BONE_PIN(P8_06, default, P8_06(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_06, gpio, P8_06(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_06, gpio_pu, P8_06(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_06, gpio_pd, P8_06(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_07 (ZCZ ball R7) gpmc_advn_ale (gpio2_2) */ + BONE_PIN(P8_07, default, P8_07(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_07, gpio, P8_07(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_07, gpio_pu, P8_07(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_07, gpio_pd, P8_07(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_07, timer, P8_07(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_08 (ZCZ ball T7) gpmc_oen_ren (gpio2_3) */ + BONE_PIN(P8_08, default, P8_08(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_08, gpio, P8_08(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_08, gpio_pu, P8_08(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_08, gpio_pd, P8_08(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_08, timer, P8_08(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_09 (ZCZ ball T6) gpmc_be0n_cle (gpio2_5) */ + BONE_PIN(P8_09, default, P8_09(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_09, gpio, P8_09(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_09, gpio_pu, P8_09(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_09, gpio_pd, P8_09(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_09, timer, P8_09(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_10 (ZCZ ball U6) gpmc_wen (gpio2_4) */ + BONE_PIN(P8_10, default, P8_10(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_10, gpio, P8_10(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_10, gpio_pu, P8_10(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_10, gpio_pd, P8_10(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_10, timer, P8_10(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_11 (ZCZ ball R12) gpmc_ad13 (gpio1_13) */ + BONE_PIN(P8_11, default, P8_11(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_11, gpio, P8_11(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_11, gpio_pu, P8_11(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_11, gpio_pd, P8_11(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_11, eqep, P8_11(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P8_11, pruout, P8_11(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6)) + + /* P8_12 (ZCZ ball T12) gpmc_ad12 (gpio1_12) */ + BONE_PIN(P8_12, default, P8_12(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_12, gpio, P8_12(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_12, gpio_pu, P8_12(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_12, gpio_pd, P8_12(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_12, eqep, P8_12(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P8_12, pruout, P8_12(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6)) + + /* P8_13 (ZCZ ball T10) gpmc_ad9 (gpio0_23) */ + BONE_PIN(P8_13, default, P8_13(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_13, gpio, P8_13(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_13, gpio_pu, P8_13(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_13, gpio_pd, P8_13(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_13, pwm, P8_13(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE4)) + + /* P8_14 (ZCZ ball T11) wl1835: wl_en */ + + /* P8_15 (ZCZ ball U13) gpmc_ad15 (gpio1_15) */ + BONE_PIN(P8_15, default, P8_15(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_15, gpio, P8_15(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_15, gpio_pu, P8_15(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_15, gpio_pd, P8_15(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_15, eqep, P8_15(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P8_15, pru_ecap_pwm, P8_15(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_15, pruin, P8_15(PIN_INPUT | MUX_MODE6)) + + /* P8_16 (ZCZ ball V13) gpmc_ad14 (gpio1_14) */ + BONE_PIN(P8_16, default, P8_16(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_16, gpio, P8_16(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_16, gpio_pu, P8_16(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_16, gpio_pd, P8_16(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_16, eqep, P8_16(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P8_16, pruin, P8_16(PIN_INPUT | MUX_MODE6)) + + /* P8_17 (ZCZ ball U12) wl1835: wl_irq */ + + /* P8_18 (ZCZ ball V12) gpmc_clk (gpio2_1) */ + BONE_PIN(P8_18, default, P8_18(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_18, gpio, P8_18(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_18, gpio_pu, P8_18(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_18, gpio_pd, P8_18(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_19 (ZCZ ball U10) gpmc_ad8 (gpio0_22) */ + BONE_PIN(P8_19, default, P8_19(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_19, gpio, P8_19(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_19, gpio_pu, P8_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_19, gpio_pd, P8_19(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_19, pwm, P8_19(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE4)) + + /* P8_20 (ZCZ ball V9) gpmc_csn2 (emmc) */ + BONE_PIN(P8_20, default, P8_20(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_20, gpio, P8_20(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_20, gpio_pu, P8_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_20, gpio_pd, P8_20(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_20, pruout, P8_20(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_20, pruin, P8_20(PIN_INPUT | MUX_MODE6)) + + /* P8_21 (ZCZ ball U9) gpmc_csn1 (emmc) */ + BONE_PIN(P8_21, default, P8_21(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_21, gpio, P8_21(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_21, gpio_pu, P8_21(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_21, gpio_pd, P8_21(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_21, pruout, P8_21(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_21, pruin, P8_21(PIN_INPUT | MUX_MODE6)) + + /* P8_22 (ZCZ ball V8) gpmc_ad5 (emmc) */ + BONE_PIN(P8_22, default, P8_22(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_22, gpio, P8_22(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_22, gpio_pu, P8_22(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_22, gpio_pd, P8_22(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_23 (ZCZ ball U8) gpmc_ad4 (emmc) */ + BONE_PIN(P8_23, default, P8_23(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_23, gpio, P8_23(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_23, gpio_pu, P8_23(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_23, gpio_pd, P8_23(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_24 (ZCZ ball V7) gpmc_ad1 (emmc) */ + BONE_PIN(P8_24, default, P8_24(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_24, gpio, P8_24(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_24, gpio_pu, P8_24(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_24, gpio_pd, P8_24(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_25 (ZCZ ball U7) gpmc_ad0 (emmc) */ + BONE_PIN(P8_25, default, P8_25(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_25, gpio, P8_25(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_25, gpio_pu, P8_25(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_25, gpio_pd, P8_25(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P8_26 (ZCZ ball V6) gpio-hog wl1835 */ + + /* P8_27 (ZCZ ball U5) lcd_vsync (hdmi) */ + BONE_PIN(P8_27, default, P8_27(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_27, gpio, P8_27(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_27, gpio_pu, P8_27(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_27, gpio_pd, P8_27(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_27, pruout, P8_27(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_27, pruin, P8_27(PIN_INPUT | MUX_MODE6)) + + /* P8_28 (ZCZ ball V5) lcd_pclk (hdmi) */ + BONE_PIN(P8_28, default, P8_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_28, gpio, P8_28(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_28, gpio_pu, P8_28(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_28, gpio_pd, P8_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_28, pruout, P8_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_28, pruin, P8_28(PIN_INPUT | MUX_MODE6)) + + /* P8_29 (ZCZ ball R5) lcd_hsync (hdmi) */ + BONE_PIN(P8_29, default, P8_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_29, gpio, P8_29(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_29, gpio_pu, P8_29(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_29, gpio_pd, P8_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_29, pruout, P8_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_29, pruin, P8_29(PIN_INPUT | MUX_MODE6)) + + /* P8_30 (ZCZ ball R6) lcd_ac_bias_en (hdmi) */ + BONE_PIN(P8_30, default, P8_30(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_30, gpio, P8_30(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_30, gpio_pu, P8_30(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_30, gpio_pd, P8_30(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_30, pruout, P8_30(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_30, pruin, P8_30(PIN_INPUT | MUX_MODE6)) + + /* P8_31 (ZCZ ball V4) lcd_data14 (hdmi) */ + BONE_PIN(P8_31, default, P8_31(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_31, gpio, P8_31(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_31, gpio_pu, P8_31(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_31, gpio_pd, P8_31(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_31, eqep, P8_31(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + BONE_PIN(P8_31, uart, P8_31(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P8_32 (ZCZ ball T5) lcd_data15 (hdmi) */ + BONE_PIN(P8_32, default, P8_32(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_32, gpio, P8_32(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_32, gpio_pu, P8_32(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_32, gpio_pd, P8_32(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_32, eqep, P8_32(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_33 (ZCZ ball V3) lcd_data13 (hdmi) */ + BONE_PIN(P8_33, default, P8_33(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_33, gpio, P8_33(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_33, gpio_pu, P8_33(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_33, gpio_pd, P8_33(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_33, eqep, P8_33(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_34 (ZCZ ball U4) lcd_data11 (hdmi) */ + BONE_PIN(P8_34, default, P8_34(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_34, gpio, P8_34(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_34, gpio_pu, P8_34(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_34, gpio_pd, P8_34(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_34, pwm, P8_34(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE2)) + + /* P8_35 (ZCZ ball V2) lcd_data12 (hdmi) */ + BONE_PIN(P8_35, default, P8_35(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_35, gpio, P8_35(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_35, gpio_pu, P8_35(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_35, gpio_pd, P8_35(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_35, eqep, P8_35(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + + /* P8_36 (ZCZ ball U3) lcd_data10 (hdmi) */ + BONE_PIN(P8_36, default, P8_36(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_36, gpio, P8_36(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_36, gpio_pu, P8_36(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_36, gpio_pd, P8_36(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_36, pwm, P8_36(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE2)) + + /* P8_37 (ZCZ ball U1) lcd_data8 (hdmi) */ + BONE_PIN(P8_37, default, P8_37(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_37, gpio, P8_37(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_37, gpio_pu, P8_37(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_37, gpio_pd, P8_37(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_37, pwm, P8_37(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE2)) + BONE_PIN(P8_37, uart, P8_37(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P8_38 (ZCZ ball U2) lcd_data9 (hdmi) */ + BONE_PIN(P8_38, default, P8_38(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_38, gpio, P8_38(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_38, gpio_pu, P8_38(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_38, gpio_pd, P8_38(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_38, pwm, P8_38(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE2)) + BONE_PIN(P8_38, uart, P8_38(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P8_39 (ZCZ ball T3) lcd_data6 (hdmi) */ + BONE_PIN(P8_39, default, P8_39(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_39, gpio, P8_39(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_39, gpio_pu, P8_39(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_39, gpio_pd, P8_39(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_39, eqep, P8_39(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_39, pruout, P8_39(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_39, pruin, P8_39(PIN_INPUT | MUX_MODE6)) + + /* P8_40 (ZCZ ball T4) lcd_data7 (hdmi) */ + BONE_PIN(P8_40, default, P8_40(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_40, gpio, P8_40(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_40, gpio_pu, P8_40(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_40, gpio_pd, P8_40(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_40, eqep, P8_40(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_40, pruout, P8_40(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_40, pruin, P8_40(PIN_INPUT | MUX_MODE6)) + + /* P8_41 (ZCZ ball T1) lcd_data4 (hdmi) */ + BONE_PIN(P8_41, default, P8_41(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_41, gpio, P8_41(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_41, gpio_pu, P8_41(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_41, gpio_pd, P8_41(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_41, eqep, P8_41(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_41, pruout, P8_41(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_41, pruin, P8_41(PIN_INPUT | MUX_MODE6)) + + /* P8_42 (ZCZ ball T2) lcd_data5 (hdmi) */ + BONE_PIN(P8_42, default, P8_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_42, gpio, P8_42(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_42, gpio_pu, P8_42(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_42, gpio_pd, P8_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_42, eqep, P8_42(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_42, pruout, P8_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_42, pruin, P8_42(PIN_INPUT | MUX_MODE6)) + + /* P8_43 (ZCZ ball R3) lcd_data2 (hdmi) */ + BONE_PIN(P8_43, default, P8_43(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_43, gpio, P8_43(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_43, gpio_pu, P8_43(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_43, gpio_pd, P8_43(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_43, pwm, P8_43(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_43, pruout, P8_43(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_43, pruin, P8_43(PIN_INPUT | MUX_MODE6)) + + /* P8_44 (ZCZ ball R4) lcd_data3 (hdmi) */ + BONE_PIN(P8_44, default, P8_44(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_44, gpio, P8_44(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_44, gpio_pu, P8_44(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_44, gpio_pd, P8_44(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_44, pwm, P8_44(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_44, pruout, P8_44(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_44, pruin, P8_44(PIN_INPUT | MUX_MODE6)) + + /* P8_45 (ZCZ ball R1) lcd_data0 (hdmi) */ + BONE_PIN(P8_45, default, P8_45(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_45, gpio, P8_45(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_45, gpio_pu, P8_45(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_45, gpio_pd, P8_45(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_45, pwm, P8_45(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_45, pruout, P8_45(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_45, pruin, P8_45(PIN_INPUT | MUX_MODE6)) + + /* P8_46 (ZCZ ball R2) lcd_data1 (hdmi) */ + BONE_PIN(P8_46, default, P8_46(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_46, gpio, P8_46(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_46, gpio_pu, P8_46(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_46, gpio_pd, P8_46(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P8_46, pwm, P8_46(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P8_46, pruout, P8_46(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P8_46, pruin, P8_46(PIN_INPUT | MUX_MODE6)) + + /************************/ + /* P9 Header */ + /************************/ + + /* P9_01 GND */ + + /* P9_02 GND */ + + /* P9_03 3V3 */ + + /* P9_04 3V3 */ + + /* P9_05 VDD_5V */ + + /* P9_06 VDD_5V */ + + /* P9_07 SYS_5V */ + + /* P9_08 SYS_5V */ + + /* P9_09 PWR_BUT */ + + /* P9_10 RSTn */ + + /* P9_11 (ZCZ ball T17) gpmc_wait0 (gpio0_30) */ + BONE_PIN(P9_11, default, P9_11(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_11, gpio, P9_11(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_11, gpio_pu, P9_11(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_11, gpio_pd, P9_11(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_11, uart, P9_11(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE6)) + + /* P9_12 (ZCZ ball U18) gpmc_be1n (gpio1_28) */ + BONE_PIN(P9_12, default, P9_12(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_12, gpio, P9_12(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_12, gpio_pu, P9_12(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_12, gpio_pd, P9_12(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + + /* P9_13 (ZCZ ball U17) gpmc_wpn (gpio0_31) */ + BONE_PIN(P9_13, default, P9_13(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_13, gpio, P9_13(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_13, gpio_pu, P9_13(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_13, gpio_pd, P9_13(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_13, uart, P9_13(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE6)) + + /* P9_14 (ZCZ ball U14) gpmc_a2 (gpio1_18) */ + BONE_PIN(P9_14, default, P9_14(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_14, gpio, P9_14(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_14, gpio_pu, P9_14(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_14, gpio_pd, P9_14(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_14, pwm, P9_14(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6)) + + /* P9_15 (ZCZ ball R13) gpmc_a0 (gpio1_16) */ + BONE_PIN(P9_15, default, P9_15(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_15, gpio, P9_15(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_15, gpio_pu, P9_15(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_15, gpio_pd, P9_15(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_15, pwm, P9_15(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6)) + + /* P9_16 (ZCZ ball T14) gpmc_a3 (gpio1_19) */ + BONE_PIN(P9_16, default, P9_16(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_16, gpio, P9_16(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_16, gpio_pu, P9_16(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_16, gpio_pd, P9_16(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_16, pwm, P9_16(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6)) + + /* P9_17 (ZCZ ball A16) spi0_cs0 (gpio0_5) */ + BONE_PIN(P9_17, default, P9_17(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_17, gpio, P9_17(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_17, gpio_pu, P9_17(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_17, gpio_pd, P9_17(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_17, spi_cs, P9_17(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE0)) + BONE_PIN(P9_17, i2c, P9_17(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + BONE_PIN(P9_17, pwm, P9_17(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_17, pru_uart, P9_17(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P9_18 (ZCZ ball B16) spi0_d1 (gpio0_4) */ + BONE_PIN(P9_18, default, P9_18(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_18, gpio, P9_18(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_18, gpio_pu, P9_18(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_18, gpio_pd, P9_18(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_18, spi, P9_18(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE0)) + BONE_PIN(P9_18, i2c, P9_18(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + BONE_PIN(P9_18, pwm, P9_18(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_18, pru_uart, P9_18(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P9_19 (ZCZ ball D17) uart1_rtsn (i2c2_scl) */ + BONE_PIN(P9_19, default, P9_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_19, gpio, P9_19(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_19, gpio_pu, P9_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_19, gpio_pd, P9_19(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_19, timer, P9_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_19, can, P9_19(PIN_INPUT_PULLUP | MUX_MODE2)) + BONE_PIN(P9_19, i2c, P9_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_19, spi_cs, P9_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P9_19, pru_uart, P9_19(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE5)) + + /* P9_20 (ZCZ ball D18) uart1_ctsn (i2c2_sda) */ + BONE_PIN(P9_20, default, P9_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_20, gpio, P9_20(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_20, gpio_pu, P9_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_20, gpio_pd, P9_20(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_20, timer, P9_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_20, can, P9_20(PIN_OUTPUT_PULLUP | MUX_MODE2)) + BONE_PIN(P9_20, i2c, P9_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_20, spi_cs, P9_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P9_20, pru_uart, P9_20(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE5)) + + /* P9_21 (ZCZ ball B17) spi0_d0 (gpio0_3) */ + BONE_PIN(P9_21, default, P9_21(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_21, gpio, P9_21(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_21, gpio_pu, P9_21(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_21, gpio_pd, P9_21(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_21, spi, P9_21(PIN_INPUT_PULLUP | MUX_MODE0)) + BONE_PIN(P9_21, uart, P9_21(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_21, i2c, P9_21(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + BONE_PIN(P9_21, pwm, P9_21(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_21, pru_uart, P9_21(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P9_22 (ZCZ ball A17) spi0_sclk (gpio0_2) */ + BONE_PIN(P9_22, default, P9_22(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_22, gpio, P9_22(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_22, gpio_pu, P9_22(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_22, gpio_pd, P9_22(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_22, spi_sclk, P9_22(PIN_INPUT_PULLUP | MUX_MODE0)) + BONE_PIN(P9_22, uart, P9_22(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_22, i2c, P9_22(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + BONE_PIN(P9_22, pwm, P9_22(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_22, pru_uart, P9_22(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + + /* P9_23 (ZCZ ball V14) gpmc_a1 (gpio1_17) */ + BONE_PIN(P9_23, default, P9_23(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_23, gpio, P9_23(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_23, gpio_pu, P9_23(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_23, gpio_pd, P9_23(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_23, pwm, P9_23(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6)) + + /* P9_24 (ZCZ ball D15) uart1_txd (gpio0_15) */ + BONE_PIN(P9_24, default, P9_24(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_24, gpio, P9_24(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_24, gpio_pu, P9_24(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_24, gpio_pd, P9_24(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_24, uart, P9_24(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE0)) + BONE_PIN(P9_24, can, P9_24(PIN_INPUT_PULLUP | MUX_MODE2)) + BONE_PIN(P9_24, i2c, P9_24(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_24, pru_uart, P9_24(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_24, pruin, P9_24(PIN_INPUT | MUX_MODE6)) + + /* P9_25 (ZCZ ball A14) mcasp0_ahclkx (audio) */ + BONE_PIN(P9_25, default, P9_25(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_25, gpio, P9_25(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_25, gpio_pu, P9_25(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_25, gpio_pd, P9_25(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_25, eqep, P9_25(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_25, pruout, P9_25(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_25, pruin, P9_25(PIN_INPUT | MUX_MODE6)) + + /* P9_26 (ZCZ ball D16) uart1_rxd (gpio0_14) */ + BONE_PIN(P9_26, default, P9_26(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_26, gpio, P9_26(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_26, gpio_pu, P9_26(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_26, gpio_pd, P9_26(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_26, uart, P9_26(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE0)) + BONE_PIN(P9_26, can, P9_26(PIN_OUTPUT_PULLUP | MUX_MODE2)) + BONE_PIN(P9_26, i2c, P9_26(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_26, pru_uart, P9_26(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_26, pruin, P9_26(PIN_INPUT | MUX_MODE6)) + + /* P9_27 (ZCZ ball C13) mcasp0_fsr (gpio3_19) */ + BONE_PIN(P9_27, default, P9_27(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_27, gpio, P9_27(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_27, gpio_pu, P9_27(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_27, gpio_pd, P9_27(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_27, eqep, P9_27(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_27, pruout, P9_27(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_27, pruin, P9_27(PIN_INPUT | MUX_MODE6)) + + /* P9_28 (ZCZ ball C12) mcasp0_ahclkr (audio) */ + BONE_PIN(P9_28, default, P9_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_28, gpio, P9_28(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_28, gpio_pu, P9_28(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_28, gpio_pd, P9_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_28, pwm, P9_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_28, spi_cs, P9_28(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_28, pwm2, P9_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE4)) + BONE_PIN(P9_28, pruout, P9_28(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_28, pruin, P9_28(PIN_INPUT | MUX_MODE6)) + + /* P9_29 (ZCZ ball B13) mcasp0_fsx (audio) */ + BONE_PIN(P9_29, default, P9_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_29, gpio, P9_29(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_29, gpio_pu, P9_29(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_29, gpio_pd, P9_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_29, pwm, P9_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_29, spi, P9_29(PIN_INPUT_PULLUP | MUX_MODE3)) + BONE_PIN(P9_29, pruout, P9_29(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_29, pruin, P9_29(PIN_INPUT | MUX_MODE6)) + + /* P9_30 (ZCZ ball D12) gpio-hog wl1835 */ + + /* P9_31 (ZCZ ball A13) mcasp0_aclkx (audio) */ + BONE_PIN(P9_31, default, P9_31(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_31, gpio, P9_31(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_31, gpio_pu, P9_31(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_31, gpio_pd, P9_31(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_31, pwm, P9_31(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_31, spi_sclk, P9_31(PIN_INPUT_PULLUP | MUX_MODE3)) + BONE_PIN(P9_31, pruout, P9_31(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_31, pruin, P9_31(PIN_INPUT | MUX_MODE6)) + + /* P9_32 VADC */ + + /* P9_33 (ZCZ ball C8) AIN4 */ + + /* P9_34 AGND */ + + /* P9_35 (ZCZ ball A8) AIN6 */ + + /* P9_36 (ZCZ ball B8) AIN5 */ + + /* P9_37 (ZCZ ball B7) AIN2 */ + + /* P9_38 (ZCZ ball A7) AIN3 */ + + /* P9_39 (ZCZ ball B6) AIN0 */ + + /* P9_40 (ZCZ ball C7) AIN1 */ + + /* P9_41 (ZCZ ball D14) xdma_event_intr1 (gpio0_20) */ + BONE_PIN(P9_41, default, P9_41(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_41, gpio, P9_41(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_41, gpio_pu, P9_41(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_41, gpio_pd, P9_41(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_41, timer, P9_41(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4)) + BONE_PIN(P9_41, pruin, P9_41(PIN_INPUT | MUX_MODE5)) + + /* P9_41.1 */ + /* P9_91 (ZCZ ball D13) mcasp0_axr1 (gpio3_20) */ + BONE_PIN(P9_91, default, P9_91(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_91, gpio, P9_91(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_91, gpio_pu, P9_91(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_91, gpio_pd, P9_91(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_91, eqep, P9_91(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_91, pruout, P9_91(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_91, pruin, P9_91(PIN_INPUT | MUX_MODE6)) + + /* P9_42 (ZCZ ball C18) eCAP0_in_PWM0_out (gpio0_7) */ + BONE_PIN(P9_42, default, P9_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_42, gpio, P9_42(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_42, gpio_pu, P9_42(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_42, gpio_pd, P9_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_42, pwm, P9_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE0)) + BONE_PIN(P9_42, uart, P9_42(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_42, spi_cs, P9_42(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE2)) + BONE_PIN(P9_42, pru_ecap_pwm, P9_42(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE3)) + BONE_PIN(P9_42, spi_sclk, P9_42(PIN_INPUT_PULLUP | MUX_MODE4)) + + /* P9_42.1 */ + /* P9_92 (ZCZ ball B12) mcasp0_aclkr (gpio3_18) */ + BONE_PIN(P9_92, default, P9_92(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_92, gpio, P9_92(PIN_OUTPUT | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_92, gpio_pu, P9_92(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_92, gpio_pd, P9_92(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7)) + BONE_PIN(P9_92, eqep, P9_92(PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE1)) + BONE_PIN(P9_92, pruout, P9_92(PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5)) + BONE_PIN(P9_92, pruin, P9_92(PIN_INPUT | MUX_MODE6)) + + /* P9_43 GND */ + + /* P9_44 GND */ + + /* P9_45 GND */ + + /* P9_46 GND */ +}; + +&i2c1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + + clock-frequency = <100000>; + symlink = "bone/i2c/1"; +}; + +&i2c2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + + clock-frequency = <100000>; + symlink = "bone/i2c/2"; +}; + +&uart1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/uart/1"; +}; + +&uart2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/uart/2"; +}; + +&uart3 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/uart/3"; +}; + +&uart4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/uart/4"; +}; + +&uart5 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/uart/5"; +}; + +&dcan0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/can/0"; +}; + +&dcan1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/can/1"; +}; + +&eqep0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/eqep/0"; +}; + +&eqep1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/eqep/1"; +}; + +&eqep2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + symlink = "bone/eqep/2"; +}; + +&epwmss0 { + status = "okay"; +}; + +&epwmss1 { + status = "okay"; +}; + +&epwmss2 { + status = "okay"; +}; + +&ehrpwm0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; +}; + +&ehrpwm1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; +}; + +&ehrpwm2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; +}; + +&ecap0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; +}; + +&ecap1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; +}; + +&ecap2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; +}; + +&spi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + + channel@0 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "rohm,dh2228fv"; + symlink = "bone/spi/0.0"; + + reg = <0>; + spi-max-frequency = <16000000>; + spi-cpha; + }; + + channel@1 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "rohm,dh2228fv"; + symlink = "bone/spi/0.1"; + + reg = <1>; + spi-max-frequency = <16000000>; + }; +}; + +&spi1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + + channel@0 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "rohm,dh2228fv"; + symlink = "bone/spi/1.0"; + + reg = <0>; + spi-max-frequency = <16000000>; + spi-cpha; + }; + + channel@1 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "rohm,dh2228fv"; + symlink = "bone/spi/1.1"; + + reg = <1>; + spi-max-frequency = <16000000>; + }; +}; + +/**********************************************************************/ +/* Pin Multiplex Helpers */ +/* */ +/* These provide userspace runtime pin configuration for the */ +/* BeagleBone cape expansion headers */ +/**********************************************************************/ + +&ocp { + /************************/ + /* P8 Header */ + /************************/ + + /* P8_01 GND */ + + /* P8_02 GND */ + + + /* P8_03 (ZCZ ball R9) emmc */ + P8_03_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_03_default_pin>; + pinctrl-1 = <&P8_03_gpio_pin>; + pinctrl-2 = <&P8_03_gpio_pu_pin>; + pinctrl-3 = <&P8_03_gpio_pd_pin>; + }; + + /* P8_04 (ZCZ ball T9) emmc */ + P8_04_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_04_default_pin>; + pinctrl-1 = <&P8_04_gpio_pin>; + pinctrl-2 = <&P8_04_gpio_pu_pin>; + pinctrl-3 = <&P8_04_gpio_pd_pin>; + }; + + /* P8_05 (ZCZ ball R8) emmc */ + P8_05_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_05_default_pin>; + pinctrl-1 = <&P8_05_gpio_pin>; + pinctrl-2 = <&P8_05_gpio_pu_pin>; + pinctrl-3 = <&P8_05_gpio_pd_pin>; + }; + + /* P8_06 (ZCZ ball T8) emmc */ + P8_06_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_06_default_pin>; + pinctrl-1 = <&P8_06_gpio_pin>; + pinctrl-2 = <&P8_06_gpio_pu_pin>; + pinctrl-3 = <&P8_06_gpio_pd_pin>; + }; + + /* P8_07 (ZCZ ball R7) */ + P8_07_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer"; + pinctrl-0 = <&P8_07_default_pin>; + pinctrl-1 = <&P8_07_gpio_pin>; + pinctrl-2 = <&P8_07_gpio_pu_pin>; + pinctrl-3 = <&P8_07_gpio_pd_pin>; + pinctrl-4 = <&P8_07_timer_pin>; + }; + + /* P8_08 (ZCZ ball T7) */ + P8_08_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer"; + pinctrl-0 = <&P8_08_default_pin>; + pinctrl-1 = <&P8_08_gpio_pin>; + pinctrl-2 = <&P8_08_gpio_pu_pin>; + pinctrl-3 = <&P8_08_gpio_pd_pin>; + pinctrl-4 = <&P8_08_timer_pin>; + }; + + /* P8_09 (ZCZ ball T6) */ + P8_09_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer"; + pinctrl-0 = <&P8_09_default_pin>; + pinctrl-1 = <&P8_09_gpio_pin>; + pinctrl-2 = <&P8_09_gpio_pu_pin>; + pinctrl-3 = <&P8_09_gpio_pd_pin>; + pinctrl-4 = <&P8_09_timer_pin>; + }; + + /* P8_10 (ZCZ ball U6) */ + P8_10_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer"; + pinctrl-0 = <&P8_10_default_pin>; + pinctrl-1 = <&P8_10_gpio_pin>; + pinctrl-2 = <&P8_10_gpio_pu_pin>; + pinctrl-3 = <&P8_10_gpio_pd_pin>; + pinctrl-4 = <&P8_10_timer_pin>; + }; + + /* P8_11 (ZCZ ball R12) */ + P8_11_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout"; + pinctrl-0 = <&P8_11_default_pin>; + pinctrl-1 = <&P8_11_gpio_pin>; + pinctrl-2 = <&P8_11_gpio_pu_pin>; + pinctrl-3 = <&P8_11_gpio_pd_pin>; + pinctrl-4 = <&P8_11_eqep_pin>; + pinctrl-5 = <&P8_11_pruout_pin>; + }; + + /* P8_12 (ZCZ ball T12) */ + P8_12_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout"; + pinctrl-0 = <&P8_12_default_pin>; + pinctrl-1 = <&P8_12_gpio_pin>; + pinctrl-2 = <&P8_12_gpio_pu_pin>; + pinctrl-3 = <&P8_12_gpio_pd_pin>; + pinctrl-4 = <&P8_12_eqep_pin>; + pinctrl-5 = <&P8_12_pruout_pin>; + }; + + /* P8_13 (ZCZ ball T10) */ + P8_13_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P8_13_default_pin>; + pinctrl-1 = <&P8_13_gpio_pin>; + pinctrl-2 = <&P8_13_gpio_pu_pin>; + pinctrl-3 = <&P8_13_gpio_pd_pin>; + pinctrl-4 = <&P8_13_pwm_pin>; + }; + + /* P8_14 (ZCZ ball T11) wl1835: wl_en */ + + /* P8_15 (ZCZ ball U13) */ + P8_15_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pru_ecap_pwm", "pruin"; + pinctrl-0 = <&P8_15_default_pin>; + pinctrl-1 = <&P8_15_gpio_pin>; + pinctrl-2 = <&P8_15_gpio_pu_pin>; + pinctrl-3 = <&P8_15_gpio_pd_pin>; + pinctrl-4 = <&P8_15_eqep_pin>; + pinctrl-5 = <&P8_15_pru_ecap_pwm_pin>; + pinctrl-6 = <&P8_15_pruin_pin>; + }; + + /* P8_16 (ZCZ ball V13) */ + P8_16_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruin"; + pinctrl-0 = <&P8_16_default_pin>; + pinctrl-1 = <&P8_16_gpio_pin>; + pinctrl-2 = <&P8_16_gpio_pu_pin>; + pinctrl-3 = <&P8_16_gpio_pd_pin>; + pinctrl-4 = <&P8_16_eqep_pin>; + pinctrl-5 = <&P8_16_pruin_pin>; + }; + + /* P8_17 (ZCZ ball U12) wl1835: wl_irq */ + + /* P8_18 (ZCZ ball V12) */ + P8_18_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_18_default_pin>; + pinctrl-1 = <&P8_18_gpio_pin>; + pinctrl-2 = <&P8_18_gpio_pu_pin>; + pinctrl-3 = <&P8_18_gpio_pd_pin>; + }; + + /* P8_19 (ZCZ ball U10) */ + P8_19_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P8_19_default_pin>; + pinctrl-1 = <&P8_19_gpio_pin>; + pinctrl-2 = <&P8_19_gpio_pu_pin>; + pinctrl-3 = <&P8_19_gpio_pd_pin>; + pinctrl-4 = <&P8_19_pwm_pin>; + }; + + /* P8_20 (ZCZ ball V9) emmc */ + P8_20_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin"; + pinctrl-0 = <&P8_20_default_pin>; + pinctrl-1 = <&P8_20_gpio_pin>; + pinctrl-2 = <&P8_20_gpio_pu_pin>; + pinctrl-3 = <&P8_20_gpio_pd_pin>; + pinctrl-4 = <&P8_20_pruout_pin>; + pinctrl-5 = <&P8_20_pruin_pin>; + }; + + /* P8_21 (ZCZ ball U9) emmc */ + P8_21_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin"; + pinctrl-0 = <&P8_21_default_pin>; + pinctrl-1 = <&P8_21_gpio_pin>; + pinctrl-2 = <&P8_21_gpio_pu_pin>; + pinctrl-3 = <&P8_21_gpio_pd_pin>; + pinctrl-4 = <&P8_21_pruout_pin>; + pinctrl-5 = <&P8_21_pruin_pin>; + }; + + /* P8_22 (ZCZ ball V8) emmc */ + P8_22_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_22_default_pin>; + pinctrl-1 = <&P8_22_gpio_pin>; + pinctrl-2 = <&P8_22_gpio_pu_pin>; + pinctrl-3 = <&P8_22_gpio_pd_pin>; + }; + + /* P8_23 (ZCZ ball U8) emmc */ + P8_23_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_23_default_pin>; + pinctrl-1 = <&P8_23_gpio_pin>; + pinctrl-2 = <&P8_23_gpio_pu_pin>; + pinctrl-3 = <&P8_23_gpio_pd_pin>; + }; + + /* P8_24 (ZCZ ball V7) emmc */ + P8_24_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_24_default_pin>; + pinctrl-1 = <&P8_24_gpio_pin>; + pinctrl-2 = <&P8_24_gpio_pu_pin>; + pinctrl-3 = <&P8_24_gpio_pd_pin>; + }; + + /* P8_25 (ZCZ ball U7) emmc */ + P8_25_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P8_25_default_pin>; + pinctrl-1 = <&P8_25_gpio_pin>; + pinctrl-2 = <&P8_25_gpio_pu_pin>; + pinctrl-3 = <&P8_25_gpio_pd_pin>; + }; + + /* P8_26 (ZCZ ball V6) gpio-hog wl1835 */ + + /* P8_27 (ZCZ ball U5) hdmi */ + P8_27_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin"; + pinctrl-0 = <&P8_27_default_pin>; + pinctrl-1 = <&P8_27_gpio_pin>; + pinctrl-2 = <&P8_27_gpio_pu_pin>; + pinctrl-3 = <&P8_27_gpio_pd_pin>; + pinctrl-4 = <&P8_27_pruout_pin>; + pinctrl-5 = <&P8_27_pruin_pin>; + }; + + /* P8_28 (ZCZ ball V5) hdmi */ + P8_28_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin"; + pinctrl-0 = <&P8_28_default_pin>; + pinctrl-1 = <&P8_28_gpio_pin>; + pinctrl-2 = <&P8_28_gpio_pu_pin>; + pinctrl-3 = <&P8_28_gpio_pd_pin>; + pinctrl-4 = <&P8_28_pruout_pin>; + pinctrl-5 = <&P8_28_pruin_pin>; + }; + + /* P8_29 (ZCZ ball R5) hdmi */ + P8_29_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin"; + pinctrl-0 = <&P8_29_default_pin>; + pinctrl-1 = <&P8_29_gpio_pin>; + pinctrl-2 = <&P8_29_gpio_pu_pin>; + pinctrl-3 = <&P8_29_gpio_pd_pin>; + pinctrl-4 = <&P8_29_pruout_pin>; + pinctrl-5 = <&P8_29_pruin_pin>; + }; + + /* P8_30 (ZCZ ball R6) hdmi */ + P8_30_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin"; + pinctrl-0 = <&P8_30_default_pin>; + pinctrl-1 = <&P8_30_gpio_pin>; + pinctrl-2 = <&P8_30_gpio_pu_pin>; + pinctrl-3 = <&P8_30_gpio_pd_pin>; + pinctrl-4 = <&P8_30_pruout_pin>; + pinctrl-5 = <&P8_30_pruin_pin>; + }; + + /* P8_31 (ZCZ ball V4) hdmi */ + P8_31_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "eqep"; + pinctrl-0 = <&P8_31_default_pin>; + pinctrl-1 = <&P8_31_gpio_pin>; + pinctrl-2 = <&P8_31_gpio_pu_pin>; + pinctrl-3 = <&P8_31_gpio_pd_pin>; + pinctrl-4 = <&P8_31_uart_pin>; + pinctrl-5 = <&P8_31_eqep_pin>; + }; + + /* P8_32 (ZCZ ball T5) hdmi */ + P8_32_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep"; + pinctrl-0 = <&P8_32_default_pin>; + pinctrl-1 = <&P8_32_gpio_pin>; + pinctrl-2 = <&P8_32_gpio_pu_pin>; + pinctrl-3 = <&P8_32_gpio_pd_pin>; + pinctrl-4 = <&P8_32_eqep_pin>; + }; + + /* P8_33 (ZCZ ball V3) hdmi */ + P8_33_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep"; + pinctrl-0 = <&P8_33_default_pin>; + pinctrl-1 = <&P8_33_gpio_pin>; + pinctrl-2 = <&P8_33_gpio_pu_pin>; + pinctrl-3 = <&P8_33_gpio_pd_pin>; + pinctrl-4 = <&P8_33_eqep_pin>; + }; + + /* P8_34 (ZCZ ball U4) hdmi */ + P8_34_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P8_34_default_pin>; + pinctrl-1 = <&P8_34_gpio_pin>; + pinctrl-2 = <&P8_34_gpio_pu_pin>; + pinctrl-3 = <&P8_34_gpio_pd_pin>; + pinctrl-4 = <&P8_34_pwm_pin>; + }; + + /* P8_35 (ZCZ ball V2) hdmi */ + P8_35_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep"; + pinctrl-0 = <&P8_35_default_pin>; + pinctrl-1 = <&P8_35_gpio_pin>; + pinctrl-2 = <&P8_35_gpio_pu_pin>; + pinctrl-3 = <&P8_35_gpio_pd_pin>; + pinctrl-4 = <&P8_35_eqep_pin>; + }; + + /* P8_36 (ZCZ ball U3) hdmi */ + P8_36_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P8_36_default_pin>; + pinctrl-1 = <&P8_36_gpio_pin>; + pinctrl-2 = <&P8_36_gpio_pu_pin>; + pinctrl-3 = <&P8_36_gpio_pd_pin>; + pinctrl-4 = <&P8_36_pwm_pin>; + }; + + /* P8_37 (ZCZ ball U1) hdmi */ + P8_37_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "pwm"; + pinctrl-0 = <&P8_37_default_pin>; + pinctrl-1 = <&P8_37_gpio_pin>; + pinctrl-2 = <&P8_37_gpio_pu_pin>; + pinctrl-3 = <&P8_37_gpio_pd_pin>; + pinctrl-4 = <&P8_37_uart_pin>; + pinctrl-5 = <&P8_37_pwm_pin>; + }; + + /* P8_38 (ZCZ ball U2) hdmi */ + P8_38_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "pwm"; + pinctrl-0 = <&P8_38_default_pin>; + pinctrl-1 = <&P8_38_gpio_pin>; + pinctrl-2 = <&P8_38_gpio_pu_pin>; + pinctrl-3 = <&P8_38_gpio_pd_pin>; + pinctrl-4 = <&P8_38_uart_pin>; + pinctrl-5 = <&P8_38_pwm_pin>; + }; + + /* P8_39 (ZCZ ball T3) hdmi */ + P8_39_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P8_39_default_pin>; + pinctrl-1 = <&P8_39_gpio_pin>; + pinctrl-2 = <&P8_39_gpio_pu_pin>; + pinctrl-3 = <&P8_39_gpio_pd_pin>; + pinctrl-4 = <&P8_39_eqep_pin>; + pinctrl-5 = <&P8_39_pruout_pin>; + pinctrl-6 = <&P8_39_pruin_pin>; + }; + + /* P8_40 (ZCZ ball T4) hdmi */ + P8_40_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P8_40_default_pin>; + pinctrl-1 = <&P8_40_gpio_pin>; + pinctrl-2 = <&P8_40_gpio_pu_pin>; + pinctrl-3 = <&P8_40_gpio_pd_pin>; + pinctrl-4 = <&P8_40_eqep_pin>; + pinctrl-5 = <&P8_40_pruout_pin>; + pinctrl-6 = <&P8_40_pruin_pin>; + }; + + /* P8_41 (ZCZ ball T1) hdmi */ + P8_41_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P8_41_default_pin>; + pinctrl-1 = <&P8_41_gpio_pin>; + pinctrl-2 = <&P8_41_gpio_pu_pin>; + pinctrl-3 = <&P8_41_gpio_pd_pin>; + pinctrl-4 = <&P8_41_eqep_pin>; + pinctrl-5 = <&P8_41_pruout_pin>; + pinctrl-6 = <&P8_41_pruin_pin>; + }; + + /* P8_42 (ZCZ ball T2) hdmi */ + P8_42_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P8_42_default_pin>; + pinctrl-1 = <&P8_42_gpio_pin>; + pinctrl-2 = <&P8_42_gpio_pu_pin>; + pinctrl-3 = <&P8_42_gpio_pd_pin>; + pinctrl-4 = <&P8_42_eqep_pin>; + pinctrl-5 = <&P8_42_pruout_pin>; + pinctrl-6 = <&P8_42_pruin_pin>; + }; + + /* P8_43 (ZCZ ball R3) hdmi */ + P8_43_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P8_43_default_pin>; + pinctrl-1 = <&P8_43_gpio_pin>; + pinctrl-2 = <&P8_43_gpio_pu_pin>; + pinctrl-3 = <&P8_43_gpio_pd_pin>; + pinctrl-4 = <&P8_43_pwm_pin>; + pinctrl-5 = <&P8_43_pruout_pin>; + pinctrl-6 = <&P8_43_pruin_pin>; + }; + + /* P8_44 (ZCZ ball R4) hdmi */ + P8_44_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P8_44_default_pin>; + pinctrl-1 = <&P8_44_gpio_pin>; + pinctrl-2 = <&P8_44_gpio_pu_pin>; + pinctrl-3 = <&P8_44_gpio_pd_pin>; + pinctrl-4 = <&P8_44_pwm_pin>; + pinctrl-5 = <&P8_44_pruout_pin>; + pinctrl-6 = <&P8_44_pruin_pin>; + }; + + /* P8_45 (ZCZ ball R1) hdmi */ + P8_45_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P8_45_default_pin>; + pinctrl-1 = <&P8_45_gpio_pin>; + pinctrl-2 = <&P8_45_gpio_pu_pin>; + pinctrl-3 = <&P8_45_gpio_pd_pin>; + pinctrl-4 = <&P8_45_pwm_pin>; + pinctrl-5 = <&P8_45_pruout_pin>; + pinctrl-6 = <&P8_45_pruin_pin>; + }; + + /* P8_46 (ZCZ ball R2) hdmi */ + P8_46_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P8_46_default_pin>; + pinctrl-1 = <&P8_46_gpio_pin>; + pinctrl-2 = <&P8_46_gpio_pu_pin>; + pinctrl-3 = <&P8_46_gpio_pd_pin>; + pinctrl-4 = <&P8_46_pwm_pin>; + pinctrl-5 = <&P8_46_pruout_pin>; + pinctrl-6 = <&P8_46_pruin_pin>; + }; + + /************************/ + /* P9 Header */ + /************************/ + + /* P9_01 GND */ + + /* P9_02 GND */ + + /* P9_03 3V3 */ + + /* P9_04 3V3 */ + + /* P9_05 VDD_5V */ + + /* P9_06 VDD_5V */ + + /* P9_07 SYS_5V */ + + /* P9_08 SYS_5V */ + + /* P9_09 PWR_BUT */ + + /* P9_10 RSTn */ + + /* P9_11 (ZCZ ball T17) */ + P9_11_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart"; + pinctrl-0 = <&P9_11_default_pin>; + pinctrl-1 = <&P9_11_gpio_pin>; + pinctrl-2 = <&P9_11_gpio_pu_pin>; + pinctrl-3 = <&P9_11_gpio_pd_pin>; + pinctrl-4 = <&P9_11_uart_pin>; + }; + + /* P9_12 (ZCZ ball U18) */ + P9_12_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd"; + pinctrl-0 = <&P9_12_default_pin>; + pinctrl-1 = <&P9_12_gpio_pin>; + pinctrl-2 = <&P9_12_gpio_pu_pin>; + pinctrl-3 = <&P9_12_gpio_pd_pin>; + }; + + /* P9_13 (ZCZ ball U17) */ + P9_13_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart"; + pinctrl-0 = <&P9_13_default_pin>; + pinctrl-1 = <&P9_13_gpio_pin>; + pinctrl-2 = <&P9_13_gpio_pu_pin>; + pinctrl-3 = <&P9_13_gpio_pd_pin>; + pinctrl-4 = <&P9_13_uart_pin>; + }; + + /* P9_14 (ZCZ ball U14) */ + P9_14_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P9_14_default_pin>; + pinctrl-1 = <&P9_14_gpio_pin>; + pinctrl-2 = <&P9_14_gpio_pu_pin>; + pinctrl-3 = <&P9_14_gpio_pd_pin>; + pinctrl-4 = <&P9_14_pwm_pin>; + }; + + /* P9_15 (ZCZ ball R13) */ + P9_15_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P9_15_default_pin>; + pinctrl-1 = <&P9_15_gpio_pin>; + pinctrl-2 = <&P9_15_gpio_pu_pin>; + pinctrl-3 = <&P9_15_gpio_pd_pin>; + pinctrl-4 = <&P9_15_pwm_pin>; + }; + + /* P9_16 (ZCZ ball T14) */ + P9_16_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P9_16_default_pin>; + pinctrl-1 = <&P9_16_gpio_pin>; + pinctrl-2 = <&P9_16_gpio_pu_pin>; + pinctrl-3 = <&P9_16_gpio_pd_pin>; + pinctrl-4 = <&P9_16_pwm_pin>; + }; + + /* P9_17 (ZCZ ball A16) */ + P9_17_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_cs", "i2c", "pwm", "pru_uart"; + pinctrl-0 = <&P9_17_default_pin>; + pinctrl-1 = <&P9_17_gpio_pin>; + pinctrl-2 = <&P9_17_gpio_pu_pin>; + pinctrl-3 = <&P9_17_gpio_pd_pin>; + pinctrl-4 = <&P9_17_spi_cs_pin>; + pinctrl-5 = <&P9_17_i2c_pin>; + pinctrl-6 = <&P9_17_pwm_pin>; + pinctrl-7 = <&P9_17_pru_uart_pin>; + }; + + /* P9_18 (ZCZ ball B16) */ + P9_18_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "i2c", "pwm", "pru_uart"; + pinctrl-0 = <&P9_18_default_pin>; + pinctrl-1 = <&P9_18_gpio_pin>; + pinctrl-2 = <&P9_18_gpio_pu_pin>; + pinctrl-3 = <&P9_18_gpio_pd_pin>; + pinctrl-4 = <&P9_18_spi_pin>; + pinctrl-5 = <&P9_18_i2c_pin>; + pinctrl-6 = <&P9_18_pwm_pin>; + pinctrl-7 = <&P9_18_pru_uart_pin>; + }; + + /* P9_19 (ZCZ ball D17) i2c */ + P9_19_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_cs", "can", "i2c", "pru_uart", "timer"; + pinctrl-0 = <&P9_19_default_pin>; + pinctrl-1 = <&P9_19_gpio_pin>; + pinctrl-2 = <&P9_19_gpio_pu_pin>; + pinctrl-3 = <&P9_19_gpio_pd_pin>; + pinctrl-4 = <&P9_19_spi_cs_pin>; + pinctrl-5 = <&P9_19_can_pin>; + pinctrl-6 = <&P9_19_i2c_pin>; + pinctrl-7 = <&P9_19_pru_uart_pin>; + pinctrl-8 = <&P9_19_timer_pin>; + }; + + /* P9_20 (ZCZ ball D18) i2c */ + P9_20_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_cs", "can", "i2c", "pru_uart", "timer"; + pinctrl-0 = <&P9_20_default_pin>; + pinctrl-1 = <&P9_20_gpio_pin>; + pinctrl-2 = <&P9_20_gpio_pu_pin>; + pinctrl-3 = <&P9_20_gpio_pd_pin>; + pinctrl-4 = <&P9_20_spi_cs_pin>; + pinctrl-5 = <&P9_20_can_pin>; + pinctrl-6 = <&P9_20_i2c_pin>; + pinctrl-7 = <&P9_20_pru_uart_pin>; + pinctrl-8 = <&P9_20_timer_pin>; + }; + + /* P9_21 (ZCZ ball B17) */ + P9_21_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "uart", "i2c", "pwm", "pru_uart"; + pinctrl-0 = <&P9_21_default_pin>; + pinctrl-1 = <&P9_21_gpio_pin>; + pinctrl-2 = <&P9_21_gpio_pu_pin>; + pinctrl-3 = <&P9_21_gpio_pd_pin>; + pinctrl-4 = <&P9_21_spi_pin>; + pinctrl-5 = <&P9_21_uart_pin>; + pinctrl-6 = <&P9_21_i2c_pin>; + pinctrl-7 = <&P9_21_pwm_pin>; + pinctrl-8 = <&P9_21_pru_uart_pin>; + }; + + /* P9_22 (ZCZ ball A17) */ + P9_22_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_sclk", "uart", "i2c", "pwm", "pru_uart"; + pinctrl-0 = <&P9_22_default_pin>; + pinctrl-1 = <&P9_22_gpio_pin>; + pinctrl-2 = <&P9_22_gpio_pu_pin>; + pinctrl-3 = <&P9_22_gpio_pd_pin>; + pinctrl-4 = <&P9_22_spi_sclk_pin>; + pinctrl-5 = <&P9_22_uart_pin>; + pinctrl-6 = <&P9_22_i2c_pin>; + pinctrl-7 = <&P9_22_pwm_pin>; + pinctrl-8 = <&P9_22_pru_uart_pin>; + }; + + /* P9_23 (ZCZ ball V14) */ + P9_23_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm"; + pinctrl-0 = <&P9_23_default_pin>; + pinctrl-1 = <&P9_23_gpio_pin>; + pinctrl-2 = <&P9_23_gpio_pu_pin>; + pinctrl-3 = <&P9_23_gpio_pd_pin>; + pinctrl-4 = <&P9_23_pwm_pin>; + }; + + /* P9_24 (ZCZ ball D15) */ + P9_24_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "can", "i2c", "pru_uart", "pruin"; + pinctrl-0 = <&P9_24_default_pin>; + pinctrl-1 = <&P9_24_gpio_pin>; + pinctrl-2 = <&P9_24_gpio_pu_pin>; + pinctrl-3 = <&P9_24_gpio_pd_pin>; + pinctrl-4 = <&P9_24_uart_pin>; + pinctrl-5 = <&P9_24_can_pin>; + pinctrl-6 = <&P9_24_i2c_pin>; + pinctrl-7 = <&P9_24_pru_uart_pin>; + pinctrl-8 = <&P9_24_pruin_pin>; + }; + + /* P9_25 (ZCZ ball A14) audio */ + P9_25_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P9_25_default_pin>; + pinctrl-1 = <&P9_25_gpio_pin>; + pinctrl-2 = <&P9_25_gpio_pu_pin>; + pinctrl-3 = <&P9_25_gpio_pd_pin>; + pinctrl-4 = <&P9_25_eqep_pin>; + pinctrl-5 = <&P9_25_pruout_pin>; + pinctrl-6 = <&P9_25_pruin_pin>; + }; + + /* P9_26 (ZCZ ball D16) */ + P9_26_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "can", "i2c", "pru_uart", "pruin"; + pinctrl-0 = <&P9_26_default_pin>; + pinctrl-1 = <&P9_26_gpio_pin>; + pinctrl-2 = <&P9_26_gpio_pu_pin>; + pinctrl-3 = <&P9_26_gpio_pd_pin>; + pinctrl-4 = <&P9_26_uart_pin>; + pinctrl-5 = <&P9_26_can_pin>; + pinctrl-6 = <&P9_26_i2c_pin>; + pinctrl-7 = <&P9_26_pru_uart_pin>; + pinctrl-8 = <&P9_26_pruin_pin>; + }; + + /* P9_27 (ZCZ ball C13) */ + P9_27_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P9_27_default_pin>; + pinctrl-1 = <&P9_27_gpio_pin>; + pinctrl-2 = <&P9_27_gpio_pu_pin>; + pinctrl-3 = <&P9_27_gpio_pd_pin>; + pinctrl-4 = <&P9_27_eqep_pin>; + pinctrl-5 = <&P9_27_pruout_pin>; + pinctrl-6 = <&P9_27_pruin_pin>; + }; + + /* P9_28 (ZCZ ball C12) audio */ + P9_28_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_cs", "pwm", "pwm2", "pruout", "pruin"; + pinctrl-0 = <&P9_28_default_pin>; + pinctrl-1 = <&P9_28_gpio_pin>; + pinctrl-2 = <&P9_28_gpio_pu_pin>; + pinctrl-3 = <&P9_28_gpio_pd_pin>; + pinctrl-4 = <&P9_28_spi_cs_pin>; + pinctrl-5 = <&P9_28_pwm_pin>; + pinctrl-6 = <&P9_28_pwm2_pin>; + pinctrl-7 = <&P9_28_pruout_pin>; + pinctrl-8 = <&P9_28_pruin_pin>; + }; + + /* P9_29 (ZCZ ball B13) audio */ + P9_29_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P9_29_default_pin>; + pinctrl-1 = <&P9_29_gpio_pin>; + pinctrl-2 = <&P9_29_gpio_pu_pin>; + pinctrl-3 = <&P9_29_gpio_pd_pin>; + pinctrl-4 = <&P9_29_spi_pin>; + pinctrl-5 = <&P9_29_pwm_pin>; + pinctrl-6 = <&P9_29_pruout_pin>; + pinctrl-7 = <&P9_29_pruin_pin>; + }; + + /* P9_30 (ZCZ ball D12) gpio-hog wl1835 */ + + /* P9_31 (ZCZ ball A13) audio */ + P9_31_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_sclk", "pwm", "pruout", "pruin"; + pinctrl-0 = <&P9_31_default_pin>; + pinctrl-1 = <&P9_31_gpio_pin>; + pinctrl-2 = <&P9_31_gpio_pu_pin>; + pinctrl-3 = <&P9_31_gpio_pd_pin>; + pinctrl-4 = <&P9_31_spi_sclk_pin>; + pinctrl-5 = <&P9_31_pwm_pin>; + pinctrl-6 = <&P9_31_pruout_pin>; + pinctrl-7 = <&P9_31_pruin_pin>; + }; + + /* P9_32 VADC */ + + /* P9_33 (ZCZ ball C8) AIN4 */ + + /* P9_34 AGND */ + + /* P9_35 (ZCZ ball A8) AIN6 */ + + /* P9_36 (ZCZ ball B8) AIN5 */ + + /* P9_37 (ZCZ ball B7) AIN2 */ + + /* P9_38 (ZCZ ball A7) AIN3 */ + + /* P9_39 (ZCZ ball B6) AIN0 */ + + /* P9_40 (ZCZ ball C7) AIN1 */ + + /* P9_41 (ZCZ ball D14) */ + P9_41_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer", "pruin"; + pinctrl-0 = <&P9_41_default_pin>; + pinctrl-1 = <&P9_41_gpio_pin>; + pinctrl-2 = <&P9_41_gpio_pu_pin>; + pinctrl-3 = <&P9_41_gpio_pd_pin>; + pinctrl-4 = <&P9_41_timer_pin>; + pinctrl-5 = <&P9_41_pruin_pin>; + }; + + /* P9_41.1 */ + /* P9_91 (ZCZ ball D13) */ + P9_91_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P9_91_default_pin>; + pinctrl-1 = <&P9_91_gpio_pin>; + pinctrl-2 = <&P9_91_gpio_pu_pin>; + pinctrl-3 = <&P9_91_gpio_pd_pin>; + pinctrl-4 = <&P9_91_eqep_pin>; + pinctrl-5 = <&P9_91_pruout_pin>; + pinctrl-6 = <&P9_91_pruin_pin>; + }; + + /* P9_42 (ZCZ ball C18) */ + P9_42_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi_cs", "spi_sclk", "uart", "pwm", "pru_ecap_pwm"; + pinctrl-0 = <&P9_42_default_pin>; + pinctrl-1 = <&P9_42_gpio_pin>; + pinctrl-2 = <&P9_42_gpio_pu_pin>; + pinctrl-3 = <&P9_42_gpio_pd_pin>; + pinctrl-4 = <&P9_42_spi_cs_pin>; + pinctrl-5 = <&P9_42_spi_sclk_pin>; + pinctrl-6 = <&P9_42_uart_pin>; + pinctrl-7 = <&P9_42_pwm_pin>; + pinctrl-8 = <&P9_42_pru_ecap_pwm_pin>; + }; + + /* P9_42.1 */ + /* P9_92 (ZCZ ball B12) */ + P9_92_pinmux { + compatible = "bone-pinmux-helper"; + status = "okay"; + pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "eqep", "pruout", "pruin"; + pinctrl-0 = <&P9_92_default_pin>; + pinctrl-1 = <&P9_92_gpio_pin>; + pinctrl-2 = <&P9_92_gpio_pu_pin>; + pinctrl-3 = <&P9_92_gpio_pd_pin>; + pinctrl-4 = <&P9_92_eqep_pin>; + pinctrl-5 = <&P9_92_pruout_pin>; + pinctrl-6 = <&P9_92_pruin_pin>; + }; + + /* P9_43 GND */ + + /* P9_44 GND */ + + /* P9_45 GND */ + + /* P9_46 GND */ + + cape-universal { + compatible = "gpio-of-helper"; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + + P8_03 { + gpio-name = "P8_03"; + gpio = <&gpio1 6 0>; + input; + dir-changeable; + }; + + P8_04 { + gpio-name = "P8_04"; + gpio = <&gpio1 7 0>; + input; + dir-changeable; + }; + + P8_05 { + gpio-name = "P8_05"; + gpio = <&gpio1 2 0>; + input; + dir-changeable; + }; + + P8_06 { + gpio-name = "P8_06"; + gpio = <&gpio1 3 0>; + input; + dir-changeable; + }; + + P8_07 { + gpio-name = "P8_07"; + gpio = <&gpio2 2 0>; + input; + dir-changeable; + }; + + P8_08 { + gpio-name = "P8_08"; + gpio = <&gpio2 3 0>; + input; + dir-changeable; + }; + + P8_09 { + gpio-name = "P8_09"; + gpio = <&gpio2 5 0>; + input; + dir-changeable; + }; + + P8_10 { + gpio-name = "P8_10"; + gpio = <&gpio2 4 0>; + input; + dir-changeable; + }; + + P8_11 { + gpio-name = "P8_11"; + gpio = <&gpio1 13 0>; + input; + dir-changeable; + }; + + P8_12 { + gpio-name = "P8_12"; + gpio = <&gpio1 12 0>; + input; + dir-changeable; + }; + + P8_13 { + gpio-name = "P8_13"; + gpio = <&gpio0 23 0>; + input; + dir-changeable; + }; + + P8_15 { + gpio-name = "P8_15"; + gpio = <&gpio1 15 0>; + input; + dir-changeable; + }; + + P8_16 { + gpio-name = "P8_16"; + gpio = <&gpio1 14 0>; + input; + dir-changeable; + }; + + P8_18 { + gpio-name = "P8_18"; + gpio = <&gpio2 1 0>; + input; + dir-changeable; + }; + + P8_19 { + gpio-name = "P8_19"; + gpio = <&gpio0 22 0>; + input; + dir-changeable; + }; + + P8_20 { + gpio-name = "P8_20"; + gpio = <&gpio1 31 0>; + input; + dir-changeable; + }; + + P8_21 { + gpio-name = "P8_21"; + gpio = <&gpio1 30 0>; + input; + dir-changeable; + }; + + P8_22 { + gpio-name = "P8_22"; + gpio = <&gpio1 5 0>; + input; + dir-changeable; + }; + + P8_23 { + gpio-name = "P8_23"; + gpio = <&gpio1 4 0>; + input; + dir-changeable; + }; + + P8_24 { + gpio-name = "P8_24"; + gpio = <&gpio1 1 0>; + input; + dir-changeable; + }; + + P8_25 { + gpio-name = "P8_25"; + gpio = <&gpio1 0 0>; + input; + dir-changeable; + }; + + P8_27 { + gpio-name = "P8_27"; + gpio = <&gpio2 22 0>; + input; + dir-changeable; + }; + + P8_28 { + gpio-name = "P8_28"; + gpio = <&gpio2 24 0>; + input; + dir-changeable; + }; + + P8_29 { + gpio-name = "P8_29"; + gpio = <&gpio2 23 0>; + input; + dir-changeable; + }; + + P8_30 { + gpio-name = "P8_30"; + gpio = <&gpio2 25 0>; + input; + dir-changeable; + }; + + P8_31 { + gpio-name = "P8_31"; + gpio = <&gpio0 10 0>; + input; + dir-changeable; + }; + + P8_32 { + gpio-name = "P8_32"; + gpio = <&gpio0 11 0>; + input; + dir-changeable; + }; + + P8_33 { + gpio-name = "P8_33"; + gpio = <&gpio0 9 0>; + input; + dir-changeable; + }; + + P8_34 { + gpio-name = "P8_34"; + gpio = <&gpio2 17 0>; + input; + dir-changeable; + }; + + P8_35 { + gpio-name = "P8_35"; + gpio = <&gpio0 8 0>; + input; + dir-changeable; + }; + + P8_36 { + gpio-name = "P8_36"; + gpio = <&gpio2 16 0>; + input; + dir-changeable; + }; + + P8_37 { + gpio-name = "P8_37"; + gpio = <&gpio2 14 0>; + input; + dir-changeable; + }; + + P8_38 { + gpio-name = "P8_38"; + gpio = <&gpio2 15 0>; + input; + dir-changeable; + }; + + P8_39 { + gpio-name = "P8_39"; + gpio = <&gpio2 12 0>; + input; + dir-changeable; + }; + + P8_40 { + gpio-name = "P8_40"; + gpio = <&gpio2 13 0>; + input; + dir-changeable; + }; + + P8_41 { + gpio-name = "P8_41"; + gpio = <&gpio2 10 0>; + input; + dir-changeable; + }; + + P8_42 { + gpio-name = "P8_42"; + gpio = <&gpio2 11 0>; + input; + dir-changeable; + }; + + P8_43 { + gpio-name = "P8_43"; + gpio = <&gpio2 8 0>; + input; + dir-changeable; + }; + + P8_44 { + gpio-name = "P8_44"; + gpio = <&gpio2 9 0>; + input; + dir-changeable; + }; + + P8_45 { + gpio-name = "P8_45"; + gpio = <&gpio2 6 0>; + input; + dir-changeable; + }; + + P8_46 { + gpio-name = "P8_46"; + gpio = <&gpio2 7 0>; + input; + dir-changeable; + }; + + P9_11 { + gpio-name = "P9_11"; + gpio = <&gpio0 30 0>; + input; + dir-changeable; + }; + + P9_12 { + gpio-name = "P9_12"; + gpio = <&gpio1 28 0>; + input; + dir-changeable; + }; + + P9_13 { + gpio-name = "P9_13"; + gpio = <&gpio0 31 0>; + input; + dir-changeable; + }; + + P9_14 { + gpio-name = "P9_14"; + gpio = <&gpio1 18 0>; + input; + dir-changeable; + }; + + P9_15 { + gpio-name = "P9_15"; + gpio = <&gpio1 16 0>; + input; + dir-changeable; + }; + + P9_16 { + gpio-name = "P9_16"; + gpio = <&gpio1 19 0>; + input; + dir-changeable; + }; + + P9_17 { + gpio-name = "P9_17"; + gpio = <&gpio0 5 0>; + input; + dir-changeable; + }; + + P9_18 { + gpio-name = "P9_18"; + gpio = <&gpio0 4 0>; + input; + dir-changeable; + }; + + P9_19 { + gpio-name = "P9_19"; + gpio = <&gpio0 13 0>; + input; + dir-changeable; + }; + + P9_20 { + gpio-name = "P9_20"; + gpio = <&gpio0 12 0>; + input; + dir-changeable; + }; + + P9_21 { + gpio-name = "P9_21"; + gpio = <&gpio0 3 0>; + input; + dir-changeable; + }; + + P9_22 { + gpio-name = "P9_22"; + gpio = <&gpio0 2 0>; + input; + dir-changeable; + }; + + P9_23 { + gpio-name = "P9_23"; + gpio = <&gpio1 17 0>; + input; + dir-changeable; + }; + + P9_24 { + gpio-name = "P9_24"; + gpio = <&gpio0 15 0>; + input; + dir-changeable; + }; + + P9_25 { + gpio-name = "P9_25"; + gpio = <&gpio3 21 0>; + input; + dir-changeable; + }; + + P9_26 { + gpio-name = "P9_26"; + gpio = <&gpio0 14 0>; + input; + dir-changeable; + }; + + P9_27 { + gpio-name = "P9_27"; + gpio = <&gpio3 19 0>; + input; + dir-changeable; + }; + + P9_28 { + gpio-name = "P9_28"; + gpio = <&gpio3 17 0>; + input; + dir-changeable; + }; + + P9_29 { + gpio-name = "P9_29"; + gpio = <&gpio3 15 0>; + input; + dir-changeable; + }; + + P9_31 { + gpio-name = "P9_31"; + gpio = <&gpio3 14 0>; + input; + dir-changeable; + }; + + P9_41 { + gpio-name = "P9_41"; + gpio = <&gpio0 20 0>; + input; + dir-changeable; + }; + + P9_91 { + gpio-name = "P9_91"; + gpio = <&gpio3 20 0>; + input; + dir-changeable; + }; + + P9_42 { + gpio-name = "P9_42"; + gpio = <&gpio0 7 0>; + input; + dir-changeable; + }; + + P9_92 { + gpio-name = "P9_92"; + gpio = <&gpio3 18 0>; + input; + dir-changeable; + }; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-bonegreen-wireless.dts b/arch/arm/boot/dts/ti/omap/am335x-bonegreen-wireless.dts --- a/arch/arm/boot/dts/ti/omap/am335x-bonegreen-wireless.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-bonegreen-wireless.dts 2024-07-07 20:37:34.620306429 -0400 @@ -13,6 +13,12 @@ model = "TI AM335x BeagleBone Green Wireless"; compatible = "ti,am335x-bone-green-wireless", "ti,am335x-bone-green", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + chosen { + base_dtb = "am335x-bonegreen-wireless.dts"; + base_dtb_timestamp = __TIMESTAMP__; + wl1835_bt = "S3-texas-300000"; + }; + wlan_en_reg: fixedregulator@2 { compatible = "regulator-fixed"; regulator-name = "wlan-en-regulator"; @@ -24,9 +30,60 @@ gpio = <&gpio0 26 0>; enable-active-high; }; + + leds { + pinctrl-names = "default"; + //pinctrl-0 = <&user_leds_s0>; + pinctrl-0 = <&user_leds_s0 &bt_pins>; + + compatible = "gpio-leds"; + + led2 { + label = "beaglebone:green:usr0"; + gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + + led3 { + label = "beaglebone:green:usr1"; + gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc0"; + default-state = "off"; + }; + + led4 { + label = "beaglebone:green:usr2"; + gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "cpu0"; + default-state = "off"; + }; + + led5 { + label = "beaglebone:green:usr3"; + gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc1"; + default-state = "off"; + }; + + wl18xx_bt_en: led7 { + label = "wl18xx_bt_en"; + gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; }; &am33xx_pinmux { + user_leds_s0: user-leds-s0-pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a5.gpio1_21 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_a6.gpio1_22 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a7.gpio1_23 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_a8.gpio1_24 */ + >; + }; + bt_pins: bt-pins { pinctrl-single,pins = < AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_ad12.gpio1_28 BT_EN */ @@ -63,6 +120,9 @@ }; &mac_sw { + /delete-property/pinctrl-names; + /delete-property/pinctrl-0; + /delete-property/pinctrl-1; status = "disabled"; }; @@ -91,13 +151,14 @@ &uart3 { pinctrl-names = "default"; - pinctrl-0 = <&uart3_pins &bt_pins>; + pinctrl-0 = <&uart3_pins>; + //pinctrl-0 = <&uart3_pins &bt_pins>; status = "okay"; - bluetooth { - compatible = "ti,wl1835-st"; - enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; - }; + //bluetooth { + // compatible = "ti,wl1835-st"; + // enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + //}; }; &gpio1 { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-bonegreen-wireless-uboot-univ.dts b/arch/arm/boot/dts/ti/omap/am335x-bonegreen-wireless-uboot-univ.dts --- a/arch/arm/boot/dts/ti/omap/am335x-bonegreen-wireless-uboot-univ.dts 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/am335x-bonegreen-wireless-uboot-univ.dts 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ +/dts-v1/; + +#include "am33xx.dtsi" +#include "am335x-bone-common.dtsi" +#include "am335x-bonegreen-wireless-common-univ.dtsi" +#include + +/ { + model = "TI AM335x BeagleBone Green Wireless"; + compatible = "ti,am335x-bone-green-wireless", "ti,am335x-bone-green", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + + chosen { + base_dtb = "am335x-bonegreen-wireless-uboot-univ.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; +}; + +&ldo3_reg { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; +}; + +&mmc1 { + vmmc-supply = <&vmmcsd_fixed>; +}; + +&gpio1 { + ls-buf-en-hog { + gpio-hog; + gpios = <29 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "LS_BUF_EN"; + }; +}; + +/* BT_AUD_OUT from wl1835 has to be pulled low when WL_EN is activated.*/ +/* in case it isn't, wilink8 ends up in one of the test modes that */ +/* intruces various issues (elp wkaeup timeouts etc.) */ +/* On the BBGW this pin is routed through the level shifter (U21) that */ +/* introduces a pullup on the line and wilink8 ends up in a bad state. */ +/* use a gpio hog to force this pin low. An alternative may be adding */ +/* an external pulldown on U21 pin 4. */ + +&gpio3 { + bt-aud-in-hog { + gpio-hog; + gpios = <16 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "MCASP0_AHCLKR"; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-osd3358-sm-red.dts b/arch/arm/boot/dts/ti/omap/am335x-osd3358-sm-red.dts --- a/arch/arm/boot/dts/ti/omap/am335x-osd3358-sm-red.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-osd3358-sm-red.dts 2024-07-07 20:37:34.620306429 -0400 @@ -10,13 +10,16 @@ #include "am33xx.dtsi" #include "am335x-osd335x-common.dtsi" -#include - -#include +#include "am335x-boneblack-hdmi.dtsi" / { model = "Octavo Systems OSD3358-SM-RED"; compatible = "oct,osd3358-sm-refdesign", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + + chosen { + base_dtb = "am335x-osd3358-sm-red.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; }; &ldo3_reg { @@ -33,48 +36,7 @@ status = "okay"; }; -&lcdc { - status = "okay"; - - /* If you want to get 24 bit RGB and 16 BGR mode instead of - * current 16 bit RGB and 24 BGR modes, set the propety - * below to "crossed" and uncomment the video-ports -property - * in tda19988 node. - * AM335x errata for wiring: - * https://www.ti.com/lit/er/sprz360i/sprz360i.pdf - */ - - blue-and-red-wiring = "straight"; - - port { - lcdc_0: endpoint { - remote-endpoint = <&hdmi_0>; - }; - }; -}; - &i2c0 { - tda19988: hdmi-encoder@70 { - compatible = "nxp,tda998x"; - reg = <0x70>; - - pinctrl-names = "default", "off"; - pinctrl-0 = <&nxp_hdmi_bonelt_pins>; - pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>; - - /* Convert 24bit BGR to RGB, e.g. cross red and blue wiring */ - /* video-ports = <0x234501>; */ - - #sound-dai-cells = <0>; - audio-ports = < TDA998x_I2S 0x03>; - - port { - hdmi_0: endpoint { - remote-endpoint = <&lcdc_0>; - }; - }; - }; - mpu9250: imu@68 { compatible = "invensense,mpu6050"; reg = <0x68>; @@ -101,51 +63,7 @@ }; }; -&mcasp0 { - #sound-dai-cells = <0>; - pinctrl-names = "default"; - pinctrl-0 = <&mcasp0_pins>; - status = "okay"; - op-mode = <0>; /* MCASP_IIS_MODE */ - tdm-slots = <2>; - serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ - 0 0 1 0 - >; - tx-num-evt = <32>; - rx-num-evt = <32>; -}; - / { - clk_mcasp0_fixed: clk-mcasp0-fixed { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <24576000>; - }; - - clk_mcasp0: clk-mcasp0 { - #clock-cells = <0>; - compatible = "gpio-gate-clock"; - clocks = <&clk_mcasp0_fixed>; - enable-gpios = <&gpio1 27 0>; /* BeagleBone Black Clk enable on GPIO1_27 */ - }; - - sound { - compatible = "simple-audio-card"; - simple-audio-card,name = "TI BeagleBone Black"; - simple-audio-card,format = "i2s"; - simple-audio-card,bitclock-master = <&dailink0_master>; - simple-audio-card,frame-master = <&dailink0_master>; - - dailink0_master: simple-audio-card,cpu { - sound-dai = <&mcasp0>; - clocks = <&clk_mcasp0>; - }; - - simple-audio-card,codec { - sound-dai = <&tda19988>; - }; - }; - chosen { stdout-path = &uart0; }; @@ -194,51 +112,6 @@ }; &am33xx_pinmux { - pinctrl-names = "default"; - pinctrl-0 = <&clkout2_pin>; - - nxp_hdmi_bonelt_pins: nxp-hdmi-bonelt-pins { - pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLDOWN, MUX_MODE3) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT_PULLDOWN, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE0) - >; - }; - - nxp_hdmi_bonelt_off_pins: nxp-hdmi-bonelt-off-pins { - pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLDOWN, MUX_MODE3) - >; - }; - - mcasp0_pins: mcasp0-pins { - pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_INPUT_PULLUP, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_OUTPUT_PULLDOWN, MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/ - AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_OUTPUT_PULLUP, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_OUTPUT_PULLDOWN, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a11.GPIO1_27 */ - >; - }; - flash_enable: flash-enable-pins { pinctrl-single,pins = < AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* rmii1_ref_clk.gpio0_29 */ @@ -280,12 +153,6 @@ >; }; - clkout2_pin: pinmux-clkout2-pins { - pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_OUTPUT_PULLDOWN, MUX_MODE3) /* xdma_event_intr1.clkout2 */ - >; - }; - cpsw_default: cpsw-default-pins { pinctrl-single,pins = < /* Slave 1 */ @@ -372,6 +239,7 @@ pinctrl-0 = <&uart0_pins>; status = "okay"; + symlink = "bone/uart/0"; }; &usb0 { @@ -389,6 +257,7 @@ pinctrl-0 = <&i2c2_pins>; status = "okay"; clock-frequency = <100000>; + symlink = "bone/i2c/2"; }; &cpsw_port1 { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-osd335x-common.dtsi b/arch/arm/boot/dts/ti/omap/am335x-osd335x-common.dtsi --- a/arch/arm/boot/dts/ti/omap/am335x-osd335x-common.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-osd335x-common.dtsi 2024-07-07 20:37:34.620306429 -0400 @@ -49,6 +49,7 @@ status = "okay"; clock-frequency = <400000>; + symlink = "bone/i2c/0"; tps: tps@24 { reg = <0x24>; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-pocketbeagle.dts b/arch/arm/boot/dts/ti/omap/am335x-pocketbeagle.dts --- a/arch/arm/boot/dts/ti/omap/am335x-pocketbeagle.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-pocketbeagle.dts 2024-07-07 20:37:34.624306449 -0400 @@ -8,6 +8,7 @@ #include "am33xx.dtsi" #include "am335x-osd335x-common.dtsi" +#include / { model = "TI AM335x PocketBeagle"; @@ -15,6 +16,8 @@ chosen { stdout-path = &uart0; + base_dtb = "am335x-pocketbeagle.dts"; + base_dtb_timestamp = __TIMESTAMP__; }; leds { @@ -25,6 +28,8 @@ led-usr0 { label = "beaglebone:green:usr0"; + color = ; + function = LED_FUNCTION_HEARTBEAT; gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; default-state = "off"; @@ -32,6 +37,8 @@ led-usr1 { label = "beaglebone:green:usr1"; + color = ; + function = LED_FUNCTION_DISK_ACTIVITY; gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>; linux,default-trigger = "mmc0"; default-state = "off"; @@ -39,6 +46,8 @@ led-usr2 { label = "beaglebone:green:usr2"; + color = ; + function = LED_FUNCTION_CPU; gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>; linux,default-trigger = "cpu0"; default-state = "off"; @@ -46,6 +55,8 @@ led-usr3 { label = "beaglebone:green:usr3"; + color = ; + function = LED_FUNCTION_INDICATOR; gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>; default-state = "off"; }; @@ -112,7 +123,7 @@ "P2.24", "P2.33", "P2.22", - "P2.18", + "P2.18 [PRU0.15i]", "NC", "NC", "P2.01 [PWM1A]", @@ -208,11 +219,6 @@ compatible = "pinconf-single"; pinctrl-names = "default"; - pinctrl-0 = < &P2_03_gpio &P1_34_gpio &P2_19_gpio &P2_24_gpio - &P2_33_gpio &P2_22_gpio &P2_18_gpio &P2_10_gpio - &P2_06_gpio &P2_04_gpio &P2_02_gpio &P2_08_gpio - &P2_17_gpio >; - /* P2_03 (ZCZ ball T10) gpio0_23 0x824 PIN 9 */ P2_03_gpio: P2-03-gpio-pins { pinctrl-single,pins = < @@ -267,10 +273,10 @@ pinctrl-single,bias-pulldown = < 0x10 0x00 0x10 0x18>; }; - /* P2_18 (ZCZ ball U13) gpio1_15 0x83c PIN 15 */ - P2_18_gpio: P2-18-gpio-pins { + /* P2_20 (ZCZ ball T13) gpio2_00 0x888 */ + P2_20_gpio: P2-20-gpio-pins { pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLUP, MUX_MODE7) + AM33XX_PADCONF(AM335X_PIN_GPMC_CSN3, PIN_INPUT_PULLUP, MUX_MODE7) >; pinctrl-single,bias-pullup = < 0x10 0x10 0x00 0x18>; pinctrl-single,bias-pulldown = < 0x10 0x00 0x10 0x18>; @@ -401,6 +407,27 @@ AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_OUTPUT_PULLDOWN, MUX_MODE6) /* (U17) gpmc_wpn.uart4_txd */ >; }; + + pru0_pins: pinmux-pru0-pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_INPUT_PULLUP, MUX_MODE5)/* (D14) xdma_event_intr1.pr1_pru0_pru_r31_16 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_OUTPUT_PULLDOWN, MUX_MODE5)/* (A14) mcasp0_ahclkx.pr1_pru0_pru_r30_7 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_OUTPUT_PULLDOWN, MUX_MODE5) /* (B12) mcasp0_acklr.pr1_pru0_pru_r30_4 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_OUTPUT_PULLDOWN, MUX_MODE5) /* (B13) mcasp0_fsx.pr1_pru0_pru_r30_1 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLUP, MUX_MODE6) /* (U13) gpmc_ad15.pr1_pru0_pru_r31_15 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR1, PIN_OUTPUT_PULLDOWN, MUX_MODE5) /* (D13) mcasp0_axr1.pr1_pru0_pru_r30_6 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_OUTPUT_PULLDOWN, MUX_MODE5)/* (C12) mcasp0_ahclkr.pr1_pru0_pru_r30_3 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR0, PIN_OUTPUT_PULLDOWN, MUX_MODE5) /* (D12) mcasp0_axr0.pr1_pru0_pru_r30_2 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_FSR, PIN_OUTPUT_PULLDOWN, MUX_MODE5) /* (C13) mcasp0_fsr.pr1_pru0_pru_r30_5 */ + >; + }; + + pru1_pins: pinmux-pru1-pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE5)/*(R6) lcd_ac_bias_en.pr1_pru1_pru_r30_11 */ + AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT_PULLDOWN, MUX_MODE5) /* (V5) lcd_pclk.pr1_pru1_pru_r30_10 */ + >; + }; }; &epwmss0 { @@ -482,3 +509,17 @@ &usb1 { dr_mode = "host"; }; + +&pruss_tm { + status = "okay"; +}; + +&pru0 { + pinctrl-names = "default"; + pinctrl-0 = <&pru0_pins>; +}; + +&pru1 { + pinctrl-names = "default"; + pinctrl-0 = <&pru1_pins>; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/AM335X-PRU-UIO-00A0.dtso b/arch/arm/boot/dts/ti/omap/AM335X-PRU-UIO-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/AM335X-PRU-UIO-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/AM335X-PRU-UIO-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + AM335X-PRU-UIO-00A0.kernel = __TIMESTAMP__; + }; +}; + + +&pruss_tm { + status = "okay"; +}; + +&pruss { + compatible = "ti,pruss-v2"; + ti,pintc-offset = <0x20000>; + interrupt-parent = <&intc>; + interrupts = <20 21 22 23 24 25 26 27>; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe.dts b/arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe.dts --- a/arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe.dts 2024-07-07 20:37:34.624306449 -0400 @@ -14,6 +14,11 @@ / { model = "SanCloud BeagleBone Enhanced"; compatible = "sancloud,am335x-boneenhanced", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + + chosen { + base_dtb = "am335x-sancloud-bbe.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; }; &am33xx_pinmux { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe-extended-wifi.dts b/arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe-extended-wifi.dts --- a/arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe-extended-wifi.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe-extended-wifi.dts 2024-07-07 20:37:34.624306449 -0400 @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2021 Sancloud Ltd - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ */ /dts-v1/; @@ -18,6 +18,11 @@ "ti,am335x-bone", "ti,am33xx"; + chosen { + base_dtb = "am335x-sancloud-bbe-extended-wifi.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; + wlan_en_reg: fixedregulator@2 { compatible = "regulator-fixed"; regulator-name = "wlan-en-regulator"; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe-lite.dts b/arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe-lite.dts --- a/arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe-lite.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe-lite.dts 2024-07-07 20:37:34.624306449 -0400 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ * Copyright (C) 2021 SanCloud Ltd */ /dts-v1/; @@ -16,6 +16,11 @@ "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + + chosen { + base_dtb = "am335x-sancloud-bbe-lite.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; }; &am33xx_pinmux { @@ -42,6 +47,7 @@ #size-cells = <0>; compatible = "micron,spi-authenta"; + symlink = "bone/spi/0.0"; reg = <0>; spi-max-frequency = <16000000>; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am33xx.dtsi b/arch/arm/boot/dts/ti/omap/am33xx.dtsi --- a/arch/arm/boot/dts/ti/omap/am33xx.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am33xx.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -640,10 +640,11 @@ #size-cells = <1>; ranges = <0 0x56000000 0x1000000>; - /* - * Closed source PowerVR driver, no child device - * binding or driver in mainline - */ + gpu@0 { + compatible = "ti,omap3630-gpu", "img,powervr-sgx530"; + reg = <0x0 0x10000>; /* 64kB */ + interrupts = <37>; + }; }; }; }; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi b/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi --- a/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -302,7 +302,7 @@ am33xx_pinmux: pinmux@800 { compatible = "pinctrl-single"; reg = <0x800 0x238>; - #pinctrl-cells = <2>; + #pinctrl-cells = <1>; pinctrl-single,register-width = <32>; pinctrl-single,function-mask = <0x7f>; }; @@ -854,7 +854,7 @@ #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x300000 0x80000>; - status = "disabled"; + status = "okay"; pruss: pruss@0 { compatible = "ti,am3356-pruss"; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am3517.dtsi b/arch/arm/boot/dts/ti/omap/am3517.dtsi --- a/arch/arm/boot/dts/ti/omap/am3517.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am3517.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -161,12 +161,13 @@ clock-names = "fck", "ick"; #address-cells = <1>; #size-cells = <1>; - ranges = <0 0x50000000 0x4000>; + ranges = <0 0x50000000 0x10000>; - /* - * Closed source PowerVR driver, no child device - * binding or driver in mainline - */ + gpu@0 { + compatible = "ti,omap3430-gpu", "img,powervr-sgx530"; + reg = <0x0 0x10000>; /* 64kB */ + interrupts = <21>; + }; }; }; }; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am4372.dtsi b/arch/arm/boot/dts/ti/omap/am4372.dtsi --- a/arch/arm/boot/dts/ti/omap/am4372.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am4372.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -719,6 +719,12 @@ #address-cells = <1>; #size-cells = <1>; ranges = <0 0x56000000 0x1000000>; + + gpu@0 { + compatible = "ti,omap3630-gpu", "img,powervr-sgx530"; + reg = <0x0 0x10000>; /* 64kB */ + interrupts = ; + }; }; }; }; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts b/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts --- a/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts 2024-07-07 20:37:34.624306449 -0400 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) 2014-2019 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2014-2019 Texas Instruments Incorporated - https://www.ti.com/ */ /dts-v1/; @@ -12,6 +12,7 @@ #include #include #include +#include "bbai-bone-buses.dtsi" / { model = "BeagleBoard.org BeagleBone AI"; @@ -22,10 +23,19 @@ rtc0 = &tps659038_rtc; rtc1 = &rtc; display0 = &hdmi_conn; + mmc0 = &mmc1; + mmc1 = &mmc2; + mmc2 = &mmc4; + i2c0 = &i2c1; + i2c1 = &i2c5; + i2c2 = &i2c4; + i2c3 = &i2c3; }; chosen { stdout-path = &uart1; + base_dtb = "am5729-beagleboneai.dts"; + base_dtb_timestamp = __TIMESTAMP__; }; memory@0 { @@ -103,6 +113,8 @@ leds { compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins_default>; led0 { label = "beaglebone:green:usr0"; @@ -186,10 +198,14 @@ emmc_pwrseq: emmc_pwrseq { compatible = "mmc-pwrseq-emmc"; reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_pwrseq_pins_default>; }; brcmf_pwrseq: brcmf_pwrseq { compatible = "mmc-pwrseq-simple"; + pinctrl-names = "default"; + pinctrl-0 = <&brcmf_pwrseq_pins_default>; reset-gpios = <&gpio3 22 GPIO_ACTIVE_LOW>, /* BT-REG-ON */ <&gpio3 18 GPIO_ACTIVE_LOW>; /* WL-REG-ON */ }; @@ -197,13 +213,85 @@ extcon_usb1: extcon_usb1 { compatible = "linux,extcon-usb-gpio"; ti,enable-id-detection; - id-gpio = <&gpio3 13 GPIO_ACTIVE_HIGH>; + id-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&extcon_usb1_pins_default>; + }; +}; + +&dra7_pmx_core { + extcon_usb1_pins_default: extcon_usb1_pins_default { + pinctrl-single,pins = < + DRA7XX_CORE_IOPAD(0x3518, PIN_INPUT | MUX_MODE14) /* AG2: vin1a_d9.gpio3_13 - USR0 */ + >; + }; + + led_pins_default: led_pins_default { + pinctrl-single,pins = < + DRA7XX_CORE_IOPAD(0x3528, PIN_OUTPUT | MUX_MODE14) /* AF6: vin1a_d13.gpio3_17 - USR0 */ + DRA7XX_CORE_IOPAD(0x36c0, PIN_OUTPUT | MUX_MODE14) /* J11: mcasp1_axr3.gpio5_5 - USR1 */ + DRA7XX_CORE_IOPAD(0x3520, PIN_OUTPUT | MUX_MODE14) /* AG5: vin1a_d12.gpio3_15 - USR2 */ + DRA7XX_CORE_IOPAD(0x351c, PIN_OUTPUT | MUX_MODE14) /* AG3: vin1a_d10.gpio3_14 - USR3 */ + DRA7XX_CORE_IOPAD(0x3500, PIN_OUTPUT | MUX_MODE14) /* AH6: vin1a_d3.gpio3_7 - USR4 */ + >; + }; + + emmc_pwrseq_pins_default: emmc_pwrseq_pins_default { + pinctrl-single,pins = < + DRA7XX_CORE_IOPAD(0x36c8, PIN_OUTPUT_PULLUP | MUX_MODE14) /* F13: mcasp1_axr5.gpio5_7 - eMMC_RSTn */ + >; + }; + + brcmf_pwrseq_pins_default: brcmf_pwrseq_pins_default { + pinctrl-single,pins = < + DRA7XX_CORE_IOPAD(0x352c, PIN_OUTPUT_PULLUP | MUX_MODE14) /* AF3: vin1a_d14.gpio3_18 - WL_REG_ON */ + DRA7XX_CORE_IOPAD(0x353c, PIN_OUTPUT_PULLUP | MUX_MODE14) /* AE5: vin1a_d18.gpio3_22 - BT_REG_ON */ + >; + }; + + wifibt_extra_pins_default: wifibt_extra_pins_default { + pinctrl-single,pins = < + DRA7XX_CORE_IOPAD(0x3540, PIN_INPUT | MUX_MODE14) /* AE1: vin1a_d19.gpio3_23 - WL_HOST_WAKE */ + DRA7XX_CORE_IOPAD(0x3450, PIN_INPUT | MUX_MODE8) /* P6: vin1a_d20.uart6_rxd - UART6_RXD */ + DRA7XX_CORE_IOPAD(0x3454, PIN_INPUT | MUX_MODE8) /* R9: vin1a_d21.uart6_txd - UART6_TXD */ + DRA7XX_CORE_IOPAD(0x3458, PIN_INPUT | MUX_MODE8) /* R5: vin1a_d22.uart6_ctsn - UART6_CTSN */ + DRA7XX_CORE_IOPAD(0x345c, PIN_INPUT | MUX_MODE8) /* P5: vin1a_d23.uart6_rtsn - UART6_RTSN */ + DRA7XX_CORE_IOPAD(0x3534, PIN_INPUT_PULLDOWN | MUX_MODE14) /* AF1: vin1a_d16.gpio3_20 - BT_HOST_WAKE */ + DRA7XX_CORE_IOPAD(0x3538, PIN_OUTPUT_PULLDOWN | MUX_MODE14) /* AE3: vin1a_d6.gpio3_21 - BT_WAKE */ + >; + }; + + adc_pins_default: adc_pins_default { + pinctrl-single,pins = < + DRA7XX_CORE_IOPAD(0x3550, PIN_OUTPUT | MUX_MODE14) /* AD3: vin1a_d23.gpio3_27 - VDD_ADC_SEL */ + DRA7XX_CORE_IOPAD(0x34DC, PIN_INPUT_PULLUP | MUX_MODE14) /* AG8: vin1a_clk0.gpio2_30 - INT_ADC */ + >; + }; + + pmic_pins_default: pmic_pins_default { + pinctrl-single,pins = < + DRA7XX_CORE_IOPAD(0x3690, PIN_INPUT_PULLUP | MUX_MODE14) /* F21: gpio6_16.gpio6_16 - PMIC_INT */ + >; + }; + + hdmi_pins_default: hdmi_pins_default { + pinctrl-single,pins = < + DRA7XX_CORE_IOPAD(0x3808, PIN_INPUT | MUX_MODE1) /* C25: i2c2_sda.hdmi1_ddc_scl - HDMI_DDC_SCL */ + DRA7XX_CORE_IOPAD(0x380C, PIN_INPUT | MUX_MODE1) /* F17: i2c2_scl.hdmi1_ddc_sda - HDMI_DDC_SDA */ + DRA7XX_CORE_IOPAD(0x37BC, PIN_INPUT | MUX_MODE6) /* B20: spi1_cs3.hdmi1_cec - HDMI_DDC_CEC */ +#if 0 + DRA7XX_CORE_IOPAD(0x37B8, PIN_INPUT | MUX_MODE6) /* B21: spi1_cs2.hdmi1_hpd - HDMI_DDC_HPD */ +#else + DRA7XX_CORE_IOPAD(0x37B8, PIN_INPUT | MUX_MODE14) /* B21: spi1_cs2.gpio7_12 - HDMI_DDC_HPD */ +#endif + >; }; }; &i2c1 { status = "okay"; clock-frequency = <400000>; + symlink = "bone/i2c/0"; tps659038: tps659038@58 { compatible = "ti,tps659038"; @@ -211,6 +299,9 @@ interrupt-parent = <&gpio6>; interrupts = <16 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins_default>; + #interrupt-cells = <2>; interrupt-controller; @@ -423,6 +514,9 @@ st,adc-freq = <1>; /* 3.25 MHz ADC clock speed */ st,sample-time = <4>; /* ADC converstion time: 80 clocks */ + pinctrl-names = "default"; + pinctrl-0 = <&adc_pins_default>; + stmpe_adc { compatible = "st,stmpe-adc"; st,norequest-mask = <0x00>; /* mask any channels to be used by touchscreen */ @@ -461,6 +555,11 @@ #pwm-cells = <2>; }; }; + + eeprom: eeprom@50 { + compatible = "atmel,24c32"; + reg = <0x50>; + }; }; &mcspi3 { @@ -485,6 +584,7 @@ &uart1 { status = "okay"; + symlink = "bone/uart/0"; }; &davinci_mdio_sw { @@ -549,7 +649,11 @@ ti,needs-special-reset; dmas = <&sdma_xbar 47>, <&sdma_xbar 48>; dma-names = "tx", "rx"; - + pinctrl-names = "default", "hs", "ddr_1_8v", "hs200_1_8v"; + pinctrl-0 = <&mmc2_pins_default>; + pinctrl-1 = <&mmc2_pins_hs>; + pinctrl-2 = <&mmc2_pins_ddr_rev20>; + pinctrl-3 = <&mmc2_pins_hs200>; }; &mmc4 { @@ -562,6 +666,10 @@ /* DDR50: DDR up to 50 MHz (1.8 V signaling). */ status = "okay"; + pinctrl-names = "default", "hs"; + pinctrl-0 = <&mmc4_pins_default &wifibt_extra_pins_default>; + pinctrl-1 = <&mmc4_pins_hs &wifibt_extra_pins_default>; + ti,needs-special-reset; vmmc-supply = <&vdd_3v3>; cap-power-off-card; @@ -621,6 +729,8 @@ &hdmi { status = "okay"; vdda-supply = <&vdd_1v8_phy_ldo4>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_pins_default>; port { hdmi_out: endpoint { @@ -674,6 +784,7 @@ &i2c4 { status = "okay"; clock-frequency = <100000>; + symlink = "bone/i2c/2"; }; &ipu2 { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am57xx-beagle-x15.dts b/arch/arm/boot/dts/ti/omap/am57xx-beagle-x15.dts --- a/arch/arm/boot/dts/ti/omap/am57xx-beagle-x15.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am57xx-beagle-x15.dts 2024-07-07 20:37:34.624306449 -0400 @@ -8,6 +8,11 @@ / { /* NOTE: This describes the "original" pre-production A2 revision */ model = "TI AM5728 BeagleBoard-X15"; + + chosen { + base_dtb = "am57xx-beagle-x15.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; }; &tpd12s015 { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am57xx-beagle-x15-revb1.dts b/arch/arm/boot/dts/ti/omap/am57xx-beagle-x15-revb1.dts --- a/arch/arm/boot/dts/ti/omap/am57xx-beagle-x15-revb1.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am57xx-beagle-x15-revb1.dts 2024-07-07 20:37:34.624306449 -0400 @@ -7,6 +7,11 @@ / { model = "TI AM5728 BeagleBoard-X15 rev B1"; + + chosen { + base_dtb = "am57xx-beagle-x15-revb1.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; }; &tpd12s015 { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/am57xx-beagle-x15-revc.dts b/arch/arm/boot/dts/ti/omap/am57xx-beagle-x15-revc.dts --- a/arch/arm/boot/dts/ti/omap/am57xx-beagle-x15-revc.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/am57xx-beagle-x15-revc.dts 2024-07-07 20:37:34.624306449 -0400 @@ -7,6 +7,11 @@ / { model = "TI AM5728 BeagleBoard-X15 rev C"; + + chosen { + base_dtb = "am57xx-beagle-x15-revc.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; }; &tpd12s015 { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-ADC-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-ADC-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-ADC-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-ADC-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-ADC-00A0.kernel = __TIMESTAMP__; + }; +}; + +&tscadc { + status = "okay"; + adc { + // Configure one or more (up to 8) steps for the adc to execute: + + + // For each step, the channel to sample. + // range: 0 .. 7 + ti,adc-channels = <0 1 2 3 4 5 6 7>; + // + // BeagleBone Black (and most other variants): + // ch 0 P9.39 + // ch 1 P9.40 + // ch 2 P9.37 + // ch 3 P9.38 + // ch 4 P9.33 + // ch 5 P9.36 + // ch 6 P9.35 + // ch 7 measures 0.5 * VDD_3V3B with 2.4 kΩ source impedance + // + // PocketBeagle: + // ch 0 P1.19 + // ch 1 P1.21 + // ch 2 P1.23 + // ch 3 P1.25 + // ch 4 P1.27 + // ch 5 P2.35 via 10k/10k voltage divider + // ch 6 P1.02 via 10k/10k voltage divider + // ch 7 P2.36 via pmic mux + // + // The divider used on PocketBeagle channels 5 and 6 makes the effective voltage V_eff and + // source impedance Z_eff seen by the adc on these channels depend on the voltage V_src and + // impedance Z_src of the source connected to the corresponding pin as follows: + // + // V_eff = V_src / (2 + Z_src / (10 kΩ)) + // Z_eff = 5 kΩ * (1 + Z_src / (Z_src + 20 kΩ)) + // ≈ 5 kΩ + Z_src / 4 for small values of Z_src (up to 2 kΩ or so) + + + // For each step, number of adc clock cycles to wait between setting up muxes and sampling. + // range: 0 .. 262143 + // optional, default is 152 (XXX but why?!) + ti,chan-step-opendelay = <152 152 152 152 152 152 152 152>; + //` + // XXX is there any purpose to set this nonzero other than to fine-tune the sample rate? + + + // For each step, how many times it should sample to average. + // range: 1 .. 16, must be power of two (i.e. 1, 2, 4, 8, or 16) + // optional, default is 16 + ti,chan-step-avg = <16 16 16 16 16 16 16 16>; + // + // If you're using periodic sampling (using the iio block device rather than sysfs) then + // you should consider setting this to 1 and if desired reduce the samplerate in userspace + // instead since averaging isn't a particularly good low-pass filter. + // + // If you're using sysfs to occasionally read a value, then the default value of 16 will + // still get you the most accurate readings. + + + // For each step, number of adc clock cycles to sample minus two. + // range: 0 .. 255 (resulting in sampling time of 2 .. 257 cycles) + // optional, default is 0 + ti,chan-step-sampledelay = <0 0 0 0 0 0 0 0>; + // + // If this is set too low, accuracy will deteriorate when the thing you're measuring has a + // high source impedance. The maximum source impedance recommended (by erratum 1.0.32) is: + // (2 + sampledelay) * 2.873 kΩ - 0.2 kΩ + // which means that the default should be fine for source impedance up to 5.5 kΩ. + // + // (This seems to ensure the sampling time is at least 21 times the RC constant, based on + // the 5.5 pF nominal capacitance specified in the datasheet.) + + + // After sampling, conversion time is 13 adc clock cycles. + // + // The adc clock frequency is 3 MHz, therefore the total time per step in microseconds is: + // ( opendelay + avg * ( 2 + sampledelay + 13 ) ) / 3 + // + // If all steps use the same timings then the sample rate will be: + // 3 MHz / ( opendelay + avg * ( 2 + sampledelay + 13 ) ) / number_of_steps + // + // The highest samplerate obtainable (avg=1, opendelay=0, sampledelay=0) is therefore: + // 200 kHz / number_of_steps + // = 25 kHz when using all 8 steps. + // + // Using avg=16 reduces that to: + // 12.5 kHz / number_of_steps + // = 1.5625 kHz when using all 8 steps. + // + // Using the default values (avg=16, opendelay=152, sampledelay=0) reduces that to: + // 7.653 kHz / number_of_steps + // = 0.9566 kHz when using all 8 steps. + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/bbai-bone-buses.dtsi b/arch/arm/boot/dts/ti/omap/bbai-bone-buses.dtsi --- a/arch/arm/boot/dts/ti/omap/bbai-bone-buses.dtsi 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/bbai-bone-buses.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Deepak Khatri + * Copyright (C) 2021 Robert Nelson + * See Cape Interface Spec page for more info on Bone Buses + * https://elinux.org/Beagleboard:BeagleBone_cape_interface_spec + * https://docs.beagleboard.io/latest/boards/capes/cape-interface-spec.html + */ + +#include +#include + +// For dummy refrence when peripheral is not available. +&{/} { + not_available: not_available { + // Use ¬_available phandle when bus not available! + // This node is responsible to create these entries, + // /sys/firmware/devicetree/base/__symbols__/not_available + // /sys/firmware/devicetree/base/not_available + }; +}; + +// For compatible bone pinmuxing +bone_pinmux: &dra7_pmx_core { + bborg_comms_can_pins: pinmux_comms_can_pins { + pinctrl-single,pins = < + DRA7XX_CORE_IOPAD(0x368C, PIN_INPUT_PULLUP | MUX_MODE2) /* P9_24: F20: gpio6_15.dcan2_rx */ + DRA7XX_CORE_IOPAD(0x3688, PIN_OUTPUT_PULLUP | MUX_MODE2) /* P9_26A: E21: gpio6_14.dcan2_tx */ + DRA7XX_CORE_IOPAD(0x3544, PIN_OUTPUT | MUX_MODE15) /* P9_26B: AE2: vin1a_d20.off */ + >; + }; + + bborg_comms_rs485_pins: pinmux_comms_rs485_pins { + pinctrl-single,pins = < + DRA7XX_CORE_IOPAD(0x3730, PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4) /* P9_13A: C17: mcasp3_axr1.uart5_txd */ + DRA7XX_CORE_IOPAD(0x3680, PIN_OUTPUT | MUX_MODE15) /* P9_13B: AB10: usb1_drvvbus.off */ + DRA7XX_CORE_IOPAD(0x372C, PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE4) /* P9_11A: B19: mcasp3_axr0.uart5_rxd */ + DRA7XX_CORE_IOPAD(0x3620, PIN_OUTPUT | MUX_MODE15) /* P9_11B: B8: vout1_d17.off */ + >; + }; +}; + +// UART +// https://docs.beagleboard.io/latest/boards/capes/cape-interface-spec.html#uart +bone_uart_1: &uart10 { + symlink = "bone/uart/1"; +}; + +bone_uart_2: &uart3 { + symlink = "bone/uart/2"; +}; + +bone_uart_3: ¬_available { + // not available on BBAI +}; + +bone_uart_4: &uart5 { + symlink = "bone/uart/4"; + status = "disabled"; + pinctrl-names = "default"; + pinctrl-0 = <&bborg_comms_rs485_pins>; +}; + +// CAN +// https://docs.beagleboard.io/latest/boards/capes/cape-interface-spec.html#can +bone_can_0: ¬_available { + // Not available on BBAI +}; + +bone_can_1: &dcan2 { + symlink = "bone/can/1"; + status = "disabled"; + pinctrl-names = "default"; + pinctrl-0 = <&bborg_comms_can_pins>; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-BBBW-WL1835-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-BBBW-WL1835-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-BBBW-WL1835-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-BBBW-WL1835-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-BBBW-WL1835-00A0.kernel = __TIMESTAMP__; + }; +}; + +&{/} { + model = "TI AM335x BeagleBone Black Wireless"; + compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + + wlan_en_reg: fixedregulator@2 { + compatible = "regulator-fixed"; + regulator-name = "wlan-en-regulator"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + startup-delay-us= <70000>; + + /* WL_EN */ + gpio = <&gpio3 9 0>; + enable-active-high; + }; +}; + +&am33xx_pinmux { + bt_pins: pinmux_bt_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gmii1_txd0.gpio0_28 - BT_EN */ + >; + }; + + mmc3_pins: pinmux_mmc3_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLUP, MUX_MODE6 ) /* (L15) gmii1_rxd1.mmc2_clk */ + AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLUP, MUX_MODE6 ) /* (J16) gmii1_txen.mmc2_cmd */ + AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (J17) gmii1_rxdv.mmc2_dat0 */ + AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (J18) gmii1_txd3.mmc2_dat1 */ + AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (K15) gmii1_txd2.mmc2_dat2 */ + AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (H16) gmii1_col.mmc2_dat3 */ + >; + }; + + uart3_pins: pinmux_uart3_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLUP, MUX_MODE1) /* gmii1_rxd3.uart3_rxd */ + AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE1) /* gmii1_rxd2.uart3_txd */ + AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT, MUX_MODE3) /* mdio_data.uart3_ctsn */ + AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLDOWN, MUX_MODE3) /* mdio_clk.uart3_rtsn */ + >; + }; + + wl18xx_pins: pinmux_wl18xx_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gmii1_txclk.gpio3_9 WL_EN */ + AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7) /* rmii1_refclk.gpio0_29 WL_IRQ */ + AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gmii1_rxclk.gpio3_10 LS_BUF_EN */ + >; + }; +}; + +&mac_sw { + /delete-property/pinctrl-names; + /delete-property/pinctrl-0; + /delete-property/pinctrl-1; + status = "disabled"; +}; + +&mmc3 { + dmas = <&edma_xbar 12 0 1 + &edma_xbar 13 0 2>; + dma-names = "tx", "rx"; + status = "okay"; + vmmc-supply = <&wlan_en_reg>; + bus-width = <4>; + non-removable; + cap-power-off-card; + keep-power-in-suspend; + pinctrl-names = "default"; + pinctrl-0 = <&mmc3_pins &wl18xx_pins>; + + #address-cells = <1>; + #size-cells = <0>; + wlcore: wlcore@2 { + compatible = "ti,wl1835"; + reg = <2>; + interrupt-parent = <&gpio0>; + interrupts = <29 IRQ_TYPE_EDGE_RISING>; + }; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins &bt_pins>; + status = "okay"; + + bluetooth { + compatible = "ti,wl1835-st"; + enable-gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + }; +}; + +&gpio3 { + ls-buf-en-hog { + gpio-hog; + gpios = <10 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "LS_BUF_EN"; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-BBGG-WL1835-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-BBGG-WL1835-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-BBGG-WL1835-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-BBGG-WL1835-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-BBGG-WL1835-00A0.kernel = __TIMESTAMP__; + wl1835_bt = "S3-texas-300000"; + }; +}; + +&{/} { + model = "SeeedStudio BeagleBone Green Gateway"; + compatible = "ti,am335x-bone-green-gateway", "ti,am335x-bone-green", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; + + aliases { + rtc0 = &extrtc; + rtc1 = "/ocp/rtc@44e3e000"; + }; + + wlan_en_reg: fixedregulator@2 { + compatible = "regulator-fixed"; + regulator-name = "wlan-en-regulator"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + startup-delay-us= <70000>; + + /* WL_EN */ + gpio = <&gpio3 9 0>; + enable-active-high; + }; + + leds { + pinctrl-names = "default"; + //pinctrl-0 = <&user_leds_s0>; + pinctrl-0 = <&user_leds_s0 &bt_pins>; + + compatible = "gpio-leds"; + + led2 { + label = "beaglebone:green:usr0"; + gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + + led3 { + label = "beaglebone:green:usr1"; + gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc0"; + default-state = "off"; + }; + + led4 { + label = "beaglebone:green:usr2"; + gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "cpu0"; + default-state = "off"; + }; + + led5 { + label = "beaglebone:green:usr3"; + gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc1"; + default-state = "off"; + }; + + led6 { + label = "beaglebone:green:usr4"; + gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "netdev"; + default-state = "off"; + }; + + wl18xx_bt_en: led7 { + label = "wl18xx_bt_en"; + gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; +}; + +&am33xx_pinmux { + pinctrl-names = "default"; + pinctrl-0 = <&usbhost_pins>; + + user_leds_s0: user_leds_s0 { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a5.gpio1_21 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_a6.gpio1_22 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a7.gpio1_23 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_a8.gpio1_24 */ + AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_OUTPUT_PULLUP, MUX_MODE7) /* WL_Active_LED / USR4 */ + >; + }; + + bt_pins: pinmux_bt_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gmii1_txd0.gpio0_28 - BT_EN */ + >; + }; + + mmc3_pins: pinmux_mmc3_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLUP, MUX_MODE6 ) /* (L15) gmii1_rxd1.mmc2_clk */ + AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLUP, MUX_MODE6 ) /* (J16) gmii1_txen.mmc2_cmd */ + AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (J17) gmii1_rxdv.mmc2_dat0 */ + AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (J18) gmii1_txd3.mmc2_dat1 */ + AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (K15) gmii1_txd2.mmc2_dat2 */ + AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (H16) gmii1_col.mmc2_dat3 */ + >; + }; + + uart2_grove_pins: pinmux_uart2_grove_pins { + pinctrl-single,pins = < + AM33XX_IOPAD(0x90c, PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE6) + AM33XX_IOPAD(0x910, PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE6) + >; + }; + + uart3_pins: pinmux_uart3_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLUP, MUX_MODE1) /* gmii1_rxd3.uart3_rxd */ + AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE1) /* gmii1_rxd2.uart3_txd */ + AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT, MUX_MODE3) /* mdio_data.uart3_ctsn */ + AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLDOWN, MUX_MODE3) /* mdio_clk.uart3_rtsn */ + >; + }; + + usbhost_pins: pinmux_usbhost_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gmii1_txd1.gpio0[21] */ + >; + }; + + wl18xx_pins: pinmux_wl18xx_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gmii1_txclk.gpio3_9 WL_EN */ + AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7) /* rmii1_refclk.gpio0_29 WL_IRQ */ + AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gmii1_rxclk.gpio3_10 LS_BUF_EN */ + >; + }; +}; + +&mac_sw { + /delete-property/pinctrl-names; + /delete-property/pinctrl-0; + /delete-property/pinctrl-1; + status = "disabled"; +}; + +&mmc3 { + dmas = <&edma_xbar 12 0 1 + &edma_xbar 13 0 2>; + dma-names = "tx", "rx"; + status = "okay"; + vmmc-supply = <&wlan_en_reg>; + bus-width = <4>; + non-removable; + cap-power-off-card; + keep-power-in-suspend; + pinctrl-names = "default"; + pinctrl-0 = <&mmc3_pins &wl18xx_pins>; + + #address-cells = <1>; + #size-cells = <0>; + wlcore: wlcore@2 { + compatible = "ti,wl1835"; + reg = <2>; + interrupt-parent = <&gpio0>; + interrupts = <29 IRQ_TYPE_EDGE_RISING>; + }; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_grove_pins>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; + //pinctrl-0 = <&uart3_pins &bt_pins>; + status = "okay"; + + //bluetooth { + // compatible = "ti,wl1835-st"; + // enable-gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + //}; +}; + +&i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + extrtc: rtc@68 { + compatible = "dallas,ds1340"; + reg = <0x68>; + }; +}; + +// (K16) gmii1_txd1.gpio0[21] +&gpio0 { + usb-reset-hog { + gpio-hog; + gpios = <21 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "usb_reset"; + }; +}; + +&gpio3 { + ls-buf-en-hog { + gpio-hog; + gpios = <10 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "LS_BUF_EN"; + }; +}; + +&usb1 { + #address-cells = <1>; + #size-cells = <0>; + + hub@1 { + compatible = "usb424,9512"; + reg = <1>; + + #address-cells = <1>; + #size-cells = <0>; + + ethernet: ethernet@1 { + compatible = "usb424,ec00"; + reg = <1>; + }; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-BBGW-WL1835-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-BBGW-WL1835-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-BBGW-WL1835-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-BBGW-WL1835-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-BBGW-WL1835-00A0.kernel = __TIMESTAMP__; + wl1835_bt = "S3-texas-300000"; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_12_pinmux { status = "disabled"; }; /* gpmc_ad12.gpio1_28 BT_EN */ + P8_12_pinmux { status = "disabled"; }; /* gpmc_ad12.mmc2_dat0 */ + P8_11_pinmux { status = "disabled"; }; /* gpmc_ad13.mmc2_dat1 */ + P8_16_pinmux { status = "disabled"; }; /* gpmc_ad14.mmc2_dat2 */ + P8_15_pinmux { status = "disabled"; }; /* gpmc_ad15.mmc2_dat3 */ + + P8_18_pinmux { status = "disabled"; }; /* gpmc_clk.mmc2_clk */ + + //Audio... + P9_28_pinmux { status = "disabled"; }; + P9_29_pinmux { status = "disabled"; }; + P9_31_pinmux { status = "disabled"; }; + + /* wl1835 */ + P8_14_pinmux { status = "disabled"; }; /* wl1835: wl_en */ + P8_17_pinmux { status = "disabled"; }; /* wl1835: wl_irq */ + P8_26_pinmux { status = "disabled"; }; /* wl1835: LS_BUF_EN */ + P9_30_pinmux { status = "disabled"; }; /* wl1835: MCASP0_AHCLKR */ +}; + +&{/} { + model = "TI AM335x BeagleBone Green Wireless"; + compatible = "ti,am335x-bone-green-wireless", "ti,am335x-bone-green", "ti,am335x-bone", "ti,am33xx"; + + wlan_en_reg: fixedregulator@2 { + compatible = "regulator-fixed"; + regulator-name = "wlan-en-regulator"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + startup-delay-us= <70000>; + + /* WL_EN */ + gpio = <&gpio0 26 0>; + enable-active-high; + }; + + leds { + pinctrl-names = "default"; + //pinctrl-0 = <&user_leds_s0>; + pinctrl-0 = <&user_leds_s0 &bt_pins>; + + compatible = "gpio-leds"; + + led2 { + label = "beaglebone:green:usr0"; + gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + + led3 { + label = "beaglebone:green:usr1"; + gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc0"; + default-state = "off"; + }; + + led4 { + label = "beaglebone:green:usr2"; + gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "cpu0"; + default-state = "off"; + }; + + led5 { + label = "beaglebone:green:usr3"; + gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc1"; + default-state = "off"; + }; + + wl18xx_bt_en: led7 { + label = "wl18xx_bt_en"; + gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; +}; + +&am33xx_pinmux { + user_leds_s0: user_leds_s0 { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a5.gpio1_21 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_a6.gpio1_22 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a7.gpio1_23 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_a8.gpio1_24 */ + >; + }; + + bt_pins: pinmux_bt_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_ad12.gpio1_28 BT_EN */ + >; + }; + + mmc3_pins: pinmux_mmc3_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_INPUT_PULLUP, MUX_MODE3) /* gpmc_ad12.mmc2_dat0 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_INPUT_PULLUP, MUX_MODE3) /* gpmc_ad13.mmc2_dat1 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_INPUT_PULLUP, MUX_MODE3) /* gpmc_ad14.mmc2_dat2 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLUP, MUX_MODE3) /* gpmc_ad15.mmc2_dat3 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_CSN3, PIN_INPUT_PULLUP, MUX_MODE3) /* gpmc_csn3.mmc2_cmd */ + AM33XX_PADCONF(AM335X_PIN_GPMC_CLK, PIN_INPUT_PULLUP, MUX_MODE3) /* gpmc_clk.mmc2_clk */ + >; + }; + + uart3_pins: pinmux_uart3_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLUP, MUX_MODE1) /* gmii1_rxd3.uart3_rxd */ + AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE1) /* gmii1_rxd2.uart3_txd */ + AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT, MUX_MODE3) /* mdio_data.uart3_ctsn */ + AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLDOWN, MUX_MODE3) /* mdio_clk.uart3_rtsn */ + >; + }; + + wl18xx_pins: pinmux_wl18xx_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_ad10.gpio0_26 WL_EN */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_INPUT_PULLDOWN, MUX_MODE7) /* gpmc_ad11.gpio0_27 WL_IRQ */ + AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_csn0.gpio1_29 LS_BUF_EN */ + >; + }; +}; + +&mac_sw { + /delete-property/pinctrl-names; + /delete-property/pinctrl-0; + /delete-property/pinctrl-1; + status = "disabled"; +}; + +&mmc3 { + dmas = <&edma_xbar 12 0 1 + &edma_xbar 13 0 2>; + dma-names = "tx", "rx"; + status = "okay"; + vmmc-supply = <&wlan_en_reg>; + bus-width = <4>; + non-removable; + cap-power-off-card; + keep-power-in-suspend; + pinctrl-names = "default"; + pinctrl-0 = <&mmc3_pins &wl18xx_pins>; + + #address-cells = <1>; + #size-cells = <0>; + wlcore: wlcore@2 { + compatible = "ti,wl1835"; + reg = <2>; + interrupt-parent = <&gpio0>; + interrupts = <27 IRQ_TYPE_EDGE_RISING>; + }; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; + //pinctrl-0 = <&uart3_pins &bt_pins>; + status = "okay"; + + //bluetooth { + // compatible = "ti,wl1835-st"; + // enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + //}; +}; + +&gpio1 { + ls-buf-en-hog { + gpio-hog; + gpios = <29 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "LS_BUF_EN"; + }; +}; + +/* BT_AUD_OUT from wl1835 has to be pulled low when WL_EN is activated.*/ +/* in case it isn't, wilink8 ends up in one of the test modes that */ +/* intruces various issues (elp wkaeup timeouts etc.) */ +/* On the BBGW this pin is routed through the level shifter (U21) that */ +/* introduces a pullup on the line and wilink8 ends up in a bad state. */ +/* use a gpio hog to force this pin low. An alternative may be adding */ +/* an external pulldown on U21 pin 4. */ + +&gpio3 { + bt-aud-in-hog { + gpio-hog; + gpios = <16 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "MCASP0_AHCLKR"; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-BONE-4D5R-01-00A1.dtso b/arch/arm/boot/dts/ti/omap/BB-BONE-4D5R-01-00A1.dtso --- a/arch/arm/boot/dts/ti/omap/BB-BONE-4D5R-01-00A1.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-BONE-4D5R-01-00A1.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-BONE-4D5R-01-00A1.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P8_45_pinmux { status = "disabled"; }; /* lcd: lcd_data0 */ + P8_46_pinmux { status = "disabled"; }; /* lcd: lcd_data1 */ + P8_43_pinmux { status = "disabled"; }; /* lcd: lcd_data2 */ + P8_44_pinmux { status = "disabled"; }; /* lcd: lcd_data3 */ + P8_41_pinmux { status = "disabled"; }; /* lcd: lcd_data4 */ + P8_42_pinmux { status = "disabled"; }; /* lcd: lcd_data5 */ + P8_39_pinmux { status = "disabled"; }; /* lcd: lcd_data6 */ + P8_40_pinmux { status = "disabled"; }; /* lcd: lcd_data7 */ + P8_37_pinmux { status = "disabled"; }; /* lcd: lcd_data8 */ + P8_38_pinmux { status = "disabled"; }; /* lcd: lcd_data9 */ + P8_36_pinmux { status = "disabled"; }; /* lcd: lcd_data10 */ + P8_34_pinmux { status = "disabled"; }; /* lcd: lcd_data11 */ + P8_35_pinmux { status = "disabled"; }; /* lcd: lcd_data12 */ + P8_33_pinmux { status = "disabled"; }; /* lcd: lcd_data13 */ + P8_31_pinmux { status = "disabled"; }; /* lcd: lcd_data14 */ + P8_32_pinmux { status = "disabled"; }; /* lcd: lcd_data15 */ + + P8_27_pinmux { status = "disabled"; }; /* lcd: lcd_vsync */ + P8_29_pinmux { status = "disabled"; }; /* lcd: lcd_hsync */ + P8_28_pinmux { status = "disabled"; }; /* lcd: lcd_pclk */ + P8_30_pinmux { status = "disabled"; }; /* lcd: lcd_ac_bias_en */ + + P9_27_pinmux { status = "disabled"; }; /* lcd: gpio3_19 DISPEN */ + + P9_14_pinmux { status = "disabled"; }; /* pwm: ehrpwm1a PWM_BL */ + + P9_18_pinmux { status = "disabled"; }; /* i2c1_sda */ + P9_17_pinmux { status = "disabled"; }; /* i2c1_scl */ + P9_26_pinmux { status = "disabled"; }; /* touch interrupt on gpio0_14 */ +}; + +&am33xx_pinmux { + bb_lcd_pwm_backlight_pins: pinmux_bb_lcd_pwm_backlight_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_OUTPUT, MUX_MODE6) /* gpmc_a2.ehrpwm1a, OMAP_MUX_MODE6 | AM33XX_PIN_OUTPUT */ + >; + }; + + bb_lcd_lcd_pins: pinmux_bb_lcd_lcd_pins { + pinctrl-single,pins = < + /*LCD enable */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_FSR, PIN_OUTPUT, MUX_MODE7) /* mcasp0_fsr.gpio3_19, OUTPUT | MODE7 LCD DISEN */ + + AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0) + + AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT, MUX_MODE0) + >; + }; + + bb_i2c1_pins: pinmux_bb_i2c1_pins { + pinctrl-single,pins = < + AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | SLEWCTRL_SLOW | MUX_MODE2) /* spi0_d1.i2c1_sda */ + AM33XX_IOPAD(0x95C, PIN_INPUT_PULLUP | SLEWCTRL_SLOW | MUX_MODE2) /* spi0_cs0.i2c1_scl */ + >; + }; + + ar1021_pins: pinmux_ar1021_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT, MUX_MODE7) + >; + }; +}; + +&epwmss1 { + status = "okay"; +}; + +&ehrpwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&bb_lcd_pwm_backlight_pins>; + status = "okay"; +}; + +&lcdc { + status = "okay"; + + blue-and-red-wiring = "straight"; + + //FIXME - LCD doesn't init... + //port { + // lcdc_0: endpoint@0 { + // remote-endpoint = <&panel_0>; + // }; + //}; +}; + +&i2c1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_i2c1_pins>; + + clock-frequency = <100000>; + + #address-cells = <1>; + #size-cells = <0>; + + ar1021: ar1021@4d { + status = "okay"; + compatible = "microchip,ar1021-i2c"; + reg = <0x4d>; + pinctrl-names = "default"; + pinctrl-0 = <&ar1021_pins>; + interrupt-parent = <&gpio0>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH>; + + touchscreen-offset-x=<250>; + touchscreen-offset-y=<300>; + + touchscreen-inverted-y; + }; +}; + +&{/} { + backlight: backlight { + status = "okay"; + compatible = "pwm-backlight"; + pwms = <&ehrpwm1 0 500000 0>; + brightness-levels = < + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 48 49 + 50 51 52 53 54 55 56 57 58 59 + 60 61 62 63 64 65 66 67 68 69 + 70 71 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 88 89 + 90 91 92 93 94 95 96 97 98 99 + 100 + >; + default-brightness-level = <100>; + }; + + panel { + status = "okay"; + compatible = "ti,tilcdc,panel"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_lcd_lcd_pins>; + backlight = <&backlight>; + enable-gpios = <&gpio3 19 0>; + + //FIXME - LCD doesn't init... + //port { + // panel_0: endpoint@0 { + // remote-endpoint = <&lcdc_0>; + // }; + //}; + + panel-info { + ac-bias = <255>; + ac-bias-intrpt = <0>; + dma-burst-sz = <16>; + bpp = <16>; + fdd = <0x80>; + sync-edge = <0>; + sync-ctrl = <1>; + raster-order = <0>; + fifo-th = <0>; + }; + + display-timings { + native-mode = <&timing0>; + /* Settings for ThreeFive S9700RTWV35TR / LCD7 cape: */ + timing0: 800x480 { + clock-frequency = <30000000>; + hactive = <800>; + vactive = <480>; + hfront-porch = <40>; + hback-porch = <40>; + hsync-len = <48>; + vback-porch = <30>; + vfront-porch = <13>; + vsync-len = <3>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-BONE-eMMC1-01-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-BONE-eMMC1-01-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-BONE-eMMC1-01-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-BONE-eMMC1-01-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-BONE-eMMC1-01-00A0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P8_21_pinmux { status = "disabled"; }; /* mmc1_clk */ + P8_20_pinmux { status = "disabled"; }; /* mmc1_cmd */ + P8_25_pinmux { status = "disabled"; }; /* mmc1_dat0 */ + P8_24_pinmux { status = "disabled"; }; /* mmc1_dat1 */ + P8_05_pinmux { status = "disabled"; }; /* mmc1_dat2 */ + P8_06_pinmux { status = "disabled"; }; /* mmc1_dat3 */ + P8_23_pinmux { status = "disabled"; }; /* mmc1_dat4 */ + P8_22_pinmux { status = "disabled"; }; /* mmc1_dat5 */ + P8_03_pinmux { status = "disabled"; }; /* mmc1_dat6 */ + P8_04_pinmux { status = "disabled"; }; /* mmc1_dat7 */ +}; + +&am33xx_pinmux { + emmc_pins: pinmux_emmc_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT_PULLUP, MUX_MODE2) /* gpmc_csn1.mmc1_clk */ + AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2) /* gpmc_csn2.mmc1_cmd */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */ + >; + }; +}; + +&mmc2 { + vmmc-supply = <&vmmcsd_fixed>; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_pins>; + bus-width = <8>; + status = "okay"; + non-removable; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-BONE-LCD4-01-00A1.dtso b/arch/arm/boot/dts/ti/omap/BB-BONE-LCD4-01-00A1.dtso --- a/arch/arm/boot/dts/ti/omap/BB-BONE-LCD4-01-00A1.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-BONE-LCD4-01-00A1.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-BONE-LCD4-01-00A1.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_12_pinmux { status = "disabled"; }; /* P9_12: gpmc_ben1.gpio1_28, INPUT | PULLDIS | MODE7 */ + + P9_14_pinmux { status = "disabled"; }; /* P9_14: gpmc_a2.ehrpwm1a */ + + P9_27_pinmux { status = "disabled"; }; /* P9_27: mcasp0_fsr.gpio3_19 */ + + P8_45_pinmux { status = "disabled"; }; /* P8_45: lcd_data0.lcd_data0 */ + P8_46_pinmux { status = "disabled"; }; /* P8_46: lcd_data1.lcd_data1 */ + P8_43_pinmux { status = "disabled"; }; /* P8_43: lcd_data2.lcd_data2 */ + P8_44_pinmux { status = "disabled"; }; /* P8_44: lcd_data3.lcd_data3 */ + P8_41_pinmux { status = "disabled"; }; /* P8_41: lcd_data4.lcd_data4 */ + P8_42_pinmux { status = "disabled"; }; /* P8_42: lcd_data5.lcd_data5 */ + P8_39_pinmux { status = "disabled"; }; /* P8_39: lcd_data6.lcd_data6 */ + P8_40_pinmux { status = "disabled"; }; /* P8_40: lcd_data7.lcd_data7 */ + P8_37_pinmux { status = "disabled"; }; /* P8_37: lcd_data8.lcd_data8 */ + P8_38_pinmux { status = "disabled"; }; /* P8_38: lcd_data9.lcd_data9 */ + P8_36_pinmux { status = "disabled"; }; /* P8_36: lcd_data10.lcd_data10 */ + P8_34_pinmux { status = "disabled"; }; /* P8_34: lcd_data11.lcd_data11 */ + P8_35_pinmux { status = "disabled"; }; /* P8_35: lcd_data12.lcd_data12 */ + P8_33_pinmux { status = "disabled"; }; /* P8_33: lcd_data13.lcd_data13 */ + P8_31_pinmux { status = "disabled"; }; /* P8_31: lcd_data14.lcd_data14 */ + P8_32_pinmux { status = "disabled"; }; /* P8_32: lcd_data15.lcd_data15 */ + + P8_27_pinmux { status = "disabled"; }; /* P8_27: lcd_vsync.lcd_vsync */ + P8_29_pinmux { status = "disabled"; }; /* P8_29: lcd_hsync.lcd_hsync */ + P8_28_pinmux { status = "disabled"; }; /* P8_28: lcd_pclk.lcd_pclk */ + P8_30_pinmux { status = "disabled"; }; /* P8_30: lcd_ac_bias_en.lcd_ac_bias_en */ + + P9_15_pinmux { status = "disabled"; }; /* P9_15: gpmc_a0.gpio1_16 */ + P9_23_pinmux { status = "disabled"; }; /* P9_23: gpmc_a1.gpio1_17 */ + P9_16_pinmux { status = "disabled"; }; /* P9_16: gpmc_a3.gpio1_19 */ + P9_30_pinmux { status = "disabled"; }; /* P9_30: mcasp0_axr0.gpio3_16 */ + P9_24_pinmux { status = "disabled"; }; /* P9_24: uart1_txd.gpio0_15 */ +}; + +&am33xx_pinmux { + bb_lcd_led_pins: pinmux_bb_lcd_led_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_INPUT, MUX_MODE7) /* P9_12: gpmc_ben1.gpio1_28, INPUT | PULLDIS | MODE7 */ + >; + }; + + bb_lcd_pwm_backlight_pins: pinmux_bb_lcd_pwm_backlight_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_OUTPUT_PULLDOWN, MUX_MODE6) /* P9_14: gpmc_a2.ehrpwm1a */ + >; + }; + + bb_lcd_lcd_pins: pinmux_bb_lcd_lcd_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MCASP0_FSR, PIN_OUTPUT_PULLUP, MUX_MODE7) /* P9_27: mcasp0_fsr.gpio3_19 */ + + AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0) + + AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT, MUX_MODE0) + >; + }; + + bb_lcd_keymap_pins: pinmux_bb_lcd_keymap_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_INPUT, MUX_MODE7) /* P9_15: gpmc_a0.gpio1_16 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT, MUX_MODE7) /* P9_23: gpmc_a1.gpio1_17 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_INPUT, MUX_MODE7) /* P9_16: gpmc_a3.gpio1_19 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR0, PIN_INPUT, MUX_MODE7) /* P9_30: mcasp0_axr0.gpio3_16 */ + AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_INPUT, MUX_MODE7) /* P9_24: uart1_txd.gpio0_15 */ + >; + }; +}; + +&epwmss1 { + status = "okay"; +}; + +&ehrpwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&bb_lcd_pwm_backlight_pins>; + status = "okay"; +}; + +&lcdc { + status = "okay"; + + blue-and-red-wiring = "straight"; + + //FIXME - LCD doesn't init... + //port { + // lcdc_0: endpoint@0 { + // remote-endpoint = <&panel_0>; + // }; + //}; +}; + +&tscadc { + status = "okay"; + tsc { + ti,wires = <4>; + ti,x-plate-resistance = <200>; + ti,coordinate-readouts = <5>; + ti,wire-config = <0x00 0x11 0x22 0x33>; + ti,charge-delay = <0x400>; + }; + + adc { + ti,adc-channels = <4 5 6 7>; + }; +}; + +&{/} { + backlight: backlight { + status = "okay"; + compatible = "pwm-backlight"; + pwms = <&ehrpwm1 0 500000 0>; + brightness-levels = < + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 48 49 + 50 51 52 53 54 55 56 57 58 59 + 60 61 62 63 64 65 66 67 68 69 + 70 71 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 88 89 + 90 91 92 93 94 95 96 97 98 99 + 100 + >; + default-brightness-level = <100>; + }; + + panel { + status = "okay"; + compatible = "ti,tilcdc,panel"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_lcd_lcd_pins>; + backlight = <&backlight>; + + //FIXME - LCD doesn't init... + //port { + // panel_0: endpoint@0 { + // remote-endpoint = <&lcdc_0>; + // }; + //}; + + panel-info { + ac-bias = <255>; + ac-bias-intrpt = <0>; + dma-burst-sz = <16>; + bpp = <16>; + fdd = <0x80>; + sync-edge = <0>; + sync-ctrl = <1>; + raster-order = <0>; + fifo-th = <0>; + }; + display-timings { + native-mode = <&timing0>; + /* www.newhavendisplay.com/app_notes/OTA5180A.pdf */ + timing0: 480x272 { + clock-frequency = <9200000>; + hactive = <480>; + vactive = <272>; + hfront-porch = <8>; + hback-porch = <47>; + hsync-len = <41>; + vback-porch = <2>; + vfront-porch = <3>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_lcd_led_pins>; + + led-ld0 { + label = "lcd:green:usr0"; + gpios = <&gpio1 28 0>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_lcd_keymap_pins>; + + button-1 { + debounce_interval = <50>; + linux,code = <105>; + label = "left"; + gpios = <&gpio1 16 0x1>; + gpio-key,wakeup; + autorepeat; + }; + button-2 { + debounce_interval = <50>; + linux,code = <106>; + label = "right"; + gpios = <&gpio1 17 0x1>; + gpio-key,wakeup; + autorepeat; + }; + button-3 { + debounce_interval = <50>; + linux,code = <103>; + label = "up"; + gpios = <&gpio1 19 0x1>; + gpio-key,wakeup; + autorepeat; + }; + button-4 { + debounce_interval = <50>; + linux,code = <108>; + label = "down"; + gpios = <&gpio3 16 0x1>; + gpio-key,wakeup; + autorepeat; + }; + button-5 { + debounce_interval = <50>; + linux,code = <28>; + label = "enter"; + gpios = <&gpio0 15 0x1>; + gpio-key,wakeup; + }; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-BONE-NH7C-01-A0.dtso b/arch/arm/boot/dts/ti/omap/BB-BONE-NH7C-01-A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-BONE-NH7C-01-A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-BONE-NH7C-01-A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-BONE-NH7C-01-A0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P8_45_pinmux { status = "disabled"; }; /* lcd: lcd_data0 */ + P8_46_pinmux { status = "disabled"; }; /* lcd: lcd_data1 */ + P8_43_pinmux { status = "disabled"; }; /* lcd: lcd_data2 */ + P8_44_pinmux { status = "disabled"; }; /* lcd: lcd_data3 */ + P8_41_pinmux { status = "disabled"; }; /* lcd: lcd_data4 */ + P8_42_pinmux { status = "disabled"; }; /* lcd: lcd_data5 */ + P8_39_pinmux { status = "disabled"; }; /* lcd: lcd_data6 */ + P8_40_pinmux { status = "disabled"; }; /* lcd: lcd_data7 */ + P8_37_pinmux { status = "disabled"; }; /* lcd: lcd_data8 */ + P8_38_pinmux { status = "disabled"; }; /* lcd: lcd_data9 */ + P8_36_pinmux { status = "disabled"; }; /* lcd: lcd_data10 */ + P8_34_pinmux { status = "disabled"; }; /* lcd: lcd_data11 */ + P8_35_pinmux { status = "disabled"; }; /* lcd: lcd_data12 */ + P8_33_pinmux { status = "disabled"; }; /* lcd: lcd_data13 */ + P8_31_pinmux { status = "disabled"; }; /* lcd: lcd_data14 */ + P8_32_pinmux { status = "disabled"; }; /* lcd: lcd_data15 */ + + P8_15_pinmux { status = "disabled"; }; /* gpmc_ad15.lcd_data16 */ + P8_16_pinmux { status = "disabled"; }; /* gpmc_ad14.lcd_data17 */ + P8_11_pinmux { status = "disabled"; }; /* gpmc_ad13.lcd_data18 */ + P8_12_pinmux { status = "disabled"; }; /* gpmc_ad12.lcd_data19 */ + P8_17_pinmux { status = "disabled"; }; /* gpmc_ad11.lcd_data20 */ + P8_14_pinmux { status = "disabled"; }; /* gpmc_ad10.lcd_data21 */ + P8_13_pinmux { status = "disabled"; }; /* gpmc_ad9.lcd_data22 */ + P8_19_pinmux { status = "disabled"; }; /* gpmc_ad8.lcd_data23 */ + + P8_27_pinmux { status = "disabled"; }; /* lcd: lcd_vsync */ + P8_29_pinmux { status = "disabled"; }; /* lcd: lcd_hsync */ + P8_28_pinmux { status = "disabled"; }; /* lcd: lcd_pclk */ + P8_30_pinmux { status = "disabled"; }; /* lcd: lcd_ac_bias_en */ + + P8_18_pinmux { status = "disabled"; }; /* lcd: enable */ + + P9_14_pinmux { status = "disabled"; }; /* pwm: ehrpwm1a */ + + P9_27_pinmux { status = "disabled"; }; /* ft5336: gpio3_15 */ +}; + +&am33xx_pinmux { + bb_lcd_pwm_backlight_pins: pinmux_bb_lcd_pwm_backlight_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_OUTPUT_PULLDOWN, MUX_MODE6) /* P9_14: gpmc_a2.ehrpwm1a */ + >; + }; + + bb_lcd_lcd_pins: pinmux_bb_lcd_lcd_pins { + pinctrl-single,pins = < + /*LCD enable */ + AM33XX_PADCONF(AM335X_PIN_GPMC_CLK, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_clk_mux0.gpio2_1 */ + + AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0) + + AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_OUTPUT, MUX_MODE1) /* P8_15: gpmc_ad15.lcd_data16 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_OUTPUT, MUX_MODE1) /* P8_16: gpmc_ad14.lcd_data17 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_OUTPUT, MUX_MODE1) /* P8_11: gpmc_ad13.lcd_data18 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_OUTPUT, MUX_MODE1) /* P8_12: gpmc_ad12.lcd_data19 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_OUTPUT, MUX_MODE1) /* P8_17: gpmc_ad11.lcd_data20 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_OUTPUT, MUX_MODE1) /* P8_14: gpmc_ad10.lcd_data21 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_OUTPUT, MUX_MODE1) /* P8_13: gpmc_ad9.lcd_data22 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_OUTPUT, MUX_MODE1) /* P8_19: gpmc_ad8.lcd_data23 */ + + AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT, MUX_MODE0) + >; + }; + + edt_ft5x06_pins: pinmux_edt_ft5x06_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MCASP0_FSR, PIN_INPUT_PULLDOWN, MUX_MODE7) /* mcasp0_fsr.gpio3_19 */ + >; + }; +}; + +&epwmss1 { + status = "okay"; +}; + +&ehrpwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&bb_lcd_pwm_backlight_pins>; + status = "okay"; +}; + +&lcdc { + status = "okay"; + + blue-and-red-wiring = "crossed"; + + //FIXME - LCD doesn't init... + //port { + // lcdc_0: endpoint@0 { + // remote-endpoint = <&panel_0>; + // }; + //}; +}; + +&i2c2 { + status = "okay"; + + clock-frequency = <100000>; + + #address-cells = <1>; + #size-cells = <0>; + + edt-ft5x06@38 { + status = "okay"; + compatible = "edt,edt-ft5406"; + reg = <0x38>; + pinctrl-names = "default"; + pinctrl-0 = <&edt_ft5x06_pins>; + interrupt-parent = <&gpio3>; + interrupts = <19 0>; + //reset-gpios = <&gpio3 14 GPIO_ACTIVE_LOW>; + + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; + //touchscreen-swapped-x-y; + }; +}; + +&{/} { + backlight: backlight { + status = "okay"; + compatible = "pwm-backlight"; + pwms = <&ehrpwm1 0 500000 0>; + brightness-levels = < + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 48 49 + 50 51 52 53 54 55 56 57 58 59 + 60 61 62 63 64 65 66 67 68 69 + 70 71 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 88 89 + 90 91 92 93 94 95 96 97 98 99 + 100 + >; + default-brightness-level = <100>; + }; + + /* NHD-7.0-800480EF-ATXL# */ + panel { + status = "okay"; + compatible = "ti,tilcdc,panel"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_lcd_lcd_pins>; + backlight = <&backlight>; + enable-gpios = <&gpio2 1 0>; + + //FIXME - LCD doesn't init... + //port { + // panel_0: endpoint@0 { + // remote-endpoint = <&lcdc_0>; + // }; + //}; + + panel-info { + ac-bias = <255>; + ac-bias-intrpt = <0>; + dma-burst-sz = <16>; + bpp = <32>; + fdd = <0x80>; + tft-alt-mode = <0>; + stn-565-mode = <0>; + mono-8bit-mode = <0>; + sync-edge = <0>; + sync-ctrl = <0>; + raster-order = <0>; + fifo-th = <0>; + }; + + display-timings { + native-mode = <&timing0>; + timing0: 800x480 { + clock-frequency = <45000000>; + hactive = <800>; + vactive = <480>; + hfront-porch = <40>; + hback-porch = <40>; + hsync-len = <48>; + vback-porch = <29>; + vfront-porch = <13>; + vsync-len = <3>; + hsync-active = <0>; + vsync-active = <0>; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-CAPE-DISP-CT4-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-CAPE-DISP-CT4-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-CAPE-DISP-CT4-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-CAPE-DISP-CT4-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-CAPE-DISP-CT4-00A0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P8_45_pinmux { status = "disabled"; }; /* lcd: lcd_data0 */ + P8_46_pinmux { status = "disabled"; }; /* lcd: lcd_data1 */ + P8_43_pinmux { status = "disabled"; }; /* lcd: lcd_data2 */ + P8_44_pinmux { status = "disabled"; }; /* lcd: lcd_data3 */ + P8_41_pinmux { status = "disabled"; }; /* lcd: lcd_data4 */ + P8_42_pinmux { status = "disabled"; }; /* lcd: lcd_data5 */ + P8_39_pinmux { status = "disabled"; }; /* lcd: lcd_data6 */ + P8_40_pinmux { status = "disabled"; }; /* lcd: lcd_data7 */ + P8_37_pinmux { status = "disabled"; }; /* lcd: lcd_data8 */ + P8_38_pinmux { status = "disabled"; }; /* lcd: lcd_data9 */ + P8_36_pinmux { status = "disabled"; }; /* lcd: lcd_data10 */ + P8_34_pinmux { status = "disabled"; }; /* lcd: lcd_data11 */ + P8_35_pinmux { status = "disabled"; }; /* lcd: lcd_data12 */ + P8_33_pinmux { status = "disabled"; }; /* lcd: lcd_data13 */ + P8_31_pinmux { status = "disabled"; }; /* lcd: lcd_data14 */ + P8_32_pinmux { status = "disabled"; }; /* lcd: lcd_data15 */ + + P8_27_pinmux { status = "disabled"; }; /* lcd: lcd_vsync */ + P8_29_pinmux { status = "disabled"; }; /* lcd: lcd_hsync */ + P8_28_pinmux { status = "disabled"; }; /* lcd: lcd_pclk */ + P8_30_pinmux { status = "disabled"; }; /* lcd: lcd_ac_bias_en */ + + P9_28_pinmux { status = "disabled"; }; /* pwm: eCAP2_in_PWM2_out */ + + P9_29_pinmux { status = "disabled"; }; /* ft5336: gpio3_15 */ + P9_31_pinmux { status = "disabled"; }; /* ft5336: gpio3_14 */ +}; + +&am33xx_pinmux { + bb_lcd_pwm_backlight_pins: pinmux_bb_lcd_pwm_backlight_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_OUTPUT_PULLDOWN, MUX_MODE4) /* mcasp0_ahclkr.eCAP2_in_PWM2_out */ + >; + }; + + bb_lcd_lcd_pins: pinmux_bb_lcd_lcd_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0) + + AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT, MUX_MODE0) + >; + }; + + edt_ft5336_ts_pins: pinmux_edt_ft5336_ts_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_INPUT_PULLDOWN, MUX_MODE7) /* mcasp0_fsx.gpio3_15 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_INPUT_PULLDOWN, MUX_MODE7) /* mcasp0_aclkx.gpio3_14 */ + >; + }; +}; + +&epwmss2 { + status = "okay"; +}; + +&ecap2 { + pinctrl-names = "default"; + pinctrl-0 = <&bb_lcd_pwm_backlight_pins>; + status = "okay"; +}; + +&lcdc { + status = "okay"; + + blue-and-red-wiring = "straight"; + + //FIXME - LCD doesn't init... + //port { + // lcdc_0: endpoint@0 { + // remote-endpoint = <&panel_0>; + // }; + //}; +}; + +&i2c2 { + status = "okay"; + + /* this is the configuration part */ + clock-frequency = <100000>; + + #address-cells = <1>; + #size-cells = <0>; + + edt-ft5336@38 { + status = "okay"; + compatible = "edt,edt-ft5336", "edt,edt-ft5306", "edt,edt-ft5x06"; + reg = <0x38>; + pinctrl-names = "default"; + pinctrl-0 = <&edt_ft5336_ts_pins>; + interrupt-parent = <&gpio3>; + interrupts = <15 0>; + reset-gpios = <&gpio3 14 GPIO_ACTIVE_LOW>; + + touchscreen-size-x = <272>; + touchscreen-size-y = <480>; + touchscreen-swapped-x-y; + }; +}; + +&{/} { + backlight: backlight { + status = "okay"; + compatible = "pwm-backlight"; + pwms = <&ecap2 0 500000 0>; + brightness-levels = < + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 48 49 + 50 51 52 53 54 55 56 57 58 59 + 60 61 62 63 64 65 66 67 68 69 + 70 71 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 88 89 + 90 91 92 93 94 95 96 97 98 99 + 100 + >; + default-brightness-level = <50>; + }; + + panel { + status = "okay"; + compatible = "ti,tilcdc,panel"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_lcd_lcd_pins>; + backlight = <&backlight>; + + //FIXME - LCD doesn't init... + //port { + // panel_0: endpoint@0 { + // remote-endpoint = <&lcdc_0>; + // }; + //}; + + panel-info { + ac-bias = <255>; + ac-bias-intrpt = <0>; + dma-burst-sz = <16>; + bpp = <16>; + fdd = <0x80>; + tft-alt-mode = <0>; + stn-565-mode = <0>; + mono-8bit-mode = <0>; + sync-edge = <0>; + sync-ctrl = <1>; + raster-order = <0>; + fifo-th = <0>; + }; + /* ILI6480 */ + display-timings { + native-mode = <&timing0>; + timing0: 480x272 { + clock-frequency = <9000000>; + hactive = <480>; + vactive = <272>; + hfront-porch = <5>; + hback-porch = <40>; + hsync-len = <1>; + vback-porch = <8>; + vfront-porch = <8>; + vsync-len = <1>; + hsync-active = <0>; + vsync-active = <0>; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-HDMI-TDA998x-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-HDMI-TDA998x-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-HDMI-TDA998x-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-HDMI-TDA998x-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-HDMI-TDA998x-00A0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_25_pinmux { status = "disabled"; }; /* mcasp0_ahclkx */ + P9_28_pinmux { status = "disabled"; }; /* mcasp0_axr2 */ + P9_29_pinmux { status = "disabled"; }; /* mcasp0_fsx */ + P9_31_pinmux { status = "disabled"; }; /* mcasp0_aclkx */ + P8_45_pinmux { status = "disabled"; }; /* lcd_data0 */ + P8_46_pinmux { status = "disabled"; }; /* lcd_data1 */ + P8_43_pinmux { status = "disabled"; }; /* lcd_data2 */ + P8_44_pinmux { status = "disabled"; }; /* lcd_data3 */ + P8_41_pinmux { status = "disabled"; }; /* lcd_data4 */ + P8_42_pinmux { status = "disabled"; }; /* lcd_data5 */ + P8_39_pinmux { status = "disabled"; }; /* lcd_data6 */ + P8_40_pinmux { status = "disabled"; }; /* lcd_data7 */ + P8_37_pinmux { status = "disabled"; }; /* lcd_data8 */ + P8_38_pinmux { status = "disabled"; }; /* lcd_data9 */ + P8_36_pinmux { status = "disabled"; }; /* lcd_data10 */ + P8_34_pinmux { status = "disabled"; }; /* lcd_data11 */ + P8_35_pinmux { status = "disabled"; }; /* lcd_data12 */ + P8_33_pinmux { status = "disabled"; }; /* lcd_data13 */ + P8_31_pinmux { status = "disabled"; }; /* lcd_data14 */ + P8_32_pinmux { status = "disabled"; }; /* lcd_data15 */ + P8_27_pinmux { status = "disabled"; }; /* lcd_vsync */ + P8_29_pinmux { status = "disabled"; }; /* lcd_hsync */ + P8_28_pinmux { status = "disabled"; }; /* lcd_pclk */ + P8_30_pinmux { status = "disabled"; }; /* lcd_ac_bias_en */ +}; + +&am33xx_pinmux { + nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLUP, MUX_MODE7) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + >; + }; + + nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLDOWN, MUX_MODE7) + >; + }; + + mcasp0_pins: mcasp0_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_INPUT_PULLUP, MUX_MODE0) /* mcasp0_ahcklx.mcasp0_ahclkx */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_OUTPUT_PULLDOWN, MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/ + AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_OUTPUT_PULLUP, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a11.GPIO1_27 */ + >; + }; +}; + +&lcdc { + status = "okay"; + + /* If you want to get 24 bit RGB and 16 BGR mode instead of + * current 16 bit RGB and 24 BGR modes, set the propety + * below to "crossed" and uncomment the video-ports -property + * in tda19988 node. + */ + blue-and-red-wiring = "straight"; + + port { + lcdc_0: endpoint@0 { + remote-endpoint = <&hdmi_0>; + }; + }; +}; + +&i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + tda19988: tda19988@70 { + compatible = "nxp,tda998x"; + reg = <0x70>; + nxp,calib-gpios = <&gpio1 25 0>; + interrupts-extended = <&gpio1 25 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-names = "default", "off"; + pinctrl-0 = <&nxp_hdmi_bonelt_pins>; + pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>; + + /* Convert 24bit BGR to RGB, e.g. cross red and blue wiring */ + /* video-ports = <0x234501>; */ + + #sound-dai-cells = <0>; + audio-ports = < TDA998x_I2S 0x03>; + + ports { + port@0 { + hdmi_0: endpoint@0 { + remote-endpoint = <&lcdc_0>; + }; + }; + }; + }; +}; + +&mcasp0 { + #sound-dai-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&mcasp0_pins>; + status = "okay"; + op-mode = <0>; /* MCASP_IIS_MODE */ + tdm-slots = <2>; + serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ + 0 0 1 0 + >; + tx-num-evt = <32>; + rx-num-evt = <32>; +}; + +&{/} { + clk_mcasp0_fixed: clk_mcasp0_fixed { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24576000>; + }; + + clk_mcasp0: clk_mcasp0 { + #clock-cells = <0>; + compatible = "gpio-gate-clock"; + clocks = <&clk_mcasp0_fixed>; + enable-gpios = <&gpio1 27 0>; /* BeagleBone Black Clk enable on GPIO1_27 */ + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "TI BeagleBone Black"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&dailink0_master>; + simple-audio-card,frame-master = <&dailink0_master>; + + dailink0_master: simple-audio-card,cpu { + sound-dai = <&mcasp0>; + clocks = <&clk_mcasp0>; + }; + + simple-audio-card,codec { + sound-dai = <&tda19988>; + }; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-I2C1-MCP7940X-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-I2C1-MCP7940X-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-I2C1-MCP7940X-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-I2C1-MCP7940X-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2015 Robert Nelson + */ + +/dts-v1/; +/plugin/; + +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-I2C1-MCP7940X-00A0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_17_pinmux { status = "disabled"; }; /* spi0_d1.i2c1_sda */ + P9_18_pinmux { status = "disabled"; }; /* spi0_cs0.i2c1_scl */ + P8_26_pinmux { status = "disabled"; }; /* rtc: gpio1_29 */ +}; + +&{/} { + aliases { + rtc0 = &extrtc; + /* find /sys/firmware/devicetree/ | grep rtc@ */ + rtc1 = "/ocp/interconnect@44c00000/segment@200000/target-module@3e000/rtc@0"; + }; + + gpio_keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_gpio1_29_pins>; + + rtc_mfp@1 { + label = "rtc_mfp"; + gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>; + linux,code = <143>; /* System Wake Up */ + gpio-key,wakeup; + }; + }; +}; + +&am33xx_pinmux { + bb_gpio1_29_pins: pinmux_bb_gpio1_29_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_INPUT, MUX_MODE7) /* gpmc_csn0.gpio1_29 */ + >; + }; + + bb_i2c1_pins: pinmux_bb_i2c1_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_SPI0_D1, SLEWCTRL_SLOW | PIN_INPUT_PULLUP, MUX_MODE2) /* spi0_d1.i2c1_sda */ + AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, SLEWCTRL_SLOW | PIN_INPUT_PULLUP, MUX_MODE2) /* spi0_cs0.i2c1_scl */ + >; + }; +}; + +&i2c1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_i2c1_pins>; + + clock-frequency = <100000>; + + #address-cells = <1>; + #size-cells = <0>; + + extrtc: mcp7940x@68 { + status = "okay"; + compatible = "microchip,mcp7940x"; + reg = <0x68>; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-I2C1-RTC-DS3231.dtso b/arch/arm/boot/dts/ti/omap/BB-I2C1-RTC-DS3231.dtso --- a/arch/arm/boot/dts/ti/omap/BB-I2C1-RTC-DS3231.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-I2C1-RTC-DS3231.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Sam Cohen + * + * Based on BB-I2C2-RTC-DS3231.dts: + * Copyright (C) 2019 Tomas Arturo Herrera Castro + * + * DTS file for DS3231 Real Time Clock, running on the I2C1 interface. Also see + * BB-I2C2-RTC-DS3231.dts to run this RTC on I2C2. + * + * Tested on BeagleBone Black Wireless + */ + +/dts-v1/; +/plugin/; + +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-I2C1-RTC-DS3231.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_17_pinmux { status = "disabled"; }; /* spi0_d1.i2c1_sda */ + P9_18_pinmux { status = "disabled"; }; /* spi0_cs0.i2c1_scl */ +}; + +&{/} { + aliases { + rtc0 = &extrtc; + /* find /sys/firmware/devicetree/ | grep rtc@ */ + rtc1 = "/ocp/interconnect@44c00000/segment@200000/target-module@3e000/rtc@0"; + }; +}; + +&am33xx_pinmux { + bb_i2c1_pins: pinmux_bb_i2c1_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_SPI0_D1, SLEWCTRL_SLOW | PIN_INPUT_PULLUP, MUX_MODE2) /* spi0_d1.i2c1_sda */ + AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, SLEWCTRL_SLOW | PIN_INPUT_PULLUP, MUX_MODE2) /* spi0_cs0.i2c1_scl */ + >; + }; +}; + +&i2c1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_i2c1_pins>; + + clock-frequency = <100000>; + + #address-cells = <1>; + #size-cells = <0>; + + extrtc: ds3231@68 { + status = "okay"; + compatible = "maxim,ds3231"; + reg = <0x68>; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-I2C1-RTC-PCF8563.dtso b/arch/arm/boot/dts/ti/omap/BB-I2C1-RTC-PCF8563.dtso --- a/arch/arm/boot/dts/ti/omap/BB-I2C1-RTC-PCF8563.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-I2C1-RTC-PCF8563.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018 Robert Nelson + */ + +/dts-v1/; +/plugin/; + +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-I2C1-RTC-PCF8563.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_17_pinmux { status = "disabled"; }; /* spi0_d1.i2c1_sda */ + P9_18_pinmux { status = "disabled"; }; /* spi0_cs0.i2c1_scl */ +}; + +&{/} { + aliases { + rtc0 = &extrtc; + /* find /sys/firmware/devicetree/ | grep rtc@ */ + rtc1 = "/ocp/interconnect@44c00000/segment@200000/target-module@3e000/rtc@0"; + }; +}; + +&am33xx_pinmux { + bb_i2c1_pins: pinmux_bb_i2c1_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_SPI0_D1, SLEWCTRL_SLOW | PIN_INPUT_PULLUP, MUX_MODE2) /* spi0_d1.i2c1_sda */ + AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, SLEWCTRL_SLOW | PIN_INPUT_PULLUP, MUX_MODE2) /* spi0_cs0.i2c1_scl */ + >; + }; +}; + +&i2c1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_i2c1_pins>; + + clock-frequency = <100000>; + + #address-cells = <1>; + #size-cells = <0>; + + extrtc: pcf8563@51 { + status = "okay"; + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-I2C2-BME680.dtso b/arch/arm/boot/dts/ti/omap/BB-I2C2-BME680.dtso --- a/arch/arm/boot/dts/ti/omap/BB-I2C2-BME680.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-I2C2-BME680.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Robert Nelson + */ + +/dts-v1/; +/plugin/; + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-I2C2-BME680.kernel = __TIMESTAMP__; + }; +}; + +&i2c2 { + status = "okay"; + + clock-frequency = <100000>; + + #address-cells = <1>; + #size-cells = <0>; + + bme680@76 { + status = "okay"; + compatible = "bosch,bme680"; + reg = <0x76>; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-I2C2-MPU6050.dtso b/arch/arm/boot/dts/ti/omap/BB-I2C2-MPU6050.dtso --- a/arch/arm/boot/dts/ti/omap/BB-I2C2-MPU6050.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-I2C2-MPU6050.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Robert Nelson + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-I2C2-MPU6050.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_12_pinmux { status = "disabled"; }; +}; + +&am33xx_pinmux { + mpu6050_pins: pinmux_mpu6050_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_INPUT, MUX_MODE7) /* gpio1_28 */ + >; + }; +}; + +&i2c2 { + status = "okay"; + + clock-frequency = <400000>; + + #address-cells = <1>; + #size-cells = <0>; + + imu@68 { + pinctrl-names = "default"; + pinctrl-0 = <&mpu6050_pins>; + compatible = "invensense,mpu6050"; + reg = <0x68>; + interrupt-parent = <&gpio1>; + interrupts = <28 IRQ_TYPE_EDGE_RISING>; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-LCD-ADAFRUIT-24-SPI1-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-LCD-ADAFRUIT-24-SPI1-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-LCD-ADAFRUIT-24-SPI1-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-LCD-ADAFRUIT-24-SPI1-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 CircuitCo + * Copyright (C) 2018 Drew Fustini + * Copyright (C) 2019 Mark A. Yoder + * + * Adafruit 2.4" TFT LCD on SPI1 bus using tinydrm ili9341 driver + * + * DOCUMENTATION: + * -------------- + * This file was copied from src/arm/BB-SPIDEV1-00A0.dts and modified + * by Drew Fustini based on an exmample from David Lechner. + * Later modified by Mark A. Yoder for the 2.4" LCD. + * + * This is the Adafruit 2.4" TFT LCD: + * https://www.adafruit.com/product/2478 + * + * It should be connected to BeagleBone SPI1 bus: + * + * P9.16 <--> lite (pwm) [OPTIONAL] + * P9.23 <--> lite (gpio) [OPTIONAL] + * P9.25 <--> reset + * P9.27 <--> dc + * P9.28 <--> tft_cs + * P9.29 <--> miso + * P9.30 <--> mosi + * P9.31 <--> clk + * + * This overlay will load the mainline tinydrm ili9341 driver by David Lechner: + * https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/tiny/ili9341.c + * + * Tested with 4.19.59-ti-r26 kernel on Debian 10.1 image + * + * Run libdrm modetest for colorbar test based on instructions from: + * https://github.com/notro/tinydrm/wiki/Development#modetest + * + * modetest -M "ili9341" -c #this will display connector id + * modetest -M "ili9341" -s 28:128x160 #connector id and resolution + * # you should now see a color bar on the LCD + * + * Mailing list post with more information: + * https://groups.google.com/d/msg/beagleboard/GuMQIP_XCW0/b3lxbx_8AwAJ + * + * Discussion with notro on how to test tinydrm driver: + * https://github.com/notro/tinydrm/issues/1#issuecomment-367279037 + */ + +/dts-v1/; +/plugin/; + +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-LCD-ADAFRUIT-24-SPI1-00A0 = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_25_pinmux { status = "disabled"; }; /* lcd reset */ + P9_16_pinmux { status = "disabled"; }; /* lcd pwm backlight (OPTIONAL) */ + P9_27_pinmux { status = "disabled"; }; /* lcd dc */ + P9_28_pinmux { status = "disabled"; }; /* spi1_cs0 */ + P9_29_pinmux { status = "disabled"; }; /* spi1_d0 */ + P9_30_pinmux { status = "disabled"; }; /* spi1_d1 */ + P9_31_pinmux { status = "disabled"; }; /* spi1_sclk */ +}; + +&am33xx_pinmux { + /* default state has all gpios released and mode set to uart1 */ + /* See page 1446 of am35xx TRM */ + bb_spi1_pins: pinmux_bb_spi1_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_INPUT, MUX_MODE3) /* mcasp0_aclkx.spi1_sclk */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_INPUT, MUX_MODE3) /* mcasp0_fsx.spi1_d0 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR0, PIN_INPUT, MUX_MODE3) /* mcasp0_axr0.spi1_d1 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_INPUT, MUX_MODE3) /* mcasp0_ahclkr.spi1_cs0 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_FSR, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpio, dc */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpio, reset */ + >; + }; + + backlight_pwm_pins: pinmux_backlight_pwm_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_OUTPUT, MUX_MODE6) /* gpmc_a2.ehrpwm1b */ + >; + }; /* gpmc_a2.ehrpwm1b */ +}; + +&epwmss1 { + status = "okay"; +}; + +&ehrpwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&backlight_pwm_pins>; + status = "okay"; +}; + +&spi1 { + #address-cells = <1>; + #size-cells = <0>; + + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_spi1_pins>; + + channel@0{ + status = "disabled"; + reg = <0>; + }; + + display@0{ + status = "okay"; + compatible = "adafruit,yx240qv29", "ilitek,ili9341"; + reg = <0>; + spi-max-frequency = <32000000>; + dc-gpios = <&gpio3 19 0>; // lcd dc P9.27 gpio3[19] + reset-gpios = <&gpio3 21 0>; // lcd reset P9.25 gpio3[21] + // backlight is optional + // choose either pwm or gpio control + //backlight = <&backlight_gpio>; // lcd lite P9.23 gpio1[17] + backlight = <&backlight_pwm>; // lcd lite P9.16 gpmc_a2.ehrpwm1b + // refer to https://elinux.org/Beagleboard:Cape_Expansion_Headers + // rotation is optional + rotation = <270>; + }; +}; + +&{/} { + bl_reg: backlight-regulator { + compatible = "regulator-fixed"; + regulator-name = "backlight"; + regulator-always-on; + regulator-boot-on; + }; + + /* backlight is optional */ + backlight_gpio: backlight_gpio { + compatible = "gpio-backlight"; + gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>; + // connect lcd lite pin to P9.23 which is gpio1[17] + // refer to https://elinux.org/Beagleboard:Cape_Expansion_Headers + }; + + /* + * Turn the PWM backlight on by setting bl_power to 0: + * echo 0 > /sys/class/backlight/backlight_pwm/bl_power + */ + backlight_pwm: backlight_pwm { + // P9.16 <--> lite (pwm-backlight EHRPWM1B) + status = "okay"; + compatible = "pwm-backlight"; + pwms = <&ehrpwm1 1 500000 0>; // First digit: 0 for A side of pwm, 1 for B side + // 500000 is the PWM period in ns + // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/pwm/pwm.txt + brightness-levels = < + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 48 49 + 50 51 52 53 54 55 56 57 58 59 + 60 61 62 63 64 65 66 67 68 69 + 70 71 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 88 89 + 90 91 92 93 94 95 96 97 98 99 + 100 + >; + default-brightness-level = <100>; + power-supply = <&bl_reg>; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-NHDMI-TDA998x-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-NHDMI-TDA998x-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-NHDMI-TDA998x-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-NHDMI-TDA998x-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-NHDMI-TDA998x-00A0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P8_45_pinmux { status = "disabled"; }; /* lcd_data0 */ + P8_46_pinmux { status = "disabled"; }; /* lcd_data1 */ + P8_43_pinmux { status = "disabled"; }; /* lcd_data2 */ + P8_44_pinmux { status = "disabled"; }; /* lcd_data3 */ + P8_41_pinmux { status = "disabled"; }; /* lcd_data4 */ + P8_42_pinmux { status = "disabled"; }; /* lcd_data5 */ + P8_39_pinmux { status = "disabled"; }; /* lcd_data6 */ + P8_40_pinmux { status = "disabled"; }; /* lcd_data7 */ + P8_37_pinmux { status = "disabled"; }; /* lcd_data8 */ + P8_38_pinmux { status = "disabled"; }; /* lcd_data9 */ + P8_36_pinmux { status = "disabled"; }; /* lcd_data10 */ + P8_34_pinmux { status = "disabled"; }; /* lcd_data11 */ + P8_35_pinmux { status = "disabled"; }; /* lcd_data12 */ + P8_33_pinmux { status = "disabled"; }; /* lcd_data13 */ + P8_31_pinmux { status = "disabled"; }; /* lcd_data14 */ + P8_32_pinmux { status = "disabled"; }; /* lcd_data15 */ + P8_27_pinmux { status = "disabled"; }; /* lcd_vsync */ + P8_29_pinmux { status = "disabled"; }; /* lcd_hsync */ + P8_28_pinmux { status = "disabled"; }; /* lcd_pclk */ + P8_30_pinmux { status = "disabled"; }; /* lcd_ac_bias_en */ +}; + +&am33xx_pinmux { + nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLUP, MUX_MODE7) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + >; + }; + + nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLDOWN, MUX_MODE7) + >; + }; +}; + +&lcdc { + status = "okay"; + + /* If you want to get 24 bit RGB and 16 BGR mode instead of + * current 16 bit RGB and 24 BGR modes, set the propety + * below to "crossed" and uncomment the video-ports -property + * in tda19988 node. + */ + blue-and-red-wiring = "straight"; + + port { + lcdc_0: endpoint@0 { + remote-endpoint = <&hdmi_0>; + }; + }; +}; + +&i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + tda19988: tda19988@70 { + compatible = "nxp,tda998x"; + reg = <0x70>; + nxp,calib-gpios = <&gpio1 25 0>; + interrupts-extended = <&gpio1 25 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-names = "default", "off"; + pinctrl-0 = <&nxp_hdmi_bonelt_pins>; + pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>; + + /* Convert 24bit BGR to RGB, e.g. cross red and blue wiring */ + /* video-ports = <0x234501>; */ + + ports { + port@0 { + hdmi_0: endpoint@0 { + remote-endpoint = <&lcdc_0>; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BBORG_COMMS-00A2.dtso b/arch/arm/boot/dts/ti/omap/BBORG_COMMS-00A2.dtso --- a/arch/arm/boot/dts/ti/omap/BBORG_COMMS-00A2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BBORG_COMMS-00A2.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012,2019 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2015 Robert Nelson + * Copyright (C) 2015 Sebastian JegerÃ¥s + */ + +/* + * Tested RobertCNelson [20240119] BBB and BBAI (6.1.69-ti-r21) + * + * sudo ip link set can0 type can bitrate 500000 + * sudo ifconfig can0 up + * + * candump can0 + * cansend can0 123#DEADBEEF + */ + +/dts-v1/; +/plugin/; + +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BBORG_COMMS-00A2.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_24_pinmux { status = "disabled"; }; + P9_26_pinmux { status = "disabled"; }; + P9_13_pinmux { status = "disabled"; }; + P9_11_pinmux { status = "disabled"; }; +}; + +&bone_can_1 { + status = "okay"; +}; + +&bone_uart_4 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BBORG_FAN-A000.dtso b/arch/arm/boot/dts/ti/omap/BBORG_FAN-A000.dtso --- a/arch/arm/boot/dts/ti/omap/BBORG_FAN-A000.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BBORG_FAN-A000.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Robert Nelson + */ + +/dts-v1/; +/plugin/; + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BBORG_FAN-A000.kernel = __TIMESTAMP__; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BBORG_RELAY-00A2.dtso b/arch/arm/boot/dts/ti/omap/BBORG_RELAY-00A2.dtso --- a/arch/arm/boot/dts/ti/omap/BBORG_RELAY-00A2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BBORG_RELAY-00A2.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2015 Robert Nelson + * Copyright (C) 2019 Amilcar Lucas + */ + +/dts-v1/; +/plugin/; + +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BBORG_RELAY-00A2.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_41_pinmux { status = "disabled"; }; /* P9_41: gpmc_a0.gpio0_20 */ + P9_42_pinmux { status = "disabled"; }; /* P9_42: gpmc_a1.gpio0_07 */ + P9_30_pinmux { status = "disabled"; }; /* P9_30: gpmc_be1n.gpio3_16 */ + P9_27_pinmux { status = "disabled"; }; /* P9_27: mcasp0_fsr.gpio3_19 */ +}; + +&am33xx_pinmux { + bb_gpio_relay_pins: pinmux_bb_gpio_relay_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* P9_41: Relay1 */ + AM33XX_PADCONF(AM335X_PIN_ECAP0_IN_PWM0_OUT, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* P9_42: Relay2 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR0, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* P9_30: Relay3 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_FSR, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* P9_27: Relay4 */ + >; + }; +}; + +&{/} { + leds { + pinctrl-names = "default"; + pinctrl-0 = <&bb_gpio_relay_pins>; + + compatible = "gpio-leds"; + + jp@1 { + label = "relay-jp1"; + gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + jp@2 { + label = "relay-jp2"; + gpios = <&gpio0 07 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + jp@3 { + label = "relay-jp3"; + gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + jp@4 { + label = "relay-jp4"; + gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-SPIDEV0-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-SPIDEV0-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-SPIDEV0-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-SPIDEV0-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 CircuitCo + * Virtual cape for SPI0 on connector pins P9.22 P9.21 P9.18 P9.17 + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-SPIDEV0-00A0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_17_pinmux { status = "disabled"; }; /* P9_17 (A16) spi0_cs0.spi0_cs0 */ + P9_18_pinmux { status = "disabled"; }; /* P9_18 (B16) spi0_d1.spi0_d1 */ + P9_21_pinmux { status = "disabled"; }; /* P9_21 (B17) spi0_d0.spi0_d0 */ + P9_22_pinmux { status = "disabled"; }; /* P9_22 (A17) spi0_sclk.spi0_sclk */ +}; + +&am33xx_pinmux { + bb_spi0_pins: pinmux_bb_spi0_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT, MUX_MODE0) /* P9_22 (A17) spi0_sclk.spi0_sclk */ + AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_INPUT, MUX_MODE0) /* P9_21 (B17) spi0_d0.spi0_d0 */ + AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_INPUT, MUX_MODE0) /* P9_18 (B16) spi0_d1.spi0_d1 */ + AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT, MUX_MODE0) /* P9_17 (A16) spi0_cs0.spi0_cs0 */ + >; + }; +}; + +&spi0 { + #address-cells = <1>; + #size-cells = <0>; + + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_spi0_pins>; + + /* + * Select the D0 pin as output and D1 as + * input. The default is D0 as input and + * D1 as output. + */ + //ti,pindir-d0-out-d1-in; + + channel@0 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "rohm,dh2228fv"; + symlink = "bone/spi/0.0"; + + reg = <0>; + spi-max-frequency = <16000000>; + spi-cpha; + }; + + channel@1 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "rohm,dh2228fv"; + symlink = "bone/spi/0.1"; + + reg = <1>; + spi-max-frequency = <16000000>; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-SPIDEV1-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-SPIDEV1-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-SPIDEV1-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-SPIDEV1-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 CircuitCo + * Virtual cape for SPI1 on connector pins P9.29 P9.31 P9.30 P9.28 + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-SPIDEV1-00A0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_28_pinmux { status = "disabled"; }; /* P9_28 (C12) mcasp0_ahclkr.spi1_cs0 */ + P9_30_pinmux { status = "disabled"; }; /* P9_30 (D12) mcasp0_axr0.spi1_d1 */ + P9_29_pinmux { status = "disabled"; }; /* P9_29 (B13) mcasp0_fsx.spi1_d0 */ + P9_31_pinmux { status = "disabled"; }; /* P9_31 (A13) mcasp0_aclkx.spi1_sclk */ +}; + +&am33xx_pinmux { + bb_spi1_pins: pinmux_bb_spi1_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_INPUT, MUX_MODE3) /* P9_31 (A13) mcasp0_aclkx.spi1_sclk */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_INPUT, MUX_MODE3) /* P9_29 (B13) mcasp0_fsx.spi1_d0 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR0, PIN_INPUT, MUX_MODE3) /* P9_30 (D12) mcasp0_axr0.spi1_d1 */ + AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_INPUT, MUX_MODE3) /* P9_28 (C12) mcasp0_ahclkr.spi1_cs0 */ + >; + }; +}; + +&spi1 { + #address-cells = <1>; + #size-cells = <0>; + + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_spi1_pins>; + + /* + * Select the D0 pin as output and D1 as + * input. The default is D0 as input and + * D1 as output. + */ + //ti,pindir-d0-out-d1-in; + + channel@0 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "rohm,dh2228fv"; + symlink = "bone/spi/1.0"; + + reg = <0>; + spi-max-frequency = <16000000>; + spi-cpha; + }; + + channel@1 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "rohm,dh2228fv"; + symlink = "bone/spi/1.1"; + + reg = <1>; + spi-max-frequency = <16000000>; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-UART1-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-UART1-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-UART1-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-UART1-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 CircuitCo + * Virtual cape for UART1 on connector pins P9.24 P9.26 + */ + +/dts-v1/; +/plugin/; + +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-UART1-00A0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_24_pinmux { status = "disabled"; }; /* uart1_txd */ + P9_26_pinmux { status = "disabled"; }; /* uart1_rxd */ +}; + +&am33xx_pinmux { + bb_uart1_pins: pinmux_bb_uart1_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT, MUX_MODE0) /* P9_24 uart1_txd.uart1_txd */ + AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT, MUX_MODE0) /* P9_26 uart1_rxd.uart1_rxd */ + //AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT, MUX_MODE0) /* P9_19 uart1_rtsn.uart1_rtsn */ + //AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT, MUX_MODE0) /* P9_20 uart1_ctsn.uart1_ctsn */ + >; + }; +}; + +&uart1 { + /* sudo agetty 115200 ttyS1 */ + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_uart1_pins>; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-UART2-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-UART2-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-UART2-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-UART2-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 CircuitCo + * Virtual cape for UART2 on connector pins P9.21 P9.22 + */ + +/dts-v1/; +/plugin/; + +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-UART2-00A0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_21_pinmux { status = "disabled"; }; /* P9_21: spi0_d0.uart2_txd */ + P9_22_pinmux { status = "disabled"; }; /* P9_22: spi0_sclk.uart2_rxd */ +}; + +&am33xx_pinmux { + bb_uart2_pins: pinmux_bb_uart2_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_OUTPUT, MUX_MODE1) /* P9_21 spi0_d0.uart2_txd */ + AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT, MUX_MODE1) /* P9_22 spi0_sclk.uart2_rxd */ + //AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE6) /* P8_38 lcd_data9.uart2_rtsn */ + //AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_INPUT, MUX_MODE6) /* P8_37 lcd_data8.uart2_ctsn */ + >; + }; +}; + +&uart2 { + /* sudo agetty 115200 ttyS2 */ + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_uart2_pins>; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-UART4-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-UART4-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-UART4-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-UART4-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 CircuitCo + * Virtual cape for UART4 on connector pins P9.13 P9.11 + */ + +/dts-v1/; +/plugin/; + +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-UART4-00A0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_13_pinmux { status = "disabled"; }; /* P9_13: uart4_txd */ + P9_11_pinmux { status = "disabled"; }; /* P9_11: uart4_rxd */ +}; + +&am33xx_pinmux { + bb_uart4_pins: pinmux_bb_uart4_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_OUTPUT, MUX_MODE6) /* P9_13 gpmc_wpn.uart4_txd_mux2 */ + AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT, MUX_MODE6) /* P9_13 gpmc_wait0.uart4_rxd_mux2 */ + >; + }; +}; + +&uart4 { + /* sudo agetty 115200 ttyS4 */ + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_uart4_pins>; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BB-W1-P9.12-00A0.dtso b/arch/arm/boot/dts/ti/omap/BB-W1-P9.12-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/BB-W1-P9.12-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BB-W1-P9.12-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2015 Robert Nelson + * Virtual cape for onewire on connector pin P9.12 + */ + +/dts-v1/; +/plugin/; + +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BB-W1-P9.12-00A0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P9_12_pinmux { status = "disabled"; }; /* P9_12 (U18) gpmc_be1n.gpio1_28 */ +}; + +&am33xx_pinmux { + bb_dallas_w1_pins: pinmux_bb_dallas_w1_pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_INPUT_PULLUP, MUX_MODE7) /* P9_12 (U18) gpmc_be1n.gpio1_28 */ + >; + }; +}; + +&{/} { + onewire { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&bb_dallas_w1_pins>; + + compatible = "w1-gpio"; + gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + }; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/BONE-ADC.dtso b/arch/arm/boot/dts/ti/omap/BONE-ADC.dtso --- a/arch/arm/boot/dts/ti/omap/BONE-ADC.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/BONE-ADC.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Deepak Khatri + * See Cape Interface Spec page for more info on Bone Buses + * https://elinux.org/Beagleboard:BeagleBone_cape_interface_spec + * + * Virtual cape for Bone ADC + */ + +/dts-v1/; +/plugin/; + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BONE-ADC.kernel = __TIMESTAMP__; + }; +}; + +/* + * See these files for the phandles (&bone_*) and other bone bus nodes + * am335x-bbb-bone-buses.dtsi + */ +&bone_adc { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/dra7.dtsi b/arch/arm/boot/dts/ti/omap/dra7.dtsi --- a/arch/arm/boot/dts/ti/omap/dra7.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/dra7.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -638,7 +638,7 @@ }; }; - abb_mpu: regulator-abb-mpu { + abb_mpu: regulator-abb-mpu@4ae07ddc { compatible = "ti,abb-v3"; regulator-name = "abb_mpu"; #address-cells = <0>; @@ -671,7 +671,7 @@ >; }; - abb_ivahd: regulator-abb-ivahd { + abb_ivahd: regulator-abb-ivahd@4ae07e34 { compatible = "ti,abb-v3"; regulator-name = "abb_ivahd"; #address-cells = <0>; @@ -704,7 +704,7 @@ >; }; - abb_dspeve: regulator-abb-dspeve { + abb_dspeve: regulator-abb-dspeve@4ae07e30 { compatible = "ti,abb-v3"; regulator-name = "abb_dspeve"; #address-cells = <0>; @@ -737,7 +737,7 @@ >; }; - abb_gpu: regulator-abb-gpu { + abb_gpu: regulator-abb-gpu@4ae07de4 { compatible = "ti,abb-v3"; regulator-name = "abb_gpu"; #address-cells = <0>; @@ -850,12 +850,19 @@ ; ti,sysc-sidle = , , - ; + , + ; clocks = <&gpu_clkctrl DRA7_GPU_CLKCTRL 0>; clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x56000000 0x2000000>; + + gpu@0 { + compatible = "ti,am5728-gpu", "img,powervr-sgx544"; + reg = <0x0 0x10000>; /* 64kB */ + interrupts = ; + }; }; crossbar_mpu: crossbar@4a002a48 { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi b/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi --- a/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -80,7 +80,7 @@ }; }; - phy_gmii_sel: phy-gmii-sel { + phy_gmii_sel: phy-gmii-sel@554 { compatible = "ti,dra7xx-phy-gmii-sel"; reg = <0x554 0x4>; #phy-cells = <1>; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/dra7xx-clocks.dtsi b/arch/arm/boot/dts/ti/omap/dra7xx-clocks.dtsi --- a/arch/arm/boot/dts/ti/omap/dra7xx-clocks.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/dra7xx-clocks.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -1685,7 +1685,7 @@ reg = <0x0558>; }; - sys_32k_ck: clock-sys-32k { + sys_32k_ck: clock-sys-32k@6c4 { #clock-cells = <0>; compatible = "ti,mux-clock"; clock-output-names = "sys_32k_ck"; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/Makefile b/arch/arm/boot/dts/ti/omap/Makefile --- a/arch/arm/boot/dts/ti/omap/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/Makefile 2024-07-07 20:37:34.620306429 -0400 @@ -1,4 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 + +ifeq ($(CONFIG_OF_OVERLAY),y) +DTC_FLAGS += -@ +endif + dtb-$(CONFIG_ARCH_OMAP2) += \ omap2420-h4.dtb \ omap2420-n800.dtb \ @@ -87,6 +92,39 @@ am335x-base0033.dtb \ am335x-bone.dtb \ am335x-boneblack.dtb \ + am335x-boneblack-uboot.dtb \ + PB-MIKROBUS-1.dtbo \ + PB-MIKROBUS-0.dtbo \ + M-BB-BBGG-00A0.dtbo \ + M-BB-BBG-00A0.dtbo \ + BONE-ADC.dtbo \ + BBORG_RELAY-00A2.dtbo \ + BBORG_FAN-A000.dtbo \ + BBORG_COMMS-00A2.dtbo \ + BB-W1-P9.12-00A0.dtbo \ + BB-UART4-00A0.dtbo \ + BB-UART2-00A0.dtbo \ + BB-UART1-00A0.dtbo \ + BB-SPIDEV1-00A0.dtbo \ + BB-SPIDEV0-00A0.dtbo \ + BB-NHDMI-TDA998x-00A0.dtbo \ + BB-LCD-ADAFRUIT-24-SPI1-00A0.dtbo \ + BB-I2C2-MPU6050.dtbo \ + BB-I2C2-BME680.dtbo \ + BB-I2C1-RTC-PCF8563.dtbo \ + BB-I2C1-RTC-DS3231.dtbo \ + BB-I2C1-MCP7940X-00A0.dtbo \ + BB-HDMI-TDA998x-00A0.dtbo \ + BB-CAPE-DISP-CT4-00A0.dtbo \ + BB-BONE-eMMC1-01-00A0.dtbo \ + BB-BONE-NH7C-01-A0.dtbo \ + BB-BONE-LCD4-01-00A1.dtbo \ + BB-BONE-4D5R-01-00A1.dtbo \ + BB-BBGW-WL1835-00A0.dtbo \ + BB-BBGG-WL1835-00A0.dtbo \ + BB-BBBW-WL1835-00A0.dtbo \ + BB-ADC-00A0.dtbo \ + AM335X-PRU-UIO-00A0.dtbo \ am335x-boneblack-wireless.dtb \ am335x-boneblue.dtb \ am335x-bonegreen.dtb \ diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/M-BB-BBG-00A0.dtso b/arch/arm/boot/dts/ti/omap/M-BB-BBG-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/M-BB-BBG-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/M-BB-BBG-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + M-BB-BBG-00A0.kernel = __TIMESTAMP__; + }; +}; + +&{/} { + model = "TI AM335x BeagleBone Green"; + compatible = "ti,am335x-bone-green", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/M-BB-BBGG-00A0.dtso b/arch/arm/boot/dts/ti/omap/M-BB-BBGG-00A0.dtso --- a/arch/arm/boot/dts/ti/omap/M-BB-BBGG-00A0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/M-BB-BBGG-00A0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + M-BB-BBGG-00A0.kernel = __TIMESTAMP__; + }; +}; + +&{/} { + model = "SeeedStudio BeagleBone Green Gateway"; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/omap34xx.dtsi b/arch/arm/boot/dts/ti/omap/omap34xx.dtsi --- a/arch/arm/boot/dts/ti/omap/omap34xx.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/omap34xx.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -164,12 +164,13 @@ clock-names = "fck", "ick"; #address-cells = <1>; #size-cells = <1>; - ranges = <0 0x50000000 0x4000>; + ranges = <0 0x50000000 0x10000>; - /* - * Closed source PowerVR driver, no child device - * binding or driver in mainline - */ + gpu@0 { + compatible = "ti,omap3430-gpu", "img,powervr-sgx530"; + reg = <0x0 0x10000>; /* 64kB */ + interrupts = <21>; + }; }; }; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/omap36xx.dtsi b/arch/arm/boot/dts/ti/omap/omap36xx.dtsi --- a/arch/arm/boot/dts/ti/omap/omap36xx.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/omap36xx.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -211,10 +211,11 @@ #size-cells = <1>; ranges = <0 0x50000000 0x2000000>; - /* - * Closed source PowerVR driver, no child device - * binding or driver in mainline - */ + gpu@0 { + compatible = "ti,omap3630-gpu", "img,powervr-sgx530"; + reg = <0x0 0x2000000>; /* 32MB */ + interrupts = <21>; + }; }; }; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/omap4.dtsi b/arch/arm/boot/dts/ti/omap/omap4.dtsi --- a/arch/arm/boot/dts/ti/omap/omap4.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/omap4.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -501,10 +501,11 @@ #size-cells = <1>; ranges = <0 0x56000000 0x2000000>; - /* - * Closed source PowerVR driver, no child device - * binding or driver in mainline - */ + gpu@0 { + compatible = "ti,omap4430-gpu", "img,powervr-sgx540"; + reg = <0x0 0x2000000>; /* 32MB */ + interrupts = ; + }; }; /* diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/omap4-panda-common.dtsi b/arch/arm/boot/dts/ti/omap/omap4-panda-common.dtsi --- a/arch/arm/boot/dts/ti/omap/omap4-panda-common.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/omap4-panda-common.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -408,6 +408,7 @@ reg = <0x48>; /* IRQ# = 7 */ interrupts = ; /* IRQ_SYS_1N cascaded to gic */ + system-power-controller; }; twl6040: twl@4b { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/omap4-sdp.dts b/arch/arm/boot/dts/ti/omap/omap4-sdp.dts --- a/arch/arm/boot/dts/ti/omap/omap4-sdp.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/omap4-sdp.dts 2024-07-07 20:37:34.624306449 -0400 @@ -439,7 +439,7 @@ /* * Ambient Light Sensor - * http://www.rohm.com/products/databook/sensor/pdf/bh1780gli-e.pdf + * https://www.rohm.com/products/databook/sensor/pdf/bh1780gli-e.pdf (defunct) */ bh1780@29 { compatible = "rohm,bh1780"; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/omap5.dtsi b/arch/arm/boot/dts/ti/omap/omap5.dtsi --- a/arch/arm/boot/dts/ti/omap/omap5.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/omap5.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -453,10 +453,11 @@ #size-cells = <1>; ranges = <0 0x56000000 0x2000000>; - /* - * Closed source PowerVR driver, no child device - * binding or driver in mainline - */ + gpu@0 { + compatible = "ti,omap5432-gpu", "img,powervr-sgx544"; + reg = <0x0 0x2000000>; /* 32MB */ + interrupts = ; + }; }; target-module@58000000 { diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/PB-MIKROBUS-0.dtso b/arch/arm/boot/dts/ti/omap/PB-MIKROBUS-0.dtso --- a/arch/arm/boot/dts/ti/omap/PB-MIKROBUS-0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/PB-MIKROBUS-0.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2020 Vaishnav M A, BeagleBoard.org Foundation. + */ + +/dts-v1/; +/plugin/; + +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + PB-MIKROBUS-0.kernel = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P2_01_pinmux { status = "disabled"; }; + P2_03_pinmux { status = "disabled"; }; + P2_05_pinmux { status = "disabled"; }; + P2_07_pinmux { status = "disabled"; }; + P2_09_pinmux { status = "disabled"; }; + P2_11_pinmux { status = "disabled"; }; + P1_12_pinmux { status = "disabled"; }; + P1_10_pinmux { status = "disabled"; }; + P1_08_pinmux { status = "disabled"; }; + P1_06_pinmux { status = "disabled"; }; + P1_04_pinmux { status = "disabled"; }; + P1_02_pinmux { status = "disabled"; }; +}; + +&{/} { + aliases { + mikrobus0 = "/mikrobus-0"; + }; + + mikrobus-0 { + compatible = "linux,mikrobus"; + status = "okay"; + pinctrl-names = "default", "pwm_default", "pwm_gpio", + "uart_default", "uart_gpio", "i2c_default", + "i2c_gpio", "spi_default", "spi_gpio"; + pinctrl-0 = < + &P2_03_gpio_input_pin + &P1_04_gpio_pin + &P1_02_gpio_pin + >; + pinctrl-1 = <&P2_01_pwm_pin>; + pinctrl-2 = <&P2_01_gpio_pin>; + pinctrl-3 = < + &P2_05_uart_pin + &P2_07_uart_pin + >; + pinctrl-4 = < + &P2_05_gpio_pin + &P2_07_gpio_pin + >; + pinctrl-5 = < + &P2_09_i2c_pin + &P2_11_i2c_pin + >; + pinctrl-6 = < + &P2_09_gpio_pin + &P2_11_gpio_pin + >; + pinctrl-7 = < + &P1_12_spi_pin + &P1_10_spi_pin + &P1_08_spi_sclk_pin + &P1_06_spi_cs_pin + >; + pinctrl-8 = < + &P1_12_gpio_pin + &P1_10_gpio_pin + &P1_08_gpio_pin + &P1_06_gpio_pin + >; + i2c-adapter = <&i2c1>; + spi-master = <0>; + spi-cs = <0 1>; + uart = <&uart4>; + pwms = <&ehrpwm1 0 500000 0>; + mikrobus-gpios = <&gpio1 18 0> , <&gpio0 23 0>, + <&gpio0 30 0> , <&gpio0 31 0>, + <&gpio0 15 0> , <&gpio0 14 0>, + <&gpio0 4 0> , <&gpio0 3 0>, + <&gpio0 2 0> , <&gpio0 5 0>, + <&gpio2 25 0> , <&gpio2 3 0>; + }; +}; + +&spi0 { + status = "okay"; + channel@0{ status = "disabled"; }; +}; + +&uart4 { + status = "okay"; + force-empty-serdev-controller; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/PB-MIKROBUS-1.dtso b/arch/arm/boot/dts/ti/omap/PB-MIKROBUS-1.dtso --- a/arch/arm/boot/dts/ti/omap/PB-MIKROBUS-1.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/boot/dts/ti/omap/PB-MIKROBUS-1.dtso 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2020 Vaishnav M A, BeagleBoard.org Foundation. + */ + +/dts-v1/; +/plugin/; + +#include +#include + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + PB-MIKROBUS-1 = __TIMESTAMP__; + }; +}; + +/* + * Free up the pins used by the cape from the pinmux helpers. + */ +&ocp { + P1_36_pinmux { status = "disabled"; }; + P1_34_pinmux { status = "disabled"; }; + P1_32_pinmux { status = "disabled"; }; + P1_30_pinmux { status = "disabled"; }; + P1_28_pinmux { status = "disabled"; }; + P1_26_pinmux { status = "disabled"; }; + P2_25_pinmux { status = "disabled"; }; + P2_27_pinmux { status = "disabled"; }; + P2_29_pinmux { status = "disabled"; }; + P2_31_pinmux { status = "disabled"; }; + P2_33_pinmux { status = "disabled"; }; + P2_35_pinmux { status = "disabled"; }; +}; + +&{/} { + aliases { + mikrobus1 = "/mikrobus-1"; + }; + + mikrobus-1 { + compatible = "linux,mikrobus"; + status = "okay"; + pinctrl-names = "default", "pwm_default", "pwm_gpio", + "uart_default", "uart_gpio", "i2c_default", + "i2c_gpio", "spi_default", "spi_gpio"; + pinctrl-0 = < + &P1_34_gpio_input_pin + &P2_33_gpio_pin + &P2_35_gpio_pin + >; + pinctrl-1 = <&P1_36_pwm_pin>; + pinctrl-2 = <&P1_36_gpio_pin>; + pinctrl-3 = < + &P1_32_uart_pin + &P1_30_uart_pin + >; + pinctrl-4 = < + &P1_32_gpio_pin + &P1_30_gpio_pin + >; + pinctrl-5 = < + &P1_26_i2c_pin + &P1_28_i2c_pin + >; + pinctrl-6 = < + &P1_26_gpio_pin + &P1_28_gpio_pin + >; + pinctrl-7 = < + &P2_25_spi_pin + &P2_27_spi_pin + &P2_29_spi_sclk_pin + &P2_31_spi_cs_pin + >; + pinctrl-8 = < + &P2_25_gpio_pin + &P2_27_gpio_pin + &P2_29_gpio_pin + &P2_31_gpio_pin + >; + i2c-adapter = <&i2c2>; + spi-master = <1>; + spi-cs = <1 2>; + uart = <&uart0>; + pwms = <&ehrpwm0 0 500000 0>; + mikrobus-gpios = <&gpio3 14 0> , <&gpio0 26 0>, + <&gpio1 10 0> , <&gpio1 11 0>, + <&gpio0 13 0> , <&gpio0 12 0>, + <&gpio1 9 0> , <&gpio1 8 0>, + <&gpio0 7 0> , <&gpio0 19 0>, + <&gpio1 13 0> , <&gpio2 22 0>; + }; +}; + +&spi1 { + status = "okay"; + channel@0{ status = "disabled"; }; + channel@1{ status = "disabled"; }; +}; + +&uart0 { + status = "okay"; + force-empty-serdev-controller; +}; diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/twl4030.dtsi b/arch/arm/boot/dts/ti/omap/twl4030.dtsi --- a/arch/arm/boot/dts/ti/omap/twl4030.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/twl4030.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ */ /* diff -Naur --no-dereference a/arch/arm/boot/dts/ti/omap/twl6030.dtsi b/arch/arm/boot/dts/ti/omap/twl6030.dtsi --- a/arch/arm/boot/dts/ti/omap/twl6030.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/boot/dts/ti/omap/twl6030.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ */ /* * Integrated Power Management Chip - * http://www.ti.com/lit/ds/symlink/twl6030.pdf + * https://www.ti.com/lit/ds/symlink/twl6030.pdf */ &twl { compatible = "ti,twl6030"; diff -Naur --no-dereference a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig --- a/arch/arm/configs/keystone_defconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/configs/keystone_defconfig 2024-07-07 20:37:34.624306449 -0400 @@ -98,7 +98,6 @@ CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_TARGET_CLUSTERIP=y CONFIG_IP_NF_TARGET_ECN=y CONFIG_IP_NF_TARGET_TTL=y CONFIG_IP_NF_RAW=y diff -Naur --no-dereference a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig --- a/arch/arm/configs/multi_v7_defconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/configs/multi_v7_defconfig 2024-07-07 20:37:34.624306449 -0400 @@ -228,6 +228,7 @@ CONFIG_QCOM_FASTRPC=m CONFIG_APDS9802ALS=y CONFIG_ISL29003=y +CONFIG_SRAM_DMA_HEAP=y CONFIG_PCI_ENDPOINT_TEST=m CONFIG_EEPROM_AT24=y CONFIG_BLK_DEV_SD=y @@ -717,6 +718,7 @@ CONFIG_DRM_SUN4I=m CONFIG_DRM_OMAP=m CONFIG_OMAP5_DSS_HDMI=y +CONFIG_DRM_TILCDC=m CONFIG_DRM_MSM=m CONFIG_DRM_FSL_DCU=m CONFIG_DRM_TEGRA=y @@ -857,7 +859,6 @@ CONFIG_USB_MUSB_SUNXI=m CONFIG_USB_MUSB_TUSB6010=m CONFIG_USB_MUSB_OMAP2PLUS=m -CONFIG_USB_MUSB_AM35X=m CONFIG_USB_MUSB_DSPS=m CONFIG_USB_MUSB_UX500=m CONFIG_USB_UX500_DMA=y @@ -1034,6 +1035,10 @@ CONFIG_RZN1_DMAMUX=m CONFIG_RCAR_DMAC=y CONFIG_RENESAS_USB_DMAC=m +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_SYSTEM=y +CONFIG_DMABUF_HEAPS_CMA=y +CONFIG_DMABUF_HEAPS_CARVEOUT=y CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_MMIO=y CONFIG_STAGING=y @@ -1078,6 +1083,7 @@ CONFIG_EXYNOS_IOMMU=y CONFIG_QCOM_IOMMU=y CONFIG_REMOTEPROC=y +CONFIG_REMOTEPROC_CDEV=y CONFIG_OMAP_REMOTEPROC=m CONFIG_OMAP_REMOTEPROC_WATCHDOG=y CONFIG_KEYSTONE_REMOTEPROC=m @@ -1176,6 +1182,8 @@ CONFIG_PWM_BCM2835=y CONFIG_PWM_BRCMSTB=m CONFIG_PWM_FSL_FTM=m +CONFIG_PWM_TIECAP=m +CONFIG_PWM_TIEHRPWM=m CONFIG_PWM_MESON=m CONFIG_PWM_RCAR=m CONFIG_PWM_RENESAS_TPU=y @@ -1189,6 +1197,7 @@ CONFIG_PWM_VT8500=y CONFIG_KEYSTONE_IRQ=y CONFIG_RESET_MCHP_SPARX5=y +CONFIG_RESET_SCMI=y CONFIG_PHY_SUN4I_USB=y CONFIG_PHY_SUN9I_USB=y CONFIG_PHY_BRCM_USB=m diff -Naur --no-dereference a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig --- a/arch/arm/configs/omap2plus_defconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm/configs/omap2plus_defconfig 2024-07-07 20:37:34.624306449 -0400 @@ -78,7 +78,6 @@ CONFIG_IP_PNP_RARP=y CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=m -CONFIG_NF_LOG_NETDEV=m CONFIG_NF_CONNTRACK_ZONES=y CONFIG_NF_CONNTRACK_EVENTS=y CONFIG_NF_CONNTRACK_TIMEOUT=y @@ -92,7 +91,6 @@ CONFIG_NF_TABLES_NETDEV=y CONFIG_NFT_NUMGEN=m CONFIG_NFT_CT=m -CONFIG_NFT_COUNTER=m CONFIG_NFT_CONNLIMIT=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m @@ -100,7 +98,6 @@ CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_TUNNEL=m -CONFIG_NFT_OBJREF=m CONFIG_NFT_QUEUE=m CONFIG_NFT_QUOTA=m CONFIG_NFT_REJECT=m @@ -179,7 +176,6 @@ CONFIG_NETFILTER_XT_MATCH_U32=m CONFIG_NFT_DUP_IPV4=m CONFIG_NFT_FIB_IPV4=m -CONFIG_NF_FLOW_TABLE_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -193,14 +189,12 @@ CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_CLUSTERIP=m CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_TARGET_TTL=m CONFIG_IP_NF_RAW=m CONFIG_IP_NF_SECURITY=m CONFIG_NFT_DUP_IPV6=m CONFIG_NFT_FIB_IPV6=m -CONFIG_NF_FLOW_TABLE_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -225,7 +219,6 @@ CONFIG_NF_TABLES_BRIDGE=m CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m -CONFIG_NF_LOG_BRIDGE=m CONFIG_BRIDGE=m CONFIG_BRIDGE_VLAN_FILTERING=y CONFIG_VLAN_8021Q=m @@ -560,7 +553,6 @@ CONFIG_USB_MUSB_HDRC=m CONFIG_USB_MUSB_TUSB6010=m CONFIG_USB_MUSB_OMAP2PLUS=m -CONFIG_USB_MUSB_AM35X=m CONFIG_USB_MUSB_DSPS=m CONFIG_USB_INVENTRA_DMA=y CONFIG_USB_TI_CPPI41_DMA=y diff -Naur --no-dereference a/arch/arm/configs/rcn-ee_defconfig b/arch/arm/configs/rcn-ee_defconfig --- a/arch/arm/configs/rcn-ee_defconfig 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm/configs/rcn-ee_defconfig 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,2864 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_LZ4=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_JIT=y +CONFIG_BPF_LSM=y +CONFIG_PREEMPT=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=m +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_RDMA=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_MISC=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +# CONFIG_SYSFS_SYSCALL is not set +CONFIG_PROFILING=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +CONFIG_SOC_OMAP5=y +CONFIG_SOC_AM33XX=y +CONFIG_SOC_DRA7XX=y +CONFIG_SOC_HAS_OMAP2_SDRC=y +CONFIG_OMAP5_ERRATA_801819=y +CONFIG_ARM_THUMBEE=y +CONFIG_PL310_ERRATA_588369=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_PL310_ERRATA_753970=y +CONFIG_ARM_ERRATA_430973=y +CONFIG_ARM_ERRATA_773022=y +CONFIG_ARM_ERRATA_814220=y +CONFIG_SMP=y +# CONFIG_ARM_CPU_TOPOLOGY is not set +CONFIG_MCPM=y +CONFIG_NR_CPUS=2 +CONFIG_ARM_PSCI=y +CONFIG_HZ_250=y +CONFIG_ARCH_FORCE_MAX_ORDER=12 +CONFIG_PARAVIRT=y +# CONFIG_ATAGS is not set +CONFIG_EFI=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPUFREQ_DT=m +CONFIG_CPUFREQ_DT_PLATDEV=y +# CONFIG_ARM_OMAP2PLUS_CPUFREQ is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_ARM_CPUIDLE=y +CONFIG_ARM_PSCI_CPUIDLE=y +CONFIG_KERNEL_MODE_NEON=y +CONFIG_HIBERNATION=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_DEBUG=y +CONFIG_PM_ADVANCED_DEBUG=y +CONFIG_APM_EMULATION=y +CONFIG_ENERGY_MODEL=y +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_COMPRESS_XZ=y +CONFIG_BLK_DEV_ZONED=y +CONFIG_BLK_DEV_THROTTLING=y +CONFIG_BLK_WBT=y +CONFIG_BLK_CGROUP_IOCOST=y +CONFIG_BLK_SED_OPAL=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_KARMA_PARTITION=y +CONFIG_MQ_IOSCHED_KYBER=m +CONFIG_IOSCHED_BFQ=m +CONFIG_BINFMT_MISC=m +CONFIG_ZSWAP=y +CONFIG_Z3FOLD=m +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_KSM=y +CONFIG_USERFAULTFD=y +CONFIG_LRU_GEN=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_PACKET_DIAG=m +CONFIG_UNIX_DIAG=m +CONFIG_TLS=m +CONFIG_TLS_DEVICE=y +CONFIG_XFRM_USER=m +CONFIG_XFRM_INTERFACE=m +CONFIG_XFRM_SUB_POLICY=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=m +CONFIG_NET_KEY_MIGRATE=y +CONFIG_XDP_SOCKETS=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_FIB_TRIE_STATS=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_ESP_OFFLOAD=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_DIAG=m +CONFIG_INET_UDP_DIAG=m +CONFIG_INET_RAW_DIAG=m +CONFIG_INET_DIAG_DESTROY=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_NV=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_DCTCP=m +CONFIG_TCP_CONG_CDG=m +CONFIG_TCP_CONG_BBR=m +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_ESP_OFFLOAD=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_ILA=m +CONFIG_IPV6_VTI=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_GRE=m +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y +CONFIG_IPV6_SEG6_LWTUNNEL=y +CONFIG_IPV6_SEG6_HMAC=y +CONFIG_NETLABEL=y +CONFIG_MPTCP=y +CONFIG_NETWORK_PHY_TIMESTAMPING=y +CONFIG_NETFILTER=y +CONFIG_BRIDGE_NETFILTER=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_ZONES=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_TIMEOUT=y +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_SNMP=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_NETLINK_TIMEOUT=m +CONFIG_NF_CT_NETLINK_HELPER=m +CONFIG_NETFILTER_NETLINK_GLUE_CT=y +CONFIG_NF_TABLES=m +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_NETDEV=y +CONFIG_NFT_NUMGEN=m +CONFIG_NFT_CT=m +CONFIG_NFT_FLOW_OFFLOAD=m +CONFIG_NFT_CONNLIMIT=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_NAT=m +CONFIG_NFT_TUNNEL=m +CONFIG_NFT_QUEUE=m +CONFIG_NFT_QUOTA=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_COMPAT=m +CONFIG_NFT_HASH=m +CONFIG_NFT_FIB_INET=m +CONFIG_NFT_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m +CONFIG_NFT_SYNPROXY=m +CONFIG_NFT_DUP_NETDEV=m +CONFIG_NFT_FWD_NETDEV=m +CONFIG_NFT_FIB_NETDEV=m +CONFIG_NF_FLOW_TABLE_INET=m +CONFIG_NF_FLOW_TABLE=m +CONFIG_NETFILTER_XT_SET=m +CONFIG_NETFILTER_XT_TARGET_AUDIT=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_CT=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HMARK=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LED=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_TEE=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m +CONFIG_NETFILTER_XT_MATCH_CGROUP=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPCOMP=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_SET=m +CONFIG_IP_SET_BITMAP_IP=m +CONFIG_IP_SET_BITMAP_IPMAC=m +CONFIG_IP_SET_BITMAP_PORT=m +CONFIG_IP_SET_HASH_IP=m +CONFIG_IP_SET_HASH_IPMARK=m +CONFIG_IP_SET_HASH_IPPORT=m +CONFIG_IP_SET_HASH_IPPORTIP=m +CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_IPMAC=m +CONFIG_IP_SET_HASH_MAC=m +CONFIG_IP_SET_HASH_NETPORTNET=m +CONFIG_IP_SET_HASH_NET=m +CONFIG_IP_SET_HASH_NETNET=m +CONFIG_IP_SET_HASH_NETPORT=m +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_FO=m +CONFIG_IP_VS_OVF=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_MH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_PE_SIP=m +CONFIG_NFT_DUP_IPV4=m +CONFIG_NFT_FIB_IPV4=m +CONFIG_NF_TABLES_ARP=y +CONFIG_NF_LOG_ARP=m +CONFIG_NF_LOG_IPV4=m +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_RPFILTER=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SYNPROXY=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_NFT_DUP_IPV6=m +CONFIG_NFT_FIB_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RPFILTER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_SRH=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_TARGET_SYNPROXY=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_IP6_NF_NAT=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_IP6_NF_TARGET_NPT=m +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_CONNTRACK_BRIDGE=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_NFLOG=m +CONFIG_IP_DCCP=m +CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=y +CONFIG_SCTP_COOKIE_HMAC_MD5=y +CONFIG_RDS=m +CONFIG_RDS_TCP=m +CONFIG_TIPC=m +CONFIG_ATM=m +CONFIG_ATM_CLIP=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +CONFIG_L2TP=m +CONFIG_L2TP_DEBUGFS=m +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_LLC2=m +CONFIG_ATALK=m +CONFIG_PHONET=m +CONFIG_6LOWPAN=m +CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m +CONFIG_6LOWPAN_GHC_UDP=m +CONFIG_6LOWPAN_GHC_ICMPV6=m +CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m +CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m +CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m +CONFIG_IEEE802154=m +CONFIG_IEEE802154_6LOWPAN=m +CONFIG_MAC802154=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFB=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_CBS=m +CONFIG_NET_SCH_ETF=m +CONFIG_NET_SCH_TAPRIO=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_DRR=m +CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_SKBPRIO=m +CONFIG_NET_SCH_CHOKE=m +CONFIG_NET_SCH_QFQ=m +CONFIG_NET_SCH_CODEL=m +CONFIG_NET_SCH_FQ_CODEL=y +CONFIG_NET_SCH_CAKE=m +CONFIG_NET_SCH_FQ=m +CONFIG_NET_SCH_HHF=m +CONFIG_NET_SCH_PIE=m +CONFIG_NET_SCH_FQ_PIE=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_PLUG=m +CONFIG_NET_SCH_ETS=m +CONFIG_NET_SCH_DEFAULT=y +CONFIG_DEFAULT_FQ_CODEL=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_PERF=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=m +CONFIG_NET_CLS_CGROUP=y +CONFIG_NET_CLS_BPF=m +CONFIG_NET_CLS_FLOWER=m +CONFIG_NET_CLS_MATCHALL=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_CANID=m +CONFIG_NET_EMATCH_IPSET=m +CONFIG_NET_EMATCH_IPT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_SAMPLE=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_NET_ACT_CSUM=m +CONFIG_NET_ACT_MPLS=m +CONFIG_NET_ACT_VLAN=m +CONFIG_NET_ACT_BPF=m +CONFIG_NET_ACT_CONNMARK=m +CONFIG_NET_ACT_CTINFO=m +CONFIG_NET_ACT_SKBMOD=m +CONFIG_NET_ACT_IFE=m +CONFIG_NET_ACT_TUNNEL_KEY=m +CONFIG_NET_ACT_CT=m +CONFIG_NET_ACT_GATE=m +CONFIG_NET_IFE_SKBMARK=m +CONFIG_NET_IFE_SKBPRIO=m +CONFIG_NET_IFE_SKBTCINDEX=m +CONFIG_DCB=y +CONFIG_BATMAN_ADV=m +CONFIG_BATMAN_ADV_NC=y +CONFIG_OPENVSWITCH=m +CONFIG_VSOCKETS=m +CONFIG_VIRTIO_VSOCKETS=m +CONFIG_NETLINK_DIAG=m +CONFIG_NET_MPLS_GSO=y +CONFIG_MPLS_ROUTING=m +CONFIG_MPLS_IPTUNNEL=m +CONFIG_HSR=m +CONFIG_NET_SWITCHDEV=y +CONFIG_QRTR=m +CONFIG_QRTR_SMD=m +CONFIG_QRTR_TUN=m +CONFIG_NET_NCSI=y +CONFIG_CGROUP_NET_PRIO=y +CONFIG_BPF_STREAM_PARSER=y +CONFIG_NET_PKTGEN=m +CONFIG_NET_DROP_MONITOR=m +CONFIG_HAMRADIO=y +CONFIG_AX25=m +CONFIG_NETROM=m +CONFIG_ROSE=m +CONFIG_MKISS=m +CONFIG_6PACK=m +CONFIG_BPQETHER=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_YAM=m +CONFIG_CAN=m +CONFIG_CAN_J1939=m +CONFIG_CAN_ISOTP=m +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m +CONFIG_BT_6LOWPAN=m +CONFIG_BT_LEDS=y +CONFIG_BT_MSFTEXT=y +CONFIG_BT_HCIBTUSB=m +CONFIG_BT_HCIBTUSB_MTK=y +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_NOKIA=m +CONFIG_BT_HCIUART_ATH3K=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUART_INTEL=y +CONFIG_BT_HCIUART_BCM=y +CONFIG_BT_HCIUART_RTL=y +CONFIG_BT_HCIUART_QCA=y +CONFIG_BT_HCIUART_AG6XX=y +CONFIG_BT_HCIUART_MRVL=y +CONFIG_BT_MRVL=m +CONFIG_BT_MRVL_SDIO=m +CONFIG_BT_ATH3K=m +CONFIG_BT_MTKUART=m +CONFIG_AF_RXRPC_IPV6=y +CONFIG_RXKAD=y +CONFIG_AF_KCM=m +CONFIG_CFG80211=m +# CONFIG_CFG80211_DEFAULT_PS is not set +CONFIG_MAC80211=m +CONFIG_MAC80211_MESH=y +CONFIG_RFKILL=y +CONFIG_RFKILL_INPUT=y +CONFIG_NET_9P=m +CONFIG_NET_9P_VIRTIO=m +CONFIG_NFC=m +CONFIG_NFC_DIGITAL=m +CONFIG_NFC_NCI=m +CONFIG_NFC_NCI_SPI=m +CONFIG_NFC_NCI_UART=m +CONFIG_NFC_TRF7970A=m +CONFIG_NFC_SIM=m +CONFIG_NFC_PORT100=m +CONFIG_NFC_PN533_USB=m +CONFIG_NFC_PN533_I2C=m +CONFIG_NFC_ST_NCI_I2C=m +CONFIG_NFC_ST_NCI_SPI=m +CONFIG_NFC_NXP_NCI=m +CONFIG_NFC_NXP_NCI_I2C=m +CONFIG_NFC_ST95HF=m +CONFIG_PAGE_POOL_STATS=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_EXTRA_FIRMWARE="regulatory.db regulatory.db.p7s am335x-pm-firmware.elf am335x-bone-scale-data.bin am335x-evm-scale-data.bin am43x-evm-scale-data.bin" +CONFIG_EXTRA_FIRMWARE_DIR="firmware" +CONFIG_OMAP_OCP2SCP=y +CONFIG_CONNECTOR=y +CONFIG_DMI_SYSFS=y +CONFIG_TRUSTED_FOUNDATIONS=y +CONFIG_EFI_BOOTLOADER_CONTROL=m +CONFIG_EFI_CAPSULE_LOADER=m +CONFIG_RESET_ATTACK_MITIGATION=y +CONFIG_GNSS=m +CONFIG_GNSS_MTK_SERIAL=m +CONFIG_GNSS_SIRF_SERIAL=m +CONFIG_GNSS_UBX_SERIAL=m +CONFIG_MTD=y +CONFIG_MTD_AR7_PARTS=m +CONFIG_MTD_OF_PARTS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_RFD_FTL=m +CONFIG_SSFDC=m +CONFIG_MTD_OOPS=m +CONFIG_MTD_SWAP=m +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PLATRAM=m +CONFIG_MTD_DATAFLASH=m +CONFIG_MTD_SST25L=m +CONFIG_MTD_ONENAND=y +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_ONENAND_2X_PROGRAM=y +CONFIG_MTD_RAW_NAND=y +CONFIG_MTD_NAND_OMAP2=m +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_ECC_SW_BCH=y +CONFIG_MTD_LPDDR=m +CONFIG_MTD_SPI_NOR=m +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BLOCK=y +CONFIG_OF_OVERLAY=y +CONFIG_BLK_DEV_NULL_BLK=m +CONFIG_ZRAM=m +CONFIG_ZRAM_WRITEBACK=y +CONFIG_ZRAM_MEMORY_TRACKING=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_DRBD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_ATA_OVER_ETH=m +CONFIG_VIRTIO_BLK=m +CONFIG_BLK_DEV_RBD=m +CONFIG_AD525X_DPOT=m +CONFIG_AD525X_DPOT_I2C=m +CONFIG_AD525X_DPOT_SPI=m +CONFIG_ICS932S401=m +CONFIG_APDS9802ALS=m +CONFIG_ISL29003=m +CONFIG_ISL29020=m +CONFIG_SENSORS_TSL2550=m +CONFIG_SENSORS_BH1770=m +CONFIG_SENSORS_APDS990X=m +CONFIG_HMC6352=m +CONFIG_DS1682=m +CONFIG_SRAM=y +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +CONFIG_EEPROM_LEGACY=m +CONFIG_EEPROM_MAX6875=m +CONFIG_EEPROM_93XX46=m +CONFIG_EEPROM_EE1004=m +CONFIG_TI_ST=m +CONFIG_RAID_ATTRS=m +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +CONFIG_BLK_DEV_SR=m +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_ATA=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_MD_CLUSTER=m +CONFIG_BCACHE=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_UNSTRIPED=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m +CONFIG_DM_CACHE=m +CONFIG_DM_WRITECACHE=m +CONFIG_DM_ERA=m +CONFIG_DM_MIRROR=m +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_QL=m +CONFIG_DM_MULTIPATH_ST=m +CONFIG_DM_DELAY=m +CONFIG_DM_UEVENT=y +CONFIG_DM_FLAKEY=m +CONFIG_DM_VERITY=m +CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y +CONFIG_DM_SWITCH=m +CONFIG_DM_LOG_WRITES=m +CONFIG_DM_INTEGRITY=m +CONFIG_DM_ZONED=m +CONFIG_TARGET_CORE=m +CONFIG_TCM_IBLOCK=m +CONFIG_TCM_FILEIO=m +CONFIG_TCM_PSCSI=m +CONFIG_TCM_USER2=m +CONFIG_LOOPBACK_TARGET=m +CONFIG_ISCSI_TARGET=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m +CONFIG_DUMMY=m +CONFIG_WIREGUARD=m +CONFIG_EQUALIZER=m +CONFIG_IFB=m +CONFIG_NET_TEAM=m +CONFIG_NET_TEAM_MODE_BROADCAST=m +CONFIG_NET_TEAM_MODE_ROUNDROBIN=m +CONFIG_NET_TEAM_MODE_RANDOM=m +CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m +CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m +CONFIG_IPVTAP=m +CONFIG_VXLAN=m +CONFIG_GENEVE=m +CONFIG_GTP=m +CONFIG_MACSEC=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_VIRTIO_NET=m +CONFIG_NLMON=m +CONFIG_NET_VRF=m +CONFIG_ATM_DUMMY=m +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +CONFIG_KS8851=m +CONFIG_ENC28J60=y +CONFIG_ENCX24J600=y +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +CONFIG_SMC91X=m +CONFIG_SMSC911X=m +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +CONFIG_TI_CPSW_PHY_SEL=y +CONFIG_TI_CPSW=y +CONFIG_TI_CPSW_SWITCHDEV=y +CONFIG_TI_CPTS=y +# CONFIG_NET_VENDOR_VIA is not set +CONFIG_WIZNET_W5100=y +CONFIG_WIZNET_W5100_SPI=y +# CONFIG_NET_VENDOR_XILINX is not set +CONFIG_LED_TRIGGER_PHY=y +CONFIG_MICREL_PHY=y +CONFIG_MICROCHIP_PHY=y +CONFIG_MICROSEMI_PHY=m +CONFIG_AT803X_PHY=y +CONFIG_DP83867_PHY=y +CONFIG_DP83869_PHY=m +CONFIG_VITESSE_PHY=y +CONFIG_CAN_VCAN=m +CONFIG_CAN_VXCAN=m +CONFIG_CAN_SLCAN=m +CONFIG_CAN_C_CAN=m +CONFIG_CAN_C_CAN_PLATFORM=m +CONFIG_CAN_HI311X=m +CONFIG_CAN_MCP251X=m +CONFIG_CAN_MCP251XFD=m +CONFIG_CAN_8DEV_USB=m +CONFIG_CAN_EMS_USB=m +CONFIG_CAN_ESD_USB=m +CONFIG_CAN_GS_USB=m +CONFIG_CAN_KVASER_USB=m +CONFIG_CAN_MCBA_USB=m +CONFIG_CAN_PEAK_USB=m +CONFIG_CAN_UCAN=m +CONFIG_MDIO_BCM_UNIMAC=m +CONFIG_MDIO_GPIO=y +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOATM=m +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_LAN78XX=m +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_CDC_EEM=m +CONFIG_USB_NET_CDC_NCM=m +CONFIG_USB_NET_HUAWEI_CDC_NCM=m +CONFIG_USB_NET_CDC_MBIM=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_SR9700=m +CONFIG_USB_NET_SR9800=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +CONFIG_USB_NET_ZAURUS=m +CONFIG_USB_NET_CX82310_ETH=m +CONFIG_USB_NET_KALMIA=m +CONFIG_USB_NET_QMI_WWAN=m +CONFIG_USB_HSO=m +CONFIG_USB_NET_INT51X1=m +CONFIG_USB_CDC_PHONET=m +CONFIG_USB_IPHETH=m +CONFIG_USB_SIERRA_NET=m +CONFIG_USB_VL600=m +CONFIG_USB_NET_CH9200=m +CONFIG_USB_NET_AQC111=m +CONFIG_ATH9K=m +CONFIG_ATH9K_CHANNEL_CONTEXT=y +CONFIG_ATH9K_HTC=m +CONFIG_CARL9170=m +CONFIG_ATH6KL=m +CONFIG_ATH6KL_USB=m +CONFIG_AR5523=m +CONFIG_ATH10K=m +CONFIG_ATH10K_USB=m +CONFIG_ATH11K=m +CONFIG_ATH11K_AHB=m +CONFIG_AT76C50X_USB=m +CONFIG_BRCMFMAC=m +CONFIG_BRCMFMAC_USB=y +# CONFIG_WLAN_VENDOR_CISCO is not set +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_MESH=y +CONFIG_LIBERTAS_THINFIRM=m +CONFIG_LIBERTAS_THINFIRM_USB=m +CONFIG_MWIFIEX=m +CONFIG_MWIFIEX_USB=m +CONFIG_MT7601U=m +CONFIG_MT76x0U=m +CONFIG_MT76x2U=m +CONFIG_MT7663U=m +CONFIG_MT7921U=m +CONFIG_WILC1000_SPI=m +CONFIG_RT2X00=m +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +CONFIG_RT2800USB=m +CONFIG_RT2800USB_RT3573=y +CONFIG_RT2800USB_RT53XX=y +CONFIG_RT2800USB_RT55XX=y +CONFIG_RTL8187=m +CONFIG_RTL8192CU=m +# CONFIG_RTLWIFI_DEBUG is not set +CONFIG_RTL8XXXU=m +CONFIG_RTW88=m +CONFIG_RTW88_8822BU=m +CONFIG_RTW88_8822CU=m +CONFIG_RTW88_8723DU=m +CONFIG_RTW88_8821CU=m +CONFIG_RTW89=m +CONFIG_RSI_91X=m +# CONFIG_RSI_SDIO is not set +CONFIG_WL1251=m +CONFIG_WL1251_SPI=m +CONFIG_WL1251_SDIO=m +CONFIG_WL12XX=m +CONFIG_WL18XX=m +CONFIG_WLCORE_SPI=m +CONFIG_WLCORE_SDIO=m +CONFIG_ZD1211RW=m +CONFIG_USB_NET_RNDIS_WLAN=m +CONFIG_MAC80211_HWSIM=m +CONFIG_IEEE802154_AT86RF230=m +CONFIG_IEEE802154_MRF24J40=m +CONFIG_IEEE802154_CC2520=m +CONFIG_IEEE802154_ATUSB=m +CONFIG_IEEE802154_WPANUSB=m +CONFIG_IEEE802154_ADF7242=m +CONFIG_IEEE802154_CA8210=m +CONFIG_IEEE802154_MCR20A=m +CONFIG_IEEE802154_HWSIM=m +CONFIG_INPUT_SPARSEKMAP=m +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_KEYBOARD_ADP5588=m +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_QT2160=m +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_TCA8418=m +CONFIG_KEYBOARD_LM8323=m +CONFIG_KEYBOARD_MAX7359=m +CONFIG_KEYBOARD_STOWAWAY=m +# CONFIG_MOUSE_PS2 is not set +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_ELAN_I2C=m +CONFIG_MOUSE_SYNAPTICS_I2C=m +CONFIG_MOUSE_SYNAPTICS_USB=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=m +CONFIG_JOYSTICK_IFORCE_232=m +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_ZHENHUA=m +CONFIG_JOYSTICK_AS5011=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_PSXPAD_SPI=y +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y +CONFIG_JOYSTICK_PXRC=m +CONFIG_JOYSTICK_FSIA6B=m +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_HANWANG=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_PEGASUS=m +CONFIG_TABLET_SERIAL_WACOM4=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_AD7877=m +CONFIG_TOUCHSCREEN_AD7879=m +CONFIG_TOUCHSCREEN_AD7879_I2C=m +CONFIG_TOUCHSCREEN_AR1021_I2C=y +CONFIG_TOUCHSCREEN_ATMEL_MXT=m +CONFIG_TOUCHSCREEN_DYNAPRO=m +CONFIG_TOUCHSCREEN_HAMPSHIRE=m +CONFIG_TOUCHSCREEN_EETI=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GOODIX=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_ELAN=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_WACOM_W8001=m +CONFIG_TOUCHSCREEN_MCS5000=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_INEXIO=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_EDT_FT5X06=y +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_TI_AM335X_TSC=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_TOUCHIT213=m +CONFIG_TOUCHSCREEN_TSC2005=m +CONFIG_TOUCHSCREEN_TSC2007=m +CONFIG_TOUCHSCREEN_SILEAD=y +CONFIG_TOUCHSCREEN_STMPE=y +CONFIG_TOUCHSCREEN_TPS6507X=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_AD714X=m +CONFIG_INPUT_MMA8450=m +CONFIG_INPUT_GPIO_DECODER=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_YEALINK=m +CONFIG_INPUT_CM109=m +CONFIG_INPUT_TPS65218_PWRBUTTON=y +CONFIG_INPUT_TPS65219_PWRBUTTON=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_PALMAS_PWRBUTTON=y +CONFIG_RMI4_F34=y +CONFIG_RMI4_F3A=y +CONFIG_RMI4_F55=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_DMA is not set +CONFIG_SERIAL_8250_NR_UARTS=6 +CONFIG_SERIAL_8250_RUNTIME_UARTS=6 +CONFIG_SERIAL_8250_OMAP=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_MAX3100=m +CONFIG_SERIAL_MAX310X=m +CONFIG_N_GSM=m +CONFIG_RPMSG_TTY=m +CONFIG_SERIAL_DEV_BUS=y +CONFIG_TTY_PRINTK=m +CONFIG_VIRTIO_CONSOLE=m +CONFIG_HW_RANDOM_VIRTIO=m +CONFIG_TCG_TIS_I2C_ATMEL=y +CONFIG_TCG_TIS_I2C_INFINEON=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_ARB_GPIO_CHALLENGE=m +CONFIG_I2C_MUX_GPIO=y +CONFIG_I2C_MUX_PCA954x=m +CONFIG_I2C_MUX_PINCTRL=y +CONFIG_I2C_GPIO=y +CONFIG_I2C_DIOLAN_U2C=m +CONFIG_I2C_ROBOTFUZZ_OSIF=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_SLAVE=y +CONFIG_I2C_SLAVE_EEPROM=y +CONFIG_SPI=y +CONFIG_SPI_GPIO=y +CONFIG_SPI_OMAP24XX=y +CONFIG_SPI_TI_QSPI=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_SLAVE=y +CONFIG_SPI_SLAVE_TIME=m +CONFIG_SPI_SLAVE_SYSTEM_CONTROL=m +CONFIG_PPS_CLIENT_LDISC=m +CONFIG_PPS_CLIENT_GPIO=m +CONFIG_PINCTRL_MCP23S08=m +CONFIG_PINCTRL_PALMAS=y +CONFIG_PINCTRL_SINGLE=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_GPIO_SYSCON=y +CONFIG_GPIO_ADNP=m +CONFIG_GPIO_MAX7300=m +CONFIG_GPIO_MAX732X=m +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y +CONFIG_GPIO_PCF857X=m +CONFIG_GPIO_TPIC2810=m +CONFIG_GPIO_PALMAS=y +CONFIG_GPIO_STMPE=y +CONFIG_GPIO_TPS65218=y +CONFIG_GPIO_74X164=m +CONFIG_GPIO_MAX3191X=m +CONFIG_GPIO_MAX7301=m +CONFIG_GPIO_MC33880=m +CONFIG_GPIO_PISOSR=m +CONFIG_GPIO_XRA1403=m +CONFIG_GPIO_AGGREGATOR=y +CONFIG_W1=y +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_GPIO=m +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_DS2405=m +CONFIG_W1_SLAVE_DS2408=m +CONFIG_W1_SLAVE_DS2413=m +CONFIG_W1_SLAVE_DS2406=m +CONFIG_W1_SLAVE_DS2423=m +CONFIG_W1_SLAVE_DS2805=m +CONFIG_W1_SLAVE_DS2430=m +CONFIG_W1_SLAVE_DS2431=m +CONFIG_W1_SLAVE_DS2433=m +CONFIG_W1_SLAVE_DS2433_CRC=y +CONFIG_W1_SLAVE_DS2438=m +CONFIG_W1_SLAVE_DS250X=m +CONFIG_W1_SLAVE_DS2780=m +CONFIG_W1_SLAVE_DS2781=m +CONFIG_W1_SLAVE_DS28E04=m +CONFIG_W1_SLAVE_DS28E17=m +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_RESET_GPIO_RESTART=y +CONFIG_POWER_RESET_RESTART=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +CONFIG_SYSCON_REBOOT_MODE=m +CONFIG_GENERIC_ADC_BATTERY=m +CONFIG_BATTERY_DS2760=m +CONFIG_CHARGER_GPIO=m +CONFIG_CHARGER_BQ2415X=m +CONFIG_SENSORS_AD7314=m +CONFIG_SENSORS_AD7414=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM1177=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7310=m +CONFIG_SENSORS_ADT7410=m +CONFIG_SENSORS_ADT7411=m +CONFIG_SENSORS_ADT7462=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_ADT7475=m +CONFIG_SENSORS_AHT10=m +CONFIG_SENSORS_AQUACOMPUTER_D5NEXT=m +CONFIG_SENSORS_AS370=m +CONFIG_SENSORS_ASC7621=m +CONFIG_SENSORS_AXI_FAN_CONTROL=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_CORSAIR_CPRO=m +CONFIG_SENSORS_CORSAIR_PSU=m +CONFIG_SENSORS_DRIVETEMP=m +CONFIG_SENSORS_DS620=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FTSTEUTATES=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_G760A=m +CONFIG_SENSORS_G762=m +CONFIG_SENSORS_GPIO_FAN=y +CONFIG_SENSORS_HIH6130=m +CONFIG_SENSORS_IIO_HWMON=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_JC42=m +CONFIG_SENSORS_POWR1220=m +CONFIG_SENSORS_LINEAGE=m +CONFIG_SENSORS_LTC2945=m +CONFIG_SENSORS_LTC2947_I2C=m +CONFIG_SENSORS_LTC2947_SPI=m +CONFIG_SENSORS_LTC2990=m +CONFIG_SENSORS_LTC2992=m +CONFIG_SENSORS_LTC4151=m +CONFIG_SENSORS_LTC4215=m +CONFIG_SENSORS_LTC4222=m +CONFIG_SENSORS_LTC4245=m +CONFIG_SENSORS_LTC4260=m +CONFIG_SENSORS_LTC4261=m +CONFIG_SENSORS_MAX1111=m +CONFIG_SENSORS_MAX127=m +CONFIG_SENSORS_MAX16065=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX1668=m +CONFIG_SENSORS_MAX197=m +CONFIG_SENSORS_MAX31722=m +CONFIG_SENSORS_MAX31730=m +CONFIG_SENSORS_MAX31760=m +CONFIG_SENSORS_MAX6620=m +CONFIG_SENSORS_MAX6621=m +CONFIG_SENSORS_MAX6639=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MAX6697=m +CONFIG_SENSORS_MAX31790=m +CONFIG_SENSORS_MCP3021=m +CONFIG_SENSORS_TC654=m +CONFIG_SENSORS_TPS23861=m +CONFIG_SENSORS_MR75203=m +CONFIG_SENSORS_ADCXX=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM73=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_LM95234=m +CONFIG_SENSORS_LM95241=m +CONFIG_SENSORS_LM95245=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_NTC_THERMISTOR=m +CONFIG_SENSORS_NCT6683=m +CONFIG_SENSORS_NCT6775_I2C=m +CONFIG_SENSORS_NCT7802=m +CONFIG_SENSORS_NCT7904=m +CONFIG_SENSORS_NPCM7XX=m +CONFIG_SENSORS_NZXT_KRAKEN2=m +CONFIG_SENSORS_NZXT_SMART2=m +CONFIG_SENSORS_OCC_P8_I2C=m +CONFIG_SENSORS_PCF8591=m +CONFIG_PMBUS=m +CONFIG_SENSORS_ADM1266=m +CONFIG_SENSORS_ADM1275=m +CONFIG_SENSORS_IBM_CFFPS=m +CONFIG_SENSORS_INSPUR_IPSPS=m +CONFIG_SENSORS_IR35221=m +CONFIG_SENSORS_IR38064=m +CONFIG_SENSORS_IRPS5401=m +CONFIG_SENSORS_ISL68137=m +CONFIG_SENSORS_LM25066=m +CONFIG_SENSORS_LTC2978=m +CONFIG_SENSORS_LTC2978_REGULATOR=y +CONFIG_SENSORS_LTC3815=m +CONFIG_SENSORS_MAX16064=m +CONFIG_SENSORS_MAX16601=m +CONFIG_SENSORS_MAX20730=m +CONFIG_SENSORS_MAX20751=m +CONFIG_SENSORS_MAX31785=m +CONFIG_SENSORS_MAX34440=m +CONFIG_SENSORS_MAX8688=m +CONFIG_SENSORS_MP2975=m +CONFIG_SENSORS_PXE1610=m +CONFIG_SENSORS_TPS40422=m +CONFIG_SENSORS_TPS53679=m +CONFIG_SENSORS_UCD9000=m +CONFIG_SENSORS_UCD9200=m +CONFIG_SENSORS_XDPE122=m +CONFIG_SENSORS_ZL6100=m +CONFIG_SENSORS_PWM_FAN=m +CONFIG_SENSORS_SBTSI=m +CONFIG_SENSORS_SBRMI=m +CONFIG_SENSORS_SHT15=m +CONFIG_SENSORS_SHT21=m +CONFIG_SENSORS_SHT3x=m +CONFIG_SENSORS_SHT4x=m +CONFIG_SENSORS_SHTC1=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_EMC1403=m +CONFIG_SENSORS_EMC2103=m +CONFIG_SENSORS_EMC2305=m +CONFIG_SENSORS_EMC6W201=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SCH5627=m +CONFIG_SENSORS_SCH5636=m +CONFIG_SENSORS_STTS751=m +CONFIG_SENSORS_ADC128D818=m +CONFIG_SENSORS_ADS7828=m +CONFIG_SENSORS_ADS7871=m +CONFIG_SENSORS_AMC6821=m +CONFIG_SENSORS_INA209=m +CONFIG_SENSORS_INA2XX=m +CONFIG_SENSORS_INA238=m +CONFIG_SENSORS_INA3221=m +CONFIG_SENSORS_TC74=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_TMP102=m +CONFIG_SENSORS_TMP103=m +CONFIG_SENSORS_TMP108=m +CONFIG_SENSORS_TMP401=m +CONFIG_SENSORS_TMP421=m +CONFIG_SENSORS_TMP464=m +CONFIG_SENSORS_TMP513=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_W83773G=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83795=m +CONFIG_SENSORS_W83795_FANCTRL=y +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83L786NG=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_THERMAL_STATISTICS=y +CONFIG_THERMAL_GOV_FAIR_SHARE=y +CONFIG_THERMAL_GOV_BANG_BANG=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_EMULATION=y +CONFIG_TI_THERMAL=y +CONFIG_OMAP5_THERMAL=y +CONFIG_DRA752_THERMAL=y +CONFIG_GENERIC_ADC_THERMAL=m +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_SYSFS=y +CONFIG_WATCHDOG_PRETIMEOUT_GOV=y +CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=m +CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP=y +CONFIG_SOFT_WATCHDOG=y +CONFIG_OMAP_WATCHDOG=y +CONFIG_MFD_STMPE=y +CONFIG_MFD_TI_AM335X_TSCADC=y +CONFIG_MFD_PALMAS=y +CONFIG_MFD_TPS65217=y +CONFIG_MFD_TPS65218=y +CONFIG_MFD_TPS65219=y +CONFIG_MFD_TPS6594_I2C=y +CONFIG_MFD_TPS6594_SPI=y +CONFIG_MFD_WL1273_CORE=m +CONFIG_REGULATOR_USERSPACE_CONSUMER=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_PALMAS=y +CONFIG_REGULATOR_PBIAS=y +CONFIG_REGULATOR_PWM=y +CONFIG_REGULATOR_TI_ABB=y +CONFIG_REGULATOR_TPS65217=y +CONFIG_REGULATOR_TPS65218=y +CONFIG_REGULATOR_TPS65219=y +CONFIG_RC_CORE=m +CONFIG_LIRC=y +CONFIG_RC_DECODERS=y +CONFIG_IR_IMON_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_XMP_DECODER=m +CONFIG_RC_DEVICES=y +CONFIG_IR_GPIO_CIR=m +CONFIG_IR_IGORPLUGUSB=m +CONFIG_IR_IGUANA=m +CONFIG_IR_IMON=m +CONFIG_IR_IMON_RAW=m +CONFIG_IR_MCEUSB=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_STREAMZAP=m +CONFIG_IR_TTUSBIR=m +CONFIG_RC_ATI_REMOTE=m +CONFIG_RC_LOOPBACK=m +CONFIG_USB_PULSE8_CEC=m +CONFIG_USB_RAINSHADOW_CEC=m +CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_GSPCA=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m +CONFIG_USB_GSPCA_DTCS033=m +CONFIG_USB_GSPCA_ETOMS=m +CONFIG_USB_GSPCA_FINEPIX=m +CONFIG_USB_GSPCA_JEILINJ=m +CONFIG_USB_GSPCA_JL2005BCD=m +CONFIG_USB_GSPCA_KINECT=m +CONFIG_USB_GSPCA_KONICA=m +CONFIG_USB_GSPCA_MARS=m +CONFIG_USB_GSPCA_MR97310A=m +CONFIG_USB_GSPCA_NW80X=m +CONFIG_USB_GSPCA_OV519=m +CONFIG_USB_GSPCA_OV534=m +CONFIG_USB_GSPCA_OV534_9=m +CONFIG_USB_GSPCA_PAC207=m +CONFIG_USB_GSPCA_PAC7302=m +CONFIG_USB_GSPCA_PAC7311=m +CONFIG_USB_GSPCA_SE401=m +CONFIG_USB_GSPCA_SN9C2028=m +CONFIG_USB_GSPCA_SN9C20X=m +CONFIG_USB_GSPCA_SONIXB=m +CONFIG_USB_GSPCA_SONIXJ=m +CONFIG_USB_GSPCA_SPCA1528=m +CONFIG_USB_GSPCA_SPCA500=m +CONFIG_USB_GSPCA_SPCA501=m +CONFIG_USB_GSPCA_SPCA505=m +CONFIG_USB_GSPCA_SPCA506=m +CONFIG_USB_GSPCA_SPCA508=m +CONFIG_USB_GSPCA_SPCA561=m +CONFIG_USB_GSPCA_SQ905=m +CONFIG_USB_GSPCA_SQ905C=m +CONFIG_USB_GSPCA_SQ930X=m +CONFIG_USB_GSPCA_STK014=m +CONFIG_USB_GSPCA_STK1135=m +CONFIG_USB_GSPCA_STV0680=m +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m +CONFIG_USB_GSPCA_TOUPTEK=m +CONFIG_USB_GSPCA_TV8532=m +CONFIG_USB_GSPCA_VC032X=m +CONFIG_USB_GSPCA_VICAM=m +CONFIG_USB_GSPCA_XIRLINK_CIT=m +CONFIG_USB_GSPCA_ZC3XX=m +CONFIG_USB_GL860=m +CONFIG_USB_M5602=m +CONFIG_USB_STV06XX=m +CONFIG_USB_PWC=m +CONFIG_USB_S2255=m +CONFIG_VIDEO_USBTV=m +CONFIG_USB_VIDEO_CLASS=m +CONFIG_VIDEO_GO7007=m +CONFIG_VIDEO_GO7007_USB=m +CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m +CONFIG_VIDEO_HDPVR=m +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_STK1160=m +CONFIG_VIDEO_AU0828=m +CONFIG_VIDEO_AU0828_RC=y +CONFIG_VIDEO_CX231XX=m +CONFIG_VIDEO_CX231XX_ALSA=m +CONFIG_VIDEO_CX231XX_DVB=m +CONFIG_DVB_AS102=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_USB_V2=m +CONFIG_DVB_USB_AF9015=m +CONFIG_DVB_USB_AF9035=m +CONFIG_DVB_USB_ANYSEE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_CE6230=m +CONFIG_DVB_USB_DVBSKY=m +CONFIG_DVB_USB_EC168=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_LME2510=m +CONFIG_DVB_USB_MXL111SF=m +CONFIG_DVB_USB_RTL28XXU=m +CONFIG_DVB_USB_ZD1301=m +CONFIG_DVB_USB=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_AZ6027=m +CONFIG_DVB_USB_CINERGY_T2=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_DTV5100=m +CONFIG_DVB_USB_DW2102=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_PCTV452E=m +CONFIG_DVB_USB_TECHNISAT_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_VP7045=m +CONFIG_SMS_USB_DRV=m +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_EM28XX_V4L2=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_VIDEO_EM28XX_DVB=m +CONFIG_USB_AIRSPY=m +CONFIG_USB_HACKRF=m +CONFIG_USB_MSI2500=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m +CONFIG_RADIO_SI4713=m +CONFIG_USB_KEENE=m +CONFIG_USB_MA901=m +CONFIG_USB_MR800=m +CONFIG_USB_RAREMONO=m +CONFIG_RADIO_SI470X=m +CONFIG_USB_SI470X=m +CONFIG_I2C_SI4713=m +CONFIG_RADIO_WL128X=m +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_MUX=m +CONFIG_VIDEO_TI_VPE=m +CONFIG_SMS_SDIO_DRV=m +CONFIG_VIDEO_IMX219=m +CONFIG_VIDEO_IMX290=m +CONFIG_VIDEO_MT9P031=m +CONFIG_VIDEO_OV5640=m +CONFIG_VIDEO_OV5645=m +CONFIG_VIDEO_OV5647=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_CS3308=m +CONFIG_VIDEO_CS5345=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_VP27SMPX=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_VPX3220=m +CONFIG_VIDEO_SAA717X=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_SAA6752HS=m +CONFIG_VIDEO_M52790=m +CONFIG_CXD2880_SPI_DRV=m +CONFIG_MEDIA_TUNER_M88RS6000T=m +CONFIG_MEDIA_TUNER_MT2131=m +CONFIG_MEDIA_TUNER_MXL301RF=m +CONFIG_MEDIA_TUNER_QM1D1B0004=m +CONFIG_DVB_MXL5XX=m +CONFIG_DVB_STV0910=m +CONFIG_DVB_STV6111=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24117=m +CONFIG_DVB_MB86A16=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA8261=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_ZL10036=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_DIB9000=m +CONFIG_DVB_L64781=m +CONFIG_DVB_S5H1432=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_STV0367=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_MN88443X=m +CONFIG_DVB_ASCOT2E=m +CONFIG_DVB_HELENE=m +CONFIG_DVB_HORUS3A=m +CONFIG_DVB_ISL6405=m +CONFIG_DVB_LGS8GL5=m +CONFIG_DVB_LNBH25=m +CONFIG_DVB_LNBH29=m +CONFIG_DVB_TDA665x=m +CONFIG_DVB_CXD2099=m +CONFIG_DVB_DUMMY_FE=m +CONFIG_AUXDISPLAY=y +CONFIG_HD44780=m +CONFIG_IMG_ASCII_LCD=m +CONFIG_HT16K33=m +CONFIG_LCD2S=m +CONFIG_DRM=y +CONFIG_DRM_LOAD_EDID_FIRMWARE=y +CONFIG_DRM_DP_AUX_CHARDEV=y +CONFIG_DRM_I2C_NXP_TDA998X=y +CONFIG_DRM_VGEM=m +CONFIG_DRM_UDL=m +CONFIG_DRM_OMAP=y +CONFIG_OMAP5_DSS_HDMI=y +CONFIG_DRM_TILCDC=y +CONFIG_DRM_PANEL_SIMPLE=y +CONFIG_DRM_PANEL_LG_LB035Q02=m +CONFIG_DRM_PANEL_NEC_NL8048HL11=m +CONFIG_DRM_PANEL_ORISETECH_OTM8009A=y +CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS=y +CONFIG_DRM_PANEL_SHARP_LS037V7DW01=m +CONFIG_DRM_PANEL_SONY_ACX565AKM=m +CONFIG_DRM_PANEL_TPO_TD028TTEC1=m +CONFIG_DRM_PANEL_TPO_TD043MTEA1=m +CONFIG_DRM_DISPLAY_CONNECTOR=y +CONFIG_DRM_ITE_IT66121=m +CONFIG_DRM_LVDS_CODEC=y +CONFIG_DRM_SII902X=y +CONFIG_DRM_SIMPLE_BRIDGE=m +CONFIG_DRM_TOSHIBA_TC358767=y +CONFIG_DRM_TOSHIBA_TC358768=y +CONFIG_DRM_TI_TFP410=y +CONFIG_DRM_TI_TPD12S015=y +CONFIG_DRM_I2C_ADV7511=y +CONFIG_DRM_I2C_ADV7511_AUDIO=y +CONFIG_DRM_ETNAVIV=y +CONFIG_DRM_GM12U320=m +CONFIG_TINYDRM_HX8357D=m +CONFIG_TINYDRM_ILI9225=m +CONFIG_TINYDRM_ILI9341=m +CONFIG_TINYDRM_ILI9486=m +CONFIG_TINYDRM_MI0283QT=m +CONFIG_TINYDRM_REPAPER=m +CONFIG_TINYDRM_ST7586=m +CONFIG_TINYDRM_ST7735R=m +CONFIG_DRM_TIDSS=y +CONFIG_DRM_LEGACY=y +CONFIG_FB=y +CONFIG_FB_SMSCUFX=m +CONFIG_FB_UDL=m +CONFIG_FB_SIMPLE=y +CONFIG_FB_SSD1307=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_TILEBLITTING=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_PLATFORM=y +CONFIG_BACKLIGHT_PWM=y +CONFIG_BACKLIGHT_GPIO=y +CONFIG_BACKLIGHT_LED=y +CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_CLUT224 is not set +CONFIG_SOUND=m +CONFIG_SND=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_HRTIMER=m +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_DUMMY=m +CONFIG_SND_ALOOP=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_MPU401=m +CONFIG_SND_HDA_PREALLOC_SIZE=2048 +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_UA101=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_USB_6FIRE=m +CONFIG_SND_USB_HIFACE=m +CONFIG_SND_BCD2000=m +CONFIG_SND_USB_POD=m +CONFIG_SND_USB_PODHD=m +CONFIG_SND_USB_TONEPORT=m +CONFIG_SND_USB_VARIAX=m +CONFIG_SND_SOC=m +CONFIG_SND_SOC_DAVINCI_MCASP=m +CONFIG_SND_SOC_OMAP_DMIC=m +CONFIG_SND_SOC_OMAP_MCBSP=m +CONFIG_SND_SOC_OMAP_MCPDM=m +CONFIG_SND_SOC_OMAP_HDMI=m +CONFIG_SND_SOC_ADAU1701=m +CONFIG_SND_SOC_ADAU7002=m +CONFIG_SND_SOC_AK4554=m +CONFIG_SND_SOC_CS42L51_I2C=m +CONFIG_SND_SOC_CS4265=m +CONFIG_SND_SOC_CS4271_I2C=m +CONFIG_SND_SOC_DMIC=m +CONFIG_SND_SOC_ES8328_I2C=m +CONFIG_SND_SOC_ES8328_SPI=m +CONFIG_SND_SOC_MAX98357A=m +CONFIG_SND_SOC_PCM3168A_I2C=m +CONFIG_SND_SOC_PCM5102A=m +CONFIG_SND_SOC_PCM512x_I2C=m +CONFIG_SND_SOC_SGTL5000=m +CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m +CONFIG_SND_SOC_SPDIF=m +CONFIG_SND_SOC_TLV320AIC23_I2C=m +CONFIG_SND_SOC_TLV320AIC31XX=m +CONFIG_SND_SOC_TS3A227E=m +CONFIG_SND_SOC_WM8753=m +CONFIG_SND_SOC_WM8804_I2C=m +CONFIG_SND_SOC_WM8903=m +CONFIG_SND_SOC_WM8904=m +CONFIG_SND_SOC_WM8960=m +CONFIG_SND_SOC_TPA6130A2=m +CONFIG_SND_SIMPLE_CARD=m +CONFIG_SND_AUDIO_GRAPH_CARD=m +CONFIG_HID_BATTERY_STRENGTH=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_A4TECH=m +CONFIG_HID_ACCUTOUCH=m +CONFIG_HID_ACRUX=m +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=m +CONFIG_HID_ASUS=m +CONFIG_HID_AUREAL=m +CONFIG_HID_BELKIN=m +CONFIG_HID_BETOP_FF=m +CONFIG_HID_BIGBEN_FF=m +CONFIG_HID_CHERRY=m +CONFIG_HID_CHICONY=m +CONFIG_HID_CORSAIR=m +CONFIG_HID_COUGAR=m +CONFIG_HID_MACALLY=m +CONFIG_HID_PRODIKEYS=m +CONFIG_HID_CMEDIA=m +CONFIG_HID_CP2112=m +CONFIG_HID_CREATIVE_SB0540=m +CONFIG_HID_CYPRESS=m +CONFIG_HID_DRAGONRISE=m +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=m +CONFIG_HID_ELAN=m +CONFIG_HID_ELECOM=m +CONFIG_HID_ELO=m +CONFIG_HID_EZKEY=m +CONFIG_HID_FT260=m +CONFIG_HID_GEMBIRD=m +CONFIG_HID_GFRM=m +CONFIG_HID_GLORIOUS=m +CONFIG_HID_HOLTEK=m +CONFIG_HOLTEK_FF=y +CONFIG_HID_VIVALDI=m +CONFIG_HID_GT683R=m +CONFIG_HID_KEYTOUCH=m +CONFIG_HID_KYE=m +CONFIG_HID_UCLOGIC=m +CONFIG_HID_WALTOP=m +CONFIG_HID_VIEWSONIC=m +CONFIG_HID_GYRATION=m +CONFIG_HID_ICADE=m +CONFIG_HID_ITE=m +CONFIG_HID_JABRA=m +CONFIG_HID_TWINHAN=m +CONFIG_HID_KENSINGTON=m +CONFIG_HID_LCPOWER=m +CONFIG_HID_LENOVO=m +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_HID_MAGICMOUSE=m +CONFIG_HID_MALTRON=m +CONFIG_HID_MAYFLASH=m +CONFIG_HID_REDRAGON=m +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_MULTITOUCH=m +CONFIG_HID_NINTENDO=m +CONFIG_NINTENDO_FF=y +CONFIG_HID_NTI=m +CONFIG_HID_NTRIG=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PENMOUNT=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_PICOLCD=m +CONFIG_HID_PICOLCD_FB=y +CONFIG_HID_PICOLCD_BACKLIGHT=y +CONFIG_HID_PICOLCD_LEDS=y +CONFIG_HID_PICOLCD_CIR=y +CONFIG_HID_PLANTRONICS=m +CONFIG_HID_PLAYSTATION=m +CONFIG_PLAYSTATION_FF=y +CONFIG_HID_PRIMAX=m +CONFIG_HID_RETRODE=m +CONFIG_HID_ROCCAT=m +CONFIG_HID_SAITEK=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SEMITEK=m +CONFIG_HID_SONY=m +CONFIG_SONY_FF=y +CONFIG_HID_SPEEDLINK=m +CONFIG_HID_STEAM=m +CONFIG_HID_STEELSERIES=m +CONFIG_HID_SUNPLUS=m +CONFIG_HID_RMI=m +CONFIG_HID_GREENASIA=m +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=m +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=m +CONFIG_HID_TOPSEED=m +CONFIG_HID_THINGM=m +CONFIG_HID_THRUSTMASTER=m +CONFIG_THRUSTMASTER_FF=y +CONFIG_HID_UDRAW_PS3=m +CONFIG_HID_U2FZERO=m +CONFIG_HID_WACOM=m +CONFIG_HID_WIIMOTE=m +CONFIG_HID_XINMO=m +CONFIG_HID_ZEROPLUS=m +CONFIG_ZEROPLUS_FF=y +CONFIG_HID_ZYDACRON=m +CONFIG_HID_SENSOR_HUB=m +CONFIG_HID_SENSOR_CUSTOM_SENSOR=m +CONFIG_HID_ALPS=m +CONFIG_HID_MCP2221=m +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_LED_TRIG=y +CONFIG_USB_ULPI_BUS=m +CONFIG_USB_CONN_GPIO=m +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DYNAMIC_MINORS=y +CONFIG_USB_OTG=y +CONFIG_USB_LEDS_TRIGGER_USBPORT=m +CONFIG_USB_MON=m +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_PRINTER=m +CONFIG_USB_TMC=m +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_REALTEK=m +CONFIG_USB_STORAGE_DATAFAB=m +CONFIG_USB_STORAGE_FREECOM=m +CONFIG_USB_STORAGE_ISD200=m +CONFIG_USB_STORAGE_USBAT=m +CONFIG_USB_STORAGE_SDDR09=m +CONFIG_USB_STORAGE_SDDR55=m +CONFIG_USB_STORAGE_JUMPSHOT=m +CONFIG_USB_STORAGE_ALAUDA=m +CONFIG_USB_STORAGE_ONETOUCH=m +CONFIG_USB_STORAGE_KARMA=m +CONFIG_USB_STORAGE_CYPRESS_ATACB=m +CONFIG_USB_STORAGE_ENE_UB6250=m +CONFIG_USB_UAS=m +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USBIP_CORE=m +CONFIG_USBIP_VHCI_HCD=m +CONFIG_USBIP_VHCI_HC_PORTS=15 +CONFIG_USBIP_VHCI_NR_HCS=8 +CONFIG_USBIP_HOST=m +CONFIG_USBIP_VUDC=m +CONFIG_USB_MUSB_HDRC=y +CONFIG_USB_MUSB_DSPS=y +CONFIG_MUSB_PIO_ONLY=y +CONFIG_USB_DWC3=y +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_SIMPLE=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP210X=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_F81232=m +CONFIG_USB_SERIAL_F8153X=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IUU=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_METRO=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_MXUPORT=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_QCAUX=m +CONFIG_USB_SERIAL_QUALCOMM=m +CONFIG_USB_SERIAL_SPCP8X5=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_SYMBOL=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTICON=m +CONFIG_USB_SERIAL_XSENS_MT=m +CONFIG_USB_SERIAL_WISHBONE=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m +CONFIG_USB_SERIAL_UPD78F0730=m +CONFIG_USB_SERIAL_XR=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_SEVSEG=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_APPLE_MFI_FASTCHARGE=m +CONFIG_USB_SISUSBVGA=m +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_TEST=m +CONFIG_USB_EHSET_TEST_FIXTURE=m +CONFIG_USB_ISIGHTFW=m +CONFIG_USB_YUREX=m +CONFIG_USB_HSIC_USB3503=m +CONFIG_USB_CHAOSKEY=m +CONFIG_NOP_USB_XCEIV=y +CONFIG_AM335X_PHY_USB=y +CONFIG_USB_GPIO_VBUS=m +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_DUMMY_HCD=m +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_ACM=y +CONFIG_USB_CONFIGFS_OBEX=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_ECM=y +CONFIG_USB_CONFIGFS_ECM_SUBSET=y +CONFIG_USB_CONFIGFS_RNDIS=y +CONFIG_USB_CONFIGFS_EEM=y +CONFIG_USB_CONFIGFS_PHONET=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_LB_SS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_UAC1=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_UVC=y +CONFIG_USB_CONFIGFS_F_PRINTER=y +CONFIG_USB_ZERO=m +CONFIG_USB_AUDIO=m +CONFIG_USB_ETH=m +CONFIG_USB_G_NCM=m +CONFIG_USB_GADGETFS=m +CONFIG_USB_FUNCTIONFS=m +CONFIG_USB_FUNCTIONFS_ETH=y +CONFIG_USB_FUNCTIONFS_RNDIS=y +CONFIG_USB_FUNCTIONFS_GENERIC=y +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m +CONFIG_USB_MIDI_GADGET=m +CONFIG_USB_G_PRINTER=m +CONFIG_USB_CDC_COMPOSITE=m +CONFIG_USB_G_NOKIA=m +CONFIG_USB_G_ACM_MS=m +CONFIG_USB_G_MULTI=m +CONFIG_USB_G_HID=m +CONFIG_USB_G_DBGP=m +CONFIG_USB_G_WEBCAM=m +CONFIG_TYPEC=y +CONFIG_TYPEC_HD3SS3220=y +CONFIG_MMC=y +CONFIG_PWRSEQ_SD8787=m +CONFIG_MMC_BLOCK_MINORS=256 +CONFIG_SDIO_UART=m +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SPI=m +CONFIG_MMC_VUB300=m +CONFIG_MMC_USHC=m +CONFIG_MMC_SDHCI_OMAP=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_CLASS_MULTICOLOR=m +CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_LP3944=m +CONFIG_LEDS_LP55XX_COMMON=m +CONFIG_LEDS_LP5523=m +CONFIG_LEDS_PCA955X=m +CONFIG_LEDS_PCA963X=m +CONFIG_LEDS_DAC124S085=m +CONFIG_LEDS_PWM=m +CONFIG_LEDS_REGULATOR=m +CONFIG_LEDS_BD2802=m +CONFIG_LEDS_LT3593=m +CONFIG_LEDS_TCA6507=m +CONFIG_LEDS_SYSCON=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_DISK=y +CONFIG_LEDS_TRIGGER_MTD=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_ACTIVITY=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGER_TRANSIENT=m +CONFIG_LEDS_TRIGGER_CAMERA=m +CONFIG_LEDS_TRIGGER_PANIC=y +CONFIG_LEDS_TRIGGER_NETDEV=y +CONFIG_LEDS_TRIGGER_PATTERN=m +CONFIG_LEDS_TRIGGER_AUDIO=m +CONFIG_ACCESSIBILITY=y +CONFIG_A11Y_BRAILLE_CONSOLE=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_ABB5ZES3=y +CONFIG_RTC_DRV_ABEOZ9=y +CONFIG_RTC_DRV_ABX80X=y +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_DS1374=y +CONFIG_RTC_DRV_DS1374_WDT=y +CONFIG_RTC_DRV_DS1672=y +CONFIG_RTC_DRV_HYM8563=y +CONFIG_RTC_DRV_MAX6900=y +CONFIG_RTC_DRV_RS5C372=y +CONFIG_RTC_DRV_ISL1208=y +CONFIG_RTC_DRV_ISL12022=y +CONFIG_RTC_DRV_ISL12026=y +CONFIG_RTC_DRV_X1205=y +CONFIG_RTC_DRV_PCF8523=y +CONFIG_RTC_DRV_PCF85063=y +CONFIG_RTC_DRV_PCF85363=y +CONFIG_RTC_DRV_PCF8563=y +CONFIG_RTC_DRV_PCF8583=y +CONFIG_RTC_DRV_M41T80=y +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_BQ32K=y +CONFIG_RTC_DRV_PALMAS=y +CONFIG_RTC_DRV_S35390A=y +CONFIG_RTC_DRV_FM3130=y +CONFIG_RTC_DRV_RX8010=y +CONFIG_RTC_DRV_RX8581=y +CONFIG_RTC_DRV_RX8025=y +CONFIG_RTC_DRV_EM3027=y +CONFIG_RTC_DRV_RV8803=y +CONFIG_RTC_DRV_M41T93=y +CONFIG_RTC_DRV_M41T94=y +CONFIG_RTC_DRV_DS1302=y +CONFIG_RTC_DRV_DS1305=y +CONFIG_RTC_DRV_DS1343=y +CONFIG_RTC_DRV_DS1347=y +CONFIG_RTC_DRV_DS1390=y +CONFIG_RTC_DRV_MAX6916=y +CONFIG_RTC_DRV_R9701=y +CONFIG_RTC_DRV_RX4581=y +CONFIG_RTC_DRV_RS5C348=y +CONFIG_RTC_DRV_MAX6902=y +CONFIG_RTC_DRV_PCF2123=y +CONFIG_RTC_DRV_MCP795=y +CONFIG_RTC_DRV_DS3232=y +CONFIG_RTC_DRV_PCF2127=y +CONFIG_RTC_DRV_RV3029C2=y +CONFIG_RTC_DRV_RX6110=y +CONFIG_RTC_DRV_DS1286=m +CONFIG_RTC_DRV_DS1511=m +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1685_FAMILY=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_DS2404=m +CONFIG_RTC_DRV_EFI=y +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_M48T35=m +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_MSM6242=m +CONFIG_RTC_DRV_RP5C01=m +CONFIG_RTC_DRV_OMAP=y +CONFIG_RTC_DRV_HID_SENSOR_TIME=m +CONFIG_DMADEVICES=y +CONFIG_TI_CPPI41=y +CONFIG_ASYNC_TX_DMA=y +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_SYSTEM=y +CONFIG_DMABUF_HEAPS_CMA=y +CONFIG_DMABUF_HEAPS_CARVEOUT=y +CONFIG_UIO=m +CONFIG_UIO_PDRV_GENIRQ=m +CONFIG_UIO_PRUSS=m +CONFIG_VIRT_DRIVERS=y +CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_INPUT=m +CONFIG_VIRTIO_MMIO=m +CONFIG_GREYBUS=m +CONFIG_GREYBUS_BEAGLEPLAY=m +CONFIG_GREYBUS_ES2=m +CONFIG_STAGING=y +CONFIG_RTLLIB=m +CONFIG_RTL8723BS=m +CONFIG_R8712U=m +CONFIG_ADIS16203=m +CONFIG_ADIS16240=m +CONFIG_AD7816=m +CONFIG_ADT7316=m +CONFIG_ADT7316_I2C=m +CONFIG_AD9832=m +CONFIG_AD9834=m +CONFIG_AD5933=m +CONFIG_AD2S1210=m +CONFIG_FB_TFT=m +CONFIG_FB_TFT_AGM1264K_FL=m +CONFIG_FB_TFT_BD663474=m +CONFIG_FB_TFT_HX8340BN=m +CONFIG_FB_TFT_HX8347D=m +CONFIG_FB_TFT_HX8353D=m +CONFIG_FB_TFT_HX8357D=m +CONFIG_FB_TFT_ILI9163=m +CONFIG_FB_TFT_ILI9320=m +CONFIG_FB_TFT_ILI9325=m +CONFIG_FB_TFT_ILI9340=m +CONFIG_FB_TFT_ILI9341=m +CONFIG_FB_TFT_ILI9481=m +CONFIG_FB_TFT_ILI9486=m +CONFIG_FB_TFT_PCD8544=m +CONFIG_FB_TFT_RA8875=m +CONFIG_FB_TFT_S6D02A1=m +CONFIG_FB_TFT_S6D1121=m +CONFIG_FB_TFT_SH1106=m +CONFIG_FB_TFT_SSD1289=m +CONFIG_FB_TFT_SSD1305=m +CONFIG_FB_TFT_SSD1306=m +CONFIG_FB_TFT_SSD1331=m +CONFIG_FB_TFT_SSD1351=m +CONFIG_FB_TFT_ST7735R=m +CONFIG_FB_TFT_ST7789V=m +CONFIG_FB_TFT_TINYLCD=m +CONFIG_FB_TFT_TLS8204=m +CONFIG_FB_TFT_UC1611=m +CONFIG_FB_TFT_UC1701=m +CONFIG_FB_TFT_UPD161704=m +CONFIG_GREYBUS_AUDIO=m +CONFIG_GREYBUS_BOOTROM=m +CONFIG_GREYBUS_FIRMWARE=m +CONFIG_GREYBUS_HID=m +CONFIG_GREYBUS_LIGHT=m +CONFIG_GREYBUS_LOG=m +CONFIG_GREYBUS_LOOPBACK=m +CONFIG_GREYBUS_POWER=m +CONFIG_GREYBUS_RAW=m +CONFIG_GREYBUS_VIBRATOR=m +CONFIG_GREYBUS_BRIDGED_PHY=m +CONFIG_GREYBUS_GPIO=m +CONFIG_GREYBUS_I2C=m +CONFIG_GREYBUS_PWM=m +CONFIG_GREYBUS_SDIO=m +CONFIG_GREYBUS_SPI=m +CONFIG_GREYBUS_UART=m +CONFIG_GREYBUS_USB=m +CONFIG_COMMON_CLK_PALMAS=y +CONFIG_COMMON_CLK_TI_ADPLL=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_OMAP=y +CONFIG_OMAP2PLUS_MBOX=y +CONFIG_OMAP_IOMMU=y +CONFIG_REMOTEPROC=y +CONFIG_REMOTEPROC_CDEV=y +CONFIG_OMAP_REMOTEPROC=m +CONFIG_WKUP_M3_RPROC=y +CONFIG_RPMSG_CHAR=m +CONFIG_RPMSG_CTRL=m +CONFIG_RPMSG_VIRTIO=y +CONFIG_SOC_TI=y +CONFIG_AMX3_PM=m +CONFIG_WKUP_M3_IPC=m +CONFIG_TI_PRUSS=m +CONFIG_PM_DEVFREQ=y +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_DEVFREQ_GOV_POWERSAVE=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_PM_DEVFREQ_EVENT=y +CONFIG_EXTCON_GPIO=y +CONFIG_EXTCON_PALMAS=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_TI_EMIF=y +CONFIG_TI_EMIF_SRAM=y +CONFIG_IIO=y +CONFIG_IIO_SW_DEVICE=m +CONFIG_IIO_SW_TRIGGER=m +CONFIG_ADIS16201=m +CONFIG_ADIS16209=m +CONFIG_ADXL313_I2C=m +CONFIG_ADXL313_SPI=m +CONFIG_ADXL345_I2C=m +CONFIG_ADXL345_SPI=m +CONFIG_ADXL355_I2C=m +CONFIG_ADXL355_SPI=m +CONFIG_ADXL367_SPI=m +CONFIG_ADXL367_I2C=m +CONFIG_ADXL372_SPI=m +CONFIG_ADXL372_I2C=m +CONFIG_BMA180=m +CONFIG_BMA220=m +CONFIG_BMA400=m +CONFIG_BMC150_ACCEL=m +CONFIG_BMI088_ACCEL=m +CONFIG_DA280=m +CONFIG_DA311=m +CONFIG_DMARD06=m +CONFIG_DMARD09=m +CONFIG_DMARD10=m +CONFIG_FXLS8962AF_I2C=m +CONFIG_FXLS8962AF_SPI=m +CONFIG_HID_SENSOR_ACCEL_3D=m +CONFIG_IIO_KX022A_SPI=m +CONFIG_IIO_KX022A_I2C=m +CONFIG_KXSD9=m +CONFIG_KXCJK1013=m +CONFIG_MC3230=m +CONFIG_MMA7455_I2C=m +CONFIG_MMA7455_SPI=m +CONFIG_MMA7660=m +CONFIG_MMA8452=m +CONFIG_MMA9551=m +CONFIG_MMA9553=m +CONFIG_MSA311=m +CONFIG_MXC4005=m +CONFIG_MXC6255=m +CONFIG_SCA3000=m +CONFIG_SCA3300=m +CONFIG_STK8312=m +CONFIG_STK8BA50=m +CONFIG_AD4130=m +CONFIG_AD7091R5=m +CONFIG_AD7124=m +CONFIG_AD7192=m +CONFIG_AD7266=m +CONFIG_AD7280=m +CONFIG_AD7291=m +CONFIG_AD7292=m +CONFIG_AD7298=m +CONFIG_AD7476=m +CONFIG_AD7606_IFACE_PARALLEL=m +CONFIG_AD7606_IFACE_SPI=m +CONFIG_AD7766=m +CONFIG_AD7768_1=m +CONFIG_AD7780=m +CONFIG_AD7791=m +CONFIG_AD7793=m +CONFIG_AD7887=m +CONFIG_AD7923=m +CONFIG_AD7949=m +CONFIG_AD799X=m +CONFIG_AD9467=m +CONFIG_ADI_AXI_ADC=m +CONFIG_CC10001_ADC=m +CONFIG_ENVELOPE_DETECTOR=m +CONFIG_HI8435=m +CONFIG_HX711=m +CONFIG_INA2XX_ADC=m +CONFIG_LTC2471=m +CONFIG_LTC2485=m +CONFIG_LTC2496=m +CONFIG_LTC2497=m +CONFIG_MAX1027=m +CONFIG_MAX11100=m +CONFIG_MAX1118=m +CONFIG_MAX11205=m +CONFIG_MAX11410=m +CONFIG_MAX1241=m +CONFIG_MAX1363=m +CONFIG_MAX9611=m +CONFIG_MCP320X=m +CONFIG_MCP3422=m +CONFIG_MCP3911=m +CONFIG_NAU7802=m +CONFIG_PALMAS_GPADC=m +CONFIG_RICHTEK_RTQ6056=m +CONFIG_SD_ADC_MODULATOR=m +CONFIG_STMPE_ADC=m +CONFIG_TI_ADC081C=m +CONFIG_TI_ADC0832=m +CONFIG_TI_ADC084S021=m +CONFIG_TI_ADC12138=m +CONFIG_TI_ADC108S102=m +CONFIG_TI_ADC128S052=m +CONFIG_TI_ADC161S626=m +CONFIG_TI_ADS1015=m +CONFIG_TI_ADS7924=m +CONFIG_TI_ADS1100=m +CONFIG_TI_ADS7950=m +CONFIG_TI_ADS8344=m +CONFIG_TI_ADS8688=m +CONFIG_TI_ADS124S08=m +CONFIG_TI_ADS131E08=m +CONFIG_TI_AM335X_ADC=y +CONFIG_TI_LMP92064=m +CONFIG_TI_TLC4541=m +CONFIG_TI_TSC2046=m +CONFIG_AD74115=m +CONFIG_AD74413R=m +CONFIG_IIO_RESCALE=m +CONFIG_AD8366=m +CONFIG_ADA4250=m +CONFIG_HMC425=m +CONFIG_AD7150=m +CONFIG_AD7746=m +CONFIG_ATLAS_PH_SENSOR=m +CONFIG_ATLAS_EZO_SENSOR=m +CONFIG_BME680=m +CONFIG_CCS811=m +CONFIG_IAQCORE=m +CONFIG_PMS7003=m +CONFIG_SCD30_CORE=m +CONFIG_SCD30_I2C=m +CONFIG_SCD30_SERIAL=m +CONFIG_SCD4X=m +CONFIG_SENSIRION_SGP30=m +CONFIG_SENSIRION_SGP40=m +CONFIG_SPS30_I2C=m +CONFIG_SPS30_SERIAL=m +CONFIG_SENSEAIR_SUNRISE_CO2=m +CONFIG_VZ89X=m +CONFIG_AD3552R=m +CONFIG_AD5064=m +CONFIG_AD5360=m +CONFIG_AD5380=m +CONFIG_AD5421=m +CONFIG_AD5446=m +CONFIG_AD5449=m +CONFIG_AD5592R=m +CONFIG_AD5593R=m +CONFIG_AD5504=m +CONFIG_AD5624R_SPI=m +CONFIG_LTC2688=m +CONFIG_AD5686_SPI=m +CONFIG_AD5696_I2C=m +CONFIG_AD5755=m +CONFIG_AD5758=m +CONFIG_AD5761=m +CONFIG_AD5764=m +CONFIG_AD5766=m +CONFIG_AD5770R=m +CONFIG_AD5791=m +CONFIG_AD7293=m +CONFIG_AD7303=m +CONFIG_AD8801=m +CONFIG_DPOT_DAC=m +CONFIG_DS4424=m +CONFIG_LTC1660=m +CONFIG_LTC2632=m +CONFIG_M62332=m +CONFIG_MAX517=m +CONFIG_MAX5522=m +CONFIG_MAX5821=m +CONFIG_MCP4725=m +CONFIG_MCP4728=m +CONFIG_MCP4922=m +CONFIG_TI_DAC082S085=m +CONFIG_TI_DAC5571=m +CONFIG_TI_DAC7311=m +CONFIG_TI_DAC7612=m +CONFIG_AD9523=m +CONFIG_ADF4350=m +CONFIG_ADF4371=m +CONFIG_ADF4377=m +CONFIG_ADMV1013=m +CONFIG_ADMV4420=m +CONFIG_ADRF6780=m +CONFIG_ADIS16080=m +CONFIG_ADIS16130=m +CONFIG_ADIS16136=m +CONFIG_ADIS16260=m +CONFIG_ADXRS290=m +CONFIG_ADXRS450=m +CONFIG_BMG160=m +CONFIG_FXAS21002C=m +CONFIG_HID_SENSOR_GYRO_3D=m +CONFIG_MPU3050_I2C=m +CONFIG_IIO_ST_GYRO_3AXIS=m +CONFIG_ITG3200=m +CONFIG_AFE4403=m +CONFIG_AFE4404=m +CONFIG_MAX30100=m +CONFIG_MAX30102=m +CONFIG_AM2315=m +CONFIG_DHT11=m +CONFIG_HDC100X=m +CONFIG_HDC2010=m +CONFIG_HID_SENSOR_HUMIDITY=m +CONFIG_HTS221=m +CONFIG_HTU21=m +CONFIG_SI7005=m +CONFIG_SI7020=m +CONFIG_ADIS16400=m +CONFIG_ADIS16460=m +CONFIG_ADIS16475=m +CONFIG_ADIS16480=m +CONFIG_BMI160_I2C=m +CONFIG_BMI160_SPI=m +CONFIG_BOSCH_BNO055_SERIAL=m +CONFIG_BOSCH_BNO055_I2C=m +CONFIG_FXOS8700_I2C=m +CONFIG_FXOS8700_SPI=m +CONFIG_KMX61=m +CONFIG_INV_ICM42600_I2C=m +CONFIG_INV_ICM42600_SPI=m +CONFIG_INV_MPU6050_I2C=m +CONFIG_INV_MPU6050_SPI=m +CONFIG_IIO_ST_LSM6DSX=m +CONFIG_IIO_ST_LSM9DS0=m +CONFIG_ADJD_S311=m +CONFIG_ADUX1020=m +CONFIG_AL3010=m +CONFIG_AL3320A=m +CONFIG_APDS9300=m +CONFIG_APDS9960=m +CONFIG_AS73211=m +CONFIG_BH1750=m +CONFIG_BH1780=m +CONFIG_CM32181=m +CONFIG_CM3232=m +CONFIG_CM3323=m +CONFIG_CM3605=m +CONFIG_CM36651=m +CONFIG_GP2AP002=m +CONFIG_GP2AP020A00F=m +CONFIG_SENSORS_ISL29018=m +CONFIG_SENSORS_ISL29028=m +CONFIG_ISL29125=m +CONFIG_HID_SENSOR_ALS=m +CONFIG_HID_SENSOR_PROX=m +CONFIG_JSA1212=m +CONFIG_ROHM_BU27008=m +CONFIG_ROHM_BU27034=m +CONFIG_RPR0521=m +CONFIG_LTR501=m +CONFIG_LTRF216A=m +CONFIG_LV0104CS=m +CONFIG_MAX44000=m +CONFIG_MAX44009=m +CONFIG_NOA1305=m +CONFIG_OPT3001=m +CONFIG_OPT4001=m +CONFIG_PA12203001=m +CONFIG_SI1133=m +CONFIG_SI1145=m +CONFIG_STK3310=m +CONFIG_ST_UVIS25=m +CONFIG_TCS3414=m +CONFIG_TCS3472=m +CONFIG_SENSORS_TSL2563=m +CONFIG_TSL2583=m +CONFIG_TSL2591=m +CONFIG_TSL2772=m +CONFIG_TSL4531=m +CONFIG_US5182D=m +CONFIG_VCNL4000=m +CONFIG_VCNL4035=m +CONFIG_VEML6030=m +CONFIG_VEML6070=m +CONFIG_VL6180=m +CONFIG_ZOPT2201=m +CONFIG_AK8974=m +CONFIG_AK09911=m +CONFIG_BMC150_MAGN_I2C=m +CONFIG_BMC150_MAGN_SPI=m +CONFIG_MAG3110=m +CONFIG_HID_SENSOR_MAGNETOMETER_3D=m +CONFIG_MMC35240=m +CONFIG_SENSORS_HMC5843_I2C=m +CONFIG_SENSORS_HMC5843_SPI=m +CONFIG_SENSORS_RM3100_I2C=m +CONFIG_SENSORS_RM3100_SPI=m +CONFIG_TI_TMAG5273=m +CONFIG_YAMAHA_YAS530=m +CONFIG_IIO_MUX=m +CONFIG_HID_SENSOR_INCLINOMETER_3D=m +CONFIG_HID_SENSOR_DEVICE_ROTATION=m +CONFIG_IIO_HRTIMER_TRIGGER=m +CONFIG_IIO_INTERRUPT_TRIGGER=m +CONFIG_IIO_TIGHTLOOP_TRIGGER=m +CONFIG_IIO_SYSFS_TRIGGER=m +CONFIG_HID_SENSOR_CUSTOM_INTEL_HINGE=m +CONFIG_AD5110=m +CONFIG_AD5272=m +CONFIG_DS1803=m +CONFIG_MAX5432=m +CONFIG_MAX5481=m +CONFIG_MAX5487=m +CONFIG_MCP4018=m +CONFIG_MCP4131=m +CONFIG_MCP4531=m +CONFIG_MCP41010=m +CONFIG_TPL0102=m +CONFIG_X9250=m +CONFIG_LMP91000=m +CONFIG_ABP060MG=m +CONFIG_BMP280=m +CONFIG_DLHL60D=m +CONFIG_DPS310=m +CONFIG_HID_SENSOR_PRESS=m +CONFIG_HP03=m +CONFIG_ICP10100=m +CONFIG_MPL115_I2C=m +CONFIG_MPL115_SPI=m +CONFIG_MPL3115=m +CONFIG_MPRLS0025PA=m +CONFIG_MS5611=m +CONFIG_MS5611_I2C=m +CONFIG_MS5611_SPI=m +CONFIG_MS5637=m +CONFIG_IIO_ST_PRESS=m +CONFIG_T5403=m +CONFIG_HP206C=m +CONFIG_ZPA2326=m +CONFIG_AS3935=m +CONFIG_IRSD200=m +CONFIG_ISL29501=m +CONFIG_LIDAR_LITE_V2=m +CONFIG_MB1232=m +CONFIG_PING=m +CONFIG_RFD77402=m +CONFIG_SRF04=m +CONFIG_SX9310=m +CONFIG_SX9324=m +CONFIG_SX9360=m +CONFIG_SX9500=m +CONFIG_SRF08=m +CONFIG_VCNL3020=m +CONFIG_VL53L0X_I2C=m +CONFIG_AD2S90=m +CONFIG_AD2S1200=m +CONFIG_LTC2983=m +CONFIG_MAXIM_THERMOCOUPLE=m +CONFIG_HID_SENSOR_TEMP=m +CONFIG_MLX90614=m +CONFIG_MLX90632=m +CONFIG_TMP006=m +CONFIG_TMP007=m +CONFIG_TMP117=m +CONFIG_TSYS01=m +CONFIG_TSYS02D=m +CONFIG_MAX30208=m +CONFIG_MAX31856=m +CONFIG_MAX31865=m +CONFIG_PWM=y +CONFIG_PWM_OMAP_DMTIMER=y +CONFIG_PWM_PCA9685=y +CONFIG_PWM_STMPE=y +CONFIG_PWM_TIECAP=y +CONFIG_PWM_TIEHRPWM=y +CONFIG_RESET_TI_SYSCON=y +CONFIG_PHY_CAN_TRANSCEIVER=m +CONFIG_OMAP_USB2=y +CONFIG_TI_PIPE3=y +CONFIG_RAS=y +CONFIG_ANDROID_BINDER_IPC=m +CONFIG_FPGA=m +CONFIG_ALTERA_PR_IP_CORE=m +CONFIG_ALTERA_PR_IP_CORE_PLAT=m +CONFIG_FPGA_MGR_ALTERA_PS_SPI=m +CONFIG_FPGA_MGR_XILINX_SPI=m +CONFIG_FPGA_MGR_ICE40_SPI=m +CONFIG_FPGA_MGR_MACHXO2_SPI=m +CONFIG_FPGA_BRIDGE=m +CONFIG_ALTERA_FREEZE_BRIDGE=m +CONFIG_XILINX_PR_DECOUPLER=m +CONFIG_FPGA_REGION=m +CONFIG_OF_FPGA_REGION=m +CONFIG_MUX_ADG792A=m +CONFIG_MUX_ADGS1408=m +CONFIG_MUX_GPIO=m +CONFIG_MUX_MMIO=m +CONFIG_COUNTER=m +CONFIG_INTERRUPT_CNT=m +CONFIG_TI_ECAP_CAPTURE=m +CONFIG_TI_EQEP=m +CONFIG_VALIDATE_FS_PARSER=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=y +CONFIG_BTRFS_FS=y +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_FS_COMPRESSION=y +CONFIG_ZONEFS_FS=m +CONFIG_FS_ENCRYPTION=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_AUTOFS_FS=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=m +CONFIG_VIRTIO_FS=m +CONFIG_OVERLAY_FS=y +CONFIG_FSCACHE=y +CONFIG_FSCACHE_STATS=y +CONFIG_CACHEFILES=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_IOCHARSET="ascii" +CONFIG_FAT_DEFAULT_UTF8=y +CONFIG_EXFAT_FS=m +CONFIG_NTFS_FS=m +CONFIG_NTFS_RW=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=m +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RUBIN=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZ4=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_ZSTD=y +CONFIG_ROMFS_FS=m +CONFIG_ROMFS_BACKED_BY_BOTH=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_SWAP=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_ROOT_NFS=y +# CONFIG_NFS_V4_2_READ_PLUS is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_BLOCKLAYOUT=y +CONFIG_NFSD_V4_SECURITY_LABEL=y +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SUNRPC_DEBUG=y +CONFIG_CEPH_FS=m +CONFIG_CEPH_FSCACHE=y +CONFIG_CEPH_FS_POSIX_ACL=y +CONFIG_CIFS=m +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +CONFIG_CIFS_DFS_UPCALL=y +CONFIG_CIFS_FSCACHE=y +CONFIG_SMB_SERVER=m +CONFIG_CODA_FS=m +CONFIG_AFS_FS=m +CONFIG_AFS_FSCACHE=y +CONFIG_9P_FS=m +CONFIG_9P_FSCACHE=y +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_9P_FS_SECURITY=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_MAC_ROMAN=m +CONFIG_NLS_MAC_CELTIC=m +CONFIG_NLS_MAC_CENTEURO=m +CONFIG_NLS_MAC_CROATIAN=m +CONFIG_NLS_MAC_CYRILLIC=m +CONFIG_NLS_MAC_GAELIC=m +CONFIG_NLS_MAC_GREEK=m +CONFIG_NLS_MAC_ICELAND=m +CONFIG_NLS_MAC_INUIT=m +CONFIG_NLS_MAC_ROMANIAN=m +CONFIG_NLS_MAC_TURKISH=m +CONFIG_DLM=m +CONFIG_DLM_DEBUG=y +CONFIG_UNICODE=y +CONFIG_KEY_DH_OPERATIONS=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK_XFRM=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_TOMOYO=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_YAMA=y +CONFIG_SECURITY_LANDLOCK=y +CONFIG_INTEGRITY_SIGNATURE=y +CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y +CONFIG_IMA=y +CONFIG_IMA_SIG_TEMPLATE=y +CONFIG_IMA_DEFAULT_HASH_SHA256=y +CONFIG_IMA_APPRAISE=y +CONFIG_IMA_ARCH_POLICY=y +CONFIG_EVM=y +CONFIG_DEFAULT_SECURITY_APPARMOR=y +CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf" +CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y +CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_CRYPTO_USER=m +CONFIG_CRYPTO_PCRYPT=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_ECRDSA=m +CONFIG_CRYPTO_CURVE25519=m +CONFIG_CRYPTO_AES_TI=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_ADIANTUM=m +CONFIG_CRYPTO_CFB=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_KEYWRAP=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_OFB=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_AEGIS128=m +CONFIG_CRYPTO_CHACHA20POLY1305=m +CONFIG_CRYPTO_CMAC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_SM3_GENERIC=m +CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_LZ4=m +CONFIG_CRYPTO_LZ4HC=m +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_USER_API_SKCIPHER=y +CONFIG_CRYPTO_USER_API_RNG=m +CONFIG_CRYPTO_USER_API_AEAD=m +# CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE is not set +CONFIG_CRYPTO_GHASH_ARM_CE=m +CONFIG_CRYPTO_NHPOLY1305_NEON=m +CONFIG_CRYPTO_BLAKE2B_NEON=m +CONFIG_CRYPTO_SHA1_ARM_NEON=m +CONFIG_CRYPTO_SHA1_ARM_CE=m +CONFIG_CRYPTO_SHA2_ARM_CE=m +CONFIG_CRYPTO_SHA512_ARM=m +CONFIG_CRYPTO_AES_ARM=m +CONFIG_CRYPTO_AES_ARM_BS=m +CONFIG_CRYPTO_AES_ARM_CE=m +CONFIG_CRYPTO_CRC32_ARM_CE=m +CONFIG_CRYPTO_CRCT10DIF_ARM_CE=m +CONFIG_CRYPTO_DEV_OMAP=y +CONFIG_CRYPTO_DEV_OMAP_SHAM=y +CONFIG_CRYPTO_DEV_OMAP_AES=y +CONFIG_CRYPTO_DEV_OMAP_DES=y +CONFIG_CRYPTO_DEV_ATMEL_ECC=y +CONFIG_CRYPTO_DEV_ATMEL_SHA204A=y +CONFIG_CRYPTO_DEV_VIRTIO=m +CONFIG_PKCS8_PRIVATE_KEY_PARSER=m +# CONFIG_RAID6_PQ_BENCHMARK is not set +CONFIG_CORDIC=m +CONFIG_CRC4=m +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_SPARC is not set +CONFIG_CMA_SIZE_MBYTES=48 +CONFIG_IRQ_POLL=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_FONT_TER16x32=y +CONFIG_PRINTK_TIME=y +CONFIG_BOOT_PRINTK_DELAY=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01b6 +CONFIG_PAGE_EXTENSION=y +CONFIG_PAGE_POISONING=y +CONFIG_DEBUG_WX=y +CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_SCHEDSTATS=y +CONFIG_DEBUG_PREEMPT=y +CONFIG_DEBUG_LIST=y +# CONFIG_RCU_TRACE is not set +CONFIG_STACK_TRACER=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_STRICT_DEVMEM is not set +CONFIG_NOTIFIER_ERROR_INJECTION=m +# CONFIG_RUNTIME_TESTING_MENU is not set diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/BONE-I2C1.dtso b/arch/arm64/boot/dts/ti/BONE-I2C1.dtso --- a/arch/arm64/boot/dts/ti/BONE-I2C1.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/BONE-I2C1.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 BeagleBoard.org - https://beagleboard.org/ + * + * https://docs.beagleboard.io/latest/boards/capes/cape-interface-spec.html#i2c + */ + +/dts-v1/; +/plugin/; + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BONE-I2C1.kernel = __TIMESTAMP__; + }; +}; + +&bone_i2c_1 { + status = "okay"; + clock-frequency = <100000>; + symlink = "bone/i2c/1"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/BONE-I2C2.dtso b/arch/arm64/boot/dts/ti/BONE-I2C2.dtso --- a/arch/arm64/boot/dts/ti/BONE-I2C2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/BONE-I2C2.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 BeagleBoard.org - https://beagleboard.org/ + * + * https://docs.beagleboard.io/latest/boards/capes/cape-interface-spec.html#i2c + */ + +/dts-v1/; +/plugin/; + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BONE-I2C2.kernel = __TIMESTAMP__; + }; +}; + +&bone_i2c_2 { + status = "okay"; + clock-frequency = <100000>; + symlink = "bone/i2c/2"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/BONE-I2C3.dtso b/arch/arm64/boot/dts/ti/BONE-I2C3.dtso --- a/arch/arm64/boot/dts/ti/BONE-I2C3.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/BONE-I2C3.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 BeagleBoard.org - https://beagleboard.org/ + * + * https://docs.beagleboard.io/latest/boards/capes/cape-interface-spec.html#i2c + */ + +/dts-v1/; +/plugin/; + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ + */ +&{/chosen} { + overlays { + BONE-I2C3.kernel = __TIMESTAMP__; + }; +}; + +&bone_i2c_3 { + status = "okay"; + clock-frequency = <100000>; + symlink = "bone/i2c/3"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-ov5640.dtso --- a/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-ov5640.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-ov5640.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ALINX AN5641 & Digilent PCam 5C - OV5640 camera module + * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; +}; + +&main_gpio0 { + p11-hog { + /* P11 - CSI2_CAMERA_GPIO1 */ + gpio-hog; + gpios = <11 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI2_CAMERA_GPIO1"; + }; +}; + +&wkup_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-tevi-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-tevi-ov5640.dtso --- a/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-tevi-ov5640.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-tevi-ov5640.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Technexion TEVI-OV5640-*-RPI - OV5640 camera module + * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&main_gpio0 { + p11-hog { + /* P11 - CSI2_CAMERA_GPIO1 */ + gpio-hog; + gpios = <11 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI2_CAMERA_GPIO1"; + }; +}; + +&wkup_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts --- a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts 2024-07-07 20:37:34.624306449 -0400 @@ -1,9 +1,9 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * https://beagleplay.org/ * - * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ - * Copyright (C) 2022-2023 Robert Nelson, BeagleBoard.org Foundation + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2022-2024 Robert Nelson, BeagleBoard.org Foundation */ /dts-v1/; @@ -12,6 +12,7 @@ #include #include #include "k3-am625.dtsi" +#include "k3-am625-beagleplay-pinmux.dtsi" / { compatible = "beagle,am625-beagleplay", "ti,am625"; @@ -29,11 +30,12 @@ i2c3 = &main_i2c3; i2c4 = &wkup_i2c0; i2c5 = &mcu_i2c0; - mdio-gpio0 = &mdio0; + mikrobus0 = &mikrobus0; mmc0 = &sdhci0; mmc1 = &sdhci1; mmc2 = &sdhci2; rtc0 = &rtc; + rtc1 = &wkup_rtc0; serial0 = &main_uart5; serial1 = &main_uart6; serial2 = &main_uart0; @@ -46,6 +48,7 @@ }; memory@80000000 { + bootph-pre-ram; device_type = "memory"; /* 2G RAM */ reg = <0x00000000 0x80000000 0x00000000 0x80000000>; @@ -83,6 +86,7 @@ }; vsys_5v0: regulator-1 { + bootph-all; compatible = "regulator-fixed"; regulator-name = "vsys_5v0"; regulator-min-microvolt = <5000000>; @@ -93,6 +97,7 @@ vdd_3v3: regulator-2 { /* output of TLV62595DMQR-U12 */ + bootph-all; compatible = "regulator-fixed"; regulator-name = "vdd_3v3"; regulator-min-microvolt = <3300000>; @@ -109,7 +114,8 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; enable-active-high; - regulator-always-on; + /* regulator-always-on; */ + regulator-off-in-suspend; vin-supply = <&vdd_3v3>; gpio = <&main_gpio0 38 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; @@ -118,6 +124,7 @@ vdd_3v3_sd: regulator-4 { /* output of TPS22918DBVR-U21 */ + bootph-all; pinctrl-names = "default"; pinctrl-0 = <&vdd_3v3_sd_pins_default>; @@ -132,6 +139,7 @@ }; vdd_sd_dv: regulator-5 { + bootph-all; compatible = "regulator-gpio"; regulator-name = "sd_hs200_switch"; pinctrl-names = "default"; @@ -146,9 +154,11 @@ }; leds { + bootph-all; compatible = "gpio-leds"; led-0 { + bootph-all; gpios = <&main_gpio0 3 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; function = LED_FUNCTION_HEARTBEAT; @@ -156,6 +166,7 @@ }; led-1 { + bootph-all; gpios = <&main_gpio0 4 GPIO_ACTIVE_HIGH>; linux,default-trigger = "disk-activity"; function = LED_FUNCTION_DISK_ACTIVITY; @@ -163,16 +174,19 @@ }; led-2 { + bootph-all; gpios = <&main_gpio0 5 GPIO_ACTIVE_HIGH>; function = LED_FUNCTION_CPU; }; led-3 { + bootph-all; gpios = <&main_gpio0 6 GPIO_ACTIVE_HIGH>; function = LED_FUNCTION_LAN; }; led-4 { + bootph-all; gpios = <&main_gpio0 9 GPIO_ACTIVE_HIGH>; function = LED_FUNCTION_WLAN; }; @@ -220,31 +234,36 @@ }; }; - /* Workaround for errata i2329 - just use mdio bitbang */ - mdio0: mdio { - compatible = "virtual,mdio-gpio"; - pinctrl-names = "default"; - pinctrl-0 = <&mdio0_pins_default>; - gpios = <&main_gpio0 86 GPIO_ACTIVE_HIGH>, /* MDC */ - <&main_gpio0 85 GPIO_ACTIVE_HIGH>; /* MDIO */ - #address-cells = <1>; - #size-cells = <0>; - - cpsw3g_phy0: ethernet-phy@0 { - reg = <0>; - }; - - cpsw3g_phy1: ethernet-phy@1 { - reg = <1>; - reset-gpios = <&main_gpio1 5 GPIO_ACTIVE_LOW>; - reset-assert-us = <25>; - reset-deassert-us = <60000>; /* T2 */ - }; + mikrobus0: linux-mikrobus { + compatible = "mikrobus-connector"; + pinctrl-names = "default", "pwm_default", "pwm_gpio", + "uart_default", "uart_gpio", "i2c_default", + "i2c_gpio", "spi_default", "spi_gpio"; + pinctrl-0 = <&mikrobus_gpio_pins_default>; + pinctrl-1 = <&mikrobus_pwm_pins_default>; + pinctrl-2 = <&mikrobus_pwm_pins_gpio>; + pinctrl-3 = <&mikrobus_uart_pins_default>; + pinctrl-4 = <&mikrobus_uart_pins_gpio>; + pinctrl-5 = <&mikrobus_i2c_pins_default>; + pinctrl-6 = <&mikrobus_i2c_pins_gpio>; + pinctrl-7 = <&mikrobus_spi_pins_default>; + pinctrl-8 = <&mikrobus_spi_pins_gpio>; + i2c-adapter = <&main_i2c3>; + spi-controller = <&main_spi2>; + spi-cs = <0 1>; + uart = <&main_uart5>; + mikrobus-gpios = <&main_gpio1 11 GPIO_ACTIVE_HIGH>, <&main_gpio1 9 GPIO_ACTIVE_HIGH>, + <&main_gpio1 24 GPIO_ACTIVE_HIGH>, <&main_gpio1 25 GPIO_ACTIVE_HIGH>, + <&main_gpio1 22 GPIO_ACTIVE_HIGH>, <&main_gpio1 23 GPIO_ACTIVE_HIGH>, + <&main_gpio1 7 GPIO_ACTIVE_HIGH>, <&main_gpio1 8 GPIO_ACTIVE_HIGH>, + <&main_gpio1 14 GPIO_ACTIVE_HIGH>, <&main_gpio1 13 GPIO_ACTIVE_HIGH>, + <&main_gpio1 12 GPIO_ACTIVE_HIGH>, <&main_gpio1 10 GPIO_ACTIVE_HIGH>; }; }; &main_pmx0 { gpio0_pins_default: gpio0-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x0004, PIN_INPUT, 7) /* (G25) OSPI0_LBCLKO.GPIO0_1 */ AM62X_IOPAD(0x0008, PIN_INPUT, 7) /* (J24) OSPI0_DQS.GPIO0_2 */ @@ -264,6 +283,7 @@ }; vdd_sd_dv_pins_default: vdd-sd-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x0244, PIN_OUTPUT, 7) /* (C17) MMC1_SDWP.GPIO1_49 */ >; @@ -283,6 +303,7 @@ }; local_i2c_pins_default: local-i2c-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x01e0, PIN_INPUT_PULLUP, 0) /* (B16) I2C0_SCL */ AM62X_IOPAD(0x01e4, PIN_INPUT_PULLUP, 0) /* (A16) I2C0_SDA */ @@ -298,8 +319,8 @@ mdio0_pins_default: mdio0-default-pins { pinctrl-single,pins = < - AM62X_IOPAD(0x0160, PIN_OUTPUT, 7) /* (AD24) MDIO0_MDC.GPIO0_86 */ - AM62X_IOPAD(0x015c, PIN_INPUT, 7) /* (AB22) MDIO0_MDIO.GPIO0_85 */ + AM62X_IOPAD(0x0160, PIN_OUTPUT, 0) /* (AD24) MDIO0_MDC */ + AM62X_IOPAD(0x015c, PIN_INPUT, 0) /* (AB22) MDIO0_MDIO */ >; }; @@ -321,6 +342,7 @@ }; emmc_pins_default: emmc-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x0220, PIN_INPUT, 0) /* (Y3) MMC0_CMD */ AM62X_IOPAD(0x0218, PIN_INPUT, 0) /* (AB1) MMC0_CLK */ @@ -336,12 +358,14 @@ }; vdd_3v3_sd_pins_default: vdd-3v3-sd-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x01c4, PIN_INPUT, 7) /* (B14) SPI0_D1_GPIO1_19 */ >; }; sd_pins_default: sd-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x023c, PIN_INPUT, 0) /* (A21) MMC1_CMD */ AM62X_IOPAD(0x0234, PIN_INPUT, 0) /* (B22) MMC1_CLK */ @@ -394,6 +418,18 @@ >; }; + mikrobus_pwm_pins_default: mikrobus-pwm-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x01a4, PIN_INPUT, 2) /* (B20) MCASP0_ACLKX.ECAP2_IN_APWM_OUT */ + >; + }; + + mikrobus_pwm_pins_gpio: mikrobus-pwm-gpio-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x01a4, PIN_INPUT, 7) /* (B20) MCASP0_ACLKX.GPIO1_11 */ + >; + }; + mikrobus_i2c_pins_default: mikrobus-i2c-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x01d0, PIN_INPUT_PULLUP, 2) /* (A15) UART0_CTSn.I2C3_SCL */ @@ -401,6 +437,13 @@ >; }; + mikrobus_i2c_pins_gpio: mikrobus-i2c-gpio-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x01d0, PIN_INPUT, 7) /* (A15) UART0_CTSn.GPIO1_22 */ + AM62X_IOPAD(0x01d4, PIN_INPUT, 7) /* (B15) UART0_RTSn.GPIO1_23 */ + >; + }; + mikrobus_uart_pins_default: mikrobus-uart-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x01d8, PIN_INPUT, 1) /* (C15) MCAN0_TX.UART5_RXD */ @@ -408,6 +451,13 @@ >; }; + mikrobus_uart_pins_gpio: mikrobus-uart-gpio-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x01d8, PIN_INPUT, 7) /* (C15) MCAN0_TX.GPIO1_24 */ + AM62X_IOPAD(0x01dc, PIN_INPUT, 7) /* (E15) MCAN0_RX.GPIO1_25 */ + >; + }; + mikrobus_spi_pins_default: mikrobus-spi-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x01b0, PIN_INPUT, 1) /* (A20) MCASP0_ACLKR.SPI2_CLK */ @@ -417,7 +467,17 @@ >; }; + mikrobus_spi_pins_gpio: mikrobus-spi-gpio-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x0194, PIN_INPUT, 7) /* (B19) MCASP0_AXR3.GPIO1_7 */ + AM62X_IOPAD(0x0198, PIN_INPUT, 7) /* (A19) MCASP0_AXR2.GPIO1_8 */ + AM62X_IOPAD(0x01ac, PIN_INPUT, 7) /* (E19) MCASP0_AFSR.GPIO1_13 */ + AM62X_IOPAD(0x01b0, PIN_INPUT, 7) /* (A20) MCASP0_ACLKR.GPIO1_14 */ + >; + }; + mikrobus_gpio_pins_default: mikrobus-gpio-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x019c, PIN_INPUT, 7) /* (B18) MCASP0_AXR1.GPIO1_9 */ AM62X_IOPAD(0x01a0, PIN_INPUT, 7) /* (E18) MCASP0_AXR0.GPIO1_10 */ @@ -425,7 +485,8 @@ >; }; - console_pins_default: console-default-pins { + main_uart0_pins_default: main-uart0-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x01c8, PIN_INPUT, 0) /* (D14) UART0_RXD */ AM62X_IOPAD(0x01cc, PIN_OUTPUT, 0) /* (E14) UART0_TXD */ @@ -501,6 +562,20 @@ AM62X_IOPAD(0x0078, PIN_OUTPUT, 1) /* (U24) GPMC0_AD15.VOUT0_DATA23 */ >; }; + + touchscreen_pins_default: touchscreen-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x01b4, PIN_OUTPUT, 7) /* (A13) SPI0_CS0.GPIO1_15 */ + AM62X_IOPAD(0x00a0, PIN_INPUT, 7) /* (K25) GPMC0_WPn.GPIO0_39 */ + >; + }; + + backlight_pins_default: bl-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x0000, PIN_OUTPUT, 7) /* (H24) OSPI0_CLK.GPIO0_0 */ + AM62X_IOPAD(0x01b8, PIN_OUTPUT, 2) /* (C13) SPI0_CS1.EHRPWM0_B */ + >; + }; }; &mcu_pmx0 { @@ -554,11 +629,13 @@ }; &usbss0 { + bootph-all; ti,vbus-divider; status = "okay"; }; &usb0 { + bootph-all; dr_mode = "peripheral"; }; @@ -592,11 +669,24 @@ }; &cpsw3g_mdio { - /* Workaround for errata i2329 - Use mdio bitbang */ - status = "disabled"; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mdio0_pins_default>; + + cpsw3g_phy0: ethernet-phy@0 { + reg = <0>; + }; + + cpsw3g_phy1: ethernet-phy@1 { + reg = <1>; + reset-gpios = <&main_gpio1 5 GPIO_ACTIVE_LOW>; + reset-assert-us = <25>; + reset-deassert-us = <60000>; /* T2 */ + }; }; &main_gpio0 { + bootph-all; pinctrl-names = "default"; pinctrl-0 = <&gpio0_pins_default>; gpio-line-names = "BL_EN_3V3", "SPE_PO_EN", "RTC_INT", /* 0-2 */ @@ -616,8 +706,7 @@ }; &main_gpio1 { - pinctrl-names = "default"; - pinctrl-0 = <&mikrobus_gpio_pins_default>; + bootph-all; gpio-line-names = "", "", "", "", "", /* 0-4 */ "SPE_RSTN", "SPE_INTN", "MIKROBUS_GPIO1_7", /* 5-7 */ "MIKROBUS_GPIO1_8", "MIKROBUS_GPIO1_9", /* 8-9 */ @@ -632,7 +721,17 @@ "SD_CD", "SD_VOLT_SEL", "", ""; /* 48-51 */ }; +&mcu_gpio0 { + gpio-line-names = "", "", "", "", /* 0-3 */ + "", "", "", "", /* 4-7 */ + "", "", "", "", /* 8-11 */ + "", "", "", "", /* 12-15 */ + "", "QWIIC_I2C0_SCL", "QWIIC_I2C0_SDA", "", /* 16-19 */ + "", "", "", ""; /* 20-23 */ +}; + &main_i2c0 { + bootph-all; pinctrl-names = "default"; pinctrl-0 = <&local_i2c_pins_default>; clock-frequency = <400000>; @@ -651,6 +750,7 @@ }; tps65219: pmic@30 { + bootph-all; compatible = "ti,tps65219"; reg = <0x30>; buck1-supply = <&vsys_5v0>; @@ -788,34 +888,31 @@ }; &main_i2c3 { - pinctrl-names = "default"; - pinctrl-0 = <&mikrobus_i2c_pins_default>; clock-frequency = <400000>; status = "okay"; }; &main_spi2 { - pinctrl-names = "default"; - pinctrl-0 = <&mikrobus_spi_pins_default>; status = "okay"; + symlink = "play/mikrobus/spi"; }; &sdhci0 { + bootph-all; pinctrl-names = "default"; pinctrl-0 = <&emmc_pins_default>; - ti,driver-strength-ohm = <50>; disable-wp; status = "okay"; }; &sdhci1 { /* SD/MMC */ + bootph-all; pinctrl-names = "default"; pinctrl-0 = <&sd_pins_default>; vmmc-supply = <&vdd_3v3_sd>; vqmmc-supply = <&vdd_sd_dv>; - ti,driver-strength-ohm = <50>; disable-wp; cd-gpios = <&main_gpio1 48 GPIO_ACTIVE_LOW>; cd-debounce-delay-ms = <100>; @@ -827,12 +924,10 @@ vmmc-supply = <&wlan_en>; pinctrl-names = "default"; pinctrl-0 = <&wifi_pins_default>, <&wifi_32k_clk>; - bus-width = <4>; non-removable; ti,fails-without-test-cd; cap-power-off-card; keep-power-in-suspend; - ti,driver-strength-ohm = <50>; assigned-clocks = <&k3_clks 157 158>; assigned-clock-parents = <&k3_clks 157 160>; #address-cells = <1>; @@ -850,8 +945,9 @@ }; &main_uart0 { + bootph-all; pinctrl-names = "default"; - pinctrl-0 = <&console_pins_default>; + pinctrl-0 = <&main_uart0_pins_default>; status = "okay"; }; @@ -861,15 +957,21 @@ }; &main_uart5 { - pinctrl-names = "default"; - pinctrl-0 = <&mikrobus_uart_pins_default>; status = "okay"; + force-empty-serdev-controller; }; &main_uart6 { pinctrl-names = "default"; pinctrl-0 = <&wifi_debug_uart_pins_default>; status = "okay"; + + mcu { + status = "okay"; + compatible = "ti,cc1352p7"; + reset-gpios = <&main_gpio0 72 GPIO_ACTIVE_LOW>; + vdds-supply = <&vdd_3v3>; + }; }; &dss { @@ -903,6 +1005,6 @@ 0 0 0 0 0 0 0 0 >; - tx-num-evt = <32>; - rx-num-evt = <32>; + tx-num-evt = <0>; + rx-num-evt = <0>; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-beagleplay-lincolntech-lcd185-panel.dtso b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-lincolntech-lcd185-panel.dtso --- a/arch/arm64/boot/dts/ti/k3-am625-beagleplay-lincolntech-lcd185-panel.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-lincolntech-lcd185-panel.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * Lincoln tech Solutions OLDI panel (LCD185-101CT) and touch DT overlay for AM625-BeaglePlay + * + * AM625-BeaglePlay: https://www.beagleboard.org/boards/beagleplay + * Panel datasheet: https://lincolntechsolutions.com/wp-content/uploads/2023/04/LCD185-101CTL1ARNTT_DS_R1.3.pdf + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&{/} { + backlight: backlight { + compatible = "pwm-backlight"; + pinctrl-names = "default"; + pinctrl-0 = <&backlight_pins_default>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + enable-gpios = <&main_gpio0 0 GPIO_ACTIVE_HIGH>; + pwms = <&epwm0 1 20000 0>; + }; + + lcd { + compatible = "lincolntech,lcd185-101ct", "panel-simple"; + backlight = <&backlight>; + /* + * Note that the OLDI TX 0 transmits the odd set of pixels + * while the OLDI TX 1 transmits the even set. This is a + * fixed configuration in the IP integration and is not + * changeable. The properties, "dual-lvds-odd-pixels" and + * "dual-lvds-even-pixels" have been used to merely + * identify if a Dual Link configuration is required. + * Swapping them will cause an error in the dss oldi driver. + */ + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + lcd_in0: endpoint { + remote-endpoint = <&oldi_0_out>; + }; + }; + port@1 { + reg = <1>; + dual-lvds-even-pixels; + lcd_in1: endpoint { + remote-endpoint = <&oldi_1_out>; + }; + }; + }; + }; +}; + +&dss { + status = "okay"; +}; + +&oldi0 { + status = "okay"; +}; + +&oldi1 { + status = "okay"; +}; + +&oldi0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + oldi_0_in: endpoint { + remote-endpoint = <&dpi0_out0>; + }; + }; + + port@1 { + reg = <1>; + oldi_0_out: endpoint { + remote-endpoint = <&lcd_in0>; + }; + }; +}; + +&oldi1_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + oldi_1_in: endpoint { + remote-endpoint = <&dpi0_out1>; + }; + }; + + port@1 { + reg = <1>; + oldi_1_out: endpoint { + remote-endpoint = <&lcd_in1>; + }; + }; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VP1: Output to OLDI */ + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + dpi0_out0: endpoint@0 { + reg = <0>; + remote-endpoint = <&oldi_0_in>; + }; + dpi0_out1: endpoint@1 { + reg = <1>; + remote-endpoint = <&oldi_1_in>; + }; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + + eeprom@57 { + compatible = "atmel,24c256"; + reg = <0x57>; + }; + + touchscreen@5d { + compatible = "goodix,gt928"; + reg = <0x5d>; + pinctrl-names = "default"; + pinctrl-0 = <&touchscreen_pins_default>; + interrupt-parent = <&main_gpio0>; + interrupts = <39 IRQ_TYPE_EDGE_FALLING>; + irq-gpios = <&main_gpio0 39 GPIO_ACTIVE_HIGH>; + reset-gpios = <&main_gpio1 15 GPIO_ACTIVE_HIGH>; + touchscreen-size-x = <1920>; + touchscreen-size-y = <1200>; + }; +}; + +&epwm0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-beagleplay-pinmux.dtsi b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-pinmux.dtsi --- a/arch/arm64/boot/dts/ti/k3-am625-beagleplay-pinmux.dtsi 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-pinmux.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * https://beagleplay.org/ + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2022-2024 Robert Nelson, BeagleBoard.org Foundation + */ + +#include + +/ { + chosen { + base_dtb = "k3-am625-beagleplay.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; + + leds { + led-0 { + label = "beaglebone:green:usr0"; + }; + + led-1 { + label = "beaglebone:green:usr1"; + }; + + led-2 { + label = "beaglebone:green:usr2"; + linux,default-trigger = "cpu"; + }; + + led-3 { + label = "beaglebone:green:usr3"; + }; + + led-4 { + label = "beaglebone:green:usr4"; + linux,default-trigger = "phy0tx"; + }; + }; +}; + +&wkup_i2c0 { + symlink = "play/csi/i2c"; +}; + +&mcu_i2c0 { + symlink = "play/qwiic/i2c"; +}; + +&main_i2c1 { + symlink = "play/grove/i2c"; +}; + +&main_i2c3 { + symlink = "play/mikrobus/i2c"; +}; + +&main_uart5 { + symlink = "play/mikrobus/uart"; +}; + +&main_uart6 { + symlink = "play/cc1352/uart"; + + mcu { + status = "okay"; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625.dtsi b/arch/arm64/boot/dts/ti/k3-am625.dtsi --- a/arch/arm64/boot/dts/ti/k3-am625.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am625.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -1,10 +1,10 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree Source for AM625 SoC family in Quad core configuration * * TRM: https://www.ti.com/lit/pdf/spruiv7 * - * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/ */ /dts-v1/; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts --- a/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts 2024-07-07 20:37:34.624306449 -0400 @@ -35,6 +35,18 @@ standby-gpios = <&gpio_exp 1 GPIO_ACTIVE_HIGH>; }; + hdmi0: connector-hdmi { + compatible = "hdmi-connector"; + label = "hdmi"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&sii9022_out>; + }; + }; + }; + keys { compatible = "gpio-keys"; autorepeat; @@ -93,6 +105,37 @@ >; }; + hdmi_int_pins_default: hdmi-int-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x040, PIN_INPUT, 7) /* (N23) GPMC0_AD1.GPIO0_16 */ + >; + }; + + main_dss0_pins_default: main-dss0-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x0b8, PIN_OUTPUT, 0) /* (U22) VOUT0_DATA0 */ + AM62X_IOPAD(0x0bc, PIN_OUTPUT, 0) /* (V24) VOUT0_DATA1 */ + AM62X_IOPAD(0x0e0, PIN_OUTPUT, 0) /* (V20) VOUT0_DATA10 */ + AM62X_IOPAD(0x0e4, PIN_OUTPUT, 0) /* (AA23) VOUT0_DATA11 */ + AM62X_IOPAD(0x0e8, PIN_OUTPUT, 0) /* (AB25) VOUT0_DATA12 */ + AM62X_IOPAD(0x0ec, PIN_OUTPUT, 0) /* (AA24) VOUT0_DATA13 */ + AM62X_IOPAD(0x0f0, PIN_OUTPUT, 0) /* (Y22) VOUT0_DATA14 */ + AM62X_IOPAD(0x0f4, PIN_OUTPUT, 0) /* (AA21) VOUT0_DATA15 */ + AM62X_IOPAD(0x0c0, PIN_OUTPUT, 0) /* (W25) VOUT0_DATA2 */ + AM62X_IOPAD(0x0c4, PIN_OUTPUT, 0) /* (W24) VOUT0_DATA3 */ + AM62X_IOPAD(0x0c8, PIN_OUTPUT, 0) /* (Y25) VOUT0_DATA4 */ + AM62X_IOPAD(0x0cc, PIN_OUTPUT, 0) /* (Y24) VOUT0_DATA5 */ + AM62X_IOPAD(0x0d0, PIN_OUTPUT, 0) /* (Y23) VOUT0_DATA6 */ + AM62X_IOPAD(0x0d4, PIN_OUTPUT, 0) /* (AA25) VOUT0_DATA7 */ + AM62X_IOPAD(0x0d8, PIN_OUTPUT, 0) /* (V21) VOUT0_DATA8 */ + AM62X_IOPAD(0x0dc, PIN_OUTPUT, 0) /* (W21) VOUT0_DATA9 */ + AM62X_IOPAD(0x0fc, PIN_OUTPUT, 0) /* (Y20) VOUT0_DE */ + AM62X_IOPAD(0x0f8, PIN_OUTPUT, 0) /* (AB24) VOUT0_HSYNC */ + AM62X_IOPAD(0x104, PIN_OUTPUT, 0) /* (AC24) VOUT0_PCLK */ + AM62X_IOPAD(0x100, PIN_OUTPUT, 0) /* (AC25) VOUT0_VSYNC */ + >; + }; + main_i2c1_pins_default: main-i2c1-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x1e8, PIN_INPUT_PULLUP, 0) /* (B17) I2C1_SCL */ @@ -179,15 +222,36 @@ cpsw3g_phy3: ethernet-phy@3 { compatible = "ethernet-phy-id2000.a231", "ethernet-phy-ieee802.3-c22"; reg = <3>; + ti,clk-output-sel = ; ti,rx-internal-delay = ; ti,fifo-depth = ; }; }; +&dss { + pinctrl-names = "default"; + pinctrl-0 = <&main_dss0_pins_default>; + status = "okay"; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VP2: DPI/HDMI Output */ + port@1 { + reg = <1>; + + dpi1_out: endpoint { + remote-endpoint = <&sii9022_in>; + }; + }; +}; + &main_i2c1 { pinctrl-names = "default"; pinctrl-0 = <&main_i2c1_pins_default>; - clock-frequency = <400000>; + clock-frequency = <100000>; status = "okay"; gpio_exp: gpio-expander@21 { @@ -201,12 +265,43 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - gpio-line-names = "GPIO0_HDMI_RST", "GPIO1_CAN0_nEN", + gpio-line-names = "", "GPIO1_CAN0_nEN", "GPIO2_LED2", "GPIO3_LVDS_GPIO", "GPIO4_BUT2", "GPIO5_LVDS_BKLT_EN", "GPIO6_ETH1_USER_RESET", "GPIO7_AUDIO_USER_RESET"; }; + sii9022: bridge-hdmi@39 { + compatible = "sil,sii9022"; + reg = <0x39>; + + interrupt-parent = <&main_gpio0>; + interrupts = <16 IRQ_TYPE_EDGE_FALLING>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_int_pins_default>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sii9022_in: endpoint { + remote-endpoint = <&dpi1_out>; + }; + }; + + port@1 { + reg = <1>; + + sii9022_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; + eeprom@51 { compatible = "atmel,24c02"; pagesize = <16>; @@ -239,7 +334,6 @@ vqmmc-supply = <&vddshv5_sdio>; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; - ti,driver-strength-ohm = <50>; disable-wp; no-1-8-v; status = "okay"; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-sk-dmtimer-pwm.dtso b/arch/arm64/boot/dts/ti/k3-am625-sk-dmtimer-pwm.dtso --- a/arch/arm64/boot/dts/ti/k3-am625-sk-dmtimer-pwm.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-sk-dmtimer-pwm.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay to enable DM timer in PWM mode for AM625-SK + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&{/} { + leds { + compatible = "pwm-leds"; + pinctrl-names; + pinctrl-0; + + led-0 { + pwms = <&main_pwm7 0 7812500 0>; + max-brightness = <255>; + }; + }; + + main_pwm7: dmtimer-main-pwm-7 { + compatible = "ti,omap-dmtimer-pwm"; + #pwm-cells = <3>; + ti,timers = <&main_timer7>; + pinctrl-0 = <&usr_led_pins_default>; + pinctrl-names = "default"; + }; + + main_pwm3: dmtimer-main-pwm-3 { + /* PWM signal routed to pin 8 of J3 header */ + compatible = "ti,omap-dmtimer-pwm"; + #pwm-cells = <3>; + ti,timers = <&main_timer3>; + pinctrl-names = "default"; + pinctrl-0 = <&main_timer3_pins_default>; + }; + + mcu_pwm0: dmtimer-mcu-pwm-0 { + compatible = "ti,omap-dmtimer-pwm"; + #pwm-cells = <3>; + ti,timers = <&mcu_timer0>; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_timer0_pins_default>; + }; +}; + +&main_pmx0 { + usr_led_pins_default: usr-led-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x244, PIN_OUTPUT, 2) /* (C17) MMC1_SDWP.TIMER_IO7 */ + >; + }; + + main_timer3_pins_default: main_timer3-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x01dc, PIN_OUTPUT, 2) /* (A15) MCAN0_RX.TIMER_IO3 */ + >; + }; +}; + +&mcu_pmx0 { + mcu_timer0_pins_default: mcu_timer0-default-pins { + pinctrl-single,pins = < + AM62X_MCU_IOPAD(0x0038, PIN_OUTPUT, 1) /* (C4) MCU_MCAN0_RX.MCU_TIMER_IO0 */ + >; + }; +}; + +&mcu_timer0 { + /* Caution: ESM might use a MCU_TIMER in an ESM example */ + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-sk.dts b/arch/arm64/boot/dts/ti/k3-am625-sk.dts --- a/arch/arm64/boot/dts/ti/k3-am625-sk.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am625-sk.dts 2024-07-07 20:37:34.624306449 -0400 @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * AM625 SK: https://www.ti.com/lit/zip/sprr448 * - * Copyright (C) 2021-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/ */ /dts-v1/; @@ -31,6 +31,7 @@ vmain_pd: regulator-0 { /* TPS65988 PD CONTROLLER OUTPUT */ + bootph-all; compatible = "regulator-fixed"; regulator-name = "vmain_pd"; regulator-min-microvolt = <5000000>; @@ -41,6 +42,7 @@ vcc_5v0: regulator-1 { /* Output of LM34936 */ + bootph-all; compatible = "regulator-fixed"; regulator-name = "vcc_5v0"; regulator-min-microvolt = <5000000>; @@ -52,6 +54,7 @@ vcc_3v3_sys: regulator-2 { /* output of LM61460-Q1 */ + bootph-all; compatible = "regulator-fixed"; regulator-name = "vcc_3v3_sys"; regulator-min-microvolt = <3300000>; @@ -63,6 +66,7 @@ vdd_mmc1: regulator-3 { /* TPS22918DBVR */ + bootph-all; compatible = "regulator-fixed"; regulator-name = "vdd_mmc1"; regulator-min-microvolt = <3300000>; @@ -75,6 +79,7 @@ vdd_sd_dv: regulator-4 { /* Output of TLV71033 */ + bootph-all; compatible = "regulator-gpio"; regulator-name = "tlv71033"; pinctrl-names = "default"; @@ -102,6 +107,7 @@ &main_pmx0 { main_rgmii2_pins_default: main-rgmii2-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x184, PIN_INPUT, 0) /* (AE23) RGMII2_RD0 */ AM62X_IOPAD(0x188, PIN_INPUT, 0) /* (AB20) RGMII2_RD1 */ @@ -119,6 +125,7 @@ }; ospi0_pins_default: ospi0-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x000, PIN_OUTPUT, 0) /* (H24) OSPI0_CLK */ AM62X_IOPAD(0x02c, PIN_OUTPUT, 0) /* (F23) OSPI0_CSn0 */ @@ -135,20 +142,32 @@ }; vdd_sd_dv_pins_default: vdd-sd-dv-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x07c, PIN_OUTPUT, 7) /* (P25) GPMC0_CLK.GPIO0_31 */ >; }; main_gpio1_ioexp_intr_pins_default: main-gpio1-ioexp-intr-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x01d4, PIN_INPUT, 7) /* (B15) UART0_RTSn.GPIO1_23 */ >; }; }; +&main_gpio0 { + bootph-all; +}; + +&main_gpio1 { + bootph-all; +}; + &main_i2c1 { + bootph-all; exp1: gpio@22 { + bootph-all; compatible = "ti,tca6424"; reg = <0x22>; gpio-controller; @@ -183,7 +202,13 @@ &cpsw3g { pinctrl-names = "default"; - pinctrl-0 = <&main_rgmii1_pins_default>, <&main_rgmii2_pins_default>; + pinctrl-0 = <&main_rgmii1_pins_default + &main_rgmii2_pins_default>; + + cpts@3d000 { + /* MAP HW3_TS_PUSH to GENF1 */ + ti,pps = <2 1>; + }; }; &cpsw_port2 { @@ -207,12 +232,18 @@ }; }; +&fss { + bootph-all; +}; + &ospi0 { + bootph-all; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&ospi0_pins_default>; flash@0 { + bootph-all; compatible = "jedec,spi-nor"; reg = <0x0>; spi-tx-bus-width = <8>; @@ -225,6 +256,7 @@ cdns,read-delay = <4>; partitions { + bootph-all; compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; @@ -260,6 +292,7 @@ }; partition@3fc0000 { + bootph-pre-ram; label = "ospi.phypattern"; reg = <0x3fc0000 0x40000>; }; @@ -270,3 +303,19 @@ &tlv320aic3106 { DVDD-supply = <&vcc_1v8>; }; + +#define K3_TS_OFFSET(pa, val) (0x4+(pa)*4) (0x10000 | val) + +×ync_router { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&cpsw_cpts>; + + /* Use Time Sync Router to map GENF1 input to HW3_TS_PUSH output */ + cpsw_cpts: cpsw-cpts { + pinctrl-single,pins = < + /* pps [cpsw cpts genf1] in17 -> out12 [cpsw cpts hw3_push] */ + K3_TS_OFFSET(12, 17) + >; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-sk-ecap-capture.dtso b/arch/arm64/boot/dts/ti/k3-am625-sk-ecap-capture.dtso --- a/arch/arm64/boot/dts/ti/k3-am625-sk-ecap-capture.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-sk-ecap-capture.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for enabling ECAP in capture mode on AM625-SK + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&main_pmx0 { + main_ecap2_capture_pins_default: main-ecap2-capture-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x01a4, PIN_INPUT, 2) /* (B20) MCASP0_ACLKX.ECAP2_IN_APWM_OUT */ + >; + }; +}; + +&ecap2 { + /* ECAP in capture mode */ + compatible = "ti,am62-ecap-capture"; + interrupt-parent = <&gic500>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&main_ecap2_capture_pins_default>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-sk-lincolntech-lcd185-panel.dtso b/arch/arm64/boot/dts/ti/k3-am625-sk-lincolntech-lcd185-panel.dtso --- a/arch/arm64/boot/dts/ti/k3-am625-sk-lincolntech-lcd185-panel.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-sk-lincolntech-lcd185-panel.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * Lincoln tech Solutions OLDI panel (LCD185-101CT) and touch DT overlay for AM625-SK + * + * AM625-SKEVM: https://www.ti.com/tool/SK-AM62 + * Panel datasheet: https://lincolntechsolutions.com/wp-content/uploads/2023/04/LCD185-101CTL1ARNTT_DS_R1.3.pdf + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&{/} { + display { + compatible = "lincolntech,lcd185-101ct", "panel-simple"; + /* + * Note that the OLDI TX 0 transmits the odd set of pixels + * while the OLDI TX 1 transmits the even set. This is a + * fixed configuration in the IP integration and is not + * changeable. The properties, "dual-lvds-odd-pixels" and + * "dual-lvds-even-pixels" have been used to merely + * identify if a Dual Link configuration is required. + * Swapping them will cause an error in the dss oldi driver. + */ + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + lcd_in0: endpoint { + remote-endpoint = <&oldi_0_out>; + }; + }; + port@1 { + reg = <1>; + dual-lvds-even-pixels; + lcd_in1: endpoint { + remote-endpoint = <&oldi_1_out>; + }; + }; + }; + }; +}; + +&dss { + status = "okay"; +}; + +&oldi0 { + status = "okay"; +}; + +&oldi1 { + status = "okay"; +}; + +&oldi0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + oldi_0_in: endpoint { + remote-endpoint = <&dpi0_out0>; + }; + }; + + port@1 { + reg = <1>; + oldi_0_out: endpoint { + remote-endpoint = <&lcd_in0>; + }; + }; +}; + +&oldi1_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + oldi_1_in: endpoint { + remote-endpoint = <&dpi0_out1>; + }; + }; + + port@1 { + reg = <1>; + oldi_1_out: endpoint { + remote-endpoint = <&lcd_in1>; + }; + }; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VP1: Output to OLDI */ + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + dpi0_out0: endpoint@0 { + reg = <0>; + remote-endpoint = <&oldi_0_in>; + }; + dpi0_out1: endpoint@1 { + reg = <1>; + remote-endpoint = <&oldi_1_in>; + }; + }; +}; + +&main_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + eeprom@57 { + compatible = "atmel,24c256"; + reg = <0x57>; + }; + + touchscreen@5d { + compatible = "goodix,gt928"; + reg = <0x5d>; + interrupt-parent = <&exp1>; + interrupts = <22 IRQ_TYPE_EDGE_FALLING>; + irq-gpios = <&exp1 22 GPIO_ACTIVE_LOW>; + touchscreen-size-x = <1920>; + touchscreen-size-y = <1200>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-sk-m2-cc3301.dtso b/arch/arm64/boot/dts/ti/k3-am625-sk-m2-cc3301.dtso --- a/arch/arm64/boot/dts/ti/k3-am625-sk-m2-cc3301.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-sk-m2-cc3301.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * DT Overlay for M.2-CC3301 board to connect to the M.2 connector on AM625-SK. + * + * Product page for board: https://www.ti.com/tool/M2-CC3301 + * CC3301 Datasheet: https://www.ti.com/lit/ds/symlink/cc3301.pdf + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include "k3-pinctrl.h" + +&{/} { + wlan_lten: regulator-30 { + compatible = "regulator-fixed"; + regulator-name = "wlan_lten"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vdd_mmc1>; + gpios = <&exp1 11 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + wlan_en: regulator-31 { + compatible = "regulator-fixed"; + regulator-name = "wlan_en"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&wlan_lten>; + enable-active-high; + gpios = <&main_gpio0 71 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&wlan_en_pins_default>; + }; +}; + +&main_pmx0 { + wlan_en_pins_default: wlan-en-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x124, PIN_OUTPUT, 7) /* (A23) MMC2_SDCD.GPIO0_71 */ + >; + }; + + main_mmc2_pins_default: main-mmc2-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x120, PIN_INPUT, 0) /* (C24) MMC2_CMD */ + AM62X_IOPAD(0x118, PIN_INPUT, 0) /* (D25) MMC2_CLK */ + AM62X_IOPAD(0x114, PIN_INPUT, 0) /* (B24) MMC2_DAT0 */ + AM62X_IOPAD(0x110, PIN_INPUT, 0) /* (C25) MMC2_DAT1 */ + AM62X_IOPAD(0x10c, PIN_INPUT, 0) /* (E23) MMC2_DAT2 */ + AM62X_IOPAD(0x108, PIN_INPUT, 0) /* (D24) MMC2_DAT3 */ + AM62X_IOPAD(0x11c, PIN_INPUT, 0) /* (#N/A) MMC2_CLKB */ + >; + }; + + main_wlirq_pins_default: main-wlirq-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x128, PIN_INPUT, 7) /* (B23) MMC2_SDWP.GPIO0_72 */ + >; + }; +}; + +&sdhci2 { + status = "okay"; + bootph-all; + vmmc-supply = <&wlan_en>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mmc2_pins_default>; + bus-width = <4>; + non-removable; + ti,fails-without-test-cd; + cap-power-off-card; + keep-power-in-suspend; + ti,driver-strength-ohm = <50>; + + #address-cells = <1>; + #size-cells = <0>; + wlcore: wlcore@2 { + compatible = "ti,cc3301"; + reg = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&main_wlirq_pins_default>; + interrupt-parent = <&main_gpio0>; + interrupts = <72 IRQ_TYPE_EDGE_FALLING>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-sk-mcspi-loopback.dtso b/arch/arm64/boot/dts/ti/k3-am625-sk-mcspi-loopback.dtso --- a/arch/arm64/boot/dts/ti/k3-am625-sk-mcspi-loopback.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-sk-mcspi-loopback.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,54 @@ + + +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for using McSPI on the RPi header on AM625-SK board. + * + * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&main_pmx0 { + main_spi0_pins_default: main-spi0-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x01bc, PIN_INPUT, 0) /* (A14) SPI0_CLK */ + AM62X_IOPAD(0x01c0, PIN_INPUT, 0) /* (B13) SPI0_D0 */ + AM62X_IOPAD(0x01c4, PIN_INPUT, 0) /* (B14) SPI0_D1 */ + AM62X_IOPAD(0x01b4, PIN_INPUT, 0) /* (A13) SPI0_CS0 */ + >; + }; +}; + +&main_i2c1 { + gpio@22 { + en_rpi_3v3 { + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "EXP_PS_3V3_EN"; + }; + }; +}; + +&main_spi0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&main_spi0_pins_default>; + pinctrl-names = "default"; + spidev@0 { + /* + * Using spidev compatible is warned loudly, + * thus use another equivalent compatible id + * from spidev. + */ + compatible = "rohm,dh2228fv"; + spi-max-frequency = <24000000>; + reg = <0>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-sk-microtips-mf101hie-panel.dtso b/arch/arm64/boot/dts/ti/k3-am625-sk-microtips-mf101hie-panel.dtso --- a/arch/arm64/boot/dts/ti/k3-am625-sk-microtips-mf101hie-panel.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-sk-microtips-mf101hie-panel.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * Microtips integrated OLDI panel (MF-101HIEBCAF0) and touch DT overlay for AM625 - SK + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +&{/} { + display { + compatible = "microtips,mf-101hiebcaf0", "panel-simple"; + /* + * Note that the OLDI TX 0 transmits the odd set of pixels + * while the OLDI TX 1 transmits the even set. This is a + * fixed configuration in the IP integration and is not + * changeable. The properties, "dual-lvds-odd-pixels" and + * "dual-lvds-even-pixels" have been used to merely + * identify if a Dual Link configuration is required. + * Swapping them will cause an error in the dss oldi driver. + */ + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + lcd_in0: endpoint { + remote-endpoint = <&oldi_0_out>; + }; + }; + port@1 { + reg = <1>; + dual-lvds-even-pixels; + lcd_in1: endpoint { + remote-endpoint = <&oldi_1_out>; + }; + }; + }; + }; +}; + +&dss { + status = "okay"; +}; + +&oldi0 { + status = "okay"; +}; + +&oldi1 { + status = "okay"; +}; + +&oldi0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + oldi_0_in: endpoint { + remote-endpoint = <&dpi0_out0>; + }; + }; + + port@1 { + reg = <1>; + oldi_0_out: endpoint { + remote-endpoint = <&lcd_in0>; + }; + }; +}; + +&oldi1_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + oldi_1_in: endpoint { + remote-endpoint = <&dpi0_out1>; + }; + }; + + port@1 { + reg = <1>; + oldi_1_out: endpoint { + remote-endpoint = <&lcd_in1>; + }; + }; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VP1: Output to OLDI */ + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + dpi0_out0: endpoint@0 { + reg = <0>; + remote-endpoint = <&oldi_0_in>; + }; + dpi0_out1: endpoint@1 { + reg = <1>; + remote-endpoint = <&oldi_1_in>; + }; + }; +}; + +&main_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@41 { + compatible = "ilitek,ili251x"; + reg = <0x41>; + interrupt-parent = <&exp1>; + interrupts = <22 IRQ_TYPE_EDGE_FALLING>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-sk-pwm.dtso b/arch/arm64/boot/dts/ti/k3-am625-sk-pwm.dtso --- a/arch/arm64/boot/dts/ti/k3-am625-sk-pwm.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-sk-pwm.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for enabling PWM output on RPi header on AM625-SK + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&main_pmx0 { + main_epwm0_pins_default: main-epwm0-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x01ac, PIN_OUTPUT, 6) /* (E19) MCASP0_AFSR.EHRPWM0_A */ + AM62X_IOPAD(0x01b0, PIN_OUTPUT, 6) /* (A20) MCASP0_ACLKR.EHRPWM0_B */ + >; + }; + main_epwm1_pins_default: main-epwm1-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x019c, PIN_OUTPUT, 6) /* (B18) MCASP0_AXR1.EHRPWM1_A */ + AM62X_IOPAD(0x01a0, PIN_OUTPUT, 6) /* (E18) MCASP0_AXR0.EHRPWM1_B */ + >; + }; + main_ecap2_pins_default: main-ecap2-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x01a4, PIN_OUTPUT, 2) /* (B20) MCASP0_ACLKX.ECAP2_IN_APWM_OUT */ + >; + }; +}; + +&main_i2c1 { + gpio@22 { + fet_sel { + gpio-hog; + gpios = <21 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "UART1_FET_SEL"; + }; + }; +}; + +&epwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_epwm0_pins_default>; + status = "okay"; +}; + +&epwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_epwm1_pins_default>; + status = "okay"; +}; + +&ecap2 { + /* ECAP in APWM mode */ + pinctrl-names = "default"; + pinctrl-0 = <&main_ecap2_pins_default>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-sk-rpi-hdr-ehrpwm.dtso b/arch/arm64/boot/dts/ti/k3-am625-sk-rpi-hdr-ehrpwm.dtso --- a/arch/arm64/boot/dts/ti/k3-am625-sk-rpi-hdr-ehrpwm.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-sk-rpi-hdr-ehrpwm.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for enabling RPi header with GPIOs and ePWMs for AM625-SK + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&main_pmx0 { + rpi_header_gpio0_pins_default: rpi-header-gpio0-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x0038, PIN_INPUT, 7) /* (E24) OSPI0_CSn3.GPIO0_14 */ + AM62X_IOPAD(0x0088, PIN_INPUT, 7) /* (L24) GPMC0_OEn_REn.GPIO0_33 */ + AM62X_IOPAD(0x0094, PIN_INPUT, 7) /* (N20) GPMC0_BE1n.GPIO0_36 */ + AM62X_IOPAD(0x009c, PIN_INPUT, 7) /* (V25) GPMC0_WAIT1.GPIO0_38 */ + AM62X_IOPAD(0x00a0, PIN_INPUT, 7) /* (K25) GPMC0_WPn.GPIO0_39 */ + AM62X_IOPAD(0x00a4, PIN_INPUT, 7) /* (M22) GPMC0_DIR.GPIO0_40 */ + AM62X_IOPAD(0x00a8, PIN_INPUT, 7) /* (M21) GPMC0_CSn0.GPIO0_41 */ + AM62X_IOPAD(0x00ac, PIN_INPUT, 7) /* (L21) GPMC0_CSn1.GPIO0_42 */ + >; + }; + + rpi_header_gpio1_pins_default: rpi-header-gpio1-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x01d0, PIN_INPUT, 7) /* (A15) UART0_CTSn.GPIO1_22 */ + >; + }; + + rpi_header_ehrpwm0_pins_default: rpi-header-ehrpwm0-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x01ac, PIN_OUTPUT, 6) /* (E19) MCASP0_AFSR.EHRPWM0_A */ + AM62X_IOPAD(0x01b0, PIN_OUTPUT, 6) /* (A20) MCASP0_ACLKR.EHRPWM0_B */ + >; + }; + + rpi_header_ehrpwm1_pins_default: rpi-header-ehrpwm1-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x019c, PIN_OUTPUT, 6) /* (B18) MCASP0_AXR1.EHRPWM1_A */ + AM62X_IOPAD(0x01a0, PIN_OUTPUT, 6) /* (E18) MCASP0_AXR0.EHRPWM1_B */ + >; + }; +}; + +&main_i2c1 { + gpio@22 { + p05-hog { + /* P05 - EXP_PS_3V3_EN */ + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "EXP_PS_3V3_EN"; + }; + + p06-hog { + /* P06 - EXP_PS_5V0_EN */ + gpio-hog; + gpios = <6 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "EXP_PS_5V0_EN"; + }; + + p25-hog { + /* P25 - UART1_FET_SEL */ + gpio-hog; + gpios = <21 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "UART1_FET_SEL"; + }; + }; +}; + +&epwm0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm0_pins_default>; +}; + +&epwm1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm1_pins_default>; +}; + + +&main_gpio0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_gpio0_pins_default>; +}; + +&main_gpio1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_gpio1_pins_default>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-mallow.dts b/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-mallow.dts --- a/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-mallow.dts 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-mallow.dts 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62 + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +/dts-v1/; + +#include "k3-am625.dtsi" +#include "k3-am62-verdin.dtsi" +#include "k3-am62-verdin-nonwifi.dtsi" +#include "k3-am62-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin AM62 on Mallow Board"; + compatible = "toradex,verdin-am62-nonwifi-mallow", + "toradex,verdin-am62-nonwifi", + "toradex,verdin-am62", + "ti,am625"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-mallow.dts b/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-mallow.dts --- a/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-mallow.dts 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-mallow.dts 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62 + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +/dts-v1/; + +#include "k3-am625.dtsi" +#include "k3-am62-verdin.dtsi" +#include "k3-am62-verdin-wifi.dtsi" +#include "k3-am62-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin AM62 WB on Mallow Board"; + compatible = "toradex,verdin-am62-wifi-mallow", + "toradex,verdin-am62-wifi", + "toradex,verdin-am62", + "ti,am625"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso b/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso --- a/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * OX05B1S Camera Module + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ox05b1s_fixed: ox05b1s-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + /* CAM port */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ox05b1s: camera@36 { + compatible = "ovti,ox05b"; + reg = <0x36>; + + clocks = <&clk_ox05b1s_fixed>; + clock-names = "inck"; + + pwdn-gpios = <&exp1 13 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + link-frequencies = /bits/ 64 <480000000>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + }; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts --- a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts 2024-07-07 20:37:34.628306469 -0400 @@ -20,7 +20,10 @@ serial0 = &wkup_uart0; serial2 = &main_uart0; serial3 = &main_uart1; + mmc0 = &sdhci0; mmc1 = &sdhci1; + ethernet0 = &cpsw_port1; + spi0 = &ospi0; }; chosen { @@ -39,6 +42,15 @@ #size-cells = <2>; ranges; + /* global cma region */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x00 0x24000000>; + alloc-ranges = <0x00 0xc0000000 0x00 0x24000000>; + linux,cma-default; + }; + secure_tfa_ddr: tfa@9e780000 { reg = <0x00 0x9e780000 0x00 0x80000>; alignment = <0x1000>; @@ -51,11 +63,62 @@ no-map; }; + wkup_r5fss0_core0_dma_memory_region: r5f-dma-memory@9c800000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9c800000 0x00 0x100000>; + no-map; + }; + wkup_r5fss0_core0_memory_region: r5f-dma-memory@9c900000 { compatible = "shared-dma-pool"; reg = <0x00 0x9c900000 0x00 0x01e00000>; no-map; }; + mcu_r5fss0_core0_dma_memory_region: r5f-dma-memory@9b800000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9b800000 0x00 0x100000>; + no-map; + }; + + mcu_r5fss0_core0_memory_region: r5f-dma-memory@9b900000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9b900000 0x00 0x0f00000>; + no-map; + }; + + c7x_0_dma_memory_region: c7x-dma-memory@99800000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x99800000 0x00 0x100000>; + no-map; + }; + + c7x_0_memory_region: c7x-memory@99900000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x99900000 0x00 0x01f00000>; + no-map; + }; + + edgeai_rtos_ipc_memory_region: edgeai-rtos-ipc-memory-region { + reg = <0x00 0xa0000000 0x00 0x01000000>; + no-map; + }; + + edgeai_memory_region: edgeai-dma-memory@a1000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1000000 0x00 0x02000000>; + no-map; + }; + + edgeai_shared_region: edgeai_shared-memories { + compatible = "dma-heap-carveout"; + reg = <0x00 0xa3000000 0x00 0x0b000000>; + }; + + edgeai_core_heaps: edgeai-core-heap-memory@ae000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xae000000 0x00 0x12000000>; + no-map; + }; }; vmain_pd: regulator-0 { @@ -79,10 +142,10 @@ regulator-boot-on; }; - vcc_3v3_sys: regulator-2 { + vcc_3v3_main: regulator-2 { /* output of LM5141-Q1 */ compatible = "regulator-fixed"; - regulator-name = "vcc_3v3_sys"; + regulator-name = "vcc_3v3_main"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; vin-supply = <&vmain_pd>; @@ -101,6 +164,31 @@ gpio = <&exp1 3 GPIO_ACTIVE_HIGH>; }; + vcc_3v3_sys: regulator-4 { + /* output of TPS222965DSGT */ + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3_sys"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_main>; + regulator-always-on; + regulator-boot-on; + }; + + vddshv_sdio: regulator-5 { + compatible = "regulator-gpio"; + regulator-name = "vddshv_sdio"; + pinctrl-names = "default"; + pinctrl-0 = <&vddshv_sdio_pins_default>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + vin-supply = <&ldo1>; + gpios = <&main_gpio0 31 GPIO_ACTIVE_HIGH>; + states = <1800000 0x0>, + <3300000 0x1>; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -114,6 +202,53 @@ default-state = "off"; }; }; + + tlv320_mclk: clk-0 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12288000>; + }; + + hdmi0: connector-hdmi { + compatible = "hdmi-connector"; + label = "hdmi"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&sii9022_out>; + }; + }; + }; + + codec_audio: sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "AM62Ax-SKEVM"; + simple-audio-card,widgets = + "Headphone", "Headphone Jack", + "Line", "Line In", + "Microphone", "Microphone Jack"; + simple-audio-card,routing = + "Headphone Jack", "HPLOUT", + "Headphone Jack", "HPROUT", + "LINE1L", "Line In", + "LINE1R", "Line In", + "MIC3R", "Microphone Jack", + "Microphone Jack", "Mic Bias"; + simple-audio-card,format = "dsp_b"; + simple-audio-card,bitclock-master = <&sound_master>; + simple-audio-card,frame-master = <&sound_master>; + simple-audio-card,bitclock-inversion; + + simple-audio-card,cpu { + sound-dai = <&mcasp1>; + }; + + sound_master: simple-audio-card,codec { + sound-dai = <&tlv320aic3106>; + clocks = <&tlv320_mclk>; + }; + }; }; &mcu_pmx0 { @@ -135,6 +270,39 @@ }; &main_pmx0 { + main_dss0_pins_default: main-dss0-default-pins { + pinctrl-single,pins = < + AM62AX_IOPAD(0x100, PIN_OUTPUT, 0) /* (V17) VOUT0_VSYNC */ + AM62AX_IOPAD(0x0f8, PIN_OUTPUT, 0) /* (T18) VOUT0_HSYNC */ + AM62AX_IOPAD(0x104, PIN_OUTPUT, 0) /* (AA22) VOUT0_PCLK */ + AM62AX_IOPAD(0x0fc, PIN_OUTPUT, 0) /* (U17) VOUT0_DE */ + AM62AX_IOPAD(0x0b8, PIN_OUTPUT, 0) /* (U22) VOUT0_DATA0 */ + AM62AX_IOPAD(0x0bc, PIN_OUTPUT, 0) /* (U21) VOUT0_DATA1 */ + AM62AX_IOPAD(0x0c0, PIN_OUTPUT, 0) /* (U20) VOUT0_DATA2 */ + AM62AX_IOPAD(0x0c4, PIN_OUTPUT, 0) /* (U19) VOUT0_DATA3 */ + AM62AX_IOPAD(0x0c8, PIN_OUTPUT, 0) /* (T19) VOUT0_DATA4 */ + AM62AX_IOPAD(0x0cc, PIN_OUTPUT, 0) /* (U18) VOUT0_DATA5 */ + AM62AX_IOPAD(0x0d0, PIN_OUTPUT, 0) /* (V22) VOUT0_DATA6 */ + AM62AX_IOPAD(0x0d4, PIN_OUTPUT, 0) /* (V21) VOUT0_DATA7 */ + AM62AX_IOPAD(0x0d8, PIN_OUTPUT, 0) /* (V19) VOUT0_DATA8 */ + AM62AX_IOPAD(0x0dc, PIN_OUTPUT, 0) /* (V18) VOUT0_DATA9 */ + AM62AX_IOPAD(0x0e0, PIN_OUTPUT, 0) /* (W22) VOUT0_DATA10 */ + AM62AX_IOPAD(0x0e4, PIN_OUTPUT, 0) /* (W21) VOUT0_DATA11 */ + AM62AX_IOPAD(0x0e8, PIN_OUTPUT, 0) /* (W20) VOUT0_DATA12 */ + AM62AX_IOPAD(0x0ec, PIN_OUTPUT, 0) /* (W19) VOUT0_DATA13 */ + AM62AX_IOPAD(0x0f0, PIN_OUTPUT, 0) /* (Y21) VOUT0_DATA14 */ + AM62AX_IOPAD(0x0f4, PIN_OUTPUT, 0) /* (Y22) VOUT0_DATA15 */ + AM62AX_IOPAD(0x05c, PIN_OUTPUT, 1) /* (P22) GPMC0_AD8.VOUT0_DATA16 */ + AM62AX_IOPAD(0x060, PIN_OUTPUT, 1) /* (R19) GPMC0_AD9.VOUT0_DATA17 */ + AM62AX_IOPAD(0x064, PIN_OUTPUT, 1) /* (R20) GPMC0_AD10.VOUT0_DATA18 */ + AM62AX_IOPAD(0x068, PIN_OUTPUT, 1) /* (R22) GPMC0_AD11.VOUT0_DATA19 */ + AM62AX_IOPAD(0x06c, PIN_OUTPUT, 1) /* (T22) GPMC0_AD12.VOUT0_DATA20 */ + AM62AX_IOPAD(0x070, PIN_OUTPUT, 1) /* (R21) GPMC0_AD13.VOUT0_DATA21 */ + AM62AX_IOPAD(0x074, PIN_OUTPUT, 1) /* (T20) GPMC0_AD14.VOUT0_DATA22 */ + AM62AX_IOPAD(0x078, PIN_OUTPUT, 1) /* (T21) GPMC0_AD15.VOUT0_DATA23 */ + >; + }; + main_uart0_pins_default: main-uart0-default-pins { pinctrl-single,pins = < AM62AX_IOPAD(0x1c8, PIN_INPUT, 0) /* (E14) UART0_RXD */ @@ -172,6 +340,22 @@ >; }; + main_mmc0_pins_default: main-mmc0-default-pins { + pinctrl-single,pins = < + AM62AX_IOPAD(0x220, PIN_INPUT, 0) /* (Y3) MMC0_CMD */ + AM62AX_IOPAD(0x218, PIN_INPUT, 0) /* (AB1) MMC0_CLKLB */ + AM62AX_IOPAD(0x21c, PIN_INPUT, 0) /* (AB1) MMC0_CLK */ + AM62AX_IOPAD(0x214, PIN_INPUT, 0) /* (AA2) MMC0_DAT0 */ + AM62AX_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (AA1) MMC0_DAT1 */ + AM62AX_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (AA3) MMC0_DAT2 */ + AM62AX_IOPAD(0x208, PIN_INPUT_PULLUP, 0) /* (Y4) MMC0_DAT3 */ + AM62AX_IOPAD(0x204, PIN_INPUT_PULLUP, 0) /* (AB2) MMC0_DAT4 */ + AM62AX_IOPAD(0x200, PIN_INPUT_PULLUP, 0) /* (AC1) MMC0_DAT5 */ + AM62AX_IOPAD(0x1fc, PIN_INPUT_PULLUP, 0) /* (AD2) MMC0_DAT6 */ + AM62AX_IOPAD(0x1f8, PIN_INPUT_PULLUP, 0) /* (AC2) MMC0_DAT7 */ + >; + }; + main_mmc1_pins_default: main-mmc1-default-pins { pinctrl-single,pins = < AM62AX_IOPAD(0x23c, PIN_INPUT, 0) /* (A21) MMC1_CMD */ @@ -219,6 +403,57 @@ AM62AX_IOPAD(0x12c, PIN_INPUT, 0) /* (W16) RGMII1_TX_CTL */ >; }; + + main_mcasp1_pins_default: main-mcasp1-default-pins { + pinctrl-single,pins = < + AM62AX_IOPAD(0x090, PIN_INPUT, 2) /* (L19) GPMC0_BE0n_CLE.MCASP1_ACLKX */ + AM62AX_IOPAD(0x098, PIN_INPUT, 2) /* (R18) GPMC0_WAIT0.MCASP1_AFSX */ + AM62AX_IOPAD(0x08c, PIN_OUTPUT, 2) /* (K19) GPMC0_WEn.MCASP1_AXR0 */ + AM62AX_IOPAD(0x084, PIN_INPUT, 2) /* (L18) GPMC0_ADVn_ALE.MCASP1_AXR2 */ + >; + }; + + main_gpio1_ioexp_intr_pins_default: main-gpio1-ioexp-intr-default-pins { + pinctrl-single,pins = < + AM62AX_IOPAD(0x01d4, PIN_INPUT, 7) /* (C15) UART0_RTSn.GPIO1_23 */ + >; + }; + + vddshv_sdio_pins_default: vddshv-sdio-default-pins { + pinctrl-single,pins = < + AM62AX_IOPAD(0x07c, PIN_OUTPUT, 7) /* (M19) GPMC0_CLK.GPIO0_31 */ + >; + }; + + ospi0_pins_default: ospi0-default-pins { + pinctrl-single,pins = < + AM62AX_IOPAD(0x000, PIN_OUTPUT, 0) /* (H24) OSPI0_CLK */ + AM62AX_IOPAD(0x02c, PIN_OUTPUT, 0) /* (F23) OSPI0_CSn0 */ + AM62AX_IOPAD(0x00c, PIN_INPUT, 0) /* (E25) OSPI0_D0 */ + AM62AX_IOPAD(0x010, PIN_INPUT, 0) /* (G24) OSPI0_D1 */ + AM62AX_IOPAD(0x014, PIN_INPUT, 0) /* (F25) OSPI0_D2 */ + AM62AX_IOPAD(0x018, PIN_INPUT, 0) /* (F24) OSPI0_D3 */ + AM62AX_IOPAD(0x01c, PIN_INPUT, 0) /* (J23) OSPI0_D4 */ + AM62AX_IOPAD(0x020, PIN_INPUT, 0) /* (J25) OSPI0_D5 */ + AM62AX_IOPAD(0x024, PIN_INPUT, 0) /* (H25) OSPI0_D6 */ + AM62AX_IOPAD(0x028, PIN_INPUT, 0) /* (J22) OSPI0_D7 */ + AM62AX_IOPAD(0x008, PIN_INPUT, 0) /* (J24) OSPI0_DQS */ + >; + }; +}; + +&mcu_pmx0 { + status = "okay"; + + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + AM62AX_MCU_IOPAD(0x000, PIN_INPUT, 7) /* (E11) MCU_GPIO0_0 */ + >; + }; +}; + +&mcu_gpio0 { + status = "okay"; }; &main_i2c0 { @@ -244,6 +479,87 @@ }; }; }; + + tps659312: pmic@48 { + compatible = "ti,tps6593-q1"; + reg = <0x48>; + ti,primary-pmic; + system-power-controller; + + gpio-controller; + #gpio-cells = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&mcu_gpio0>; + interrupts = <0 IRQ_TYPE_EDGE_FALLING>; + + buck123-supply = <&vcc_3v3_sys>; + buck4-supply = <&vcc_3v3_sys>; + buck5-supply = <&vcc_3v3_sys>; + ldo1-supply = <&vcc_3v3_sys>; + ldo2-supply = <&vcc_3v3_sys>; + ldo3-supply = <&buck5>; + ldo4-supply = <&vcc_3v3_sys>; + + regulators { + buck123: buck123 { + regulator-name = "vcc_core"; + regulator-min-microvolt = <715000>; + regulator-max-microvolt = <895000>; + regulator-boot-on; + regulator-always-on; + }; + + buck4: buck4 { + regulator-name = "vcc_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + buck5: buck5 { + regulator-name = "vcc_1v8_sys"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo1: ldo1 { + regulator-name = "vddshv5_sdio"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo2: ldo2 { + regulator-name = "vpp_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo3: ldo3 { + regulator-name = "vcc_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo4: ldo4 { + regulator-name = "vdda_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; }; &main_i2c1 { @@ -257,6 +573,12 @@ reg = <0x22>; gpio-controller; #gpio-cells = <2>; + interrupt-parent = <&main_gpio1>; + interrupts = <23 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&main_gpio1_ioexp_intr_pins_default>; gpio-line-names = "GPIO_CPSW2_RST", "GPIO_CPSW1_RST", "BT_EN_SOC", "MMC1_SD_EN", @@ -271,15 +593,94 @@ "MCASP1_FET_SEL", "UART1_FET_SEL", "PD_I2C_IRQ", "IO_EXP_TEST_LED"; }; + + tlv320aic3106: audio-codec@1b { + #sound-dai-cells = <0>; + compatible = "ti,tlv320aic3106"; + reg = <0x1b>; + ai3x-micbias-vg = <1>; /* 2.0V */ + + /* Regulators */ + AVDD-supply = <&vcc_3v3_sys>; + IOVDD-supply = <&vcc_3v3_sys>; + DRVDD-supply = <&vcc_3v3_sys>; + DVDD-supply = <&buck5>; + }; + + exp2: gpio@23 { + compatible = "ti,tca6424"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = "", "", + "", "", + "", "", + "", "", + "WL_LT_EN", "CSI_RSTz", + "", "", + "", "", + "", "", + "SPI0_FET_SEL", "SPI0_FET_OE", + "RGMII2_BRD_CONN_DET", "CSI_SEL2", + "CSI_EN", "AUTO_100M_1000M_CONFIG", + "CSI_VLDO_SEL", "SoC_WLAN_SDIO_RST"; + }; + + sii9022: bridge-hdmi@3b { + compatible = "sil,sii9022"; + reg = <0x3b>; + interrupt-parent = <&exp1>; + interrupts = <16 IRQ_TYPE_EDGE_FALLING>; + #sound-dai-cells = <0>; + sil,i2s-data-lanes = < 0 >; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sii9022_in: endpoint { + remote-endpoint = <&dpi1_out>; + }; + }; + + port@1 { + reg = <1>; + + sii9022_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; +}; + +&main_i2c2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c2_pins_default>; + clock-frequency = <400000>; +}; + +&sdhci0 { + /* eMMC */ + status = "okay"; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&main_mmc0_pins_default>; + disable-wp; }; &sdhci1 { /* SD/MMC */ status = "okay"; vmmc-supply = <&vdd_mmc1>; + vqmmc-supply = <&vddshv_sdio>; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; - ti,driver-strength-ohm = <50>; disable-wp; }; @@ -299,6 +700,9 @@ status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_uart0_pins_default>; + interrupts-extended = <&gic500 GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>, + <&main_pmx0 0x1c8>; /* (D14) UART0_RXD PADCONFIG114 */ + interrupt-names = "irq", "wakeup"; }; /* Main UART1 is used for TIFS firmware logs */ @@ -337,6 +741,11 @@ status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_rgmii1_pins_default>; + + cpts@3d000 { + /* MAP HW3_TS_PUSH to GENF1 */ + ti,pps = <2 1>; + }; }; &cpsw_port1 { @@ -361,3 +770,158 @@ ti,min-output-impedance; }; }; + +&mcasp1 { + status = "okay"; + #sound-dai-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&main_mcasp1_pins_default>; + + op-mode = <0>; /* MCASP_IIS_MODE */ + tdm-slots = <2>; + + serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ + 1 0 2 0 + 0 0 0 0 + 0 0 0 0 + 0 0 0 0 + >; + tx-num-evt = <0>; + rx-num-evt = <0>; +}; + +&dss { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_dss0_pins_default>; +}; + +&dss_ports { + /* VP2: DPI Output */ + hdmi0_dss: port@1 { + reg = <1>; + + dpi1_out: endpoint { + remote-endpoint = <&sii9022_in>; + }; + }; +}; + +&mailbox0_cluster0 { + mbox_r5_0: mbox-r5-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + +&mailbox0_cluster1 { + mbox_c7x_0: mbox-c7x-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + +&mailbox0_cluster2 { + mbox_mcu_r5_0: mbox-mcu-r5-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + +&c7x_0 { + mboxes = <&mailbox0_cluster1>, <&mbox_c7x_0>; + memory-region = <&c7x_0_dma_memory_region>, + <&c7x_0_memory_region>; +}; + +&wkup_r5fss0_core0 { + mboxes = <&mailbox0_cluster0>, <&mbox_r5_0>; + memory-region = <&wkup_r5fss0_core0_dma_memory_region>, + <&wkup_r5fss0_core0_memory_region>; +}; + +&mcu_r5fss0_core0 { + mboxes = <&mailbox0_cluster2>, <&mbox_mcu_r5_0>; + memory-region = <&mcu_r5fss0_core0_dma_memory_region>, + <&mcu_r5fss0_core0_memory_region>; +}; + +#define K3_TS_OFFSET(pa, val) (0x4+(pa)*4) (0x10000 | val) + +×ync_router { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&cpsw_cpts>; + + /* Use Time Sync Router to map GENF1 input to HW3_TS_PUSH output */ + cpsw_cpts: cpsw-cpts { + pinctrl-single,pins = < + /* pps [cpsw cpts genf1] in17 -> out12 [cpsw cpts hw3_push] */ + K3_TS_OFFSET(12, 17) + >; + }; +}; + +&fss { + status = "okay"; +}; + +&ospi0 { + pinctrl-names = "default"; + pinctrl-0 = <&ospi0_pins_default>; + + flash@0{ + compatible = "spi-nand"; + reg = <0x0>; + spi-tx-bus-width = <8>; + spi-rx-bus-width = <8>; + spi-max-frequency = <50000000>; + cdns,tshsl-ns = <60>; + cdns,tsd2d-ns = <60>; + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "ospi_nand.tiboot3"; + reg = <0x0 0x80000>; + }; + + partition@80000 { + label = "ospi_nand.tispl"; + reg = <0x80000 0x200000>; + }; + + partition@280000 { + label = "ospi_nand.u-boot"; + reg = <0x280000 0x400000>; + }; + + partition@680000 { + label = "ospi_nand.env"; + reg = <0x680000 0x40000>; + }; + + partition@6c0000 { + label = "ospi_nand.env.backup"; + reg = <0x6c0000 0x40000>; + }; + + partition@2000000 { + label = "ospi_nand.rootfs"; + reg = <0x2000000 0x5fc0000>; + }; + + partition@7fc0000 { + label = "ospi_nand.phypattern"; + reg = <0x7fc0000 0x40000>; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62a7-sk-e3-max-opp.dtso b/arch/arm64/boot/dts/ti/k3-am62a7-sk-e3-max-opp.dtso --- a/arch/arm64/boot/dts/ti/k3-am62a7-sk-e3-max-opp.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk-e3-max-opp.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay to run AM62A7-SK Rev E3 board at maximum performance + * Requires VDD_CORE to be at 0.85V + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +&{/} { + opp-table { + /* + * Add 1.4GHz and disable lower OPPs for max A53 performance + * Only for AM62A7-SK Rev E3 board + * Requires VDD_CORE to be at 0.85V + */ + opp-200000000 { + status = "disabled"; + }; + + opp-400000000 { + status = "disabled"; + }; + + opp-600000000 { + status = "disabled"; + }; + + opp-800000000 { + status = "disabled"; + }; + + opp-1000000000 { + status = "disabled"; + }; + + opp-1250000000 { + status = "disabled"; + }; + + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; + opp-supported-hw = <0x01 0x0004>; + clock-latency-ns = <6000000>; + }; + }; +}; + +&c7x_0 { + /* + * Override C7x frequency to 1 GHz for max performance + * Only for AM62A7-SK Rev E3 board + * Requires VDD_CORE to be at 0.85V + */ + clocks = <&k3_clks 208 0>; + assigned-clocks = <&k3_clks 208 0>; + assigned-clock-rates = <1000000000>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62a7-sk-ethernet-dc01.dtso b/arch/arm64/boot/dts/ti/k3-am62a7-sk-ethernet-dc01.dtso --- a/arch/arm64/boot/dts/ti/k3-am62a7-sk-ethernet-dc01.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk-ethernet-dc01.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT Overlay for second CPSW3G port in RGMII mode using SK-ETHERNET-DC01 + * Add-On Daughtercard with AM62A7-SK. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include "k3-pinctrl.h" + +&{/} { + aliases { + ethernet1 = "/bus@f0000/ethernet@8000000/ethernet-ports/port@2"; + }; +}; + +&cpsw3g { + pinctrl-0 = <&main_rgmii1_pins_default>, + <&main_rgmii2_pins_default>; +}; + +&cpsw_port2 { + status = "okay"; + phy-mode = "rgmii-rxid"; + phy-handle = <&cpsw3g_phy1>; +}; + +&cpsw3g_mdio { + #address-cells = <1>; + #size-cells = <0>; + + cpsw3g_phy1: ethernet-phy@1 { + reg = <1>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + ti,min-output-impedance; + }; +}; + +&main_pmx0 { + main_rgmii2_pins_default: main-rgmii2-default-pins { + pinctrl-single,pins = < + AM62AX_IOPAD(0x0184, PIN_INPUT, 0) /* (AA21) RGMII2_RD0 */ + AM62AX_IOPAD(0x0188, PIN_INPUT, 0) /* (Y20) RGMII2_RD1 */ + AM62AX_IOPAD(0x018c, PIN_INPUT, 0) /* (AB21) RGMII2_RD2 */ + AM62AX_IOPAD(0x0190, PIN_INPUT, 0) /* (AB20) RGMII2_RD3 */ + AM62AX_IOPAD(0x0180, PIN_INPUT, 0) /* (AA20) RGMII2_RXC */ + AM62AX_IOPAD(0x017c, PIN_INPUT, 0) /* (W18) RGMII2_RX_CTL */ + AM62AX_IOPAD(0x016c, PIN_INPUT, 0) /* (AA19) RGMII2_TD0 */ + AM62AX_IOPAD(0x0170, PIN_INPUT, 0) /* (Y18) RGMII2_TD1 */ + AM62AX_IOPAD(0x0174, PIN_INPUT, 0) /* (AA18) RGMII2_TD2 */ + AM62AX_IOPAD(0x0178, PIN_INPUT, 0) /* (W17) RGMII2_TD3 */ + AM62AX_IOPAD(0x0168, PIN_INPUT, 0) /* (AB19) RGMII2_TXC */ + AM62AX_IOPAD(0x0164, PIN_INPUT, 0) /* (Y19) RGMII2_TX_CTL */ + >; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62a7-sk-fusion.dtso b/arch/arm64/boot/dts/ti/k3-am62a7-sk-fusion.dtso --- a/arch/arm64/boot/dts/ti/k3-am62a7-sk-fusion.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk-fusion.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Fusion (FPD-Link III) board on SK-AM62A + * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&exp2 { + p19-hog { + /* P19 - CSI_SEL2 */ + gpio-hog; + gpios = <19 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "CSI_SEL2"; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + deser@3d { + compatible = "ti,ds90ub960-q1"; + reg = <0x3d>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62a7-sk-m2-cc3301.dtso b/arch/arm64/boot/dts/ti/k3-am62a7-sk-m2-cc3301.dtso --- a/arch/arm64/boot/dts/ti/k3-am62a7-sk-m2-cc3301.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk-m2-cc3301.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * DT Overlay for M.2-CC3301 board to connect to the M.2 connector on AM625-SK. + * + * Product page for board: https://www.ti.com/tool/M2-CC3301 + * CC3301 Datasheet: https://www.ti.com/lit/ds/symlink/cc3301.pdf + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include "k3-pinctrl.h" + +&{/} { + wlan_lten: regulator-30 { + compatible = "regulator-fixed"; + regulator-name = "wlan_lten"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vdd_mmc1>; + gpios = <&exp1 11 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + wlan_en: regulator-31 { + compatible = "regulator-fixed"; + regulator-name = "wlan_en"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&wlan_lten>; + enable-active-high; + gpios = <&main_gpio0 71 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&wlan_en_pins_default>; + }; +}; + +&main_pmx0 { + wlan_en_pins_default: wlan-en-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x124, PIN_OUTPUT, 7) /* (A23) MMC2_SDCD.GPIO0_71 */ + >; + }; + + main_mmc2_pins_default: main-mmc2-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x120, PIN_INPUT, 0) /* (C24) MMC2_CMD */ + AM62X_IOPAD(0x118, PIN_INPUT, 0) /* (D25) MMC2_CLK */ + AM62X_IOPAD(0x114, PIN_INPUT, 0) /* (B24) MMC2_DAT0 */ + AM62X_IOPAD(0x110, PIN_INPUT, 0) /* (C25) MMC2_DAT1 */ + AM62X_IOPAD(0x10c, PIN_INPUT, 0) /* (E23) MMC2_DAT2 */ + AM62X_IOPAD(0x108, PIN_INPUT, 0) /* (D24) MMC2_DAT3 */ + AM62X_IOPAD(0x11c, PIN_INPUT, 0) /* (#N/A) MMC2_CLKB */ + >; + }; + + main_wlirq_pins_default: main-wlirq-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x128, PIN_INPUT, 7) /* (B23) MMC2_SDWP.GPIO0_72 */ + >; + }; +}; + +&sdhci2 { + status = "okay"; + bootph-all; + vmmc-supply = <&wlan_en>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mmc2_pins_default>; + bus-width = <4>; + non-removable; + ti,fails-without-test-cd; + cap-power-off-card; + keep-power-in-suspend; + ti,driver-strength-ohm = <50>; + + #address-cells = <1>; + #size-cells = <0>; + cc33xx: cc33xx@2 { + compatible = "ti,cc3301"; + reg = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&main_wlirq_pins_default>; + interrupt-parent = <&main_gpio0>; + interrupts = <72 IRQ_TYPE_EDGE_FALLING>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62a7-sk-rpi-hdr-ehrpwm.dtso b/arch/arm64/boot/dts/ti/k3-am62a7-sk-rpi-hdr-ehrpwm.dtso --- a/arch/arm64/boot/dts/ti/k3-am62a7-sk-rpi-hdr-ehrpwm.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk-rpi-hdr-ehrpwm.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for enabling RPi header with GPIOs and ePWMs on AM62A-SK + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&main_pmx0 { + rpi_header_gpio0_pins_default: rpi-header-gpio0-pins-default { + pinctrl-single,pins = < + AM62AX_IOPAD(0x0038, PIN_INPUT, 7) /* (G20) OSPI0_CSn3.GPIO0_14 */ + AM62AX_IOPAD(0x0088, PIN_INPUT, 7) /* (L17) GPMC0_OEn_REn.GPIO0_33 */ + AM62AX_IOPAD(0x0094, PIN_INPUT, 7) /* (M18) GPMC0_BE1n.GPIO0_36 */ + AM62AX_IOPAD(0x009c, PIN_INPUT, 7) /* (R17) GPMC0_WAIT1.GPIO0_38 */ + AM62AX_IOPAD(0x00a0, PIN_INPUT, 7) /* (K17) GPMC0_WPn.GPIO0_39 */ + AM62AX_IOPAD(0x00a4, PIN_INPUT, 7) /* (K18) GPMC0_DIR.GPIO0_40 */ + AM62AX_IOPAD(0x00a8, PIN_INPUT, 7) /* (M19) GPMC0_CSn0.GPIO0_41 */ + AM62AX_IOPAD(0x00ac, PIN_INPUT, 7) /* (M21) GPMC0_CSn1.GPIO0_42 */ + >; + }; + + rpi_header_gpio1_pins_default: rpi-header-gpio1-pins-default { + pinctrl-single,pins = < + AM62AX_IOPAD(0x0194, PIN_INPUT, 7) /* (C19) MCASP0_AXR3.GPIO1_7 */ + AM62AX_IOPAD(0x0198, PIN_INPUT, 7) /* (B19) MCASP0_AXR2.GPIO1_8 */ + AM62AX_IOPAD(0x01a4, PIN_INPUT, 7) /* (A19) MCASP0_ACLKX.GPIO1_11 */ + AM62AX_IOPAD(0x01b4, PIN_INPUT, 7) /* (D16) SPI0_CS0.GPIO1_15 */ + AM62AX_IOPAD(0x01b8, PIN_INPUT, 7) /* (C16) SPI0_CS1.GPIO1_16 */ + AM62AX_IOPAD(0x01bc, PIN_INPUT, 7) /* (A17) SPI0_CLK.GPIO1_17 */ + AM62AX_IOPAD(0x01c0, PIN_INPUT, 7) /* (B15) SPI0_D0.GPIO1_18 */ + AM62AX_IOPAD(0x01c4, PIN_INPUT, 7) /* (E15) SPI0_D1.GPIO1_19 */ + AM62AX_IOPAD(0x01d0, PIN_INPUT, 7) /* (F14) UART0_CTSn.GPIO1_22 */ + AM62AX_IOPAD(0x01d8, PIN_INPUT, 7) /* (B17) MCAN0_TX.GPIO1_24 */ + AM62AX_IOPAD(0x01dc, PIN_INPUT, 7) /* (C18) MCAN0_RX.GPIO1_25 */ + >; + }; + + rpi_header_ehrpwm0_pins_default: rpi-header-ehrpwm0-pins-default { + pinctrl-single,pins = < + AM62AX_IOPAD(0x01ac, PIN_OUTPUT, 6) /* (B21) MCASP0_AFSR.EHRPWM0_A */ + AM62AX_IOPAD(0x01b0, PIN_OUTPUT, 6) /* (A21) MCASP0_ACLKR.EHRPWM0_B */ + >; + }; + + rpi_header_ehrpwm1_pins_default: rpi-header-ehrpwm1-pins-default { + pinctrl-single,pins = < + AM62AX_IOPAD(0x019c, PIN_OUTPUT, 6) /* (B18) MCASP0_AXR1.EHRPWM1_A */ + AM62AX_IOPAD(0x01a0, PIN_OUTPUT, 6) /* (B20) MCASP0_AXR0.EHRPWM1_B */ + >; + }; +}; + +&main_i2c1 { + gpio@22 { + p05-hog { + /* P05 - EXP_PS_3V3_EN */ + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "EXP_PS_3V3_EN"; + }; + + p06-hog { + /* P06 - EXP_PS_5V0_EN */ + gpio-hog; + gpios = <6 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "EXP_PS_5V0_EN"; + }; + + p25-hog { + /* P25 - UART1_FET_SEL */ + gpio-hog; + gpios = <21 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "UART1_FET_SEL"; + }; + }; +}; + +&epwm0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm0_pins_default>; +}; + +&epwm1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm1_pins_default>; +}; + + +&main_gpio0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_gpio0_pins_default>; +}; + +&main_gpio1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_gpio1_pins_default>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62a.dtsi b/arch/arm64/boot/dts/ti/k3-am62a.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62a.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62a.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -61,10 +61,13 @@ <0x00 0x08000000 0x00 0x08000000 0x00 0x00200000>, /* Main CPSW */ <0x00 0x0e000000 0x00 0x0e000000 0x00 0x01d20000>, /* Second peripheral window */ <0x00 0x0fd00000 0x00 0x0fd00000 0x00 0x00020000>, /* GPU */ + <0x00 0x0fd20000 0x00 0x0fd20000 0x00 0x00000100>, /* JPEGENC0_CORE */ + <0x00 0x0fd20200 0x00 0x0fd20200 0x00 0x00000200>, /* JPEGENC0_CORE_MMU */ <0x00 0x20000000 0x00 0x20000000 0x00 0x0a008000>, /* Third peripheral window */ <0x00 0x30040000 0x00 0x30040000 0x00 0x00080000>, /* PRUSS-M */ <0x00 0x30101000 0x00 0x30101000 0x00 0x00010100>, /* CSI window */ <0x00 0x30200000 0x00 0x30200000 0x00 0x00010000>, /* DSS */ + <0x00 0x30300000 0x00 0x30300000 0x00 0x00001000>, /* MCRC64 */ <0x00 0x30210000 0x00 0x30210000 0x00 0x00010000>, /* VPU */ <0x00 0x31000000 0x00 0x31000000 0x00 0x00050000>, /* USB0 DWC3 Core window */ <0x00 0x31100000 0x00 0x31100000 0x00 0x00050000>, /* USB1 DWC3 Core window */ @@ -123,3 +126,7 @@ #include "k3-am62a-main.dtsi" #include "k3-am62a-mcu.dtsi" #include "k3-am62a-wakeup.dtsi" + +&dmsc { + ti,partial-io-wakeup-sources = <&mcu_mcan0>, <&mcu_mcan1>, <&mcu_uart0>, <&wkup_uart0>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -42,9 +42,8 @@ }; }; - main_conf: syscon@100000 { - compatible = "ti,j721e-system-controller", "syscon", "simple-mfd"; - reg = <0x00 0x00100000 0x00 0x20000>; + main_conf: bus@100000 { + compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00 0x00 0x00100000 0x20000>; @@ -101,8 +100,13 @@ <0x00 0x4c000000 0x00 0x20000>, <0x00 0x4a820000 0x00 0x20000>, <0x00 0x4aa40000 0x00 0x20000>, - <0x00 0x4bc00000 0x00 0x100000>; - reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4bc00000 0x00 0x100000>, + <0x00 0x48600000 0x00 0x8000>, + <0x00 0x484a4000 0x00 0x2000>, + <0x00 0x484c2000 0x00 0x2000>, + <0x00 0x48420000 0x00 0x2000>; + reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "bchan"; msi-parent = <&inta_main_dmss>; #dma-cells = <3>; ti,sci = <&dmsc>; @@ -117,8 +121,13 @@ reg = <0x00 0x485c0000 0x00 0x100>, <0x00 0x4a800000 0x00 0x20000>, <0x00 0x4aa00000 0x00 0x40000>, - <0x00 0x4b800000 0x00 0x400000>; - reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4b800000 0x00 0x400000>, + <0x00 0x485e0000 0x00 0x10000>, + <0x00 0x484a0000 0x00 0x2000>, + <0x00 0x484c0000 0x00 0x2000>, + <0x00 0x48430000 0x00 0x1000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "rflow"; msi-parent = <&inta_main_dmss>; #dma-cells = <2>; ti,sci = <&dmsc>; @@ -144,6 +153,44 @@ }; }; + dmss_csi: bus@4e000000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + dma-ranges; + ranges = <0x00 0x4e000000 0x00 0x4e000000 0x00 0x300000>; + + ti,sci-dev-id = <198>; + + inta_main_dmss_csi: interrupt-controller@4e0a0000 { + compatible = "ti,sci-inta"; + reg = <0x00 0x4e0a0000 0x00 0x8000>; + #interrupt-cells = <0>; + interrupt-controller; + interrupt-parent = <&gic500>; + msi-controller; + ti,sci = <&dmsc>; + ti,sci-dev-id = <200>; + ti,interrupt-ranges = <0 237 8>; + ti,unmapped-event-sources = <&main_bcdma_csi>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + }; + + main_bcdma_csi: dma-controller@4e230000 { + compatible = "ti,am62a-dmss-bcdma-csirx"; + reg = <0x00 0x4e230000 0x00 0x100>, + <0x00 0x4e180000 0x00 0x8000>, + <0x00 0x4e100000 0x00 0x10000>; + reg-names = "gcfg", "rchanrt", "ringrt"; + msi-parent = <&inta_main_dmss_csi>; + #dma-cells = <3>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <199>; + ti,sci-rm-range-rchan = <0x21>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + }; + }; + dmsc: system-controller@44043000 { compatible = "ti,k2g-sci"; reg = <0x00 0x44043000 0x00 0xfe0>; @@ -169,6 +216,25 @@ }; }; + crypto: crypto@40900000 { + compatible = "ti,am62-sa3ul"; + reg = <0x00 0x40900000 0x00 0x1200>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x40900000 0x00 0x40900000 0x00 0x30000>; + + dmas = <&main_pktdma 0xf501 0>, <&main_pktdma 0x7506 0>, + <&main_pktdma 0x7507 0>; + dma-names = "tx", "rx1", "rx2"; + }; + + crc: crc@30300000 { + compatible = "ti,am62-mcrc64"; + reg = <0x00 0x30300000 0x00 0x1000>; + clocks = <&k3_clks 116 0>; + power-domains = <&k3_pds 116 TI_SCI_PD_EXCLUSIVE>; + }; + secure_proxy_sa3: mailbox@43600000 { compatible = "ti,am654-secure-proxy"; #mbox-cells = <1>; @@ -185,11 +251,31 @@ }; main_pmx0: pinctrl@f4000 { - compatible = "pinctrl-single"; - reg = <0x00 0xf4000 0x00 0x2ac>; + compatible = "ti,am654-padconf", "pinctrl-single"; + reg = <0x00 0xf4000 0x00 0x25c>; #pinctrl-cells = <1>; pinctrl-single,register-width = <32>; pinctrl-single,function-mask = <0xffffffff>; + /* + * pinctrl IP DOES NOT give any functional IRQs when a + * system is in active state. This IRQ is only a dummy IRQ + * that is being used to trick Linux into thinking that + * GIC can potentially recieve an interrupt from this IP. + * This helps us setup the IO daisychain wakeups for deep + * sleep via chained wake IRQs. + * Please feel free to assign a different number here as + * long as it is unused if 99 conflicts with another use case. + */ + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + }; + + main_esm: esm@420000 { + compatible = "ti,j721e-esm"; + reg = <0x0 0x420000 0x0 0x1000>; + ti,esm-pins = <160>, <161>, <162>, <163>, <177>, <178>; + bootph-pre-ram; }; main_timer0: timer@2400000 { @@ -488,6 +574,24 @@ status = "disabled"; }; + sdhci0: mmc@fa10000 { + compatible = "ti,am62-sdhci"; + reg = <0x00 0xfa10000 0x00 0x260>, <0x00 0xfa18000 0x00 0x134>; + interrupts = ; + power-domains = <&k3_pds 57 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 57 5>, <&k3_clks 57 6>; + clock-names = "clk_ahb", "clk_xin"; + assigned-clocks = <&k3_clks 57 6>; + assigned-clock-parents = <&k3_clks 57 8>; + bus-width = <8>; + mmc-hs200-1_8v; + ti,clkbuf-sel = <0x7>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-hs200 = <0x6>; + status = "disabled"; + }; + sdhci1: mmc@fa00000 { compatible = "ti,am62-sdhci"; reg = <0x00 0xfa00000 0x00 0x260>, <0x00 0xfa08000 0x00 0x134>; @@ -495,7 +599,8 @@ power-domains = <&k3_pds 58 TI_SCI_PD_EXCLUSIVE>; clocks = <&k3_clks 58 5>, <&k3_clks 58 6>; clock-names = "clk_ahb", "clk_xin"; - ti,trm-icp = <0x2>; + bus-width = <4>; + ti,clkbuf-sel = <0x7>; ti,otap-del-sel-legacy = <0x0>; ti,otap-del-sel-sd-hs = <0x0>; ti,otap-del-sel-sdr12 = <0xf>; @@ -507,18 +612,39 @@ ti,itap-del-sel-sd-hs = <0x0>; ti,itap-del-sel-sdr12 = <0x0>; ti,itap-del-sel-sdr25 = <0x0>; - ti,clkbuf-sel = <0x7>; + status = "disabled"; + }; + + sdhci2: mmc@fa20000 { + compatible = "ti,am62-sdhci"; + reg = <0x00 0xfa20000 0x00 0x260>, <0x00 0xfa28000 0x00 0x134>; + interrupts = ; + power-domains = <&k3_pds 184 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 184 5>, <&k3_clks 184 6>; + clock-names = "clk_ahb", "clk_xin"; bus-width = <4>; - no-1-8-v; + ti,clkbuf-sel = <0x7>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-sd-hs = <0x0>; + ti,otap-del-sel-sdr12 = <0xf>; + ti,otap-del-sel-sdr25 = <0xf>; + ti,otap-del-sel-sdr50 = <0xc>; + ti,otap-del-sel-sdr104 = <0x6>; + ti,otap-del-sel-ddr50 = <0x9>; + ti,itap-del-sel-legacy = <0x0>; + ti,itap-del-sel-sd-hs = <0x0>; + ti,itap-del-sel-sdr12 = <0x0>; + ti,itap-del-sel-sdr25 = <0x0>; status = "disabled"; }; usbss0: dwc3-usb@f900000 { compatible = "ti,am62-usb"; - reg = <0x00 0x0f900000 0x00 0x800>; + reg = <0x00 0x0f900000 0x00 0x800>, + <0x00 0x0f908000 0x00 0x400>; clocks = <&k3_clks 161 3>; clock-names = "ref"; - ti,syscon-phy-pll-refclk = <&wkup_conf 0x4008>; + ti,syscon-phy-pll-refclk = <&usb0_phy_ctrl 0x0>; #address-cells = <2>; #size-cells = <2>; power-domains = <&k3_pds 178 TI_SCI_PD_EXCLUSIVE>; @@ -533,15 +659,18 @@ interrupt-names = "host", "peripheral"; maximum-speed = "high-speed"; dr_mode = "otg"; + snps,usb2-gadget-lpm-disable; + snps,usb2-lpm-disable; }; }; usbss1: dwc3-usb@f910000 { compatible = "ti,am62-usb"; - reg = <0x00 0x0f910000 0x00 0x800>; + reg = <0x00 0x0f910000 0x00 0x800>, + <0x00 0x0f918000 0x00 0x400>; clocks = <&k3_clks 162 3>; clock-names = "ref"; - ti,syscon-phy-pll-refclk = <&wkup_conf 0x4018>; + ti,syscon-phy-pll-refclk = <&usb1_phy_ctrl 0x0>; #address-cells = <2>; #size-cells = <2>; power-domains = <&k3_pds 179 TI_SCI_PD_EXCLUSIVE>; @@ -556,6 +685,8 @@ interrupt-names = "host", "peripheral"; maximum-speed = "high-speed"; dr_mode = "otg"; + snps,usb2-gadget-lpm-disable; + snps,usb2-lpm-disable; }; }; @@ -578,7 +709,7 @@ clocks = <&k3_clks 75 7>; assigned-clocks = <&k3_clks 75 7>; assigned-clock-parents = <&k3_clks 75 8>; - assigned-clock-rates = <166666666>; + assigned-clock-rates = <200000000>; power-domains = <&k3_pds 75 TI_SCI_PD_EXCLUSIVE>; #address-cells = <1>; #size-cells = <0>; @@ -655,6 +786,15 @@ }; }; + timesync_router: pinctrl@a40000 { + compatible = "pinctrl-single"; + reg = <0x0 0xa40000 0x0 0x800>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x000107ff>; + status = "disabled"; + }; + hwspinlock: spinlock@2a000000 { compatible = "ti,am64-hwspinlock"; reg = <0x00 0x2a000000 0x00 0x1000>; @@ -816,4 +956,210 @@ clock-names = "fck"; status = "disabled"; }; + + eqep0: counter@23200000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23200000 0x00 0x100>; + power-domains = <&k3_pds 59 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 59 0>; + interrupts = ; + status = "disabled"; + }; + + eqep1: counter@23210000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23210000 0x00 0x100>; + power-domains = <&k3_pds 60 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 60 0>; + interrupts = ; + status = "disabled"; + }; + + eqep2: counter@23220000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23220000 0x00 0x100>; + power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 62 0>; + interrupts = ; + status = "disabled"; + }; + + mcasp0: audio-controller@2b00000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x00 0x02b00000 0x00 0x2000>, + <0x00 0x02b08000 0x00 0x400>; + reg-names = "mpu", "dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + + dmas = <&main_bcdma 0 0xc500 0>, <&main_bcdma 0 0x4500 0>; + dma-names = "tx", "rx"; + + clocks = <&k3_clks 190 0>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 190 0>; + assigned-clock-parents = <&k3_clks 190 2>; + power-domains = <&k3_pds 190 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcasp1: audio-controller@2b10000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x00 0x02b10000 0x00 0x2000>, + <0x00 0x02b18000 0x00 0x400>; + reg-names = "mpu", "dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + + dmas = <&main_bcdma 0 0xc501 0>, <&main_bcdma 0 0x4501 0>; + dma-names = "tx", "rx"; + + clocks = <&k3_clks 191 0>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 191 0>; + assigned-clock-parents = <&k3_clks 191 2>; + power-domains = <&k3_pds 191 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcasp2: audio-controller@2b20000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x00 0x02b20000 0x00 0x2000>, + <0x00 0x02b28000 0x00 0x400>; + reg-names = "mpu", "dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + + dmas = <&main_bcdma 0 0xc502 0>, <&main_bcdma 0 0x4502 0>; + dma-names = "tx", "rx"; + + clocks = <&k3_clks 192 0>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 192 0>; + assigned-clock-parents = <&k3_clks 192 2>; + power-domains = <&k3_pds 192 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + ti_csi2rx0: ticsi2rx@30102000 { + compatible = "ti,j721e-csi2rx-shim"; + dmas = <&main_bcdma_csi 0 0x5000 0>, <&main_bcdma_csi 0 0x5001 0>, + <&main_bcdma_csi 0 0x5002 0>, <&main_bcdma_csi 0 0x5003 0>, + <&main_bcdma_csi 0 0x5004 0>, <&main_bcdma_csi 0 0x5005 0>; + dma-names = "rx0", "rx1", "rx2", "rx3", "rx4", "rx5"; + reg = <0x00 0x30102000 0x00 0x1000>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + cdns_csi2rx0: csi-bridge@30101000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x30101000 0x00 0x1000>; + clocks = <&k3_clks 182 0>, <&k3_clks 182 3>, <&k3_clks 182 0>, + <&k3_clks 182 0>, <&k3_clks 182 4>, <&k3_clks 182 4>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi0_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi0_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi0_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi0_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + dphy0: phy@30110000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x30110000 0x00 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 185 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + dss: dss@30200000 { + compatible = "ti,am62a7-dss"; + reg = <0x00 0x30200000 0x00 0x1000>, /* common */ + <0x00 0x30202000 0x00 0x1000>, /* vidl1 */ + <0x00 0x30206000 0x00 0x1000>, /* vid */ + <0x00 0x30207000 0x00 0x1000>, /* ovr1 */ + <0x00 0x30208000 0x00 0x1000>, /* ovr2 */ + <0x00 0x3020a000 0x00 0x1000>, /* vp1: Tied OFF in the SoC */ + <0x00 0x3020b000 0x00 0x1000>, /* vp2: Used as DPI Out */ + <0x00 0x30201000 0x00 0x1000>; /* common1 */ + reg-names = "common", "vidl1", "vid", + "ovr1", "ovr2", "vp1", "vp2", "common1"; + power-domains = <&k3_pds 186 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 186 6>, + <&k3_clks 186 0>, + <&k3_clks 186 2>; + clock-names = "fck", "vp1", "vp2"; + interrupts = ; + status = "disabled"; + + dss_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + vpu: video-codec@30210000 { + compatible = "ti,j721s2-wave521c", "cnm,wave521c"; + reg = <0x00 0x30210000 0x00 0x10000>; + clocks = <&k3_clks 204 2>; + power-domains = <&k3_pds 204 TI_SCI_PD_EXCLUSIVE>; + sram = <&oc_sram>; + sram-size=<0xf800>; + }; + + c7x_0: dsp@7e000000 { + compatible = "ti,am62a-c7xv-dsp"; + reg = <0x00 0x7e000000 0x00 0x00100000>; + reg-names = "l2sram"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <208>; + ti,sci-proc-ids = <0x04 0xff>; + resets = <&k3_reset 208 1>; + firmware-name = "am62a-c71_0-fw"; + }; + + e5010: jpeg-encoder@fd20000 { + compatible = "ti,am62a-jpeg-enc", "img,e5010-jpeg-enc"; + reg = <0x00 0xfd20000 0x00 0x100>, + <0x00 0xfd20200 0x00 0x200>; + reg-names = "core", "mmu"; + clocks = <&k3_clks 201 0>; + power-domains = <&k3_pds 201 TI_SCI_PD_EXCLUSIVE>; + interrupts = ; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62a-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-mcu.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62a-mcu.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62a-mcu.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -6,6 +6,17 @@ */ &cbass_mcu { + mcu_ram: sram@79100000 { + compatible = "mmio-sram"; + reg = <0x00 0x79100000 0x00 0x80000>; + ranges = <0x00 0x00 0x79100000 0x80000>; + #address-cells = <1>; + #size-cells = <1>; + + mcu1-sram@0 { + reg = <0x0 0x80000>; + }; + }; mcu_pmx0: pinctrl@4084000 { compatible = "pinctrl-single"; reg = <0x00 0x04084000 0x00 0x88>; @@ -15,6 +26,13 @@ status = "disabled"; }; + mcu_esm: esm@4100000 { + compatible = "ti,j721e-esm"; + reg = <0x0 0x4100000 0x0 0x1000>; + ti,esm-pins = <0>, <1>, <2>, <85>; + bootph-pre-ram; + }; + /* * The MCU domain timer interrupts are routed only to the ESM module, * and not currently available for Linux. The MCU domain timers are @@ -153,6 +171,7 @@ clocks = <&k3_clks 188 6>, <&k3_clks 188 1>; clock-names = "hclk", "cclk"; bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + wakeup-source; status = "disabled"; }; @@ -165,6 +184,31 @@ clocks = <&k3_clks 189 6>, <&k3_clks 189 1>; clock-names = "hclk", "cclk"; bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + wakeup-source; status = "disabled"; }; + + mcu_r5fss0: r5fss@79000000 { + compatible = "ti,am62-r5fss"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x79000000 0x00 0x79000000 0x8000>, + <0x79020000 0x00 0x79020000 0x8000>; + power-domains = <&k3_pds 7 TI_SCI_PD_EXCLUSIVE>; + mcu_r5fss0_core0: r5f@79000000 { + compatible = "ti,am62-r5f"; + reg = <0x79000000 0x00008000>, + <0x79020000 0x00008000>; + reg-names = "atcm", "btcm"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <9>; + ti,sci-proc-ids = <0x03 0xff>; + resets = <&k3_reset 9 1>; + firmware-name = "am62a-mcu-r5f0_0-fw"; + ti,atcm-enable = <0>; + ti,btcm-enable = <1>; + ti,loczrama = <0>; + sram = <&mcu_ram>; + }; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -5,6 +5,8 @@ * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ */ +#include + &cbass_wakeup { wkup_conf: syscon@43000000 { compatible = "ti,j721e-system-controller", "syscon", "simple-mfd"; @@ -17,16 +19,46 @@ compatible = "ti,am654-chipid"; reg = <0x14 0x4>; }; + + usb0_phy_ctrl: syscon@4008 { + compatible = "ti,am62-usb-phy-ctrl", "syscon"; + reg = <0x4008 0x4>; + }; + + usb1_phy_ctrl: syscon@4018 { + compatible = "ti,am62-usb-phy-ctrl", "syscon"; + reg = <0x4018 0x4>; + }; }; - wkup_uart0: serial@2b300000 { - compatible = "ti,am64-uart", "ti,am654-uart"; - reg = <0x00 0x2b300000 0x00 0x100>; - interrupts = ; + target-module@2b300050 { + compatible = "ti,sysc-omap2", "ti,sysc"; + reg = <0 0x2b300050 0 0x4>, + <0 0x2b300054 0 0x4>, + <0 0x2b300058 0 0x4>; + reg-names = "rev", "sysc", "syss"; + ti,sysc-mask = <(SYSC_OMAP2_ENAWAKEUP | + SYSC_OMAP2_SOFTRESET | + SYSC_OMAP2_AUTOIDLE)>; + ti,sysc-sidle = , + , + , + ; + ti,syss-mask = <1>; + ti,no-reset-on-init; power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>; clocks = <&k3_clks 114 0>; - clock-names = "fclk"; - status = "disabled"; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0x2b300000 0x100000>; + + wkup_uart0: serial@0 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0 0x100>; + interrupts = ; + status = "disabled"; + }; }; wkup_i2c0: i2c@2b200000 { @@ -49,7 +81,6 @@ clock-names = "vbus", "osc32k"; power-domains = <&k3_pds 117 TI_SCI_PD_EXCLUSIVE>; wakeup-source; - status = "disabled"; }; wkup_rti0: watchdog@2b000000 { @@ -63,6 +94,29 @@ status = "reserved"; }; + wkup_r5fss0: r5fss@78000000 { + compatible = "ti,am62-r5fss"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x78000000 0x00 0x78000000 0x8000>, + <0x78100000 0x00 0x78100000 0x8000>; + power-domains = <&k3_pds 119 TI_SCI_PD_EXCLUSIVE>; + wkup_r5fss0_core0: r5f@78000000 { + compatible = "ti,am62-r5f"; + reg = <0x78000000 0x00008000>, + <0x78100000 0x00008000>; + reg-names = "atcm", "btcm"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <121>; + ti,sci-proc-ids = <0x01 0xff>; + resets = <&k3_reset 121 1>; + firmware-name = "am62-wkup-r5f0_0-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + }; + wkup_vtm0: temperature-sensor@b00000 { compatible = "ti,j7200-vtm"; reg = <0x00 0xb00000 0x00 0x400>, diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62.dtsi b/arch/arm64/boot/dts/ti/k3-am62.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree Source for AM62 SoC Family * - * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/ */ #include @@ -47,6 +47,7 @@ }; cbass_main: bus@f0000 { + bootph-all; compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; @@ -65,6 +66,7 @@ <0x00 0x30040000 0x00 0x30040000 0x00 0x00080000>, /* PRUSS-M */ <0x00 0x30101000 0x00 0x30101000 0x00 0x00010100>, /* CSI window */ <0x00 0x30200000 0x00 0x30200000 0x00 0x00010000>, /* DSS */ + <0x00 0x30300000 0x00 0x30300000 0x00 0x00001000>, /* MCRC64 */ <0x00 0x31000000 0x00 0x31000000 0x00 0x00050000>, /* USB0 DWC3 Core window */ <0x00 0x31100000 0x00 0x31100000 0x00 0x00050000>, /* USB1 DWC3 Core window */ <0x00 0x40900000 0x00 0x40900000 0x00 0x00030000>, /* SA3UL */ @@ -86,6 +88,7 @@ <0x00 0x43000000 0x00 0x43000000 0x00 0x00020000>; cbass_mcu: bus@4000000 { + bootph-all; compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; @@ -93,6 +96,7 @@ }; cbass_wakeup: bus@b00000 { + bootph-all; compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; @@ -117,3 +121,7 @@ #include "k3-am62-main.dtsi" #include "k3-am62-mcu.dtsi" #include "k3-am62-wakeup.dtsi" + +&dmsc { + ti,partial-io-wakeup-sources = <&mcu_mcan0>, <&mcu_mcan1>, <&mcu_uart0>, <&wkup_uart0>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts b/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts --- a/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts 2024-07-07 20:37:34.624306449 -0400 @@ -229,3 +229,61 @@ &tlv320aic3106 { DVDD-supply = <&buck2_reg>; }; + +&ospi0 { + assigned-clock-rates = <200000000>; + + flash@0 { + compatible = "spi-nand"; + reg = <0x0>; + spi-tx-bus-width = <8>; + spi-rx-bus-width = <8>; + spi-max-frequency = <50000000>; + cdns,tshsl-ns = <60>; + cdns,tsd2d-ns = <60>; + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "ospi_nand.tiboot3"; + reg = <0x0 0x80000>; + }; + + partition@80000 { + label = "ospi_nand.tispl"; + reg = <0x80000 0x200000>; + }; + + partition@280000 { + label = "ospi_nand.u-boot"; + reg = <0x280000 0x400000>; + }; + + partition@680000 { + label = "ospi_nand.env"; + reg = <0x680000 0x40000>; + }; + + partition@6c0000 { + label = "ospi_nand.env.backup"; + reg = <0x6c0000 0x40000>; + }; + + partition@2000000 { + label = "ospi_nand.rootfs"; + reg = <0x2000000 0x5fc0000>; + }; + + partition@7fc0000 { + label = "ospi_nand.phypattern"; + reg = <0x7fc0000 0x40000>; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-lp-sk-lincolntech-lcd185-panel.dtso b/arch/arm64/boot/dts/ti/k3-am62-lp-sk-lincolntech-lcd185-panel.dtso --- a/arch/arm64/boot/dts/ti/k3-am62-lp-sk-lincolntech-lcd185-panel.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62-lp-sk-lincolntech-lcd185-panel.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-or-late OR MIT +/** + * Lincoln tech Solutions OLDI panel (LCD185-101CT) and touch DT overlay for AM62-LP-SK + * + * AM62-LP SKEVM: https://www.ti.com/tool/SK-AM62-LP + * Panel datasheet: https://lincolntechsolutions.com/wp-content/uploads/2023/04/LCD185-101CTL1ARNTT_DS_R1.3.pdf + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&{/} { + display { + compatible = "lincolntech,lcd185-101ct", "panel-simple"; + /* + * Note that the OLDI TX 0 transmits the odd set of pixels + * while the OLDI TX 1 transmits the even set. This is a + * fixed configuration in the IP integration and is not + * changeable. The properties, "dual-lvds-odd-pixels" and + * "dual-lvds-even-pixels" have been used to merely + * identify if a Dual Link configuration is required. + * Swapping them will cause an error in the dss oldi driver. + */ + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + lcd_in0: endpoint { + remote-endpoint = <&oldi_0_out>; + }; + }; + port@1 { + reg = <1>; + dual-lvds-even-pixels; + lcd_in1: endpoint { + remote-endpoint = <&oldi_1_out>; + }; + }; + }; + }; +}; + +&dss { + status = "okay"; +}; + +&oldi0 { + status = "okay"; +}; + +&oldi1 { + status = "okay"; +}; + +&oldi0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + oldi_0_in: endpoint { + remote-endpoint = <&dpi0_out0>; + }; + }; + + port@1 { + reg = <1>; + oldi_0_out: endpoint { + remote-endpoint = <&lcd_in0>; + }; + }; +}; + +&oldi1_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + oldi_1_in: endpoint { + remote-endpoint = <&dpi0_out1>; + }; + }; + + port@1 { + reg = <1>; + oldi_1_out: endpoint { + remote-endpoint = <&lcd_in1>; + }; + }; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VP1: Output to OLDI */ + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + dpi0_out0: endpoint@0 { + reg = <0>; + remote-endpoint = <&oldi_0_in>; + }; + dpi0_out1: endpoint@1 { + reg = <1>; + remote-endpoint = <&oldi_1_in>; + }; + }; +}; + +&main_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + eeprom@57 { + compatible = "atmel,24c256"; + reg = <0x57>; + }; + + touchscreen@5d { + compatible = "goodix,gt928"; + reg = <0x5d>; + interrupt-parent = <&exp1>; + interrupts = <15 IRQ_TYPE_EDGE_FALLING>; + irq-gpios = <&exp1 15 GPIO_ACTIVE_LOW>; + reset-gpios = <&exp2 18 GPIO_ACTIVE_LOW>; + touchscreen-size-x = <1920>; + touchscreen-size-y = <1200>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-lp-sk-microtips-mf101hie-panel.dtso b/arch/arm64/boot/dts/ti/k3-am62-lp-sk-microtips-mf101hie-panel.dtso --- a/arch/arm64/boot/dts/ti/k3-am62-lp-sk-microtips-mf101hie-panel.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62-lp-sk-microtips-mf101hie-panel.dtso 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * Microtips integrated OLDI panel (MF-101HIEBCAF0) and touch DT overlay for AM62 LP-SK + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +&{/} { + display { + compatible = "microtips,mf-101hiebcaf0", "panel-simple"; + /* + * Note that the OLDI TX 0 transmits the odd set of pixels + * while the OLDI TX 1 transmits the even set. This is a + * fixed configuration in the IP integration and is not + * changeable. The properties, "dual-lvds-odd-pixels" and + * "dual-lvds-even-pixels" have been used to merely + * identify if a Dual Link configuration is required. + * Swapping them will cause an error in the dss oldi driver. + */ + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + lcd_in0: endpoint { + remote-endpoint = <&oldi_0_out>; + }; + }; + port@1 { + reg = <1>; + dual-lvds-even-pixels; + lcd_in1: endpoint { + remote-endpoint = <&oldi_1_out>; + }; + }; + }; + }; +}; + +&dss { + status = "okay"; +}; + +&oldi0 { + status = "okay"; +}; + +&oldi1 { + status = "okay"; +}; + +&oldi0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + oldi_0_in: endpoint { + remote-endpoint = <&dpi0_out0>; + }; + }; + + port@1 { + reg = <1>; + oldi_0_out: endpoint { + remote-endpoint = <&lcd_in0>; + }; + }; +}; + +&oldi1_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + oldi_1_in: endpoint { + remote-endpoint = <&dpi0_out1>; + }; + }; + + port@1 { + reg = <1>; + oldi_1_out: endpoint { + remote-endpoint = <&lcd_in1>; + }; + }; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VP1: Output to OLDI */ + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + dpi0_out0: endpoint@0 { + reg = <0>; + remote-endpoint = <&oldi_0_in>; + }; + dpi0_out1: endpoint@1 { + reg = <1>; + remote-endpoint = <&oldi_1_in>; + }; + }; +}; + +&main_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@41 { + compatible = "ilitek,ili251x"; + reg = <0x41>; + interrupt-parent = <&exp1>; + interrupts = <15 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&exp2 18 GPIO_ACTIVE_LOW>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree Source for AM625 SoC Family Main Domain peripherals * - * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/ */ &cbass_main { @@ -42,9 +42,8 @@ }; }; - main_conf: syscon@100000 { - compatible = "syscon", "simple-mfd"; - reg = <0x00 0x00100000 0x00 0x20000>; + main_conf: bus@100000 { + compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x00 0x00100000 0x20000>; @@ -78,10 +77,16 @@ assigned-clock-parents = <&k3_clks 157 18>; #clock-cells = <0>; }; + + dss_oldi_io_ctrl: oldi-io-controller@8600 { + compatible = "ti,am625-dss-oldi-io-ctrl", "syscon"; + reg = <0x8600 0x200>; + }; }; dmss: bus@48000000 { - compatible = "simple-mfd"; + bootph-all; + compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; dma-ranges; @@ -90,6 +95,7 @@ ti,sci-dev-id = <25>; secure_proxy_main: mailbox@4d000000 { + bootph-all; compatible = "ti,am654-secure-proxy"; #mbox-cells = <1>; reg-names = "target_data", "rt", "scfg"; @@ -119,8 +125,13 @@ <0x00 0x4c000000 0x00 0x20000>, <0x00 0x4a820000 0x00 0x20000>, <0x00 0x4aa40000 0x00 0x20000>, - <0x00 0x4bc00000 0x00 0x100000>; - reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4bc00000 0x00 0x100000>, + <0x00 0x48600000 0x00 0x8000>, + <0x00 0x484a4000 0x00 0x2000>, + <0x00 0x484c2000 0x00 0x2000>, + <0x00 0x48420000 0x00 0x2000>; + reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "bchan"; msi-parent = <&inta_main_dmss>; #dma-cells = <3>; @@ -136,8 +147,13 @@ reg = <0x00 0x485c0000 0x00 0x100>, <0x00 0x4a800000 0x00 0x20000>, <0x00 0x4aa00000 0x00 0x40000>, - <0x00 0x4b800000 0x00 0x400000>; - reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4b800000 0x00 0x400000>, + <0x00 0x485e0000 0x00 0x10000>, + <0x00 0x484a0000 0x00 0x2000>, + <0x00 0x484c0000 0x00 0x2000>, + <0x00 0x48430000 0x00 0x1000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "rflow"; msi-parent = <&inta_main_dmss>; #dma-cells = <2>; @@ -165,6 +181,7 @@ }; dmsc: system-controller@44043000 { + bootph-all; compatible = "ti,k2g-sci"; ti,host-id = <12>; mbox-names = "rx", "tx"; @@ -174,16 +191,19 @@ reg = <0x00 0x44043000 0x00 0xfe0>; k3_pds: power-controller { + bootph-all; compatible = "ti,sci-pm-domain"; #power-domain-cells = <2>; }; k3_clks: clock-controller { + bootph-all; compatible = "ti,k2g-sci-clk"; #clock-cells = <2>; }; k3_reset: reset-controller { + bootph-all; compatible = "ti,sci-reset"; #reset-cells = <2>; }; @@ -201,7 +221,15 @@ dma-names = "tx", "rx1", "rx2"; }; + crc: crc@30300000 { + compatible = "ti,am62-mcrc64"; + reg = <0x00 0x30300000 0x00 0x1000>; + clocks = <&k3_clks 116 0>; + power-domains = <&k3_pds 116 TI_SCI_PD_EXCLUSIVE>; + }; + secure_proxy_sa3: mailbox@43600000 { + bootph-pre-ram; compatible = "ti,am654-secure-proxy"; #mbox-cells = <1>; reg-names = "target_data", "rt", "scfg"; @@ -217,20 +245,36 @@ }; main_pmx0: pinctrl@f4000 { - compatible = "pinctrl-single"; + bootph-all; + compatible = "ti,am654-padconf", "pinctrl-single"; reg = <0x00 0xf4000 0x00 0x2ac>; #pinctrl-cells = <1>; pinctrl-single,register-width = <32>; pinctrl-single,function-mask = <0xffffffff>; + /* + * pinctrl IP DOES NOT give any functional IRQs when a + * system is in active state. This IRQ is only a dummy IRQ + * that is being used to trick Linux into thinking that + * GIC can potentially recieve an interrupt from this IP. + * This helps us setup the IO daisychain wakeups for deep + * sleep via chained wake IRQs. + * Please feel free to assign a different number here as + * long as it is unused if 98 conflicts with another use case. + */ + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; }; main_esm: esm@420000 { + bootph-pre-ram; compatible = "ti,j721e-esm"; reg = <0x00 0x420000 0x00 0x1000>; ti,esm-pins = <160>, <161>, <162>, <163>, <177>, <178>; }; main_timer0: timer@2400000 { + bootph-all; compatible = "ti,am654-timer"; reg = <0x00 0x2400000 0x00 0x400>; interrupts = ; @@ -492,6 +536,9 @@ main_gpio0: gpio@600000 { compatible = "ti,am64-gpio", "ti,keystone-gpio"; reg = <0x0 0x00600000 0x0 0x100>; + gpio-ranges = <&main_pmx0 0 0 32>, + <&main_pmx0 32 33 38>, + <&main_pmx0 70 72 22>; gpio-controller; #gpio-cells = <2>; interrupt-parent = <&main_gpio_intr>; @@ -510,6 +557,10 @@ compatible = "ti,am64-gpio", "ti,keystone-gpio"; reg = <0x0 0x00601000 0x0 0x100>; gpio-controller; + gpio-ranges = <&main_pmx0 0 94 41>, + <&main_pmx0 41 136 6>, + <&main_pmx0 47 143 3>, + <&main_pmx0 50 149 2>; #gpio-cells = <2>; interrupt-parent = <&main_gpio_intr>; interrupts = <180>, <181>, <182>, @@ -532,10 +583,9 @@ clock-names = "clk_ahb", "clk_xin"; assigned-clocks = <&k3_clks 57 6>; assigned-clock-parents = <&k3_clks 57 8>; + bus-width = <8>; mmc-ddr-1_8v; mmc-hs200-1_8v; - ti,trm-icp = <0x2>; - bus-width = <8>; ti,clkbuf-sel = <0x7>; ti,otap-del-sel-legacy = <0x0>; ti,otap-del-sel-mmc-hs = <0x0>; @@ -553,7 +603,8 @@ power-domains = <&k3_pds 58 TI_SCI_PD_EXCLUSIVE>; clocks = <&k3_clks 58 5>, <&k3_clks 58 6>; clock-names = "clk_ahb", "clk_xin"; - ti,trm-icp = <0x2>; + bus-width = <4>; + ti,clkbuf-sel = <0x7>; ti,otap-del-sel-legacy = <0x8>; ti,otap-del-sel-sd-hs = <0x0>; ti,otap-del-sel-sdr12 = <0x0>; @@ -565,8 +616,6 @@ ti,itap-del-sel-sd-hs = <0x1>; ti,itap-del-sel-sdr12 = <0xa>; ti,itap-del-sel-sdr25 = <0x1>; - ti,clkbuf-sel = <0x7>; - bus-width = <4>; status = "disabled"; }; @@ -577,7 +626,8 @@ power-domains = <&k3_pds 184 TI_SCI_PD_EXCLUSIVE>; clocks = <&k3_clks 184 5>, <&k3_clks 184 6>; clock-names = "clk_ahb", "clk_xin"; - ti,trm-icp = <0x2>; + bus-width = <4>; + ti,clkbuf-sel = <0x7>; ti,otap-del-sel-legacy = <0x8>; ti,otap-del-sel-sd-hs = <0x0>; ti,otap-del-sel-sdr12 = <0x0>; @@ -589,16 +639,16 @@ ti,itap-del-sel-sd-hs = <0xa>; ti,itap-del-sel-sdr12 = <0xa>; ti,itap-del-sel-sdr25 = <0x1>; - ti,clkbuf-sel = <0x7>; status = "disabled"; }; usbss0: dwc3-usb@f900000 { compatible = "ti,am62-usb"; - reg = <0x00 0x0f900000 0x00 0x800>; + reg = <0x00 0x0f900000 0x00 0x800>, + <0x00 0x0f908000 0x00 0x400>; clocks = <&k3_clks 161 3>; clock-names = "ref"; - ti,syscon-phy-pll-refclk = <&wkup_conf 0x4008>; + ti,syscon-phy-pll-refclk = <&usb0_phy_ctrl 0x0>; #address-cells = <2>; #size-cells = <2>; power-domains = <&k3_pds 178 TI_SCI_PD_EXCLUSIVE>; @@ -620,10 +670,11 @@ usbss1: dwc3-usb@f910000 { compatible = "ti,am62-usb"; - reg = <0x00 0x0f910000 0x00 0x800>; + reg = <0x00 0x0f910000 0x00 0x800>, + <0x00 0x0f918000 0x00 0x400>; clocks = <&k3_clks 162 3>; clock-names = "ref"; - ti,syscon-phy-pll-refclk = <&wkup_conf 0x4018>; + ti,syscon-phy-pll-refclk = <&usb1_phy_ctrl 0x0>; #address-cells = <2>; #size-cells = <2>; power-domains = <&k3_pds 179 TI_SCI_PD_EXCLUSIVE>; @@ -669,6 +720,15 @@ }; }; + gpu: gpu@fd00000 { + compatible = "ti,am62-gpu", "img,img-axe"; + reg = <0x00 0x0fd00000 0x00 0x20000>; + clocks = <&k3_clks 187 0>; + clock-names = "core"; + interrupts = ; + power-domains = <&k3_pds 187 TI_SCI_PD_EXCLUSIVE>; + }; + cpsw3g: ethernet@8000000 { compatible = "ti,am642-cpsw-nuss"; #address-cells = <2>; @@ -759,12 +819,47 @@ interrupts = ; status = "disabled"; + oldi-txes { + #address-cells = <1>; + #size-cells = <0>; + + oldi0: oldi@0 { + reg = <0>; + clocks = <&k3_clks 186 0>; + clock-names = "s_clk"; + ti,companion-oldi = <&oldi1>; + ti,oldi-io-ctrl = <&dss_oldi_io_ctrl>; + status = "disabled"; + + oldi0_ports: ports { + }; + }; + + oldi1: oldi@1 { + reg = <1>; + ti,secondary-oldi; + status = "disabled"; + + oldi1_ports: ports { + }; + }; + }; + dss_ports: ports { #address-cells = <1>; #size-cells = <0>; }; }; + timesync_router: pinctrl@a40000 { + compatible = "pinctrl-single"; + reg = <0x0 0xa40000 0x0 0x800>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x000107ff>; + status = "disabled"; + }; + hwspinlock: spinlock@2a000000 { compatible = "ti,am64-hwspinlock"; reg = <0x00 0x2a000000 0x00 0x1000>; @@ -811,6 +906,33 @@ status = "disabled"; }; + eqep0: counter@23200000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23200000 0x00 0x100>; + power-domains = <&k3_pds 59 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 59 0>; + interrupts = ; + status = "disabled"; + }; + + eqep1: counter@23210000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23210000 0x00 0x100>; + power-domains = <&k3_pds 60 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 60 0>; + interrupts = ; + status = "disabled"; + }; + + eqep2: counter@23220000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23220000 0x00 0x100>; + power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 62 0>; + interrupts = ; + status = "disabled"; + }; + main_mcan0: can@20701000 { compatible = "bosch,m_can"; reg = <0x00 0x20701000 0x00 0x200>, @@ -960,4 +1082,67 @@ power-domains = <&k3_pds 192 TI_SCI_PD_EXCLUSIVE>; status = "disabled"; }; + + ti_csi2rx0: ticsi2rx@30102000 { + compatible = "ti,j721e-csi2rx-shim"; + dmas = <&main_bcdma 0 0x4700 0>, <&main_bcdma 0 0x4701 0>, + <&main_bcdma 0 0x4702 0>, <&main_bcdma 0 0x4703 0>; + dma-names = "rx0", "rx1", "rx2", "rx3"; + reg = <0x00 0x30102000 0x00 0x1000>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + cdns_csi2rx0: csi-bridge@30101000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x30101000 0x00 0x1000>; + clocks = <&k3_clks 182 0>, <&k3_clks 182 3>, <&k3_clks 182 0>, + <&k3_clks 182 0>, <&k3_clks 182 4>, <&k3_clks 182 4>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi0_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi0_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi0_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi0_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + dphy0: phy@30110000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x30110000 0x00 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 185 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -1,12 +1,13 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree Source for AM625 SoC Family MCU Domain peripherals * - * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/ */ &cbass_mcu { mcu_pmx0: pinctrl@4084000 { + bootph-all; compatible = "pinctrl-single"; reg = <0x00 0x04084000 0x00 0x88>; #pinctrl-cells = <1>; @@ -15,6 +16,7 @@ }; mcu_esm: esm@4100000 { + bootph-pre-ram; compatible = "ti,j721e-esm"; reg = <0x00 0x4100000 0x00 0x1000>; ti,esm-pins = <0>, <1>, <2>, <85>; @@ -157,6 +159,7 @@ clocks = <&k3_clks 188 6>, <&k3_clks 188 1>; clock-names = "hclk", "cclk"; bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + wakeup-source; status = "disabled"; }; @@ -169,6 +172,20 @@ clocks = <&k3_clks 189 6>, <&k3_clks 189 1>; clock-names = "hclk", "cclk"; bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + wakeup-source; + status = "disabled"; + }; + + mcu_m4fss: m4fss@5000000 { + compatible = "ti,am64-m4fss"; + reg = <0x00 0x5000000 0x00 0x30000>, + <0x00 0x5040000 0x00 0x10000>; + reg-names = "iram", "dram"; + resets = <&k3_reset 9 1>; + firmware-name = "am62-mcu-m4f0_0-fw"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <9>; + ti,sci-proc-ids = <0x18 0xff>; status = "disabled"; }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p5.dtsi b/arch/arm64/boot/dts/ti/k3-am62p5.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62p5.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62p5.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -1,7 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree file for the AM62P5 SoC family (quad core) - * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ * * TRM: https://www.ti.com/lit/pdf/spruj83 */ @@ -47,6 +47,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + operating-points-v2 = <&a53_opp_table>; clocks = <&k3_clks 135 0>; }; @@ -62,6 +63,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + operating-points-v2 = <&a53_opp_table>; clocks = <&k3_clks 136 0>; }; @@ -77,6 +79,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + operating-points-v2 = <&a53_opp_table>; clocks = <&k3_clks 137 0>; }; @@ -92,10 +95,54 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + operating-points-v2 = <&a53_opp_table>; clocks = <&k3_clks 138 0>; }; }; + a53_opp_table: opp-table { + compatible = "operating-points-v2-ti-cpu"; + opp-shared; + syscon = <&wkup_conf>; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-supported-hw = <0x01 0x0007>; + clock-latency-ns = <6000000>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-supported-hw = <0x01 0x0007>; + clock-latency-ns = <6000000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-supported-hw = <0x01 0x0007>; + clock-latency-ns = <6000000>; + }; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-supported-hw = <0x01 0x0007>; + clock-latency-ns = <6000000>; + }; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-supported-hw = <0x01 0x0006>; + clock-latency-ns = <6000000>; + }; + + opp-1250000000 { + opp-hz = /bits/ 64 <1250000000>; + opp-supported-hw = <0x01 0x0004>; + clock-latency-ns = <6000000>; + opp-suspend; + }; + }; + l2_0: l2-cache0 { compatible = "cache"; cache-unified; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p5-sk-dsi-rpi-7inch-panel.dtso b/arch/arm64/boot/dts/ti/k3-am62p5-sk-dsi-rpi-7inch-panel.dtso --- a/arch/arm64/boot/dts/ti/k3-am62p5-sk-dsi-rpi-7inch-panel.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk-dsi-rpi-7inch-panel.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * DT Overlay for RPi 7inch touchscreen panel interfaced with DSI on + * AM62P5-SK EVM. + * + * RPi DSI Panel: https://www.raspberrypi.com/products/raspberry-pi-touch-display/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +&{/} { + panel0 { + compatible = "raspberrypi,7inch-dsi", "simple-panel"; + backlight = <&display_reg>; + power-supply = <&display_reg>; + + port { + + panel_in: endpoint { + remote-endpoint = <&panel_bridge_out>; + }; + }; + }; + + bridge_reg: bridge-regulator { + compatible = "regulator-fixed"; + regulator-name = "bridge-reg"; + gpio = <&display_reg 0 0>; + vin-supply = <&display_reg>; + enable-active-high; + }; +}; + +&dphy_tx0 { + status = "okay"; +}; + +&main_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + display_reg: regulator@45 { + compatible = "raspberrypi,7inch-touchscreen-panel-regulator"; + reg = <0x45>; + gpio-controller; + #gpio-cells = <2>; + }; +}; + +&dss1 { + status = "okay"; +}; + +&dss1_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* DSS1-VP1: DSI Output */ + port@1 { + reg = <1>; + + dss1_dpi1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; +}; + +&dsi0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dsi0_out: endpoint { + remote-endpoint = <&panel_bridge_in>; + }; + }; + + port@1 { + reg = <1>; + + dsi0_in: endpoint { + remote-endpoint = <&dss1_dpi1_out>; + }; + }; + }; + + bridge@0 { + status = "okay"; + compatible = "toshiba,tc358762"; + reg = <0>; + vddc-supply = <&bridge_reg>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + panel_bridge_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + + panel_bridge_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts --- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts 2024-07-07 20:37:34.628306469 -0400 @@ -8,6 +8,9 @@ /dts-v1/; +#include +#include +#include #include "k3-am62p5.dtsi" / { @@ -18,6 +21,14 @@ serial0 = &wkup_uart0; serial2 = &main_uart0; serial3 = &main_uart1; + mmc0 = &sdhci0; + mmc1 = &sdhci1; + mmc2 = &sdhci2; + spi0 = &ospi0; + ethernet0 = &cpsw_port1; + ethernet1 = &cpsw_port2; + usb0 = &usb0; + usb1 = &usb1; }; chosen { @@ -29,6 +40,7 @@ reg = <0x00000000 0x80000000 0x00000000 0x80000000>, <0x00000008 0x80000000 0x00000001 0x80000000>; device_type = "memory"; + bootph-pre-ram; }; reserved-memory { @@ -36,6 +48,43 @@ #size-cells = <2>; ranges; + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x00 0x24000000>; + linux,cma-default; + }; + + rtos_ipc_memory_region: rtos-ipc-memory@9b500000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9b500000 0x00 0x00300000>; + no-map; + }; + + mcu_r5fss0_core0_dma_memory_region: mcu-r5fss-dma-memory-region@9b800000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9b800000 0x00 0x00100000>; + no-map; + }; + + mcu_r5fss0_core0_memory_region: mcu-r5fss-memory-region@9b900000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9b900000 0x00 0x00f00000>; + no-map; + }; + + wkup_r5fss0_core0_dma_memory_region: r5f-dma-memory@9c800000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9c800000 0x00 0x00100000>; + no-map; + }; + + wkup_r5fss0_core0_memory_region: r5f-memory@9c900000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9c900000 0x00 0x01e00000>; + no-map; + }; + secure_tfa_ddr: tfa@9e780000 { reg = <0x00 0x9e780000 0x00 0x80000>; no-map; @@ -45,42 +94,692 @@ reg = <0x00 0x9e800000 0x00 0x01800000>; /* for OP-TEE */ no-map; }; + }; - wkup_r5fss0_core0_memory_region: r5f-dma-memory@9c900000 { - compatible = "shared-dma-pool"; - reg = <0x00 0x9c900000 0x00 0x01e00000>; - no-map; + vmain_pd: regulator-0 { + /* TPS65988 PD CONTROLLER OUTPUT */ + compatible = "regulator-fixed"; + regulator-name = "vmain_pd"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + bootph-all; + }; + + vcc_5v0: regulator-1 { + /* Output of TPS630702RNMR */ + compatible = "regulator-fixed"; + regulator-name = "vcc_5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vmain_pd>; + regulator-always-on; + regulator-boot-on; + bootph-all; + }; + + vdd_mmc1: regulator-2 { + /* TPS22918DBVR */ + compatible = "regulator-fixed"; + regulator-name = "vdd_mmc1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + enable-active-high; + gpio = <&exp1 3 GPIO_ACTIVE_HIGH>; + bootph-all; + }; + + vddshv_sdio: regulator-3 { + compatible = "regulator-gpio"; + regulator-name = "vddshv_sdio"; + pinctrl-names = "default"; + pinctrl-0 = <&vddshv_sdio_pins_default>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + gpios = <&main_gpio0 31 GPIO_ACTIVE_HIGH>; + states = <1800000 0x0>, + <3300000 0x1>; + bootph-all; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&usr_led_pins_default>; + + led-0 { + label = "am62-sk:green:heartbeat"; + gpios = <&main_gpio1 49 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + function = LED_FUNCTION_HEARTBEAT; + default-state = "off"; + }; + }; + + opp-table { + /* Add 1.4GHz OPP for am62p5-sk board. Requires VDD_CORE at 0v85 */ + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; + opp-supported-hw = <0x01 0x0004>; + clock-latency-ns = <6000000>; + }; + }; + + tlv320_mclk: clk-0 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12288000>; + }; + + codec_audio: sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "AM62x-SKEVM"; + simple-audio-card,widgets = + "Headphone", "Headphone Jack", + "Line", "Line In", + "Microphone", "Microphone Jack"; + simple-audio-card,routing = + "Headphone Jack", "HPLOUT", + "Headphone Jack", "HPROUT", + "LINE1L", "Line In", + "LINE1R", "Line In", + "MIC3R", "Microphone Jack", + "Microphone Jack", "Mic Bias"; + simple-audio-card,format = "dsp_b"; + simple-audio-card,bitclock-master = <&sound_master>; + simple-audio-card,frame-master = <&sound_master>; + simple-audio-card,bitclock-inversion; + + simple-audio-card,cpu { + sound-dai = <&mcasp1>; + }; + + sound_master: simple-audio-card,codec { + sound-dai = <&tlv320aic3106>; + clocks = <&tlv320_mclk>; }; }; + + hdmi0: connector-hdmi { + compatible = "hdmi-connector"; + label = "hdmi"; + type = "a"; + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&sii9022_out>; + }; + }; + }; +}; + +&main_gpio0 { + bootph-all; +}; + +&main_gpio1 { + bootph-all; }; &main_pmx0 { - main_uart0_pins_default: main-uart0-default-pins { + bootph-all; + + main_i2c0_pins_default: main-i2c0-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x01e0, PIN_INPUT_PULLUP, 0) /* (B25) I2C0_SCL */ + AM62PX_IOPAD(0x01e4, PIN_INPUT_PULLUP, 0) /* (A24) I2C0_SDA */ + >; + }; + + main_i2c1_pins_default: main-i2c1-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x01e8, PIN_INPUT_PULLUP, 0) /* (C24) I2C1_SCL */ + AM62PX_IOPAD(0x01ec, PIN_INPUT_PULLUP, 0) /* (B24) I2C1_SDA */ + >; + bootph-all; + }; + + main_i2c2_pins_default: main-i2c2-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x00b0, PIN_INPUT_PULLUP, 1) /* (T22) GPMC0_CSn2.I2C2_SCL */ + AM62PX_IOPAD(0x00b4, PIN_INPUT_PULLUP, 1) /* (U25) GPMC0_CSn3.I2C2_SDA */ + >; + }; + + main_gpio1_ioexp_intr_pins_default: main-gpio1-ioexp-intr-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x01d4, PIN_INPUT, 7) /* (C22) UART0_RTSn.GPIO1_23 */ + >; + }; + + main_mcasp1_pins_default: main-mcasp1-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x0090, PIN_INPUT, 2) /* (U24) GPMC0_BE0n_CLE.MCASP1_ACLKX */ + AM62PX_IOPAD(0x0098, PIN_INPUT, 2) /* (AA24) GPMC0_WAIT0.MCASP1_AFSX */ + AM62PX_IOPAD(0x008c, PIN_OUTPUT, 2) /* (T25) GPMC0_WEn.MCASP1_AXR0 */ + AM62PX_IOPAD(0x0084, PIN_INPUT, 2) /* (R25) GPMC0_ADVn_ALE.MCASP1_AXR2 */ + >; + }; + + main_mdio1_pins_default: main-mdio1-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x0160, PIN_OUTPUT, 0) /* (F17) MDIO0_MDC */ + AM62PX_IOPAD(0x015c, PIN_INPUT, 0) /* (F16) MDIO0_MDIO */ + >; + }; + + main_mmc1_pins_default: main-mmc1-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x023c, PIN_INPUT, 0) /* (H20) MMC1_CMD */ + AM62PX_IOPAD(0x0234, PIN_OUTPUT, 0) /* (J24) MMC1_CLK */ + AM62PX_IOPAD(0x0230, PIN_INPUT, 0) /* (H21) MMC1_DAT0 */ + AM62PX_IOPAD(0x022c, PIN_INPUT_PULLUP, 0) /* (H23) MMC1_DAT1 */ + AM62PX_IOPAD(0x0228, PIN_INPUT_PULLUP, 0) /* (H22) MMC1_DAT2 */ + AM62PX_IOPAD(0x0224, PIN_INPUT_PULLUP, 0) /* (H25) MMC1_DAT3 */ + AM62PX_IOPAD(0x0240, PIN_INPUT, 0) /* (D23) MMC1_SDCD */ + >; bootph-all; + }; + + main_mmc2_pins_default: main-mmc2-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x0120, PIN_INPUT, 0) /* (K24) MMC2_CMD */ + AM62PX_IOPAD(0x0118, PIN_OUTPUT, 0) /* (K21) MMC2_CLK */ + AM62PX_IOPAD(0x011C, PIN_INPUT, 0) /* () MMC2_CLKLB */ + AM62PX_IOPAD(0x0114, PIN_INPUT, 0) /* (K23) MMC2_DAT0 */ + AM62PX_IOPAD(0x0110, PIN_INPUT_PULLUP, 0) /* (K22) MMC2_DAT1 */ + AM62PX_IOPAD(0x010c, PIN_INPUT_PULLUP, 0) /* (L20) MMC2_DAT2 */ + AM62PX_IOPAD(0x0108, PIN_INPUT_PULLUP, 0) /* (L21) MMC2_DAT3 */ + >; + bootph-all; + }; + + main_rgmii1_pins_default: main-rgmii1-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x014c, PIN_INPUT, 0) /* (B15) RGMII1_RD0 */ + AM62PX_IOPAD(0x0150, PIN_INPUT, 0) /* (B16) RGMII1_RD1 */ + AM62PX_IOPAD(0x0154, PIN_INPUT, 0) /* (A14) RGMII1_RD2 */ + AM62PX_IOPAD(0x0158, PIN_INPUT, 0) /* (B14) RGMII1_RD3 */ + AM62PX_IOPAD(0x0148, PIN_INPUT, 0) /* (A16) RGMII1_RXC */ + AM62PX_IOPAD(0x0144, PIN_INPUT, 0) /* (A15) RGMII1_RX_CTL */ + AM62PX_IOPAD(0x0134, PIN_INPUT, 0) /* (A18) RGMII1_TD0 */ + AM62PX_IOPAD(0x0138, PIN_INPUT, 0) /* (C17) RGMII1_TD1 */ + AM62PX_IOPAD(0x013c, PIN_INPUT, 0) /* (A17) RGMII1_TD2 */ + AM62PX_IOPAD(0x0140, PIN_INPUT, 0) /* (C16) RGMII1_TD3 */ + AM62PX_IOPAD(0x0130, PIN_INPUT, 0) /* (B17) RGMII1_TXC */ + AM62PX_IOPAD(0x012c, PIN_INPUT, 0) /* (B18) RGMII1_TX_CTL */ + >; + bootph-all; + }; + + main_rgmii2_pins_default: main-rgmii2-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x0184, PIN_INPUT, 0) /* (E19) RGMII2_RD0 */ + AM62PX_IOPAD(0x0188, PIN_INPUT, 0) /* (E16) RGMII2_RD1 */ + AM62PX_IOPAD(0x018c, PIN_INPUT, 0) /* (E17) RGMII2_RD2 */ + AM62PX_IOPAD(0x0190, PIN_INPUT, 0) /* (C19) RGMII2_RD3 */ + AM62PX_IOPAD(0x0180, PIN_INPUT, 0) /* (D19) RGMII2_RXC */ + AM62PX_IOPAD(0x017c, PIN_INPUT, 0) /* (F19) RGMII2_RX_CTL */ + AM62PX_IOPAD(0x016c, PIN_INPUT, 0) /* (B19) RGMII2_TD0 */ + AM62PX_IOPAD(0x0170, PIN_INPUT, 0) /* (A21) RGMII2_TD1 */ + AM62PX_IOPAD(0x0174, PIN_INPUT, 0) /* (D17) RGMII2_TD2 */ + AM62PX_IOPAD(0x0178, PIN_INPUT, 0) /* (A19) RGMII2_TD3 */ + AM62PX_IOPAD(0x0168, PIN_INPUT, 0) /* (D16) RGMII2_TXC */ + AM62PX_IOPAD(0x0164, PIN_INPUT, 0) /* (A20) RGMII2_TX_CTL */ + >; + bootph-all; + }; + + main_uart0_pins_default: main-uart0-default-pins { pinctrl-single,pins = < AM62PX_IOPAD(0x1c8, PIN_INPUT, 0) /* (A22) UART0_RXD */ AM62PX_IOPAD(0x1cc, PIN_OUTPUT, 0) /* (B22) UART0_TXD */ - AM62PX_IOPAD(0x1d0, PIN_INPUT, 0) /* (A23) UART0_CTSn */ - AM62PX_IOPAD(0x1d4, PIN_OUTPUT, 0) /* (C22) UART0_RTSn */ >; + bootph-all; }; main_uart1_pins_default: main-uart1-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x0194, PIN_INPUT, 2) /* (D25) MCASP0_AXR3.UART1_CTSn */ + AM62PX_IOPAD(0x0198, PIN_OUTPUT, 2) /* (E25) MCASP0_AXR2.UART1_RTSn */ + AM62PX_IOPAD(0x01ac, PIN_INPUT, 2) /* (G23) MCASP0_AFSR.UART1_RXD */ + AM62PX_IOPAD(0x01b0, PIN_OUTPUT, 2) /* (G20) MCASP0_ACLKR.UART1_TXD */ + >; bootph-all; + }; + + main_usb1_pins_default: main-usb1-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x0258, PIN_INPUT, 0) /* (G21) USB1_DRVVBUS */ + >; + }; + + main_wlirq_pins_default: main-wlirq-default-pins { pinctrl-single,pins = < - AM62PX_IOPAD(0x194, PIN_INPUT, 2) /* (D25) MCASP0_AXR3 */ - AM62PX_IOPAD(0x198, PIN_OUTPUT, 2) /* (E25) MCASP0_AXR2 */ - AM62PX_IOPAD(0x1ac, PIN_INPUT, 2) /* (G23) MCASP0_AFSR */ - AM62PX_IOPAD(0x1b0, PIN_OUTPUT, 2) /* (G20) MCASP0_ACLKR */ + AM62PX_IOPAD(0x0128, PIN_INPUT, 7) /* (K25) MMC2_SDWP.GPIO0_72 */ + >; + }; + + ospi0_pins_default: ospi0-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x0000, PIN_OUTPUT, 0) /* (P23) OSPI0_CLK */ + AM62PX_IOPAD(0x002c, PIN_OUTPUT, 0) /* (M25) OSPI0_CSn0 */ + AM62PX_IOPAD(0x000c, PIN_INPUT, 0) /* (L25) OSPI0_D0 */ + AM62PX_IOPAD(0x0010, PIN_INPUT, 0) /* (N24) OSPI0_D1 */ + AM62PX_IOPAD(0x0014, PIN_INPUT, 0) /* (N25) OSPI0_D2 */ + AM62PX_IOPAD(0x0018, PIN_INPUT, 0) /* (M24) OSPI0_D3 */ + AM62PX_IOPAD(0x001c, PIN_INPUT, 0) /* (N21) OSPI0_D4 */ + AM62PX_IOPAD(0x0020, PIN_INPUT, 0) /* (N22) OSPI0_D5 */ + AM62PX_IOPAD(0x0024, PIN_INPUT, 0) /* (P21) OSPI0_D6 */ + AM62PX_IOPAD(0x0028, PIN_INPUT, 0) /* (N20) OSPI0_D7 */ + AM62PX_IOPAD(0x0008, PIN_INPUT, 0) /* (P22) OSPI0_DQS */ + >; + bootph-all; + }; + + usr_led_pins_default: usr-led-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x0244, PIN_INPUT, 7) /* (D24) MMC1_SDWP.GPIO1_49 */ + >; + }; + + vddshv_sdio_pins_default: vddshvr-sdio-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x007c, PIN_INPUT, 7) /* (Y25) GPMC0_CLK.GPIO0_31 */ + >; + bootph-all; + }; + + wlan_en_pins_default: wlan-en-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x0124, PIN_INPUT, 7) /* (J25) MMC2_SDCD.GPIO0_71 */ + >; + }; + + main_dpi_pins_default: main-dpi-default-pins { + pinctrl-single,pins = < + AM62PX_IOPAD(0x0100, PIN_OUTPUT, 0) /* (W20) VOUT0_VSYNC */ + AM62PX_IOPAD(0x00f8, PIN_OUTPUT, 0) /* (AC20) VOUT0_HSYNC */ + AM62PX_IOPAD(0x0104, PIN_OUTPUT, 0) /* (Y21) VOUT0_PCLK */ + AM62PX_IOPAD(0x00fc, PIN_OUTPUT, 0) /* (W21) VOUT0_DE */ + AM62PX_IOPAD(0x00b8, PIN_OUTPUT, 0) /* (AE24) VOUT0_DATA0 */ + AM62PX_IOPAD(0x00bc, PIN_OUTPUT, 0) /* (W23) VOUT0_DATA1 */ + AM62PX_IOPAD(0x00c0, PIN_OUTPUT, 0) /* (AA23) VOUT0_DATA2 */ + AM62PX_IOPAD(0x00c4, PIN_OUTPUT, 0) /* (Y23) VOUT0_DATA3 */ + AM62PX_IOPAD(0x00c8, PIN_OUTPUT, 0) /* (AB23) VOUT0_DATA4 */ + AM62PX_IOPAD(0x00cc, PIN_OUTPUT, 0) /* (AD23) VOUT0_DATA5 */ + AM62PX_IOPAD(0x00d0, PIN_OUTPUT, 0) /* (AC23) VOUT0_DATA6 */ + AM62PX_IOPAD(0x00d4, PIN_OUTPUT, 0) /* (AE23) VOUT0_DATA7 */ + AM62PX_IOPAD(0x00d8, PIN_OUTPUT, 0) /* (AE22) VOUT0_DATA8 */ + AM62PX_IOPAD(0x00dc, PIN_OUTPUT, 0) /* (AC22) VOUT0_DATA9 */ + AM62PX_IOPAD(0x00e0, PIN_OUTPUT, 0) /* (W22) VOUT0_DATA10 */ + AM62PX_IOPAD(0x00e4, PIN_OUTPUT, 0) /* (AE21) VOUT0_DATA11 */ + AM62PX_IOPAD(0x00e8, PIN_OUTPUT, 0) /* (AD21) VOUT0_DATA12 */ + AM62PX_IOPAD(0x00ec, PIN_OUTPUT, 0) /* (AC21) VOUT0_DATA13 */ + AM62PX_IOPAD(0x00f0, PIN_OUTPUT, 0) /* (AA20) VOUT0_DATA14 */ + AM62PX_IOPAD(0x00f4, PIN_OUTPUT, 0) /* (Y20) VOUT0_DATA15 */ + AM62PX_IOPAD(0x005c, PIN_OUTPUT, 1) /* (AC25) GPMC0_AD8.VOUT0_DATA16 */ + AM62PX_IOPAD(0x0060, PIN_OUTPUT, 1) /* (AB25) GPMC0_AD9.VOUT0_DATA17 */ + AM62PX_IOPAD(0x0064, PIN_OUTPUT, 1) /* (AA25) GPMC0_AD10.VOUT0_DATA18 */ + AM62PX_IOPAD(0x0068, PIN_OUTPUT, 1) /* (W24) GPMC0_AD11.VOUT0_DATA19 */ + AM62PX_IOPAD(0x006c, PIN_OUTPUT, 1) /* (Y24) GPMC0_AD12.VOUT0_DATA20 */ + AM62PX_IOPAD(0x0070, PIN_OUTPUT, 1) /* (AD25) GPMC0_AD13.VOUT0_DATA21 */ + AM62PX_IOPAD(0x0074, PIN_OUTPUT, 1) /* (AB24) GPMC0_AD14.VOUT0_DATA22 */ + AM62PX_IOPAD(0x0078, PIN_OUTPUT, 1) /* (AC24) GPMC0_AD15.VOUT0_DATA23 */ + AM62PX_IOPAD(0x009c, PIN_OUTPUT, 1) /* (AD24) GPMC0_WAIT1.VOUT0_EXTPCLKIN */ >; }; }; -&main_uart0 { +&main_i2c0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c0_pins_default>; + clock-frequency = <400000>; + + typec_pd0: usb-power-controller@3f { + compatible = "ti,tps6598x"; + reg = <0x3f>; + + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + self-powered; + data-role = "dual"; + power-role = "sink"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + usb_con_hs: endpoint { + remote-endpoint = <&usb0_hs_ep>; + }; + }; + }; + }; + }; +}; + +&main_i2c1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_pins_default>; + clock-frequency = <100000>; bootph-all; + + tlv320aic3106: audio-codec@1b { + #sound-dai-cells = <0>; + compatible = "ti,tlv320aic3106"; + reg = <0x1b>; + ai3x-micbias-vg = <1>; /* 2.0V */ + }; + + exp1: gpio@22 { + compatible = "ti,tca6424"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "OLDI_INT#", "x8_NAND_DETECT", + "UART1_FET_SEL", "MMC1_SD_EN", + "VPP_EN", "EXP_PS_3V3_EN", + "UART1_FET_BUF_EN", "EXP_HAT_DETECT", + "DSI_GPIO0", "DSI_GPIO1", + "OLDI_EDID", "BT_UART_WAKE_SOC_3V3", + "USB_TYPEA_OC_INDICATION", "CSI_GPIO0", + "CSI_GPIO1", "WLAN_ALERTn", + "HDMI_INTn", "TEST_GPIO2", + "MCASP1_FET_EN", "MCASP1_BUF_BT_EN", + "MCASP1_FET_SEL", "DSI_EDID", + "PD_I2C_IRQ", "IO_EXP_TEST_LED"; + + interrupt-parent = <&main_gpio1>; + interrupts = <23 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&main_gpio1_ioexp_intr_pins_default>; + bootph-all; + }; + + exp2: gpio@23 { + compatible = "ti,tca6424"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "BT_EN_SOC", "EXP_PS_5V0_EN", + "", "", + "", "", + "", "", + "WL_LT_EN", "", + "TP3", "TP6", + "TP4", "TP7", + "TP5", "TP8", + "SoC_I2C2_MCAN_SEL", "GPIO_HDMI_RSTn", + "GPIO_CPSW2_RST", "GPIO_CPSW1_RST", + "GPIO_OLDI_RSTn", "GPIO_AUD_RSTn", + "GPIO_eMMC_RSTn", "SoC_WLAN_SDIO_RST"; + }; + + sii9022: bridge-hdmi@3b { + compatible = "sil,sii9022"; + reg = <0x3b>; + interrupt-parent = <&exp1>; + interrupts = <16 IRQ_TYPE_EDGE_FALLING>; + #sound-dai-cells = <0>; + sil,i2s-data-lanes = < 0 >; + + hdmi_tx_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* + * HDMI can be serviced with 3 potential VPs - + * (DSS0 VP1 / DSS1 VP0 / DSS1 VP1). + * For now, we will service it with DSS0 VP1. + */ + port@0 { + reg = <0>; + + sii9022_in: endpoint { + remote-endpoint = <&dss0_dpi1_out>; + }; + }; + + port@1 { + reg = <1>; + + sii9022_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; +}; + +&main_i2c2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c2_pins_default>; + clock-frequency = <400000>; +}; + +&sdhci0 { + status = "okay"; + ti,driver-strength-ohm = <50>; + disable-wp; + bootph-all; +}; + +&sdhci1 { + /* SD/MMC */ + status = "okay"; + vmmc-supply = <&vdd_mmc1>; + vqmmc-supply = <&vddshv_sdio>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mmc1_pins_default>; + disable-wp; + bootph-all; +}; + +&cpsw3g { + pinctrl-names = "default"; + pinctrl-0 = <&main_rgmii1_pins_default>, + <&main_rgmii2_pins_default>; +}; + +&cpsw_port1 { + phy-mode = "rgmii-rxid"; + phy-handle = <&cpsw3g_phy0>; +}; + +&cpsw_port2 { + phy-mode = "rgmii-rxid"; + phy-handle = <&cpsw3g_phy1>; +}; + +&cpsw3g_mdio { + pinctrl-names = "default"; + pinctrl-0 = <&main_mdio1_pins_default>; + status = "okay"; + + cpsw3g_phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + ti,min-output-impedance; + }; + + cpsw3g_phy1: ethernet-phy@1 { + reg = <1>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + ti,min-output-impedance; + }; +}; + +&usbss0 { + status = "okay"; + ti,vbus-divider; +}; + +&usbss1 { + status = "okay"; + ti,vbus-divider; +}; + +&usb0 { + usb-role-switch; + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + usb0_hs_ep: endpoint { + remote-endpoint = <&usb_con_hs>; + }; + }; +}; + +&usb1 { + dr_mode = "host"; + pinctrl-names = "default"; + pinctrl-0 = <&main_usb1_pins_default>; +}; + +&mcasp1 { + status = "okay"; + #sound-dai-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&main_mcasp1_pins_default>; + + op-mode = <0>; /* MCASP_IIS_MODE */ + tdm-slots = <2>; + + serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ + 1 0 2 0 + 0 0 0 0 + 0 0 0 0 + 0 0 0 0 + >; + tx-num-evt = <0>; + rx-num-evt = <0>; +}; + +&fss { + bootph-all; +}; + +&ospi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&ospi0_pins_default>; + bootph-all; + + flash@0{ + compatible = "jedec,spi-nor"; + reg = <0x0>; + spi-tx-bus-width = <8>; + spi-rx-bus-width = <8>; + spi-max-frequency = <25000000>; + cdns,tshsl-ns = <60>; + cdns,tsd2d-ns = <60>; + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <4>; + bootph-all; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + bootph-all; + + partition@0 { + label = "ospi.tiboot3"; + reg = <0x00 0x80000>; + }; + + partition@80000 { + label = "ospi.tispl"; + reg = <0x80000 0x200000>; + }; + + partition@280000 { + label = "ospi.u-boot"; + reg = <0x280000 0x400000>; + }; + + partition@680000 { + label = "ospi.env"; + reg = <0x680000 0x40000>; + }; + + partition@6c0000 { + label = "ospi.env.backup"; + reg = <0x6c0000 0x40000>; + }; + + partition@800000 { + label = "ospi.rootfs"; + reg = <0x800000 0x37c0000>; + }; + + partition@3fc0000 { + label = "ospi.phypattern"; + reg = <0x3fc0000 0x40000>; + bootph-all; + }; + }; + }; +}; + +&mailbox0_cluster0 { + mbox_r5_0: mbox-r5-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + +&mailbox0_cluster1 { + mbox_mcu_r5_0: mbox-mcu-r5-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + +&wkup_r5fss0 { + status = "okay"; +}; + +&wkup_r5fss0_core0 { + mboxes = <&mailbox0_cluster0 &mbox_r5_0>; + memory-region = <&wkup_r5fss0_core0_dma_memory_region>, + <&wkup_r5fss0_core0_memory_region>; +}; + +&mcu_r5fss0 { + status = "okay"; +}; + +&mcu_r5fss0_core0 { + mboxes = <&mailbox0_cluster1 &mbox_mcu_r5_0>; + memory-region = <&mcu_r5fss0_core0_dma_memory_region>, + <&mcu_r5fss0_core0_memory_region>; +}; + +&main_uart0 { pinctrl-names = "default"; pinctrl-0 = <&main_uart0_pins_default>; + interrupts-extended = <&gic500 GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>, + <&main_pmx0 0x1c8>; /* (D14) UART0_RXD PADCONFIG114 */ + interrupt-names = "irq", "wakeup"; status = "okay"; + bootph-all; }; &main_uart1 { @@ -88,29 +787,56 @@ pinctrl-0 = <&main_uart1_pins_default>; /* Main UART1 is used by TIFS firmware */ status = "reserved"; -}; - -&cbass_mcu { bootph-all; }; &mcu_pmx0 { bootph-all; + wkup_uart0_pins_default: wkup-uart0-default-pins { - bootph-all; pinctrl-single,pins = < - AM62PX_MCU_IOPAD(0x02c, PIN_INPUT, 0) /* (C7) WKUP_UART0_CTSn */ - AM62PX_MCU_IOPAD(0x030, PIN_OUTPUT, 0) /* (C6) WKUP_UART0_RTSn */ AM62PX_MCU_IOPAD(0x024, PIN_INPUT, 0) /* (D8) WKUP_UART0_RXD */ AM62PX_MCU_IOPAD(0x028, PIN_OUTPUT, 0) /* (D7) WKUP_UART0_TXD */ >; + bootph-all; }; }; &wkup_uart0 { /* WKUP UART0 is used by DM firmware */ - bootph-all; pinctrl-names = "default"; pinctrl-0 = <&wkup_uart0_pins_default>; status = "reserved"; + bootph-all; +}; + +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */ +&mcu_gpio0 { + status = "reserved"; +}; + +&mcu_gpio_intr { + status = "reserved"; +}; + +&dss_oldi_io_ctrl { + bootph-all; +}; + +&dss0 { + bootph-all; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_dpi_pins_default>; +}; + +&dss0_ports { + /* DSS0-VP2: DPI/HDMI Output */ + hdmi0_dss: port@1 { + reg = <1>; + + dss0_dpi1_out: endpoint { + remote-endpoint = <&sii9022_in>; + }; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p5-sk-eqep.dtso b/arch/arm64/boot/dts/ti/k3-am62p5-sk-eqep.dtso --- a/arch/arm64/boot/dts/ti/k3-am62p5-sk-eqep.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk-eqep.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for enabling EQEP on AM62P5-SK + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&main_pmx0 { + main_eqep0_pins_default: main-eqep0-pins-default { + pinctrl-single,pins = < + AM62PX_IOPAD(0x0194, PIN_INPUT, 8) /* (D25) MCASP0_AXR3.EQEP0_A */ + AM62PX_IOPAD(0x0198, PIN_INPUT, 8) /* (E25) MCASP0_AXR2.EQEP0_B */ + AM62PX_IOPAD(0x01a0, PIN_INPUT, 8) /* (F23) MCASP0_AXR0.EQEP0_I */ + AM62PX_IOPAD(0x019c, PIN_INPUT, 8) /* (E24) MCASP0_AXR1.EQEP0_S */ + >; + }; +}; + +&main_i2c1 { + gpio@22 { + p02-hog { + /* P02 - UART1_FET_SEL */ + gpio-hog; + gpios = <2 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "UART1_FET_SEL"; + }; + }; +}; + +&main_uart1 { + /* Disable FW debug logs */ + status = "disabled"; +}; + +&eqep0 { + status = "okay"; + /* EQEP0 A & B available on pins 40 & 38 of J4 header */ + pinctrl-names = "default"; + pinctrl-0 = <&main_eqep0_pins_default>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p5-sk-m2-cc3301.dtso b/arch/arm64/boot/dts/ti/k3-am62p5-sk-m2-cc3301.dtso --- a/arch/arm64/boot/dts/ti/k3-am62p5-sk-m2-cc3301.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk-m2-cc3301.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * DT Overlay for M.2-CC3301 board to connect to the M.2 connector on AM625-SK. + * + * Product page for board: https://www.ti.com/tool/M2-CC3301 + * CC3301 Datasheet: https://www.ti.com/lit/ds/symlink/cc3301.pdf + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&{/} { + wlan_lten: regulator-30 { + compatible = "regulator-fixed"; + regulator-name = "wlan_lten"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vdd_mmc1>; + gpios = <&exp2 8 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + wlan_en: regulator-31 { + compatible = "regulator-fixed"; + regulator-name = "wlan_en"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&wlan_lten>; + enable-active-high; + gpios = <&main_gpio0 71 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&wlan_en_pins_default>; + }; +}; + +&sdhci2 { + status = "okay"; + bootph-all; + vmmc-supply = <&wlan_en>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mmc2_pins_default>; + bus-width = <4>; + non-removable; + ti,fails-without-test-cd; + cap-power-off-card; + keep-power-in-suspend; + ti,driver-strength-ohm = <50>; + + #address-cells = <1>; + #size-cells = <0>; + cc33xx: cc33xx@0 { + compatible = "ti,cc3301"; + reg = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&main_wlirq_pins_default>; + interrupt-parent = <&main_gpio0>; + interrupts = <72 IRQ_TYPE_EDGE_FALLING>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p5-sk-mcan.dtso b/arch/arm64/boot/dts/ti/k3-am62p5-sk-mcan.dtso --- a/arch/arm64/boot/dts/ti/k3-am62p5-sk-mcan.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk-mcan.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT overlay for enabling MCAN for AM62P-SK + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&{/} { + transceiver1: can-phy0 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; + + transceiver2: can-phy1 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; + + transceiver3: can-phy2 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; + + transceiver4: can-phy3 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; +}; + +&main_pmx0 { + main_mcan0_pins_default: main-mcan0-pins-default { + pinctrl-single,pins = < + AM62PX_IOPAD(0x01dc, PIN_INPUT, 0) /* (F20) MCAN0_RX */ + AM62PX_IOPAD(0x01d8, PIN_OUTPUT, 0) /* (B23) MCAN0_TX */ + >; + }; + + main_mcan1_pins_default: main-mcan1-pins-default { + pinctrl-single,pins = < + AM62PX_IOPAD(0x00b4, PIN_INPUT, 5) /* (U25) GPMC0_CSn3.MCAN1_RX */ + AM62PX_IOPAD(0x00b0, PIN_OUTPUT, 5) /* (T22) GPMC0_CSn2.MCAN1_TX */ + >; + }; +}; + +&mcu_pmx0 { + mcu_mcan0_pins_default: mcu-mcan0-pins-default { + pinctrl-single,pins = < + AM62PX_MCU_IOPAD(0x0038, PIN_INPUT, 0) /* (D6) MCU_MCAN0_RX */ + AM62PX_MCU_IOPAD(0x0034, PIN_OUTPUT, 0) /* (E8) MCU_MCAN0_TX */ + >; + }; + + mcu_mcan1_pins_default: mcu-mcan1-pins-default { + pinctrl-single,pins = < + AM62PX_MCU_IOPAD(0x0040, PIN_INPUT, 0) /* (E7) MCU_MCAN1_RX */ + AM62PX_MCU_IOPAD(0x003c, PIN_OUTPUT, 0) /* (F8) MCU_MCAN1_TX */ + >; + }; +}; + +&main_i2c2{ + /* + * main_i2c2 is using (U25) and (T22) + * so disable to use main_mcan1 + */ + status = "disabled"; +}; + +&main_i2c1 { + /* + * Unset GPIO SoC_I2C2_MCAN_SEL to + * route MCAN1 signals to MCAN1 HDR + */ + gpio@23 { + p20-hog { + /* P20 - SoC_I2C2_MCAN_SEL */ + gpio-hog; + gpios = <16 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "SoC_I2C2_MCAN_SEL"; + }; + }; +}; + +&main_mcan0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan0_pins_default>; + phys = <&transceiver1>; +}; + +&main_mcan1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan1_pins_default>; + phys = <&transceiver2>; +}; + +&mcu_mcan0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_pins_default>; + phys = <&transceiver3>; +}; + +&mcu_mcan1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan1_pins_default>; + phys = <&transceiver4>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p5-sk-microtips-mf070zima-lcd3.dtso b/arch/arm64/boot/dts/ti/k3-am62p5-sk-microtips-mf070zima-lcd3.dtso --- a/arch/arm64/boot/dts/ti/k3-am62p5-sk-microtips-mf070zima-lcd3.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk-microtips-mf070zima-lcd3.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * Microtips integrated DSI panel (MF-070ZIMACAA0) and touch DT overlay for AM62P5-SK + * + * AM62P5-SK EVM: https://www.ti.com/tool/SK-AM62P-LP + * Panel: https://simplespec.microtipsusa.com/uploads/spec/datasheetFile/3004/13-070ZIMACAA0-S_V1.1_20231120.pdf + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&dphy_tx0 { + status = "okay"; +}; + +&dss1 { + status = "okay"; +}; + +&dss1_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* DSS1-VP1: DSI Output */ + port@1 { + reg = <1>; + + dss1_dpi1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; +}; + +&dsi0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dsi0_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + + port@1 { + reg = <1>; + + dsi0_in: endpoint { + remote-endpoint = <&dss1_dpi1_out>; + }; + }; + }; + + dsi_panel0: panel-dsi@0 { + compatible = "microtips,mf-070zimacaa0", "ilitek,ili9881c"; + reg = <0>; + + port { + panel_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + }; +}; + +&main_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@41 { + compatible = "ilitek,ili251x"; + reg = <0x41>; + reset-gpios = <&exp1 8 GPIO_ACTIVE_LOW>; + interrupt-parent = <&exp1>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p5-sk-microtips-mf101hie-panel.dtso b/arch/arm64/boot/dts/ti/k3-am62p5-sk-microtips-mf101hie-panel.dtso --- a/arch/arm64/boot/dts/ti/k3-am62p5-sk-microtips-mf101hie-panel.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk-microtips-mf101hie-panel.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * Microtips integrated OLDI panel (MF-101HIEBCAF0) and touch DT overlay for AM62P5-SK + * + * Panel datasheet: https://simplespec.microtipsusa.com/uploads/spec/datasheetFile/2588/13-101HIEBCAF0-S_V1.1_20221104.pdf + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&{/} { + display { + compatible = "microtips,mf-101hiebcaf0", "panel-simple"; + + /* + * Note that the OLDI TX 0 transmits the odd set of pixels + * while the OLDI TX 1 transmits the even set. This is a + * fixed configuration in the IP integration and is not + * changeable. The properties, "dual-lvds-odd-pixels" and + * "dual-lvds-even-pixels" have been used to merely + * identify if a Dual Link configuration is required. + * Swapping them will cause an error in the dss oldi driver. + */ + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + + lcd_in0: endpoint { + remote-endpoint = <&oldi0_dss0_out>; + }; + }; + + port@1 { + reg = <1>; + dual-lvds-even-pixels; + + lcd_in1: endpoint { + remote-endpoint = <&oldi1_dss0_out>; + }; + }; + }; + }; +}; + +&dss0 { + status = "okay"; +}; + +&oldi0_dss0 { + status = "okay"; +}; + +&oldi1_dss0 { + status = "okay"; +}; + +&oldi0_dss0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + oldi0_dss0_in: endpoint { + remote-endpoint = <&dss0_dpi0_out0>; + }; + }; + + port@1 { + reg = <1>; + + oldi0_dss0_out: endpoint { + remote-endpoint = <&lcd_in0>; + }; + }; +}; + +&oldi1_dss0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + oldi1_dss0_in: endpoint { + remote-endpoint = <&dss0_dpi0_out1>; + }; + }; + + port@1 { + reg = <1>; + + oldi1_dss0_out: endpoint { + remote-endpoint = <&lcd_in1>; + }; + }; +}; + +&dss0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VP1: Output to OLDI */ + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + dss0_dpi0_out0: endpoint@0 { + reg = <0>; + remote-endpoint = <&oldi0_dss0_in>; + }; + + dss0_dpi0_out1: endpoint@1 { + reg = <1>; + remote-endpoint = <&oldi1_dss0_in>; + }; + }; +}; + +&main_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@41 { + compatible = "ilitek,ili251x"; + reg = <0x41>; + interrupt-parent = <&exp1>; + interrupts = <0 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&exp2 20 GPIO_ACTIVE_LOW>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p5-sk-microtips-mf103hie-lcd2.dtso b/arch/arm64/boot/dts/ti/k3-am62p5-sk-microtips-mf103hie-lcd2.dtso --- a/arch/arm64/boot/dts/ti/k3-am62p5-sk-microtips-mf103hie-lcd2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk-microtips-mf103hie-lcd2.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * Microtips integrated OLDI panel (MF-103HIEB0GA0) (SK-LCD2) DT overlay for AM62PS5-SK + * + * Panel datasheet: https://simplespec.microtipsusa.com/uploads/spec/datasheetFile/2660/13-103HIEB0GA0-S_V1.0_20211206.pdf + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&{/} { + display { + compatible = "microtips,mf-103hieb0ga0", "panel-simple"; + + /* + * Note that the OLDI TX 0 transmits the odd set of pixels + * while the OLDI TX 1 transmits the even set. This is a + * fixed configuration in the IP integration and is not + * changeable. The properties, "dual-lvds-odd-pixels" and + * "dual-lvds-even-pixels" have been used to merely + * identify if a Dual Link configuration is required. + * Swapping them will cause an error in the dss oldi driver. + */ + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + + lcd_in0: endpoint { + remote-endpoint = <&oldi0_dss0_out>; + }; + }; + + port@1 { + reg = <1>; + dual-lvds-even-pixels; + + lcd_in1: endpoint { + remote-endpoint = <&oldi1_dss0_out>; + }; + }; + }; + }; +}; + +&dss0 { + status = "okay"; +}; + +&oldi0_dss0 { + status = "okay"; +}; + +&oldi1_dss0 { + status = "okay"; +}; + +&oldi0_dss0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + oldi0_dss0_in: endpoint { + remote-endpoint = <&dss0_dpi0_out0>; + }; + }; + + port@1 { + reg = <1>; + + oldi0_dss0_out: endpoint { + remote-endpoint = <&lcd_in0>; + }; + }; +}; + +&oldi1_dss0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + oldi1_dss0_in: endpoint { + remote-endpoint = <&dss0_dpi0_out1>; + }; + }; + + port@1 { + reg = <1>; + + oldi1_dss0_out: endpoint { + remote-endpoint = <&lcd_in1>; + }; + }; +}; + +&dss0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VP1: Output to OLDI */ + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + dss0_dpi0_out0: endpoint@0 { + reg = <0>; + remote-endpoint = <&oldi0_dss0_in>; + }; + + dss0_dpi0_out1: endpoint@1 { + reg = <1>; + remote-endpoint = <&oldi1_dss0_in>; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p5-sk-rpi-hdr-ehrpwm.dtso b/arch/arm64/boot/dts/ti/k3-am62p5-sk-rpi-hdr-ehrpwm.dtso --- a/arch/arm64/boot/dts/ti/k3-am62p5-sk-rpi-hdr-ehrpwm.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk-rpi-hdr-ehrpwm.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for enabling RPi header with GPIOs and ePWMs on AM62P-SK + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&main_pmx0 { + rpi_header_gpio0_pins_default: rpi-header-gpio0-pins-default { + pinctrl-single,pins = < + AM62PX_IOPAD(0x0038, PIN_INPUT, 7) /* (L23) OSPI0_CSn3.GPIO0_14 */ + AM62PX_IOPAD(0x0088, PIN_INPUT, 7) /* (R24) GPMC0_OEn_REn.GPIO0_33 */ + AM62PX_IOPAD(0x0094, PIN_INPUT, 7) /* (T24) GPMC0_BE1n.GPIO0_36 */ + AM62PX_IOPAD(0x009c, PIN_INPUT, 7) /* (AD24) GPMC0_WAIT1.GPIO0_38 */ + AM62PX_IOPAD(0x00a0, PIN_INPUT, 7) /* (P24) GPMC0_WPn.GPIO0_39 */ + AM62PX_IOPAD(0x00a4, PIN_INPUT, 7) /* (P25) GPMC0_DIR.GPIO0_40 */ + AM62PX_IOPAD(0x00a8, PIN_INPUT, 7) /* (T23) GPMC0_CSn0.GPIO0_41 */ + AM62PX_IOPAD(0x00ac, PIN_INPUT, 7) /* (U23) GPMC0_CSn1.GPIO0_42 */ + >; + }; + + rpi_header_gpio1_pins_default: rpi-header-gpio1-pins-default { + pinctrl-single,pins = < + AM62PX_IOPAD(0x01a4, PIN_INPUT, 7) /* (F24) MCASP0_ACLKX.GPIO1_11 */ + AM62PX_IOPAD(0x01bc, PIN_INPUT, 7) /* (B21) SPI0_CLK.GPIO1_17 */ + AM62PX_IOPAD(0x01c0, PIN_INPUT, 7) /* (B20) SPI0_D0.GPIO1_18 */ + AM62PX_IOPAD(0x01c4, PIN_INPUT, 7) /* (C21) SPI0_D1.GPIO1_19 */ + AM62PX_IOPAD(0x01d0, PIN_INPUT, 7) /* (A23) UART0_CTSn.GPIO1_22 */ + AM62PX_IOPAD(0x01d8, PIN_INPUT, 7) /* (B23) MCAN0_TX.GPIO1_24 */ + AM62PX_IOPAD(0x01dc, PIN_INPUT, 7) /* (F20) MCAN0_RX.GPIO1_25 */ + >; + }; + + rpi_header_ehrpwm0_pins_default: rpi-header-ehrpwm0-pins-default { + pinctrl-single,pins = < + AM62PX_IOPAD(0x01b4, PIN_OUTPUT, 2) /* (D20) SPI0_CS0.EHRPWM0_A */ + AM62PX_IOPAD(0x01b8, PIN_OUTPUT, 2) /* (E20) SPI0_CS1.EHRPWM0_B */ + >; + }; + + rpi_header_ehrpwm1_pins_default: rpi-header-ehrpwm1-pins-default { + pinctrl-single,pins = < + AM62PX_IOPAD(0x019c, PIN_OUTPUT, 6) /* (E24) MCASP0_AXR1.EHRPWM1_A */ + AM62PX_IOPAD(0x01a0, PIN_OUTPUT, 6) /* (F23) MCASP0_AXR0.EHRPWM1_B */ + >; + }; +}; + +&main_i2c1 { + gpio@22 { + p02-hog { + /* P02 - UART1_FET_SEL */ + gpio-hog; + gpios = <2 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "UART1_FET_SEL"; + }; + + p05-hog { + /* P05 - EXP_PS_3V3_EN */ + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "EXP_PS_3V3_EN"; + }; + }; + + gpio@23 { + p01-hog { + /* P01 - EXP_PS_5V0_EN */ + gpio-hog; + gpios = <1 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "EXP_PS_5V0_EN"; + }; + }; +}; + + +//&dss0 { +// /* Conflict with GPIO0_38 */ +// status = "disabled"; +//}; + +&epwm0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm0_pins_default>; +}; + +&epwm1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm1_pins_default>; +}; + +&main_gpio0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_gpio0_pins_default>; +}; + +&main_gpio1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_gpio1_pins_default>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p.dtsi b/arch/arm64/boot/dts/ti/k3-am62p.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62p.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62p.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree Source for AM62P SoC Family * - * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ */ #include @@ -45,10 +45,10 @@ }; cbass_main: bus@f0000 { - bootph-all; compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; + bootph-all; ranges = <0x00 0x000f0000 0x00 0x000f0000 0x00 0x00030000>, /* Main MMRs */ <0x00 0x00420000 0x00 0x00420000 0x00 0x00001000>, /* ESM0 */ @@ -59,12 +59,17 @@ <0x00 0x01000000 0x00 0x01000000 0x00 0x01b28400>, /* First peripheral window */ <0x00 0x08000000 0x00 0x08000000 0x00 0x00200000>, /* Main CPSW */ <0x00 0x0e000000 0x00 0x0e000000 0x00 0x01d20000>, /* Second peripheral window */ - <0x00 0x0fd00000 0x00 0x0fd00000 0x00 0x00020000>, /* GPU */ + <0x00 0x0fd80000 0x00 0x0fd80000 0x00 0x00080000>, /* GPU */ <0x00 0x20000000 0x00 0x20000000 0x00 0x0a008000>, /* Third peripheral window */ <0x00 0x30040000 0x00 0x30040000 0x00 0x00080000>, /* PRUSS-M */ <0x00 0x30101000 0x00 0x30101000 0x00 0x00010100>, /* CSI window */ + <0x00 0x301C0000 0x00 0x301C0000 0x00 0x00001000>, /* DPHY-TX */ <0x00 0x30200000 0x00 0x30200000 0x00 0x00010000>, /* DSS */ <0x00 0x30210000 0x00 0x30210000 0x00 0x00010000>, /* VPU */ + <0x00 0x30220000 0x00 0x30220000 0x00 0x00010000>, /* DSS1 */ + <0x00 0x30270000 0x00 0x30270000 0x00 0x00010000>, /* DSI Wrapper */ + <0x00 0x30300000 0x00 0x30300000 0x00 0x00001000>, /* MCRC64 */ + <0x00 0x30500000 0x00 0x30500000 0x00 0x00100000>, /* DSI Config */ <0x00 0x31000000 0x00 0x31000000 0x00 0x00050000>, /* USB0 DWC3 Core window */ <0x00 0x31100000 0x00 0x31100000 0x00 0x00050000>, /* USB1 DWC3 Core window */ <0x00 0x40900000 0x00 0x40900000 0x00 0x00030000>, /* SA3UL */ @@ -100,10 +105,10 @@ <0x00 0x79020000 0x00 0x79020000 0x00 0x00008000>, /* MCU R5 BTCM */ <0x00 0x79100000 0x00 0x79100000 0x00 0x00040000>, /* MCU IRAM0 */ <0x00 0x79140000 0x00 0x79140000 0x00 0x00040000>; /* MCU IRAM1 */ + bootph-all; }; cbass_wakeup: bus@b00000 { - bootph-all; compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; @@ -112,11 +117,34 @@ <0x00 0x43000000 0x00 0x43000000 0x00 0x00020000>, /* WKUP CTRL MMR */ <0x00 0x78000000 0x00 0x78000000 0x00 0x00008000>, /* DM R5 ATCM*/ <0x00 0x78100000 0x00 0x78100000 0x00 0x00008000>; /* DM R5 BTCM*/ + bootph-all; }; }; + + dss0_vp1_clk: clock-divider-oldi-dss0 { + compatible = "fixed-factor-clock"; + clocks = <&k3_clks 186 0>; + #clock-cells = <0>; + clock-div = <7>; + clock-mult = <1>; + }; + + dss1_vp1_clk: clock-divider-oldi-dss1 { + compatible = "fixed-factor-clock"; + clocks = <&k3_clks 232 0>; + #clock-cells = <0>; + clock-div = <7>; + clock-mult = <1>; + }; + + #include "k3-am62p-thermal.dtsi" }; /* Now include peripherals for each bus segment */ #include "k3-am62p-main.dtsi" #include "k3-am62p-mcu.dtsi" #include "k3-am62p-wakeup.dtsi" + +&dmsc { + ti,partial-io-wakeup-sources = <&mcu_mcan0>, <&mcu_mcan1>, <&mcu_uart0>, <&wkup_uart0>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi b/arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -317,7 +317,6 @@ &sdhci0 { pinctrl-names = "default"; pinctrl-0 = <&main_mmc0_pins_default>; - ti,driver-strength-ohm = <50>; disable-wp; non-removable; status = "okay"; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-main.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62p-main.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62p-main.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -1,7 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* - * Device Tree file for the AM62P main domain peripherals - * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * Device Tree file for the AM62P MAIN domain peripherals + * + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ */ &cbass_main { @@ -40,18 +41,42 @@ }; }; + main_conf: bus@100000 { + compatible = "simple-bus"; + reg = <0x00 0x00100000 0x00 0x20000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x00 0x00 0x00100000 0x20000>; + + phy_gmii_sel: phy@4044 { + compatible = "ti,am654-phy-gmii-sel"; + reg = <0x4044 0x8>; + #phy-cells = <1>; + }; + + epwm_tbclk: clock-controller@4130 { + compatible = "ti,am62-epwm-tbclk"; + reg = <0x4130 0x4>; + #clock-cells = <1>; + }; + + dss_oldi_io_ctrl: dss-oldi-io-ctrl@8600 { + compatible = "syscon"; + reg = <0x8600 0x200>; + }; + }; + dmss: bus@48000000 { - bootph-all; - compatible = "simple-mfd"; + compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; dma-ranges; ranges = <0x00 0x48000000 0x00 0x48000000 0x00 0x06400000>; + bootph-all; ti,sci-dev-id = <25>; secure_proxy_main: mailbox@4d000000 { - bootph-all; compatible = "ti,am654-secure-proxy"; #mbox-cells = <1>; reg-names = "target_data", "rt", "scfg"; @@ -60,11 +85,123 @@ <0x00 0x4a400000 0x00 0x80000>; interrupt-names = "rx_012"; interrupts = ; + bootph-all; + }; + + inta_main_dmss: interrupt-controller@48000000 { + compatible = "ti,sci-inta"; + reg = <0x00 0x48000000 0x00 0x100000>; + #interrupt-cells = <0>; + interrupt-controller; + interrupt-parent = <&gic500>; + msi-controller; + ti,sci = <&dmsc>; + ti,sci-dev-id = <28>; + ti,interrupt-ranges = <5 69 35>; + ti,unmapped-event-sources = <&main_bcdma>, <&main_pktdma>; + }; + + main_bcdma: dma-controller@485c0100 { + compatible = "ti,am64-dmss-bcdma"; + reg = <0x00 0x485c0100 0x00 0x100>, + <0x00 0x4c000000 0x00 0x20000>, + <0x00 0x4a820000 0x00 0x20000>, + <0x00 0x4aa40000 0x00 0x20000>, + <0x00 0x4bc00000 0x00 0x100000>, + <0x00 0x48600000 0x00 0x8000>, + <0x00 0x484a4000 0x00 0x2000>, + <0x00 0x484c2000 0x00 0x2000>, + <0x00 0x48420000 0x00 0x2000>; + reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "bchan"; + msi-parent = <&inta_main_dmss>; + #dma-cells = <3>; + + ti,sci = <&dmsc>; + ti,sci-dev-id = <26>; + ti,sci-rm-range-bchan = <0x20>; /* BLOCK_COPY_CHAN */ + ti,sci-rm-range-rchan = <0x21>; /* SPLIT_TR_RX_CHAN */ + ti,sci-rm-range-tchan = <0x22>; /* SPLIT_TR_TX_CHAN */ + bootph-all; + }; + + main_pktdma: dma-controller@485c0000 { + compatible = "ti,am64-dmss-pktdma"; + reg = <0x00 0x485c0000 0x00 0x100>, + <0x00 0x4a800000 0x00 0x20000>, + <0x00 0x4aa00000 0x00 0x40000>, + <0x00 0x4b800000 0x00 0x400000>, + <0x00 0x485e0000 0x00 0x10000>, + <0x00 0x484a0000 0x00 0x2000>, + <0x00 0x484c0000 0x00 0x2000>, + <0x00 0x48430000 0x00 0x1000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "rflow"; + msi-parent = <&inta_main_dmss>; + #dma-cells = <2>; + bootph-all; + + ti,sci = <&dmsc>; + ti,sci-dev-id = <30>; + ti,sci-rm-range-tchan = <0x23>, /* UNMAPPED_TX_CHAN */ + <0x24>, /* CPSW_TX_CHAN */ + <0x25>, /* SAUL_TX_0_CHAN */ + <0x26>; /* SAUL_TX_1_CHAN */ + ti,sci-rm-range-tflow = <0x10>, /* RING_UNMAPPED_TX_CHAN */ + <0x11>, /* RING_CPSW_TX_CHAN */ + <0x12>, /* RING_SAUL_TX_0_CHAN */ + <0x13>; /* RING_SAUL_TX_1_CHAN */ + ti,sci-rm-range-rchan = <0x29>, /* UNMAPPED_RX_CHAN */ + <0x2b>, /* CPSW_RX_CHAN */ + <0x2d>, /* SAUL_RX_0_CHAN */ + <0x2f>, /* SAUL_RX_1_CHAN */ + <0x31>, /* SAUL_RX_2_CHAN */ + <0x33>; /* SAUL_RX_3_CHAN */ + ti,sci-rm-range-rflow = <0x2a>, /* FLOW_UNMAPPED_RX_CHAN */ + <0x2c>, /* FLOW_CPSW_RX_CHAN */ + <0x2e>, /* FLOW_SAUL_RX_0/1_CHAN */ + <0x32>; /* FLOW_SAUL_RX_2/3_CHAN */ + }; + }; + + dmss_csi: bus@4e000000 { + compatible = "simple-bus"; + ranges = <0x00 0x4e000000 0x00 0x4e000000 0x00 0x408000>; + #address-cells = <2>; + #size-cells = <2>; + dma-ranges; + ti,sci-dev-id = <198>; + + inta_main_dmss_csi: interrupt-controller@4e400000 { + compatible = "ti,sci-inta"; + reg = <0x00 0x4e400000 0x00 0x8000>; + #interrupt-cells = <0>; + interrupt-controller; + interrupt-parent = <&gic500>; + msi-controller; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <200>; + ti,interrupt-ranges = <0 237 8>; + ti,unmapped-event-sources = <&main_bcdma_csi>; + }; + + main_bcdma_csi: dma-controller@4e230000 { + compatible = "ti,am62a-dmss-bcdma-csirx"; + reg = <0x00 0x4e230000 0x00 0x100>, + <0x00 0x4e180000 0x00 0x8000>, + <0x00 0x4e100000 0x00 0x10000>; + reg-names = "gcfg", "rchanrt", "ringrt"; + #dma-cells = <3>; + msi-parent = <&inta_main_dmss_csi>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <199>; + ti,sci-rm-range-rchan = <0x21>; }; }; dmsc: system-controller@44043000 { - bootph-all; compatible = "ti,k2g-sci"; ti,host-id = <12>; mbox-names = "rx", "tx"; @@ -72,37 +209,103 @@ <&secure_proxy_main 13>; reg-names = "debug_messages"; reg = <0x00 0x44043000 0x00 0xfe0>; + bootph-all; k3_pds: power-controller { - bootph-all; compatible = "ti,sci-pm-domain"; #power-domain-cells = <2>; + bootph-all; }; k3_clks: clock-controller { - bootph-all; compatible = "ti,k2g-sci-clk"; #clock-cells = <2>; + bootph-all; }; k3_reset: reset-controller { - bootph-all; compatible = "ti,sci-reset"; #reset-cells = <2>; + bootph-all; }; }; - main_pmx0: pinctrl@f4000 { + crypto: crypto@40900000 { + compatible = "ti,am62-sa3ul"; + reg = <0x00 0x40900000 0x00 0x1200>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x40900000 0x00 0x40900000 0x00 0x30000>; + + dmas = <&main_pktdma 0xf501 0>, <&main_pktdma 0x7506 0>, + <&main_pktdma 0x7507 0>; + dma-names = "tx", "rx1", "rx2"; + }; + + crc: crc@30300000 { + compatible = "ti,am62-mcrc64"; + reg = <0x00 0x30300000 0x00 0x1000>; + clocks = <&k3_clks 116 0>; + power-domains = <&k3_pds 116 TI_SCI_PD_EXCLUSIVE>; + }; + + secure_proxy_sa3: mailbox@43600000 { + compatible = "ti,am654-secure-proxy"; + #mbox-cells = <1>; + reg-names = "target_data", "rt", "scfg"; + reg = <0x00 0x43600000 0x00 0x10000>, + <0x00 0x44880000 0x00 0x20000>, + <0x00 0x44860000 0x00 0x20000>; + /* + * Marked Disabled: + * Node is incomplete as it is meant for bootloaders and + * firmware on non-MPU processors + */ + status = "disabled"; bootph-all; - compatible = "pinctrl-single"; + }; + + main_pmx0: pinctrl@f4000 { + compatible = "ti,am654-padconf", "pinctrl-single"; reg = <0x00 0xf4000 0x00 0x2ac>; #pinctrl-cells = <1>; pinctrl-single,register-width = <32>; pinctrl-single,function-mask = <0xffffffff>; + pinctrl-single,gpio-range = + <&main_pmx0_range 0 32 (PIN_INPUT | PIN_GPIO_MUX_MODE)>, + <&main_pmx0_range 33 92 (PIN_INPUT | PIN_GPIO_MUX_MODE)>, + <&main_pmx0_range 137 5 (PIN_INPUT | PIN_GPIO_MUX_MODE)>, + <&main_pmx0_range 143 3 (PIN_INPUT | PIN_GPIO_MUX_MODE)>, + <&main_pmx0_range 149 2 (PIN_INPUT | PIN_GPIO_MUX_MODE)>; + + /* + * pinctrl IP DOES NOT give any functional IRQs when a + * system is in active state. This IRQ is only a dummy IRQ + * that is being used to trick Linux into thinking that + * GIC can potentially recieve an interrupt from this IP. + * This helps us setup the IO daisychain wakeups for deep + * sleep via chained wake IRQs. + * Please feel free to assign a different number here as + * long as it is unused if 98 conflicts with another use case. + */ + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + bootph-all; + + main_pmx0_range: gpio-range { + #pinctrl-single,gpio-range-cells = <3>; + }; + }; + + main_esm: esm@420000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x420000 0x00 0x1000>; + ti,esm-pins = <160>, <161>, <162>, <163>, <177>, <178>; + bootph-pre-ram; }; main_timer0: timer@2400000 { - bootph-all; compatible = "ti,am654-timer"; reg = <0x00 0x2400000 0x00 0x400>; interrupts = ; @@ -112,6 +315,91 @@ assigned-clock-parents = <&k3_clks 36 3>; power-domains = <&k3_pds 36 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + bootph-all; + }; + + main_timer1: timer@2410000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2410000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 37 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 37 2>; + assigned-clock-parents = <&k3_clks 37 3>; + power-domains = <&k3_pds 37 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer2: timer@2420000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2420000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 38 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 38 2>; + assigned-clock-parents = <&k3_clks 38 3>; + power-domains = <&k3_pds 38 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer3: timer@2430000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2430000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 39 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 39 2>; + assigned-clock-parents = <&k3_clks 39 3>; + power-domains = <&k3_pds 39 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer4: timer@2440000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2440000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 40 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 40 2>; + assigned-clock-parents = <&k3_clks 40 3>; + power-domains = <&k3_pds 40 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer5: timer@2450000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2450000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 41 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 41 2>; + assigned-clock-parents = <&k3_clks 41 3>; + power-domains = <&k3_pds 41 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer6: timer@2460000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2460000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 42 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 42 2>; + assigned-clock-parents = <&k3_clks 42 3>; + power-domains = <&k3_pds 42 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer7: timer@2470000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2470000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 43 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 43 2>; + assigned-clock-parents = <&k3_clks 43 3>; + power-domains = <&k3_pds 43 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; }; main_uart0: serial@2800000 { @@ -133,4 +421,878 @@ clock-names = "fclk"; status = "disabled"; }; + + main_uart2: serial@2820000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02820000 0x00 0x100>; + interrupts = ; + power-domains = <&k3_pds 153 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 153 0>; + clock-names = "fclk"; + status = "disabled"; + }; + + main_uart3: serial@2830000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02830000 0x00 0x100>; + interrupts = ; + power-domains = <&k3_pds 154 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 154 0>; + clock-names = "fclk"; + status = "disabled"; + }; + + main_uart4: serial@2840000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02840000 0x00 0x100>; + interrupts = ; + power-domains = <&k3_pds 155 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 155 0>; + clock-names = "fclk"; + status = "disabled"; + }; + + main_uart5: serial@2850000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02850000 0x00 0x100>; + interrupts = ; + power-domains = <&k3_pds 156 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 156 0>; + clock-names = "fclk"; + status = "disabled"; + }; + + main_uart6: serial@2860000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02860000 0x00 0x100>; + interrupts = ; + power-domains = <&k3_pds 158 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 158 0>; + clock-names = "fclk"; + status = "disabled"; + }; + + main_i2c0: i2c@20000000 { + compatible = "ti,am64-i2c", "ti,omap4-i2c"; + reg = <0x00 0x20000000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 102 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 102 2>; + clock-names = "fck"; + status = "disabled"; + }; + + main_i2c1: i2c@20010000 { + compatible = "ti,am64-i2c", "ti,omap4-i2c"; + reg = <0x00 0x20010000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 103 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 103 2>; + clock-names = "fck"; + status = "disabled"; + }; + + main_i2c2: i2c@20020000 { + compatible = "ti,am64-i2c", "ti,omap4-i2c"; + reg = <0x00 0x20020000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 104 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 104 2>; + clock-names = "fck"; + status = "disabled"; + }; + + main_i2c3: i2c@20030000 { + compatible = "ti,am64-i2c", "ti,omap4-i2c"; + reg = <0x00 0x20030000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 105 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 105 2>; + clock-names = "fck"; + status = "disabled"; + }; + + main_spi0: spi@20100000 { + compatible = "ti,am654-mcspi", "ti,omap4-mcspi"; + reg = <0x00 0x20100000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 141 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 141 0>; + status = "disabled"; + }; + + main_spi1: spi@20110000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x20110000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 142 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 142 0>; + status = "disabled"; + }; + + main_spi2: spi@20120000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x20120000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 143 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 143 0>; + status = "disabled"; + }; + + main_gpio_intr: interrupt-controller@a00000 { + compatible = "ti,sci-intr"; + reg = <0x00 0x00a00000 0x00 0x800>; + ti,intr-trigger-type = <1>; + interrupt-controller; + interrupt-parent = <&gic500>; + #interrupt-cells = <1>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <3>; + ti,interrupt-ranges = <0 32 16>; + }; + + main_gpio0: gpio@600000 { + compatible = "ti,am64-gpio", "ti,keystone-gpio"; + reg = <0x00 0x00600000 0x00 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&main_gpio_intr>; + interrupts = <190>, <191>, <192>, + <193>, <194>, <195>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <92>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 77 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 77 0>; + clock-names = "gpio"; + gpio-ranges = <&main_pmx0 0 0 32>, <&main_pmx0 32 33 38>, + <&main_pmx0 70 72 22>; + }; + + main_gpio1: gpio@601000 { + compatible = "ti,am64-gpio", "ti,keystone-gpio"; + reg = <0x00 0x00601000 0x00 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&main_gpio_intr>; + interrupts = <180>, <181>, <182>, + <183>, <184>, <185>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <52>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 78 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 78 0>; + clock-names = "gpio"; + gpio-ranges = <&main_pmx0 0 94 32>, <&main_pmx0 42 137 5>, + <&main_pmx0 47 143 3>, <&main_pmx0 50 149 2>; + }; + + sdhci0: mmc@fa10000 { + compatible = "ti,am64-sdhci-8bit"; + reg = <0x00 0x0fa10000 0x00 0x1000>, <0x00 0x0fa18000 0x00 0x400>; + interrupts = ; + power-domains = <&k3_pds 57 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 57 1>, <&k3_clks 57 2>; + clock-names = "clk_ahb", "clk_xin"; + assigned-clocks = <&k3_clks 57 2>; + assigned-clock-parents = <&k3_clks 57 4>; + bus-width = <8>; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + ti,clkbuf-sel = <0x7>; + ti,strobe-sel = <0x55>; + ti,trm-icp = <0x8>; + ti,otap-del-sel-legacy = <0x1>; + ti,otap-del-sel-mmc-hs = <0x1>; + ti,otap-del-sel-ddr52 = <0x6>; + ti,otap-del-sel-hs200 = <0x8>; + ti,otap-del-sel-hs400 = <0x5>; + ti,itap-del-sel-legacy = <0x10>; + ti,itap-del-sel-mmc-hs = <0xa>; + ti,itap-del-sel-ddr52 = <0x3>; + status = "disabled"; + }; + + sdhci1: mmc@fa00000 { + compatible = "ti,am62-sdhci"; + reg = <0x00 0x0fa00000 0x00 0x1000>, <0x00 0x0fa08000 0x00 0x400>; + interrupts = ; + power-domains = <&k3_pds 58 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 58 5>, <&k3_clks 58 6>; + clock-names = "clk_ahb", "clk_xin"; + bus-width = <4>; + ti,clkbuf-sel = <0x7>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-sd-hs = <0x0>; + ti,otap-del-sel-sdr12 = <0xf>; + ti,otap-del-sel-sdr25 = <0xf>; + ti,otap-del-sel-sdr50 = <0xc>; + ti,otap-del-sel-ddr50 = <0x9>; + ti,otap-del-sel-sdr104 = <0x6>; + ti,itap-del-sel-legacy = <0x0>; + ti,itap-del-sel-sd-hs = <0x0>; + ti,itap-del-sel-sdr12 = <0x0>; + ti,itap-del-sel-sdr25 = <0x0>; + status = "disabled"; + }; + + sdhci2: mmc@fa20000 { + compatible = "ti,am62-sdhci"; + reg = <0x00 0x0fa20000 0x00 0x1000>, <0x00 0x0fa28000 0x00 0x400>; + interrupts = ; + power-domains = <&k3_pds 184 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 184 5>, <&k3_clks 184 6>; + clock-names = "clk_ahb", "clk_xin"; + bus-width = <4>; + ti,clkbuf-sel = <0x7>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-sd-hs = <0x0>; + ti,otap-del-sel-sdr12 = <0xf>; + ti,otap-del-sel-sdr25 = <0xf>; + ti,otap-del-sel-sdr50 = <0xc>; + ti,otap-del-sel-ddr50 = <0x9>; + ti,otap-del-sel-sdr104 = <0x6>; + ti,itap-del-sel-legacy = <0x0>; + ti,itap-del-sel-sd-hs = <0x0>; + ti,itap-del-sel-sdr12 = <0x0>; + ti,itap-del-sel-sdr25 = <0x0>; + status = "disabled"; + }; + + usbss0: usb@f900000 { + compatible = "ti,am62-usb"; + reg = <0x00 0x0f900000 0x00 0x800>, + <0x00 0x0f908000 0x00 0x400>; + clocks = <&k3_clks 161 3>; + clock-names = "ref"; + ti,syscon-phy-pll-refclk = <&usb0_phy_ctrl 0x0>; + #address-cells = <2>; + #size-cells = <2>; + power-domains = <&k3_pds 178 TI_SCI_PD_EXCLUSIVE>; + ranges; + status = "disabled"; + + usb0: usb@31000000 { + compatible = "snps,dwc3"; + reg = <0x00 0x31000000 0x00 0x50000>; + interrupts = , /* irq.0 */ + ; /* irq.0 */ + interrupt-names = "host", "peripheral"; + maximum-speed = "high-speed"; + dr_mode = "otg"; + snps,usb2-gadget-lpm-disable; + snps,usb2-lpm-disable; + }; + }; + + usbss1: usb@f910000 { + compatible = "ti,am62-usb"; + reg = <0x00 0x0f910000 0x00 0x800>, + <0x00 0x0f918000 0x00 0x400>; + clocks = <&k3_clks 162 3>; + clock-names = "ref"; + ti,syscon-phy-pll-refclk = <&usb1_phy_ctrl 0x0>; + #address-cells = <2>; + #size-cells = <2>; + power-domains = <&k3_pds 179 TI_SCI_PD_EXCLUSIVE>; + ranges; + status = "disabled"; + + usb1: usb@31100000 { + compatible = "snps,dwc3"; + reg = <0x00 0x31100000 0x00 0x50000>; + interrupts = , /* irq.0 */ + ; /* irq.0 */ + interrupt-names = "host", "peripheral"; + maximum-speed = "high-speed"; + dr_mode = "otg"; + snps,usb2-gadget-lpm-disable; + snps,usb2-lpm-disable; + }; + }; + + fss: bus@fc00000 { + compatible = "simple-bus"; + reg = <0x00 0x0fc00000 0x00 0x70000>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + ospi0: spi@fc40000 { + compatible = "ti,am654-ospi", "cdns,qspi-nor"; + reg = <0x00 0x0fc40000 0x00 0x100>, + <0x05 0x00000000 0x01 0x00000000>; + interrupts = ; + cdns,fifo-depth = <256>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x0>; + clocks = <&k3_clks 75 7>; + assigned-clocks = <&k3_clks 75 7>; + assigned-clock-parents = <&k3_clks 75 8>; + assigned-clock-rates = <166666666>; + power-domains = <&k3_pds 75 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + }; + + cpsw3g: ethernet@8000000 { + compatible = "ti,am642-cpsw-nuss"; + #address-cells = <2>; + #size-cells = <2>; + reg = <0x00 0x08000000 0x00 0x200000>; + reg-names = "cpsw_nuss"; + ranges = <0x00 0x00 0x00 0x08000000 0x00 0x200000>; + clocks = <&k3_clks 13 0>; + assigned-clocks = <&k3_clks 13 3>; + assigned-clock-parents = <&k3_clks 13 11>; + clock-names = "fck"; + power-domains = <&k3_pds 13 TI_SCI_PD_EXCLUSIVE>; + + dmas = <&main_pktdma 0xc600 15>, + <&main_pktdma 0xc601 15>, + <&main_pktdma 0xc602 15>, + <&main_pktdma 0xc603 15>, + <&main_pktdma 0xc604 15>, + <&main_pktdma 0xc605 15>, + <&main_pktdma 0xc606 15>, + <&main_pktdma 0xc607 15>, + <&main_pktdma 0x4600 15>; + dma-names = "tx0", "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", + "tx7", "rx"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + cpsw_port1: port@1 { + reg = <1>; + ti,mac-only; + label = "port1"; + phys = <&phy_gmii_sel 1>; + mac-address = [00 00 00 00 00 00]; + }; + + cpsw_port2: port@2 { + reg = <2>; + ti,mac-only; + label = "port2"; + phys = <&phy_gmii_sel 2>; + mac-address = [00 00 00 00 00 00]; + }; + }; + + cpsw3g_mdio: mdio@f00 { + compatible = "ti,cpsw-mdio","ti,davinci_mdio"; + reg = <0x00 0xf00 0x00 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 13 0>; + clock-names = "fck"; + bus_freq = <1000000>; + status = "disabled"; + }; + + cpts@3d000 { + compatible = "ti,j721e-cpts"; + reg = <0x00 0x3d000 0x00 0x400>; + clocks = <&k3_clks 13 3>; + clock-names = "cpts"; + interrupts-extended = <&gic500 GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpts"; + ti,cpts-ext-ts-inputs = <4>; + ti,cpts-periodic-outputs = <2>; + }; + }; + + hwspinlock: spinlock@2a000000 { + compatible = "ti,am64-hwspinlock"; + reg = <0x00 0x2a000000 0x00 0x1000>; + #hwlock-cells = <1>; + }; + + mailbox0_cluster0: mailbox@29000000 { + compatible = "ti,am64-mailbox"; + reg = <0x00 0x29000000 0x00 0x200>; + interrupts = ; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + }; + + mailbox0_cluster1: mailbox@29010000 { + compatible = "ti,am64-mailbox"; + reg = <0x00 0x29010000 0x00 0x200>; + interrupts = ; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + }; + + mailbox0_cluster2: mailbox@29020000 { + compatible = "ti,am64-mailbox"; + reg = <0x00 0x29020000 0x00 0x200>; + interrupts = ; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + }; + + mailbox0_cluster3: mailbox@29030000 { + compatible = "ti,am64-mailbox"; + reg = <0x00 0x29030000 0x00 0x200>; + interrupts = ; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + }; + + ecap0: pwm@23100000 { + compatible = "ti,am3352-ecap"; + #pwm-cells = <3>; + reg = <0x00 0x23100000 0x00 0x100>; + power-domains = <&k3_pds 51 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 51 0>; + clock-names = "fck"; + status = "disabled"; + }; + + ecap1: pwm@23110000 { + compatible = "ti,am3352-ecap"; + #pwm-cells = <3>; + reg = <0x00 0x23110000 0x00 0x100>; + power-domains = <&k3_pds 52 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 52 0>; + clock-names = "fck"; + status = "disabled"; + }; + + ecap2: pwm@23120000 { + compatible = "ti,am3352-ecap"; + #pwm-cells = <3>; + reg = <0x00 0x23120000 0x00 0x100>; + power-domains = <&k3_pds 53 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 53 0>; + clock-names = "fck"; + status = "disabled"; + }; + + eqep0: counter@23200000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23200000 0x00 0x100>; + power-domains = <&k3_pds 59 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 59 0>; + interrupts = ; + status = "disabled"; + }; + + eqep1: counter@23210000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23210000 0x00 0x100>; + power-domains = <&k3_pds 60 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 60 0>; + interrupts = ; + status = "disabled"; + }; + + eqep2: counter@23220000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23220000 0x00 0x100>; + power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 62 0>; + interrupts = ; + status = "disabled"; + }; + + main_mcan0: can@20701000 { + compatible = "bosch,m_can"; + reg = <0x00 0x20701000 0x00 0x200>, + <0x00 0x20708000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 98 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 98 6>, <&k3_clks 98 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan1: can@20711000 { + compatible = "bosch,m_can"; + reg = <0x00 0x20711000 0x00 0x200>, + <0x00 0x20718000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 99 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 99 6>, <&k3_clks 99 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_rti0: watchdog@e000000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x0e000000 0x00 0x100>; + clocks = <&k3_clks 125 0>; + power-domains = <&k3_pds 125 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 125 0>; + assigned-clock-parents = <&k3_clks 125 2>; + }; + + main_rti1: watchdog@e010000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x0e010000 0x00 0x100>; + clocks = <&k3_clks 126 0>; + power-domains = <&k3_pds 126 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 126 0>; + assigned-clock-parents = <&k3_clks 126 2>; + }; + + main_rti2: watchdog@e020000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x0e020000 0x00 0x100>; + clocks = <&k3_clks 127 0>; + power-domains = <&k3_pds 127 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 127 0>; + assigned-clock-parents = <&k3_clks 127 2>; + }; + + main_rti3: watchdog@e030000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x0e030000 0x00 0x100>; + clocks = <&k3_clks 128 0>; + power-domains = <&k3_pds 128 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 128 0>; + assigned-clock-parents = <&k3_clks 128 2>; + }; + + main_rti15: watchdog@e0f0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x0e0f0000 0x00 0x100>; + clocks = <&k3_clks 130 0>; + power-domains = <&k3_pds 130 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 130 0>; + assigned-clock-parents = <&k3_clks 130 2>; + }; + + epwm0: pwm@23000000 { + compatible = "ti,am64-epwm", "ti,am3352-ehrpwm"; + #pwm-cells = <3>; + reg = <0x00 0x23000000 0x00 0x100>; + power-domains = <&k3_pds 86 TI_SCI_PD_EXCLUSIVE>; + clocks = <&epwm_tbclk 0>, <&k3_clks 86 0>; + clock-names = "tbclk", "fck"; + status = "disabled"; + }; + + epwm1: pwm@23010000 { + compatible = "ti,am64-epwm", "ti,am3352-ehrpwm"; + #pwm-cells = <3>; + reg = <0x00 0x23010000 0x00 0x100>; + power-domains = <&k3_pds 87 TI_SCI_PD_EXCLUSIVE>; + clocks = <&epwm_tbclk 1>, <&k3_clks 87 0>; + clock-names = "tbclk", "fck"; + status = "disabled"; + }; + + epwm2: pwm@23020000 { + compatible = "ti,am64-epwm", "ti,am3352-ehrpwm"; + #pwm-cells = <3>; + reg = <0x00 0x23020000 0x00 0x100>; + power-domains = <&k3_pds 88 TI_SCI_PD_EXCLUSIVE>; + clocks = <&epwm_tbclk 2>, <&k3_clks 88 0>; + clock-names = "tbclk", "fck"; + status = "disabled"; + }; + + mcasp0: audio-controller@2b00000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x00 0x02b00000 0x00 0x2000>, + <0x00 0x02b08000 0x00 0x400>; + reg-names = "mpu", "dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + + dmas = <&main_bcdma 0 0xc500 0>, <&main_bcdma 0 0x4500 0>; + dma-names = "tx", "rx"; + + clocks = <&k3_clks 190 0>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 190 0>; + assigned-clock-parents = <&k3_clks 190 2>; + power-domains = <&k3_pds 190 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcasp1: audio-controller@2b10000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x00 0x02b10000 0x00 0x2000>, + <0x00 0x02b18000 0x00 0x400>; + reg-names = "mpu", "dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + + dmas = <&main_bcdma 0 0xc501 0>, <&main_bcdma 0 0x4501 0>; + dma-names = "tx", "rx"; + + clocks = <&k3_clks 191 0>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 191 0>; + assigned-clock-parents = <&k3_clks 191 2>; + power-domains = <&k3_pds 191 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcasp2: audio-controller@2b20000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x00 0x02b20000 0x00 0x2000>, + <0x00 0x02b28000 0x00 0x400>; + reg-names = "mpu", "dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + + dmas = <&main_bcdma 0 0xc502 0>, <&main_bcdma 0 0x4502 0>; + dma-names = "tx", "rx"; + + clocks = <&k3_clks 192 0>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 192 0>; + assigned-clock-parents = <&k3_clks 192 2>; + power-domains = <&k3_pds 192 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + vpu: video-codec@30210000 { + compatible = "ti,j721s2-wave521c", "cnm,wave521c"; + reg = <0x00 0x30210000 0x00 0x10000>; + interrupts = ; + clocks = <&k3_clks 204 2>; + power-domains = <&k3_pds 204 TI_SCI_PD_EXCLUSIVE>; + sram = <&oc_sram>; + sram-size = <0xf800>; + }; + + gpu: gpu@fd80000 { + compatible = "ti,am62p-pvr", "img,pvr-bxs64"; + reg = <0x00 0x0fd80000 0x00 0x80000>; + interrupts = ; + power-domains = <&k3_pds 237 TI_SCI_PD_EXCLUSIVE>, + <&k3_pds 242 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 237 3>; + assigned-clock-rates = <800000000>; + power-domain-names = "firmware", "dust"; + clocks = <&k3_clks 237 3>; + clock-names = "core"; + }; + + ti_csi2rx0: ticsi2rx@30102000 { + compatible = "ti,j721e-csi2rx-shim"; + reg = <0x00 0x30102000 0x00 0x1000>; + ranges; + #address-cells = <2>; + #size-cells = <2>; + dmas = <&main_bcdma_csi 0 0x5000 0>, <&main_bcdma_csi 0 0x5001 0>, + <&main_bcdma_csi 0 0x5002 0>, <&main_bcdma_csi 0 0x5003 0>, + <&main_bcdma_csi 0 0x5004 0>, <&main_bcdma_csi 0 0x5005 0>; + dma-names = "rx0", "rx1", "rx2", "rx3", "rx4", "rx5"; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + cdns_csi2rx0: csi-bridge@30101000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x30101000 0x00 0x1000>; + clocks = <&k3_clks 182 0>, <&k3_clks 182 3>, <&k3_clks 182 0>, + <&k3_clks 182 0>, <&k3_clks 182 4>, <&k3_clks 182 4>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi0_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi0_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi0_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi0_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + dphy0: phy@30110000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x30110000 0x00 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 185 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + dss0: dss@30200000 { + compatible = "ti,am62p51-dss"; + reg = <0x00 0x30200000 0x00 0x1000>, /* common */ + <0x00 0x30202000 0x00 0x1000>, /* vidl1 */ + <0x00 0x30206000 0x00 0x1000>, /* vid */ + <0x00 0x30207000 0x00 0x1000>, /* ovr1 */ + <0x00 0x30208000 0x00 0x1000>, /* ovr2 */ + <0x00 0x3020a000 0x00 0x1000>, /* vp1: Used for OLDI */ + <0x00 0x3020b000 0x00 0x1000>, /* vp2: Used as DPI Out */ + <0x00 0x30201000 0x00 0x1000>; /* common1 */ + reg-names = "common", "vidl1", "vid", + "ovr1", "ovr2", "vp1", "vp2", "common1"; + power-domains = <&k3_pds 186 TI_SCI_PD_EXCLUSIVE>, /* DSS0 */ + <&k3_pds 243 TI_SCI_PD_EXCLUSIVE>, /* OLDI0 */ + <&k3_pds 244 TI_SCI_PD_EXCLUSIVE>; /* OLDI1 */ + clocks = <&k3_clks 186 6>, + <&dss0_vp1_clk>, + <&k3_clks 186 2>; + clock-names = "fck", "vp1", "vp2"; + interrupts = ; + status = "disabled"; + + oldi-txes { + #address-cells = <1>; + #size-cells = <0>; + + oldi0_dss0: oldi@0 { + reg = <0>; + clocks = <&k3_clks 186 0>; + clock-names = "s_clk"; + ti,companion-oldi = <&oldi1_dss0>; + ti,oldi-io-ctrl = <&dss_oldi_io_ctrl>; + status = "disabled"; + + oldi0_dss0_ports: ports { + }; + }; + + oldi1_dss0: oldi@1 { + reg = <1>; + ti,secondary-oldi; + status = "disabled"; + + oldi1_dss0_ports: ports { + }; + }; + }; + + dss0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + dss1: dss@30220000 { + compatible = "ti,am62p52-dss"; + reg = <0x00 0x30220000 0x00 0x1000>, /* common */ + <0x00 0x30222000 0x00 0x1000>, /* vidl1 */ + <0x00 0x30226000 0x00 0x1000>, /* vid */ + <0x00 0x30227000 0x00 0x1000>, /* ovr1 */ + <0x00 0x30228000 0x00 0x1000>, /* ovr2 */ + <0x00 0x3022a000 0x00 0x1000>, /* vp1: Used for OLDI */ + <0x00 0x3022b000 0x00 0x1000>, /* vp2: Used as DPI Out */ + <0x00 0x30221000 0x00 0x1000>; /* common1 */ + reg-names = "common", "vidl1", "vid", + "ovr1", "ovr2", "vp1", "vp2", "common1"; + power-domains = <&k3_pds 232 TI_SCI_PD_EXCLUSIVE>, /* DSS0 */ + <&k3_pds 244 TI_SCI_PD_EXCLUSIVE>; /* OLDI1 */ + clocks = <&k3_clks 232 8>, + <&dss1_vp1_clk>, + <&k3_clks 232 4>; + clock-names = "fck", "vp1", "vp2"; + interrupts = ; + status = "disabled"; + + oldi-txes { + #address-cells = <1>; + #size-cells = <0>; + + oldi1_dss1: oldi@1 { + reg = <0>; + clocks = <&k3_clks 232 0>; + clock-names = "s_clk"; + ti,oldi-io-ctrl = <&dss_oldi_io_ctrl>; + status = "disabled"; + + oldi1_dss1_ports: ports { + }; + }; + }; + + dss1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + dphy_tx0: phy@301c0000 { + compatible = "ti,j721e-dphy"; + reg = <0x0 0x301c0000 0x0 0x1000>; + clocks = <&k3_clks 238 16>, <&k3_clks 238 1>; + clock-names = "psm", "pll_ref"; + #phy-cells = <0>; + power-domains = <&k3_pds 238 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 238 1>; + assigned-clock-parents = <&k3_clks 238 2>; + assigned-clock-rates = <25000000>; + status = "disabled"; + }; + + dsi0: dsi@30500000 { + compatible = "ti,j721e-dsi"; + reg = <0x0 0x30500000 0x0 0x100000>, <0x0 0x30270000 0x0 0x100>; + clocks = <&k3_clks 231 2>, <&k3_clks 231 5>; + clock-names = "dsi_p_clk", "dsi_sys_clk"; + power-domains = <&k3_pds 231 TI_SCI_PD_EXCLUSIVE>; + interrupt-parent = <&gic500>; + interrupts = ; + phys = <&dphy_tx0>; + phy-names = "dphy"; + status = "disabled"; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-mcu.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62p-mcu.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62p-mcu.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -1,7 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree file for the AM62P MCU domain peripherals - * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ */ &cbass_mcu { @@ -11,5 +11,208 @@ #pinctrl-cells = <1>; pinctrl-single,register-width = <32>; pinctrl-single,function-mask = <0xffffffff>; + pinctrl-single,gpio-range = + <&mcu_pmx_range 0 21 (PIN_INPUT | PIN_GPIO_MUX_MODE)>, + <&mcu_pmx_range 23 1 (PIN_INPUT | PIN_GPIO_MUX_MODE)>, + <&mcu_pmx_range 32 2 (PIN_INPUT | PIN_GPIO_MUX_MODE)>; + bootph-all; + + mcu_pmx_range: gpio-range { + #pinctrl-single,gpio-range-cells = <3>; + }; + }; + + mcu_esm: esm@4100000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x4100000 0x00 0x1000>; + ti,esm-pins = <0>, <1>, <2>, <85>; + bootph-pre-ram; + }; + + /* + * The MCU domain timer interrupts are routed only to the ESM module, + * and not currently available for Linux. The MCU domain timers are + * of limited use without interrupts, and likely reserved by the ESM. + */ + mcu_timer0: timer@4800000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x4800000 0x00 0x400>; + clocks = <&k3_clks 35 2>; + clock-names = "fck"; + power-domains = <&k3_pds 35 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + status = "reserved"; + }; + + mcu_timer1: timer@4810000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x4810000 0x00 0x400>; + clocks = <&k3_clks 48 2>; + clock-names = "fck"; + power-domains = <&k3_pds 48 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + status = "reserved"; + }; + + mcu_timer2: timer@4820000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x4820000 0x00 0x400>; + clocks = <&k3_clks 49 2>; + clock-names = "fck"; + power-domains = <&k3_pds 49 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + status = "reserved"; + }; + + mcu_timer3: timer@4830000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x4830000 0x00 0x400>; + clocks = <&k3_clks 50 2>; + clock-names = "fck"; + power-domains = <&k3_pds 50 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + status = "reserved"; + }; + + mcu_uart0: serial@4a00000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x04a00000 0x00 0x100>; + interrupts = ; + power-domains = <&k3_pds 149 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 149 0>; + clock-names = "fclk"; + status = "disabled"; + }; + + mcu_i2c0: i2c@4900000 { + compatible = "ti,am64-i2c", "ti,omap4-i2c"; + reg = <0x00 0x04900000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 106 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 106 2>; + clock-names = "fck"; + status = "disabled"; + }; + + mcu_spi0: spi@4b00000 { + compatible = "ti,am654-mcspi", "ti,omap4-mcspi"; + reg = <0x00 0x04b00000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 147 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 147 0>; + status = "disabled"; + }; + + mcu_spi1: spi@4b10000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x04b10000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 148 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 148 0>; + status = "disabled"; + }; + + mcu_gpio_intr: interrupt-controller@4210000 { + compatible = "ti,sci-intr"; + reg = <0x00 0x04210000 0x00 0x200>; + ti,intr-trigger-type = <1>; + interrupt-controller; + interrupt-parent = <&gic500>; + #interrupt-cells = <1>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <5>; + ti,interrupt-ranges = <0 104 4>; + }; + + mcu_gpio0: gpio@4201000 { + compatible = "ti,am64-gpio", "ti,keystone-gpio"; + reg = <0x00 0x4201000 0x00 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&mcu_gpio_intr>; + interrupts = <30>, <31>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <24>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 79 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 79 0>; + clock-names = "gpio"; + gpio-ranges = <&mcu_pmx0 0 0 21>, <&mcu_pmx0 21 23 1>, + <&mcu_pmx0 22 32 2>; + }; + + mcu_rti0: watchdog@4880000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x04880000 0x00 0x100>; + clocks = <&k3_clks 131 0>; + power-domains = <&k3_pds 131 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 131 0>; + assigned-clock-parents = <&k3_clks 131 2>; + /* Tightly coupled to M4F */ + status = "reserved"; + }; + + mcu_mcan0: can@4e08000 { + compatible = "bosch,m_can"; + reg = <0x00 0x4e08000 0x00 0x200>, + <0x00 0x4e00000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 188 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 188 6>, <&k3_clks 188 1>; + clock-names = "hclk", "cclk"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + interrupts = , + ; + interrupt-names = "int0", "int1"; + wakeup-source; + status = "disabled"; + }; + + mcu_mcan1: can@4e18000 { + compatible = "bosch,m_can"; + reg = <0x00 0x4e18000 0x00 0x200>, + <0x00 0x4e10000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 189 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 189 6>, <&k3_clks 189 1>; + clock-names = "hclk", "cclk"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + interrupts = , + ; + interrupt-names = "int0", "int1"; + wakeup-source; + status = "disabled"; + }; + + mcu_r5fss0: r5fss@79000000 { + compatible = "ti,am62-r5fss"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x79000000 0x00 0x79000000 0x8000>, + <0x79020000 0x00 0x79020000 0x8000>; + power-domains = <&k3_pds 7 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + mcu_r5fss0_core0: r5f@79000000 { + compatible = "ti,am62-r5f"; + reg = <0x79000000 0x00008000>, + <0x79020000 0x00008000>; + reg-names = "atcm", "btcm"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <9>; + ti,sci-proc-ids = <0x03 0xff>; + resets = <&k3_reset 9 1>; + firmware-name = "am62p-mcu-r5f0_0-fw"; + ti,atcm-enable = <0>; + ti,btcm-enable = <1>; + ti,loczrama = <0>; + }; }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p-thermal.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-thermal.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62p-thermal.dtsi 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62p-thermal.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include + +thermal_zones: thermal-zones { + main0_thermal: main0-thermal { + polling-delay-passive = <250>; /* milliSeconds */ + polling-delay = <500>; /* milliSeconds */ + thermal-sensors = <&wkup_vtm0 0>; + + trips { + main0_crit: main0-crit { + temperature = <125000>; /* milliCelsius */ + hysteresis = <2000>; /* milliCelsius */ + type = "critical"; + }; + }; + }; + + main1_thermal: main1-thermal { + polling-delay-passive = <250>; /* milliSeconds */ + polling-delay = <500>; /* milliSeconds */ + thermal-sensors = <&wkup_vtm0 1>; + + trips { + main1_crit: main1-crit { + temperature = <125000>; /* milliCelsius */ + hysteresis = <2000>; /* milliCelsius */ + type = "critical"; + }; + }; + }; + + main2_thermal: main2-thermal { + polling-delay-passive = <250>; /* milliSeconds */ + polling-delay = <500>; /* milliSeconds */ + thermal-sensors = <&wkup_vtm0 2>; + + trips { + main2_crit: main2-crit { + temperature = <125000>; /* milliCelsius */ + hysteresis = <2000>; /* milliCelsius */ + type = "critical"; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62p-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-wakeup.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62p-wakeup.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62p-wakeup.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -1,32 +1,130 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree file for the AM62P wakeup domain peripherals - * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ */ +#include + &cbass_wakeup { - wkup_conf: bus@43000000 { - bootph-all; - compatible = "simple-bus"; + wkup_conf: syscon@43000000 { + compatible = "syscon", "simple-mfd"; reg = <0x00 0x43000000 0x00 0x20000>; #address-cells = <1>; #size-cells = <1>; ranges = <0x00 0x00 0x43000000 0x20000>; + bootph-all; chipid: chipid@14 { - bootph-all; compatible = "ti,am654-chipid"; reg = <0x14 0x4>; + bootph-all; + }; + + usb0_phy_ctrl: syscon@4008 { + compatible = "ti,am62-usb-phy-ctrl", "syscon"; + reg = <0x4008 0x4>; + }; + + usb1_phy_ctrl: syscon@4018 { + compatible = "ti,am62-usb-phy-ctrl", "syscon"; + reg = <0x4018 0x4>; }; }; - wkup_uart0: serial@2b300000 { - compatible = "ti,am64-uart", "ti,am654-uart"; - reg = <0x00 0x2b300000 0x00 0x100>; - interrupts = ; + target-module@2b300050 { + compatible = "ti,sysc-omap2", "ti,sysc"; + reg = <0 0x2b300050 0 0x4>, + <0 0x2b300054 0 0x4>, + <0 0x2b300058 0 0x4>; + reg-names = "rev", "sysc", "syss"; + ti,sysc-mask = <(SYSC_OMAP2_ENAWAKEUP | + SYSC_OMAP2_SOFTRESET | + SYSC_OMAP2_AUTOIDLE)>; + ti,sysc-sidle = , + , + , + ; + ti,syss-mask = <1>; + ti,no-reset-on-init; power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>; clocks = <&k3_clks 114 0>; - clock-names = "fclk"; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0x2b300000 0x100000>; + + wkup_uart0: serial@0 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0 0x100>; + interrupts = ; + status = "disabled"; + }; + }; + + wkup_i2c0: i2c@2b200000 { + compatible = "ti,am64-i2c", "ti,omap4-i2c"; + reg = <0x00 0x2b200000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 107 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 107 4>; + clock-names = "fck"; + status = "disabled"; + }; + + wkup_rtc0: rtc@2b1f0000 { + compatible = "ti,am62-rtc"; + reg = <0x00 0x2b1f0000 0x00 0x100>; + interrupts = ; + clocks = <&k3_clks 117 6> , <&k3_clks 117 0>; + clock-names = "vbus", "osc32k"; + power-domains = <&k3_pds 117 TI_SCI_PD_EXCLUSIVE>; + wakeup-source; + }; + + wkup_rti0: watchdog@2b000000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2b000000 0x00 0x100>; + clocks = <&k3_clks 132 0>; + power-domains = <&k3_pds 132 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 132 0>; + assigned-clock-parents = <&k3_clks 132 2>; + /* Used by DM firmware */ + status = "reserved"; + }; + + wkup_vtm0: temperature-sensor@b00000 { + compatible = "ti,j7200-vtm"; + reg = <0x00 0xb00000 0x00 0x400>, + <0x00 0xb01000 0x00 0x400>; + power-domains = <&k3_pds 95 TI_SCI_PD_EXCLUSIVE>; + #thermal-sensor-cells = <1>; + }; + + wkup_r5fss0: r5fss@78000000 { + compatible = "ti,am62-r5fss"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x78000000 0x00 0x78000000 0x8000>, + <0x78100000 0x00 0x78100000 0x8000>; + power-domains = <&k3_pds 119 TI_SCI_PD_EXCLUSIVE>; status = "disabled"; + + wkup_r5fss0_core0: r5f@78000000 { + compatible = "ti,am62-r5f"; + reg = <0x78000000 0x00008000>, + <0x78100000 0x00008000>; + reg-names = "atcm", "btcm"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <121>; + ti,sci-proc-ids = <0x01 0xff>; + resets = <&k3_reset 121 1>; + firmware-name = "am62-wkup-r5f0_0-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-thermal.dtsi b/arch/arm64/boot/dts/ti/k3-am62-thermal.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62-thermal.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62-thermal.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -1,4 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ #include diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -185,7 +185,6 @@ /* Verdin SD_1 */ &sdhci1 { - ti,driver-strength-ohm = <33>; status = "okay"; }; @@ -214,6 +213,5 @@ /* Verdin UART_2 */ &wkup_uart0 { - /* FIXME: WKUP UART0 is used by DM firmware */ - status = "reserved"; + status = "okay"; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -206,7 +206,6 @@ /* Verdin SD_1 */ &sdhci1 { - ti,driver-strength-ohm = <33>; status = "okay"; }; @@ -235,6 +234,5 @@ /* Verdin UART_2 */ &wkup_uart0 { - /* FIXME: WKUP UART0 is used by DM firmware */ - status = "reserved"; + status = "okay"; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -42,6 +42,22 @@ usb1 = &usb1; }; + connector { + compatible = "gpio-usb-b-connector", "usb-b-connector"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb0_id>; + id-gpios = <&main_gpio1 19 GPIO_ACTIVE_HIGH>; + label = "USB_1"; + self-powered; + vbus-supply = <®_usb0_vbus>; + + port { + usb_dr_connector: endpoint { + remote-endpoint = <&usb0_ep>; + }; + }; + }; + verdin_gpio_keys: gpio-keys { compatible = "gpio-keys"; pinctrl-names = "default"; @@ -151,6 +167,18 @@ vin-supply = <®_sd_3v3_1v8>; }; + reg_usb0_vbus: regulator-usb0-vbus { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb0_en>; + enable-active-high; + /* Verdin USB_1_EN (SODIMM 155) */ + gpio = <&main_gpio1 50 GPIO_ACTIVE_HIGH>; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "USB_1_EN"; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; @@ -233,6 +261,13 @@ >; }; + /* Verdin SPI_1 CS as GPIO */ + pinctrl_qspi1_io4_gpio: main-gpio0-7-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x001c, PIN_INPUT, 7) /* (J23) OSPI0_D4.GPIO0_7 */ /* SODIMM 202 */ + >; + }; + /* Verdin QSPI_1_CS# as GPIO (conflict with Verdin QSPI_1 interface) */ pinctrl_qspi1_cs_gpio: main-gpio0-11-default-pins { pinctrl-single,pins = < @@ -429,6 +464,13 @@ >; }; + /* Verdin USB_1_EN */ + pinctrl_usb0_en: main-gpio1-50-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x0254, PIN_INPUT, 7) /* (C20) USB0_DRVVBUS.GPIO1_50 */ /* SODIMM 155 */ + >; + }; + /* On-module I2C - PMIC_I2C */ pinctrl_i2c0: main-i2c0-default-pins { pinctrl-single,pins = < @@ -599,12 +641,18 @@ pinctrl_spi1: main-spi1-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x0020, PIN_INPUT, 1) /* (J25) OSPI0_D5.SPI1_CLK */ /* SODIMM 196 */ - AM62X_IOPAD(0x001c, PIN_INPUT, 1) /* (J23) OSPI0_D4.SPI1_CS0 */ /* SODIMM 202 */ AM62X_IOPAD(0x0024, PIN_INPUT, 1) /* (H25) OSPI0_D6.SPI1_D0 */ /* SODIMM 200 */ AM62X_IOPAD(0x0028, PIN_INPUT, 1) /* (J22) OSPI0_D7.SPI1_D1 */ /* SODIMM 198 */ >; }; + /* Verdin SPI_1 CS */ + pinctrl_spi1_cs0: main-spi1-cs0-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x001c, PIN_INPUT, 1) /* (J23) OSPI0_D4.SPI1_CS0 */ /* SODIMM 202 */ + >; + }; + /* ETH_25MHz_CLK */ pinctrl_eth_clock: main-system-clkout0-default-pins { pinctrl-single,pins = < @@ -647,13 +695,6 @@ >; }; - /* Verdin USB_1 */ - pinctrl_usb0: main-usb0-default-pins { - pinctrl-single,pins = < - AM62X_IOPAD(0x0254, PIN_OUTPUT, 0) /* (C20) USB0_DRVVBUS */ /* SODIMM 155 */ - >; - }; - /* Verdin USB_2 */ pinctrl_usb1: main-usb1-default-pins { pinctrl-single,pins = < @@ -1000,7 +1041,7 @@ "", "", "SODIMM_17", - "", /* 50 */ + "SODIMM_155", /* 50 */ "", "", "", @@ -1105,7 +1146,7 @@ regulator-always-on; regulator-boot-on; regulator-max-microvolt = <850000>; - regulator-min-microvolt = <850000>; + regulator-min-microvolt = <750000>; regulator-name = "+VDD_CORE (PMIC BUCK1)"; }; @@ -1278,7 +1319,7 @@ /* Verdin SPI_1 */ &main_spi1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_spi1>; + pinctrl-0 = <&pinctrl_spi1>, <&pinctrl_spi1_cs0>; ti,pindir-d0-out-d1-in; status = "disabled"; }; @@ -1309,8 +1350,8 @@ 0 0 0 0 >; tdm-slots = <2>; - rx-num-evt = <32>; - tx-num-evt = <32>; + rx-num-evt = <0>; + tx-num-evt = <0>; #sound-dai-cells = <0>; status = "disabled"; }; @@ -1327,8 +1368,8 @@ 0 0 0 0 >; tdm-slots = <2>; - rx-num-evt = <32>; - tx-num-evt = <32>; + rx-num-evt = <0>; + tx-num-evt = <0>; #sound-dai-cells = <0>; status = "disabled"; }; @@ -1394,7 +1435,6 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdhci0>; non-removable; - ti,driver-strength-ohm = <50>; status = "okay"; }; @@ -1403,7 +1443,6 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdhci1>; disable-wp; - ti,driver-strength-ohm = <50>; vmmc-supply = <®_sdhc1_vmmc>; vqmmc-supply = <®_sdhc1_vqmmc>; status = "disabled"; @@ -1415,11 +1454,16 @@ status = "disabled"; }; -/* TODO: role swich using ID pin */ &usb0 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usb0>, <&pinctrl_usb0_id>; + adp-disable; + usb-role-switch; status = "disabled"; + + port { + usb0_ep: endpoint { + remote-endpoint = <&usb_dr_connector>; + }; + }; }; /* Verdin USB_2 */ diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-verdin-mallow.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-mallow.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62-verdin-mallow.dtsi 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-mallow.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * Common dtsi for Verdin AM62 SoM on Mallow carrier board + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62 + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +#include + +/ { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi1_clk_gpio>, + <&pinctrl_qspi1_cs_gpio>, + <&pinctrl_qspi1_io0_gpio>, + <&pinctrl_qspi1_io1_gpio>; + + /* SODIMM 52 - USER_LED_1_RED */ + led-0 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&main_gpio0 0 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 54 - USER_LED_1_GREEN */ + led-1 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&main_gpio0 11 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 56 - USER_LED_2_RED */ + led-2 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&main_gpio0 3 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 58 - USER_LED_2_GREEN */ + led-3 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&main_gpio0 4 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +/* Verdin ETH */ +&cpsw3g { + status = "okay"; +}; + +/* Verdin MDIO */ +&cpsw3g_mdio { + status = "okay"; +}; + +/* Verdin ETH_1*/ +&cpsw_port1 { + status = "okay"; +}; + +/* Verdin PWM_1 and PWM_2*/ +&epwm0 { + status = "okay"; +}; + +/* Verdin PWM_3 DSI */ +&epwm1 { + status = "okay"; +}; + +&main_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ctrl_sleep_moci>, + <&pinctrl_gpio_1>, + <&pinctrl_gpio_2>, + <&pinctrl_gpio_3>, + <&pinctrl_gpio_4>; +}; + +/* Verdin I2C_1 */ +&main_i2c1 { + status = "okay"; + + /* Temperature sensor */ + sensor@4f { + compatible = "ti,tmp1075"; + reg = <0x4f>; + }; + + /* EEPROM */ + eeprom@57 { + compatible = "st,24c02", "atmel,24c02"; + reg = <0x57>; + pagesize = <16>; + }; +}; + +/* Verdin I2C_2 DSI */ +&main_i2c2 { + status = "okay"; +}; + +/* Verdin I2C_4 CSI */ +&main_i2c3 { + status = "okay"; +}; + +/* Verdin CAN_1 */ +&main_mcan0 { + status = "okay"; +}; + +/* Verdin SPI_1 */ +&main_spi1 { + pinctrl-0 = <&pinctrl_spi1>, + <&pinctrl_spi1_cs0>, + <&pinctrl_qspi1_cs2_gpio>; + cs-gpios = <0>, <&main_gpio0 12 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +/* Verdin UART_3 */ +&main_uart0 { + status = "okay"; +}; + +/* Verdin UART_1 */ +&main_uart1 { + status = "okay"; +}; + +/* Verdin I2C_3_HDMI */ +&mcu_i2c0 { + status = "okay"; +}; + +/* Verdin CAN_2 */ +&mcu_mcan0 { + status = "okay"; +}; + +/* Verdin UART_4 */ +&mcu_uart0 { + status = "okay"; +}; + +/* Verdin SD_1 */ +&sdhci1 { + status = "okay"; +}; + +/* Verdin USB_1 */ +&usbss0 { + status = "okay"; +}; + +&usb0 { + status = "okay"; +}; + +/* Verdin USB_2 */ +&usbss1 { + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; + +/* Verdin CTRL_WAKE1_MICO# */ +&verdin_gpio_keys { + status = "okay"; +}; + +/* Verdin UART_2 */ +&wkup_uart0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-verdin-wifi.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-wifi.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62-verdin-wifi.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-wifi.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -26,7 +26,6 @@ mmc-pwrseq = <&wifi_pwrseq>; non-removable; ti,fails-without-test-cd; - ti,driver-strength-ohm = <50>; vmmc-supply = <®_3v3>; status = "okay"; }; @@ -35,5 +34,11 @@ &main_uart5 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart5>; + uart-has-rtscts; status = "okay"; + + bluetooth { + compatible = "nxp,88w8987-bt"; + fw-init-baudrate = <3000000>; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -207,6 +207,5 @@ /* Verdin UART_2 */ &wkup_uart0 { - /* FIXME: WKUP UART0 is used by DM firmware */ - status = "reserved"; + status = "okay"; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi 2024-07-07 20:37:34.624306449 -0400 @@ -1,12 +1,15 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree Source for AM625 SoC Family Wakeup Domain peripherals * - * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/ */ +#include + &cbass_wakeup { wkup_conf: syscon@43000000 { + bootph-all; compatible = "syscon", "simple-mfd"; reg = <0x00 0x43000000 0x00 0x20000>; #address-cells = <1>; @@ -14,19 +17,50 @@ ranges = <0x0 0x00 0x43000000 0x20000>; chipid: chipid@14 { + bootph-all; compatible = "ti,am654-chipid"; reg = <0x14 0x4>; }; + + usb0_phy_ctrl: syscon@4008 { + compatible = "ti,am62-usb-phy-ctrl", "syscon"; + reg = <0x4008 0x4>; + }; + + usb1_phy_ctrl: syscon@4018 { + compatible = "ti,am62-usb-phy-ctrl", "syscon"; + reg = <0x4018 0x4>; + }; }; - wkup_uart0: serial@2b300000 { - compatible = "ti,am64-uart", "ti,am654-uart"; - reg = <0x00 0x2b300000 0x00 0x100>; - interrupts = ; + target-module@2b300050 { + compatible = "ti,sysc-omap2", "ti,sysc"; + reg = <0x00 0x2b300050 0x00 0x4>, + <0x00 0x2b300054 0x00 0x4>, + <0x00 0x2b300058 0x00 0x4>; + reg-names = "rev", "sysc", "syss"; + ti,sysc-mask = <(SYSC_OMAP2_ENAWAKEUP | + SYSC_OMAP2_SOFTRESET | + SYSC_OMAP2_AUTOIDLE)>; + ti,sysc-sidle = , + , + , + ; + ti,syss-mask = <1>; + ti,no-reset-on-init; power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>; clocks = <&k3_clks 114 0>; - clock-names = "fclk"; - status = "disabled"; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x2b300000 0x100000>; + + wkup_uart0: serial@0 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x0 0x100>; + interrupts = ; + status = "disabled"; + }; }; wkup_i2c0: i2c@2b200000 { diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra-gpio-fan.dtso b/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra-gpio-fan.dtso --- a/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra-gpio-fan.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra-gpio-fan.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) 2024 PHYTEC America LLC + * Author: Garrett Giordano + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include "k3-pinctrl.h" + +&{/} { + fan: gpio-fan { + compatible = "gpio-fan"; + gpio-fan,speed-map = <0 0 8600 1>; + gpios = <&main_gpio0 40 GPIO_ACTIVE_LOW>; + #cooling-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&gpio_fan_pins_default>; + }; +}; + +&main_pmx0 { + gpio_fan_pins_default: gpio-fan-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x0a4, PIN_OUTPUT, 7) /* (M22) GPMC0_DIR.GPIO0_40 */ + >; + }; +}; + +&thermal_zones { + main0_thermal: main0-thermal { + trips { + main0_thermal_trip0: main0-thermal-trip { + temperature = <65000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "active"; + }; + }; + + cooling-maps { + map0 { + trip = <&main0_thermal_trip0>; + cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Common dtsi for AM62x SK and derivatives * - * Copyright (C) 2021-2023 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/ */ #include @@ -28,6 +28,7 @@ }; memory@80000000 { + bootph-pre-ram; device_type = "memory"; /* 2G RAM */ reg = <0x00000000 0x80000000 0x00000000 0x80000000>; @@ -38,15 +39,41 @@ #size-cells = <2>; ranges; - ramoops@9ca00000 { + ramoops@9c700000 { compatible = "ramoops"; - reg = <0x00 0x9ca00000 0x00 0x00100000>; + reg = <0x00 0x9c700000 0x00 0x00100000>; record-size = <0x8000>; console-size = <0x8000>; ftrace-size = <0x00>; pmsg-size = <0x8000>; }; + rtos_ipc_memory_region: ipc-memories@9c800000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9c800000 0x00 0x00300000>; + no-map; + }; + + mcu_m4fss_dma_memory_region: m4f-dma-memory@9cb00000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9cb00000 0x00 0x100000>; + no-map; + }; + + mcu_m4fss_memory_region: m4f-memory@9cc00000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9cc00000 0x00 0xe00000>; + no-map; + }; + + /* global cma region */ + linux,cma { + compatible = "shared-dma-pool"; + size = <0x00 0x8000000>; + reusable; + linux,cma-default; + }; + secure_tfa_ddr: tfa@9e780000 { reg = <0x00 0x9e780000 0x00 0x80000>; alignment = <0x1000>; @@ -130,6 +157,7 @@ &main_pmx0 { /* First pad number is ALW package and second is AMC package */ main_uart0_pins_default: main-uart0-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x1c8, PIN_INPUT, 0) /* (D14/A13) UART0_RXD */ AM62X_IOPAD(0x1cc, PIN_OUTPUT, 0) /* (E14/E11) UART0_TXD */ @@ -137,6 +165,7 @@ }; main_uart1_pins_default: main-uart1-default-pins { + bootph-pre-ram; pinctrl-single,pins = < AM62X_IOPAD(0x194, PIN_INPUT, 2) /* (B19/B18) MCASP0_AXR3.UART1_CTSn */ AM62X_IOPAD(0x198, PIN_OUTPUT, 2) /* (A19/B17) MCASP0_AXR2.UART1_RTSn */ @@ -153,6 +182,7 @@ }; main_i2c1_pins_default: main-i2c1-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x1e8, PIN_INPUT_PULLUP, 0) /* (B17/A17) I2C1_SCL */ AM62X_IOPAD(0x1ec, PIN_INPUT_PULLUP, 0) /* (A17/A16) I2C1_SDA */ @@ -167,6 +197,7 @@ }; main_mmc0_pins_default: main-mmc0-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x220, PIN_INPUT, 0) /* (Y3/V3) MMC0_CMD */ AM62X_IOPAD(0x218, PIN_INPUT, 0) /* (AB1/Y1) MMC0_CLK */ @@ -182,6 +213,7 @@ }; main_mmc1_pins_default: main-mmc1-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x23c, PIN_INPUT, 0) /* (A21/C18) MMC1_CMD */ AM62X_IOPAD(0x234, PIN_INPUT, 0) /* (B22/A20) MMC1_CLK */ @@ -207,6 +239,7 @@ }; main_rgmii1_pins_default: main-rgmii1-default-pins { + bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x14c, PIN_INPUT, 0) /* (AB17/W15) RGMII1_RD0 */ AM62X_IOPAD(0x150, PIN_INPUT, 0) /* (AC17/Y16) RGMII1_RD1 */ @@ -223,6 +256,22 @@ >; }; + ospi0_pins_default: ospi0-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x000, PIN_OUTPUT, 0) /* (H24) OSPI0_CLK */ + AM62X_IOPAD(0x02c, PIN_OUTPUT, 0) /* (F23) OSPI0_CSn0 */ + AM62X_IOPAD(0x00c, PIN_INPUT, 0) /* (E25) OSPI0_D0 */ + AM62X_IOPAD(0x010, PIN_INPUT, 0) /* (G24) OSPI0_D1 */ + AM62X_IOPAD(0x014, PIN_INPUT, 0) /* (F25) OSPI0_D2 */ + AM62X_IOPAD(0x018, PIN_INPUT, 0) /* (F24) OSPI0_D3 */ + AM62X_IOPAD(0x01c, PIN_INPUT, 0) /* (J23) OSPI0_D4 */ + AM62X_IOPAD(0x020, PIN_INPUT, 0) /* (J25) OSPI0_D5 */ + AM62X_IOPAD(0x024, PIN_INPUT, 0) /* (H25) OSPI0_D6 */ + AM62X_IOPAD(0x028, PIN_INPUT, 0) /* (J22) OSPI0_D7 */ + AM62X_IOPAD(0x008, PIN_INPUT, 0) /* (J24) OSPI0_DQS */ + >; + }; + main_usb1_pins_default: main-usb1-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x0258, PIN_OUTPUT, 0) /* (F18/E16) USB1_DRVVBUS */ @@ -274,6 +323,7 @@ &mcu_pmx0 { wkup_uart0_pins_default: wkup-uart0-default-pins { + bootph-pre-ram; pinctrl-single,pins = < AM62X_MCU_IOPAD(0x02c, PIN_INPUT, 0) /* (C6/A7) WKUP_UART0_CTSn */ AM62X_MCU_IOPAD(0x030, PIN_OUTPUT, 0) /* (A4/B4) WKUP_UART0_RTSn */ @@ -285,19 +335,25 @@ &wkup_uart0 { /* WKUP UART0 is used by DM firmware */ + bootph-pre-ram; status = "reserved"; pinctrl-names = "default"; pinctrl-0 = <&wkup_uart0_pins_default>; }; &main_uart0 { + bootph-all; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_uart0_pins_default>; + interrupts-extended = <&gic500 GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>, + <&main_pmx0 0x1c8>; /* (D14) UART0_RXD PADCONFIG114 */ + interrupt-names = "irq", "wakeup"; }; &main_uart1 { /* Main UART1 is used by TIFS firmware */ + bootph-pre-ram; status = "reserved"; pinctrl-names = "default"; pinctrl-0 = <&main_uart1_pins_default>; @@ -389,39 +445,50 @@ }; }; +&main_i2c2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c2_pins_default>; + clock-frequency = <400000>; +}; + &sdhci0 { + bootph-all; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_mmc0_pins_default>; - ti,driver-strength-ohm = <50>; disable-wp; }; &sdhci1 { /* SD/MMC */ + bootph-all; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; - ti,driver-strength-ohm = <50>; disable-wp; }; &cpsw3g { + bootph-all; pinctrl-names = "default"; pinctrl-0 = <&main_rgmii1_pins_default>; }; &cpsw_port1 { + bootph-all; phy-mode = "rgmii-rxid"; phy-handle = <&cpsw3g_phy0>; }; &cpsw3g_mdio { + bootph-all; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_mdio1_pins_default>; cpsw3g_phy0: ethernet-phy@0 { + bootph-all; reg = <0>; ti,rx-internal-delay = ; ti,fifo-depth = ; @@ -436,7 +503,15 @@ }; }; +&mcu_m4fss { + mboxes = <&mailbox0_cluster0 &mbox_m4_0>; + memory-region = <&mcu_m4fss_dma_memory_region>, + <&mcu_m4fss_memory_region>; + status = "okay"; +}; + &usbss0 { + bootph-all; status = "okay"; ti,vbus-divider; }; @@ -447,6 +522,7 @@ }; &usb0 { + bootph-all; #address-cells = <1>; #size-cells = <0>; usb-role-switch; @@ -481,11 +557,16 @@ 0 0 0 0 0 0 0 0 >; - tx-num-evt = <32>; - rx-num-evt = <32>; + tx-num-evt = <0>; + rx-num-evt = <0>; +}; + +&dss_oldi_io_ctrl { + bootph-all; }; &dss { + bootph-all; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_dss0_pins_default>; @@ -493,7 +574,7 @@ &dss_ports { /* VP2: DPI Output */ - port@1 { + hdmi0_dss: port@1 { reg = <1>; dpi1_out: endpoint { @@ -501,3 +582,18 @@ }; }; }; + +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */ +&mcu_gpio0 { + status = "reserved"; +}; + +&mcu_gpio_intr { + status = "reserved"; +}; + +&ospi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&ospi0_pins_default>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX219 (RPi v2) Camera Module + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_imx219_fixed: imx219-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + /* CAM port */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ov5640: camera@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed>; + clock-names = "xclk"; + + reset-gpios = <&exp1 13 GPIO_ACTIVE_HIGH>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ALINX AN5641 & Digilent PCam 5C - OV5640 camera module + * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + /* CAM port */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + powerdown-gpios = <&exp1 13 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Technexion TEVI-OV5640-*-RPI - OV5640 camera module + * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + /* CAM port */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + powerdown-gpios = <&exp1 13 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-v3link-fusion.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-v3link-fusion.dtso --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-v3link-fusion.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-v3link-fusion.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Arducam V3Link UC-A09 board + * https://www.arducam.com/fpd-link-3-cameras/ + * + * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62x-sk-eqep.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-eqep.dtso --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-eqep.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-eqep.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for enabling EQEP on AM625-SK, AM62 LP-SK, and AM62A7-SK + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&main_pmx0 { + main_eqep0_pins_default: main-eqep0-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x0194, PIN_INPUT, 8) /* (B19/C19) MCASP0_AXR3.EQEP0_A */ + AM62X_IOPAD(0x0198, PIN_INPUT, 8) /* (A19/B19) MCASP0_AXR2.EQEP0_B */ + AM62X_IOPAD(0x01a0, PIN_INPUT, 8) /* (E18/B20) MCASP0_AXR0.EQEP0_I */ + AM62X_IOPAD(0x019c, PIN_INPUT, 8) /* (B18/B18) MCASP0_AXR1.EQEP0_S */ + >; + }; +}; + +&main_i2c1 { + gpio@22 { + p25-hog { + /* P25 - UART1_FET_SEL */ + gpio-hog; + gpios = <21 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "UART1_FET_SEL"; + }; + }; +}; + +&main_uart1 { + /* Disable FW debug logs */ + status = "disabled"; +}; + +&eqep0 { + status = "okay"; + /* EQEP0 A & B available on pins 38 & 35 of J3 on AM625-SK & AM62 LP-SK */ + /* EQEP0 A & B available on pins 40 & 38 of J3 on AM62A7-SK */ + pinctrl-names = "default"; + pinctrl-0 = <&main_eqep0_pins_default>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62x-sk-fastboot-disable-hdmi.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-fastboot-disable-hdmi.dtso --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-fastboot-disable-hdmi.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-fastboot-disable-hdmi.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * Overlay to remove HDMI support for TI K3 AM62* SK + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +&hdmi0 { + status = "disabled"; +}; + +&sii9022 { + status = "disabled"; +}; + +&hdmi0_dss { + status = "disabled"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62x-sk-lpm-wkup-sources.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-lpm-wkup-sources.dtso --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-lpm-wkup-sources.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-lpm-wkup-sources.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * AM62 family of devices can wakeup from Low Power Modes via + * multiple wakeup sources. This overlay enables MAIN GPIO, MCU GPIO, + * and MCU MCAN pins. + * + * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "k3-pinctrl.h" + +&{/} { + gpio_key { + compatible = "gpio-keys"; + autorepeat; + pinctrl-names = "default"; + pinctrl-0 = <&main_gpio1_pins_default>; + switch { + label = "WKGPIO"; + linux,code = ; + interrupts-extended = <&main_gpio1 10 IRQ_TYPE_EDGE_RISING>, + <&main_pmx0 0x1a0>; + interrupt-names = "irq", "wakeup"; + }; + }; + + mcu_gpio_key { + compatible = "gpio-keys"; + autorepeat; + pinctrl-names = "default"; + pinctrl-0 = <&wake_mcugpio1_pins_default>; + interrupt-parent = <&mcu_gpio0>; + interrupts = <4 IRQ_TYPE_EDGE_RISING>; + switch { + label = "MCUGPIO"; + linux,code = <143>; + gpios = <&mcu_gpio0 4 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + }; +}; + +&main_pmx0 { + main_gpio1_pins_default: main-gpio1-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x1a0, PIN_INPUT_PULLUP, 7) /* (E18) MCASP0_AXR0.EHRPWM1_B */ + >; + }; +}; + +&mcu_pmx0 { + wake_mcugpio1_pins_default: wake-mcugpio1-pins-default { + pinctrl-single,pins = < + AM62X_MCU_IOPAD(0x0010, PIN_INPUT, 7) /* (D8) MCU_SPI0_D1.MCU_GPIO0_4 */ + >; + }; + + mcu_mcan0_tx_pins_default: mcu-mcan0-tx-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x034, PIN_OUTPUT, 0) /* (D6) MCU_MCAN0_TX */ + >; + }; + + mcu_mcan0_rx_pins_default: mcu-mcan0-rx-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x038, PIN_INPUT, 0) /* (B3) MCU_MCAN0_RX */ + >; + }; + + mcu_mcan0_rx_pins_wakeup: mcu-mcan0-rx-pins-wakeup { + pinctrl-single,pins = < + AM62X_IOPAD(0x038, PIN_INPUT | WKUP_EN, 0) /* (B3) MCU_MCAN0_RX */ + >; + }; + + mcu_mcan1_tx_pins_default: mcu-mcan1-tx-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x03c, PIN_OUTPUT, 0) /* (E5) MCU_MCAN1_TX */ + >; + }; + + mcu_mcan1_rx_pins_default: mcu-mcan1-rx-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x040, PIN_INPUT, 0) /* (D4) MCU_MCAN1_RX */ + >; + }; + + mcu_mcan1_rx_pins_wakeup: mcu-mcan1-rx-pins-wakeup { + pinctrl-single,pins = < + AM62X_IOPAD(0x040, PIN_INPUT | WKUP_EN, 0) /* (D4) MCU_MCAN1_RX */ + >; + }; + + mcu_uart0_pins_default: mcu-uart0-pins-default { + pinctrl-single,pins = < + AM62X_MCU_IOPAD(0x001c, PIN_INPUT, 0) /* MCU_UART0_CTSn */ + AM62X_MCU_IOPAD(0x0020, PIN_OUTPUT, 0) /* MCU_UART0_RTSn */ + AM62X_MCU_IOPAD(0x0018, PIN_OUTPUT, 0) /* MCU_UART0_TXD */ + >; + }; + + mcu_uart0_rxd_pins_default: mcu-uart0-rxd-pins-default { + pinctrl-single,pins = < + AM62X_MCU_IOPAD(0x0014, PIN_INPUT, 0) /* MCU_UART0_RXD */ + >; + }; + + mcu_uart0_rxd_pins_wakeup: mcu-uart0-rxd-pins-wakeup { + pinctrl-single,pins = < + AM62X_MCU_IOPAD(0x0014, PIN_INPUT | WKUP_EN, 0) /* MCU_UART0_RXD */ + >; + }; +}; + +&mcu_gpio0 { + status = "okay"; +}; + +&mcu_gpio_intr { + status = "okay"; +}; + +&mcu_mcan0 { + pinctrl-names = "default", "wakeup"; + pinctrl-0 = <&mcu_mcan0_tx_pins_default>, <&mcu_mcan0_rx_pins_default>; + pinctrl-1 = <&mcu_mcan0_tx_pins_default>, <&mcu_mcan0_rx_pins_wakeup>; + status = "okay"; +}; + +&mcu_mcan1 { + pinctrl-names = "default", "wakeup"; + pinctrl-0 = <&mcu_mcan1_tx_pins_default>, <&mcu_mcan1_rx_pins_default>; + pinctrl-1 = <&mcu_mcan1_tx_pins_default>, <&mcu_mcan1_rx_pins_wakeup>; + status = "okay"; +}; + +&mcu_uart0 { + pinctrl-names = "default", "wakeup"; + pinctrl-0 = <&mcu_uart0_pins_default>, <&mcu_uart0_rxd_pins_default>; + pinctrl-1 = <&mcu_uart0_pins_default>, <&mcu_uart0_rxd_pins_wakeup>; + status = "ok"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62x-sk-mcan.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-mcan.dtso --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-mcan.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-mcan.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT overlay to enable MCAN on AM625-SK, AM62A-SK, AM62 LP-SK + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include "k3-pinctrl.h" + +&{/} { + transceiver1: can-phy0 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; + + transceiver2: can-phy1 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; + + transceiver3: can-phy2 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; +}; + +&main_pmx0 { + main_mcan0_pins_default: main-mcan0-pins-default { + pinctrl-single,pins = < + AM62X_IOPAD(0x01dc, PIN_INPUT, 0) /* (E15) MCAN0_RX */ + AM62X_IOPAD(0x01d8, PIN_OUTPUT, 0) /* (C15) MCAN0_TX */ + >; + }; +}; + +&mcu_pmx0 { + mcu_mcan0_pins_default: mcu-mcan0-pins-default { + pinctrl-single,pins = < + AM62X_MCU_IOPAD(0x0038, PIN_INPUT, 0) /* (B3) MCU_MCAN0_RX */ + AM62X_MCU_IOPAD(0x0034, PIN_OUTPUT, 0) /* (D6) MCU_MCAN0_TX */ + >; + }; + + mcu_mcan1_pins_default: mcu-mcan1-pins-default { + pinctrl-single,pins = < + AM62X_MCU_IOPAD(0x0040, PIN_INPUT, 0) /* (D4) MCU_MCAN1_RX */ + AM62X_MCU_IOPAD(0x003c, PIN_OUTPUT, 0) /* (E5) MCU_MCAN1_TX */ + >; + }; +}; + +&main_mcan0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan0_pins_default>; + phys = <&transceiver1>; + status = "okay"; +}; + +&mcu_mcan0 { + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_pins_default>; + phys = <&transceiver2>; + status = "okay"; +}; + +&mcu_mcan1 { + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan1_pins_default>; + phys = <&transceiver3>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am62x-sk-microtips-mf103hie-lcd2.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-microtips-mf103hie-lcd2.dtso --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-microtips-mf103hie-lcd2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-microtips-mf103hie-lcd2.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * Microtips integrated OLDI panel (MF-103HIEB0GA0) (SK-LCD2) DT overlay for AM625-SK and AM62-LP SK + * + * AM625-SKEVM: https://www.ti.com/tool/SK-AM62 + * AM62-LP SKEVM: https://www.ti.com/tool/SK-AM62-LP + * Panel datasheet: https://simplespec.microtipsusa.com/uploads/spec/datasheetFile/2660/13-103HIEB0GA0-S_V1.0_20211206.pdf + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&{/} { + display { + compatible = "microtips,mf-103hieb0ga0", "panel-simple"; + /* + * Note that the OLDI TX 0 transmits the odd set of pixels + * while the OLDI TX 1 transmits the even set. This is a + * fixed configuration in the IP integration and is not + * changeable. The properties, "dual-lvds-odd-pixels" and + * "dual-lvds-even-pixels" have been used to merely + * identify if a Dual Link configuration is required. + * Swapping them will cause an error in the dss oldi driver. + */ + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + lcd_in0: endpoint { + remote-endpoint = <&oldi_0_out>; + }; + }; + port@1 { + reg = <1>; + dual-lvds-even-pixels; + lcd_in1: endpoint { + remote-endpoint = <&oldi_1_out>; + }; + }; + }; + }; +}; + +&dss { + status = "okay"; +}; + +&oldi0 { + status = "okay"; +}; + +&oldi1 { + status = "okay"; +}; + +&oldi0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + oldi_0_in: endpoint { + remote-endpoint = <&dpi0_out0>; + }; + }; + + port@1 { + reg = <1>; + oldi_0_out: endpoint { + remote-endpoint = <&lcd_in0>; + }; + }; +}; + +&oldi1_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + oldi_1_in: endpoint { + remote-endpoint = <&dpi0_out1>; + }; + }; + + port@1 { + reg = <1>; + oldi_1_out: endpoint { + remote-endpoint = <&lcd_in1>; + }; + }; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VP1: Output to OLDI */ + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + dpi0_out0: endpoint@0 { + reg = <0>; + remote-endpoint = <&oldi_0_in>; + }; + dpi0_out1: endpoint@1 { + reg = <1>; + remote-endpoint = <&oldi_1_in>; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am642-evm.dts b/arch/arm64/boot/dts/ti/k3-am642-evm.dts --- a/arch/arm64/boot/dts/ti/k3-am642-evm.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am642-evm.dts 2024-07-07 20:37:34.628306469 -0400 @@ -32,6 +32,7 @@ mmc1 = &sdhci1; ethernet0 = &cpsw_port1; ethernet1 = &cpsw_port2; + ethernet2 = &icssg1_emac0; }; memory@80000000 { @@ -100,6 +101,18 @@ no-map; }; + mcu_m4fss_dma_memory_region: m4f-dma-memory@a4000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4000000 0x00 0x100000>; + no-map; + }; + + mcu_m4fss_memory_region: m4f-memory@a4100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4100000 0x00 0xf00000>; + no-map; + }; + rtos_ipc_memory_region: ipc-memories@a5000000 { reg = <0x00 0xa5000000 0x00 0x00800000>; alignment = <0x1000>; @@ -198,7 +211,7 @@ mux-gpios = <&exp1 12 GPIO_ACTIVE_HIGH>; }; - mdio-mux-1 { + mdio_mux_1: mdio-mux-1 { compatible = "mdio-mux-multiplexer"; mux-controls = <&mdio_mux>; mdio-parent-bus = <&cpsw3g_mdio>; @@ -229,6 +242,65 @@ max-bitrate = <5000000>; standby-gpios = <&exp1 9 GPIO_ACTIVE_HIGH>; }; + + icssg1_eth: icssg1-eth { + compatible = "ti,am642-icssg-prueth"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg1_rgmii1_pins_default>; + sram = <&oc_sram>; + ti,prus = <&pru1_0>, <&rtu1_0>, <&tx_pru1_0>, <&pru1_1>, <&rtu1_1>, <&tx_pru1_1>; + firmware-name = "ti-pruss/am64x-sr2-pru0-prueth-fw.elf", + "ti-pruss/am64x-sr2-rtu0-prueth-fw.elf", + "ti-pruss/am64x-sr2-txpru0-prueth-fw.elf", + "ti-pruss/am64x-sr2-pru1-prueth-fw.elf", + "ti-pruss/am64x-sr2-rtu1-prueth-fw.elf", + "ti-pruss/am64x-sr2-txpru1-prueth-fw.elf"; + + ti,pruss-gp-mux-sel = <2>, /* MII mode */ + <2>, + <2>, + <2>, /* MII mode */ + <2>, + <2>; + ti,mii-g-rt = <&icssg1_mii_g_rt>; + ti,mii-rt = <&icssg1_mii_rt>; + ti,iep = <&icssg1_iep0>, <&icssg1_iep1>; + ti,pa-stats = <&icssg1_pa_stats>; + interrupt-parent = <&icssg1_intc>; + interrupts = <24 0 2>, <25 1 3>; + interrupt-names = "tx_ts0", "tx_ts1"; + dmas = <&main_pktdma 0xc200 15>, /* egress slice 0 */ + <&main_pktdma 0xc201 15>, /* egress slice 0 */ + <&main_pktdma 0xc202 15>, /* egress slice 0 */ + <&main_pktdma 0xc203 15>, /* egress slice 0 */ + <&main_pktdma 0xc204 15>, /* egress slice 1 */ + <&main_pktdma 0xc205 15>, /* egress slice 1 */ + <&main_pktdma 0xc206 15>, /* egress slice 1 */ + <&main_pktdma 0xc207 15>, /* egress slice 1 */ + <&main_pktdma 0x4200 15>, /* ingress slice 0 */ + <&main_pktdma 0x4201 15>; /* ingress slice 1 */ + dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3", + "tx1-0", "tx1-1", "tx1-2", "tx1-3", + "rx0", "rx1"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + icssg1_emac0: port@0 { + reg = <0>; + phy-handle = <&icssg1_phy1>; + phy-mode = "rgmii-id"; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + icssg1_emac1: port@1 { + reg = <1>; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + status = "disabled"; + }; + }; + }; }; &main_pmx0 { @@ -383,6 +455,36 @@ AM64X_IOPAD(0x0030, PIN_OUTPUT_PULLUP, 7) /* (L18) OSPI0_CSN1.GPIO0_12 */ >; }; + + icssg1_mdio1_pins_default: icssg1-mdio1-default-pins { + pinctrl-single,pins = < + AM64X_IOPAD(0x015c, PIN_OUTPUT, 0) /* (Y6) PRG1_MDIO0_MDC */ + AM64X_IOPAD(0x0158, PIN_INPUT, 0) /* (AA6) PRG1_MDIO0_MDIO */ + >; + }; + + icssg1_rgmii1_pins_default: icssg1-rgmii1-default-pins{ + pinctrl-single,pins = < + AM64X_IOPAD(0x00b8, PIN_INPUT, 2) /* (Y7) PRG1_PRU0_GPO0.PRG1_RGMII1_RD0 */ + AM64X_IOPAD(0x00bc, PIN_INPUT, 2) /* (U8) PRG1_PRU0_GPO1.PRG1_RGMII1_RD1 */ + AM64X_IOPAD(0x00c0, PIN_INPUT, 2) /* (W8) PRG1_PRU0_GPO2.PRG1_RGMII1_RD2 */ + AM64X_IOPAD(0x00c4, PIN_INPUT, 2) /* (V8) PRG1_PRU0_GPO3.PRG1_RGMII1_RD3 */ + AM64X_IOPAD(0x00d0, PIN_INPUT, 2) /* (AA7) PRG1_PRU0_GPO6.PRG1_RGMII1_RXC */ + AM64X_IOPAD(0x00c8, PIN_INPUT, 2) /* (Y8) PRG1_PRU0_GPO4.PRG1_RGMII1_RX_CTL */ + AM64X_IOPAD(0x00e4, PIN_INPUT, 2) /* (AA8) PRG1_PRU0_GPO11.PRG1_RGMII1_TD0 */ + AM64X_IOPAD(0x00e8, PIN_INPUT, 2) /* (U9) PRG1_PRU0_GPO12.PRG1_RGMII1_TD1 */ + AM64X_IOPAD(0x00ec, PIN_INPUT, 2) /* (W9) PRG1_PRU0_GPO13.PRG1_RGMII1_TD2 */ + AM64X_IOPAD(0x00f0, PIN_INPUT, 2) /* (AA9) PRG1_PRU0_GPO14.PRG1_RGMII1_TD3 */ + AM64X_IOPAD(0x00f8, PIN_INPUT, 2) /* (V9) PRG1_PRU0_GPO16.PRG1_RGMII1_TXC */ + AM64X_IOPAD(0x00f4, PIN_INPUT, 2) /* (Y9) PRG1_PRU0_GPO15.PRG1_RGMII1_TX_CTL */ + >; + }; + + icssg1_iep0_pins_default: icssg1-iep0-default-pins { + pinctrl-single,pins = < + AM64X_IOPAD(0x0104, PIN_OUTPUT, 2) /* (W7) PRG1_PRU0_GPO19.PRG1_IEP0_EDC_SYNC_OUT0 */ + >; + }; }; &main_uart0 { @@ -407,6 +509,15 @@ pinctrl-0 = <&main_i2c0_pins_default>; clock-frequency = <400000>; + gpio@38 { + /* TCA9554 */ + compatible = "nxp,pca9554"; + reg = <0x38>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "HSE_DETECT"; + }; + eeprom@50 { /* AT24CM01 */ compatible = "atmel,24c1024"; @@ -459,11 +570,15 @@ bootph-all; }; -/* mcu_gpio0 is reserved for mcu firmware usage */ +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */ &mcu_gpio0 { status = "reserved"; }; +&mcu_gpio_intr { + status = "reserved"; +}; + &main_spi0 { status = "okay"; pinctrl-names = "default"; @@ -481,10 +596,10 @@ /* eMMC */ &sdhci0 { status = "okay"; - bus-width = <8>; non-removable; ti,driver-strength-ohm = <50>; disable-wp; + bootph-all; }; /* SD/MMC */ @@ -493,9 +608,7 @@ status = "okay"; vmmc-supply = <&vdd_mmc1>; pinctrl-names = "default"; - bus-width = <4>; pinctrl-0 = <&main_mmc1_pins_default>; - ti,driver-strength-ohm = <50>; disable-wp; }; @@ -517,6 +630,11 @@ bootph-all; pinctrl-names = "default"; pinctrl-0 = <&rgmii1_pins_default>, <&rgmii2_pins_default>; + + /* Map HW8_TS_PUSH to GENF1 */ + cpts@3d000 { + ti,pps = <7 1>; + }; }; &cpsw_port1 { @@ -647,29 +765,36 @@ }; &main_r5fss0_core0 { - mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss0_core0>; + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core0>; memory-region = <&main_r5fss0_core0_dma_memory_region>, <&main_r5fss0_core0_memory_region>; }; &main_r5fss0_core1 { - mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss0_core1>; + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core1>; memory-region = <&main_r5fss0_core1_dma_memory_region>, <&main_r5fss0_core1_memory_region>; }; &main_r5fss1_core0 { - mboxes = <&mailbox0_cluster4>, <&mbox_main_r5fss1_core0>; + mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core0>; memory-region = <&main_r5fss1_core0_dma_memory_region>, <&main_r5fss1_core0_memory_region>; }; &main_r5fss1_core1 { - mboxes = <&mailbox0_cluster4>, <&mbox_main_r5fss1_core1>; + mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core1>; memory-region = <&main_r5fss1_core1_dma_memory_region>, <&main_r5fss1_core1_memory_region>; }; +&mcu_m4fss { + mboxes = <&mailbox0_cluster6 &mbox_m4_0>; + memory-region = <&mcu_m4fss_dma_memory_region>, + <&mcu_m4fss_memory_region>; + status = "okay"; +}; + &serdes_ln_ctrl { idle-states = ; }; @@ -692,12 +817,6 @@ num-lanes = <1>; }; -&pcie0_ep { - phys = <&serdes0_pcie_link>; - phy-names = "pcie-phy"; - num-lanes = <1>; -}; - &ecap0 { status = "okay"; /* PWM is available on Pin 1 of header J12 */ @@ -718,3 +837,41 @@ pinctrl-0 = <&main_mcan1_pins_default>; phys = <&transceiver2>; }; + +&icssg1_mdio { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg1_mdio1_pins_default>; + + icssg1_phy1: ethernet-phy@f { + reg = <0xf>; + tx-internal-delay-ps = <250>; + rx-internal-delay-ps = <2000>; + }; +}; + +#define TS_OFFSET(pa, val) (0x4+(pa)*4) (0x10000 | val) + +×ync_router { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&cpsw_cpts_pps>; + + /* + * Use Time Sync Router to map GENF1 input to HW8_TS_PUSH output as well + * as the PRU ICSSG0 SYNC1 output. + */ + cpsw_cpts_pps: cpsw-cpts-pps { + pinctrl-single,pins = < + /* pps [cpts genf1] in22 -> out37 [cpts hw8_push] */ + TS_OFFSET(37, 22) + /* pps [cpts genf1] in22 -> out26 [SYNC1_OUT pin] */ + TS_OFFSET(26, 22) + >; + }; +}; + +&icssg1_iep0 { + pinctrl-names = "default"; + pinctrl-0 = <&icssg1_iep0_pins_default>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am642-evm-icssg1-dualemac.dtso b/arch/arm64/boot/dts/ti/k3-am642-evm-icssg1-dualemac.dtso --- a/arch/arm64/boot/dts/ti/k3-am642-evm-icssg1-dualemac.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am642-evm-icssg1-dualemac.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT overlay for enabling 2nd ICSSG1 port on AM642 EVM + * + * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&{/} { + aliases { + ethernet1 = "/icssg1-eth/ethernet-ports/port@1"; + }; + + mdio-mux-2 { + compatible = "mdio-mux-multiplexer"; + mux-controls = <&mdio_mux>; + mdio-parent-bus = <&icssg1_mdio>; + #address-cells = <1>; + #size-cells = <0>; + + mdio@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + icssg1_phy2: ethernet-phy@3 { + reg = <3>; + tx-internal-delay-ps = <250>; + rx-internal-delay-ps = <2000>; + }; + }; + }; +}; + +&main_pmx0 { + icssg1_rgmii2_pins_default: icssg1-rgmii2-default-pins { + pinctrl-single,pins = < + AM64X_IOPAD(0x0108, PIN_INPUT, 2) /* (W11) PRG1_PRU1_GPO0.RGMII2_RD0 */ + AM64X_IOPAD(0x010c, PIN_INPUT, 2) /* (V11) PRG1_PRU1_GPO1.RGMII2_RD1 */ + AM64X_IOPAD(0x0110, PIN_INPUT, 2) /* (AA12) PRG1_PRU1_GPO2.RGMII2_RD2 */ + AM64X_IOPAD(0x0114, PIN_INPUT, 2) /* (Y12) PRG1_PRU1_GPO3.RGMII2_RD3 */ + AM64X_IOPAD(0x0120, PIN_INPUT, 2) /* (U11) PRG1_PRU1_GPO6.RGMII2_RXC */ + AM64X_IOPAD(0x0118, PIN_INPUT, 2) /* (W12) PRG1_PRU1_GPO4.RGMII2_RX_CTL */ + AM64X_IOPAD(0x0134, PIN_OUTPUT, 2) /* (AA10) PRG1_PRU1_GPO11.RGMII2_TD0 */ + AM64X_IOPAD(0x0138, PIN_OUTPUT, 2) /* (V10) PRG1_PRU1_GPO12.RGMII2_TD1 */ + AM64X_IOPAD(0x013c, PIN_OUTPUT, 2) /* (U10) PRG1_PRU1_GPO13.RGMII2_TD2 */ + AM64X_IOPAD(0x0140, PIN_OUTPUT, 2) /* (AA11) PRG1_PRU1_GPO14.RGMII2_TD3 */ + AM64X_IOPAD(0x0148, PIN_OUTPUT, 2) /* (Y10) PRG1_PRU1_GPO16.RGMII2_TXC */ + AM64X_IOPAD(0x0144, PIN_OUTPUT, 2) /* (Y11) PRG1_PRU1_GPO15.RGMII2_TX_CTL */ + >; + }; +}; + +&cpsw3g { + pinctrl-0 = <&rgmii1_pins_default>; +}; + +&cpsw_port2 { + status = "disabled"; +}; + +&mdio_mux_1 { + status = "disabled"; +}; + +&icssg1_eth { + pinctrl-0 = <&icssg1_rgmii1_pins_default>, <&icssg1_rgmii2_pins_default>; +}; + +&icssg1_emac1 { + status = "okay"; + phy-handle = <&icssg1_phy2>; + phy-mode = "rgmii-id"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am642-evm-icssg1-dualemac-mii.dtso b/arch/arm64/boot/dts/ti/k3-am642-evm-icssg1-dualemac-mii.dtso --- a/arch/arm64/boot/dts/ti/k3-am642-evm-icssg1-dualemac-mii.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am642-evm-icssg1-dualemac-mii.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT overlay for enabling both ICSSG1 port on AM642 EVM in MII mode + * + * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; +#include +#include "k3-pinctrl.h" + +&{/} { + aliases { + ethernet1 = "/icssg1-eth/ethernet-ports/port@1"; + }; + + mdio-mux-2 { + compatible = "mdio-mux-multiplexer"; + mux-controls = <&mdio_mux>; + mdio-parent-bus = <&icssg1_mdio>; + #address-cells = <1>; + #size-cells = <0>; + + mdio@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + icssg1_phy2: ethernet-phy@3 { + reg = <3>; + }; + }; + }; +}; + +&main_pmx0 { + icssg1_mii1_pins_default: icssg1-mii1-default-pins { + pinctrl-single,pins = < + AM64X_IOPAD(0x00f8, PIN_INPUT, 1) /* (V9) PRG1_PRU0_GPO16.PR1_MII_MT0_CLK */ + AM64X_IOPAD(0x00f4, PIN_OUTPUT, 0) /* (Y9) PRG1_PRU0_GPO15.PR1_MII0_TXEN */ + AM64X_IOPAD(0x00f0, PIN_OUTPUT, 0) /* (AA9) PRG1_PRU0_GPO14.PR1_MII0_TXD3 */ + AM64X_IOPAD(0x00ec, PIN_OUTPUT, 0) /* (W9) PRG1_PRU0_GPO13.PR1_MII0_TXD2 */ + AM64X_IOPAD(0x00e8, PIN_OUTPUT, 0) /* (U9) PRG1_PRU0_GPO12.PR1_MII0_TXD1 */ + AM64X_IOPAD(0x00e4, PIN_OUTPUT, 0) /* (AA8) PRG1_PRU0_GPO11.PR1_MII0_TXD0 */ + AM64X_IOPAD(0x00c8, PIN_INPUT, 1) /* (Y8) PRG1_PRU0_GPO4.PR1_MII0_RXDV */ + AM64X_IOPAD(0x00d0, PIN_INPUT, 1) /* (AA7) PRG1_PRU0_GPO6.PR1_MII_MR0_CLK */ + AM64X_IOPAD(0x00c4, PIN_INPUT, 1) /* (V8) PRG1_PRU0_GPO3.PR1_MII0_RXD3 */ + AM64X_IOPAD(0x00c0, PIN_INPUT, 1) /* (W8) PRG1_PRU0_GPO2.PR1_MII0_RXD2 */ + AM64X_IOPAD(0x00cc, PIN_INPUT, 1) /* (V13) PRG1_PRU0_GPO5.PR1_MII0_RXER */ + AM64X_IOPAD(0x00bc, PIN_INPUT, 1) /* (U8) PRG1_PRU0_GPO1.PR1_MII0_RXD1 */ + AM64X_IOPAD(0x00b8, PIN_INPUT, 1) /* (Y7) PRG1_PRU0_GPO0.PR1_MII0_RXD0 */ + AM64X_IOPAD(0x00d8, PIN_INPUT, 1) /* (W13) PRG1_PRU0_GPO8.PR1_MII0_RXLINK */ + >; + }; + + icssg1_mii2_pins_default: icssg1-mii2-default-pins { + pinctrl-single,pins = < + AM64X_IOPAD(0x0148, PIN_INPUT, 1) /* (Y10) PRG1_PRU1_GPO16.PR1_MII_MT1_CLK */ + AM64X_IOPAD(0x0144, PIN_OUTPUT, 0) /* (Y11) PRG1_PRU1_GPO15.PR1_MII1_TXEN */ + AM64X_IOPAD(0x0140, PIN_OUTPUT, 0) /* (AA11) PRG1_PRU1_GPO14.PR1_MII1_TXD3 */ + AM64X_IOPAD(0x013c, PIN_OUTPUT, 0) /* (U10) PRG1_PRU1_GPO13.PR1_MII1_TXD2 */ + AM64X_IOPAD(0x0138, PIN_OUTPUT, 0) /* (V10) PRG1_PRU1_GPO12.PR1_MII1_TXD1 */ + AM64X_IOPAD(0x0134, PIN_OUTPUT, 0) /* (AA10) PRG1_PRU1_GPO11.PR1_MII1_TXD0 */ + AM64X_IOPAD(0x0118, PIN_INPUT, 1) /* (W12) PRG1_PRU1_GPO4.PR1_MII1_RXDV */ + AM64X_IOPAD(0x0120, PIN_INPUT, 1) /* (U11) PRG1_PRU1_GPO6.PR1_MII_MR1_CLK */ + AM64X_IOPAD(0x0114, PIN_INPUT, 1) /* (Y12) PRG1_PRU1_GPO3.PR1_MII1_RXD3 */ + AM64X_IOPAD(0x0110, PIN_INPUT, 1) /* (AA12) PRG1_PRU1_GPO2.PR1_MII1_RXD2 */ + AM64X_IOPAD(0x011c, PIN_INPUT, 1) /* (AA13) PRG1_PRU1_GPO5.PR1_MII1_RXER */ + AM64X_IOPAD(0x010c, PIN_INPUT, 1) /* (V11) PRG1_PRU1_GPO1.PR1_MII1_RXD1 */ + AM64X_IOPAD(0x0108, PIN_INPUT, 1) /* (W11) PRG1_PRU1_GPO0.PR1_MII1_RXD0 */ + AM64X_IOPAD(0x0128, PIN_INPUT, 1) /* (U12) PRG1_PRU1_GPO8.PR1_MII1_RXLINK */ + >; + }; +}; + +&cpsw3g { + pinctrl-0 = <&rgmii1_pins_default>; +}; + +&cpsw_port2 { + status = "disabled"; +}; + +&mdio_mux_1 { + status = "disabled"; +}; + +&icssg1_eth { + pinctrl-0 = <&icssg1_mii1_pins_default &icssg1_mii2_pins_default>; +}; + +&icssg1_emac0 { + phy-mode = "mii"; +}; + +&icssg1_emac1 { + status = "okay"; + phy-handle = <&icssg1_phy2>; + phy-mode = "mii"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts --- a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts 2024-07-07 20:37:34.628306469 -0400 @@ -159,6 +159,15 @@ >; }; + main_spi0_pins_default: main-spi0-default-pins { + pinctrl-single,pins = < + AM64X_IOPAD(0x020c, PIN_OUTPUT, 7) /* (C13) SPI0_CS1.GPIO1_43 */ + AM64X_IOPAD(0x0210, PIN_INPUT, 0) /* (D13) SPI0_CLK */ + AM64X_IOPAD(0x0214, PIN_OUTPUT, 0) /* (A13) SPI0_D0 */ + AM64X_IOPAD(0x0218, PIN_INPUT, 0) /* (A14) SPI0_D1 */ + >; + }; + main_uart0_pins_default: main-uart0-default-pins { pinctrl-single,pins = < AM64X_IOPAD(0x0230, PIN_INPUT, 0) /* (D15) UART0_RXD */ @@ -248,6 +257,20 @@ phys = <&can_tc2>; }; +&main_spi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_spi0_pins_default>; + cs-gpios = <0>, <&main_gpio1 43 GPIO_ACTIVE_LOW>; + ti,pindir-d0-out-d1-in; + + tpm@1 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <1>; + spi-max-frequency = <10000000>; + }; +}; + &main_uart0 { status = "okay"; pinctrl-names = "default"; @@ -269,7 +292,6 @@ pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; bus-width = <4>; - ti,driver-strength-ohm = <50>; disable-wp; no-1-8-v; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am642-sk.dts b/arch/arm64/boot/dts/ti/k3-am642-sk.dts --- a/arch/arm64/boot/dts/ti/k3-am642-sk.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am642-sk.dts 2024-07-07 20:37:34.628306469 -0400 @@ -99,6 +99,18 @@ no-map; }; + mcu_m4fss_dma_memory_region: m4f-dma-memory@a4000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4000000 0x00 0x100000>; + no-map; + }; + + mcu_m4fss_memory_region: m4f-memory@a4100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4100000 0x00 0xf00000>; + no-map; + }; + rtos_ipc_memory_region: ipc-memories@a5000000 { reg = <0x00 0xa5000000 0x00 0x00800000>; alignment = <0x1000>; @@ -357,6 +369,16 @@ AM64X_IOPAD(0x0270, PIN_INPUT, 0) /* (D18) ECAP0_IN_APWM_OUT */ >; }; + + main_eqep0_pins_default: main-eqep0-default-pins { + pinctrl-single,pins = < + AM64X_IOPAD(0x00a0, PIN_INPUT, 3) /* (N16) GPMC0_WPn.EQEP0_A */ + AM64X_IOPAD(0x00a4, PIN_INPUT, 3) /* (N17) GPMC0_DIR.EQEP0_B */ + AM64X_IOPAD(0x00ac, PIN_INPUT, 3) /* (R20) GPMC0_CSn1.EQEP0_I */ + AM64X_IOPAD(0x00a8, PIN_INPUT, 3) /* (R19) GPMC0_CSn0.EQEP0_S */ + >; + }; + main_wlan_en_pins_default: main-wlan-en-default-pins { pinctrl-single,pins = < AM64X_IOPAD(0x00c4, PIN_OUTPUT_PULLUP, 7) /* (V8) GPIO0_48 */ @@ -433,11 +455,15 @@ }; }; -/* mcu_gpio0 is reserved for mcu firmware usage */ +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */ &mcu_gpio0 { status = "reserved"; }; +&mcu_gpio_intr { + status = "reserved"; +}; + &sdhci0 { status = "okay"; vmmc-supply = <&wlan_en>; @@ -465,9 +491,7 @@ status = "okay"; vmmc-supply = <&vdd_mmc1>; pinctrl-names = "default"; - bus-width = <4>; pinctrl-0 = <&main_mmc1_pins_default>; - ti,driver-strength-ohm = <50>; disable-wp; }; @@ -514,6 +538,11 @@ &cpsw3g { pinctrl-names = "default"; pinctrl-0 = <&rgmii1_pins_default>, <&rgmii2_pins_default>; + + /* Map HW8_TS_PUSH to GENF1 */ + cpts@3d000 { + ti,pps = <7 1>; + }; }; &cpsw_port1 { @@ -642,32 +671,67 @@ }; &main_r5fss0_core0 { - mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss0_core0>; + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core0>; memory-region = <&main_r5fss0_core0_dma_memory_region>, <&main_r5fss0_core0_memory_region>; }; &main_r5fss0_core1 { - mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss0_core1>; + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core1>; memory-region = <&main_r5fss0_core1_dma_memory_region>, <&main_r5fss0_core1_memory_region>; }; &main_r5fss1_core0 { - mboxes = <&mailbox0_cluster4>, <&mbox_main_r5fss1_core0>; + mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core0>; memory-region = <&main_r5fss1_core0_dma_memory_region>, <&main_r5fss1_core0_memory_region>; }; &main_r5fss1_core1 { - mboxes = <&mailbox0_cluster4>, <&mbox_main_r5fss1_core1>; + mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core1>; memory-region = <&main_r5fss1_core1_dma_memory_region>, <&main_r5fss1_core1_memory_region>; }; +&mcu_m4fss { + mboxes = <&mailbox0_cluster6 &mbox_m4_0>; + memory-region = <&mcu_m4fss_dma_memory_region>, + <&mcu_m4fss_memory_region>; + status = "okay"; +}; + &ecap0 { status = "okay"; /* PWM is available on Pin 1 of header J3 */ pinctrl-names = "default"; pinctrl-0 = <&main_ecap0_pins_default>; }; + +&eqep0 { + status = "okay"; + /* EQEP0 A & B available on pins 18 & 22 of J4 header */ + pinctrl-names = "default"; + pinctrl-0 = <&main_eqep0_pins_default>; +}; + +#define TS_OFFSET(pa, val) (0x4+(pa)*4) (0x10000 | val) + +×ync_router { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&cpsw_cpts_pps>; + + /* + * Use Time Sync Router to map GENF1 input to HW8_TS_PUSH output as well + * as the PRU ICSSG0 SYNC1 output. + */ + cpsw_cpts_pps: cpsw-cpts-pps { + pinctrl-single,pins = < + /* pps [cpts genf1] in22 -> out37 [cpts hw8_push] */ + TS_OFFSET(37, 22) + /* pps [cpts genf1] in22 -> out26 [SYNC1_OUT pin] */ + TS_OFFSET(26, 22) + >; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi --- a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -85,6 +85,15 @@ no-map; }; }; + + reg_1v8: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "V_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; }; &main_i2c0 { @@ -96,11 +105,13 @@ tmp1075: temperature-sensor@4a { compatible = "ti,tmp1075"; reg = <0x4a>; + vs-supply = <®_1v8>; }; eeprom0: eeprom@50 { compatible = "st,24c02", "atmel,24c02"; reg = <0x50>; + vcc-supply = <®_1v8>; pagesize = <16>; read-only; }; @@ -114,6 +125,7 @@ eeprom1: eeprom@54 { compatible = "st,24c64", "atmel,24c64"; reg = <0x54>; + vcc-supply = <®_1v8>; pagesize = <32>; }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts --- a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts 2024-07-07 20:37:34.628306469 -0400 @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -19,6 +20,7 @@ compatible = "tq,am642-tqma6442l-mbax4xxl", "tq,am642-tqma6442l", "ti,am642"; model = "TQ-Systems TQMa64xxL SoM on MBax4xxL carrier board"; + chassis-type = "embedded"; aliases { ethernet0 = &cpsw_port1; @@ -58,12 +60,14 @@ pinctrl-0 = <&mcu_gpio_leds_pins>; led-0 { - label = "led0"; gpios = <&mcu_gpio0 8 GPIO_ACTIVE_HIGH>; + color = ; + function = LED_FUNCTION_INDICATOR; }; led-1 { - label = "led1"; gpios = <&mcu_gpio0 9 GPIO_ACTIVE_HIGH>; + color = ; + function = LED_FUNCTION_INDICATOR; }; }; @@ -170,7 +174,8 @@ &main_gpio1 { pinctrl-names = "default"; - pinctrl-0 = <&main_gpio1_hog_pins>; + pinctrl-0 = <&main_gpio1_hog_pins>, + <&main_gpio1_pru_pins>; gpio-line-names = "", "", "", "", /* 0-3 */ "", "", "", "", /* 4-7 */ @@ -417,7 +422,6 @@ cd-gpios = <&main_gpio1 77 GPIO_ACTIVE_LOW>; disable-wp; no-mmc; - ti,driver-strength-ohm = <50>; ti,fails-without-test-cd; /* Enabled by overlay */ }; @@ -544,6 +548,79 @@ >; }; + main_gpio1_pru_pins: main-gpio1-pru-pins { + pinctrl-single,pins = < + /* (Y1) PRG0_PRU0_GPO0.GPIO1_0 */ + AM64X_IOPAD(0x0160, PIN_INPUT, 7) + /* (R4) PRG0_PRU0_GPO1.GPIO1_1 */ + AM64X_IOPAD(0x0164, PIN_INPUT, 7) + /* (U2) PRG0_PRU0_GPO2.GPIO1_2 */ + AM64X_IOPAD(0x0168, PIN_INPUT, 7) + /* (V2) PRG0_PRU0_GPO3.GPIO1_3 */ + AM64X_IOPAD(0x016c, PIN_INPUT, 7) + /* (AA2) PRG0_PRU0_GPO4.GPIO1_4 */ + AM64X_IOPAD(0x0170, PIN_INPUT, 7) + /* (R3) PRG0_PRU0_GPO5.GPIO1_5 */ + AM64X_IOPAD(0x0174, PIN_INPUT, 7) + /* (T3) PRG0_PRU0_GPO6.GPIO1_6 */ + AM64X_IOPAD(0x0178, PIN_INPUT, 7) + /* (T1) PRG0_PRU0_GPO7.GPIO1_7 */ + AM64X_IOPAD(0x017c, PIN_INPUT, 7) + /* (T2) PRG0_PRU0_GPO8.GPIO1_8 */ + AM64X_IOPAD(0x0180, PIN_INPUT, 7) + /* (Y3) PRG0_PRU0_GPO11.GPIO1_11 */ + AM64X_IOPAD(0x018c, PIN_INPUT, 7) + /* (AA3) PRG0_PRU0_GPO12.GPIO1_12 */ + AM64X_IOPAD(0x0190, PIN_INPUT, 7) + /* (R6) PRG0_PRU0_GPO13.GPIO1_13 */ + AM64X_IOPAD(0x0194, PIN_INPUT, 7) + /* (V4) PRG0_PRU0_GPO14.GPIO1_14 */ + AM64X_IOPAD(0x0198, PIN_INPUT, 7) + /* (T5) PRG0_PRU0_GPO15.GPIO1_15 */ + AM64X_IOPAD(0x019c, PIN_INPUT, 7) + /* (U4) PRG0_PRU0_GPO16.GPIO1_16 */ + AM64X_IOPAD(0x01a0, PIN_INPUT, 7) + /* (U1) PRG0_PRU0_GPO17.GPIO1_17 */ + AM64X_IOPAD(0x01a4, PIN_INPUT, 7) + /* (V1) PRG0_PRU0_GPO18.GPIO1_18 */ + AM64X_IOPAD(0x01a8, PIN_INPUT, 7) + /* (W1) PRG0_PRU0_GPO19.GPIO1_19 */ + AM64X_IOPAD(0x01ac, PIN_INPUT, 7) + /* (Y2) PRG0_PRU1_GPO0.GPIO1_20 */ + AM64X_IOPAD(0x01b0, PIN_INPUT, 7) + /* (W2) PRG0_PRU1_GPO1.GPIO1_21 */ + AM64X_IOPAD(0x01b4, PIN_INPUT, 7) + /* (V3) PRG0_PRU1_GPO2.GPIO1_22 */ + AM64X_IOPAD(0x01b8, PIN_INPUT, 7) + /* (T4) PRG0_PRU1_GPO3.GPIO1_23 */ + AM64X_IOPAD(0x01bc, PIN_INPUT, 7) + /* (W3) PRG0_PRU1_GPO4.GPIO1_24 */ + AM64X_IOPAD(0x01c0, PIN_INPUT, 7) + /* (P4) PRG0_PRU1_GPO5.GPIO1_25 */ + AM64X_IOPAD(0x01c4, PIN_INPUT, 7) + /* (R5) PRG0_PRU1_GPO6.GPIO1_26 */ + AM64X_IOPAD(0x01c8, PIN_INPUT, 7) + /* (R1) PRG0_PRU1_GPO8.GPIO1_28 */ + AM64X_IOPAD(0x01d0, PIN_INPUT, 7) + /* (W4) PRG0_PRU1_GPO11.GPIO1_31 */ + AM64X_IOPAD(0x01dc, PIN_INPUT, 7) + /* (Y4) PRG0_PRU1_GPO12.GPIO1_32 */ + AM64X_IOPAD(0x01e0, PIN_INPUT, 7) + /* (T6) PRG0_PRU1_GPO13.GPIO1_33 */ + AM64X_IOPAD(0x01e4, PIN_INPUT, 7) + /* (U6) PRG0_PRU1_GPO14.GPIO1_34 */ + AM64X_IOPAD(0x01e8, PIN_INPUT, 7) + /* (U5) PRG0_PRU1_GPO15.GPIO1_35 */ + AM64X_IOPAD(0x01ec, PIN_INPUT, 7) + /* (AA4) PRG0_PRU1_GPO16.GPIO1_36 */ + AM64X_IOPAD(0x01f0, PIN_INPUT, 7) + /* (P2) PRG0_MDIO0_MDIO.GPIO1_40 */ + AM64X_IOPAD(0x0200, PIN_INPUT, 7) + /* (P3) PRG0_MDIO0_MDC.GPIO1_41 */ + AM64X_IOPAD(0x0204, PIN_INPUT, 7) + >; + }; + main_mcan0_pins: main-mcan0-pins { pinctrl-single,pins = < /* (B17) MCAN0_RX */ diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am64.dtsi b/arch/arm64/boot/dts/ti/k3-am64.dtsi --- a/arch/arm64/boot/dts/ti/k3-am64.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am64.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -47,6 +47,7 @@ }; cbass_main: bus@f4000 { + bootph-all; compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; @@ -85,6 +86,7 @@ <0x00 0x04000000 0x00 0x04000000 0x00 0x01ff1400>; cbass_mcu: bus@4000000 { + bootph-all; compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi --- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -38,6 +38,7 @@ }; main_conf: syscon@43000000 { + bootph-all; compatible = "ti,j721e-system-controller", "syscon", "simple-mfd"; reg = <0x0 0x43000000 0x0 0x20000>; #address-cells = <1>; @@ -45,14 +46,16 @@ ranges = <0x0 0x0 0x43000000 0x20000>; chipid@14 { + bootph-all; compatible = "ti,am654-chipid"; reg = <0x00000014 0x4>; }; - serdes_ln_ctrl: mux-controller { - compatible = "mmio-mux"; + serdes_ln_ctrl: mux-controller@4080 { + compatible = "reg-mux"; + reg = <0x4080 0x4>; #mux-control-cells = <1>; - mux-reg-masks = <0x4080 0x3>; /* SERDES0 lane0 select */ + mux-reg-masks = <0x0 0x3>; /* SERDES0 lane0 select */ }; phy_gmii_sel: phy@4044 { @@ -61,7 +64,7 @@ #phy-cells = <1>; }; - epwm_tbclk: clock-controller@4140 { + epwm_tbclk: clock-controller@4130 { compatible = "ti,am64-epwm-tbclk"; reg = <0x4130 0x4>; #clock-cells = <1>; @@ -96,7 +99,8 @@ }; dmss: bus@48000000 { - compatible = "simple-mfd"; + bootph-all; + compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; dma-ranges; @@ -105,6 +109,7 @@ ti,sci-dev-id = <25>; secure_proxy_main: mailbox@4d000000 { + bootph-all; compatible = "ti,am654-secure-proxy"; #mbox-cells = <1>; reg-names = "target_data", "rt", "scfg"; @@ -134,8 +139,13 @@ <0x00 0x4c000000 0x00 0x20000>, <0x00 0x4a820000 0x00 0x20000>, <0x00 0x4aa40000 0x00 0x20000>, - <0x00 0x4bc00000 0x00 0x100000>; - reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4bc00000 0x00 0x100000>, + <0x00 0x48600000 0x00 0x8000>, + <0x00 0x484a4000 0x00 0x2000>, + <0x00 0x484c2000 0x00 0x2000>, + <0x00 0x48420000 0x00 0x2000>; + reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "bchan"; msi-parent = <&inta_main_dmss>; #dma-cells = <3>; @@ -151,8 +161,13 @@ reg = <0x00 0x485c0000 0x00 0x100>, <0x00 0x4a800000 0x00 0x20000>, <0x00 0x4aa00000 0x00 0x40000>, - <0x00 0x4b800000 0x00 0x400000>; - reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4b800000 0x00 0x400000>, + <0x00 0x485e0000 0x00 0x20000>, + <0x00 0x484a0000 0x00 0x4000>, + <0x00 0x484c0000 0x00 0x2000>, + <0x00 0x48430000 0x00 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "rflow"; msi-parent = <&inta_main_dmss>; #dma-cells = <2>; @@ -188,6 +203,7 @@ }; dmsc: system-controller@44043000 { + bootph-all; compatible = "ti,k2g-sci"; ti,host-id = <12>; mbox-names = "rx", "tx"; @@ -197,22 +213,26 @@ reg = <0x00 0x44043000 0x00 0xfe0>; k3_pds: power-controller { + bootph-all; compatible = "ti,sci-pm-domain"; #power-domain-cells = <2>; }; k3_clks: clock-controller { + bootph-all; compatible = "ti,k2g-sci-clk"; #clock-cells = <2>; }; k3_reset: reset-controller { + bootph-all; compatible = "ti,sci-reset"; #reset-cells = <2>; }; }; main_pmx0: pinctrl@f4000 { + bootph-all; compatible = "pinctrl-single"; reg = <0x00 0xf4000 0x00 0x2d0>; #pinctrl-cells = <1>; @@ -221,6 +241,7 @@ }; main_timer0: timer@2400000 { + bootph-all; compatible = "ti,am654-timer"; reg = <0x00 0x2400000 0x00 0x400>; interrupts = ; @@ -365,6 +386,7 @@ }; main_esm: esm@420000 { + bootph-pre-ram; compatible = "ti,j721e-esm"; reg = <0x00 0x420000 0x00 0x1000>; ti,esm-pins = <160>, <161>; @@ -605,8 +627,10 @@ power-domains = <&k3_pds 57 TI_SCI_PD_EXCLUSIVE>; clocks = <&k3_clks 57 0>, <&k3_clks 57 1>; clock-names = "clk_ahb", "clk_xin"; + bus-width = <8>; mmc-ddr-1_8v; mmc-hs200-1_8v; + ti,clkbuf-sel = <0x7>; ti,trm-icp = <0x2>; ti,otap-del-sel-legacy = <0x0>; ti,otap-del-sel-mmc-hs = <0x0>; @@ -625,7 +649,8 @@ power-domains = <&k3_pds 58 TI_SCI_PD_EXCLUSIVE>; clocks = <&k3_clks 58 3>, <&k3_clks 58 4>; clock-names = "clk_ahb", "clk_xin"; - ti,trm-icp = <0x2>; + bus-width = <4>; + ti,clkbuf-sel = <0x7>; ti,otap-del-sel-legacy = <0x0>; ti,otap-del-sel-sd-hs = <0x0>; ti,otap-del-sel-sdr12 = <0xf>; @@ -637,7 +662,6 @@ ti,itap-del-sel-sd-hs = <0x0>; ti,itap-del-sel-sdr12 = <0x0>; ti,itap-del-sel-sdr25 = <0x0>; - ti,clkbuf-sel = <0x7>; status = "disabled"; }; @@ -1027,25 +1051,6 @@ status = "disabled"; }; - pcie0_ep: pcie-ep@f102000 { - compatible = "ti,am64-pcie-ep", "ti,j721e-pcie-ep"; - reg = <0x00 0x0f102000 0x00 0x1000>, - <0x00 0x0f100000 0x00 0x400>, - <0x00 0x0d000000 0x00 0x00800000>, - <0x00 0x68000000 0x00 0x08000000>; - reg-names = "intd_cfg", "user_cfg", "reg", "mem"; - interrupt-names = "link_state"; - interrupts = ; - ti,syscon-pcie-ctrl = <&main_conf 0x4070>; - max-link-speed = <2>; - num-lanes = <1>; - power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 114 0>; - clock-names = "fck"; - max-functions = /bits/ 8 <1>; - status = "disabled"; - }; - epwm0: pwm@23000000 { compatible = "ti,am64-epwm", "ti,am3352-ehrpwm"; #pwm-cells = <3>; @@ -1166,22 +1171,49 @@ status = "disabled"; }; + eqep0: counter@23200000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23200000 0x00 0x100>; + power-domains = <&k3_pds 59 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 59 0>; + interrupts = ; + status = "disabled"; + }; + + eqep1: counter@23210000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23210000 0x00 0x100>; + power-domains = <&k3_pds 60 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 60 0>; + interrupts = ; + status = "disabled"; + }; + + eqep2: counter@23220000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23220000 0x00 0x100>; + power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 62 0>; + interrupts = ; + status = "disabled"; + }; + main_rti0: watchdog@e000000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0xe000000 0x00 0x100>; - clocks = <&k3_clks 125 0>; - power-domains = <&k3_pds 125 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 125 0>; - assigned-clock-parents = <&k3_clks 125 2>; + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0xe000000 0x00 0x100>; + clocks = <&k3_clks 125 0>; + power-domains = <&k3_pds 125 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 125 0>; + assigned-clock-parents = <&k3_clks 125 2>; }; main_rti1: watchdog@e010000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0xe010000 0x00 0x100>; - clocks = <&k3_clks 126 0>; - power-domains = <&k3_pds 126 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 126 0>; - assigned-clock-parents = <&k3_clks 126 2>; + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0xe010000 0x00 0x100>; + clocks = <&k3_clks 126 0>; + power-domains = <&k3_pds 126 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 126 0>; + assigned-clock-parents = <&k3_clks 126 2>; }; icssg0: icssg@30000000 { @@ -1230,6 +1262,18 @@ }; }; + icssg0_iep0: iep@2e000 { + compatible = "ti,am654-icss-iep"; + reg = <0x2e000 0x1000>; + clocks = <&icssg0_iepclk_mux>; + }; + + icssg0_iep1: iep@2f000 { + compatible = "ti,am654-icss-iep"; + reg = <0x2f000 0x1000>; + clocks = <&icssg0_iepclk_mux>; + }; + icssg0_mii_rt: mii-rt@32000 { compatible = "ti,pruss-mii", "syscon"; reg = <0x32000 0x100>; @@ -1240,6 +1284,11 @@ reg = <0x33000 0x1000>; }; + icssg0_pa_stats: pa-stats@2c000 { + compatible = "ti,pruss-pa-st", "syscon"; + reg = <0x2c000 0x1000>; + }; + icssg0_intc: interrupt-controller@20000 { compatible = "ti,icssg-intc"; reg = <0x20000 0x2000>; @@ -1266,6 +1315,9 @@ <0x22400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am64x-pru0_0-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <16 2 2>; + interrupt-names = "vring"; }; rtu0_0: rtu@4000 { @@ -1275,6 +1327,9 @@ <0x23400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am64x-rtu0_0-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <20 4 4>; + interrupt-names = "vring"; }; tx_pru0_0: txpru@a000 { @@ -1293,6 +1348,9 @@ <0x24400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am64x-pru0_1-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <18 3 3>; + interrupt-names = "vring"; }; rtu0_1: rtu@6000 { @@ -1302,6 +1360,9 @@ <0x23c00 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am64x-rtu0_1-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <22 5 5>; + interrupt-names = "vring"; }; tx_pru0_1: txpru@c000 { @@ -1371,6 +1432,18 @@ }; }; + icssg1_iep0: iep@2e000 { + compatible = "ti,am654-icss-iep"; + reg = <0x2e000 0x1000>; + clocks = <&icssg1_iepclk_mux>; + }; + + icssg1_iep1: iep@2f000 { + compatible = "ti,am654-icss-iep"; + reg = <0x2f000 0x1000>; + clocks = <&icssg1_iepclk_mux>; + }; + icssg1_mii_rt: mii-rt@32000 { compatible = "ti,pruss-mii", "syscon"; reg = <0x32000 0x100>; @@ -1381,6 +1454,11 @@ reg = <0x33000 0x1000>; }; + icssg1_pa_stats: pa-stats@2c000 { + compatible = "ti,pruss-pa-st", "syscon"; + reg = <0x2c000 0x1000>; + }; + icssg1_intc: interrupt-controller@20000 { compatible = "ti,icssg-intc"; reg = <0x20000 0x2000>; @@ -1407,6 +1485,9 @@ <0x22400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am64x-pru1_0-fw"; + interrupt-parent = <&icssg1_intc>; + interrupts = <16 2 2>; + interrupt-names = "vring"; }; rtu1_0: rtu@4000 { @@ -1416,6 +1497,9 @@ <0x23400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am64x-rtu1_0-fw"; + interrupt-parent = <&icssg1_intc>; + interrupts = <20 4 4>; + interrupt-names = "vring"; }; tx_pru1_0: txpru@a000 { @@ -1434,6 +1518,9 @@ <0x24400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am64x-pru1_1-fw"; + interrupt-parent = <&icssg1_intc>; + interrupts = <18 3 3>; + interrupt-names = "vring"; }; rtu1_1: rtu@6000 { @@ -1443,6 +1530,9 @@ <0x23c00 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am64x-rtu1_1-fw"; + interrupt-parent = <&icssg1_intc>; + interrupts = <22 5 5>; + interrupt-names = "vring"; }; tx_pru1_1: txpru@c000 { diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi --- a/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -146,6 +146,7 @@ }; mcu_pmx0: pinctrl@4084000 { + bootph-all; compatible = "pinctrl-single"; reg = <0x00 0x4084000 0x00 0x84>; #pinctrl-cells = <1>; @@ -154,8 +155,22 @@ }; mcu_esm: esm@4100000 { + bootph-pre-ram; compatible = "ti,j721e-esm"; reg = <0x00 0x4100000 0x00 0x1000>; ti,esm-pins = <0>, <1>; }; + + mcu_m4fss: m4fss@5000000 { + compatible = "ti,am64-m4fss"; + reg = <0x00 0x5000000 0x00 0x30000>, + <0x00 0x5040000 0x00 0x10000>; + reg-names = "iram", "dram"; + resets = <&k3_reset 9 1>; + firmware-name = "am64-mcu-m4f0_0-fw"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <9>; + ti,sci-proc-ids = <0x18 0xff>; + status = "disabled"; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi b/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi --- a/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -29,7 +29,7 @@ reg = <0x00000000 0x80000000 0x00000000 0x80000000>; }; - reserved-memory { + reserved_memory: reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; @@ -39,6 +39,54 @@ alignment = <0x1000>; no-map; }; + + main_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core0_memory_region: r5f-memory@a0100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core1_dma_memory_region: r5f-dma-memory@a1000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core1_memory_region: r5f-memory@a1100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core0_dma_memory_region: r5f-dma-memory@a2000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core0_memory_region: r5f-memory@a2100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core1_dma_memory_region: r5f-dma-memory@a3000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core1_memory_region: r5f-memory@a3100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3100000 0x00 0xf00000>; + no-map; + }; }; leds { @@ -126,6 +174,12 @@ AM64X_IOPAD(0x002c, PIN_OUTPUT, 0) /* (L19) OSPI0_CSn0 */ >; }; + + rtc_pins_default: rtc-defaults-pins { + pinctrl-single,pins = < + AM64X_IOPAD(0x0278, PIN_INPUT, 7) /* (C19) EXTINTn.GPIO1_70 */ + >; + }; }; &cpsw3g { @@ -160,6 +214,34 @@ status = "disabled"; }; +&mailbox0_cluster2 { + status = "okay"; + + mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; + + mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 { + ti,mbox-rx = <2 0 2>; + ti,mbox-tx = <3 0 2>; + }; +}; + +&mailbox0_cluster4 { + status = "okay"; + + mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; + + mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 { + ti,mbox-rx = <2 0 2>; + ti,mbox-tx = <3 0 2>; + }; +}; + &main_i2c0 { status = "okay"; pinctrl-names = "default"; @@ -177,9 +259,38 @@ i2c_som_rtc: rtc@52 { compatible = "microcrystal,rv3028"; reg = <0x52>; + pinctrl-names = "default"; + pinctrl-0 = <&rtc_pins_default>; + interrupt-parent = <&main_gpio1>; + interrupts = <70 IRQ_TYPE_EDGE_FALLING>; + wakeup-source; }; }; +&main_r5fss0_core0 { + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core0>; + memory-region = <&main_r5fss0_core0_dma_memory_region>, + <&main_r5fss0_core0_memory_region>; +}; + +&main_r5fss0_core1 { + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core1>; + memory-region = <&main_r5fss0_core1_dma_memory_region>, + <&main_r5fss0_core1_memory_region>; +}; + +&main_r5fss1_core0 { + mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core0>; + memory-region = <&main_r5fss1_core0_dma_memory_region>, + <&main_r5fss1_core0_memory_region>; +}; + +&main_r5fss1_core1 { + mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core1>; + memory-region = <&main_r5fss1_core1_dma_memory_region>, + <&main_r5fss1_core1_memory_region>; +}; + &ospi0 { status = "okay"; pinctrl-names = "default"; @@ -207,3 +318,10 @@ disable-wp; keep-power-in-suspend; }; + +&tscadc0 { + status = "okay"; + adc { + ti,adc-channels = <0 1 2 3 4 5 6 7>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi --- a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -9,6 +9,7 @@ * Common bits of the IOT2050 Basic variant, PG1 and PG2 */ +#include "k3-am652.dtsi" #include "k3-am65-iot2050-common.dtsi" / { @@ -17,21 +18,6 @@ /* 1G RAM */ reg = <0x00000000 0x80000000 0x00000000 0x40000000>; }; - - cpus { - cpu-map { - /delete-node/ cluster1; - }; - /delete-node/ cpu@100; - /delete-node/ cpu@101; - }; - - /delete-node/ l2-cache1; -}; - -/* eMMC */ -&sdhci0 { - status = "disabled"; }; &main_pmx0 { diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am652.dtsi b/arch/arm64/boot/dts/ti/k3-am652.dtsi --- a/arch/arm64/boot/dts/ti/k3-am652.dtsi 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am652.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for AM65 SoC family in Dual core configuration + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include "k3-am65.dtsi" + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu-map { + cluster0: cluster0 { + core0 { + cpu = <&cpu0>; + }; + + core1 { + cpu = <&cpu1>; + }; + }; + }; + + cpu0: cpu@0 { + compatible = "arm,cortex-a53"; + reg = <0x000>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&L2_0>; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a53"; + reg = <0x001>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&L2_0>; + }; + }; + + L2_0: l2-cache0 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x80000>; + cache-line-size = <64>; + cache-sets = <512>; + next-level-cache = <&msmc_l3>; + }; + + msmc_l3: l3-cache0 { + compatible = "cache"; + cache-level = <3>; + cache-unified; + }; + + thermal_zones: thermal-zones { + #include "k3-am654-industrial-thermal.dtsi" + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi --- a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -11,6 +11,7 @@ /dts-v1/; +#include "k3-am654.dtsi" #include "k3-am65-iot2050-common.dtsi" / { @@ -43,6 +44,7 @@ /* eMMC */ &sdhci0 { + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_mmc0_pins_default>; bus-width = <8>; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts --- a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts 2024-07-07 20:37:34.628306469 -0400 @@ -27,12 +27,6 @@ }; &main_pmx0 { - main_m2_enable_pins_default: main-m2-enable-default-pins { - pinctrl-single,pins = < - AM65X_IOPAD(0x01c4, PIN_INPUT_PULLUP, 7) /* (AH13) GPIO1_17 */ - >; - }; - main_bkey_pcie_reset: main-bkey-pcie-reset-default-pins { pinctrl-single,pins = < AM65X_IOPAD(0x01bc, PIN_OUTPUT_PULLUP, 7) /* (AG13) GPIO1_15 */ @@ -66,15 +60,13 @@ &main_gpio0 { pinctrl-names = "default"; - pinctrl-0 = - <&main_m2_pcie_mux_control>, - <&arduino_io_d4_to_d9_pins_default>; + pinctrl-0 = <&main_m2_pcie_mux_control>; }; &main_gpio1 { pinctrl-names = "default"; pinctrl-0 = - <&main_m2_enable_pins_default>, + <&main_pcie_enable_pins_default>, <&main_pmx0_m2_config_pins_default>, <&main_pmx1_m2_config_pins_default>, <&cp2102n_reset_pin_default>; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts --- a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts 2024-07-07 20:37:34.628306469 -0400 @@ -33,6 +33,7 @@ memory@80000000 { device_type = "memory"; + bootph-all; /* 4G RAM */ reg = <0x00000000 0x80000000 0x00000000 0x80000000>, <0x00000008 0x80000000 0x00000000 0x80000000>; @@ -369,6 +370,13 @@ ti,enable-vout-discharge; }; + gpio@38 { + compatible = "nxp,pca9554"; + reg = <0x38>; + gpio-controller; + #gpio-cells = <2>; + }; + pca9554: gpio@39 { compatible = "nxp,pca9554"; reg = <0x39>; @@ -442,6 +450,7 @@ }; &sdhci0 { + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_mmc0_pins_default>; bus-width = <8>; @@ -456,6 +465,7 @@ * disable sdhci1 */ &sdhci1 { + status = "okay"; vmmc-supply = <&vdd_mmc1_sd>; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; @@ -522,13 +532,13 @@ &mcu_r5fss0_core0 { memory-region = <&mcu_r5fss0_core0_dma_memory_region>, <&mcu_r5fss0_core0_memory_region>; - mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>; + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>; }; &mcu_r5fss0_core1 { memory-region = <&mcu_r5fss0_core1_dma_memory_region>, <&mcu_r5fss0_core1_memory_region>; - mboxes = <&mailbox0_cluster1>, <&mbox_mcu_r5fss0_core1>; + mboxes = <&mailbox0_cluster1 &mbox_mcu_r5fss0_core1>; }; &ospi0 { diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am654-base-board-toshiba-tc358867-evm.dtso b/arch/arm64/boot/dts/ti/k3-am654-base-board-toshiba-tc358867-evm.dtso --- a/arch/arm64/boot/dts/ti/k3-am654-base-board-toshiba-tc358867-evm.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am654-base-board-toshiba-tc358867-evm.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * Toshiba TC358867 expansion board for AM654-EVM. + * + * AM654 GP EVM: https://www.ti.com/tool/TMDX654GPEVM + * Toshiba TC358867: https://toshiba.semicon-storage.com/eu/semiconductor/product/interface-bridge-ics-for-mobile-peripheral-devices/display-interface-bridge-ics/detail.TC358867XBG.html + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +&{/} { + dp_refclk: fixed-clock-tc358767 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <19200000>; + }; +}; + +&main_pmx0 { + dss_vout1_pins_default: dss-vout1-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0000, PIN_OUTPUT, 1) /* VOUT1_DATA0 */ + AM65X_IOPAD(0x0004, PIN_OUTPUT, 1) /* VOUT1_DATA1 */ + AM65X_IOPAD(0x0008, PIN_OUTPUT, 1) /* VOUT1_DATA2 */ + AM65X_IOPAD(0x000c, PIN_OUTPUT, 1) /* VOUT1_DATA3 */ + AM65X_IOPAD(0x0010, PIN_OUTPUT, 1) /* VOUT1_DATA4 */ + AM65X_IOPAD(0x0014, PIN_OUTPUT, 1) /* VOUT1_DATA5 */ + AM65X_IOPAD(0x0018, PIN_OUTPUT, 1) /* VOUT1_DATA6 */ + AM65X_IOPAD(0x001c, PIN_OUTPUT, 1) /* VOUT1_DATA7 */ + AM65X_IOPAD(0x0020, PIN_OUTPUT, 1) /* VOUT1_DATA8 */ + AM65X_IOPAD(0x0024, PIN_OUTPUT, 1) /* VOUT1_DATA9 */ + AM65X_IOPAD(0x0028, PIN_OUTPUT, 1) /* VOUT1_DATA10 */ + AM65X_IOPAD(0x002c, PIN_OUTPUT, 1) /* VOUT1_DATA11 */ + AM65X_IOPAD(0x0030, PIN_OUTPUT, 1) /* VOUT1_DATA12 */ + AM65X_IOPAD(0x0034, PIN_OUTPUT, 1) /* VOUT1_DATA13 */ + AM65X_IOPAD(0x0038, PIN_OUTPUT, 1) /* VOUT1_DATA14 */ + AM65X_IOPAD(0x003c, PIN_OUTPUT, 1) /* VOUT1_DATA15 */ + AM65X_IOPAD(0x0040, PIN_OUTPUT, 1) /* VOUT1_DATA16 */ + AM65X_IOPAD(0x0044, PIN_OUTPUT, 1) /* VOUT1_DATA17 */ + AM65X_IOPAD(0x0048, PIN_OUTPUT, 1) /* VOUT1_DATA18 */ + AM65X_IOPAD(0x004c, PIN_OUTPUT, 1) /* VOUT1_DATA19 */ + AM65X_IOPAD(0x0050, PIN_OUTPUT, 1) /* VOUT1_DATA20 */ + AM65X_IOPAD(0x0054, PIN_OUTPUT, 1) /* VOUT1_DATA21 */ + AM65X_IOPAD(0x0058, PIN_OUTPUT, 1) /* VOUT1_DATA22 */ + AM65X_IOPAD(0x005c, PIN_OUTPUT, 1) /* VOUT1_DATA23 */ + AM65X_IOPAD(0x0060, PIN_OUTPUT, 1) /* VOUT1_VSYNC */ + AM65X_IOPAD(0x0064, PIN_OUTPUT, 1) /* VOUT1_HSYNC */ + AM65X_IOPAD(0x0068, PIN_OUTPUT, 1) /* VOUT1_PCLK */ + AM65X_IOPAD(0x006c, PIN_OUTPUT, 1) /* VOUT1_DE */ + >; + }; +}; + +&main_i2c1 { + #address-cells = <1>; + #size-cells = <0>; + + edp-bridge@f { + compatible = "toshiba,tc358767"; + reg = <0x0f>; + clock-names = "ref"; + clocks = <&dp_refclk>; + reset-gpios = <&pca9555 6 GPIO_ACTIVE_HIGH>; + toshiba,hpd-pin = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + bridge_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + }; + }; +}; + +&dss { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&dss_vout1_pins_default>; + + assigned-clocks = <&k3_clks 67 2>; + assigned-clock-parents = <&k3_clks 67 5>; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + port@1 { + reg = <1>; + + dpi_out: endpoint { + remote-endpoint = <&bridge_in>; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am654-icssg2.dtso b/arch/arm64/boot/dts/ti/k3-am654-icssg2.dtso --- a/arch/arm64/boot/dts/ti/k3-am654-icssg2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am654-icssg2.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT overlay for IDK application board on AM654 EVM + * + * Copyright (C) 2018-2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&{/} { + aliases { + ethernet1 = "/icssg2-eth/ethernet-ports/port@0"; + ethernet2 = "/icssg2-eth/ethernet-ports/port@1"; + }; + + /* Ethernet node on PRU-ICSSG2 */ + icssg2_eth: icssg2-eth { + compatible = "ti,am654-icssg-prueth"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg2_rgmii_pins_default>; + sram = <&msmc_ram>; + ti,prus = <&pru2_0>, <&rtu2_0>, <&tx_pru2_0>, + <&pru2_1>, <&rtu2_1>, <&tx_pru2_1>; + firmware-name = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf", + "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf", + "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf", + "ti-pruss/am65x-sr2-pru1-prueth-fw.elf", + "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf", + "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf"; + + ti,pruss-gp-mux-sel = <2>, /* MII mode */ + <2>, + <2>, + <2>, /* MII mode */ + <2>, + <2>; + + ti,mii-g-rt = <&icssg2_mii_g_rt>; + ti,mii-rt = <&icssg2_mii_rt>; + ti,pa-stats = <&icssg2_pa_stats>; + ti,iep = <&icssg2_iep0>, <&icssg2_iep1>; + + interrupt-parent = <&icssg2_intc>; + interrupts = <24 0 2>, <25 1 3>; + interrupt-names = "tx_ts0", "tx_ts1"; + + dmas = <&main_udmap 0xc300>, /* egress slice 0 */ + <&main_udmap 0xc301>, /* egress slice 0 */ + <&main_udmap 0xc302>, /* egress slice 0 */ + <&main_udmap 0xc303>, /* egress slice 0 */ + <&main_udmap 0xc304>, /* egress slice 1 */ + <&main_udmap 0xc305>, /* egress slice 1 */ + <&main_udmap 0xc306>, /* egress slice 1 */ + <&main_udmap 0xc307>, /* egress slice 1 */ + <&main_udmap 0x4300>, /* ingress slice 0 */ + <&main_udmap 0x4301>; /* ingress slice 1 */ + + dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3", + "tx1-0", "tx1-1", "tx1-2", "tx1-3", + "rx0", "rx1"; + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + icssg2_emac0: port@0 { + reg = <0>; + phy-handle = <&icssg2_phy0>; + phy-mode = "rgmii-id"; + ti,syscon-rgmii-delay = <&scm_conf 0x4120>; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + icssg2_emac1: port@1 { + reg = <1>; + phy-handle = <&icssg2_phy1>; + phy-mode = "rgmii-id"; + ti,syscon-rgmii-delay = <&scm_conf 0x4124>; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + }; + }; +}; + +&main_pmx0 { + + icssg2_mdio_pins_default: icssg2-mdio-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x0094, PIN_INPUT, 2) /* (AC19) PRG2_PRU0_GPO7.PRG2_MDIO0_MDIO */ + AM65X_IOPAD(0x00c8, PIN_OUTPUT, 2) /* (AE15) PRG2_PRU1_GPO7.PRG2_MDIO0_MDC */ + >; + }; + + icssg2_rgmii_pins_default: icssg2-rgmii-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x00ac, PIN_INPUT, 2) /* (AH15) PRG2_PRU1_GPO0.PRG2_RGMII2_RD0 */ + AM65X_IOPAD(0x00b0, PIN_INPUT, 2) /* (AC16) PRG2_PRU1_GPO1.PRG2_RGMII2_RD1 */ + AM65X_IOPAD(0x00b4, PIN_INPUT, 2) /* (AD17) PRG2_PRU1_GPO2.PRG2_RGMII2_RD2 */ + AM65X_IOPAD(0x00b8, PIN_INPUT, 2) /* (AH14) PRG2_PRU1_GPO3.PRG2_RGMII2_RD3 */ + AM65X_IOPAD(0x00cc, PIN_OUTPUT, 2) /* (AD15) PRG2_PRU1_GPO8.PRG2_RGMII2_TD0 */ + AM65X_IOPAD(0x00d0, PIN_OUTPUT, 2) /* (AF14) PRG2_PRU1_GPO9.PRG2_RGMII2_TD1 */ + AM65X_IOPAD(0x00d4, PIN_OUTPUT, 2) /* (AC15) PRG2_PRU1_GPO10.PRG2_RGMII2_TD2 */ + AM65X_IOPAD(0x00d8, PIN_OUTPUT, 2) /* (AD14) PRG2_PRU1_GPO11.PRG2_RGMII2_TD3 */ + AM65X_IOPAD(0x00dc, PIN_INPUT, 2) /* (AE14) PRG2_PRU1_GPO16.PRG2_RGMII2_TXC */ + AM65X_IOPAD(0x00c4, PIN_OUTPUT, 2) /* (AC17) PRG2_PRU1_GPO6.PRG2_RGMII2_TX_CTL */ + AM65X_IOPAD(0x00c0, PIN_INPUT, 2) /* (AG15) PRG2_PRU1_GPO5.PRG2_RGMII2_RXC */ + AM65X_IOPAD(0x00bc, PIN_INPUT, 2) /* (AG14) PRG2_PRU1_GPO4.PRG2_RGMII2_RX_CTL */ + + AM65X_IOPAD(0x0078, PIN_INPUT, 2) /* (AF18) PRG2_PRU0_GPO0.PRG2_RGMII1_RD0 */ + AM65X_IOPAD(0x007c, PIN_INPUT, 2) /* (AE18) PRG2_PRU0_GPO1.PRG2_RGMII1_RD1 */ + AM65X_IOPAD(0x0080, PIN_INPUT, 2) /* (AH17) PRG2_PRU0_GPO2.PRG2_RGMII1_RD2 */ + AM65X_IOPAD(0x0084, PIN_INPUT, 2) /* (AG18) PRG2_PRU0_GPO3.PRG2_RGMII1_RD3 */ + AM65X_IOPAD(0x0098, PIN_OUTPUT, 2) /* (AH16) PRG2_PRU0_GPO8.PRG2_RGMII1_TD0 */ + AM65X_IOPAD(0x009c, PIN_OUTPUT, 2) /* (AG16) PRG2_PRU0_GPO9.PRG2_RGMII1_TD1 */ + AM65X_IOPAD(0x00a0, PIN_OUTPUT, 2) /* (AF16) PRG2_PRU0_GPO10.PRG2_RGMII1_TD2 */ + AM65X_IOPAD(0x00a4, PIN_OUTPUT, 2) /* (AE16) PRG2_PRU0_GPO11.PRG2_RGMII1_TD3 */ + AM65X_IOPAD(0x00a8, PIN_INPUT, 2) /* (AD16) PRG2_PRU0_GPO16.PRG2_RGMII1_TXC */ + AM65X_IOPAD(0x0090, PIN_OUTPUT, 2) /* (AE17) PRG2_PRU0_GPO6.PRG2_RGMII1_TX_CTL */ + AM65X_IOPAD(0x008c, PIN_INPUT, 2) /* (AF17) PRG2_PRU0_GPO5.PRG2_RGMII1_RXC */ + AM65X_IOPAD(0x0088, PIN_INPUT, 2) /* (AG17) PRG2_PRU0_GPO4.PRG2_RGMII1_RX_CTL */ + >; + }; +}; + +&icssg2_mdio { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg2_mdio_pins_default>; + #address-cells = <1>; + #size-cells = <0>; + + icssg2_phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; + + icssg2_phy1: ethernet-phy@3 { + reg = <3>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am654-idk.dtso b/arch/arm64/boot/dts/ti/k3-am654-idk.dtso --- a/arch/arm64/boot/dts/ti/k3-am654-idk.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am654-idk.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT overlay for IDK application board on AM654 EVM + * + * Copyright (C) 2018-2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include "k3-pinctrl.h" + +&{/} { + aliases { + ethernet3 = "/icssg0-eth/ethernet-ports/port@0"; + ethernet4 = "/icssg0-eth/ethernet-ports/port@1"; + ethernet5 = "/icssg1-eth/ethernet-ports/port@0"; + ethernet6 = "/icssg1-eth/ethernet-ports/port@1"; + }; + + /* Ethernet node on PRU-ICSSG0 */ + icssg0_eth: icssg0-eth { + compatible = "ti,am654-icssg-prueth"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg0_rgmii_pins_default>; + sram = <&msmc_ram>; + ti,prus = <&pru0_0>, <&rtu0_0>, <&tx_pru0_0>, <&pru0_1>, <&rtu0_1>, <&tx_pru0_1>; + firmware-name = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf", + "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf", + "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf", + "ti-pruss/am65x-sr2-pru1-prueth-fw.elf", + "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf", + "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf"; + + ti,pruss-gp-mux-sel = <2>, /* MII mode */ + <2>, + <2>, + <2>, /* MII mode */ + <2>, + <2>; + + ti,mii-g-rt = <&icssg0_mii_g_rt>; + ti,mii-rt = <&icssg0_mii_rt>; + ti,pa-stats = <&icssg0_pa_stats>; + ti,iep = <&icssg0_iep0>, <&icssg0_iep1>; + + interrupt-parent = <&icssg0_intc>; + interrupts = <24 0 2>, <25 1 3>; + interrupt-names = "tx_ts0", "tx_ts1"; + + dmas = <&main_udmap 0xc100>, /* egress slice 0 */ + <&main_udmap 0xc101>, /* egress slice 0 */ + <&main_udmap 0xc102>, /* egress slice 0 */ + <&main_udmap 0xc103>, /* egress slice 0 */ + <&main_udmap 0xc104>, /* egress slice 1 */ + <&main_udmap 0xc105>, /* egress slice 1 */ + <&main_udmap 0xc106>, /* egress slice 1 */ + <&main_udmap 0xc107>, /* egress slice 1 */ + + <&main_udmap 0x4100>, /* ingress slice 0 */ + <&main_udmap 0x4101>, /* ingress slice 1 */ + <&main_udmap 0x4102>, /* mgmnt rsp slice 0 */ + <&main_udmap 0x4103>; /* mgmnt rsp slice 1 */ + dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3", + "tx1-0", "tx1-1", "tx1-2", "tx1-3", + "rx0", "rx1"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + icssg0_emac0: port@0 { + reg = <0>; + phy-handle = <&icssg0_phy0>; + phy-mode = "rgmii-id"; + ti,syscon-rgmii-delay = <&scm_conf 0x4100>; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + icssg0_emac1: port@1 { + reg = <1>; + phy-handle = <&icssg0_phy1>; + phy-mode = "rgmii-id"; + ti,syscon-rgmii-delay = <&scm_conf 0x4104>; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + }; + }; + + /* Ethernet node on PRU-ICSSG1 */ + icssg1_eth: icssg1-eth { + compatible = "ti,am654-icssg-prueth"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg1_rgmii_pins_default>; + sram = <&msmc_ram>; + ti,prus = <&pru1_0>, <&rtu1_0>, <&tx_pru1_0>, <&pru1_1>, <&rtu1_1>, <&tx_pru1_1>; + firmware-name = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf", + "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf", + "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf", + "ti-pruss/am65x-sr2-pru1-prueth-fw.elf", + "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf", + "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf"; + + ti,pruss-gp-mux-sel = <2>, /* MII mode */ + <2>, + <2>, + <2>, /* MII mode */ + <2>, + <2>; + + ti,mii-g-rt = <&icssg1_mii_g_rt>; + ti,mii-rt = <&icssg1_mii_rt>; + ti,pa-stats = <&icssg1_pa_stats>; + ti,iep = <&icssg1_iep0>, <&icssg1_iep1>; + + interrupt-parent = <&icssg1_intc>; + interrupts = <24 0 2>, <25 1 3>; + interrupt-names = "tx_ts0", "tx_ts1"; + + dmas = <&main_udmap 0xc200>, /* egress slice 0 */ + <&main_udmap 0xc201>, /* egress slice 0 */ + <&main_udmap 0xc202>, /* egress slice 0 */ + <&main_udmap 0xc203>, /* egress slice 0 */ + <&main_udmap 0xc204>, /* egress slice 1 */ + <&main_udmap 0xc205>, /* egress slice 1 */ + <&main_udmap 0xc206>, /* egress slice 1 */ + <&main_udmap 0xc207>, /* egress slice 1 */ + + <&main_udmap 0x4200>, /* ingress slice 0 */ + <&main_udmap 0x4201>, /* ingress slice 1 */ + <&main_udmap 0x4202>, /* mgmnt rsp slice 0 */ + <&main_udmap 0x4203>; /* mgmnt rsp slice 1 */ + dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3", + "tx1-0", "tx1-1", "tx1-2", "tx1-3", + "rx0", "rx1"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + icssg1_emac0: port@0 { + reg = <0>; + phy-handle = <&icssg1_phy0>; + phy-mode = "rgmii-id"; + ti,syscon-rgmii-delay = <&scm_conf 0x4110>; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + icssg1_emac1: port@1 { + reg = <1>; + phy-handle = <&icssg1_phy1>; + phy-mode = "rgmii-id"; + ti,syscon-rgmii-delay = <&scm_conf 0x4114>; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + }; + }; + + transceiver1: can-phy0 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&mcan0_gpio_pins_default>; + standby-gpios = <&main_gpio1 47 GPIO_ACTIVE_LOW>; + }; + + transceiver2: can-phy1 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&mcan1_gpio_pins_default>; + standby-gpios = <&main_gpio1 67 GPIO_ACTIVE_LOW>; + }; +}; + +&main_pmx0 { + + icssg0_mdio_pins_default: icssg0-mdio-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x0294, PIN_INPUT, 0) /* (AE26) PRG0_MDIO0_MDIO */ + AM65X_IOPAD(0x0298, PIN_OUTPUT, 0) /* (AE28) PRG0_MDIO0_MDC */ + >; + }; + + icssg0_rgmii_pins_default: icssg0-rgmii-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x0244, PIN_INPUT, 2) /* (AB28) PRG0_PRU1_GPO0.PRG0_RGMII2_RD0 */ + AM65X_IOPAD(0x0248, PIN_INPUT, 2) /* (AC28) PRG0_PRU1_GPO1.PRG0_RGMII2_RD1 */ + AM65X_IOPAD(0x024c, PIN_INPUT, 2) /* (AC27) PRG0_PRU1_GPO2.PRG0_RGMII2_RD2 */ + AM65X_IOPAD(0x0250, PIN_INPUT, 2) /* (AB26) PRG0_PRU1_GPO3.PRG0_RGMII2_RD3 */ + AM65X_IOPAD(0x0274, PIN_OUTPUT, 2) /* (AC25) PRG0_PRU1_GPO12.PRG0_RGMII2_TD0 */ + AM65X_IOPAD(0x0278, PIN_OUTPUT, 2) /* (AD25) PRG0_PRU1_GPO13.PRG0_RGMII2_TD1 */ + AM65X_IOPAD(0x027c, PIN_OUTPUT, 2) /* (AD24) PRG0_PRU1_GPO14.PRG0_RGMII2_TD2 */ + AM65X_IOPAD(0x0280, PIN_OUTPUT, 2) /* (AE27) PRG0_PRU1_GPO15.PRG0_RGMII2_TD3 */ + AM65X_IOPAD(0x0284, PIN_INPUT, 2) /* (AC24) PRG0_PRU1_GPO16.PRG0_RGMII2_TXC */ + AM65X_IOPAD(0x0270, PIN_OUTPUT, 2) /* (AB24) PRG0_PRU1_GPO11.PRG0_RGMII2_TX_CTL */ + AM65X_IOPAD(0x025c, PIN_INPUT, 2) /* (AB27) PRG0_PRU1_GPO6.PRG0_RGMII2_RXC */ + AM65X_IOPAD(0x0254, PIN_INPUT, 2) /* (AA25) PRG0_PRU1_GPO4.PRG0_RGMII2_RX_CTL */ + + AM65X_IOPAD(0x01f4, PIN_INPUT, 2) /* (V24) PRG0_PRU0_GPO0.PRG0_RGMII1_RD0 */ + AM65X_IOPAD(0x01f8, PIN_INPUT, 2) /* (W25) PRG0_PRU0_GPO1.PRG0_RGMII1_RD1 */ + AM65X_IOPAD(0x01fc, PIN_INPUT, 2) /* (W24) PRG0_PRU0_GPO2.PRG0_RGMII1_RD2 */ + AM65X_IOPAD(0x0200, PIN_INPUT, 2) /* (AA27) PRG0_PRU0_GPO3.PRG0_RGMII1_RD3 */ + AM65X_IOPAD(0x0224, PIN_OUTPUT, 2) /* (AD27) PRG0_PRU0_GPO12.PRG0_RGMII1_TD0 */ + AM65X_IOPAD(0x0228, PIN_OUTPUT, 2) /* (AC26) PRG0_PRU0_GPO13.PRG0_RGMII1_TD1 */ + AM65X_IOPAD(0x022c, PIN_OUTPUT, 2) /* (AD26) PRG0_PRU0_GPO14.PRG0_RGMII1_TD2 */ + AM65X_IOPAD(0x0230, PIN_OUTPUT, 2) /* (AA24) PRG0_PRU0_GPO15.PRG0_RGMII1_TD3 */ + AM65X_IOPAD(0x0234, PIN_INPUT, 2) /* (AD28) PRG0_PRU0_GPO16.PRG0_RGMII1_TXC */ + AM65X_IOPAD(0x0220, PIN_OUTPUT, 2) /* (AB25) PRG0_PRU0_GPO11.PRG0_RGMII1_TX_CTL */ + AM65X_IOPAD(0x020c, PIN_INPUT, 2) /* (Y25) PRG0_PRU0_GPO6.PRG0_RGMII1_RXC */ + AM65X_IOPAD(0x0204, PIN_INPUT, 2) /* (Y24) PRG0_PRU0_GPO4.PRG0_RGMII1_RX_CTL */ + >; + }; + + icssg0_iep0_pins_default: icssg0-iep0-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x0240, PIN_INPUT, 2) /* (U24) PRG0_PRU0_GPO19.PRG0_IEP0_EDC_SYNC_OUT0 */ + >; + }; + + icssg1_mdio_pins_default: icssg1-mdio-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x0180, PIN_INPUT, 0) /* (AD18) PRG1_MDIO0_MDIO */ + AM65X_IOPAD(0x0184, PIN_OUTPUT, 0) /* (AH18) PRG1_MDIO0_MDC */ + >; + }; + + icssg1_rgmii_pins_default: icssg1-rgmii-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x0130, PIN_INPUT, 2) /* (AH24) PRG1_PRU1_GPO0.PRG1_RGMII2_RD0 */ + AM65X_IOPAD(0x0134, PIN_INPUT, 2) /* (AH23) PRG1_PRU1_GPO1.PRG1_RGMII2_RD1 */ + AM65X_IOPAD(0x0138, PIN_INPUT, 2) /* (AG21) PRG1_PRU1_GPO2.PRG1_RGMII2_RD2 */ + AM65X_IOPAD(0x013c, PIN_INPUT, 2) /* (AH22) PRG1_PRU1_GPO3.PRG1_RGMII2_RD3 */ + AM65X_IOPAD(0x0160, PIN_OUTPUT, 2) /* (AE20) PRG1_PRU1_GPO12.PRG1_RGMII2_TD0 */ + AM65X_IOPAD(0x0164, PIN_OUTPUT, 2) /* (AF19) PRG1_PRU1_GPO13.PRG1_RGMII2_TD1 */ + AM65X_IOPAD(0x0168, PIN_OUTPUT, 2) /* (AH19) PRG1_PRU1_GPO14.PRG1_RGMII2_TD2 */ + AM65X_IOPAD(0x016c, PIN_OUTPUT, 2) /* (AG19) PRG1_PRU1_GPO15.PRG1_RGMII2_TD3 */ + AM65X_IOPAD(0x0170, PIN_INPUT, 2) /* (AE19) PRG1_PRU1_GPO16.PRG1_RGMII2_TXC */ + AM65X_IOPAD(0x015c, PIN_OUTPUT, 2) /* (AC20) PRG1_PRU1_GPO11.PRG1_RGMII2_TX_CTL */ + AM65X_IOPAD(0x0148, PIN_INPUT, 2) /* (AG22) PRG1_PRU1_GPO6.PRG1_RGMII2_RXC */ + AM65X_IOPAD(0x0140, PIN_INPUT, 2) /* (AE21) PRG1_PRU1_GPO4.PRG1_RGMII2_RX_CTL */ + + AM65X_IOPAD(0x00e0, PIN_INPUT, 2) /* (AE22) PRG1_PRU0_GPO0.PRG1_RGMII1_RD0 */ + AM65X_IOPAD(0x00e4, PIN_INPUT, 2) /* (AG24) PRG1_PRU0_GPO1.PRG1_RGMII1_RD1 */ + AM65X_IOPAD(0x00e8, PIN_INPUT, 2) /* (AF23) PRG1_PRU0_GPO2.PRG1_RGMII1_RD2 */ + AM65X_IOPAD(0x00ec, PIN_INPUT, 2) /* (AD21) PRG1_PRU0_GPO3.PRG1_RGMII1_RD3 */ + AM65X_IOPAD(0x0110, PIN_OUTPUT, 2) /* (AH20) PRG1_PRU0_GPO12.PRG1_RGMII1_TD0 */ + AM65X_IOPAD(0x0114, PIN_OUTPUT, 2) /* (AH21) PRG1_PRU0_GPO13.PRG1_RGMII1_TD1 */ + AM65X_IOPAD(0x0118, PIN_OUTPUT, 2) /* (AG20) PRG1_PRU0_GPO14.PRG1_RGMII1_TD2 */ + AM65X_IOPAD(0x011c, PIN_OUTPUT, 2) /* (AD19) PRG1_PRU0_GPO15.PRG1_RGMII1_TD3 */ + AM65X_IOPAD(0x0120, PIN_INPUT, 2) /* (AD20) PRG1_PRU0_GPO16.PRG1_RGMII1_TXC */ + AM65X_IOPAD(0x010c, PIN_OUTPUT, 2) /* (AF21) PRG1_PRU0_GPO11.PRG1_RGMII1_TX_CTL */ + AM65X_IOPAD(0x00f8, PIN_INPUT, 2) /* (AF22) PRG1_PRU0_GPO6.PRG1_RGMII1_RXC */ + AM65X_IOPAD(0x00f0, PIN_INPUT, 2) /* (AG23) PRG1_PRU0_GPO4.PRG1_RGMII1_RX_CTL */ + >; + }; + + icssg1_iep0_pins_default: icssg1-iep0-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x012c, PIN_INPUT, 2) /* (AG26) PRG1_PRU0_GPO19.PRG1_IEP0_EDC_SYNC_OUT0 */ + >; + }; + + mcan0_gpio_pins_default: mcan0-gpio-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x023c, PIN_INPUT, 7) /* (V25) PRG0_PRU0_GPIO18:GPIO1_47 */ + >; + }; + + mcan1_gpio_pins_default: mcan1-gpio-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x028c, PIN_INPUT, 7) /* (Y26) PRG0_PRU1_GPIO18.GPIO1_67 */ + >; + }; +}; + +&wkup_pmx0 { + mcu_mcan0_pins_default: mcu-mcan0-pins-default { + pinctrl-single,pins = < + AM65X_WKUP_IOPAD(0x00ac, PIN_INPUT_PULLUP, 0) /* (W2) MCU_MCAN0_RX */ + AM65X_WKUP_IOPAD(0x00a8, PIN_OUTPUT_PULLUP, 0) /* (W1) MCU_MCAN0_TX */ + >; + }; + + mcu_mcan1_pins_default: mcu-mcan1-pins-default { + pinctrl-single,pins = < + AM65X_WKUP_IOPAD(0x00c4, PIN_INPUT_PULLUP, 1) /* (AD3) WKUP_GPIO0_5.MCU_MCAN1_RX */ + AM65X_WKUP_IOPAD(0x00c0, PIN_OUTPUT_PULLUP, 1) /* (AC3) WKUP_GPIO0_4.MCU_MCAN1_TX */ + >; + }; +}; + +&icssg0_mdio { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg0_mdio_pins_default>; + #address-cells = <1>; + #size-cells = <0>; + + icssg0_phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; + + icssg0_phy1: ethernet-phy@3 { + reg = <3>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; +}; + +&icssg0_iep0 { + pinctrl-names = "default"; + pinctrl-0 = <&icssg0_iep0_pins_default>; +}; + +&icssg1_mdio { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg1_mdio_pins_default>; + #address-cells = <1>; + #size-cells = <0>; + + icssg1_phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; + + icssg1_phy1: ethernet-phy@3 { + reg = <3>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; +}; + +&icssg1_iep0 { + pinctrl-names = "default"; + pinctrl-0 = <&icssg1_iep0_pins_default>; +}; + +&m_can0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_pins_default>; + phys = <&transceiver1>; +}; + +&m_can1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan1_pins_default>; + phys = <&transceiver2>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am654-pcie-usb2.dtso b/arch/arm64/boot/dts/ti/k3-am654-pcie-usb2.dtso --- a/arch/arm64/boot/dts/ti/k3-am654-pcie-usb2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am654-pcie-usb2.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT overlay for SERDES personality card: 2lane PCIe + USB2.0 Host on AM654 EVM + * + * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; +#include +#include +#include +#include "k3-pinctrl.h" + +&serdes0 { + assigned-clocks = <&k3_clks 153 4>, + <&serdes0 AM654_SERDES_CMU_REFCLK>, + <&serdes0 AM654_SERDES_RO_REFCLK>; + assigned-clock-parents = <&k3_clks 153 8>, + <&k3_clks 153 4>, + <&k3_clks 153 4>; + status = "okay"; +}; + +&serdes1 { + assigned-clocks = <&serdes1 AM654_SERDES_CMU_REFCLK>; + assigned-clock-parents = <&serdes0 AM654_SERDES_RO_REFCLK>; + status = "okay"; +}; + +&pcie0_rc { + num-lanes = <2>; + phys = <&serdes0 PHY_TYPE_PCIE 1>, <&serdes1 PHY_TYPE_PCIE 1>; + phy-names = "pcie-phy0", "pcie-phy1"; + reset-gpios = <&pca9555 5 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&main_pmx0 { + usb0_pins_default: usb0-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x02bc, PIN_OUTPUT, 0) /* (AD9) USB0_DRVVBUS */ + >; + }; +}; + +&dwc3_0 { + status = "okay"; +}; + +&usb0_phy { + status = "okay"; +}; + +&usb0 { + pinctrl-names = "default"; + pinctrl-0 = <&usb0_pins_default>; + dr_mode = "host"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am654-pcie-usb3.dtso b/arch/arm64/boot/dts/ti/k3-am654-pcie-usb3.dtso --- a/arch/arm64/boot/dts/ti/k3-am654-pcie-usb3.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am654-pcie-usb3.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT overlay for SERDES personality card: 1lane PCIe + USB3.0 DRD on AM654 EVM + * + * Copyright (C) 2018-2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; +#include +#include +#include + +#include "k3-pinctrl.h" + +&serdes1 { + status = "okay"; +}; + +&pcie1_rc { + num-lanes = <1>; + phys = <&serdes1 PHY_TYPE_PCIE 0>; + phy-names = "pcie-phy0"; + reset-gpios = <&pca9555 5 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&main_pmx0 { + usb0_pins_default: usb0_pins_default { + pinctrl-single,pins = < + AM65X_IOPAD(0x02bc, PIN_OUTPUT, 0) /* (AD9) USB0_DRVVBUS */ + >; + }; +}; + +&serdes0 { + status = "okay"; + assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>; + assigned-clock-parents = <&k3_clks 153 7>, <&k3_clks 153 4>; +}; + +&dwc3_0 { + status = "okay"; + assigned-clock-parents = <&k3_clks 151 4>, /* set REF_CLK to 20MHz i.e. PER0_PLL/48 */ + <&k3_clks 151 8>; /* set PIPE3_TXB_CLK to WIZ8B2M4VSB */ + phys = <&serdes0 PHY_TYPE_USB3 0>; + phy-names = "usb3-phy"; +}; + +&usb0 { + pinctrl-names = "default"; + pinctrl-0 = <&usb0_pins_default>; + dr_mode = "host"; + maximum-speed = "super-speed"; + snps,dis-u1-entry-quirk; + snps,dis-u2-entry-quirk; +}; + +&usb0_phy { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am65.dtsi b/arch/arm64/boot/dts/ti/k3-am65.dtsi --- a/arch/arm64/boot/dts/ti/k3-am65.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am65.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -54,6 +54,7 @@ ranges = <0x00 0x00100000 0x00 0x00100000 0x00 0x00020000>, /* ctrl mmr */ <0x00 0x00600000 0x00 0x00600000 0x00 0x00001100>, /* GPIO */ <0x00 0x00900000 0x00 0x00900000 0x00 0x00012000>, /* serdes */ + <0x00 0x00a40000 0x00 0x00a40000 0x00 0x00000800>, /* timesync router */ <0x00 0x01000000 0x00 0x01000000 0x00 0x0af02400>, /* Most peripherals */ <0x00 0x30800000 0x00 0x30800000 0x00 0x0bc00000>, /* MAIN NAVSS */ <0x00 0x70000000 0x00 0x70000000 0x00 0x00200000>, /* MSMC SRAM */ diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -9,8 +9,8 @@ * Common bits of the IOT2050 Basic and Advanced variants, PG1 and PG2 */ -#include "k3-am654.dtsi" #include +#include / { aliases { @@ -27,6 +27,8 @@ spi0 = &mcu_spi0; mmc0 = &sdhci1; mmc1 = &sdhci0; + ethernet1 = &icssg0_emac0; + ethernet2 = &icssg0_emac1; }; chosen { @@ -73,6 +75,12 @@ alignment = <0x1000>; no-map; }; + + /* To reserve the power-on(PON) reason for watchdog reset */ + wdt_reset_memory_region: wdt-memory@a2200000 { + reg = <0x00 0xa2200000 0x00 0x1000>; + no-map; + }; }; leds { @@ -111,9 +119,498 @@ #clock-cells = <0>; clock-frequency = <19200000>; }; + + /* Dual Ethernet application node on PRU-ICSSG0 */ + icssg0_eth: icssg0-eth { + compatible = "ti,am654-icssg-prueth"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg0_rgmii_pins_default>; + sram = <&msmc_ram>; + + ti,prus = <&pru0_0>, <&rtu0_0>, <&tx_pru0_0>, + <&pru0_1>, <&rtu0_1>, <&tx_pru0_1>; + firmware-name = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf", + "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf", + "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf", + "ti-pruss/am65x-sr2-pru1-prueth-fw.elf", + "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf", + "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf"; + + ti,pruss-gp-mux-sel = <2>, /* MII mode */ + <2>, + <2>, + <2>, /* MII mode */ + <2>, + <2>; + + ti,mii-g-rt = <&icssg0_mii_g_rt>; + ti,mii-rt = <&icssg0_mii_rt>; + ti,iep = <&icssg0_iep0>, <&icssg0_iep1>; + + interrupt-parent = <&icssg0_intc>; + interrupts = <24 0 2>, <25 1 3>; + interrupt-names = "tx_ts0", "tx_ts1"; + + dmas = <&main_udmap 0xc100>, /* egress slice 0 */ + <&main_udmap 0xc101>, /* egress slice 0 */ + <&main_udmap 0xc102>, /* egress slice 0 */ + <&main_udmap 0xc103>, /* egress slice 0 */ + <&main_udmap 0xc104>, /* egress slice 1 */ + <&main_udmap 0xc105>, /* egress slice 1 */ + <&main_udmap 0xc106>, /* egress slice 1 */ + <&main_udmap 0xc107>, /* egress slice 1 */ + <&main_udmap 0x4100>, /* ingress slice 0 */ + <&main_udmap 0x4101>; /* ingress slice 1 */ + dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3", + "tx1-0", "tx1-1", "tx1-2", "tx1-3", + "rx0", "rx1"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + icssg0_emac0: port@0 { + reg = <0>; + phy-handle = <&icssg0_eth0_phy>; + phy-mode = "rgmii-id"; + ti,syscon-rgmii-delay = <&scm_conf 0x4100>; + ti,half-duplex-capable; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + + icssg0_emac1: port@1 { + reg = <1>; + phy-handle = <&icssg0_eth1_phy>; + phy-mode = "rgmii-id"; + ti,syscon-rgmii-delay = <&scm_conf 0x4104>; + ti,half-duplex-capable; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + }; + }; }; &wkup_pmx0 { + pinctrl-names = + "default", + "d0-uart0-rxd", "d0-gpio", "d0-gpio-pullup", "d0-gpio-pulldown", + "d1-uart0-txd", "d1-gpio", "d1-gpio-pullup", "d1-gpio-pulldown", + "d2-uart0-ctsn", "d2-gpio", "d2-gpio-pullup", "d2-gpio-pulldown", + "d3-uart0-rtsn", "d3-gpio", "d3-gpio-pullup", "d3-gpio-pulldown", + "d10-spi0-cs0", "d10-gpio", "d10-gpio-pullup", "d10-gpio-pulldown", + "d11-spi0-d0", "d11-gpio", "d11-gpio-pullup", "d11-gpio-pulldown", + "d12-spi0-d1", "d12-gpio", "d12-gpio-pullup", "d12-gpio-pulldown", + "d13-spi0-clk", "d13-gpio", "d13-gpio-pullup", "d13-gpio-pulldown", + "a0-gpio", "a0-gpio-pullup", "a0-gpio-pulldown", + "a1-gpio", "a1-gpio-pullup", "a1-gpio-pulldown", + "a2-gpio", "a2-gpio-pullup", "a2-gpio-pulldown", + "a3-gpio", "a3-gpio-pullup", "a3-gpio-pulldown", + "a4-gpio", "a4-gpio-pullup", "a4-gpio-pulldown", + "a5-gpio", "a5-gpio-pullup", "a5-gpio-pulldown"; + + pinctrl-0 = <&d0_uart0_rxd>; + pinctrl-1 = <&d0_uart0_rxd>; + pinctrl-2 = <&d0_gpio>; + pinctrl-3 = <&d0_gpio_pullup>; + pinctrl-4 = <&d0_gpio_pulldown>; + pinctrl-5 = <&d1_uart0_txd>; + pinctrl-6 = <&d1_gpio>; + pinctrl-7 = <&d1_gpio_pullup>; + pinctrl-8 = <&d1_gpio_pulldown>; + pinctrl-9 = <&d2_uart0_ctsn>; + pinctrl-10 = <&d2_gpio>; + pinctrl-11 = <&d2_gpio_pullup>; + pinctrl-12 = <&d2_gpio_pulldown>; + pinctrl-13 = <&d3_uart0_rtsn>; + pinctrl-14 = <&d3_gpio>; + pinctrl-15 = <&d3_gpio_pullup>; + pinctrl-16 = <&d3_gpio_pulldown>; + pinctrl-17 = <&d10_spi0_cs0>; + pinctrl-18 = <&d10_gpio>; + pinctrl-19 = <&d10_gpio_pullup>; + pinctrl-20 = <&d10_gpio_pulldown>; + pinctrl-21 = <&d11_spi0_d0>; + pinctrl-22 = <&d11_gpio>; + pinctrl-23 = <&d11_gpio_pullup>; + pinctrl-24 = <&d11_gpio_pulldown>; + pinctrl-25 = <&d12_spi0_d1>; + pinctrl-26 = <&d12_gpio>; + pinctrl-27 = <&d12_gpio_pullup>; + pinctrl-28 = <&d12_gpio_pulldown>; + pinctrl-29 = <&d13_spi0_clk>; + pinctrl-30 = <&d13_gpio>; + pinctrl-31 = <&d13_gpio_pullup>; + pinctrl-32 = <&d13_gpio_pulldown>; + pinctrl-33 = <&a0_gpio>; + pinctrl-34 = <&a0_gpio_pullup>; + pinctrl-35 = <&a0_gpio_pulldown>; + pinctrl-36 = <&a1_gpio>; + pinctrl-37 = <&a1_gpio_pullup>; + pinctrl-38 = <&a1_gpio_pulldown>; + pinctrl-39 = <&a2_gpio>; + pinctrl-40 = <&a2_gpio_pullup>; + pinctrl-41 = <&a2_gpio_pulldown>; + pinctrl-42 = <&a3_gpio>; + pinctrl-43 = <&a3_gpio_pullup>; + pinctrl-44 = <&a3_gpio_pulldown>; + pinctrl-45 = <&a4_gpio>; + pinctrl-46 = <&a4_gpio_pullup>; + pinctrl-47 = <&a4_gpio_pulldown>; + pinctrl-48 = <&a5_gpio>; + pinctrl-49 = <&a5_gpio_pullup>; + pinctrl-50 = <&a5_gpio_pulldown>; + + d0_uart0_rxd: d0-uart0-rxd-pins { + pinctrl-single,pins = < + /* (P4) MCU_UART0_RXD */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4) + >; + }; + + d0_gpio: d0-gpio-pins { + pinctrl-single,pins = < + /* (P4) WKUP_GPIO0_29 */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 7) + >; + }; + + d0_gpio_pullup: d0-gpio-pullup-pins { + pinctrl-single,pins = < + /* (P4) WKUP_GPIO0_29 */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT_PULLUP, 7) + >; + }; + + d0_gpio_pulldown: d0-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (P4) WKUP_GPIO0_29 */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d1_uart0_txd: d1-uart0-txd-pins { + pinctrl-single,pins = < + /* (P5) MCU_UART0_TXD */ + AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4) + >; + }; + + d1_gpio: d1-gpio-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_30 */ + AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7) + >; + }; + + d1_gpio_pullup: d1-gpio-pullup-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_30 */ + AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7) + >; + }; + + d1_gpio_pulldown: d1-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_30 */ + AM65X_WKUP_IOPAD(0x0048, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d2_uart0_ctsn: d2-uart0-ctsn-pins { + pinctrl-single,pins = < + /* (P1) MCU_UART0_CTSn */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 4) + >; + }; + + d2_gpio: d2-gpio-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_31 */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7) + >; + }; + + d2_gpio_pullup: d2-gpio-pullup-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_31 */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7) + >; + }; + + d2_gpio_pulldown: d2-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_31 */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d3_uart0_rtsn: d3-uart0-rtsn-pins { + pinctrl-single,pins = < + /* (N3) MCU_UART0_RTSn */ + AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 4) + >; + }; + + d3_gpio: d3-gpio-pins { + pinctrl-single,pins = < + /* (N3) WKUP_GPIO0_33 */ + AM65X_WKUP_IOPAD(0x0054, PIN_INPUT, 7) + >; + }; + + d3_gpio_pullup: d3-gpio-pullup-pins { + pinctrl-single,pins = < + /* (N3) WKUP_GPIO0_33 */ + AM65X_WKUP_IOPAD(0x0054, PIN_INPUT, 7) + >; + }; + + d3_gpio_pulldown: d3-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (N3) WKUP_GPIO0_33 */ + AM65X_WKUP_IOPAD(0x0054, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d10_spi0_cs0: d10-spi0-cs0-pins { + pinctrl-single,pins = < + /* (Y4) MCU_SPI0_CS0 */ + AM65X_WKUP_IOPAD(0x009c, PIN_OUTPUT, 0) + >; + }; + + d10_gpio: d10-gpio-pins { + pinctrl-single,pins = < + /* (Y4) WKUP_GPIO0_51 */ + AM65X_WKUP_IOPAD(0x009c, PIN_INPUT, 7) + >; + }; + + d10_gpio_pullup: d10-gpio-pullup-pins { + pinctrl-single,pins = < + /* (Y4) WKUP_GPIO0_51 */ + AM65X_WKUP_IOPAD(0x009c, PIN_INPUT, 7) + >; + }; + + d10_gpio_pulldown: d10-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (Y4) WKUP_GPIO0_51 */ + AM65X_WKUP_IOPAD(0x009c, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d11_spi0_d0: d11-spi0-d0-pins { + pinctrl-single,pins = < + /* (Y3) MCU_SPI0_D0 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 0) + >; + }; + + d11_gpio: d11-gpio-pins { + pinctrl-single,pins = < + /* (Y3) WKUP_GPIO0_49 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 7) + >; + }; + + d11_gpio_pullup: d11-gpio-pullup-pins { + pinctrl-single,pins = < + /* (Y3) WKUP_GPIO0_49 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 7) + >; + }; + + d11_gpio_pulldown: d11-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (Y3) WKUP_GPIO0_49 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d12_spi0_d1: d12-spi0-d1-pins { + pinctrl-single,pins = < + /* (Y2) MCU_SPI0_D1 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 0) + >; + }; + + d12_gpio: d12-gpio-pins { + pinctrl-single,pins = < + /* (Y2) WKUP_GPIO0_50 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 7) + >; + }; + + d12_gpio_pullup: d12-gpio-pullup-pins { + pinctrl-single,pins = < + /* (Y2) WKUP_GPIO0_50 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 7) + >; + }; + + d12_gpio_pulldown: d12-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (Y2) WKUP_GPIO0_50 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d13_spi0_clk: d13-spi0-clk-pins { + pinctrl-single,pins = < + /* (Y1) MCU_SPI0_CLK */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 0) + >; + }; + + d13_gpio: d13-gpio-pins { + pinctrl-single,pins = < + /* (Y1) WKUP_GPIO0_48 */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 7) + >; + }; + + d13_gpio_pullup: d13-gpio-pullup-pins { + pinctrl-single,pins = < + /* (Y1) WKUP_GPIO0_48 */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 7) + >; + }; + + d13_gpio_pulldown: d13-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (Y1) WKUP_GPIO0_48 */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a0_gpio: a0-gpio-pins { + pinctrl-single,pins = < + /* (L6) WKUP_GPIO0_45 */ + AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 7) + >; + }; + + a0_gpio_pullup: a0-gpio-pullup-pins { + pinctrl-single,pins = < + /* (L6) WKUP_GPIO0_45 */ + AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 7) + >; + }; + + a0_gpio_pulldown: a0-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (L6) WKUP_GPIO0_45 */ + AM65X_WKUP_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a1_gpio: a1-gpio-pins { + pinctrl-single,pins = < + /* (M6) WKUP_GPIO0_44 */ + AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 7) + >; + }; + + a1_gpio_pullup: a1-gpio-pullup-pins { + pinctrl-single,pins = < + /* (M6) WKUP_GPIO0_44 */ + AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 7) + >; + }; + + a1_gpio_pulldown: a1-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (M6) WKUP_GPIO0_44 */ + AM65X_WKUP_IOPAD(0x0080, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a2_gpio: a2-gpio-pins { + pinctrl-single,pins = < + /* (L5) WKUP_GPIO0_43 */ + AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7) + >; + }; + + a2_gpio_pullup: a2-gpio-pullup-pins { + pinctrl-single,pins = < + /* (L5) WKUP_GPIO0_43 */ + AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7) + >; + }; + + a2_gpio_pulldown: a2-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (L5) WKUP_GPIO0_43 */ + AM65X_WKUP_IOPAD(0x007C, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a3_gpio: a3-gpio-pins { + pinctrl-single,pins = < + /* (M5) WKUP_GPIO0_39 */ + AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7) + >; + }; + + a3_gpio_pullup: a3-gpio-pullup-pins { + pinctrl-single,pins = < + /* (M5) WKUP_GPIO0_39 */ + AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7) + >; + }; + + a3_gpio_pulldown: a3-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (M5) WKUP_GPIO0_39 */ + AM65X_WKUP_IOPAD(0x006C, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a4_gpio: a4-gpio-pins { + pinctrl-single,pins = < + /* (L2) WKUP_GPIO0_42 */ + AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 7) + >; + }; + + a4_gpio_pullup: a4-gpio-pullup-pins { + pinctrl-single,pins = < + /* (L2) WKUP_GPIO0_42 */ + AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 7) + >; + }; + + a4_gpio_pulldown: a4-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (L2) WKUP_GPIO0_42 */ + AM65X_WKUP_IOPAD(0x0078, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a5_gpio: a5-gpio-pins { + pinctrl-single,pins = < + /* (N5) WKUP_GPIO0_35 */ + AM65X_WKUP_IOPAD(0x005C, PIN_INPUT, 7) + >; + }; + + a5_gpio_pullup: a5-gpio-pullup-pins { + pinctrl-single,pins = < + /* (N5) WKUP_GPIO0_35 */ + AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLUP, 7) + >; + }; + + a5_gpio_pulldown: a5-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (N5) WKUP_GPIO0_35 */ + AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLDOWN, 7) + >; + }; + wkup_i2c0_pins_default: wkup-i2c0-default-pins { pinctrl-single,pins = < /* (AC7) WKUP_I2C0_SCL */ @@ -146,23 +643,6 @@ >; }; - arduino_uart_pins_default: arduino-uart-default-pins { - pinctrl-single,pins = < - /* (P4) MCU_UART0_RXD */ - AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4) - /* (P5) MCU_UART0_TXD */ - AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4) - >; - }; - - arduino_io_d2_to_d3_pins_default: arduino-io-d2-to-d3-default-pins { - pinctrl-single,pins = < - /* (P1) WKUP_GPIO0_31 */ - AM65X_WKUP_IOPAD(0x004C, PIN_OUTPUT, 7) - /* (N3) WKUP_GPIO0_33 */ - AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 7) - >; - }; arduino_io_oe_pins_default: arduino-io-oe-default-pins { pinctrl-single,pins = < @@ -242,6 +722,220 @@ }; &main_pmx0 { + pinctrl-names = + "default", + "d4-ehrpwm0-a", "d4-gpio", "d4-gpio-pullup", "d4-gpio-pulldown", + "d5-ehrpwm1-a", "d5-gpio", "d5-gpio-pullup", "d5-gpio-pulldown", + "d6-ehrpwm2-a", "d6-gpio", "d6-gpio-pullup", "d6-gpio-pulldown", + "d7-ehrpwm3-a", "d7-gpio", "d7-gpio-pullup", "d7-gpio-pulldown", + "d8-ehrpwm4-a", "d8-gpio", "d8-gpio-pullup", "d8-gpio-pulldown", + "d9-ehrpwm5-a", "d9-gpio", "d9-gpio-pullup", "d9-gpio-pulldown"; + + pinctrl-0 = <&d4_ehrpwm0_a>; + pinctrl-1 = <&d4_ehrpwm0_a>; + pinctrl-2 = <&d4_gpio>; + pinctrl-3 = <&d4_gpio_pullup>; + pinctrl-4 = <&d4_gpio_pulldown>; + + pinctrl-5 = <&d5_ehrpwm1_a>; + pinctrl-6 = <&d5_gpio>; + pinctrl-7 = <&d5_gpio_pullup>; + pinctrl-8 = <&d5_gpio_pulldown>; + + pinctrl-9 = <&d6_ehrpwm2_a>; + pinctrl-10 = <&d6_gpio>; + pinctrl-11 = <&d6_gpio_pullup>; + pinctrl-12 = <&d6_gpio_pulldown>; + + pinctrl-13 = <&d7_ehrpwm3_a>; + pinctrl-14 = <&d7_gpio>; + pinctrl-15 = <&d7_gpio_pullup>; + pinctrl-16 = <&d7_gpio_pulldown>; + + pinctrl-17 = <&d8_ehrpwm4_a>; + pinctrl-18 = <&d8_gpio>; + pinctrl-19 = <&d8_gpio_pullup>; + pinctrl-20 = <&d8_gpio_pulldown>; + + pinctrl-21 = <&d9_ehrpwm5_a>; + pinctrl-22 = <&d9_gpio>; + pinctrl-23 = <&d9_gpio_pullup>; + pinctrl-24 = <&d9_gpio_pulldown>; + + d4_ehrpwm0_a: d4-ehrpwm0-a-pins { + pinctrl-single,pins = < + /* (AG18) EHRPWM0_A */ + AM65X_IOPAD(0x0084, PIN_OUTPUT, 5) + >; + }; + + d4_gpio: d4-gpio-pins { + pinctrl-single,pins = < + /* (AG18) GPIO0_33 */ + AM65X_IOPAD(0x0084, PIN_INPUT, 7) + >; + }; + + d4_gpio_pullup: d4-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AG18) GPIO0_33 */ + AM65X_IOPAD(0x0084, PIN_INPUT_PULLUP, 7) + >; + }; + + d4_gpio_pulldown: d4-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AG18) GPIO0_33 */ + AM65X_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d5_ehrpwm1_a: d5-ehrpwm1-a-pins { + pinctrl-single,pins = < + /* (AF17) EHRPWM1_A */ + AM65X_IOPAD(0x008C, PIN_OUTPUT, 5) + >; + }; + + d5_gpio: d5-gpio-pins { + pinctrl-single,pins = < + /* (AF17) GPIO0_35 */ + AM65X_IOPAD(0x008C, PIN_INPUT, 7) + >; + }; + + d5_gpio_pullup: d5-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AF17) GPIO0_35 */ + AM65X_IOPAD(0x008C, PIN_INPUT_PULLUP, 7) + >; + }; + + d5_gpio_pulldown: d5-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AF17) GPIO0_35 */ + AM65X_IOPAD(0x008C, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d6_ehrpwm2_a: d6-ehrpwm2-a-pins { + pinctrl-single,pins = < + /* (AH16) EHRPWM2_A */ + AM65X_IOPAD(0x0098, PIN_OUTPUT, 5) + >; + }; + + d6_gpio: d6-gpio-pins { + pinctrl-single,pins = < + /* (AH16) GPIO0_38 */ + AM65X_IOPAD(0x0098, PIN_INPUT, 7) + >; + }; + + d6_gpio_pullup: d6-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AH16) GPIO0_38 */ + AM65X_IOPAD(0x0098, PIN_INPUT_PULLUP, 7) + >; + }; + + d6_gpio_pulldown: d6-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AH16) GPIO0_38 */ + AM65X_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d7_ehrpwm3_a: d7-ehrpwm3-a-pins { + pinctrl-single,pins = < + /* (AH15) EHRPWM3_A */ + AM65X_IOPAD(0x00AC, PIN_OUTPUT, 5) + >; + }; + + d7_gpio: d7-gpio-pins { + pinctrl-single,pins = < + /* (AH15) GPIO0_43 */ + AM65X_IOPAD(0x00AC, PIN_INPUT, 7) + >; + }; + + d7_gpio_pullup: d7-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AH15) GPIO0_43 */ + AM65X_IOPAD(0x00AC, PIN_INPUT_PULLUP, 7) + >; + }; + + d7_gpio_pulldown: d7-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AH15) GPIO0_43 */ + AM65X_IOPAD(0x00AC, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d8_ehrpwm4_a: d8-ehrpwm4-a-pins { + pinctrl-single,pins = < + /* (AG15) EHRPWM4_A */ + AM65X_IOPAD(0x00C0, PIN_OUTPUT, 5) + >; + }; + + d8_gpio: d8-gpio-pins { + pinctrl-single,pins = < + /* (AG15) GPIO0_48 */ + AM65X_IOPAD(0x00C0, PIN_INPUT, 7) + >; + }; + + d8_gpio_pullup: d8-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AG15) GPIO0_48 */ + AM65X_IOPAD(0x00C0, PIN_INPUT_PULLUP, 7) + >; + }; + + d8_gpio_pulldown: d8-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AG15) GPIO0_48 */ + AM65X_IOPAD(0x00C0, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d9_ehrpwm5_a: d9-ehrpwm5-a-pins { + pinctrl-single,pins = < + /* (AD15) EHRPWM5_A */ + AM65X_IOPAD(0x00CC, PIN_OUTPUT, 5) + >; + }; + + d9_gpio: d9-gpio-pins { + pinctrl-single,pins = < + /* (AD15) GPIO0_51 */ + AM65X_IOPAD(0x00CC, PIN_INPUT, 7) + >; + }; + + d9_gpio_pullup: d9-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AD15) GPIO0_51 */ + AM65X_IOPAD(0x00CC, PIN_INPUT_PULLUP, 7) + >; + }; + + d9_gpio_pulldown: d9-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AD15) GPIO0_51 */ + AM65X_IOPAD(0x00CC, PIN_INPUT_PULLDOWN, 7) + >; + }; + + main_pcie_enable_pins_default: main-pcie-enable-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x01c4, PIN_INPUT_PULLUP, 7) /* (AH13) GPIO1_17 */ + >; + }; + main_uart1_pins_default: main-uart1-default-pins { pinctrl-single,pins = < AM65X_IOPAD(0x0174, PIN_INPUT, 6) /* (AE23) UART1_RXD */ @@ -283,17 +977,6 @@ >; }; - arduino_io_d4_to_d9_pins_default: arduino-io-d4-to-d9-default-pins { - pinctrl-single,pins = < - AM65X_IOPAD(0x0084, PIN_OUTPUT, 7) /* (AG18) GPIO0_33 */ - AM65X_IOPAD(0x008C, PIN_OUTPUT, 7) /* (AF17) GPIO0_35 */ - AM65X_IOPAD(0x0098, PIN_OUTPUT, 7) /* (AH16) GPIO0_38 */ - AM65X_IOPAD(0x00AC, PIN_OUTPUT, 7) /* (AH15) GPIO0_43 */ - AM65X_IOPAD(0x00C0, PIN_OUTPUT, 7) /* (AG15) GPIO0_48 */ - AM65X_IOPAD(0x00CC, PIN_OUTPUT, 7) /* (AD15) GPIO0_51 */ - >; - }; - dss_vout1_pins_default: dss-vout1-default-pins { pinctrl-single,pins = < AM65X_IOPAD(0x0000, PIN_OUTPUT, 1) /* VOUT1_DATA0 */ @@ -339,6 +1022,43 @@ AM65X_IOPAD(0x0070, PIN_INPUT, 5) /* (R25) I2C2_SDA */ >; }; + + icssg0_mdio_pins_default: icssg0-mdio-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x0294, PIN_INPUT, 0) /* (AE26) PRG0_MDIO0_MDIO */ + AM65X_IOPAD(0x0298, PIN_OUTPUT, 0) /* (AE28) PRG0_MDIO0_MDC */ + >; + }; + + icssg0_rgmii_pins_default: icssg0-rgmii-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x0244, PIN_INPUT, 2) /* (AB28) PRG0_PRU1_GPO0.PRG0_RGMII2_RD0 */ + AM65X_IOPAD(0x0248, PIN_INPUT, 2) /* (AC28) PRG0_PRU1_GPO1.PRG0_RGMII2_RD1 */ + AM65X_IOPAD(0x024c, PIN_INPUT, 2) /* (AC27) PRG0_PRU1_GPO2.PRG0_RGMII2_RD2 */ + AM65X_IOPAD(0x0250, PIN_INPUT, 2) /* (AB26) PRG0_PRU1_GPO3.PRG0_RGMII2_RD3 */ + AM65X_IOPAD(0x0274, PIN_OUTPUT, 2) /* (AC25) PRG0_PRU1_GPO12.PRG0_RGMII2_TD0 */ + AM65X_IOPAD(0x0278, PIN_OUTPUT, 2) /* (AD25) PRG0_PRU1_GPO13.PRG0_RGMII2_TD1 */ + AM65X_IOPAD(0x027c, PIN_OUTPUT, 2) /* (AD24) PRG0_PRU1_GPO14.PRG0_RGMII2_TD2 */ + AM65X_IOPAD(0x0280, PIN_OUTPUT, 2) /* (AE27) PRG0_PRU1_GPO15.PRG0_RGMII2_TD3 */ + AM65X_IOPAD(0x0284, PIN_INPUT, 2) /* (AC24) PRG0_PRU1_GPO16.PRG0_RGMII2_TXC */ + AM65X_IOPAD(0x0270, PIN_OUTPUT, 2) /* (AB24) PRG0_PRU1_GPO11.PRG0_RGMII2_TX_CTL */ + AM65X_IOPAD(0x025c, PIN_INPUT, 2) /* (AB27) PRG0_PRU1_GPO6.PRG0_RGMII2_RXC */ + AM65X_IOPAD(0x0254, PIN_INPUT, 2) /* (AA25) PRG0_PRU1_GPO4.PRG0_RGMII2_RX_CTL */ + + AM65X_IOPAD(0x01f4, PIN_INPUT, 2) /* (V24) PRG0_PRU0_GPO0.PRG0_RGMII1_RD0 */ + AM65X_IOPAD(0x01f8, PIN_INPUT, 2) /* (W25) PRG0_PRU0_GPO1.PRG0_RGMII1_RD1 */ + AM65X_IOPAD(0x01fc, PIN_INPUT, 2) /* (W24) PRG0_PRU0_GPO2.PRG0_RGMII1_RD2 */ + AM65X_IOPAD(0x0200, PIN_INPUT, 2) /* (AA27) PRG0_PRU0_GPO3.PRG0_RGMII1_RD3 */ + AM65X_IOPAD(0x0224, PIN_OUTPUT, 2) /* (AD27) PRG0_PRU0_GPO12.PRG0_RGMII1_TD0 */ + AM65X_IOPAD(0x0228, PIN_OUTPUT, 2) /* (AC26) PRG0_PRU0_GPO13.PRG0_RGMII1_TD1 */ + AM65X_IOPAD(0x022c, PIN_OUTPUT, 2) /* (AD26) PRG0_PRU0_GPO14.PRG0_RGMII1_TD2 */ + AM65X_IOPAD(0x0230, PIN_OUTPUT, 2) /* (AA24) PRG0_PRU0_GPO15.PRG0_RGMII1_TD3 */ + AM65X_IOPAD(0x0234, PIN_INPUT, 2) /* (AD28) PRG0_PRU0_GPO16.PRG0_RGMII1_TXC */ + AM65X_IOPAD(0x0220, PIN_OUTPUT, 2) /* (AB25) PRG0_PRU0_GPO11.PRG0_RGMII1_TX_CTL */ + AM65X_IOPAD(0x020c, PIN_INPUT, 2) /* (Y25) PRG0_PRU0_GPO6.PRG0_RGMII1_RXC */ + AM65X_IOPAD(0x0204, PIN_INPUT, 2) /* (Y24) PRG0_PRU0_GPO4.PRG0_RGMII1_RX_CTL */ + >; + }; }; &main_pmx1 { @@ -355,12 +1075,6 @@ AM65X_IOPAD(0x000c, PIN_INPUT, 0) /* (E21) I2C1_SDA */ >; }; - - ecap0_pins_default: ecap0-default-pins { - pinctrl-single,pins = < - AM65X_IOPAD(0x0010, PIN_INPUT, 0) /* (D21) ECAP0_IN_APWM_OUT */ - >; - }; }; &wkup_uart0 { @@ -376,13 +1090,9 @@ &mcu_uart0 { status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&arduino_uart_pins_default>; }; &main_gpio0 { - pinctrl-names = "default"; - pinctrl-0 = <&arduino_io_d4_to_d9_pins_default>; gpio-line-names = "main_gpio0-base", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", @@ -392,10 +1102,14 @@ "", "IO9"; }; +&main_gpio1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_pcie_enable_pins_default>; +}; + &wkup_gpio0 { pinctrl-names = "default"; pinctrl-0 = - <&arduino_io_d2_to_d3_pins_default>, <&arduino_i2c_aio_switch_pins_default>, <&arduino_io_oe_pins_default>, <&push_button_pins_default>, @@ -557,13 +1271,8 @@ status = "disabled"; }; -&ecap0 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&ecap0_pins_default>; -}; - &sdhci1 { + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; ti,driver-strength-ohm = <50>; @@ -584,9 +1293,6 @@ &mcu_spi0 { status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&mcu_spi0_pins_default>; - #address-cells = <1>; #size-cells = <0>; ti,pindir-d0-out-d1-in; @@ -718,11 +1424,33 @@ &mcu_r5fss0_core0 { memory-region = <&mcu_r5fss0_core0_dma_memory_region>, <&mcu_r5fss0_core0_memory_region>; - mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>; + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>; }; &mcu_r5fss0_core1 { memory-region = <&mcu_r5fss0_core1_dma_memory_region>, <&mcu_r5fss0_core1_memory_region>; - mboxes = <&mailbox0_cluster1>, <&mbox_mcu_r5fss0_core1>; + mboxes = <&mailbox0_cluster1 &mbox_mcu_r5fss0_core1>; +}; + +&mcu_rti1 { + memory-region = <&wdt_reset_memory_region>; +}; + +&icssg0_mdio { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg0_mdio_pins_default>; + + icssg0_eth0_phy: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; + + icssg0_eth1_phy: ethernet-phy@1 { + reg = <1>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) Siemens AG, 2021 + * Copyright (c) Siemens AG, 2021-2023 * * Authors: * Jan Kiszka @@ -44,3 +44,11 @@ &tx_pru2_1 { status = "disabled"; }; + +&icssg0_eth { + status = "disabled"; +}; + +&icssg0_mdio { + status = "disabled"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -20,7 +20,9 @@ &main_gpio1 { pinctrl-names = "default"; - pinctrl-0 = <&cp2102n_reset_pin_default>; + pinctrl-0 = + <&main_pcie_enable_pins_default>, + <&cp2102n_reset_pin_default>; gpio-line-names = "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi --- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -436,19 +436,15 @@ interrupts = ; mmc-ddr-1_8v; mmc-hs200-1_8v; + ti,clkbuf-sel = <0x7>; + ti,trm-icp = <0x8>; ti,otap-del-sel-legacy = <0x0>; ti,otap-del-sel-mmc-hs = <0x0>; - ti,otap-del-sel-sd-hs = <0x0>; - ti,otap-del-sel-sdr12 = <0x0>; - ti,otap-del-sel-sdr25 = <0x0>; - ti,otap-del-sel-sdr50 = <0x8>; - ti,otap-del-sel-sdr104 = <0x7>; - ti,otap-del-sel-ddr50 = <0x5>; ti,otap-del-sel-ddr52 = <0x5>; ti,otap-del-sel-hs200 = <0x5>; - ti,otap-del-sel-hs400 = <0x0>; - ti,trm-icp = <0x8>; + ti,itap-del-sel-ddr52 = <0x0>; dma-coherent; + status = "disabled"; }; sdhci1: mmc@4fa0000 { @@ -458,19 +454,21 @@ clocks = <&k3_clks 48 0>, <&k3_clks 48 1>; clock-names = "clk_ahb", "clk_xin"; interrupts = ; + ti,clkbuf-sel = <0x7>; + ti,trm-icp = <0x8>; ti,otap-del-sel-legacy = <0x0>; - ti,otap-del-sel-mmc-hs = <0x0>; ti,otap-del-sel-sd-hs = <0x0>; - ti,otap-del-sel-sdr12 = <0x0>; - ti,otap-del-sel-sdr25 = <0x0>; + ti,otap-del-sel-sdr12 = <0xf>; + ti,otap-del-sel-sdr25 = <0xf>; ti,otap-del-sel-sdr50 = <0x8>; ti,otap-del-sel-sdr104 = <0x7>; ti,otap-del-sel-ddr50 = <0x4>; - ti,otap-del-sel-ddr52 = <0x4>; - ti,otap-del-sel-hs200 = <0x7>; - ti,clkbuf-sel = <0x7>; - ti,trm-icp = <0x8>; + ti,itap-del-sel-legacy = <0xa>; + ti,itap-del-sel-sd-hs = <0x1>; + ti,itap-del-sel-sdr12 = <0xa>; + ti,itap-del-sel-sdr25 = <0x1>; dma-coherent; + status = "disabled"; }; scm_conf: scm-conf@100000 { @@ -498,8 +496,8 @@ }; dss_oldi_io_ctrl: dss-oldi-io-ctrl@41e0 { - compatible = "syscon"; - reg = <0x000041e0 0x14>; + compatible = "ti,am654-dss-oldi-io-ctrl", "syscon"; + reg = <0x41e0 0x14>; }; ehrpwm_tbclk: clock-controller@4140 { @@ -600,7 +598,7 @@ }; main_navss: bus@30800000 { - compatible = "simple-mfd"; + compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; ranges = <0x0 0x30800000 0x0 0x30800000 0x0 0xbc00000>; @@ -790,8 +788,12 @@ compatible = "ti,am654-navss-main-udmap"; reg = <0x0 0x31150000 0x0 0x100>, <0x0 0x34000000 0x0 0x100000>, - <0x0 0x35000000 0x0 0x100000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x35000000 0x0 0x100000>, + <0x0 0x30b00000 0x0 0x10000>, + <0x0 0x30c00000 0x0 0x10000>, + <0x0 0x30d00000 0x0 0x8000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&inta_main_udmass>; #dma-cells = <1>; @@ -880,20 +882,6 @@ status = "disabled"; }; - pcie0_ep: pcie-ep@5500000 { - compatible = "ti,am654-pcie-ep"; - reg = <0x0 0x5500000 0x0 0x1000>, <0x0 0x5501000 0x0 0x1000>, <0x0 0x10000000 0x0 0x8000000>, <0x0 0x5506000 0x0 0x1000>; - reg-names = "app", "dbics", "addr_space", "atu"; - power-domains = <&k3_pds 120 TI_SCI_PD_EXCLUSIVE>; - ti,syscon-pcie-mode = <&scm_conf 0x4060>; - num-ib-windows = <16>; - num-ob-windows = <16>; - max-link-speed = <2>; - dma-coherent; - interrupts = ; - status = "disabled"; - }; - pcie1_rc: pcie@5600000 { compatible = "ti,am654-pcie-rc"; reg = <0x0 0x5600000 0x0 0x1000>, <0x0 0x5601000 0x0 0x1000>, <0x0 0x18000000 0x0 0x2000>, <0x0 0x5606000 0x0 0x1000>; @@ -915,20 +903,6 @@ status = "disabled"; }; - pcie1_ep: pcie-ep@5600000 { - compatible = "ti,am654-pcie-ep"; - reg = <0x0 0x5600000 0x0 0x1000>, <0x0 0x5601000 0x0 0x1000>, <0x0 0x18000000 0x0 0x4000000>, <0x0 0x5606000 0x0 0x1000>; - reg-names = "app", "dbics", "addr_space", "atu"; - power-domains = <&k3_pds 121 TI_SCI_PD_EXCLUSIVE>; - ti,syscon-pcie-mode = <&scm_conf 0x4070>; - num-ib-windows = <16>; - num-ob-windows = <16>; - max-link-speed = <2>; - dma-coherent; - interrupts = ; - status = "disabled"; - }; - mcasp0: mcasp@2b00000 { compatible = "ti,am33xx-mcasp-audio"; reg = <0x0 0x02b00000 0x0 0x2000>, @@ -1045,6 +1019,13 @@ }; }; + gpu: gpu@7000000 { + compatible = "ti,am6548-gpu", "img,powervr-sgx544"; + reg = <0x0 0x7000000 0x0 0x10000>; + interrupts = ; + power-domains = <&k3_pds 65 TI_SCI_PD_EXCLUSIVE>; + }; + ehrpwm0: pwm@3000000 { compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; #pwm-cells = <3>; @@ -1105,6 +1086,17 @@ status = "disabled"; }; + timesync_router: pinctrl@a40000 { + compatible = "pinctrl-single"; + reg = <0x0 0xa40000 0x0 0x800>; + #address-cells = <1>; + #size-cells = <0>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x800007ff>; + status = "disabled"; + }; + icssg0: icssg@b000000 { compatible = "ti,am654-icssg"; reg = <0x00 0xb000000 0x00 0x80000>; @@ -1152,6 +1144,18 @@ }; }; + icssg0_iep0: iep@2e000 { + compatible = "ti,am654-icss-iep"; + reg = <0x2e000 0x1000>; + clocks = <&icssg0_iepclk_mux>; + }; + + icssg0_iep1: iep@2f000 { + compatible = "ti,am654-icss-iep"; + reg = <0x2f000 0x1000>; + clocks = <&icssg0_iepclk_mux>; + }; + icssg0_mii_rt: mii-rt@32000 { compatible = "ti,pruss-mii", "syscon"; reg = <0x32000 0x100>; @@ -1162,6 +1166,11 @@ reg = <0x33000 0x1000>; }; + icssg0_pa_stats: pa-stats@2c000 { + compatible = "ti,pruss-pa-st", "syscon"; + reg = <0x2c000 0x1000>; + }; + icssg0_intc: interrupt-controller@20000 { compatible = "ti,icssg-intc"; reg = <0x20000 0x2000>; @@ -1188,6 +1197,9 @@ <0x22400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-pru0_0-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <16 2 2>; + interrupt-names = "vring"; }; rtu0_0: rtu@4000 { @@ -1197,6 +1209,9 @@ <0x23400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-rtu0_0-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <20 4 4>; + interrupt-names = "vring"; }; tx_pru0_0: txpru@a000 { @@ -1215,6 +1230,9 @@ <0x24400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-pru0_1-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <18 3 3>; + interrupt-names = "vring"; }; rtu0_1: rtu@6000 { @@ -1224,6 +1242,9 @@ <0x23c00 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-rtu0_1-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <22 5 5>; + interrupt-names = "vring"; }; tx_pru0_1: txpru@c000 { @@ -1294,6 +1315,18 @@ }; }; + icssg1_iep0: iep@2e000 { + compatible = "ti,am654-icss-iep"; + reg = <0x2e000 0x1000>; + clocks = <&icssg1_iepclk_mux>; + }; + + icssg1_iep1: iep@2f000 { + compatible = "ti,am654-icss-iep"; + reg = <0x2f000 0x1000>; + clocks = <&icssg1_iepclk_mux>; + }; + icssg1_mii_rt: mii-rt@32000 { compatible = "ti,pruss-mii", "syscon"; reg = <0x32000 0x100>; @@ -1304,6 +1337,11 @@ reg = <0x33000 0x1000>; }; + icssg1_pa_stats: pa-stats@2c000 { + compatible = "ti,pruss-pa-st", "syscon"; + reg = <0x2c000 0x1000>; + }; + icssg1_intc: interrupt-controller@20000 { compatible = "ti,icssg-intc"; reg = <0x20000 0x2000>; @@ -1330,6 +1368,9 @@ <0x22400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-pru1_0-fw"; + interrupt-parent = <&icssg1_intc>; + interrupts = <16 2 2>; + interrupt-names = "vring"; }; rtu1_0: rtu@4000 { @@ -1339,6 +1380,9 @@ <0x23400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-rtu1_0-fw"; + interrupt-parent = <&icssg1_intc>; + interrupts = <20 4 4>; + interrupt-names = "vring"; }; tx_pru1_0: txpru@a000 { @@ -1357,6 +1401,9 @@ <0x24400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-pru1_1-fw"; + interrupt-parent = <&icssg1_intc>; + interrupts = <18 3 3>; + interrupt-names = "vring"; }; rtu1_1: rtu@6000 { @@ -1366,6 +1413,9 @@ <0x23c00 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-rtu1_1-fw"; + interrupt-parent = <&icssg1_intc>; + interrupts = <22 5 5>; + interrupt-names = "vring"; }; tx_pru1_1: txpru@c000 { @@ -1436,6 +1486,18 @@ }; }; + icssg2_iep0: iep@2e000 { + compatible = "ti,am654-icss-iep"; + reg = <0x2e000 0x1000>; + clocks = <&icssg2_iepclk_mux>; + }; + + icssg2_iep1: iep@2f000 { + compatible = "ti,am654-icss-iep"; + reg = <0x2f000 0x1000>; + clocks = <&icssg2_iepclk_mux>; + }; + icssg2_mii_rt: mii-rt@32000 { compatible = "ti,pruss-mii", "syscon"; reg = <0x32000 0x100>; @@ -1446,6 +1508,11 @@ reg = <0x33000 0x1000>; }; + icssg2_pa_stats: pa-stats@2c000 { + compatible = "ti,pruss-pa-st", "syscon"; + reg = <0x2c000 0x1000>; + }; + icssg2_intc: interrupt-controller@20000 { compatible = "ti,icssg-intc"; reg = <0x20000 0x2000>; @@ -1472,6 +1539,9 @@ <0x22400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-pru2_0-fw"; + interrupt-parent = <&icssg2_intc>; + interrupts = <16 2 2>; + interrupt-names = "vring"; }; rtu2_0: rtu@4000 { @@ -1481,6 +1551,9 @@ <0x23400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-rtu2_0-fw"; + interrupt-parent = <&icssg2_intc>; + interrupts = <20 4 4>; + interrupt-names = "vring"; }; tx_pru2_0: txpru@a000 { @@ -1499,6 +1572,9 @@ <0x24400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-pru2_1-fw"; + interrupt-parent = <&icssg2_intc>; + interrupts = <18 3 3>; + interrupt-names = "vring"; }; rtu2_1: rtu@6000 { @@ -1508,6 +1584,9 @@ <0x23c00 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-rtu2_1-fw"; + interrupt-parent = <&icssg2_intc>; + interrupts = <22 5 5>; + interrupt-names = "vring"; }; tx_pru2_1: txpru@c000 { diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi --- a/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -185,7 +185,7 @@ }; mcu_navss: bus@28380000 { - compatible = "simple-mfd"; + compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>; @@ -214,8 +214,12 @@ compatible = "ti,am654-navss-mcu-udmap"; reg = <0x0 0x285c0000 0x0 0x100>, <0x0 0x2a800000 0x0 0x40000>, - <0x0 0x2aa00000 0x0 0x40000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x2aa00000 0x0 0x40000>, + <0x0 0x284a0000 0x0 0x4000>, + <0x0 0x284c0000 0x0 0x4000>, + <0x0 0x28400000 0x0 0x2000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&inta_main_udmass>; #dma-cells = <1>; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi --- a/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -34,9 +34,16 @@ }; }; - chipid@43000014 { - compatible = "ti,am654-chipid"; - reg = <0x43000014 0x4>; + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x43000000 0x20000>; + + chipid: chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; wkup_pmx0: pinctrl@4301c000 { diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai.dts b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai.dts --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai.dts 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai.dts 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,1281 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * https://beagley-ai.org/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2024 Robert Nelson, BeagleBoard.org Foundation + */ + +/dts-v1/; + +#include +#include +#include "k3-j722s.dtsi" +#include "k3-serdes.h" +#include +#include +#include +#include "k3-am67a-beagley-ai-pinmux.dtsi" + +/ { + compatible = "beagle,am67a-beagley-ai", "ti,j722s"; + model = "BeagleBoard.org BeagleY-AI"; + + aliases { + serial0 = &wkup_uart0; + serial2 = &main_uart0; + serial3 = &main_uart1; + serial6 = &main_uart6; + mmc1 = &sdhci1; + mmc2 = &sdhci2; + rtc0 = &rtc; + spi0 = &spi_gpio; + usb0 = &usb0; + usb1 = &usb1; + i2c1 = &mcu_i2c0; + }; + + chosen { + stdout-path = &main_uart0; + base_dtb = "k3-am67a-beagley-ai.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; + + memory@80000000 { + /* 4G RAM */ + reg = <0x00000000 0x80000000 0x00000000 0x80000000>, + <0x00000008 0x80000000 0x00000000 0x80000000>; + device_type = "memory"; + bootph-pre-ram; + }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* global cma region */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x00 0x38000000>; + linux,cma-default; + }; + + secure_tfa_ddr: tfa@9e780000 { + reg = <0x00 0x9e780000 0x00 0x80000>; + no-map; + }; + + secure_ddr: optee@9e800000 { + reg = <0x00 0x9e800000 0x00 0x01800000>; + no-map; + }; + + wkup_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0000000 0x00 0x100000>; + no-map; + }; + + wkup_r5fss0_core0_memory_region: r5f-memory@a0100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0100000 0x00 0xf00000>; + no-map; + }; + + mcu_r5fss0_core0_dma_memory_region: mcu-r5fss-dma-memory-region@a1000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1000000 0x00 0x100000>; + no-map; + }; + + mcu_r5fss0_core0_memory_region: mcu-r5fss-memory-region@a1100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core0_dma_memory_region: main-r5fss-dma-memory-region@a2000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core0_memory_region: main-r5fss-memory-region@a2100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2100000 0x00 0xf00000>; + no-map; + }; + + c7x_0_dma_memory_region: c7x-dma-memory@a3000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3000000 0x00 0x100000>; + no-map; + }; + + c7x_0_memory_region: c7x-memory@a3100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3100000 0x00 0xf00000>; + no-map; + }; + + c7x_1_dma_memory_region: c7x-dma-memory@a4000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4000000 0x00 0x100000>; + no-map; + }; + + c7x_1_memory_region: c7x-memory@a4100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4100000 0x00 0xf00000>; + no-map; + }; + + rtos_ipc_memory_region: ipc-memories@a5000000 { + reg = <0x00 0xa5000000 0x00 0x1c00000>; + alignment = <0x1000>; + no-map; + }; + }; + + vsys_5v0: regulator-1 { + compatible = "regulator-fixed"; + regulator-name = "vsys_5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + bootph-all; + }; + + vdd_3v3: regulator-2 { + compatible = "regulator-fixed"; + regulator-name = "vdd_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vsys_5v0>; + regulator-always-on; + regulator-boot-on; + }; + + wlan_en: regulator-3 { + compatible = "regulator-fixed"; + regulator-name = "wlan_en"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + enable-active-high; + /* regulator-always-on; */ + regulator-off-in-suspend; + vin-supply = <&vdd_3v3>; + gpio = <&main_gpio0 4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_en_pins_default>; + }; + + vdd_mmc1: regulator-mmc1 { + compatible = "regulator-fixed"; + regulator-name = "vdd_mmc1"; + pinctrl-names = "default"; + pinctrl-0 = <&vdd_3v3_sd_pins_default>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + enable-active-high; + gpio = <&main_gpio1 50 GPIO_ACTIVE_HIGH>; + bootph-all; + }; + + vdd_sd_dv: regulator-TLV71033 { + compatible = "regulator-gpio"; + regulator-name = "tlv71033"; + pinctrl-names = "default"; + pinctrl-0 = <&vdd_sd_dv_pins_default>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + vin-supply = <&vsys_5v0>; + gpios = <&main_gpio1 49 GPIO_ACTIVE_HIGH>; + states = <1800000 0x0>, + <3300000 0x1>; + }; + + vsys_io_1v8: regulator-vsys-io-1v8 { + compatible = "regulator-fixed"; + regulator-name = "vsys_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + vsys_io_1v2: regulator-vsys-io-1v2 { + compatible = "regulator-fixed"; + regulator-name = "vsys_io_1v2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins_default>; + + led-0 { + // red PWR + label = "PWR"; + gpios = <&main_gpio0 11 GPIO_ACTIVE_LOW>; + linux,default-trigger = "default-off"; + default-state = "off"; + }; + + led-1 { + // Green ACT + label = "ACT"; + gpios = <&main_gpio0 12 GPIO_ACTIVE_HIGH>; + function = LED_FUNCTION_HEARTBEAT; + linux,default-trigger = "heartbeat"; + default-state = "on"; + }; + }; + + hdmi0: connector-hdmi { + compatible = "hdmi-connector"; + label = "hdmi"; + type = "d"; + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&it66122_out>; + }; + }; + }; + + sound0: sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "it66122 HDMI"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&hdmi_dailink_master>; + simple-audio-card,frame-master = <&hdmi_dailink_master>; + + hdmi_dailink_master: simple-audio-card,cpu { + sound-dai = <&mcasp1>; + system-clock-direction-out; + }; + + simple-audio-card,codec { + sound-dai = <&it66122>; + }; + }; + + fan: cooling_fan { + compatible = "pwm-fan"; + pinctrl-names = "default"; + pinctrl-0 = <&pwm_fan_pins>; + fan-supply = <&vsys_5v0>; + #cooling-cells = <2>; + cooling-min-state = <0>; + cooling-max-state = <3>; + cooling-levels = <0 75 125 175 250>; + pwms = <&epwm2 0 40000 0>; + pulses-per-revolution = <2>; + interrupt-parent = <&main_gpio1>; + interrupts = <22 IRQ_TYPE_EDGE_FALLING>; + status = "okay"; + }; + + mipi_switch: mipi-switch { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&mipi_switch_pins>; + + oe-pin { + label = "MIPI_SWITCH_OE"; + gpios = <&main_gpio0 1 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + sel-pin { + label = "MIPI_SWITCH_SEL"; + gpios = <&main_gpio0 2 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; + + spi_gpio: spi { + compatible = "spi-gpio"; + #address-cells = <0x1>; + #size-cells = <0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&spi_gpio_default_pins>; + + sck-gpios = <&mcu_gpio0 2 GPIO_ACTIVE_HIGH>; + miso-gpios = <&mcu_gpio0 4 GPIO_ACTIVE_HIGH>; + mosi-gpios = <&mcu_gpio0 3 GPIO_ACTIVE_HIGH>; + + num-chipselects = <2>; + cs-gpios = < + &mcu_gpio0 0 GPIO_ACTIVE_HIGH + &mcu_gpio0 9 GPIO_ACTIVE_HIGH + >; + status = "disabled"; + }; +}; + +&main_pmx0 { + bootph-all; + + /delete-property/ interrupts; + main_i2c0_pins_default: main-i2c0-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x01e0, PIN_INPUT_PULLUP, 0) /* (D23) I2C0_SCL */ + J722S_IOPAD(0x01e4, PIN_INPUT_PULLUP, 0) /* (B22) I2C0_SDA */ + >; + bootph-all; + }; + + main_uart0_pins_default: main-uart0-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x01c8, PIN_INPUT, 0) /* (A22) UART0_RXD */ + J722S_IOPAD(0x01cc, PIN_OUTPUT, 0) /* (B22) UART0_TXD */ + >; + bootph-all; + }; + + main_uart1_pins_default: main-uart1-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x01ac, PIN_INPUT, 2) /* (C27) MCASP0_AFSR.UART1_RXD */ + J722S_IOPAD(0x01b0, PIN_OUTPUT, 2) /* (F24) MCASP0_ACLKR.UART1_TXD */ + >; + bootph-all; + }; + + vdd_sd_dv_pins_default: vdd-sd-dv-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0244, PIN_OUTPUT, 7) /* (A24) MMC1_SDWP.GPIO1_49 */ + >; + bootph-all; + }; + + main_mmc1_pins_default: main-mmc1-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x023c, PIN_INPUT, 0) /* (H22) MMC1_CMD */ + J722S_IOPAD(0x0234, PIN_OUTPUT, 0) /* (H24) MMC1_CLK */ + J722S_IOPAD(0x0230, PIN_INPUT, 0) /* (H23) MMC1_DAT0 */ + J722S_IOPAD(0x022c, PIN_INPUT_PULLUP, 0) /* (H20) MMC1_DAT1 */ + J722S_IOPAD(0x0228, PIN_INPUT_PULLUP, 0) /* (J23) MMC1_DAT2 */ + J722S_IOPAD(0x0224, PIN_INPUT_PULLUP, 0) /* (H25) MMC1_DAT3 */ + J722S_IOPAD(0x0240, PIN_INPUT, 7) /* (B24) MMC1_SDCD.GPIO1_48 */ + >; + bootph-all; + }; + + ospi0_pins_default: ospi0-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0000, PIN_OUTPUT, 0) /* (P23) OSPI0_CLK */ + J722S_IOPAD(0x002c, PIN_OUTPUT, 0) /* (M25) OSPI0_CSn0 */ + J722S_IOPAD(0x000c, PIN_INPUT, 0) /* (L25) OSPI0_D0 */ + J722S_IOPAD(0x0010, PIN_INPUT, 0) /* (N24) OSPI0_D1 */ + J722S_IOPAD(0x0014, PIN_INPUT, 0) /* (N25) OSPI0_D2 */ + J722S_IOPAD(0x0018, PIN_INPUT, 0) /* (M24) OSPI0_D3 */ + J722S_IOPAD(0x001c, PIN_INPUT, 0) /* (N21) OSPI0_D4 */ + J722S_IOPAD(0x0020, PIN_INPUT, 0) /* (N22) OSPI0_D5 */ + J722S_IOPAD(0x0024, PIN_INPUT, 0) /* (P21) OSPI0_D6 */ + J722S_IOPAD(0x0028, PIN_INPUT, 0) /* (N20) OSPI0_D7 */ + J722S_IOPAD(0x0008, PIN_INPUT, 0) /* (P22) OSPI0_DQS */ + >; + bootph-all; + }; + + main_i2c1_pins_default: main-i2c1-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x01e8, PIN_INPUT_PULLUP, 0) /* (C24) I2C1_SCL */ + J722S_IOPAD(0x01ec, PIN_INPUT_PULLUP, 0) /* (A22) I2C1_SDA */ + >; + bootph-all; + }; + + main_i2c2_pins_default: main-i2c2-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x00b0, PIN_INPUT_PULLUP, 1) /* (T22) GPMC0_CSn2.I2C2_SCL */ + J722S_IOPAD(0x00b4, PIN_INPUT_PULLUP, 1) /* (U25) GPMC0_CSn3.I2C2_SDA */ + >; + }; + + main_dpi_pins_default: main-dpi-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0100, PIN_OUTPUT, 0) /* (AB23) VOUT0_VSYNC */ + J722S_IOPAD(0x00f8, PIN_OUTPUT, 0) /* (AB24) VOUT0_HSYNC */ + J722S_IOPAD(0x0104, PIN_OUTPUT, 0) /* (AC26) VOUT0_PCLK */ + J722S_IOPAD(0x00fc, PIN_OUTPUT, 0) /* (AC27) VOUT0_DE */ + J722S_IOPAD(0x00b8, PIN_OUTPUT, 0) /* (W27) VOUT0_DATA0 */ + J722S_IOPAD(0x00bc, PIN_OUTPUT, 0) /* (W25) VOUT0_DATA1 */ + J722S_IOPAD(0x00c0, PIN_OUTPUT, 0) /* (W24) VOUT0_DATA2 */ + J722S_IOPAD(0x00c4, PIN_OUTPUT, 0) /* (W23) VOUT0_DATA3 */ + J722S_IOPAD(0x00c8, PIN_OUTPUT, 0) /* (W22) VOUT0_DATA4 */ + J722S_IOPAD(0x00cc, PIN_OUTPUT, 0) /* (W21) VOUT0_DATA5 */ + J722S_IOPAD(0x00d0, PIN_OUTPUT, 0) /* (Y26) VOUT0_DATA6 */ + J722S_IOPAD(0x00d4, PIN_OUTPUT, 0) /* (Y27) VOUT0_DATA7 */ + J722S_IOPAD(0x00d8, PIN_OUTPUT, 0) /* (AA24) VOUT0_DATA8 */ + J722S_IOPAD(0x00dc, PIN_OUTPUT, 0) /* (AA27) VOUT0_DATA9 */ + J722S_IOPAD(0x00e0, PIN_OUTPUT, 0) /* (AA25) VOUT0_DATA10 */ + J722S_IOPAD(0x00e4, PIN_OUTPUT, 0) /* (AB25) VOUT0_DATA11 */ + J722S_IOPAD(0x00e8, PIN_OUTPUT, 0) /* (AA23) VOUT0_DATA12 */ + J722S_IOPAD(0x00ec, PIN_OUTPUT, 0) /* (AA22) VOUT0_DATA13 */ + J722S_IOPAD(0x00f0, PIN_OUTPUT, 0) /* (AB26) VOUT0_DATA14 */ + J722S_IOPAD(0x00f4, PIN_OUTPUT, 0) /* (AB27) VOUT0_DATA15 */ + J722S_IOPAD(0x005c, PIN_OUTPUT, 1) /* (AC25) GPMC0_AD8.VOUT0_DATA16 */ + J722S_IOPAD(0x0060, PIN_OUTPUT, 1) /* (U26) GPMC0_AD9.VOUT0_DATA17 */ + J722S_IOPAD(0x0064, PIN_OUTPUT, 1) /* (V27) GPMC0_AD10.VOUT0_DATA18 */ + J722S_IOPAD(0x0068, PIN_OUTPUT, 1) /* (V25) GPMC0_AD11.VOUT0_DATA19 */ + J722S_IOPAD(0x006c, PIN_OUTPUT, 1) /* (V26) GPMC0_AD12.VOUT0_DATA20 */ + J722S_IOPAD(0x0070, PIN_OUTPUT, 1) /* (V24) GPMC0_AD13.VOUT0_DATA21 */ + J722S_IOPAD(0x0074, PIN_OUTPUT, 1) /* (V22) GPMC0_AD14.VOUT0_DATA22 */ + J722S_IOPAD(0x0078, PIN_OUTPUT, 1) /* (V23) GPMC0_AD15.VOUT0_DATA23 */ + >; + }; + + main_gpio0_ioexp_intr_pins_default: main-gpio0-ioexp-intr-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0110, PIN_INPUT, 7) /* (G27) MMC2_DAT1.GPIO0_67 */ + >; + }; + + mdio_pins_default: mdio-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0160, PIN_OUTPUT, 0) /* (AC24) MDIO0_MDC */ + J722S_IOPAD(0x015c, PIN_INPUT, 0) /* (AD25) MDIO0_MDIO */ + >; + }; + + rgmii1_pins_default: rgmii1-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x014c, PIN_INPUT, 0) /* (AC25) RGMII1_RD0 */ + J722S_IOPAD(0x0150, PIN_INPUT, 0) /* (AD27) RGMII1_RD1 */ + J722S_IOPAD(0x0154, PIN_INPUT, 0) /* (AE24) RGMII1_RD2 */ + J722S_IOPAD(0x0158, PIN_INPUT, 0) /* (AE26) RGMII1_RD3 */ + J722S_IOPAD(0x0148, PIN_INPUT, 0) /* (AE27) RGMII1_RXC */ + J722S_IOPAD(0x0144, PIN_INPUT, 0) /* (AD23) RGMII1_RX_CTL */ + J722S_IOPAD(0x0134, PIN_OUTPUT, 0) /* (AF27) RGMII1_TD0 */ + J722S_IOPAD(0x0138, PIN_OUTPUT, 0) /* (AE23) RGMII1_TD1 */ + J722S_IOPAD(0x013c, PIN_OUTPUT, 0) /* (AG25) RGMII1_TD2 */ + J722S_IOPAD(0x0140, PIN_OUTPUT, 0) /* (AF24) RGMII1_TD3 */ + J722S_IOPAD(0x0130, PIN_OUTPUT, 0) /* (AG26) RGMII1_TXC */ + J722S_IOPAD(0x012c, PIN_OUTPUT, 0) /* (AF25) RGMII1_TX_CTL */ + >; + }; + + led_pins_default: led-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x002c, PIN_OUTPUT, 7) /* (K26) OSPI0_CSn0.GPIO0_11 */ + J722S_IOPAD(0x0030, PIN_OUTPUT, 7) /* (K23) OSPI0_CSn1.GPIO0_12 */ + >; + }; + + vdd_3v3_sd_pins_default: vdd-3v3-sd-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0254, PIN_OUTPUT, 7) /* (E25) USB0_DRVVBUS.GPIO1_50 */ + >; + }; + + main_usb1_pins_default: main-usb1-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0258, PIN_INPUT, 0) /* (B27) USB1_DRVVBUS */ + >; + }; + + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x01f4, PIN_INPUT_PULLUP, 0) /* (B23) EXTINTn */ + >; + }; + + wifi_pins_default: wifi-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0120, PIN_INPUT, 0) /* (F27) MMC2_CMD */ + J722S_IOPAD(0x0118, PIN_OUTPUT, 0) /* (H26) MMC2_CLK */ + J722S_IOPAD(0x011C, PIN_INPUT, 0) /* () MMC2_CLKLB */ + J722S_IOPAD(0x0114, PIN_INPUT, 0) /* (G26) MMC2_DAT0 */ + J722S_IOPAD(0x0110, PIN_INPUT_PULLUP, 0) /* (G27) MMC2_DAT1 */ + J722S_IOPAD(0x010c, PIN_INPUT_PULLUP, 0) /* (H27) MMC2_DAT2 */ + J722S_IOPAD(0x0108, PIN_INPUT_PULLUP, 0) /* (J27) MMC2_DAT3 */ + >; + }; + + wifi_en_pins_default: wifi-en-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0010, PIN_OUTPUT, 7) /* (L27) OSPI0_D1.GPIO0_4 */ + >; + }; + + wifi_wlirq_pins_default: wifi-wlirq-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0014, PIN_INPUT, 7) /* (L26) OSPI0_D2.GPIO0_5 */ + >; + }; + + pwm_fan_pins: pwm-fan-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0124, PIN_OUTPUT, 4) /* (F26) MMC2_SDCD.EHRPWM2_A FAN_PWM */ + J722S_IOPAD(0x01d0, PIN_INPUT, 7) /* (E22) UART0_CTSn.GPIO1_22 FAN_TACH */ + >; + }; + + dss0_pins_default: dss0-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0100, PIN_OUTPUT, 0) /* (AB23) VOUT0_VSYNC */ + J722S_IOPAD(0x00f8, PIN_OUTPUT, 0) /* (AB24) VOUT0_HSYNC */ + J722S_IOPAD(0x0104, PIN_OUTPUT, 0) /* (AC26) VOUT0_PCLK */ + J722S_IOPAD(0x00fc, PIN_OUTPUT, 0) /* (AC27) VOUT0_DE */ + J722S_IOPAD(0x00b8, PIN_OUTPUT, 0) /* (W27) VOUT0_DATA0 */ + J722S_IOPAD(0x00bc, PIN_OUTPUT, 0) /* (W25) VOUT0_DATA1 */ + J722S_IOPAD(0x00c0, PIN_OUTPUT, 0) /* (W24) VOUT0_DATA2 */ + J722S_IOPAD(0x00c4, PIN_OUTPUT, 0) /* (W23) VOUT0_DATA3 */ + J722S_IOPAD(0x00c8, PIN_OUTPUT, 0) /* (W22) VOUT0_DATA4 */ + J722S_IOPAD(0x00cc, PIN_OUTPUT, 0) /* (W21) VOUT0_DATA5 */ + J722S_IOPAD(0x00d0, PIN_OUTPUT, 0) /* (Y26) VOUT0_DATA6 */ + J722S_IOPAD(0x00d4, PIN_OUTPUT, 0) /* (Y27) VOUT0_DATA7 */ + J722S_IOPAD(0x00d8, PIN_OUTPUT, 0) /* (AA24) VOUT0_DATA8 */ + J722S_IOPAD(0x00dc, PIN_OUTPUT, 0) /* (AA27) VOUT0_DATA9 */ + J722S_IOPAD(0x00e0, PIN_OUTPUT, 0) /* (AA25) VOUT0_DATA10 */ + J722S_IOPAD(0x00e4, PIN_OUTPUT, 0) /* (AB25) VOUT0_DATA11 */ + J722S_IOPAD(0x00e8, PIN_OUTPUT, 0) /* (AA23) VOUT0_DATA12 */ + J722S_IOPAD(0x00ec, PIN_OUTPUT, 0) /* (AA22) VOUT0_DATA13 */ + J722S_IOPAD(0x00f0, PIN_OUTPUT, 0) /* (AB26) VOUT0_DATA14 */ + J722S_IOPAD(0x00f4, PIN_OUTPUT, 0) /* (AB27) VOUT0_DATA15 */ + J722S_IOPAD(0x005c, PIN_OUTPUT, 1) /* (U27) GPMC0_AD8.VOUT0_DATA16 */ + J722S_IOPAD(0x0060, PIN_OUTPUT, 1) /* (U26) GPMC0_AD9.VOUT0_DATA17 */ + J722S_IOPAD(0x0064, PIN_OUTPUT, 1) /* (V27) GPMC0_AD10.VOUT0_DATA18 */ + J722S_IOPAD(0x0068, PIN_OUTPUT, 1) /* (V25) GPMC0_AD11.VOUT0_DATA19 */ + J722S_IOPAD(0x006c, PIN_OUTPUT, 1) /* (V26) GPMC0_AD12.VOUT0_DATA20 */ + J722S_IOPAD(0x0070, PIN_OUTPUT, 1) /* (V24) GPMC0_AD13.VOUT0_DATA21 */ + J722S_IOPAD(0x0074, PIN_OUTPUT, 1) /* (V22) GPMC0_AD14.VOUT0_DATA22 */ + J722S_IOPAD(0x0078, PIN_OUTPUT, 1) /* (V23) GPMC0_AD15.VOUT0_DATA23 */ + >; + }; + + csi1_gpio_pins_default: csi1-gpio-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x01d8, PIN_OUTPUT, 7) /* (D22) MCAN0_TX.GPIO1_24 */ + >; + }; + + usb_hub: usb-hub-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0084, PIN_OUTPUT, 7) /* (N21) GPMC0_ADVn_ALE.GPIO0_32 */ + >; + }; + + mipi_switch_pins: mipi-switch-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0004, PIN_OUTPUT, 7) /* (L23) OSPI0_LBCLKO.GPIO0_1 */ + J722S_IOPAD(0x0008, PIN_OUTPUT, 7) /* (L22) OSPI0_DQS.GPIO0_2 */ + >; + }; + + main_uart6_pins_default: main-uart6-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0028, PIN_INPUT, 3) /* (M27) OSPI0_D7.UART6_CTSn */ + J722S_IOPAD(0x0024, PIN_OUTPUT, 3) /* (N27) OSPI0_D6.UART6_RTSn */ + J722S_IOPAD(0x001c, PIN_INPUT, 3) /* (L21) OSPI0_D4.UART6_RXD */ + J722S_IOPAD(0x0020, PIN_OUTPUT, 3) /* (M26) OSPI0_D5.UART6_TXD */ + >; + }; + + main_oldi_backlight_default_pins: main-backlight-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x01f0, PIN_OUTPUT, 8) /* (A23) EXT_REFCLK1.ECAP0_IN_APWM_OUT */ + >; + }; + + main_oldi_touchscreen_default_pins: main-touchscreen-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0038, PIN_INPUT, 7) /* (J22) OSPI0_CSn3.GPIO0_14 */ + >; + }; + + main_mcasp1_pins_default: main-mcasp1-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0090, PIN_INPUT, 2) /* (P27) GPMC0_BE0n_CLE.MCASP1_ACLKX */ + J722S_IOPAD(0x0098, PIN_INPUT, 2) /* (V21) GPMC0_WAIT0.MCASP1_AFSX */ + J722S_IOPAD(0x008c, PIN_INPUT, 2) /* (N23) GPMC0_WEn.MCASP1_AXR0 */ + >; + }; +}; + +&cpsw3g { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii1_pins_default>, <&gbe_pmx_obsclk>; + + assigned-clocks = <&k3_clks 227 0>; + assigned-clock-parents = <&k3_clks 227 6>; +}; + +&cpsw3g_mdio { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mdio_pins_default>; + + cpsw3g_phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + ti,min-output-impedance; + }; +}; + +&cpsw_port1 { + phy-mode = "rgmii-rxid"; + phy-handle = <&cpsw3g_phy0>; +}; + +&cpsw_port2 { + status = "disabled"; +}; + +&epwm2 { + status = "okay"; +}; + +&main_gpio0 { + status = "okay"; + pinctrl-names = "default"; + gpio-line-names = "", "", "", "", "", /* 0-4 */ + "", "", "", "", "", /* 5-9 */ + "", "", "", "", "", /* 10-14 */ + "", "", "", "", "", /* 15-19 */ + "", "", "", "", "", /* 20-24 */ + "", "", "", "", "", /* 25-29 */ + "", "", "USB_RST", "GPIO27", "", /* 30-34 */ + "", "GPIO26", "", "GPIO4", "", /* 35-39 */ + "", "GPIO22", "GPIO25", "", ""; /* 40-44 */ +}; + +&main_gpio1 { + status = "okay"; + pinctrl-names = "default"; + gpio-line-names = "", "", "", "", "", /* 0-4 */ + "", "", "GPIO16", "GPIO17", "GPIO21", /* 5-9 */ + "GPIO20", "GPIO18", "GPIO19", "GPIO15", "GPIO14", /* 10-14 */ + "GPIO5", "GPIO12", "GPIO6", "GPIO13", ""; /* 15-19 */ +}; + +&mcu_gpio0 { + status = "okay"; + pinctrl-names = "default"; + gpio-line-names = "GPIO8", "", "GPIO11", "GPIO10", "GPIO9", /* 0-4 */ + "", "", "GPIO23", "", "GPIO7", /* 5-9 */ + "GPIO24", "", "", "HDMI_RSTn", "HDMI_INTn", /* 10-14 */ + "", "", "GPIO3", "GPIO2", ""; /* 15-19 */ +}; + +&main_uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_uart0_pins_default>; + status = "okay"; + bootph-all; +}; + +&main_uart1 { + symlink = "ttyAMA0"; + //pinctrl-names = "default"; + //pinctrl-0 = <&main_uart1_pins_default>; + status = "okay"; + bootph-all; +}; + +&main_uart6 { + symlink = "board/bluetooth/uart"; + pinctrl-names = "default"; + pinctrl-0 = <&main_uart6_pins_default>; + status = "okay"; + bootph-all; + + bluetooth { + compatible = "ti,cc33xx-bt"; + cc33xx-supply = <&wlan_en>; + max-speed = <115200>; + }; +}; + +&main0_thermal { + trips { + main0_active0: trip-active0 { + temperature = <40000>; + hysteresis = <5000>; + type = "active"; + }; + + main0_active1: trip-active1 { + temperature = <48000>; + hysteresis = <3000>; + type = "active"; + }; + + main0_active2: trip-active2 { + temperature = <60000>; + hysteresis = <10000>; + type = "active"; + }; + }; + + cooling-maps { + map1 { + trip = <&main0_active0>; + cooling-device = <&fan 1 1>; + }; + + map2 { + trip = <&main0_active1>; + cooling-device = <&fan 2 2>; + }; + + map3 { + trip = <&main0_active2>; + cooling-device = <&fan 3 3>; + }; + }; +}; + +&mcu_pmx0 { + bootph-all; + + wkup_uart0_pins_default: wkup-uart0-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x02c, PIN_INPUT, 0) /* (C7) WKUP_UART0_CTSn */ + J722S_MCU_IOPAD(0x030, PIN_OUTPUT, 0) /* (C6) WKUP_UART0_RTSn */ + J722S_MCU_IOPAD(0x024, PIN_INPUT, 0) /* (D8) WKUP_UART0_RXD */ + J722S_MCU_IOPAD(0x028, PIN_OUTPUT, 0) /* (D7) WKUP_UART0_TXD */ + >; + bootph-all; + }; + + wkup_i2c0_pins_default: wkup-i2c0-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x04c, PIN_INPUT_PULLUP, 0) /* (C7) WKUP_I2C0_SCL */ + J722S_MCU_IOPAD(0x050, PIN_INPUT_PULLUP, 0) /* (C6) WKUP_I2C1_SDA */ + >; + bootph-all; + }; + + wifi_32k_clk: mcu-clk-out-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x0084, PIN_OUTPUT, 0) /* (F12) WKUP_CLKOUT0 */ + >; + }; + + hdmi_gpio_pins_default: hdmi-gpio-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x0038, PIN_INPUT_PULLUP | PIN_DEBOUNCE_CONF6, 7) /* (D8) MCU_MCAN0_RX.MCU_GPIO0_14 HDMI_INTn */ + J722S_MCU_IOPAD(0x0034, PIN_OUTPUT_PULLUP, 7) /* (B2) MCU_MCAN0_TX.MCU_GPIO0_13 HDMI_RSTn */ + >; + }; + + pcie_pins_default: pcie-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x0018, PIN_OUTPUT, 7) /* (B4) MCU_UART0_TXD.MCU_GPIO0_6 */ + J722S_MCU_IOPAD(0x0014, PIN_INPUT, 7) /* (B8) MCU_UART0_RXD.MCU_GPIO0_5 */ /* PCIE_DET_WAKE */ + J722S_MCU_IOPAD(0x0020, PIN_OUTPUT, 7) /* (C5) MCU_UART0_RTSn.MCU_GPIO0_8 */ /* PCIE_PWR_EN */ + >; + }; + + csi0_gpio_pins_default: csi0-gpio-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x003c, PIN_OUTPUT, 7) /* (C1) MCU_MCAN1_TX.MCU_GPIO0_15 */ + >; + }; + + mcu_i2c0_pins_default: mcu-i2c0-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x0044, PIN_INPUT_PULLUP, 0) /* (B13) MCU_I2C0_SCL */ + J722S_MCU_IOPAD(0x0048, PIN_INPUT_PULLUP, 0) /* (E11) MCU_I2C0_SDA */ + >; + bootph-all; + }; + + mcu_oldi_backlight_default_pins: mcu-backlight-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x002c, PIN_OUTPUT, 7) /* (C4) WKUP_UART0_CTSn.MCU_GPIO0_11 */ + >; + }; + + mcu_oldi_touchscreen_default_pins: mcu-touchscreen-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x0030, PIN_OUTPUT, 7) /* (C3) WKUP_UART0_RTSn.MCU_GPIO0_12 */ + >; + }; + + gbe_pmx_obsclk: gbe-pmx-obsclk-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x0004, PIN_OUTPUT, 1) /* (A10) MCU_SPI0_CS1.MCU_OBSCLK0 */ + >; + }; + + spi_gpio_default_pins: spi-gpio-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x000, PIN_OUTPUT, 7) /* (C12) MCU_SPI0_CS0.MCU_GPIO0_0 SS 0 */ + J722S_MCU_IOPAD(0x024, PIN_OUTPUT, 7) /* (B3) WKUP_UART0_RXD.MCU_GPIO0_9 SS 1 */ + J722S_MCU_IOPAD(0x008, PIN_OUTPUT, 7) /* (A9) MCU_SPI0_CLK.MCU_GPIO0_2 SCLK */ + J722S_MCU_IOPAD(0x010, PIN_INPUT, 7) /* (C11) MCU_SPI0_D1.MCU_GPIO0_4 MISO */ + J722S_MCU_IOPAD(0x00C, PIN_OUTPUT, 7) /* (B12) MCU_SPI0_D0.MCU_GPIO0_3 MOSI */ + >; + }; +}; + +&wkup_uart0 { + /* WKUP UART0 is used by Device Manager firmware */ + pinctrl-names = "default"; + pinctrl-0 = <&wkup_uart0_pins_default>; + status = "reserved"; + bootph-all; +}; + +&mcu_i2c0 { + symlink = "hat/mcu_i2c0"; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_i2c0_pins_default>; + clock-frequency = <100000>; + bootph-all; +}; + +&wkup_i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&wkup_i2c0_pins_default>; + symlink = "hat/wkup_i2c0"; + clock-frequency = <100000>; + status = "okay"; + bootph-all; + + tps65219: pmic@30 { + bootph-all; + compatible = "ti,tps65219"; + reg = <0x30>; + buck1-supply = <&vsys_5v0>; + buck2-supply = <&vsys_5v0>; + buck3-supply = <&vsys_5v0>; + ldo1-supply = <&vdd_3v3>; + ldo3-supply = <&vdd_3v3>; + ldo4-supply = <&vdd_3v3>; + + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&gic500>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + system-power-controller; + ti,power-button; + + regulators { + buck1_reg: buck1 { + regulator-name = "VDD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + buck2_reg: buck2 { + regulator-name = "VDD_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo1_reg: ldo1 { + regulator-name = "VDDSHV5_SDIO"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-allow-bypass; + regulator-boot-on; + regulator-always-on; + }; + + ldo2_reg: ldo2 { + regulator-name = "VDD_1V2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo3_reg: ldo3 { + regulator-name = "VDDA_PHY_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo4_reg: ldo4 { + regulator-name = "VDDA_PLL_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + eeprom@50 { + compatible = "atmel,24c32"; + reg = <0x50>; + }; + + rtc: rtc@68 { + compatible = "dallas,ds1340"; + reg = <0x68>; + }; +}; + +dsi0_csi1_i2c: &main_i2c0 { + symlink = "hat/dsi0_csi1_i2c"; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c0_pins_default>; + clock-frequency = <400000>; + bootph-all; +}; + +&main_i2c1 { + symlink = "hat/main_i2c1"; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_pins_default>; + clock-frequency = <100000>; + bootph-all; + + it66122: bridge-hdmi@4c { + compatible = "ite,it66122"; + reg = <0x4c>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_gpio_pins_default>; + vcn33-supply = <&vdd_3v3>; + vcn18-supply = <&buck2_reg>; + vrf12-supply = <&ldo2_reg>; + reset-gpios = <&mcu_gpio0 13 GPIO_ACTIVE_LOW>; + interrupt-parent = <&mcu_gpio0>; + interrupts = <14 IRQ_TYPE_EDGE_FALLING>; + #sound-dai-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* + * HDMI can be serviced with 3 potential VPs - + * (DSS0 VP1 / DSS1 VP0 / DSS1 VP1). + * For now, we will service it with DSS0 VP1. + */ + port@0 { + reg = <0>; + + it66122_in: endpoint { + bus-width = <24>; + remote-endpoint = <&dss1_dpi0_out>; + }; + }; + + port@1 { + reg = <1>; + + it66122_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; +}; + +csi0_i2c: &main_i2c2 { + symlink = "hat/csi0"; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c2_pins_default>; + clock-frequency = <400000>; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; +}; + +&sdhci0 { + /*eMMC*/ + status = "disabled"; +}; + +&sdhci1 { + /* SD/MMC */ + vmmc-supply = <&vdd_mmc1>; + vqmmc-supply = <&vdd_sd_dv>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mmc1_pins_default>; + disable-wp; + cd-gpios = <&main_gpio1 48 GPIO_ACTIVE_LOW>; + cd-debounce-delay-ms = <100>; + bootph-all; + ti,fails-without-test-cd; + status = "okay"; +}; + +&sdhci2 { + vmmc-supply = <&wlan_en>; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_pins_default>, <&wifi_32k_clk>; + bus-width = <4>; + non-removable; + ti,fails-without-test-cd; + cap-power-off-card; + keep-power-in-suspend; + ti,driver-strength-ohm = <50>; + assigned-clocks = <&k3_clks 157 174>; + assigned-clock-parents = <&k3_clks 157 175>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + wlcore: wlcore@2 { + compatible = "ti,cc33xx"; + reg = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_wlirq_pins_default>; + interrupt-parent = <&main_gpio0>; + interrupts = <5 IRQ_TYPE_EDGE_RISING>; + }; +}; + +&ospi0 { + status = "disabled"; +}; + +&dphy_tx0 { + status = "okay"; +}; + +&dsi0 { + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + + bridge@0 { + status = "disabled"; + }; +}; + +&mailbox0_cluster0 { + status = "okay"; + mbox_r5_0: mbox-r5-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + +&mailbox0_cluster1 { + status = "okay"; + mbox_mcu_r5_0: mbox-mcu-r5-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + +&mailbox0_cluster2 { + status = "okay"; + mbox_c7x_0: mbox-c7x-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + +&mailbox0_cluster3 { + status = "okay"; + mbox_main_r5_0: mbox-main-r5-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_c7x_1: mbox-c7x-1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&wkup_r5fss0 { + status = "okay"; +}; + +&wkup_r5fss0_core0 { + mboxes = <&mailbox0_cluster0 &mbox_r5_0>; + memory-region = <&wkup_r5fss0_core0_dma_memory_region>, + <&wkup_r5fss0_core0_memory_region>; +}; + +&mcu_r5fss0 { + status = "okay"; +}; + +&mcu_r5fss0_core0 { + mboxes = <&mailbox0_cluster1 &mbox_mcu_r5_0>; + memory-region = <&mcu_r5fss0_core0_dma_memory_region>, + <&mcu_r5fss0_core0_memory_region>; +}; + +&main_r5fss0 { + status = "okay"; +}; + +&main_r5fss0_core0 { + mboxes = <&mailbox0_cluster3 &mbox_main_r5_0>; + memory-region = <&main_r5fss0_core0_dma_memory_region>, + <&main_r5fss0_core0_memory_region>; +}; + +&c7x_0 { + status = "okay"; + mboxes = <&mailbox0_cluster2 &mbox_c7x_0>; + memory-region = <&c7x_0_dma_memory_region>, + <&c7x_0_memory_region>; +}; + +&c7x_1 { + status = "okay"; + mboxes = <&mailbox0_cluster3 &mbox_c7x_1>; + memory-region = <&c7x_1_dma_memory_region>, + <&c7x_1_memory_region>; +}; + +&serdes_ln_ctrl { + idle-states = , + ; +}; + +&serdes0 { + status = "okay"; + serdes0_usb_link: phy@0 { + reg = <0>; + cdns,num-lanes = <1>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 1>; + }; +}; + +&serdes1 { + serdes1_pcie_link: phy@0 { + reg = <0>; + cdns,num-lanes = <1>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz1 1>; + }; +}; + +&usbss0 { + ti,vbus-divider; + status = "okay"; +}; + +&usb0 { + dr_mode = "otg"; + usb-role-switch; +}; + +&usbss1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_usb1_pins_default>; + ti,vbus-divider; + status = "okay"; +}; + +&usb1 { + dr_mode = "host"; + maximum-speed = "super-speed"; + phys = <&serdes0_usb_link>; + phy-names = "cdns3,usb3-phy"; + + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_hub>; + status = "okay"; + + /* 2.0 hub on port 1 */ + hub_2_0: hub@1 { + compatible = "usb451,8142"; + reg = <1>; + peer-hub = <&hub_3_0>; + reset-gpios = <&main_gpio0 32 GPIO_ACTIVE_LOW>; + vdd-supply = <&vdd_3v3>; + }; + + /* 3.0 hub on port 2 */ + hub_3_0: hub@2 { + compatible = "usb451,8140"; + reg = <2>; + peer-hub = <&hub_2_0>; + reset-gpios = <&main_gpio0 32 GPIO_ACTIVE_LOW>; + vdd-supply = <&vdd_3v3>; + }; +}; + +&pcie0_rc { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pcie_pins_default>; + phys = <&serdes1_pcie_link>; + phy-names = "pcie-phy"; + num-lanes = <1>; + max-link-speed = <3>; + reset-gpios = <&mcu_gpio0 6 GPIO_ACTIVE_HIGH>; + enable-gpios = <&mcu_gpio0 8 GPIO_ACTIVE_HIGH>; /* Extra GPIO for pwr_en for BeagleY AI */ +}; + +&dss1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_dpi_pins_default>; + + assigned-clocks = <&k3_clks 241 0>, /* DSS1-VP0 */ + <&k3_clks 240 0>, /* DSS1-VP1 */ + <&k3_clks 245 0>; /* DPI Output */ + + assigned-clock-parents = <&k3_clks 241 2>, /* PLL 17 HDMI */ + <&k3_clks 240 1>, /* PLL 18 DSI */ + <&k3_clks 245 2>; /* DSS1-DPI0 */ +}; + +&dss1_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* DSS1-VP1: DPI/HDMI Output */ + port@0 { + reg = <0>; + + dss1_dpi0_out: endpoint { + remote-endpoint = <&it66122_in>; + }; + }; +}; + +&mcasp1 { + status = "okay"; + #sound-dai-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcasp1_pins_default>; + auxclk-fs-ratio = <2177>; + op-mode = <0>; /* MCASP_IIS_MODE */ + tdm-slots = <2>; + serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ + 1 0 0 0 + 0 0 0 0 + 0 0 0 0 + 0 0 0 0 + >; + tx-num-evt = <32>; + rx-num-evt = <32>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pinmux.dtsi b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pinmux.dtsi --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pinmux.dtsi 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pinmux.dtsi 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,1555 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * https://beagley-ai.org/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2024 Robert Nelson, BeagleBoard.org Foundation + */ + +#include + +/ { + hat-07-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_07_gpio>; + gpios = <&mcu_gpio0 38 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO4"; + beagle-gpio-pi = "GPIO4"; + }; + + hat-07-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_07_gpio_pu>; + gpios = <&mcu_gpio0 38 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO4"; + beagle-gpio-pi = "GPIO4"; + }; + + hat-07-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_07_gpio_pd>; + gpios = <&mcu_gpio0 38 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO4"; + beagle-gpio-pi = "GPIO4"; + }; + + hat-08-uart1-txd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_08_uart1_txd>; + gpios = <&main_gpio1 14 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO14"; + beagle-gpio-pi = "GPIO14"; + }; + + hat-08-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_08_gpio>; + gpios = <&main_gpio1 14 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO14"; + beagle-gpio-pi = "GPIO14"; + }; + + hat-08-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_08_gpio_pu>; + gpios = <&main_gpio1 14 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO14"; + beagle-gpio-pi = "GPIO14"; + }; + + hat-08-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_08_gpio_pd>; + gpios = <&main_gpio1 14 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO14"; + beagle-gpio-pi = "GPIO14"; + }; + + hat-10-uart1-rxd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_10_uart1_rxd>; + gpios = <&main_gpio1 13 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO15"; + beagle-gpio-pi = "GPIO15"; + }; + + hat-10-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_10_gpio>; + gpios = <&main_gpio1 13 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO15"; + beagle-gpio-pi = "GPIO15"; + }; + + hat-10-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_10_gpio_pu>; + gpios = <&main_gpio1 13 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO15"; + beagle-gpio-pi = "GPIO15"; + }; + + hat-10-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_10_gpio_pd>; + gpios = <&main_gpio1 13 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO15"; + beagle-gpio-pi = "GPIO15"; + }; + + hat-11-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_11_gpio>; + gpios = <&main_gpio1 8 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO17"; + beagle-gpio-pi = "GPIO17"; + }; + + hat-11-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_11_gpio_pu>; + gpios = <&main_gpio1 8 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO17"; + beagle-gpio-pi = "GPIO17"; + }; + + hat-11-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_11_gpio_pd>; + gpios = <&main_gpio1 8 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO17"; + beagle-gpio-pi = "GPIO17"; + }; + + hat-12-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_12_gpio>; + gpios = <&main_gpio1 11 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO18"; + beagle-gpio-pi = "GPIO18"; + }; + + hat-12-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_12_gpio_pu>; + gpios = <&main_gpio1 11 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO18"; + beagle-gpio-pi = "GPIO18"; + }; + + hat-12-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_12_gpio_pd>; + gpios = <&main_gpio1 11 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO18"; + beagle-gpio-pi = "GPIO18"; + }; + + hat-13-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_13_gpio>; + gpios = <&main_gpio0 33 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO27"; + beagle-gpio-pi = "GPIO27"; + }; + + hat-13-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_13_gpio_pu>; + gpios = <&main_gpio0 33 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO27"; + beagle-gpio-pi = "GPIO27"; + }; + + hat-13-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_13_gpio_pd>; + gpios = <&main_gpio0 33 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO27"; + beagle-gpio-pi = "GPIO27"; + }; + + hat-15-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_15_gpio>; + gpios = <&main_gpio0 41 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO22"; + beagle-gpio-pi = "GPIO22"; + }; + + hat-15-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_15_gpio_pu>; + gpios = <&main_gpio0 41 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO22"; + beagle-gpio-pi = "GPIO22"; + }; + + hat-15-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_15_gpio_pd>; + gpios = <&main_gpio0 41 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO22"; + beagle-gpio-pi = "GPIO22"; + }; + + hat-16-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_16_gpio>; + gpios = <&mcu_gpio0 7 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO23"; + beagle-gpio-pi = "GPIO23"; + }; + + hat-16-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_16_gpio_pu>; + gpios = <&mcu_gpio0 7 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO23"; + beagle-gpio-pi = "GPIO23"; + }; + + hat-16-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_16_gpio_pd>; + gpios = <&mcu_gpio0 7 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO23"; + beagle-gpio-pi = "GPIO23"; + }; + + hat-18-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_18_gpio>; + gpios = <&mcu_gpio0 10 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO24"; + beagle-gpio-pi = "GPIO24"; + }; + + hat-18-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_18_gpio_pu>; + gpios = <&mcu_gpio0 10 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO24"; + beagle-gpio-pi = "GPIO24"; + }; + + hat-18-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_18_gpio_pd>; + gpios = <&mcu_gpio0 10 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO24"; + beagle-gpio-pi = "GPIO24"; + }; + + hat-19-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_19_gpio>; + gpios = <&mcu_gpio0 3 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO10"; + beagle-gpio-pi = "GPIO10"; + }; + + hat-19-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_19_gpio_pu>; + gpios = <&mcu_gpio0 3 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO10"; + beagle-gpio-pi = "GPIO10"; + }; + + hat-19-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_19_gpio_pd>; + gpios = <&mcu_gpio0 3 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO10"; + beagle-gpio-pi = "GPIO10"; + }; + + hat-21-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_21_gpio>; + gpios = <&mcu_gpio0 4 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO9"; + beagle-gpio-pi = "GPIO9"; + }; + + hat-21-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_21_gpio_pu>; + gpios = <&mcu_gpio0 4 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO9"; + beagle-gpio-pi = "GPIO9"; + }; + + hat-21-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_21_gpio_pd>; + gpios = <&mcu_gpio0 4 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO9"; + beagle-gpio-pi = "GPIO9"; + }; + + hat-22-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_22_gpio>; + gpios = <&main_gpio0 42 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO25"; + beagle-gpio-pi = "GPIO25"; + }; + + hat-22-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_22_gpio_pu>; + gpios = <&main_gpio0 42 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO25"; + beagle-gpio-pi = "GPIO25"; + }; + + hat-22-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_22_gpio_pd>; + gpios = <&main_gpio0 42 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO25"; + beagle-gpio-pi = "GPIO25"; + }; + + hat-23-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_23_gpio>; + gpios = <&mcu_gpio0 2 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO11"; + beagle-gpio-pi = "GPIO11"; + }; + + hat-23-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_23_gpio_pu>; + gpios = <&mcu_gpio0 2 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO11"; + beagle-gpio-pi = "GPIO11"; + }; + + hat-23-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_23_gpio_pd>; + gpios = <&mcu_gpio0 2 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO11"; + beagle-gpio-pi = "GPIO11"; + }; + + hat-24-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_24_gpio>; + gpios = <&mcu_gpio0 0 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO8"; + beagle-gpio-pi = "GPIO8"; + }; + + hat-24-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_24_gpio_pu>; + gpios = <&mcu_gpio0 0 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO8"; + beagle-gpio-pi = "GPIO8"; + }; + + hat-24-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_24_gpio_pd>; + gpios = <&mcu_gpio0 0 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO8"; + beagle-gpio-pi = "GPIO8"; + }; + + hat-26-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_26_gpio>; + gpios = <&mcu_gpio0 9 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO7"; + beagle-gpio-pi = "GPIO7"; + }; + + hat-26-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_26_gpio_pu>; + gpios = <&mcu_gpio0 9 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO7"; + beagle-gpio-pi = "GPIO7"; + }; + + hat-26-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_26_gpio_pd>; + gpios = <&mcu_gpio0 9 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO7"; + beagle-gpio-pi = "GPIO7"; + }; + + hat-29-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_29_gpio>; + gpios = <&main_gpio1 15 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO5"; + beagle-gpio-pi = "GPIO5"; + }; + + hat-29-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_29_gpio_pu>; + gpios = <&main_gpio1 15 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO5"; + beagle-gpio-pi = "GPIO5"; + }; + + hat-29-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_29_gpio_pd>; + gpios = <&main_gpio1 15 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO5"; + beagle-gpio-pi = "GPIO5"; + }; + + hat-31-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_31_gpio>; + gpios = <&main_gpio1 17 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO6"; + beagle-gpio-pi = "GPIO6"; + }; + + hat-31-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_31_gpio_pu>; + gpios = <&main_gpio1 17 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO6"; + beagle-gpio-pi = "GPIO6"; + }; + + hat-31-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_31_gpio_pd>; + gpios = <&main_gpio1 17 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO6"; + beagle-gpio-pi = "GPIO6"; + }; + + hat-32-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_32_gpio>; + gpios = <&main_gpio1 16 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO12"; + beagle-gpio-pi = "GPIO12"; + }; + + hat-32-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_32_gpio_pu>; + gpios = <&main_gpio1 16 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO12"; + beagle-gpio-pi = "GPIO12"; + }; + + hat-32-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_32_gpio_pd>; + gpios = <&main_gpio1 16 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO12"; + beagle-gpio-pi = "GPIO12"; + }; + + hat-33-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_33_gpio>; + gpios = <&main_gpio1 18 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO13"; + beagle-gpio-pi = "GPIO13"; + }; + + hat-33-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_33_gpio_pu>; + gpios = <&main_gpio1 18 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO13"; + beagle-gpio-pi = "GPIO13"; + }; + + hat-33-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_33_gpio_pd>; + gpios = <&main_gpio1 18 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO13"; + beagle-gpio-pi = "GPIO13"; + }; + + hat-35-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_35_gpio>; + gpios = <&main_gpio1 12 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO19"; + beagle-gpio-pi = "GPIO19"; + }; + + hat-35-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_35_gpio_pu>; + gpios = <&main_gpio1 12 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO19"; + beagle-gpio-pi = "GPIO19"; + }; + + hat-35-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_35_gpio_pd>; + gpios = <&main_gpio1 12 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO19"; + beagle-gpio-pi = "GPIO19"; + }; + + hat-36-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_36_gpio>; + gpios = <&main_gpio1 7 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO16"; + beagle-gpio-pi = "GPIO16"; + }; + + hat-36-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_36_gpio_pu>; + gpios = <&main_gpio1 7 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO16"; + beagle-gpio-pi = "GPIO16"; + }; + + hat-36-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_36_gpio_pd>; + gpios = <&main_gpio1 7 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO16"; + beagle-gpio-pi = "GPIO16"; + }; + + hat-37-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_37_gpio>; + gpios = <&main_gpio0 36 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO26"; + beagle-gpio-pi = "GPIO26"; + }; + + hat-37-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_37_gpio_pu>; + gpios = <&main_gpio0 36 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO26"; + beagle-gpio-pi = "GPIO26"; + }; + + hat-37-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_37_gpio_pd>; + gpios = <&main_gpio0 36 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO26"; + beagle-gpio-pi = "GPIO26"; + }; + + hat-38-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_38_gpio>; + gpios = <&main_gpio1 10 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO20"; + beagle-gpio-pi = "GPIO20"; + }; + + hat-38-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_38_gpio_pu>; + gpios = <&main_gpio1 10 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO20"; + beagle-gpio-pi = "GPIO20"; + }; + + hat-38-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_38_gpio_pd>; + gpios = <&main_gpio1 10 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO20"; + beagle-gpio-pi = "GPIO20"; + }; + + hat-40-gpio { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_40_gpio>; + gpios = <&main_gpio1 9 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO21"; + beagle-gpio-pi = "GPIO21"; + }; + + hat-40-gpio-pu { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_40_gpio_pu>; + gpios = <&main_gpio1 9 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO21"; + beagle-gpio-pi = "GPIO21"; + }; + + hat-40-gpio-pd { + compatible = "gpio-single"; + pinctrl-names = "default"; + pinctrl-0 = <&hat_40_gpio_pd>; + gpios = <&main_gpio1 9 GPIO_ACTIVE_HIGH>; + gpio-line-names = "GPIO21"; + beagle-gpio-pi = "GPIO21"; + }; +}; + +&main_pmx0 { + hat_07_uart6_rxd: hat-07-uart6-rxd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x09C, PIN_INPUT, 3) /* (W26) GPMC0_WAIT1.UART6_RXD */ + >; + }; + + hat_07_gpio: hat-07-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x09C, PIN_INPUT, 7) /* (W26) GPMC0_WAIT1.GPIO0_38 */ + >; + }; + + hat_07_gpio_pu: hat-07-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x09C, PIN_INPUT_PULLUP, 7) /* (W26) GPMC0_WAIT1.GPIO0_38 */ + >; + }; + + hat_07_gpio_pd: hat-07-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x09C, PIN_INPUT_PULLDOWN, 7) /* (W26) GPMC0_WAIT1.GPIO0_38 */ + >; + }; + + hat_08_audio: hat-08-audio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B0, PIN_INPUT, 0) /* (F24) MCASP0_ACLKR */ + >; + }; + + hat_08_spi: hat-08-spi-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B0, PIN_INPUT, 1) /* (F24) MCASP0_ACLKR.SPI2_CLK */ + >; + }; + + hat_08_uart1_txd: hat-08-uart1-txd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B0, PIN_OUTPUT, 2) /* (F24) MCASP0_ACLKR.UART1_TXD */ + >; + }; + + hat_08_pwm: hat-08-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B0, PIN_OUTPUT, 6) /* (F24) MCASP0_ACLKR.EHRPWM0_B */ + >; + }; + + hat_08_gpio: hat-08-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B0, PIN_INPUT, 7) /* (F24) MCASP0_ACLKR.GPIO1_14 */ + >; + }; + + hat_08_gpio_pu: hat-08-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B0, PIN_INPUT_PULLUP, 7) /* (F24) MCASP0_ACLKR.GPIO1_14 */ + >; + }; + + hat_08_gpio_pd: hat-08-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B0, PIN_INPUT_PULLDOWN, 7) /* (F24) MCASP0_ACLKR.GPIO1_14 */ + >; + }; + + hat_08_eqep: hat-08-eqep-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B0, PIN_INPUT, 8) /* (F24) MCASP0_ACLKR.EQEP1_I */ + >; + }; + + hat_10_audio: hat-10-audio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1AC, PIN_INPUT, 0) /* (C27) MCASP0_AFSR */ + >; + }; + + hat_10_spi: hat-10-spi-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1AC, PIN_INPUT, 1) /* (C27) MCASP0_AFSR.SPI2_CS0 */ + >; + }; + + hat_10_uart1_rxd: hat-10-uart1-rxd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1AC, PIN_INPUT, 2) /* (C27) MCASP0_AFSR.UART1_RXD */ + >; + }; + + hat_10_pwm: hat-10-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1AC, PIN_OUTPUT, 6) /* (C27) MCASP0_AFSR.EHRPWM0_A */ + >; + }; + + hat_10_gpio: hat-10-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1AC, PIN_INPUT, 7) /* (C27) MCASP0_AFSR.GPIO1_13 */ + >; + }; + + hat_10_gpio_pu: hat-10-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1AC, PIN_INPUT_PULLUP, 7) /* (C27) MCASP0_AFSR.GPIO1_13 */ + >; + }; + + hat_10_gpio_pd: hat-10-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1AC, PIN_INPUT_PULLDOWN, 7) /* (C27) MCASP0_AFSR.GPIO1_13 */ + >; + }; + + hat_10_eqep: hat-10-eqep-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1AC, PIN_INPUT, 8) /* (C27) MCASP0_AFSR.EQEP1_S */ + >; + }; + + hat_11_audio: hat-11-audio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x198, PIN_INPUT, 0) /* (A26) MCASP0_AXR2 */ + >; + }; + + hat_11_spi: hat-11-spi-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x198, PIN_INPUT, 1) /* (A26) MCASP0_AXR2.SPI2_D1 */ + >; + }; + + /* USED by BLE */ + hat_11_uart6_txd: hat-11-uart6-txd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x198, PIN_OUTPUT, 3) /* (A26) MCASP0_AXR2.UART6_TXD */ + >; + }; + + hat_11_pwm_ecap: hat-11-pwm-ecap-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x198, PIN_OUTPUT, 5) /* (A26) MCASP0_AXR2.ECAP2_IN_APWM_OUT */ + >; + }; + + hat_11_gpio: hat-11-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x198, PIN_INPUT, 7) /* (A26) MCASP0_AXR2.GPIO1_8 */ + >; + }; + + hat_11_gpio_pu: hat-11-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x198, PIN_INPUT_PULLUP, 7) /* (A26) MCASP0_AXR2.GPIO1_8 */ + >; + }; + + hat_11_gpio_pd: hat-11-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x198, PIN_INPUT_PULLDOWN, 7) /* (A26) MCASP0_AXR2.GPIO1_8 */ + >; + }; + + hat_11_eqep: hat-11-eqep-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x198, PIN_INPUT, 8) /* (A26) MCASP0_AXR2.EQEP0_B */ + >; + }; + + hat_12_audio: hat-12-audio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A4, PIN_INPUT, 0) /* (D25) MCASP0_ACLKX */ + >; + }; + + hat_12_spi: hat-12-spi-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A4, PIN_INPUT, 1) /* (D25) MCASP0_ACLKX.SPI2_CS1 */ + >; + }; + + hat_12_pwm_ecap: hat-12-pwm-ecap-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A4, PIN_OUTPUT, 2) /* (D25) MCASP0_ACLKX.ECAP2_IN_APWM_OUT */ + >; + }; + + hat_12_gpio: hat-12-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A4, PIN_INPUT, 7) /* (D25) MCASP0_ACLKX.GPIO1_11 */ + >; + }; + + hat_12_gpio_pu: hat-12-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A4, PIN_INPUT_PULLUP, 7) /* (D25) MCASP0_ACLKX.GPIO1_11 */ + >; + }; + + hat_12_gpio_pd: hat-12-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A4, PIN_INPUT_PULLDOWN, 7) /* (D25) MCASP0_ACLKX.GPIO1_11 */ + >; + }; + + hat_12_eqep: hat-12-eqep-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A4, PIN_INPUT, 8) /* (D25) MCASP0_ACLKX.EQEP1_A */ + >; + }; + + hat_13_audio: hat-13-audio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x088, PIN_INPUT, 2) /* (N22) GPMC0_OEn_REn.MCASP1_AXR1 */ + >; + }; + + hat_13_gpio: hat-13-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x088, PIN_INPUT, 7) /* (N22) GPMC0_OEn_REn.GPIO0_33 */ + >; + }; + + hat_13_gpio_pu: hat-13-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x088, PIN_INPUT_PULLUP, 7) /* (N22) GPMC0_OEn_REn.GPIO0_33 */ + >; + }; + + hat_13_gpio_pd: hat-13-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x088, PIN_INPUT_PULLDOWN, 7) /* (N22) GPMC0_OEn_REn.GPIO0_33 */ + >; + }; + + hat_15_i2c: hat-15-i2c-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0A8, PIN_INPUT_PULLUP, 1) /* (R27) GPMC0_CSn0.I2C4_SCL */ + >; + }; + + hat_15_audio: hat-15-audio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0A8, PIN_INPUT, 3) /* (R27) GPMC0_CSn0.MCASP2_AXR14 */ + >; + }; + + hat_15_gpio: hat-15-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0A8, PIN_INPUT, 7) /* (R27) GPMC0_CSn0.GPIO0_41 */ + >; + }; + + hat_15_gpio_pu: hat-15-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0A8, PIN_INPUT_PULLUP, 7) /* (R27) GPMC0_CSn0.GPIO0_41 */ + >; + }; + + hat_15_gpio_pd: hat-15-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0A8, PIN_INPUT_PULLDOWN, 7) /* (R27) GPMC0_CSn0.GPIO0_41 */ + >; + }; + + hat_22_i2c: hat-22-i2c-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0AC, PIN_INPUT_PULLUP, 1) /* (P21) GPMC0_CSn1.I2C4_SDA */ + >; + }; + + hat_22_audio: hat-22-audio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0AC, PIN_INPUT, 3) /* (P21) GPMC0_CSn1.MCASP2_AXR15 */ + >; + }; + + hat_22_gpio: hat-22-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0AC, PIN_INPUT, 7) /* (P21) GPMC0_CSn1.GPIO0_42 */ + >; + }; + + hat_22_gpio_pu: hat-22-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0AC, PIN_INPUT_PULLUP, 7) /* (P21) GPMC0_CSn1.GPIO0_42 */ + >; + }; + + hat_22_gpio_pd: hat-22-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0AC, PIN_INPUT_PULLDOWN, 7) /* (P21) GPMC0_CSn1.GPIO0_42 */ + >; + }; + + hat_29_pwm: hat-29-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B4, PIN_OUTPUT, 2) /* (B20) SPI0_CS0.EHRPWM0_A */ + >; + }; + + hat_29_gpio: hat-29-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B4, PIN_INPUT, 7) /* (B20) SPI0_CS0.GPIO1_15 */ + >; + }; + + hat_29_gpio_pu: hat-29-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B4, PIN_INPUT_PULLUP, 7) /* (B20) SPI0_CS0.GPIO1_15 */ + >; + }; + + hat_29_gpio_pd: hat-29-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B4, PIN_INPUT_PULLDOWN, 7) /* (B20) SPI0_CS0.GPIO1_15 */ + >; + }; + + hat_31_pwm: hat-31-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1BC, PIN_OUTPUT, 2) /* (D20) SPI0_CLK.EHRPWM1_A */ + >; + }; + + hat_31_gpio: hat-31-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1BC, PIN_INPUT, 7) /* (D20) SPI0_CLK.GPIO1_17 */ + >; + }; + + hat_31_gpio_pu: hat-31-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1BC, PIN_INPUT_PULLUP, 7) /* (D20) SPI0_CLK.GPIO1_17 */ + >; + }; + + hat_31_gpio_pd: hat-31-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1BC, PIN_INPUT_PULLDOWN, 7) /* (D20) SPI0_CLK.GPIO1_17 */ + >; + }; + + hat_32_pwm: hat-32-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B8, PIN_OUTPUT, 2) /* (C20) SPI0_CS1.EHRPWM0_B */ + >; + }; + + hat_32_pwm_ecap: hat-32-pwm-ecap-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B8, PIN_OUTPUT, 3) /* (C20) SPI0_CS1.ECAP0_IN_APWM_OUT */ + >; + }; + + hat_32_gpio: hat-32-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B8, PIN_INPUT, 7) /* (C20) SPI0_CS1.GPIO1_16 */ + >; + }; + + hat_32_gpio_pu: hat-32-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B8, PIN_INPUT_PULLUP, 7) /* (C20) SPI0_CS1.GPIO1_16 */ + >; + }; + + hat_32_gpio_pd: hat-32-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B8, PIN_INPUT_PULLDOWN, 7) /* (C20) SPI0_CS1.GPIO1_16 */ + >; + }; + + hat_33_pwm: hat-33-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1C0, PIN_OUTPUT, 2) /* (E19) SPI0_D0.EHRPWM1_B */ + >; + }; + + hat_33_gpio: hat-33-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1C0, PIN_INPUT, 7) /* (E19) SPI0_D0.GPIO1_18 */ + >; + }; + + hat_33_gpio_pu: hat-33-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1C0, PIN_INPUT_PULLUP, 7) /* (E19) SPI0_D0.GPIO1_18 */ + >; + }; + + hat_33_gpio_pd: hat-33-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1C0, PIN_INPUT_PULLDOWN, 7) /* (E19) SPI0_D0.GPIO1_18 */ + >; + }; + + hat_35_audio: hat-35-audio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A8, PIN_INPUT, 0) /* (C26) MCASP0_AFSX */ + >; + }; + + hat_35_spi: hat-35-spi-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A8, PIN_INPUT, 1) /* (C26) MCASP0_AFSX.SPI2_CS3 */ + >; + }; + + hat_35_gpio: hat-35-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A8, PIN_INPUT, 7) /* (C26) MCASP0_AFSX.GPIO1_12 */ + >; + }; + + hat_35_gpio_pu: hat-35-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A8, PIN_INPUT_PULLUP, 7) /* (C26) MCASP0_AFSX.GPIO1_12 */ + >; + }; + + hat_35_gpio_pd: hat-35-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A8, PIN_INPUT_PULLDOWN, 7) /* (C26) MCASP0_AFSX.GPIO1_12 */ + >; + }; + + hat_35_eqep: hat-35-eqep-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A8, PIN_INPUT, 8) /* (C26) MCASP0_AFSX.EQEP1_B */ + >; + }; + + hat_36_audio: hat-36-audio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x194, PIN_INPUT, 0) /* (A25) MCASP0_AXR3 */ + >; + }; + + hat_36_spi: hat-36-spi-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x194, PIN_INPUT, 1) /* (A25) MCASP0_AXR3.SPI2_D0 */ + >; + }; + + /* USED by BLE */ + hat_36_uart6_rxd: hat-36-uart6-rxd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x194, PIN_INPUT, 3) /* (A25) MCASP0_AXR3.UART6_RXD */ + >; + }; + + hat_36_pwm_ecap: hat-36-pwm-ecap-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x194, PIN_OUTPUT, 5) /* (A25) MCASP0_AXR3.ECAP1_IN_APWM_OUT */ + >; + }; + + hat_36_gpio: hat-36-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x194, PIN_INPUT, 7) /* (A25) MCASP0_AXR3.GPIO1_7 */ + >; + }; + + hat_36_gpio_pu: hat-36-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x194, PIN_INPUT_PULLUP, 7) /* (A25) MCASP0_AXR3.GPIO1_7 */ + >; + }; + + hat_36_gpio_pd: hat-36-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x194, PIN_INPUT_PULLDOWN, 7) /* (A25) MCASP0_AXR3.GPIO1_7 */ + >; + }; + + hat_36_eqep: hat-36-eqep-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x194, PIN_INPUT, 8) /* (A25) MCASP0_AXR3.EQEP0_A */ + >; + }; + + hat_37_audio: hat-37-audio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x094, PIN_INPUT, 3) /* (P26) GPMC0_BE1n.MCASP2_AXR12 */ + >; + }; + + hat_37_gpio: hat-37-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x094, PIN_INPUT, 7) /* (P26) GPMC0_BE1n.GPIO0_36 */ + >; + }; + + hat_37_gpio_pu: hat-37-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x094, PIN_INPUT_PULLUP, 7) /* (P26) GPMC0_BE1n.GPIO0_36 */ + >; + }; + + hat_37_gpio_pd: hat-37-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x094, PIN_INPUT_PULLDOWN, 7) /* (P26) GPMC0_BE1n.GPIO0_36 */ + >; + }; + + hat_38_audio: hat-38-audio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A0, PIN_INPUT, 0) /* (F23) MCASP0_AXR0 */ + >; + }; + + hat_38_pwm: hat-38-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A0, PIN_OUTPUT, 6) /* (F23) MCASP0_AXR0.EHRPWM1_B */ + >; + }; + + hat_38_gpio: hat-38-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A0, PIN_INPUT, 7) /* (F23) MCASP0_AXR0.GPIO1_10 */ + >; + }; + + hat_38_gpio_pu: hat-38-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A0, PIN_INPUT_PULLUP, 7) /* (F23) MCASP0_AXR0.GPIO1_10 */ + >; + }; + + hat_38_gpio_pd: hat-38-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A0, PIN_INPUT_PULLDOWN, 7) /* (F23) MCASP0_AXR0.GPIO1_10 */ + >; + }; + + hat_38_eqep: hat-38-eqep-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A0, PIN_INPUT, 8) /* (F23) MCASP0_AXR0.EQEP0_I */ + >; + }; + + hat_40_audio: hat-40-audio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x19C, PIN_INPUT, 0) /* (B25) MCASP0_AXR1 */ + >; + }; + + hat_40_spi: hat-40-spi-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x19C, PIN_INPUT, 1) /* (B25) MCASP0_AXR1.SPI2_CS2 */ + >; + }; + + hat_40_pwm_ecap: hat-40-pwm-ecap-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x19C, PIN_OUTPUT, 2) /* (B25) MCASP0_AXR1.ECAP1_IN_APWM_OUT */ + >; + }; + + hat_40_pwm: hat-40-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x19C, PIN_OUTPUT, 6) /* (B25) MCASP0_AXR1.EHRPWM1_A */ + >; + }; + + hat_40_gpio: hat-40-gpio-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x19C, PIN_INPUT, 7) /* (B25) MCASP0_AXR1.GPIO1_9 */ + >; + }; + + hat_40_gpio_pu: hat-40-gpio-pu-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x19C, PIN_INPUT_PULLUP, 7) /* (B25) MCASP0_AXR1.GPIO1_9 */ + >; + }; + + hat_40_gpio_pd: hat-40-gpio-pd-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x19C, PIN_INPUT_PULLDOWN, 7) /* (B25) MCASP0_AXR1.GPIO1_9 */ + >; + }; + + hat_40_eqep: hat-40-eqep-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x19C, PIN_INPUT, 8) /* (B25) MCASP0_AXR1.EQEP0_S */ + >; + }; + +}; + +&mcu_pmx0 { + hat_03_i2c: hat-03-i2c-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x048, PIN_INPUT_PULLUP, 0) /* (E11) MCU_I2C0_SDA */ + >; + }; + + hat_03_gpio: hat-03-gpio-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x048, PIN_INPUT, 7) /* (E11) MCU_I2C0_SDA.MCU_GPIO0_18 */ + >; + }; + + hat_03_gpio_pu: hat-03-gpio-pu-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x048, PIN_INPUT_PULLUP, 7) /* (E11) MCU_I2C0_SDA.MCU_GPIO0_18 */ + >; + }; + + hat_03_gpio_pd: hat-03-gpio-pd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x048, PIN_INPUT_PULLDOWN, 7) /* (E11) MCU_I2C0_SDA.MCU_GPIO0_18 */ + >; + }; + + hat_05_i2c: hat-05-i2c-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x044, PIN_INPUT_PULLUP, 0) /* (B13) MCU_I2C0_SCL */ + >; + }; + + hat_05_gpio: hat-05-gpio-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x044, PIN_INPUT, 7) /* (B13) MCU_I2C0_SCL.MCU_GPIO0_17 */ + >; + }; + + hat_05_gpio_pu: hat-05-gpio-pu-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x044, PIN_INPUT_PULLUP, 7) /* (B13) MCU_I2C0_SCL.MCU_GPIO0_17 */ + >; + }; + + hat_05_gpio_pd: hat-05-gpio-pd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x044, PIN_INPUT_PULLDOWN, 7) /* (B13) MCU_I2C0_SCL.MCU_GPIO0_17 */ + >; + }; + + hat_16_gpio: hat-16-gpio-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x01C, PIN_INPUT, 7) /* (B5) MCU_UART0_CTSn.MCU_GPIO0_7 */ + >; + }; + + hat_16_gpio_pu: hat-16-gpio-pu-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x01C, PIN_INPUT_PULLUP, 7) /* (B5) MCU_UART0_CTSn.MCU_GPIO0_7 */ + >; + }; + + hat_16_gpio_pd: hat-16-gpio-pd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x01C, PIN_INPUT_PULLDOWN, 7) /* (B5) MCU_UART0_CTSn.MCU_GPIO0_7 */ + >; + }; + + /* Device Manager firmware */ + hat_18_wkup_uart0_txd: hat-18-wkup-uart0-txd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x028, PIN_OUTPUT, 0) /* (C8) WKUP_UART0_TXD */ + >; + }; + + hat_18_gpio: hat-18-gpio-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x028, PIN_INPUT, 7) /* (C8) WKUP_UART0_TXD.MCU_GPIO0_10 */ + >; + }; + + hat_18_gpio_pu: hat-18-gpio-pu-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x028, PIN_INPUT_PULLUP, 7) /* (C8) WKUP_UART0_TXD.MCU_GPIO0_10 */ + >; + }; + + hat_18_gpio_pd: hat-18-gpio-pd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x028, PIN_INPUT_PULLDOWN, 7) /* (C8) WKUP_UART0_TXD.MCU_GPIO0_10 */ + >; + }; + + hat_19_gpio: hat-19-gpio-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x00C, PIN_INPUT, 7) /* (B12) MCU_SPI0_D0.MCU_GPIO0_3 */ + >; + }; + + hat_19_gpio_pu: hat-19-gpio-pu-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x00C, PIN_INPUT_PULLUP, 7) /* (B12) MCU_SPI0_D0.MCU_GPIO0_3 */ + >; + }; + + hat_19_gpio_pd: hat-19-gpio-pd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x00C, PIN_INPUT_PULLDOWN, 7) /* (B12) MCU_SPI0_D0.MCU_GPIO0_3 */ + >; + }; + + hat_21_gpio: hat-21-gpio-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x010, PIN_INPUT, 7) /* (C11) MCU_SPI0_D1.MCU_GPIO0_4 */ + >; + }; + + hat_21_gpio_pu: hat-21-gpio-pu-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x010, PIN_INPUT_PULLUP, 7) /* (C11) MCU_SPI0_D1.MCU_GPIO0_4 */ + >; + }; + + hat_21_gpio_pd: hat-21-gpio-pd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x010, PIN_INPUT_PULLDOWN, 7) /* (C11) MCU_SPI0_D1.MCU_GPIO0_4 */ + >; + }; + + hat_23_gpio: hat-23-gpio-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x008, PIN_INPUT, 7) /* (A9) MCU_SPI0_CLK.MCU_GPIO0_2 */ + >; + }; + + hat_23_gpio_pu: hat-23-gpio-pu-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x008, PIN_INPUT_PULLUP, 7) /* (A9) MCU_SPI0_CLK.MCU_GPIO0_2 */ + >; + }; + + hat_23_gpio_pd: hat-23-gpio-pd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x008, PIN_INPUT_PULLDOWN, 7) /* (A9) MCU_SPI0_CLK.MCU_GPIO0_2 */ + >; + }; + + hat_24_gpio: hat-24-gpio-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x000, PIN_INPUT, 7) /* (C12) MCU_SPI0_CS0.MCU_GPIO0_0 */ + >; + }; + + hat_24_gpio_pu: hat-24-gpio-pu-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x000, PIN_INPUT_PULLUP, 7) /* (C12) MCU_SPI0_CS0.MCU_GPIO0_0 */ + >; + }; + + hat_24_gpio_pd: hat-24-gpio-pd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x000, PIN_INPUT_PULLDOWN, 7) /* (C12) MCU_SPI0_CS0.MCU_GPIO0_0 */ + >; + }; + + /* Device Manager firmware */ + hat_26_wkup_uart0_rxd: hat-26-wkup-uart0-rxd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x024, PIN_INPUT, 0) /* (B3) WKUP_UART0_RXD */ + >; + }; + + hat_26_gpio: hat-26-gpio-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x024, PIN_INPUT, 7) /* (B3) WKUP_UART0_RXD.MCU_GPIO0_9 */ + >; + }; + + hat_26_gpio_pu: hat-26-gpio-pu-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x024, PIN_INPUT_PULLUP, 7) /* (B3) WKUP_UART0_RXD.MCU_GPIO0_9 */ + >; + }; + + hat_26_gpio_pd: hat-26-gpio-pd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x024, PIN_INPUT_PULLDOWN, 7) /* (B3) WKUP_UART0_RXD.MCU_GPIO0_9 */ + >; + }; + + /* I2C PMIC and eeprom */ + hat_27_i2c: hat-27-i2c-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x050, PIN_INPUT_PULLUP, 0) /* (D11) WKUP_I2C0_SDA */ + >; + }; + + hat_27_gpio: hat-27-gpio-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x050, PIN_INPUT, 7) /* (D11) WKUP_I2C0_SDA.MCU_GPIO0_20 */ + >; + }; + + hat_27_gpio_pu: hat-27-gpio-pu-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x050, PIN_INPUT_PULLUP, 7) /* (D11) WKUP_I2C0_SDA.MCU_GPIO0_20 */ + >; + }; + + hat_27_gpio_pd: hat-27-gpio-pd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x050, PIN_INPUT_PULLDOWN, 7) /* (D11) WKUP_I2C0_SDA.MCU_GPIO0_20 */ + >; + }; + + /* I2C PMIC and eeprom */ + hat_28_i2c: hat-28-i2c-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x04C, PIN_INPUT_PULLUP, 0) /* (B9) WKUP_I2C0_SCL */ + >; + }; + + hat_28_gpio: hat-28-gpio-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x04C, PIN_INPUT, 7) /* (B9) WKUP_I2C0_SCL.MCU_GPIO0_19 */ + >; + }; + + hat_28_gpio_pu: hat-28-gpio-pu-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x04C, PIN_INPUT_PULLUP, 7) /* (B9) WKUP_I2C0_SCL.MCU_GPIO0_19 */ + >; + }; + + hat_28_gpio_pd: hat-28-gpio-pd-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x04C, PIN_INPUT_PULLDOWN, 7) /* (B9) WKUP_I2C0_SCL.MCU_GPIO0_19 */ + >; + }; + +}; + +&ecap0 { + status = "okay"; +}; + +&ecap1 { + status = "okay"; +}; + +&ecap2 { + status = "okay"; +}; + +&epwm0 { + status = "okay"; +}; + +&epwm1 { + status = "okay"; +}; + +&mcu_i2c0 { + symlink = "hat/mcu_i2c0"; + status = "okay"; + clock-frequency = <100000>; +}; + +dsi0_csi1_i2c: &main_i2c0 { + symlink = "hat/dsi0_csi1_i2c"; +}; + +&main_i2c1 { + symlink = "play/main_i2c1"; +}; + +csi0_i2c: &main_i2c2 { + symlink = "hat/csi0"; +}; + +//&main_i2c4 { +// symlink = "hat/i2c4"; +// status = "okay"; +// clock-frequency = <100000>; +//}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap0-gpio12.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap0-gpio12.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap0-gpio12.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap0-gpio12.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO12 ecap0 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-ecap0-gpio12.kernel = __TIMESTAMP__; + hat-32.pin = "k3-am67a-beagley-ai-pwm-ecap0-gpio12"; + hat-32.pin.beagle-pwm-address = "23100000"; + hat-32.pin.beagle-pwm-export = "0"; + hat-32.pin.beagle-gpio-pi = "GPIO12"; + hat-32.23100000.pwm = "k3-am67a-beagley-ai-pwm-ecap0-gpio12.23100000.0.GPIO12"; + gpio12.23100000.pwm = "k3-am67a-beagley-ai-pwm-ecap0-gpio12.23100000.0.GPIO12"; + }; +}; + +&main_pmx0 { + hat_32_pwm_ecap: hat-32-pwm-ecap-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B8, PIN_OUTPUT, 3) /* (C20) SPI0_CS1.ECAP0_IN_APWM_OUT */ + >; + }; +}; + +&ecap0 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_32_pwm_ecap>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap1-gpio16.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap1-gpio16.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap1-gpio16.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap1-gpio16.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO16 ecap1 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-ecap1-gpio16.kernel = __TIMESTAMP__; + hat-36.pin = "k3-am67a-beagley-ai-pwm-ecap1-gpio16"; + hat-36.pin.beagle-pwm-address = "23110000"; + hat-36.pin.beagle-pwm-export = "0"; + hat-36.pin.beagle-gpio-pi = "GPIO16"; + hat-36.23110000.pwm = "k3-am67a-beagley-ai-pwm-ecap1-gpio16.23110000.0.GPIO16"; + gpio16.23110000.pwm = "k3-am67a-beagley-ai-pwm-ecap1-gpio16.23110000.0.GPIO16"; + }; +}; + +&main_pmx0 { + hat_36_pwm_ecap: hat-36-pwm-ecap-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x194, PIN_OUTPUT, 5) /* (A25) MCASP0_AXR3.ECAP1_IN_APWM_OUT */ + >; + }; +}; + +&ecap1 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_36_pwm_ecap>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap1-gpio21.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap1-gpio21.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap1-gpio21.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap1-gpio21.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO21 ecap1 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-ecap1-gpio21.kernel = __TIMESTAMP__; + hat-40.pin = "k3-am67a-beagley-ai-pwm-ecap1-gpio21"; + hat-40.pin.beagle-pwm-address = "23110000"; + hat-40.pin.beagle-pwm-export = "0"; + hat-40.pin.beagle-gpio-pi = "GPIO21"; + hat-40.23110000.pwm = "k3-am67a-beagley-ai-pwm-ecap1-gpio21.23110000.0.GPIO21"; + gpio21.23110000.pwm = "k3-am67a-beagley-ai-pwm-ecap1-gpio21.23110000.0.GPIO21"; + }; +}; + +&main_pmx0 { + hat_40_pwm_ecap: hat-40-pwm-ecap-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x19C, PIN_OUTPUT, 2) /* (B25) MCASP0_AXR1.ECAP1_IN_APWM_OUT */ + >; + }; +}; + +&ecap1 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_40_pwm_ecap>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap2-gpio17.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap2-gpio17.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap2-gpio17.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap2-gpio17.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO17 ecap2 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-ecap2-gpio17.kernel = __TIMESTAMP__; + hat-11.pin = "k3-am67a-beagley-ai-pwm-ecap2-gpio17"; + hat-11.pin.beagle-pwm-address = "23120000"; + hat-11.pin.beagle-pwm-export = "0"; + hat-11.pin.beagle-gpio-pi = "GPIO17"; + hat-11.23120000.pwm = "k3-am67a-beagley-ai-pwm-ecap2-gpio17.23120000.0.GPIO17"; + gpio17.23120000.pwm = "k3-am67a-beagley-ai-pwm-ecap2-gpio17.23120000.0.GPIO17"; + }; +}; + +&main_pmx0 { + hat_11_pwm_ecap: hat-11-pwm-ecap-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x198, PIN_OUTPUT, 5) /* (A26) MCASP0_AXR2.ECAP2_IN_APWM_OUT */ + >; + }; +}; + +&ecap2 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_11_pwm_ecap>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap2-gpio18.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap2-gpio18.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap2-gpio18.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-ecap2-gpio18.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO18 ecap2 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-ecap2-gpio18.kernel = __TIMESTAMP__; + hat-12.pin = "k3-am67a-beagley-ai-pwm-ecap2-gpio18"; + hat-12.pin.beagle-pwm-address = "23120000"; + hat-12.pin.beagle-pwm-export = "0"; + hat-12.pin.beagle-gpio-pi = "GPIO18"; + hat-12.23120000.pwm = "k3-am67a-beagley-ai-pwm-ecap2-gpio18.23120000.0.GPIO18"; + gpio18.23120000.pwm = "k3-am67a-beagley-ai-pwm-ecap2-gpio18.23120000.0.GPIO18"; + }; +}; + +&main_pmx0 { + hat_12_pwm_ecap: hat-12-pwm-ecap-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A4, PIN_OUTPUT, 2) /* (D25) MCASP0_ACLKX.ECAP2_IN_APWM_OUT */ + >; + }; +}; + +&ecap2 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_12_pwm_ecap>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio12.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio12.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio12.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio12.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO12 epwm0 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-epwm0-gpio12.kernel = __TIMESTAMP__; + hat-32.pin = "k3-am67a-beagley-ai-pwm-epwm0-gpio12"; + hat-32.pin.beagle-pwm-address = "23000000"; + hat-32.pin.beagle-pwm-export = "1"; + hat-32.pin.beagle-gpio-pi = "GPIO12"; + hat-32.23000000.pwm = "k3-am67a-beagley-ai-pwm-epwm0-gpio12.23000000.1.GPIO12"; + gpio12.23000000.pwm = "k3-am67a-beagley-ai-pwm-epwm0-gpio12.23000000.1.GPIO12"; + }; +}; + +&main_pmx0 { + hat_32_pwm: hat-32-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B8, PIN_OUTPUT, 2) /* (C20) SPI0_CS1.EHRPWM0_B */ + >; + }; +}; + +&epwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_32_pwm>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio14.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio14.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio14.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio14.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO14 epwm0 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-epwm0-gpio14.kernel = __TIMESTAMP__; + hat-08.pin = "k3-am67a-beagley-ai-pwm-epwm0-gpio14"; + hat-08.pin.beagle-pwm-address = "23000000"; + hat-08.pin.beagle-pwm-export = "1"; + hat-08.pin.beagle-gpio-pi = "GPIO14"; + hat-08.23000000.pwm = "k3-am67a-beagley-ai-pwm-epwm0-gpio14.23000000.1.GPIO14"; + gpio14.23000000.pwm = "k3-am67a-beagley-ai-pwm-epwm0-gpio14.23000000.1.GPIO14"; + }; +}; + +&main_pmx0 { + hat_08_pwm: hat-08-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B0, PIN_OUTPUT, 6) /* (F24) MCASP0_ACLKR.EHRPWM0_B */ + >; + }; +}; + +&epwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_08_pwm>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio15.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio15.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio15.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio15.dtso 2024-07-07 20:37:34.628306469 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO15 epwm0 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-epwm0-gpio15.kernel = __TIMESTAMP__; + hat-10.pin = "k3-am67a-beagley-ai-pwm-epwm0-gpio15"; + hat-10.pin.beagle-pwm-address = "23000000"; + hat-10.pin.beagle-pwm-export = "0"; + hat-10.pin.beagle-gpio-pi = "GPIO15"; + hat-10.23000000.pwm = "k3-am67a-beagley-ai-pwm-epwm0-gpio15.23000000.0.GPIO15"; + gpio15.23000000.pwm = "k3-am67a-beagley-ai-pwm-epwm0-gpio15.23000000.0.GPIO15"; + }; +}; + +&main_pmx0 { + hat_10_pwm: hat-10-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1AC, PIN_OUTPUT, 6) /* (C27) MCASP0_AFSR.EHRPWM0_A */ + >; + }; +}; + +&epwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_10_pwm>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio5.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio5.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio5.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm0-gpio5.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO5 epwm0 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-epwm0-gpio5.kernel = __TIMESTAMP__; + hat-29.pin = "k3-am67a-beagley-ai-pwm-epwm0-gpio5"; + hat-29.pin.beagle-pwm-address = "23000000"; + hat-29.pin.beagle-pwm-export = "0"; + hat-29.pin.beagle-gpio-pi = "GPIO5"; + hat-29.23000000.pwm = "k3-am67a-beagley-ai-pwm-epwm0-gpio5.23000000.0.GPIO5"; + gpio5.23000000.pwm = "k3-am67a-beagley-ai-pwm-epwm0-gpio5.23000000.0.GPIO5"; + }; +}; + +&main_pmx0 { + hat_29_pwm: hat-29-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1B4, PIN_OUTPUT, 2) /* (B20) SPI0_CS0.EHRPWM0_A */ + >; + }; +}; + +&epwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_29_pwm>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio13.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio13.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio13.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio13.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO13 epwm1 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-epwm1-gpio13.kernel = __TIMESTAMP__; + hat-33.pin = "k3-am67a-beagley-ai-pwm-epwm1-gpio13"; + hat-33.pin.beagle-pwm-address = "23010000"; + hat-33.pin.beagle-pwm-export = "1"; + hat-33.pin.beagle-gpio-pi = "GPIO13"; + hat-33.23010000.pwm = "k3-am67a-beagley-ai-pwm-epwm1-gpio13.23010000.1.GPIO13"; + gpio13.23010000.pwm = "k3-am67a-beagley-ai-pwm-epwm1-gpio13.23010000.1.GPIO13"; + }; +}; + +&main_pmx0 { + hat_33_pwm: hat-33-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1C0, PIN_OUTPUT, 2) /* (E19) SPI0_D0.EHRPWM1_B */ + >; + }; +}; + +&epwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_33_pwm>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio20.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio20.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio20.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio20.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO20 epwm1 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-epwm1-gpio20.kernel = __TIMESTAMP__; + hat-38.pin = "k3-am67a-beagley-ai-pwm-epwm1-gpio20"; + hat-38.pin.beagle-pwm-address = "23010000"; + hat-38.pin.beagle-pwm-export = "1"; + hat-38.pin.beagle-gpio-pi = "GPIO20"; + hat-38.23010000.pwm = "k3-am67a-beagley-ai-pwm-epwm1-gpio20.23010000.1.GPIO20"; + gpio20.23010000.pwm = "k3-am67a-beagley-ai-pwm-epwm1-gpio20.23010000.1.GPIO20"; + }; +}; + +&main_pmx0 { + hat_38_pwm: hat-38-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1A0, PIN_OUTPUT, 6) /* (F23) MCASP0_AXR0.EHRPWM1_B */ + >; + }; +}; + +&epwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_38_pwm>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio21.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio21.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio21.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio21.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO21 epwm1 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-epwm1-gpio21.kernel = __TIMESTAMP__; + hat-40.pin = "k3-am67a-beagley-ai-pwm-epwm1-gpio21"; + hat-40.pin.beagle-pwm-address = "23010000"; + hat-40.pin.beagle-pwm-export = "0"; + hat-40.pin.beagle-gpio-pi = "GPIO21"; + hat-40.23010000.pwm = "k3-am67a-beagley-ai-pwm-epwm1-gpio21.23010000.0.GPIO21"; + gpio21.23010000.pwm = "k3-am67a-beagley-ai-pwm-epwm1-gpio21.23010000.0.GPIO21"; + }; +}; + +&main_pmx0 { + hat_40_pwm: hat-40-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x19C, PIN_OUTPUT, 6) /* (B25) MCASP0_AXR1.EHRPWM1_A */ + >; + }; +}; + +&epwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_40_pwm>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio6.dtso b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio6.dtso --- a/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio6.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am67a-beagley-ai-pwm-epwm1-gpio6.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DT Overlay for GPIO6 epwm1 connections within the expansion header. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +/* + * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/ +*/ +&{/chosen} { + overlays { + k3-am67a-beagley-ai-pwm-epwm1-gpio6.kernel = __TIMESTAMP__; + hat-31.pin = "k3-am67a-beagley-ai-pwm-epwm1-gpio6"; + hat-31.pin.beagle-pwm-address = "23010000"; + hat-31.pin.beagle-pwm-export = "0"; + hat-31.pin.beagle-gpio-pi = "GPIO6"; + hat-31.23010000.pwm = "k3-am67a-beagley-ai-pwm-epwm1-gpio6.23010000.0.GPIO6"; + gpio6.23010000.pwm = "k3-am67a-beagley-ai-pwm-epwm1-gpio6.23010000.0.GPIO6"; + }; +}; + +&main_pmx0 { + hat_31_pwm: hat-31-pwm-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1BC, PIN_OUTPUT, 2) /* (D20) SPI0_CLK.EHRPWM1_A */ + >; + }; +}; + +&epwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&hat_31_pwm>; + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts --- a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts 2024-07-07 20:37:34.632306489 -0400 @@ -31,6 +31,7 @@ can1 = &mcu_mcan1; can2 = &main_mcan6; can3 = &main_mcan7; + ethernet0 = &cpsw_port1; }; vusb_main: regulator-vusb-main5v0 { @@ -123,6 +124,23 @@ max-bitrate = <5000000>; }; + edp0_refclk: clock-edp0-refclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + dp0_pwr_3v3: fixedregulator-dp0-pwr { + compatible = "regulator-fixed"; + regulator-name = "dp0-pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + pinctrl-names = "default"; + gpio = <&exp2 2 GPIO_ACTIVE_HIGH>; /*P0 - DP0_3V3 _EN */ + enable-active-high; + regulator-always-on; + }; + connector-hdmi { compatible = "hdmi-connector"; label = "hdmi"; @@ -168,6 +186,13 @@ }; }; }; + + csi_mux: mux-controller { + compatible = "gpio-mux"; + #mux-state-cells = <1>; + mux-gpios = <&exp3 1 GPIO_ACTIVE_HIGH>; + idle-state = <0>; + }; }; &main_pmx0 { @@ -185,6 +210,13 @@ >; }; + main_i2c1_pins_default: main-i2c1-default-pins { + pinctrl-single,pins = < + J721S2_IOPAD(0x0ac, PIN_INPUT, 13) /* (AC25) MCASP0_AXR15.I2C1_SCL */ + J721S2_IOPAD(0x0b0, PIN_INPUT, 13) /* (AD26) MCASP1_AXR3.I2C1_SDA */ + >; + }; + main_mmc1_pins_default: main-mmc1-default-pins { pinctrl-single,pins = < J721S2_IOPAD(0x104, PIN_INPUT, 0) /* (P23) MMC1_CLK */ @@ -399,6 +431,82 @@ pinctrl-0 = <&wkup_uart0_pins_default>; }; +&wkup_i2c0 { + bootph-all; + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&wkup_i2c0_pins_default>; + status = "okay"; + + lp8733: pmic@60 { + compatible = "ti,lp8733"; + reg = <0x60>; + buck0-in-supply = <&vsys_3v3>; + buck1-in-supply = <&vsys_3v3>; + ldo0-in-supply = <&vsys_3v3>; + ldo1-in-supply = <&vsys_3v3>; + + lp8733_regulators: regulators { + lp8733_buck0_reg: buck0 { + /* FB_B0 -> LP8733-BUCK1 - VDD_MCU_0V85 */ + regulator-name = "lp8733-buck0"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-always-on; + regulator-boot-on; + }; + + lp8733_buck1_reg: buck1 { + /* FB_B1 -> LP8733-BUCK2 - VDD_DDR_1V1 */ + regulator-name = "lp8733-buck1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + regulator-boot-on; + }; + + lp8733_ldo0_reg: ldo0 { + /* LDO0 -> LP8733-LDO1 - VDA_DLL_0V8 */ + regulator-name = "lp8733-ldo0"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + lp8733_ldo1_reg: ldo1 { + /* LDO1 -> LP8733-LDO2 - VDA_LN_1V8 */ + regulator-name = "lp8733-ldo1"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + }; + }; + + tps62873a: regulator@40 { + compatible = "ti,tps62873"; + reg = <0x40>; + bootph-pre-ram; + regulator-name = "VDD_CPU_AVS"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + regulator-always-on; + }; + + tps62873b: regulator@43 { + compatible = "ti,tps62873"; + reg = <0x43>; + regulator-name = "VDD_CORE_0V8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; +}; + &mcu_uart0 { status = "okay"; pinctrl-names = "default"; @@ -430,6 +538,42 @@ }; }; +&main_i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_pins_default>; + status = "okay"; + + exp3: gpio@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "CSI_VIO_SEL", "CSI_SEL_FPC_EXPn", + "IO_EXP_CSI2_EXP_RSTz","CSI0_B_GPIO1", + "CSI1_B_GPIO1"; + }; + + i2c-mux@70 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + + cam0_i2c: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + cam1_i2c: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + }; +}; + &main_i2c4 { status = "okay"; pinctrl-names = "default"; @@ -459,6 +603,52 @@ gpio-line-names = "HDMI_PDn","HDMI_LS_OE", "DP0_3V3_EN","eDP_ENABLE"; }; + + dsi_edp_bridge: dsi-edp-bridge@2c { + compatible = "ti,sn65dsi86"; + reg = <0x2c>; + clock-names = "refclk"; + clocks = <&edp0_refclk>; + enable-gpios = <&exp2 3 GPIO_ACTIVE_HIGH>; + vpll-supply = <&vsys_io_1v8>; + vccio-supply = <&vsys_io_1v8>; + vcca-supply = <&vsys_io_1v2>; + vcc-supply = <&vsys_io_1v2>; + + aux-bus { + panel { + compatible = "ti,panel-edp"; + power-supply = <&dp0_pwr_3v3>; + + port { + dp0_panel_in: endpoint { + remote-endpoint = <&dp0_out>; + }; + }; + }; + }; + + dsi_edp_bridge_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dp0_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + + dp0_out: endpoint { + remote-endpoint = <&dp0_panel_in>; + }; + }; + }; + }; }; &main_sdhci1 { @@ -543,7 +733,6 @@ &dss_ports { #address-cells = <1>; #size-cells = <0>; - /* HDMI */ port@1 { reg = <1>; @@ -552,4 +741,94 @@ remote-endpoint = <&tfp410_in>; }; }; + + /* DSI */ + port@2 { + reg = <2>; + + dpi0_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; +}; + +&serdes_ln_ctrl { + idle-states = , , + , ; +}; + +&serdes_refclk { + clock-frequency = <100000000>; +}; + +&serdes0 { + status = "okay"; + + serdes0_pcie_link: phy@0 { + reg = <0>; + cdns,num-lanes = <2>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 1>, <&serdes_wiz0 2>; + }; + + serdes0_usb_link: phy@2 { + status = "okay"; + reg = <2>; + cdns,num-lanes = <1>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 3>; + }; +}; + +&pcie1_rc { + status = "okay"; + reset-gpios = <&exp1 10 GPIO_ACTIVE_HIGH>; + phys = <&serdes0_pcie_link>; + phy-names = "pcie-phy"; + num-lanes = <2>; +}; + +&usb_serdes_mux { + idle-states = <0>; /* USB0 to SERDES lane 2 */ +}; + +&usbss0 { + status = "okay"; + pinctrl-0 = <&main_usbss0_pins_default>; + pinctrl-names = "default"; + ti,vbus-divider; +}; + +&usb0 { + dr_mode = "host"; + maximum-speed = "super-speed"; + phys = <&serdes0_usb_link>; + phy-names = "cdns3,usb3-phy"; +}; + +&dphy_tx0 { + status = "okay"; +}; + +&dsi0 { + status = "okay"; +}; + +&dsi0_ports { + + port@0 { + reg = <0>; + dsi0_out: endpoint { + remote-endpoint = <&dp0_in>; + }; + }; + + port@1 { + reg = <1>; + dsi0_in: endpoint { + remote-endpoint = <&dpi0_out>; + }; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am68-sk-bb-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am68-sk-bb-csi2-ov5640.dtso --- a/arch/arm64/boot/dts/ti/k3-am68-sk-bb-csi2-ov5640.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am68-sk-bb-csi2-ov5640.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * LI OV5640 MIPI Camera module. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&cam0_i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + powerdown-gpios = <&exp3 2 GPIO_ACTIVE_LOW>; + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am68-sk-rpi-hdr-ehrpwm.dtso b/arch/arm64/boot/dts/ti/k3-am68-sk-rpi-hdr-ehrpwm.dtso --- a/arch/arm64/boot/dts/ti/k3-am68-sk-rpi-hdr-ehrpwm.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am68-sk-rpi-hdr-ehrpwm.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for enabling EHRPWMs on RPi expansion header on AM68 SK board. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include "k3-pinctrl.h" + +&main_pmx0 { + rpi_header_gpio0_pins_default: rpi-header-gpio0-pins-default { + pinctrl-single,pins = < + J721S2_IOPAD(0x0a8, PIN_INPUT, 7) /* (U24) MCASP0_AXR14.GPIO0_42 */ + J721S2_IOPAD(0x090, PIN_INPUT, 7) /* (W24) MCASP0_AXR8.GPIO0_36 */ + J721S2_IOPAD(0x0bc, PIN_INPUT, 7) /* (V28) MCASP1_AFSX.GPIO0_47 */ + J721S2_IOPAD(0x06c, PIN_INPUT, 7) /* (V26) MCAN1_TX.GPIO0_27 */ + J721S2_IOPAD(0x004, PIN_INPUT, 7) /* (W25) MCAN12_TX.GPIO0_1 */ + J721S2_IOPAD(0x008, PIN_INPUT, 7) /* (AC24) MCAN12_RX.GPI0_2 */ + J721S2_IOPAD(0x0b8, PIN_INPUT, 7) /* (AA24) MCASP1_ACLKX.GPIO0_46 */ + J721S2_IOPAD(0x00c, PIN_INPUT, 7) /* (AE28) MCAN13_TX.GPIO0_3 */ + J721S2_IOPAD(0x034, PIN_INPUT, 7) /* (AD24) PMIC_WAKE0.GPIO0_13 */ + J721S2_IOPAD(0x0c0, PIN_INPUT, 7) /* (T28) MCASP1_AXR0.GPIO0_48 */ + J721S2_IOPAD(0x0b4, PIN_INPUT, 7) /* (U25) MCASP1_AXR4.GPIO0_45 */ + >; + }; + + rpi_header_ehrpwm0_pins_default: rpi-header-ehrpwm0-pins-default { + pinctrl-single,pins = < + J721S2_IOPAD(0x0cc, PIN_INPUT, 5) /* (AE27) SPI0_CS0.GPIO0_51.EHRPWM0_A */ + >; + }; + + rpi_header_ehrpwm3_pins_default: rpi-header-ehrpwm3-pins-default { + pinctrl-single,pins = < + J721S2_IOPAD(0x08c, PIN_INPUT, 9) /* (T25) RGMII1_TD0.GPIO0_35.EHRPWM3_A */ + >; + }; + + rpi_header_ehrpwm4_pins_default: rpi-header-ehrpwm4-pins-default { + pinctrl-single,pins = < + J721S2_IOPAD(0x0a4, PIN_INPUT, 9) /* (T23) RGMII1_RD2.GPIO0_41.EHRPWM4_A */ + >; + }; +}; + +&main_ehrpwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm0_pins_default>; + status = "okay"; +}; + +&main_ehrpwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm3_pins_default>; + status = "okay"; +}; + +&main_ehrpwm4 { + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm4_pins_default>; + status = "okay"; +}; + +&main_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_gpio0_pins_default>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am68-sk-som.dtsi b/arch/arm64/boot/dts/ti/k3-am68-sk-som.dtsi --- a/arch/arm64/boot/dts/ti/k3-am68-sk-som.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am68-sk-som.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -11,9 +11,10 @@ / { memory@80000000 { device_type = "memory"; + bootph-all; /* 16 GB RAM */ - reg = <0x00 0x80000000 0x00 0x80000000>, - <0x08 0x80000000 0x03 0x80000000>; + reg = <0x00000000 0x80000000 0x00000000 0x80000000>, + <0x00000008 0x80000000 0x00000003 0x80000000>; }; reserved_memory: reserved-memory { @@ -21,10 +22,138 @@ #size-cells = <2>; ranges; + /* global cma region */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x00 0x38000000>; + linux,cma-default; + }; + secure_ddr: optee@9e800000 { reg = <0x00 0x9e800000 0x00 0x01800000>; no-map; }; + + mcu_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0000000 0x00 0x100000>; + no-map; + }; + + mcu_r5fss0_core0_memory_region: r5f-memory@a0100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0100000 0x00 0xf00000>; + no-map; + }; + + mcu_r5fss0_core1_dma_memory_region: r5f-dma-memory@a1000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1000000 0x00 0x100000>; + no-map; + }; + + mcu_r5fss0_core1_memory_region: r5f-memory@a1100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core0_dma_memory_region: r5f-dma-memory@a2000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core0_memory_region: r5f-memory@a2100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core1_dma_memory_region: r5f-dma-memory@a3000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core1_memory_region: r5f-memory@a3100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core0_dma_memory_region: r5f-dma-memory@a4000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core0_memory_region: r5f-memory@a4100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core1_dma_memory_region: r5f-dma-memory@a5000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa5000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core1_memory_region: r5f-memory@a5100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa5100000 0x00 0xf00000>; + no-map; + }; + + c71_0_dma_memory_region: c71-dma-memory@a6000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa6000000 0x00 0x100000>; + no-map; + }; + + c71_0_memory_region: c71-memory@a6100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa6100000 0x00 0xf00000>; + no-map; + }; + + c71_1_dma_memory_region: c71-dma-memory@a7000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa7000000 0x00 0x100000>; + no-map; + }; + + c71_1_memory_region: c71-memory@a7100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa7100000 0x00 0xf00000>; + no-map; + }; + + rtos_ipc_memory_region: ipc-memories@a8000000 { + reg = <0x00 0xa8000000 0x00 0x01c00000>; + alignment = <0x1000>; + no-map; + }; + }; +}; + +&wkup_pmx0 { + mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-pins { + pinctrl-single,pins = < + J721S2_WKUP_IOPAD(0x000, PIN_OUTPUT, 0) /* (D19) MCU_OSPI0_CLK */ + J721S2_WKUP_IOPAD(0x02c, PIN_OUTPUT, 0) /* (F15) MCU_OSPI0_CSn0 */ + J721S2_WKUP_IOPAD(0x00c, PIN_INPUT, 0) /* (C19) MCU_OSPI0_D0 */ + J721S2_WKUP_IOPAD(0x010, PIN_INPUT, 0) /* (F16) MCU_OSPI0_D1 */ + J721S2_WKUP_IOPAD(0x014, PIN_INPUT, 0) /* (G15) MCU_OSPI0_D2 */ + J721S2_WKUP_IOPAD(0x018, PIN_INPUT, 0) /* (F18) MCU_OSPI0_D3 */ + J721S2_WKUP_IOPAD(0x01c, PIN_INPUT, 0) /* (E19) MCU_OSPI0_D4 */ + J721S2_WKUP_IOPAD(0x020, PIN_INPUT, 0) /* (G19) MCU_OSPI0_D5 */ + J721S2_WKUP_IOPAD(0x024, PIN_INPUT, 0) /* (F19) MCU_OSPI0_D6 */ + J721S2_WKUP_IOPAD(0x028, PIN_INPUT, 0) /* (F20) MCU_OSPI0_D7 */ + J721S2_WKUP_IOPAD(0x008, PIN_INPUT, 0) /* (E18) MCU_OSPI0_DQS */ + >; }; }; @@ -49,3 +178,169 @@ reg = <0x51>; }; }; + +&ospi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_fss0_ospi0_pins_default>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0>; + spi-tx-bus-width = <8>; + spi-rx-bus-width = <8>; + spi-max-frequency = <25000000>; + cdns,tshsl-ns = <60>; + cdns,tsd2d-ns = <60>; + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <4>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "ospi.tiboot3"; + reg = <0x0 0x80000>; + }; + + partition@100000 { + label = "ospi.tispl"; + reg = <0x80000 0x200000>; + }; + + partition@300000 { + label = "ospi.u-boot"; + reg = <0x280000 0x400000>; + }; + + partition@700000 { + label = "ospi.env"; + reg = <0x680000 0x40000>; + }; + + partition@740000 { + label = "ospi.env.backup"; + reg = <0x6c0000 0x40000>; + }; + + partition@800000 { + label = "ospi.rootfs"; + reg = <0x800000 0x37c0000>; + }; + + partition@3fc0000 { + label = "ospi.phypattern"; + reg = <0x3fc0000 0x40000>; + }; + }; + }; +}; + +&mailbox0_cluster0 { + status = "okay"; + interrupts = <436>; + mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_mcu_r5fss0_core1: mbox-mcu-r5fss0-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster1 { + status = "okay"; + interrupts = <432>; + mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster2 { + status = "okay"; + interrupts = <428>; + mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster4 { + status = "okay"; + interrupts = <420>; + mbox_c71_0: mbox-c71-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_c71_1: mbox-c71-1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mcu_r5fss0_core0 { + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>; + memory-region = <&mcu_r5fss0_core0_dma_memory_region>, + <&mcu_r5fss0_core0_memory_region>; +}; + +&mcu_r5fss0_core1 { + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>; + memory-region = <&mcu_r5fss0_core1_dma_memory_region>, + <&mcu_r5fss0_core1_memory_region>; +}; + +&main_r5fss0_core0 { + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>; + memory-region = <&main_r5fss0_core0_dma_memory_region>, + <&main_r5fss0_core0_memory_region>; +}; + +&main_r5fss0_core1 { + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>; + memory-region = <&main_r5fss0_core1_dma_memory_region>, + <&main_r5fss0_core1_memory_region>; +}; + +&main_r5fss1_core0 { + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>; + memory-region = <&main_r5fss1_core0_dma_memory_region>, + <&main_r5fss1_core0_memory_region>; +}; + +&main_r5fss1_core1 { + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>; + memory-region = <&main_r5fss1_core1_dma_memory_region>, + <&main_r5fss1_core1_memory_region>; +}; + +&c71_0 { + status = "okay"; + mboxes = <&mailbox0_cluster4 &mbox_c71_0>; + memory-region = <&c71_0_dma_memory_region>, + <&c71_0_memory_region>; +}; + +&c71_1 { + status = "okay"; + mboxes = <&mailbox0_cluster4 &mbox_c71_1>; + memory-region = <&c71_1_dma_memory_region>, + <&c71_1_memory_region>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso b/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso --- a/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Arducam V3Link UC-A09 board + * https://www.arducam.com/fpd-link-3-cameras/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&csi_mux { + idle-state = <1>; +}; + +&cam0_i2c { + #address-cells = <1>; + #size-cells = <0>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; + +&cam1_i2c { + #address-cells = <1>; + #size-cells = <0>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy1 { + status = "okay"; +}; \ No newline at end of file diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-ov5640.dtso --- a/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-ov5640.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-ov5640.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for OV5640 Camera module on MIPI CSI connector for AM69 SK board. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&cam0_i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + powerdown-gpios = <&exp2 2 GPIO_ACTIVE_LOW>; + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am69-sk.dts b/arch/arm64/boot/dts/ti/k3-am69-sk.dts --- a/arch/arm64/boot/dts/ti/k3-am69-sk.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-am69-sk.dts 2024-07-07 20:37:34.632306489 -0400 @@ -1,6 +1,6 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* - * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ * * Design Files: https://www.ti.com/lit/zip/SPRR466 * TRM: https://www.ti.com/lit/zip/spruj52 @@ -33,9 +33,10 @@ memory@80000000 { device_type = "memory"; + bootph-all; /* 32G RAM */ - reg = <0x00 0x80000000 0x00 0x80000000>, - <0x08 0x80000000 0x07 0x80000000>; + reg = <0x00000000 0x80000000 0x00000000 0x80000000>, + <0x00000008 0x80000000 0x00000007 0x80000000>; }; reserved_memory: reserved-memory { @@ -43,10 +44,162 @@ #size-cells = <2>; ranges; + /* global cma region */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x00 0x70000000>; + linux,cma-default; + }; + secure_ddr: optee@9e800000 { reg = <0x00 0x9e800000 0x00 0x01800000>; no-map; }; + + mcu_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0000000 0x00 0x100000>; + no-map; + }; + + mcu_r5fss0_core0_memory_region: r5f-memory@a0100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0100000 0x00 0xf00000>; + no-map; + }; + + mcu_r5fss0_core1_dma_memory_region: r5f-dma-memory@a1000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1000000 0x00 0x100000>; + no-map; + }; + + mcu_r5fss0_core1_memory_region: r5f-memory@a1100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core0_dma_memory_region: r5f-dma-memory@a2000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core0_memory_region: r5f-memory@a2100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core1_dma_memory_region: r5f-dma-memory@a3000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core1_memory_region: r5f-memory@a3100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core0_dma_memory_region: r5f-dma-memory@a4000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core0_memory_region: r5f-memory@a4100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core1_dma_memory_region: r5f-dma-memory@a5000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa5000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core1_memory_region: r5f-memory@a5100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa5100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss2_core0_dma_memory_region: r5f-dma-memory@a6000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa6000000 0x00 0x100000>; + no-map; + }; + + main_r5fss2_core0_memory_region: r5f-memory@a6100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa6100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss2_core1_dma_memory_region: r5f-dma-memory@a7000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa7000000 0x00 0x100000>; + no-map; + }; + + main_r5fss2_core1_memory_region: r5f-memory@a7100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa7100000 0x00 0xf00000>; + no-map; + }; + + c71_0_dma_memory_region: c71-dma-memory@a8000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa8000000 0x00 0x100000>; + no-map; + }; + + c71_0_memory_region: c71-memory@a8100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa8100000 0x00 0xf00000>; + no-map; + }; + + c71_1_dma_memory_region: c71-dma-memory@a9000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa9000000 0x00 0x100000>; + no-map; + }; + + c71_1_memory_region: c71-memory@a9100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa9100000 0x00 0xf00000>; + no-map; + }; + + c71_2_dma_memory_region: c71-dma-memory@aa000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xaa000000 0x00 0x100000>; + no-map; + }; + + c71_2_memory_region: c71-memory@aa100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xaa100000 0x00 0xf00000>; + no-map; + }; + + c71_3_dma_memory_region: c71-dma-memory@ab000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xab000000 0x00 0x100000>; + no-map; + }; + + c71_3_memory_region: c71-memory@ab100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xab100000 0x00 0xf00000>; + no-map; + }; }; vusb_main: regulator-vusb-main5v0 { @@ -107,6 +260,108 @@ states = <1800000 0x0>, <3300000 0x1>; }; + + dp0_pwr_3v3: regulator-dp0-pwr { + compatible = "regulator-fixed"; + regulator-name = "dp0-pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + pinctrl-names = "default"; + pinctrl-0 = <&dp_pwr_en_pins_default>; + gpio = <&main_gpio0 4 0>; /* DP0_3V3 _EN */ + enable-active-high; + }; + + dp0: connector-dp0 { + compatible = "dp-connector"; + label = "DP0"; + type = "full-size"; + dp-pwr-supply = <&dp0_pwr_3v3>; + + port { + dp0_connector_in: endpoint { + remote-endpoint = <&dp0_out>; + }; + }; + }; + + connector-hdmi { + compatible = "hdmi-connector"; + label = "hdmi"; + type = "a"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_hpd_pins_default>; + ddc-i2c-bus = <&mcu_i2c1>; + hpd-gpios = <&main_gpio0 0 GPIO_ACTIVE_HIGH>; /* HDMI_HPD */ + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; + }; + + bridge-dvi { + compatible = "ti,tfp410"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_pdn_pins_default>; + powerdown-gpios = <&wkup_gpio0 14 GPIO_ACTIVE_LOW>; /* HDMI_PDn */ + ti,deskew = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint { + remote-endpoint = <&dpi1_out0>; + pclk-sample = <1>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; + + csi_mux: mux-controller { + compatible = "gpio-mux"; + #mux-state-cells = <1>; + mux-gpios = <&exp2 1 GPIO_ACTIVE_HIGH>; + idle-state = <0>; + }; + + transceiver1: can-phy0 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; + + transceiver2: can-phy1 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; + + transceiver3: can-phy2 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; + + transceiver4: can-phy3 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; + }; &main_pmx0 { @@ -126,6 +381,13 @@ >; }; + main_i2c1_pins_default: main-i2c1-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x0ac, PIN_INPUT_PULLUP, 13) /* (AE34) MCASP0_AXR15.I2C1_SCL */ + J784S4_IOPAD(0x0b0, PIN_INPUT_PULLUP, 13) /* (AL33) MCASP1_AXR3.I2C1_SDA */ + >; + }; + main_mmc1_pins_default: main-mmc1-default-pins { bootph-all; pinctrl-single,pins = < @@ -164,10 +426,108 @@ J784S4_IOPAD(0x004, PIN_INPUT, 7) /* (AG36) MCAN12_TX.GPIO0_1 */ >; }; + + dp0_pins_default: dp0-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x014, PIN_INPUT, 13) /* (AG33) MCAN14_TX.DP0_HPD */ + >; + }; + + dp_pwr_en_pins_default: dp-pwr-en-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x010, PIN_INPUT, 7) /* (AH33) MCAN13_RX.GPIO0_4 */ + >; + }; + + dss_vout0_pins_default: dss-vout0-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x074, PIN_OUTPUT, 2) /* (AC33) MCAN2_TX.VOUT0_DATA0 */ + J784S4_IOPAD(0x070, PIN_OUTPUT, 2) /* (AH38) MCAN1_RX.VOUT0_DATA1 */ + J784S4_IOPAD(0x07c, PIN_OUTPUT, 2) /* (AJ38) MCASP0_AXR3.VOUT0_DATA2 */ + J784S4_IOPAD(0x068, PIN_OUTPUT, 2) /* (AE38) MCAN0_RX.VOUT0_DATA3 */ + J784S4_IOPAD(0x064, PIN_OUTPUT, 2) /* (AF38) MCAN0_TX.VOUT0_DATA4 */ + J784S4_IOPAD(0x060, PIN_OUTPUT, 2) /* (AE36) MCASP2_AXR1.VOUT0_DATA5 */ + J784S4_IOPAD(0x05c, PIN_OUTPUT, 2) /* (AC36) MCASP2_AXR0.VOUT0_DATA6 */ + J784S4_IOPAD(0x058, PIN_OUTPUT, 2) /* (AE37) MCASP2_AFSX.VOUT0_DATA7 */ + J784S4_IOPAD(0x054, PIN_OUTPUT, 2) /* (AD37) MCASP2_ACLKX.VOUT0_DATA8 */ + J784S4_IOPAD(0x050, PIN_OUTPUT, 2) /* (AC37) MCASP1_AXR2.VOUT0_DATA9 */ + J784S4_IOPAD(0x04c, PIN_OUTPUT, 2) /* (AC32) MCASP1_AXR1.VOUT0_DATA10 */ + J784S4_IOPAD(0x048, PIN_OUTPUT, 2) /* (AK33) MCASP0_AXR2.VOUT0_DATA11 */ + J784S4_IOPAD(0x044, PIN_OUTPUT, 2) /* (AG37) MCASP0_AXR1.VOUT0_DATA12 */ + J784S4_IOPAD(0x040, PIN_OUTPUT, 2) /* (AF37) MCASP0_AXR0.VOUT0_DATA13 */ + J784S4_IOPAD(0x03c, PIN_OUTPUT, 2) /* (AK38) MCASP0_AFSX.VOUT0_DATA14 */ + J784S4_IOPAD(0x038, PIN_OUTPUT, 2) /* (AK35) MCASP0_ACLKX.VOUT0_DATA15 */ + J784S4_IOPAD(0x0c8, PIN_OUTPUT, 2) /* (AJ32) EXT_REFCLK1.VOUT0_DATA16 */ + J784S4_IOPAD(0x030, PIN_OUTPUT, 2) /* (AK37) GPIO0_12.VOUT0_DATA17 */ + J784S4_IOPAD(0x02c, PIN_OUTPUT, 2) /* (AL32) GPIO0_11.VOUT0_DATA18 */ + J784S4_IOPAD(0x028, PIN_OUTPUT, 2) /* (AE33) MCAN16_RX.VOUT0_DATA19 */ + J784S4_IOPAD(0x024, PIN_OUTPUT, 2) /* (AH34) MCAN16_TX.VOUT0_DATA20 */ + J784S4_IOPAD(0x020, PIN_OUTPUT, 2) /* (AJ35) MCAN15_RX.VOUT0_DATA21 */ + J784S4_IOPAD(0x01c, PIN_OUTPUT, 2) /* (AG34) MCAN15_TX.VOUT0_DATA22 */ + J784S4_IOPAD(0x018, PIN_OUTPUT, 2) /* (AK36) MCAN14_RX.VOUT0_DATA23 */ + J784S4_IOPAD(0x084, PIN_OUTPUT, 2) /* (AG38) MCASP0_AXR5.VOUT0_DE */ + J784S4_IOPAD(0x080, PIN_OUTPUT, 2) /* (AK34) MCASP0_AXR4.VOUT0_HSYNC */ + J784S4_IOPAD(0x078, PIN_OUTPUT, 2) /* (AH37) MCAN2_RX.VOUT0_PCLK */ + J784S4_IOPAD(0x088, PIN_OUTPUT, 2) /* (AF36) MCASP0_AXR6.VOUT0_VSYNC */ + >; + }; + + hdmi_hpd_pins_default: hdmi-hpd-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x000, PIN_INPUT, 7) /* (AN35) EXTINTN.GPIO0_0 */ + >; + }; + + main_mcan6_pins_default: main-mcan6-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x098, PIN_INPUT, 0) /* (AH36) MCAN6_RX */ + J784S4_IOPAD(0x094, PIN_OUTPUT, 0) /* (AG35) MCAN6_TX */ + >; + }; + + main_mcan7_pins_default: main-mcan7-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x0A0, PIN_INPUT, 0) /* (AD34) MCAN7_RX */ + J784S4_IOPAD(0x09C, PIN_OUTPUT, 0) /* (AF35) MCAN7_TX */ + >; + }; + + main_usbss0_pins_default: main-usbss0-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x0EC, PIN_OUTPUT, 6) /* (AN37) TIMER_IO1.USB0_DRVVBUS */ + >; + }; + +}; + +&wkup_pmx0 { + bootph-all; + mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x000, PIN_OUTPUT, 0) /* (E32) MCU_OSPI0_CLK */ + J784S4_WKUP_IOPAD(0x02c, PIN_OUTPUT, 0) /* (A32) MCU_OSPI0_CSn0 */ + J784S4_WKUP_IOPAD(0x00c, PIN_INPUT, 0) /* (B33) MCU_OSPI0_D0 */ + J784S4_WKUP_IOPAD(0x010, PIN_INPUT, 0) /* (B32) MCU_OSPI0_D1 */ + J784S4_WKUP_IOPAD(0x014, PIN_INPUT, 0) /* (C33) MCU_OSPI0_D2 */ + J784S4_WKUP_IOPAD(0x018, PIN_INPUT, 0) /* (C35) MCU_OSPI0_D3 */ + J784S4_WKUP_IOPAD(0x01c, PIN_INPUT, 0) /* (D33) MCU_OSPI0_D4 */ + J784S4_WKUP_IOPAD(0x020, PIN_INPUT, 0) /* (D34) MCU_OSPI0_D5 */ + J784S4_WKUP_IOPAD(0x024, PIN_INPUT, 0) /* (E34) MCU_OSPI0_D6 */ + J784S4_WKUP_IOPAD(0x028, PIN_INPUT, 0) /* (E33) MCU_OSPI0_D7 */ + J784S4_WKUP_IOPAD(0x008, PIN_INPUT, 0) /* (C34) MCU_OSPI0_DQS */ + >; + }; }; &wkup_pmx2 { bootph-all; + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + /* (AA37) MCU_ADC1_AIN4.WKUP_GPIO0_83 */ + J784S4_WKUP_IOPAD(0x0fc, PIN_INPUT, 7) + >; + }; + wkup_uart0_pins_default: wkup-uart0-default-pins { bootph-all; pinctrl-single,pins = < @@ -238,6 +598,36 @@ J784S4_WKUP_IOPAD(0x11c, PIN_INPUT, 7) /* (M34) WKUP_GPIO0_67 */ >; }; + + mcu_i2c1_pins_default: mcu-i2c1-default-pins { + pinctrl-single,pins = < + /* (L35) WKUP_GPIO0_8.MCU_I2C1_SCL */ + J784S4_WKUP_IOPAD(0x078, PIN_INPUT_PULLUP, 0) + /* (L34) WKUP_GPIO0_9.MCU_I2C1_SDA */ + J784S4_WKUP_IOPAD(0x07c, PIN_INPUT_PULLUP, 0) + >; + }; + + hdmi_pdn_pins_default: hdmi-pdn-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x090, PIN_INPUT, 7) /* (H37) WKUP_GPIO0_14 */ + >; + }; + + mcu_mcan0_pins_default: mcu-mcan0-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x054, PIN_INPUT, 0) /* (F38) MCU_MCAN0_RX */ + J784S4_WKUP_IOPAD(0x050, PIN_OUTPUT, 0) /* (K33) MCU_MCAN0_TX */ + >; + }; + + mcu_mcan1_pins_default: mcu-mcan1-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x06c, PIN_INPUT, 0) /* (K36) WKUP_GPIO0_5.MCU_MCAN1_RX */ + J784S4_WKUP_IOPAD(0x068, PIN_OUTPUT, 0)/* (H35) WKUP_GPIO0_4.MCU_MCAN1_TX */ + >; + }; + }; &wkup_pmx3 { @@ -248,6 +638,90 @@ }; }; +&mailbox0_cluster0 { + status = "okay"; + interrupts = <436>; + mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_mcu_r5fss0_core1: mbox-mcu-r5fss0-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster1 { + status = "okay"; + interrupts = <432>; + mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster2 { + status = "okay"; + interrupts = <428>; + mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster3 { + status = "okay"; + interrupts = <424>; + mbox_main_r5fss2_core0: mbox-main-r5fss2-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_main_r5fss2_core1: mbox-main-r5fss2-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster4 { + status = "okay"; + interrupts = <420>; + mbox_c71_0: mbox-c71-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_c71_1: mbox-c71-1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster5 { + status = "okay"; + interrupts = <416>; + mbox_c71_2: mbox-c71-2 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_c71_3: mbox-c71-3 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + &wkup_uart0 { /* Firmware usage */ status = "reserved"; @@ -267,6 +741,114 @@ compatible = "atmel,24c512"; reg = <0x51>; }; + + tps659413: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <83 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck12-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka12: buck12 { + regulator-name = "vdd_ddr_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka3: buck3 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka4: buck4 { + regulator-name = "vdd_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka5: buck5 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vdd_mcuio_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vds_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + tps62873a: regulator@40 { + compatible = "ti,tps62873"; + reg = <0x40>; + bootph-pre-ram; + regulator-name = "VDD_CPU_AVS"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + regulator-always-on; + }; + + tps62873b: regulator@43 { + compatible = "ti,tps62873"; + reg = <0x43>; + regulator-name = "VDD_CORE_0V8"; + regulator-min-microvolt = <760000>; + regulator-max-microvolt = <840000>; + regulator-boot-on; + regulator-always-on; + }; }; &wkup_gpio0 { @@ -307,7 +889,7 @@ reg = <0x21>; gpio-controller; #gpio-cells = <2>; - gpio-line-names = "BOARDID_EEPROM_WP", "CAN_STB", "GPIO_uSD_PWR_EN", + gpio-line-names = "BOARDID_EEPROM_WP", "CAN_STB", "GPIO_uSD_PWR_EN", "IO_EXP_MCU_RGMII_RST#", "IO_EXP_PCIe0_4L_PERST#", "IO_EXP_PCIe1_M.2_RTSz", "IO_EXP_PCIe3_M.2_RTSz", "PM_INA_BUS_EN", "ENET1_EXP_PWRDN", "EXP1_ENET_RSTz", @@ -316,6 +898,42 @@ }; }; +&main_i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_pins_default>; + clock-frequency = <400000>; + status = "okay"; + + exp2: gpio@21 { + compatible = "ti,tca6408"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "CSI_VIO_SEL", "CSI_MUX_SEL_2", "CSI2_RSTz", + "IO_EXP_CAM0_GPIO1", "IO_EXP_CAM1_GPIO1"; + }; + + i2c-mux@70 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + + cam0_i2c: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + cam1_i2c: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + }; +}; + &main_sdhci0 { bootph-all; /* eMMC */ @@ -362,3 +980,357 @@ phy-mode = "rgmii-rxid"; phy-handle = <&mcu_phy0>; }; + +&mcu_r5fss0_core0 { + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>; + memory-region = <&mcu_r5fss0_core0_dma_memory_region>, + <&mcu_r5fss0_core0_memory_region>; +}; + +&mcu_r5fss0_core1 { + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>; + memory-region = <&mcu_r5fss0_core1_dma_memory_region>, + <&mcu_r5fss0_core1_memory_region>; +}; + +&main_r5fss0_core0 { + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>; + memory-region = <&main_r5fss0_core0_dma_memory_region>, + <&main_r5fss0_core0_memory_region>; +}; + +&main_r5fss0_core1 { + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>; + memory-region = <&main_r5fss0_core1_dma_memory_region>, + <&main_r5fss0_core1_memory_region>; +}; + +&main_r5fss1_core0 { + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>; + memory-region = <&main_r5fss1_core0_dma_memory_region>, + <&main_r5fss1_core0_memory_region>; +}; + +&main_r5fss1_core1 { + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>; + memory-region = <&main_r5fss1_core1_dma_memory_region>, + <&main_r5fss1_core1_memory_region>; +}; + +&main_r5fss2_core0 { + mboxes = <&mailbox0_cluster3 &mbox_main_r5fss2_core0>; + memory-region = <&main_r5fss2_core0_dma_memory_region>, + <&main_r5fss2_core0_memory_region>; +}; + +&main_r5fss2_core1 { + mboxes = <&mailbox0_cluster3 &mbox_main_r5fss2_core1>; + memory-region = <&main_r5fss2_core1_dma_memory_region>, + <&main_r5fss2_core1_memory_region>; +}; + +&c71_0 { + status = "okay"; + mboxes = <&mailbox0_cluster4 &mbox_c71_0>; + memory-region = <&c71_0_dma_memory_region>, + <&c71_0_memory_region>; +}; + +&c71_1 { + status = "okay"; + mboxes = <&mailbox0_cluster4 &mbox_c71_1>; + memory-region = <&c71_1_dma_memory_region>, + <&c71_1_memory_region>; +}; + +&c71_2 { + status = "okay"; + mboxes = <&mailbox0_cluster5 &mbox_c71_2>; + memory-region = <&c71_2_dma_memory_region>, + <&c71_2_memory_region>; +}; + +&c71_3 { + status = "okay"; + mboxes = <&mailbox0_cluster5 &mbox_c71_3>; + memory-region = <&c71_3_dma_memory_region>, + <&c71_3_memory_region>; +}; + +&wkup_gpio_intr { + status = "okay"; +}; + +&mcu_i2c1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_i2c1_pins_default>; + clock-frequency = <100000>; +}; + +&serdes_refclk { + status = "okay"; + clock-frequency = <100000000>; +}; + +&dss { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&dss_vout0_pins_default>; + assigned-clocks = <&k3_clks 218 2>, + <&k3_clks 218 5>; + assigned-clock-parents = <&k3_clks 218 3>, + <&k3_clks 218 7>; +}; + +&serdes_wiz4 { + status = "okay"; +}; + +&serdes4 { + status = "okay"; + serdes4_dp_link: phy@0 { + reg = <0>; + cdns,num-lanes = <4>; + #phy-cells = <0>; + cdns,max-bit-rate = <2700>; + cdns,phy-type = ; + resets = <&serdes_wiz4 1>, <&serdes_wiz4 2>, + <&serdes_wiz4 3>, <&serdes_wiz4 4>; + }; +}; + +&mhdp { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&dp0_pins_default>; + phys = <&serdes4_dp_link>; + phy-names = "dpphy"; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* DP */ + port@0 { + reg = <0>; + + dpi0_out: endpoint { + remote-endpoint = <&dp0_in>; + }; + }; + + /* HDMI */ + port@1 { + reg = <1>; + + dpi1_out0: endpoint { + remote-endpoint = <&tfp410_in>; + }; + }; +}; + +&dp0_ports { + + port@0 { + reg = <0>; + + dp0_in: endpoint { + remote-endpoint = <&dpi0_out>; + }; + }; + + port@4 { + reg = <4>; + + dp0_out: endpoint { + remote-endpoint = <&dp0_connector_in>; + }; + }; +}; + +&mcu_mcan0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_pins_default>; + phys = <&transceiver1>; +}; + +&mcu_mcan1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan1_pins_default>; + phys = <&transceiver2>; +}; + +&main_mcan6 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan6_pins_default>; + phys = <&transceiver3>; +}; + +&main_mcan7 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan7_pins_default>; + phys = <&transceiver4>; +}; + +&ospi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_fss0_ospi0_pins_default>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0>; + spi-tx-bus-width = <8>; + spi-rx-bus-width = <8>; + spi-max-frequency = <25000000>; + cdns,tshsl-ns = <60>; + cdns,tsd2d-ns = <60>; + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <4>; + + partitions { + bootph-all; + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "ospi.tiboot3"; + reg = <0x0 0x100000>; + }; + + partition@100000 { + label = "ospi.tispl"; + reg = <0x100000 0x200000>; + }; + + partition@300000 { + label = "ospi.u-boot"; + reg = <0x300000 0x400000>; + }; + + partition@700000 { + label = "ospi.env"; + reg = <0x700000 0x40000>; + }; + + partition@740000 { + label = "ospi.env.backup"; + reg = <0x740000 0x40000>; + }; + + partition@800000 { + label = "ospi.rootfs"; + reg = <0x800000 0x37c0000>; + }; + + partition@3fc0000 { + bootph-pre-ram; + label = "ospi.phypattern"; + reg = <0x3fc0000 0x40000>; + }; + }; + }; +}; + +&serdes_ln_ctrl { + idle-states = , , + , , + , , + , ; +}; + +&serdes_wiz0 { + status = "okay"; +}; + +&serdes0 { + status = "okay"; + serdes0_pcie_link1: phy@0 { + reg = <0>; + cdns,num-lanes = <2>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 1>, <&serdes_wiz0 2>; + }; + + serdes0_pcie_link2: phy@2 { + reg = <2>; + cdns,num-lanes = <1>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 3>; + }; + + serdes0_usb_link: phy@3 { + reg = <3>; + cdns,num-lanes = <1>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 4>; + }; +}; + +&serdes_wiz1 { + status = "okay"; +}; + +&serdes1 { + status = "okay"; + serdes1_pcie_link: phy@0 { + reg = <0>; + cdns,num-lanes = <4>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz1 1>, <&serdes_wiz1 2>, <&serdes_wiz1 3>, <&serdes_wiz1 4>; + }; +}; + +&pcie0_rc { + status = "okay"; + reset-gpios = <&exp1 4 GPIO_ACTIVE_HIGH>; + phys = <&serdes1_pcie_link>; + phy-names = "pcie-phy"; +}; + +&pcie1_rc { + status = "okay"; + reset-gpios = <&exp1 5 GPIO_ACTIVE_HIGH>; + phys = <&serdes0_pcie_link1>; + phy-names = "pcie-phy"; + num-lanes = <2>; +}; + +&pcie3_rc { + status = "okay"; + reset-gpios = <&exp1 6 GPIO_ACTIVE_HIGH>; + phys = <&serdes0_pcie_link2>; + phy-names = "pcie-phy"; + num-lanes = <1>; +}; + +&usb_serdes_mux { + idle-states = <0>; /* USB0 to SERDES0 */ +}; + +&usbss0 { + status = "okay"; + pinctrl-0 = <&main_usbss0_pins_default>; + pinctrl-names = "default"; + ti,vbus-divider; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; + maximum-speed = "super-speed"; + phys = <&serdes0_usb_link>; + phy-names = "cdns3,usb3-phy"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso b/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso --- a/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Fusion (FPD-Link III) board on AM69 SK CSI2 Aux Port + * https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +&{/} { + clk_fusion1_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&cam1_i2c { + #address-cells = <1>; + #size-cells = <0>; + + deser@3d { + compatible = "ti,ds90ub960-q1"; + reg = <0x3d>; + clocks = <&clk_fusion1_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x6a 0x6b 0x6c 0x6d 0x6e 0x6f>; + + ds90ub960_2_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX*/ + port@4 { + reg = <4>; + ds90ub960_2_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy2>; + }; + }; + }; + + ds90ub960_2_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; + +&cdns_csi2rx2 { + ports { + port@0 { + status = "okay"; + + csi2_phy2: endpoint { + remote-endpoint = <&ds90ub960_2_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx2 { + status = "okay"; +}; + +&dphy_rx2 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-am69-sk-rpi-hdr-ehrpwm.dtso b/arch/arm64/boot/dts/ti/k3-am69-sk-rpi-hdr-ehrpwm.dtso --- a/arch/arm64/boot/dts/ti/k3-am69-sk-rpi-hdr-ehrpwm.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-am69-sk-rpi-hdr-ehrpwm.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for enabling EHRPWMs on RPi expansion header on AM69 SK board. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include "k3-pinctrl.h" + +&main_pmx0 { + rpi_header_gpio0_pins_default: rpi-header-gpio0-pins-default { + pinctrl-single,pins = < + J784S4_IOPAD(0x0bc, PIN_INPUT, 7) /* (AD33) MCASP1_AFSX.GPIO0_47 */ + J784S4_IOPAD(0x06c, PIN_INPUT, 7) /* (AJ37) MCASP4_AFSX.GPIO0_27 */ + J784S4_IOPAD(0x0b4, PIN_INPUT, 7) /* (AL34) MCASP1_AXR4.GPIO0_45 */ + J784S4_IOPAD(0x0c0, PIN_INPUT, 7) /* (AD38) MCASP1_AXR0.GPIO0_48 */ + J784S4_IOPAD(0x00c, PIN_INPUT, 7) /* (AF33) MCAN13_TX.GPIO0_3 */ + J784S4_IOPAD(0x0b8, PIN_INPUT, 7) /* (AC34) MCASP1_ACLKX.GPIO0_46 */ + J784S4_IOPAD(0x090, PIN_INPUT, 7) /* (AC35) MCASP0_AXR8.GPIO0_36 */ + J784S4_IOPAD(0x0a8, PIN_INPUT, 7) /* (AF34) MCASP0_AXR14.GPIO0_42 */ + J784S4_IOPAD(0x034, PIN_INPUT, 7) /* (AJ34) PMIC_WAKE0n.GPIO0_13 */ + J784S4_IOPAD(0x008, PIN_INPUT, 7) /* (AJ33) MCAN12_RX.GPIO0_2 */ + J784S4_IOPAD(0x004, PIN_INPUT, 7) /* (AG36) MCAN12_TX.GPIO0_1 */ + >; + }; + + rpi_header_ehrpwm0_pins_default: rpi-header-ehrpwm0-pins-default { + pinctrl-single,pins = < + J784S4_IOPAD(0x0cc, PIN_INPUT, 5) /* (AM37) SPI0_CS0.EHRPWM0_A */ + >; + }; + + rpi_header_ehrpwm3_pins_default: rpi-header-ehrpwm3-pins-default { + pinctrl-single,pins = < + J784S4_IOPAD(0x08c, PIN_INPUT, 9) /* (AE35) MCASP0_AXR7.EHRPWM3_A */ + >; + }; + + rpi_header_ehrpwm4_pins_default: rpi-header-ehrpwm4-pins-default { + pinctrl-single,pins = < + J784S4_IOPAD(0x0a4, PIN_INPUT, 9) /* (AJ36) MCASP0_AXR13.EHRPWM4_A */ + >; + }; +}; + +&main_ehrpwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm0_pins_default>; + status = "okay"; +}; + +&main_ehrpwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm3_pins_default>; + status = "okay"; +}; + +&main_ehrpwm4 { + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm4_pins_default>; + status = "okay"; +}; + +&main_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_gpio0_pins_default>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-0.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-0.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-0.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 0 */ + port@0 { + reg = <0>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@0 { + reg = <0>; + i2c-alias = <0x44>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-1.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-1.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-1.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-1.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 1 */ + port@1 { + reg = <1>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@1 { + reg = <1>; + i2c-alias = <0x45>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-2.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-2.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-2.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 2 */ + port@2 { + reg = <2>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@2 { + reg = <2>; + i2c-alias = <0x46>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-3.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-3.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-3.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-0-3.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 3 */ + port@3 { + reg = <3>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@3 { + reg = <3>; + i2c-alias = <0x47>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-0.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-0.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-0.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_1_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 0 */ + port@0 { + reg = <0>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_1_links { + #address-cells = <1>; + #size-cells = <0>; + + link@0 { + reg = <0>; + i2c-alias = <0x54>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-1.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-1.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-1.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-1.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_1_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 1 */ + port@1 { + reg = <1>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_1_links { + #address-cells = <1>; + #size-cells = <0>; + + link@1 { + reg = <1>; + i2c-alias = <0x55>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-2.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-2.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-2.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_1_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 2 */ + port@2 { + reg = <2>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_1_links { + #address-cells = <1>; + #size-cells = <0>; + + link@2 { + reg = <2>; + i2c-alias = <0x56>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-3.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-3.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-3.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-1-3.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_1_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 3 */ + port@3 { + reg = <3>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_1_links { + #address-cells = <1>; + #size-cells = <0>; + + link@3 { + reg = <3>; + i2c-alias = <0x57>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_2_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 0 */ + port@0 { + reg = <0>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_2_links { + #address-cells = <1>; + #size-cells = <0>; + + link@0 { + reg = <0>; + i2c-alias = <0x64>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_2_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 1 */ + port@1 { + reg = <1>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_2_links { + #address-cells = <1>; + #size-cells = <0>; + + link@1 { + reg = <1>; + i2c-alias = <0x65>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_2_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 2 */ + port@2 { + reg = <2>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_2_links { + #address-cells = <1>; + #size-cells = <0>; + + link@2 { + reg = <2>; + i2c-alias = <0x66>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_2_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 3 */ + port@3 { + reg = <3>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_2_links { + #address-cells = <1>; + #size-cells = <0>; + + link@3 { + reg = <3>; + i2c-alias = <0x67>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 0 */ + port@0 { + reg = <0>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@0 { + reg = <0>; + i2c-alias = <0x44>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2>; + /*clock-noncontinuous;*/ + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@60 { + compatible = "ovti,ov2312"; + reg = <0x60>; + + clocks = <&serializer>; + clock-names = "xvclk"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <24000000>; + + reset-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 1 */ + port@1 { + reg = <1>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@1 { + reg = <1>; + i2c-alias = <0x45>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2>; + /*clock-noncontinuous;*/ + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@60 { + compatible = "ovti,ov2312"; + reg = <0x60>; + + clocks = <&serializer>; + clock-names = "xvclk"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <24000000>; + + reset-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 2 */ + port@2 { + reg = <2>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@2 { + reg = <2>; + i2c-alias = <0x46>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2>; + /*clock-noncontinuous;*/ + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@60 { + compatible = "ovti,ov2312"; + reg = <0x60>; + + clocks = <&serializer>; + clock-names = "xvclk"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <24000000>; + + reset-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso --- a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 3 */ + port@3 { + reg = <3>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@3 { + reg = <3>; + i2c-alias = <0x47>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2>; + /*clock-noncontinuous;*/ + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@60 { + compatible = "ovti,ov2312"; + reg = <0x60>; + + clocks = <&serializer>; + clock-names = "xvclk"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <24000000>; + + reset-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts --- a/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts 2024-07-07 20:37:34.632306489 -0400 @@ -88,6 +88,34 @@ states = <1800000 0x0>, <3300000 0x1>; }; + + transceiver1: can-phy1 { + compatible = "ti,tcan1043"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_gpio_pins_default>; + standby-gpios = <&wkup_gpio0 58 GPIO_ACTIVE_LOW>; + enable-gpios = <&wkup_gpio0 0 GPIO_ACTIVE_HIGH>; + }; + + transceiver2: can-phy2 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan1_gpio_pins_default>; + standby-gpios = <&wkup_gpio0 2 GPIO_ACTIVE_HIGH>; + }; + + transceiver3: can-phy3 { + compatible = "ti,tcan1043"; + #phy-cells = <0>; + max-bitrate = <5000000>; + standby-gpios = <&exp2 7 GPIO_ACTIVE_LOW>; + enable-gpios = <&exp2 6 GPIO_ACTIVE_HIGH>; + mux-states = <&mux0 1>; + }; }; &wkup_pmx0 { @@ -139,6 +167,33 @@ J721E_WKUP_IOPAD(0x0030, PIN_INPUT, 0) /* (L4) MCU_MDIO0_MDIO */ >; }; + + mcu_mcan0_pins_default: mcu-mcan0-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x54, PIN_INPUT, 0) /* (A17) MCU_MCAN0_RX */ + J721E_WKUP_IOPAD(0x50, PIN_OUTPUT, 0) /* (A16) MCU_MCAN0_TX */ + >; + }; + + mcu_mcan1_pins_default: mcu-mcan1-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x6c, PIN_INPUT, 0) /* (B16) WKUP_GPIO0_5.MCU_MCAN1_RX */ + J721E_WKUP_IOPAD(0x68, PIN_OUTPUT, 0) /* (D13) WKUP_GPIO0_4.MCU_MCAN1_TX */ + >; + }; + + mcu_mcan0_gpio_pins_default: mcu-mcan0-gpio-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x58, PIN_INPUT, 7) /* (B18) WKUP_GPIO0_0 */ + J721E_WKUP_IOPAD(0x40, PIN_INPUT, 7) /* (B17) MCU_SPI0_D1 */ + >; + }; + + mcu_mcan1_gpio_pins_default: mcu-mcan1-gpio-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x60, PIN_INPUT, 7) /* (D14) WKUP_GPIO0_2 */ + >; + }; }; &main_pmx0 { @@ -190,6 +245,13 @@ J721E_IOPAD(0xd0, PIN_OUTPUT, 7) /* (T5) SPI0_D1.GPIO0_55 */ >; }; + + main_mcan3_pins_default: main-mcan3-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x3c, PIN_INPUT, 0) /* (W16) MCAN3_RX */ + J721E_IOPAD(0x38, PIN_OUTPUT, 0) /* (Y21) MCAN3_TX */ + >; + }; }; &main_pmx1 { @@ -253,6 +315,11 @@ &mcu_cpsw { pinctrl-names = "default"; pinctrl-0 = <&mcu_cpsw_pins_default>, <&mcu_mdio_pins_default>; + + cpts@3d000 { + /* Map HW4_TS_PUSH to GENF1 */ + ti,pps = <3 1>; + }; }; &davinci_mdio { @@ -382,15 +449,46 @@ }; &pcie1_rc { + status = "okay"; reset-gpios = <&exp1 2 GPIO_ACTIVE_HIGH>; phys = <&serdes0_pcie_link>; phy-names = "pcie-phy"; num-lanes = <2>; }; -&pcie1_ep { - phys = <&serdes0_pcie_link>; - phy-names = "pcie-phy"; - num-lanes = <2>; - status = "disabled"; +&mcu_mcan0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_pins_default>; + phys = <&transceiver1>; +}; + +&mcu_mcan1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan1_pins_default>; + phys = <&transceiver2>; +}; + +&main_mcan3 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan3_pins_default>; + phys = <&transceiver3>; +}; + +#define K3_TS_OFFSET(pa, val) (0x4+(pa)*4) (0x10000 | val) + +×ync_router { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_cpsw_cpts>; + + /* Use Time Sync Router to map GENF1 input to HW4_TS_PUSH output */ + mcu_cpsw_cpts: mcu-cpsw-cpts { + pinctrl-single,pins = < + /* pps [mcu cpsw cpts genf1] in17 -> out25 [mcu cpsw cpts hw4_push] */ + K3_TS_OFFSET(25, 17) + >; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j7200-evm-ethfw.dtso b/arch/arm64/boot/dts/ti/k3-j7200-evm-ethfw.dtso --- a/arch/arm64/boot/dts/ti/k3-j7200-evm-ethfw.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j7200-evm-ethfw.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT Overlay for CPSW5G functionality with Ethernet Switch Firmware (EthFw) + * and CPSW Proxy Client driver. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +/* uart2 is assigned to EthFw running on remote CPU core */ +&main_uart2 { + status = "reserved"; +}; + +/* Reserve shared memory for inter-core network communication */ +&reserved_memory { + #address-cells = <2>; + #size-cells = <2>; + + main_r5fss0_core0_shared_memory_queue_region:r5f-virtual-eth-queues@a5000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa5000000 0x00 0x200000>; + no-map; + }; + + main_r5fss0_core0_shared_memory_bufpool_region:r5f-virtual-eth-buffers@a5200000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa5200000 0x00 0x1e00000>; + no-map; + }; +}; + +&main_r5fss0_core0 { + memory-region = <&main_r5fss0_core0_dma_memory_region>, + <&main_r5fss0_core0_memory_region>, + <&main_r5fss0_core0_shared_memory_queue_region>, + <&main_r5fss0_core0_shared_memory_bufpool_region>; +}; + +/* EthFw uses timers so mark them reserved */ +&main_timer0 { + status = "reserved"; +}; + +&main_timer1 { + status = "reserved"; +}; + +&main_timer2 { + status = "reserved"; +}; + +&main_timer3 { + status = "reserved"; +}; + +&main_timer4 { + status = "reserved"; +}; + +&main_timer5 { + status = "reserved"; +}; + +&main_timer6 { + status = "reserved"; +}; + +&main_timer7 { + status = "reserved"; +}; + +&main_timer8 { + status = "reserved"; +}; + +&main_timer9 { + status = "reserved"; +}; + +&main_timer10 { + status = "reserved"; +}; + +&main_timer11 { + status = "reserved"; +}; + +&main_timer12 { + status = "reserved"; +}; + +&main_timer13 { + status = "reserved"; +}; + +&main_timer14 { + status = "reserved"; +}; + +&main_timer15 { + status = "reserved"; +}; + +&main_timer16 { + status = "reserved"; +}; + +&main_timer17 { + status = "reserved"; +}; + +&main_timer18 { + status = "reserved"; +}; + +&main_timer19 { + status = "reserved"; +}; + +/* EthFw configures pin W16 (MCAN3_RX) for PPS demo */ +&main_mcan3 { + status = "disabled"; +}; + +&transceiver3 { + status = "disabled"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j7200-evm-mcspi-loopback.dtso b/arch/arm64/boot/dts/ti/k3-j7200-evm-mcspi-loopback.dtso --- a/arch/arm64/boot/dts/ti/k3-j7200-evm-mcspi-loopback.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j7200-evm-mcspi-loopback.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MCSPI internal master-slave loopback example overlay for J7200. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + * + * J7200 has MCSPI4 connected as master to MCU_MCSPI2 by default and not + * pinned out to external pads, This overlay enables spidev on these + * interfaces for userspace testing. + */ + +/dts-v1/; +/plugin/; + +&main_spi4 { + status = "okay"; + #address-cells = <0>; + #size-cells = <0>; + spi-slave; + dmas = <&main_udmap 0xc610>, <&main_udmap 0x4610>; + dma-names = "tx0", "rx0"; + + slave { + /* + * Using spidev compatible is warned loudly, + * thus use another equivalent compatible id + * from spidev. + */ + compatible = "rohm,dh2228fv"; + spi-max-frequency = <24000000>; + }; +}; + +&mcu_spi2 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + spidev@0 { + /* + * Using spidev compatible is warned loudly, + * thus use another equivalent compatible id + * from spidev. + */ + compatible = "rohm,dh2228fv"; + spi-max-frequency = <24000000>; + reg = <0>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi --- a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -33,10 +33,11 @@ ranges = <0x00 0x00 0x00100000 0x1c000>; serdes_ln_ctrl: mux-controller@4080 { - compatible = "mmio-mux"; + compatible = "reg-mux"; + reg = <0x4080 0x20>; #mux-control-cells = <1>; - mux-reg-masks = <0x4080 0x3>, <0x4084 0x3>, /* SERDES0 lane0/1 select */ - <0x4088 0x3>, <0x408c 0x3>; /* SERDES0 lane2/3 select */ + mux-reg-masks = <0x0 0x3>, <0x4 0x3>, /* SERDES0 lane0/1 select */ + <0x8 0x3>, <0xc 0x3>; /* SERDES0 lane2/3 select */ }; cpsw0_phy_gmii_sel: phy@4044 { @@ -47,9 +48,10 @@ }; usb_serdes_mux: mux-controller@4000 { - compatible = "mmio-mux"; + compatible = "reg-mux"; + reg = <0x4000 0x4>; #mux-control-cells = <1>; - mux-reg-masks = <0x4000 0x8000000>; /* USB0 to SERDES0 lane 1/3 mux */ + mux-reg-masks = <0x0 0x8000000>; /* USB0 to SERDES0 lane 1/3 mux */ }; }; @@ -91,7 +93,7 @@ }; main_navss: bus@30000000 { - compatible = "simple-mfd"; + compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; ranges = <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>; @@ -281,8 +283,12 @@ compatible = "ti,j721e-navss-main-udmap"; reg = <0x00 0x31150000 0x00 0x100>, <0x00 0x34000000 0x00 0x100000>, - <0x00 0x35000000 0x00 0x100000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x00 0x35000000 0x00 0x100000>, + <0x00 0x30b00000 0x00 0x4000>, + <0x00 0x30c00000 0x00 0x4000>, + <0x00 0x30d00000 0x00 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; @@ -395,7 +401,7 @@ /* TIMERIO pad input CTRLMMR_TIMER*_CTRL registers */ main_timerio_input: pinctrl@104200 { - compatible = "pinctrl-single"; + compatible = "ti,j7200-padconf", "pinctrl-single"; reg = <0x0 0x104200 0x0 0x50>; #pinctrl-cells = <1>; pinctrl-single,register-width = <32>; @@ -404,7 +410,7 @@ /* TIMERIO pad output CTCTRLMMR_TIMERIO*_CTRL registers */ main_timerio_output: pinctrl@104280 { - compatible = "pinctrl-single"; + compatible = "ti,j7200-padconf", "pinctrl-single"; reg = <0x0 0x104280 0x0 0x20>; #pinctrl-cells = <1>; pinctrl-single,register-width = <32>; @@ -412,7 +418,7 @@ }; main_pmx0: pinctrl@11c000 { - compatible = "pinctrl-single"; + compatible = "ti,j7200-padconf", "pinctrl-single"; /* Proxy 0 addressing */ reg = <0x00 0x11c000 0x00 0x10c>; #pinctrl-cells = <1>; @@ -421,7 +427,7 @@ }; main_pmx1: pinctrl@11c11c { - compatible = "pinctrl-single"; + compatible = "ti,j7200-padconf", "pinctrl-single"; /* Proxy 0 addressing */ reg = <0x00 0x11c11c 0x00 0xc>; #pinctrl-cells = <1>; @@ -647,6 +653,7 @@ ti,otap-del-sel-hs400 = <0x5>; ti,itap-del-sel-legacy = <0x10>; ti,itap-del-sel-mmc-hs = <0xa>; + ti,itap-del-sel-ddr52 = <0x3>; ti,strobe-sel = <0x77>; ti,clkbuf-sel = <0x7>; ti,trm-icp = <0x8>; @@ -765,26 +772,7 @@ ranges = <0x01000000 0x0 0x18001000 0x00 0x18001000 0x0 0x0010000>, <0x02000000 0x0 0x18011000 0x00 0x18011000 0x0 0x7fef000>; dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; - }; - - pcie1_ep: pcie-ep@2910000 { - compatible = "ti,j7200-pcie-ep", "ti,j721e-pcie-ep"; - reg = <0x00 0x02910000 0x00 0x1000>, - <0x00 0x02917000 0x00 0x400>, - <0x00 0x0d800000 0x00 0x00800000>, - <0x00 0x18000000 0x00 0x08000000>; - reg-names = "intd_cfg", "user_cfg", "reg", "mem"; - interrupt-names = "link_state"; - interrupts = ; - ti,syscon-pcie-ctrl = <&scm_conf 0x4074>; - max-link-speed = <3>; - num-lanes = <4>; - power-domains = <&k3_pds 240 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 240 6>; - clock-names = "fck"; - max-functions = /bits/ 8 <6>; - max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>; - dma-coherent; + status = "disabled"; }; usbss0: cdns-usb@4104000 { @@ -890,6 +878,276 @@ status = "disabled"; }; + main_mcan0: can@2701000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02701000 0x00 0x200>, + <0x00 0x02708000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 156 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 156 0>, <&k3_clks 156 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan1: can@2711000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02711000 0x00 0x200>, + <0x00 0x02718000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 158 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 158 0>, <&k3_clks 158 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan2: can@2721000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02721000 0x00 0x200>, + <0x00 0x02728000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 160 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 160 0>, <&k3_clks 160 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan3: can@2731000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02731000 0x00 0x200>, + <0x00 0x02738000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 161 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 161 0>, <&k3_clks 161 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan4: can@2741000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02741000 0x00 0x200>, + <0x00 0x02748000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 162 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 162 0>, <&k3_clks 162 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan5: can@2751000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02751000 0x00 0x200>, + <0x00 0x02758000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 163 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 163 0>, <&k3_clks 163 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan6: can@2761000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02761000 0x00 0x200>, + <0x00 0x02768000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 164 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 164 0>, <&k3_clks 164 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan7: can@2771000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02771000 0x00 0x200>, + <0x00 0x02778000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 165 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 165 0>, <&k3_clks 165 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan8: can@2781000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02781000 0x00 0x200>, + <0x00 0x02788000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 166 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 166 0>, <&k3_clks 166 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan9: can@2791000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02791000 0x00 0x200>, + <0x00 0x02798000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 167 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 167 0>, <&k3_clks 167 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan10: can@27a1000 { + compatible = "bosch,m_can"; + reg = <0x00 0x027a1000 0x00 0x200>, + <0x00 0x027a8000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 168 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 168 0>, <&k3_clks 168 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan11: can@27b1000 { + compatible = "bosch,m_can"; + reg = <0x00 0x027b1000 0x00 0x200>, + <0x00 0x027b8000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 169 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 169 0>, <&k3_clks 169 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan12: can@27c1000 { + compatible = "bosch,m_can"; + reg = <0x00 0x027c1000 0x00 0x200>, + <0x00 0x027c8000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 170 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 170 0>, <&k3_clks 170 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan13: can@27d1000 { + compatible = "bosch,m_can"; + reg = <0x00 0x027d1000 0x00 0x200>, + <0x00 0x027d8000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 171 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 171 0>, <&k3_clks 171 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan14: can@2681000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02681000 0x00 0x200>, + <0x00 0x02688000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 150 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 150 0>, <&k3_clks 150 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan15: can@2691000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02691000 0x00 0x200>, + <0x00 0x02698000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 151 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 151 0>, <&k3_clks 151 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan16: can@26a1000 { + compatible = "bosch,m_can"; + reg = <0x00 0x026a1000 0x00 0x200>, + <0x00 0x026a8000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 152 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 152 0>, <&k3_clks 152 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan17: can@26b1000 { + compatible = "bosch,m_can"; + reg = <0x00 0x026b1000 0x00 0x200>, + <0x00 0x026b8000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 153 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 153 0>, <&k3_clks 153 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + main_spi0: spi@2100000 { compatible = "ti,am654-mcspi","ti,omap4-mcspi"; reg = <0x00 0x02100000 0x00 0x400>; @@ -1006,6 +1264,7 @@ assigned-clock-parents = <&k3_clks 49 2>; power-domains = <&k3_pds 49 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer1: timer@2410000 { @@ -1018,6 +1277,7 @@ assigned-clock-parents = <&k3_clks 50 2>, <&k3_clks 313 1>; power-domains = <&k3_pds 50 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer2: timer@2420000 { @@ -1238,7 +1498,7 @@ main_r5fss0: r5fss@5c00000 { compatible = "ti,j7200-r5fss"; - ti,cluster-mode = <1>; + ti,cluster-mode = <0>; #address-cells = <1>; #size-cells = <1>; ranges = <0x5c00000 0x00 0x5c00000 0x20000>, @@ -1281,4 +1541,15 @@ reg = <0x0 0x700000 0x0 0x1000>; ti,esm-pins = <656>, <657>; }; + + timesync_router: pinctrl@a40000 { + compatible = "pinctrl-single"; + reg = <0x0 0xa40000 0x0 0x800>; + #address-cells = <1>; + #size-cells = <0>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x000107ff>; + status = "disabled"; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi --- a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -178,14 +178,21 @@ }; }; - chipid@43000014 { - compatible = "ti,am654-chipid"; - reg = <0x00 0x43000014 0x00 0x4>; + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; /* MCU_TIMERIO pad input CTRLMMR_MCU_TIMER*_CTRL registers */ mcu_timerio_input: pinctrl@40f04200 { - compatible = "pinctrl-single"; + compatible = "ti,j7200-padconf", "pinctrl-single"; reg = <0x0 0x40f04200 0x0 0x28>; #pinctrl-cells = <1>; pinctrl-single,register-width = <32>; @@ -195,7 +202,7 @@ /* MCU_TIMERIO pad output CTRLMMR_MCU_TIMERIO*_CTRL registers */ mcu_timerio_output: pinctrl@40f04280 { - compatible = "pinctrl-single"; + compatible = "ti,j7200-padconf", "pinctrl-single"; reg = <0x0 0x40f04280 0x0 0x28>; #pinctrl-cells = <1>; pinctrl-single,register-width = <32>; @@ -204,7 +211,7 @@ }; wkup_pmx0: pinctrl@4301c000 { - compatible = "pinctrl-single"; + compatible = "ti,j7200-padconf", "pinctrl-single"; /* Proxy 0 addressing */ reg = <0x00 0x4301c000 0x00 0x34>; #pinctrl-cells = <1>; @@ -213,7 +220,7 @@ }; wkup_pmx1: pinctrl@4301c038 { - compatible = "pinctrl-single"; + compatible = "ti,j7200-padconf", "pinctrl-single"; /* Proxy 0 addressing */ reg = <0x00 0x4301c038 0x00 0x8>; #pinctrl-cells = <1>; @@ -222,7 +229,7 @@ }; wkup_pmx2: pinctrl@4301c068 { - compatible = "pinctrl-single"; + compatible = "ti,j7200-padconf", "pinctrl-single"; /* Proxy 0 addressing */ reg = <0x00 0x4301c068 0x00 0xec>; #pinctrl-cells = <1>; @@ -231,7 +238,7 @@ }; wkup_pmx3: pinctrl@4301c174 { - compatible = "pinctrl-single"; + compatible = "ti,j7200-padconf", "pinctrl-single"; /* Proxy 0 addressing */ reg = <0x00 0x4301c174 0x00 0x20>; #pinctrl-cells = <1>; @@ -318,7 +325,7 @@ }; mcu_navss: bus@28380000 { - compatible = "simple-mfd"; + compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>; @@ -346,8 +353,12 @@ compatible = "ti,j721e-navss-mcu-udmap"; reg = <0x00 0x285c0000 0x00 0x100>, <0x00 0x2a800000 0x00 0x40000>, - <0x00 0x2aa00000 0x00 0x40000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x00 0x2aa00000 0x00 0x40000>, + <0x00 0x284a0000 0x00 0x4000>, + <0x00 0x284c0000 0x00 0x4000>, + <0x00 0x28400000 0x00 0x2000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; @@ -507,17 +518,18 @@ status = "disabled"; }; - fss: syscon@47000000 { - compatible = "syscon", "simple-mfd"; + fss: bus@47000000 { + compatible = "simple-bus"; reg = <0x00 0x47000000 0x00 0x100>; #address-cells = <2>; #size-cells = <2>; ranges; - hbmc_mux: hbmc-mux { - compatible = "mmio-mux"; + hbmc_mux: mux-controller@47000004 { + compatible = "reg-mux"; + reg = <0x00 0x47000004 0x00 0x4>; #mux-control-cells = <1>; - mux-reg-masks = <0x4 0x2>; /* HBMC select */ + mux-reg-masks = <0x0 0x2>; /* HBMC select */ }; hbmc: hyperbus@47034000 { @@ -637,4 +649,41 @@ power-domains = <&k3_pds 154 TI_SCI_PD_EXCLUSIVE>; #thermal-sensor-cells = <1>; }; + + mcu_esm: esm@40800000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x40800000 0x00 0x1000>; + ti,esm-pins = <95>; + bootph-pre-ram; + }; + + mcu_mcan0: can@40528000 { + compatible = "bosch,m_can"; + reg = <0x00 0x40528000 0x00 0x200>, + <0x00 0x40500000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 172 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 172 0>, <&k3_clks 172 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + mcu_mcan1: can@40568000 { + compatible = "bosch,m_can"; + reg = <0x00 0x40568000 0x00 0x200>, + <0x00 0x40540000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 173 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 173 0>, <&k3_clks 173 2>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + status = "disabled"; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi --- a/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -5,14 +5,17 @@ /dts-v1/; +#include + #include "k3-j7200.dtsi" / { memory@80000000 { device_type = "memory"; + bootph-all; /* 4G RAM */ - reg = <0x00 0x80000000 0x00 0x80000000>, - <0x08 0x80000000 0x00 0x80000000>; + reg = <0x00000000 0x80000000 0x00000000 0x80000000>, + <0x00000008 0x80000000 0x00000000 0x80000000>; }; reserved_memory: reserved-memory { @@ -80,6 +83,25 @@ no-map; }; }; + + mux0: mux-controller { + compatible = "gpio-mux"; + #mux-state-cells = <1>; + mux-gpios = <&exp_som 1 GPIO_ACTIVE_HIGH>; + }; + + mux1: mux-controller { + compatible = "gpio-mux"; + #mux-state-cells = <1>; + mux-gpios = <&exp_som 2 GPIO_ACTIVE_HIGH>; + }; + + transceiver0: can-phy0 { + /* standby pin has been grounded by default */ + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; }; &wkup_pmx0 { @@ -127,6 +149,14 @@ }; }; +&wkup_pmx3 { + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x01c, PIN_INPUT, 7) /* (E18) WKUP_GPIO0_84 */ + >; + }; +}; + &main_pmx0 { main_i2c0_pins_default: main-i2c0-default-pins { pinctrl-single,pins = < @@ -134,6 +164,13 @@ J721E_IOPAD(0xd8, PIN_INPUT_PULLUP, 0) /* (W2) I2C0_SDA */ >; }; + + main_mcan0_pins_default: main-mcan0-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x24, PIN_INPUT, 0) /* (V20) MCAN0_RX */ + J721E_IOPAD(0x20, PIN_OUTPUT, 0) /* (V18) MCAN0_TX */ + >; + }; }; &hbmc { @@ -214,25 +251,25 @@ }; &mcu_r5fss0_core0 { - mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>; + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>; memory-region = <&mcu_r5fss0_core0_dma_memory_region>, <&mcu_r5fss0_core0_memory_region>; }; &mcu_r5fss0_core1 { - mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core1>; + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>; memory-region = <&mcu_r5fss0_core1_dma_memory_region>, <&mcu_r5fss0_core1_memory_region>; }; &main_r5fss0_core0 { - mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core0>; + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>; memory-region = <&main_r5fss0_core0_dma_memory_region>, <&main_r5fss0_core0_memory_region>; }; &main_r5fss0_core1 { - mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core1>; + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>; memory-region = <&main_r5fss0_core1_dma_memory_region>, <&main_r5fss0_core1_memory_region>; }; @@ -264,6 +301,151 @@ compatible = "atmel,24c256"; reg = <0x50>; }; + + tps659414: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <84 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck1-supply = <&vsys_3v3>; + buck2-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka1: buck1 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka2: buck2 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka3: buck3 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka4: buck4 { + regulator-name = "vdd_ddr_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka5: buck5 { + regulator-name = "vdd_phyio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd1_lpddr4_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vda_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vdd_wk_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_pll_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + lp876441: pmic@4c { + compatible = "ti,lp8764-q1"; + reg = <0x4c>; + system-power-controller; + interrupt-parent = <&wkup_gpio0>; + interrupts = <84 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + buck1-supply = <&vsys_3v3>; + buck2-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + + regulators: regulators { + buckb1: buck1 { + regulator-name = "vdd_cpu_avs"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <900000>; + regulator-always-on; + regulator-boot-on; + bootph-pre-ram; + }; + + buckb2: buck2 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb3: buck3 { + regulator-name = "vdd_core_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb4: buck4 { + regulator-name = "vdd_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; }; &ospi0 { @@ -325,3 +507,10 @@ }; }; }; + +&main_mcan0 { + status = "okay"; + pinctrl-0 = <&main_mcan0_pins_default>; + pinctrl-names = "default"; + phys = <&transceiver0>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64-dsi-rpi-7inch-panel.dtso b/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64-dsi-rpi-7inch-panel.dtso --- a/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64-dsi-rpi-7inch-panel.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64-dsi-rpi-7inch-panel.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * DT Overlay for RPi 7inch touchscreen panel interfaced with DSI on + * J721E based BeagleBone AI-64 (BBAI-64) platform. + * + * BBAI-64: https://www.beagleboard.org/boards/beaglebone-ai-64 + * RPi DSI Panel: https://www.raspberrypi.com/products/raspberry-pi-touch-display/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +&{/} { + bridge_reg: bridge-regulator { + compatible = "regulator-fixed"; + regulator-name = "bridge-reg"; + gpio = <&display_reg 0 0>; + vin-supply = <&display_reg>; + enable-active-high; + }; + + panel0 { + compatible = "raspberrypi,7inch-dsi", "simple-panel"; + backlight = <&display_reg>; + power-supply = <&display_reg>; + port { + panel_in: endpoint { + remote-endpoint = <&panel_bridge_out>; + }; + }; + }; +}; + +&main_pmx0 { + dsi_main_i2c4_pins: dsi-main-i2c4-pins { + pinctrl-single,pins = < + J721E_IOPAD(0xa8, PIN_INPUT_PULLUP, 2) /* (AD19) PRG1_MDIO0_MDIO.I2C4_SCL */ + J721E_IOPAD(0xac, PIN_INPUT_PULLUP, 2) /* (AD18) PRG1_MDIO0_MDC.I2C4_SDA */ + >; + }; +}; + +&main_i2c4 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&dsi_main_i2c4_pins>; + #address-cells = <1>; + #size-cells = <0>; + + display_reg: regulator@45 { + compatible = "raspberrypi,7inch-touchscreen-panel-regulator"; + reg = <0x45>; + gpio-controller; + #gpio-cells = <2>; + }; + + touch-controller@38 { + compatible = "edt,edt-ft5406"; + reg = <0x38>; + + touchscreen-size-x = < 800 >; + touchscreen-size-y = < 480 >; + + vcc-supply = <&display_reg>; + reset-gpio = <&display_reg 1 1>; + + touchscreen-inverted-x; + touchscreen-inverted-y; + }; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@2 { + reg = <2>; + + dpi2_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; +}; + +&dphy2 { + status = "okay"; +}; + +&dsi0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_out: endpoint { + remote-endpoint = <&panel_bridge_in>; + }; + }; + + port@1 { + reg = <1>; + dsi0_in: endpoint { + remote-endpoint = <&dpi2_out>; + }; + }; + }; + + bridge@0 { + compatible = "toshiba,tc358762"; + reg = <0>; + vddc-supply = <&bridge_reg>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + panel_bridge_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + panel_bridge_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + }; + +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts b/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts --- a/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts 2024-07-07 20:37:34.632306489 -0400 @@ -1,14 +1,15 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * https://beagleboard.org/ai-64 - * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ - * Copyright (C) 2022 Jason Kridner, BeagleBoard.org Foundation - * Copyright (C) 2022 Robert Nelson, BeagleBoard.org Foundation + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2022-2024 Jason Kridner, BeagleBoard.org Foundation + * Copyright (C) 2022-2024 Robert Nelson, BeagleBoard.org Foundation */ /dts-v1/; #include "k3-j721e.dtsi" +#include "k3-j721e-beagleboneai64-pinmux.dtsi" #include #include #include @@ -698,7 +699,7 @@ resets = <&serdes_wiz4 1>; cdns,phy-type = ; cdns,num-lanes = <4>; - cdns,max-bit-rate = <5400>; + cdns,max-bit-rate = <2700>; #phy-cells = <0>; }; }; @@ -804,7 +805,12 @@ }; &dss_ports { - port { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpi0_out: endpoint { remote-endpoint = <&dp0_in>; }; @@ -936,58 +942,58 @@ }; &mcu_r5fss0_core0 { - mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>; + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>; memory-region = <&mcu_r5fss0_core0_dma_memory_region>, <&mcu_r5fss0_core0_memory_region>; }; &mcu_r5fss0_core1 { - mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core1>; + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>; memory-region = <&mcu_r5fss0_core1_dma_memory_region>, <&mcu_r5fss0_core1_memory_region>; }; &main_r5fss0_core0 { - mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core0>; + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>; memory-region = <&main_r5fss0_core0_dma_memory_region>, <&main_r5fss0_core0_memory_region>; }; &main_r5fss0_core1 { - mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core1>; + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>; memory-region = <&main_r5fss0_core1_dma_memory_region>, <&main_r5fss0_core1_memory_region>; }; &main_r5fss1_core0 { - mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core0>; + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>; memory-region = <&main_r5fss1_core0_dma_memory_region>, <&main_r5fss1_core0_memory_region>; }; &main_r5fss1_core1 { - mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core1>; + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>; memory-region = <&main_r5fss1_core1_dma_memory_region>, <&main_r5fss1_core1_memory_region>; }; &c66_0 { status = "okay"; - mboxes = <&mailbox0_cluster3>, <&mbox_c66_0>; + mboxes = <&mailbox0_cluster3 &mbox_c66_0>; memory-region = <&c66_0_dma_memory_region>, <&c66_0_memory_region>; }; &c66_1 { status = "okay"; - mboxes = <&mailbox0_cluster3>, <&mbox_c66_1>; + mboxes = <&mailbox0_cluster3 &mbox_c66_1>; memory-region = <&c66_1_dma_memory_region>, <&c66_1_memory_region>; }; &c71_0 { status = "okay"; - mboxes = <&mailbox0_cluster4>, <&mbox_c71_0>; + mboxes = <&mailbox0_cluster4 &mbox_c71_0>; memory-region = <&c71_0_dma_memory_region>, <&c71_0_memory_region>; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64-microtips-mf070zima-lcd3.dtso b/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64-microtips-mf070zima-lcd3.dtso --- a/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64-microtips-mf070zima-lcd3.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64-microtips-mf070zima-lcd3.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * DT Overlay for Microtips SK-LCD3 interfaced with DSI on + * J721E based BeagleBone AI-64 (BBAI-64) platform. + * + * BBAI-64: https://www.beagleboard.org/boards/beaglebone-ai-64 + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +&main_pmx0 { + dsi_main_i2c4_pins: dsi-main-i2c4-pins { + pinctrl-single,pins = < + J721E_IOPAD(0xa8, PIN_INPUT_PULLUP, 2) /* (AD19) PRG1_MDIO0_MDIO.I2C4_SCL */ + J721E_IOPAD(0xac, PIN_INPUT_PULLUP, 2) /* (AD18) PRG1_MDIO0_MDC.I2C4_SDA */ + >; + }; + + dsi0_gpio_pins_default: dsi0-gpio-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x18c, PIN_OUTPUT, 7) /* (V23) RGMII6_RX_CTL.GPIO0_98 */ + J721E_IOPAD(0x1b4, PIN_INPUT, 7) /* (W25) RGMII6_RD0.GPIO0_108 */ + >; + }; +}; + +&main_i2c4 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&dsi_main_i2c4_pins>; + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@41 { + compatible = "ilitek,ili251x"; + reg = <0x41>; + pinctrl-names = "default"; + pinctrl-0 = <&dsi0_gpio_pins_default>; + reset-gpios = <&main_gpio0 98 GPIO_ACTIVE_LOW>; + interrupt-parent = <&main_gpio0>; + interrupts = <108 IRQ_TYPE_EDGE_FALLING>; + }; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@2 { + reg = <2>; + + dpi2_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; +}; + +&dphy2 { + status = "okay"; +}; + +&dsi0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + + port@1 { + reg = <1>; + dsi0_in: endpoint { + remote-endpoint = <&dpi2_out>; + }; + }; + }; + + dsi_panel0: panel-dsi@0 { + compatible = "microtips,mf-070zimacaa0", "ilitek,ili9881c"; + reg = <0>; + + port { + panel_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64-pinmux.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64-pinmux.dtsi --- a/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64-pinmux.dtsi 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64-pinmux.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * https://beagleboard.org/ai-64 + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2022-2024 Jason Kridner, BeagleBoard.org Foundation + * Copyright (C) 2022-2024 Robert Nelson, BeagleBoard.org Foundation + */ + +#include + +/ { + chosen { + base_dtb = "k3-j721e-beagleboneai64.dts"; + base_dtb_timestamp = __TIMESTAMP__; + }; + + leds { + led-0 { + label = "beaglebone:green:usr0"; + }; + + led-1 { + label = "beaglebone:green:usr1"; + }; + + led-2 { + label = "beaglebone:green:usr2"; + }; + + led-3 { + label = "beaglebone:green:usr3"; + }; + + led-4 { + label = "beaglebone:green:usr4"; + linux,default-trigger = "phy0tx"; + }; + }; +}; + +bone_i2c_2: &main_i2c2 { + /* BBB Header: P9.19 and P9.20 */ + clock-frequency = <100000>; +}; + +bone_i2c_3: &main_i2c4 { + /* BBB Header: P9.24 and P9.26 */ + clock-frequency = <100000>; +}; + +bone_i2c_1: &main_i2c6 { + /* BBB Header: P9.17 and P9.18 */ + clock-frequency = <100000>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts --- a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts 2024-07-07 20:37:34.632306489 -0400 @@ -1,6 +1,6 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* - * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2019-2024 Texas Instruments Incorporated - https://www.ti.com/ * * Product Link: https://www.ti.com/tool/J721EXCPXEVM */ @@ -751,6 +751,11 @@ &mcu_cpsw { pinctrl-names = "default"; pinctrl-0 = <&mcu_cpsw_pins_default>, <&mcu_mdio_pins_default>; + + cpts@3d000 { + /* Map HW4_TS_PUSH to GENF1 */ + ti,pps = <3 1>; + }; }; &davinci_mdio { @@ -911,7 +916,7 @@ resets = <&serdes_wiz4 1>; cdns,phy-type = ; cdns,num-lanes = <4>; - cdns,max-bit-rate = <5400>; + cdns,max-bit-rate = <2700>; #phy-cells = <0>; }; }; @@ -974,3 +979,19 @@ pinctrl-0 = <&main_mcan2_pins_default>; phys = <&transceiver4>; }; + +#define K3_TS_OFFSET(pa, val) (0x4+(pa)*4) (0x10000 | val) + +×ync_router { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_cpsw_cpts>; + + /* Use Time Sync Router to map GENF1 input to HW4_TS_PUSH output */ + mcu_cpsw_cpts: mcu-cpsw-cpts { + pinctrl-single,pins = < + /* pps [mcu cpsw cpts genf1] in17 -> out25 [mcu cpsw cpts hw4_push] */ + K3_TS_OFFSET(25, 17) + >; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso --- a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Infotainment Expansion Board for j721e-evm + * User Guide: + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +&{/} { + hdmi-connector { + compatible = "hdmi-connector"; + label = "hdmi"; + type = "a"; + ddc-i2c-bus = <&main_i2c1>; + digital; + /* P12 - HDMI_HPD */ + hpd-gpios = <&exp6 10 GPIO_ACTIVE_HIGH>; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; + }; + + dvi-bridge { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,tfp410"; + /* P10 - HDMI_PDn */ + powerdown-gpios = <&exp6 8 GPIO_ACTIVE_LOW>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint { + remote-endpoint = <&dpi_out0>; + pclk-sample = <1>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint { + remote-endpoint = + <&hdmi_connector_in>; + }; + }; + }; +}; + +&main_pmx0 { + main_i2c1_exp6_pins_default: main-i2c1-exp6-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x264, PIN_INPUT, 7) /* (T29) MMC2_DAT2.GPIO1_24 */ + >; + }; + + dss_vout0_pins_default: dss-vout0-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x58, PIN_OUTPUT, 10) /* (AE22) PRG1_PRU1_GPO0.VOUT0_DATA0 */ + J721E_IOPAD(0x5c, PIN_OUTPUT, 10) /* (AG23) PRG1_PRU1_GPO1.VOUT0_DATA1 */ + J721E_IOPAD(0x60, PIN_OUTPUT, 10) /* (AF23) PRG1_PRU1_GPO2.VOUT0_DATA2 */ + J721E_IOPAD(0x64, PIN_OUTPUT, 10) /* (AD23) PRG1_PRU1_GPO3.VOUT0_DATA3 */ + J721E_IOPAD(0x68, PIN_OUTPUT, 10) /* (AH24) PRG1_PRU1_GPO4.VOUT0_DATA4 */ + J721E_IOPAD(0x6c, PIN_OUTPUT, 10) /* (AG21) PRG1_PRU1_GPO5.VOUT0_DATA5 */ + J721E_IOPAD(0x70, PIN_OUTPUT, 10) /* (AE23) PRG1_PRU1_GPO6.VOUT0_DATA6 */ + J721E_IOPAD(0x74, PIN_OUTPUT, 10) /* (AC21) PRG1_PRU1_GPO7.VOUT0_DATA7 */ + J721E_IOPAD(0x78, PIN_OUTPUT, 10) /* (Y23) PRG1_PRU1_GPO8.VOUT0_DATA8 */ + J721E_IOPAD(0x7c, PIN_OUTPUT, 10) /* (AF21) PRG1_PRU1_GPO9.VOUT0_DATA9 */ + J721E_IOPAD(0x80, PIN_OUTPUT, 10) /* (AB23) PRG1_PRU1_GPO10.VOUT0_DATA10 */ + J721E_IOPAD(0x84, PIN_OUTPUT, 10) /* (AJ25) PRG1_PRU1_GPO11.VOUT0_DATA11 */ + J721E_IOPAD(0x88, PIN_OUTPUT, 10) /* (AH25) PRG1_PRU1_GPO12.VOUT0_DATA12 */ + J721E_IOPAD(0x8c, PIN_OUTPUT, 10) /* (AG25) PRG1_PRU1_GPO13.VOUT0_DATA13 */ + J721E_IOPAD(0x90, PIN_OUTPUT, 10) /* (AH26) PRG1_PRU1_GPO14.VOUT0_DATA14 */ + J721E_IOPAD(0x94, PIN_OUTPUT, 10) /* (AJ27) PRG1_PRU1_GPO15.VOUT0_DATA15 */ + J721E_IOPAD(0x30, PIN_OUTPUT, 10) /* (AF24) PRG1_PRU0_GPO11.VOUT0_DATA16 */ + J721E_IOPAD(0x34, PIN_OUTPUT, 10) /* (AJ24) PRG1_PRU0_GPO12.VOUT0_DATA17 */ + J721E_IOPAD(0x38, PIN_OUTPUT, 10) /* (AG24) PRG1_PRU0_GPO13.VOUT0_DATA18 */ + J721E_IOPAD(0x3c, PIN_OUTPUT, 10) /* (AD24) PRG1_PRU0_GPO14.VOUT0_DATA19 */ + J721E_IOPAD(0x40, PIN_OUTPUT, 10) /* (AC24) PRG1_PRU0_GPO15.VOUT0_DATA20 */ + J721E_IOPAD(0x44, PIN_OUTPUT, 10) /* (AE24) PRG1_PRU0_GPO16.VOUT0_DATA21 */ + J721E_IOPAD(0x24, PIN_OUTPUT, 10) /* (AJ20) PRG1_PRU0_GPO8.VOUT0_DATA22 */ + J721E_IOPAD(0x28, PIN_OUTPUT, 10) /* (AG20) PRG1_PRU0_GPO9.VOUT0_DATA23 */ + J721E_IOPAD(0x9c, PIN_OUTPUT, 10) /* (AC22) PRG1_PRU1_GPO17.VOUT0_DE */ + J721E_IOPAD(0x98, PIN_OUTPUT, 10) /* (AJ26) PRG1_PRU1_GPO16.VOUT0_HSYNC */ + J721E_IOPAD(0xa4, PIN_OUTPUT, 10) /* (AH22) PRG1_PRU1_GPO19.VOUT0_PCLK */ + J721E_IOPAD(0xa0, PIN_OUTPUT, 10) /* (AJ22) PRG1_PRU1_GPO18.VOUT0_VSYNC */ + >; + }; +}; + +&exp1 { + p14-hog { + /* P14 - VINOUT_MUX_SEL0 */ + gpio-hog; + gpios = <12 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "VINOUT_MUX_SEL0"; + }; + + p15-hog { + /* P15 - VINOUT_MUX_SEL1 */ + gpio-hog; + gpios = <13 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "VINOUT_MUX_SEL1"; + }; +}; + +&main_i2c1 { + /* i2c1 is used for DVI DDC, so we need to use 100kHz */ + clock-frequency = <100000>; + #address-cells = <1>; + #size-cells = <0>; + + exp6: gpio@21 { + compatible = "ti,tca6416"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_exp6_pins_default>; + interrupt-parent = <&main_gpio1>; + interrupts = <24 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + + p11-hog { + /* P11 - HDMI_DDC_OE */ + gpio-hog; + gpios = <9 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "HDMI_DDC_OE"; + }; + }; +}; + +&dss { + pinctrl-names = "default"; + pinctrl-0 = <&dss_vout0_pins_default>; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + dpi_out0: endpoint { + remote-endpoint = <&tfp410_in>; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e.dtsi b/arch/arm64/boot/dts/ti/k3-j721e.dtsi --- a/arch/arm64/boot/dts/ti/k3-j721e.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721e.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree Source for J721E SoC Family * - * Copyright (C) 2016-2019 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2016-2024 Texas Instruments Incorporated - https://www.ti.com/ */ #include diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-evm-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-j721e-evm-csi2-ov5640.dtso --- a/arch/arm64/boot/dts/ti/k3-j721e-evm-csi2-ov5640.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-evm-csi2-ov5640.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LI OV5640 MIPI Camera module on MIPI CSI connector. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&main_i2c6 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + powerdown-gpios = <&exp5 0 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; \ No newline at end of file diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-evm-ethfw.dtso b/arch/arm64/boot/dts/ti/k3-j721e-evm-ethfw.dtso --- a/arch/arm64/boot/dts/ti/k3-j721e-evm-ethfw.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-evm-ethfw.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT Overlay for CPSW9G functionality with Ethernet Switch Firmware (EthFw) + * and CPSW Proxy Client driver. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include "k3-serdes.h" + +&serdes_ln_ctrl { + idle-states = , , + , , + , , + , , + , , + , ; +}; + +/* uart2 is assigned to EthFw running on remote CPU core */ +&main_uart2 { + status = "reserved"; +}; + +/* Reserve shared memory for inter-core network communication */ +&reserved_memory { + #address-cells = <2>; + #size-cells = <2>; + + main_r5fss0_core0_shared_memory_queue_region:r5f-virtual-eth-queues@ac000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xac000000 0x00 0x200000>; + no-map; + }; + + main_r5fss0_core0_shared_memory_bufpool_region:r5f-virtual-eth-buffers@ac200000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xac200000 0x00 0x1e00000>; + no-map; + }; +}; + +&main_r5fss0_core0 { + memory-region = <&main_r5fss0_core0_dma_memory_region>, + <&main_r5fss0_core0_memory_region>, + <&main_r5fss0_core0_shared_memory_queue_region>, + <&main_r5fss0_core0_shared_memory_bufpool_region>; +}; + +/* EthFw uses timers so mark them reserved */ +&main_timer12 { + status = "reserved"; +}; + +&main_timer13 { + status = "reserved"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-evm-fusion.dtso b/arch/arm64/boot/dts/ti/k3-j721e-evm-fusion.dtso --- a/arch/arm64/boot/dts/ti/k3-j721e-evm-fusion.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-evm-fusion.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Fusion (FPD-Link III) board on J721E EVM + * https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + + +&main_i2c6 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + deser@3d { + compatible = "ti,ds90ub960-q1"; + reg = <0x3d>; + clocks = <&clk_fusion_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + deser@36 { + compatible = "ti,ds90ub960-q1"; + reg = <0x36>; + clocks = <&clk_fusion_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy1 { + status = "okay"; +}; \ No newline at end of file diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-evm-ina2xx.dtso b/arch/arm64/boot/dts/ti/k3-j721e-evm-ina2xx.dtso --- a/arch/arm64/boot/dts/ti/k3-j721e-evm-ina2xx.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-evm-ina2xx.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT Overlay for INA2xx for J721E board + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +&main_pmx0 { + main_i2c2_pins_default: main-i2c2-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x1c8, PIN_INPUT_PULLUP, 2) /* (AB5) SPI0_CLK.I2C2_SCL */ + J721E_IOPAD(0x1cc, PIN_INPUT_PULLUP, 2) /* (AA1) SPI0_D0.I2C2_SDA */ + >; + }; +}; + +&exp2 { + p08-hog { + /* P10 - PM_I2C_CTRL_OE */ + gpio-hog; + gpios = <8 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CTRL_PM_I2C_OE"; + }; +}; + +&main_i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c2_pins_default>; + clock-frequency = <400000>; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + ina226@40 { + compatible = "ti,ina226"; + reg = <0x40>; + shunt-resistor = <10000>; + }; + + ina226@41 { + compatible = "ti,ina226"; + reg = <0x41>; + shunt-resistor = <10000>; + }; + + ina226@42 { + compatible = "ti,ina226"; + reg = <0x42>; + shunt-resistor = <10000>; + }; + + ina226@43 { + compatible = "ti,ina226"; + reg = <0x43>; + shunt-resistor = <10000>; + }; + + ina226@44 { + compatible = "ti,ina226"; + reg = <0x44>; + shunt-resistor = <10000>; + }; + + ina226@45 { + compatible = "ti,ina226"; + reg = <0x45>; + shunt-resistor = <5000>; + }; + + ina226@46 { + compatible = "ti,ina226"; + reg = <0x46>; + shunt-resistor = <10000>; + }; + + ina226@47 { + compatible = "ti,ina226"; + reg = <0x47>; + shunt-resistor = <10000>; + }; + + ina226@48 { + compatible = "ti,ina226"; + reg = <0x48>; + shunt-resistor = <10000>; + }; + + ina226@49 { + compatible = "ti,ina226"; + reg = <0x49>; + shunt-resistor = <10000>; + }; + + ina226@4a { + compatible = "ti,ina226"; + reg = <0x4a>; + shunt-resistor = <10000>; + }; + + ina226@4b { + compatible = "ti,ina226"; + reg = <0x4b>; + shunt-resistor = <10000>; + }; + + ina226@4c { + compatible = "ti,ina226"; + reg = <0x4c>; + shunt-resistor = <10000>; + }; + + ina226@4d { + compatible = "ti,ina226"; + reg = <0x4d>; + shunt-resistor = <10000>; + }; + + ina226@4e { + compatible = "ti,ina226"; + reg = <0x4e>; + shunt-resistor = <10000>; + }; + + ina226@4f { + compatible = "ti,ina226"; + reg = <0x4f>; + shunt-resistor = <10000>; + }; +}; + diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-evm-pcie0-ep.dtso b/arch/arm64/boot/dts/ti/k3-j721e-evm-pcie0-ep.dtso --- a/arch/arm64/boot/dts/ti/k3-j721e-evm-pcie0-ep.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-evm-pcie0-ep.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for enabling PCIE0 instance in Endpoint Configuration with the + * J7 common processor board. + * + * J7 Common Processor Board Product Link: https://www.ti.com/tool/J721EXCPXEVM + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +/* + * Since Root Complex and Endpoint modes are mutually exclusive + * disable Root Complex mode. + */ +&pcie0_rc { + status = "disabled"; +}; + +&cbass_main { + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&gic500>; + + pcie0_ep: pcie-ep@2900000 { + compatible = "ti,j721e-pcie-ep"; + reg = <0x00 0x02900000 0x00 0x1000>, + <0x00 0x02907000 0x00 0x400>, + <0x00 0x0d000000 0x00 0x00800000>, + <0x00 0x10000000 0x00 0x08000000>; + reg-names = "intd_cfg", "user_cfg", "reg", "mem"; + interrupt-names = "link_state"; + interrupts = ; + ti,syscon-pcie-ctrl = <&scm_conf 0x4070>; + max-link-speed = <3>; + num-lanes = <1>; + power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 239 1>; + clock-names = "fck"; + max-functions = /bits/ 8 <6>; + max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>; + dma-coherent; + phys = <&serdes0_pcie_link>; + phy-names = "pcie-phy"; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi --- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree Source for J721E SoC Family Main Domain peripherals * - * Copyright (C) 2016-2020 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2016-2024 Texas Instruments Incorporated - https://www.ti.com/ */ #include #include @@ -45,15 +45,15 @@ ranges = <0x0 0x0 0x00100000 0x1c000>; serdes_ln_ctrl: mux-controller@4080 { - compatible = "mmio-mux"; - reg = <0x00004080 0x50>; + compatible = "reg-mux"; + reg = <0x4080 0x50>; #mux-control-cells = <1>; - mux-reg-masks = <0x4080 0x3>, <0x4084 0x3>, /* SERDES0 lane0/1 select */ - <0x4090 0x3>, <0x4094 0x3>, /* SERDES1 lane0/1 select */ - <0x40a0 0x3>, <0x40a4 0x3>, /* SERDES2 lane0/1 select */ - <0x40b0 0x3>, <0x40b4 0x3>, /* SERDES3 lane0/1 select */ - <0x40c0 0x3>, <0x40c4 0x3>, <0x40c8 0x3>, <0x40cc 0x3>; - /* SERDES4 lane0/1/2/3 select */ + mux-reg-masks = <0x0 0x3>, <0x4 0x3>, /* SERDES0 lane0/1 select */ + <0x10 0x3>, <0x14 0x3>, /* SERDES1 lane0/1 select */ + <0x20 0x3>, <0x24 0x3>, /* SERDES2 lane0/1 select */ + <0x30 0x3>, <0x34 0x3>, /* SERDES3 lane0/1 select */ + <0x40 0x3>, <0x44 0x3>, /* SERDES4 lane0/1 select */ + <0x48 0x3>, <0x4c 0x3>; /* SERDES4 lane2/3 select */ idle-states = , , , , , , @@ -70,10 +70,11 @@ }; usb_serdes_mux: mux-controller@4000 { - compatible = "mmio-mux"; + compatible = "reg-mux"; + reg = <0x4000 0x20>; #mux-control-cells = <1>; - mux-reg-masks = <0x4000 0x8000000>, /* USB0 to SERDES0/3 mux */ - <0x4010 0x8000000>; /* USB1 to SERDES1/2 mux */ + mux-reg-masks = <0x0 0x8000000>, /* USB0 to SERDES0/3 mux */ + <0x10 0x8000000>; /* USB1 to SERDES1/2 mux */ }; ehrpwm_tbclk: clock-controller@4140 { @@ -181,7 +182,7 @@ }; main_navss: bus@30000000 { - compatible = "simple-mfd"; + compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; ranges = <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>; @@ -382,8 +383,12 @@ compatible = "ti,j721e-navss-main-udmap"; reg = <0x0 0x31150000 0x0 0x100>, <0x0 0x34000000 0x0 0x100000>, - <0x0 0x35000000 0x0 0x100000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x35000000 0x0 0x100000>, + <0x0 0x30b00000 0x0 0x20000>, + <0x0 0x30c00000 0x0 0x10000>, + <0x0 0x30d00000 0x0 0x8000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; @@ -568,6 +573,140 @@ pinctrl-single,function-mask = <0x0000001f>; }; + ti_csi2rx0: ticsi2rx@4500000 { + compatible = "ti,j721e-csi2rx-shim"; + reg = <0x0 0x4500000 0x0 0x1000>; + ranges; + #address-cells = <2>; + #size-cells = <2>; + dmas = <&main_udmap 0x4940>, <&main_udmap 0x4941>, <&main_udmap 0x4942>, + <&main_udmap 0x4943>, <&main_udmap 0x4944>, <&main_udmap 0x4945>, + <&main_udmap 0x4946>, <&main_udmap 0x4947>, <&main_udmap 0x4948>, + <&main_udmap 0x4949>, <&main_udmap 0x494a>, <&main_udmap 0x494b>, + <&main_udmap 0x494c>, <&main_udmap 0x494d>, <&main_udmap 0x494e>, + <&main_udmap 0x494f>; + dma-names = "rx0", "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7", + "rx8", "rx9", "rx10", "rx11", "rx12", "rx13", "rx14", "rx15"; + power-domains = <&k3_pds 26 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + cdns_csi2rx0: csi-bridge@4504000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x0 0x4504000 0x0 0x1000>; + clocks = <&k3_clks 26 2>, <&k3_clks 26 0>, <&k3_clks 26 2>, + <&k3_clks 26 2>, <&k3_clks 26 3>, <&k3_clks 26 3>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi0_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi0_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi0_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi0_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + ti_csi2rx1: ticsi2rx@4510000 { + compatible = "ti,j721e-csi2rx-shim"; + reg = <0x0 0x4510000 0x0 0x1000>; + ranges; + #address-cells = <2>; + #size-cells = <2>; + dmas = <&main_udmap 0x4960>, <&main_udmap 0x4961>, <&main_udmap 0x4962>, + <&main_udmap 0x4963>, <&main_udmap 0x4964>, <&main_udmap 0x4965>, + <&main_udmap 0x4966>, <&main_udmap 0x4967>, <&main_udmap 0x4968>, + <&main_udmap 0x4969>, <&main_udmap 0x496a>, <&main_udmap 0x496b>, + <&main_udmap 0x496c>, <&main_udmap 0x496d>, <&main_udmap 0x496e>, + <&main_udmap 0x496f>; + dma-names = "rx0", "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7", + "rx8", "rx9", "rx10", "rx11", "rx12", "rx13", "rx14", "rx15"; + power-domains = <&k3_pds 27 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + cdns_csi2rx1: csi-bridge@4514000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x0 0x4514000 0x0 0x1000>; + clocks = <&k3_clks 27 2>, <&k3_clks 27 0>, <&k3_clks 27 2>, + <&k3_clks 27 2>, <&k3_clks 27 3>, <&k3_clks 27 3>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy1>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi1_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi1_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi1_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi1_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + dphy0: phy@4580000 { + compatible = "cdns,dphy-rx"; + reg = <0x0 0x4580000 0x0 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 147 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + dphy1: phy@4590000 { + compatible = "cdns,dphy-rx"; + reg = <0x0 0x4590000 0x0 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 148 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + serdes_wiz0: wiz@5000000 { compatible = "ti,j721e-wiz-16g"; #address-cells = <1>; @@ -975,6 +1114,7 @@ assigned-clock-parents = <&k3_clks 49 2>; power-domains = <&k3_pds 49 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer1: timer@2410000 { @@ -987,6 +1127,7 @@ assigned-clock-parents = <&k3_clks 50 2>, <&k3_clks 327 1>; power-domains = <&k3_pds 50 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer2: timer@2420000 { @@ -999,6 +1140,7 @@ assigned-clock-parents = <&k3_clks 51 2>; power-domains = <&k3_pds 51 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer3: timer@2430000 { @@ -1119,6 +1261,7 @@ assigned-clock-parents = <&k3_clks 63 2>; power-domains = <&k3_pds 63 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer13: timer@24d0000 { @@ -1131,6 +1274,7 @@ assigned-clock-parents = <&k3_clks 64 2>, <&k3_clks 333 1>; power-domains = <&k3_pds 64 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer14: timer@24e0000 { @@ -1143,6 +1287,7 @@ assigned-clock-parents = <&k3_clks 65 2>; power-domains = <&k3_pds 65 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer15: timer@24f0000 { @@ -1155,6 +1300,7 @@ assigned-clock-parents = <&k3_clks 66 2>, <&k3_clks 334 1>; power-domains = <&k3_pds 66 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer16: timer@2500000 { @@ -1690,6 +1836,22 @@ status = "disabled"; }; + vxe384: video-encoder@4200000 { + compatible = "img,vxe384"; + reg = <0x00 0x04200000>, + <0x00 0x100000>; + power-domains = <&k3_pds 153 TI_SCI_PD_EXCLUSIVE>; + interrupts = ; + }; + + d5520: video-decoder@4300000 { + compatible = "img,d5500-vxd"; + reg = <0x00 0x04300000>, + <0x00 0x100000>; + power-domains = <&k3_pds 144 TI_SCI_PD_EXCLUSIVE>; + interrupts = ; + }; + ufs_wrapper: ufs-wrapper@4e80000 { compatible = "ti,j721e-ufs"; reg = <0x0 0x4e80000 0x0 0x100>; @@ -1743,6 +1905,24 @@ }; }; + dsi0: dsi@48000000 { + compatible = "ti,j721e-dsi"; + reg = <0x0 0x04800000 0x0 0x100000>, <0x0 0x04710000 0x0 0x100>; + clocks = <&k3_clks 150 1>, <&k3_clks 150 5>; + clock-names = "dsi_p_clk", "dsi_sys_clk"; + power-domains = <&k3_pds 150 TI_SCI_PD_EXCLUSIVE>; + interrupt-parent = <&gic500>; + interrupts = ; + phys = <&dphy2>; + phy-names = "dphy"; + status = "disabled"; + + dsi0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + dss: dss@4a00000 { compatible = "ti,j721e-dss"; reg = @@ -2032,7 +2212,7 @@ main_r5fss0: r5fss@5c00000 { compatible = "ti,j721e-r5fss"; - ti,cluster-mode = <1>; + ti,cluster-mode = <0>; #address-cells = <1>; #size-cells = <1>; ranges = <0x5c00000 0x00 0x5c00000 0x20000>, @@ -2072,7 +2252,7 @@ main_r5fss1: r5fss@5e00000 { compatible = "ti,j721e-r5fss"; - ti,cluster-mode = <1>; + ti,cluster-mode = <0>; #address-cells = <1>; #size-cells = <1>; ranges = <0x5e00000 0x00 0x5e00000 0x20000>, @@ -2151,6 +2331,17 @@ status = "disabled"; }; + timesync_router: pinctrl@a40000 { + compatible = "pinctrl-single"; + reg = <0x0 0xa40000 0x0 0x800>; + #address-cells = <1>; + #size-cells = <0>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x000107ff>; + status = "disabled"; + }; + icssg0: icssg@b000000 { compatible = "ti,j721e-icssg"; reg = <0x00 0xb000000 0x00 0x80000>; @@ -2435,6 +2626,19 @@ }; }; + gpu: gpu@4e20000000 { + compatible = "ti,j721e-pvr", "img,pvr-ge8430"; + reg = <0x4e 0x20000000 0x00 0x80000>; + interrupts = ; + power-domains = <&k3_pds 125 TI_SCI_PD_EXCLUSIVE>, + <&k3_pds 126 TI_SCI_PD_EXCLUSIVE>; + power-domain-names = "firmware", "dust"; + clocks = <&k3_clks 125 0>; + assigned-clocks = <&k3_clks 125 0>; + assigned-clock-rates = <750000000>; + clock-names = "core"; + }; + main_mcan0: can@2701000 { compatible = "bosch,m_can"; reg = <0x00 0x02701000 0x00 0x200>, @@ -2738,4 +2942,17 @@ reg = <0x0 0x700000 0x0 0x1000>; ti,esm-pins = <344>, <345>; }; + + dphy2: phy@4480000 { + compatible = "ti,j721e-dphy"; + reg = <0x0 0x04480000 0x0 0x1000>; + clocks = <&k3_clks 296 1>, <&k3_clks 296 3>; + clock-names = "psm", "pll_ref"; + #phy-cells = <0>; + power-domains = <&k3_pds 296 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 296 3>; + assigned-clock-parents = <&k3_clks 296 4>; + assigned-clock-rates = <19200000>; + status = "disabled"; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi --- a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree Source for J721E SoC Family MCU/WAKEUP Domain peripherals * - * Copyright (C) 2016-2020 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2016-2024 Texas Instruments Incorporated - https://www.ti.com/ */ &cbass_mcu_wakeup { @@ -48,9 +48,16 @@ }; }; - chipid@43000014 { - compatible = "ti,am654-chipid"; - reg = <0x0 0x43000014 0x0 0x4>; + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; wkup_pmx0: pinctrl@4301c000 { @@ -440,7 +447,7 @@ }; mcu_navss: bus@28380000 { - compatible = "simple-mfd"; + compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>; @@ -468,8 +475,12 @@ compatible = "ti,j721e-navss-mcu-udmap"; reg = <0x0 0x285c0000 0x0 0x100>, <0x0 0x2a800000 0x0 0x40000>, - <0x0 0x2aa00000 0x0 0x40000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x2aa00000 0x0 0x40000>, + <0x0 0x284a0000 0x0 0x4000>, + <0x0 0x284c0000 0x0 0x4000>, + <0x0 0x28400000 0x0 0x2000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; @@ -671,4 +682,11 @@ power-domains = <&k3_pds 154 TI_SCI_PD_EXCLUSIVE>; #thermal-sensor-cells = <1>; }; + + mcu_esm: esm@40800000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x40800000 0x00 0x1000>; + ti,esm-pins = <95>; + bootph-pre-ram; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-sk-csi2-dual-imx219.dtso b/arch/arm64/boot/dts/ti/k3-j721e-sk-csi2-dual-imx219.dtso --- a/arch/arm64/boot/dts/ti/k3-j721e-sk-csi2-dual-imx219.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-sk-csi2-dual-imx219.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT Overlay for dual RPi Camera V2.1 (Sony IMX219) interfaced with CSI2 + * on J721E SK, AM68 SK or AM69-SK board. + * https://datasheets.raspberrypi.org/camera/camera-v2-schematic.pdf + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&{/} { + clk_imx219_fixed: imx219-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&csi_mux { + idle-state = <1>; +}; + +/* CAM0 I2C */ +&cam0_i2c { + #address-cells = <1>; + #size-cells = <0>; + imx219_0: imx219-0@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed>; + clock-names = "xclk"; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +/* CAM1 I2C */ +&cam1_i2c { + #address-cells = <1>; + #size-cells = <0>; + imx219_1: imx219-1@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed>; + clock-names = "xclk"; + + port { + csi2_cam1: endpoint { + remote-endpoint = <&csi2rx1_in_sensor>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + + csi0_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi0_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi0_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi0_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx1_in_sensor: endpoint { + remote-endpoint = <&csi2_cam1>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + + csi1_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi1_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi1_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi1_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; +}; + +&dphy1 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-sk-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-j721e-sk-csi2-ov5640.dtso --- a/arch/arm64/boot/dts/ti/k3-j721e-sk-csi2-ov5640.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-sk-csi2-ov5640.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LI OV5640 MIPI Camera module on MIPI CSI connector. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&main_pmx0 { + csi2_exp_pins_default: csi2-exp-pins-default { + pinctrl-single,pins = < + J721E_IOPAD(0x140, PIN_OUTPUT, 7) /* (AG29) PRG0_PRU1_GPO16.GPIO0_79 */ + >; + }; +}; + +&cam0_i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + pinctrl-names = "default"; + pinctrl-0 = <&csi2_exp_pins_default>; + powerdown-gpios = <&main_gpio0 79 GPIO_ACTIVE_LOW>; + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts --- a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts 2024-07-07 20:37:34.632306489 -0400 @@ -1,6 +1,6 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* - * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/ * * J721E SK URL: https://www.ti.com/tool/SK-TDA4VM */ @@ -31,6 +31,7 @@ memory@80000000 { device_type = "memory"; + bootph-all; /* 4G RAM */ reg = <0x00000000 0x80000000 0x00000000 0x80000000>, <0x00000008 0x80000000 0x00000000 0x80000000>; @@ -41,6 +42,14 @@ #size-cells = <2>; ranges; + /* global cma region */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x00 0x20000000>; + linux,cma-default; + }; + secure_ddr: optee@9e800000 { reg = <0x00 0x9e800000 0x00 0x01800000>; alignment = <0x1000>; @@ -210,6 +219,42 @@ <3300000 0x1>; }; + transceiver1: can-phy1 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_gpio_pins_default>; + standby-gpios = <&wkup_gpio0 3 GPIO_ACTIVE_HIGH>; + }; + + transceiver2: can-phy2 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan0_gpio_pins_default>; + standby-gpios = <&main_gpio0 65 GPIO_ACTIVE_HIGH>; + }; + + transceiver3: can-phy3 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan5_gpio_pins_default>; + standby-gpios = <&main_gpio0 66 GPIO_ACTIVE_HIGH>; + }; + + transceiver4: can-phy4 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan9_gpio_pins_default>; + standby-gpios = <&main_gpio0 67 GPIO_ACTIVE_HIGH>; + }; + dp_pwr_3v3: fixedregulator-dp-prw { compatible = "regulator-fixed"; regulator-name = "dp-pwr"; @@ -286,6 +331,15 @@ }; }; }; + + csi_mux: mux-controller { + compatible = "gpio-mux"; + #mux-state-cells = <1>; + mux-gpios = <&main_gpio0 88 GPIO_ACTIVE_HIGH>; + idle-state = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&main_csi_mux_sel_pins_default>; + }; }; &main_pmx0 { @@ -352,6 +406,51 @@ >; }; + main_csi_mux_sel_pins_default: main-csi-mux-sel-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x164, PIN_OUTPUT, 7) /* (V29) RGMII5_TD2 */ + >; + }; + + main_mcan0_pins_default: main-mcan0-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x208, PIN_INPUT, 0) /* (W5) MCAN0_RX */ + J721E_IOPAD(0x20c, PIN_OUTPUT, 0) /* (W6) MCAN0_TX */ + >; + }; + + main_mcan0_gpio_pins_default: main-mcan0-gpio-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x108, PIN_INPUT, 7) /* (AD27) PRG0_PRU1_GPO2.GPIO0_65 */ + >; + }; + + main_mcan5_pins_default: main-mcan5-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x050, PIN_INPUT, 6) /* (AE21) PRG1_PRU0_GPO18.MCAN5_RX */ + J721E_IOPAD(0x04c, PIN_OUTPUT, 6) /* (AJ21) PRG1_PRU0_GPO17.MCAN5_TX */ + >; + }; + + main_mcan5_gpio_pins_default: main-mcan5-gpio-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x10c, PIN_INPUT, 7) /* (AC25) PRG0_PRU1_GPO3.GPIO0_66 */ + >; + }; + + main_mcan9_pins_default: main-mcan9-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x0d0, PIN_INPUT, 6) /* (AC27) PRG0_PRU0_GPO8.MCAN9_RX */ + J721E_IOPAD(0x0cc, PIN_OUTPUT, 6) /* (AC28) PRG0_PRU0_GPO7.MCAN9_TX */ + >; + }; + + main_mcan9_gpio_pins_default: main-mcan9-gpio-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x110, PIN_INPUT, 7) /* (AD29) PRG0_PRU1_GPO4.GPIO0_67 */ + >; + }; + dp0_pins_default: dp0-default-pins { pinctrl-single,pins = < J721E_IOPAD(0x1c4, PIN_INPUT, 5) /* SPI0_CS1.DP0_HPD */ @@ -459,6 +558,12 @@ }; &wkup_pmx0 { + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x0cc, PIN_INPUT, 7) /* (G28) WKUP_GPIO0_7 */ + >; + }; + mcu_cpsw_pins_default: mcu-cpsw-default-pins { pinctrl-single,pins = < J721E_WKUP_IOPAD(0x84, PIN_INPUT, 0) /* (B24) MCU_RGMII1_RD0 */ @@ -534,6 +639,19 @@ >; }; + mcu_mcan0_pins_default: mcu-mcan0-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x0ac, PIN_INPUT, 0) /* (C29) MCU_MCAN0_RX */ + J721E_WKUP_IOPAD(0x0a8, PIN_OUTPUT, 0) /* (D29) MCU_MCAN0_TX */ + >; + }; + + mcu_mcan0_gpio_pins_default: mcu-mcan0-gpio-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x0bc, PIN_INPUT, 7) /* (F27) WKUP_GPIO0_3 */ + >; + }; + /* Reset for M.2 M Key slot on PCIe1 */ mkey_reset_pins_default: mkey-reset-pns-default-pins { pinctrl-single,pins = < @@ -560,6 +678,151 @@ compatible = "atmel,24c512"; reg = <0x51>; }; + + tps659413: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck123-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka123: buck123 { + regulator-name = "vdd_cpu_avs"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + regulator-always-on; + bootph-pre-ram; + }; + + bucka4: buck4 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka5: buck5 { + regulator-name = "vdd_phyio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd1_lpddr4_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vdda_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + tps659411: pmic@4c { + compatible = "ti,tps6594-q1"; + reg = <0x4c>; + system-power-controller; + interrupt-parent = <&wkup_gpio0>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + buck1234-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + buckb1234: buck1234 { + regulator-name = "vdd_core_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb5: buck5 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob1: ldo1 { + regulator-name = "vdd_sd_dv"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob2: ldo2 { + regulator-name = "vdd_usb_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob3: ldo3 { + regulator-name = "vdd_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob4: ldo4 { + regulator-name = "vda_pll_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; }; &mcu_uart0 { @@ -707,14 +970,14 @@ reg = <0x70>; /* CSI0 I2C */ - i2c@0 { + cam0_i2c: i2c@0 { #address-cells = <1>; #size-cells = <0>; reg = <0>; }; /* CSI1 I2C */ - i2c@1 { + cam1_i2c: i2c@1 { #address-cells = <1>; #size-cells = <0>; reg = <1>; @@ -780,7 +1043,7 @@ resets = <&serdes_wiz4 1>; cdns,phy-type = ; cdns,num-lanes = <4>; - cdns,max-bit-rate = <5400>; + cdns,max-bit-rate = <2700>; #phy-cells = <0>; }; }; @@ -942,6 +1205,34 @@ num-lanes = <2>; }; +&mcu_mcan0 { + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_pins_default>; + phys = <&transceiver1>; + status = "okay"; +}; + +&main_mcan0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan0_pins_default>; + phys = <&transceiver2>; + status = "okay"; +}; + +&main_mcan5 { + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan5_pins_default>; + phys = <&transceiver3>; + status = "okay"; +}; + +&main_mcan9 { + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan9_pins_default>; + phys = <&transceiver4>; + status = "okay"; +}; + &ufs_wrapper { status = "disabled"; }; @@ -1017,58 +1308,58 @@ }; &mcu_r5fss0_core0 { - mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>; + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>; memory-region = <&mcu_r5fss0_core0_dma_memory_region>, <&mcu_r5fss0_core0_memory_region>; }; &mcu_r5fss0_core1 { - mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core1>; + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>; memory-region = <&mcu_r5fss0_core1_dma_memory_region>, <&mcu_r5fss0_core1_memory_region>; }; &main_r5fss0_core0 { - mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core0>; + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>; memory-region = <&main_r5fss0_core0_dma_memory_region>, <&main_r5fss0_core0_memory_region>; }; &main_r5fss0_core1 { - mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core1>; + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>; memory-region = <&main_r5fss0_core1_dma_memory_region>, <&main_r5fss0_core1_memory_region>; }; &main_r5fss1_core0 { - mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core0>; + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>; memory-region = <&main_r5fss1_core0_dma_memory_region>, <&main_r5fss1_core0_memory_region>; }; &main_r5fss1_core1 { - mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core1>; + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>; memory-region = <&main_r5fss1_core1_dma_memory_region>, <&main_r5fss1_core1_memory_region>; }; &c66_0 { status = "okay"; - mboxes = <&mailbox0_cluster3>, <&mbox_c66_0>; + mboxes = <&mailbox0_cluster3 &mbox_c66_0>; memory-region = <&c66_0_dma_memory_region>, <&c66_0_memory_region>; }; &c66_1 { status = "okay"; - mboxes = <&mailbox0_cluster3>, <&mbox_c66_1>; + mboxes = <&mailbox0_cluster3 &mbox_c66_1>; memory-region = <&c66_1_dma_memory_region>, <&c66_1_memory_region>; }; &c71_0 { status = "okay"; - mboxes = <&mailbox0_cluster4>, <&mbox_c71_0>; + mboxes = <&mailbox0_cluster4 &mbox_c71_0>; memory-region = <&c71_0_dma_memory_region>, <&c71_0_memory_region>; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-sk-fpdlink-fusion.dtso b/arch/arm64/boot/dts/ti/k3-j721e-sk-fpdlink-fusion.dtso --- a/arch/arm64/boot/dts/ti/k3-j721e-sk-fpdlink-fusion.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-sk-fpdlink-fusion.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Fusion (FPD-Link III) board on J721E SK, + * AM68 SK or AM69 SK. + * https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/ + * + * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + + +&cam0_i2c { + #address-cells = <1>; + #size-cells = <0>; + + deser@3d { + compatible = "ti,ds90ub960-q1"; + reg = <0x3d>; + clocks = <&clk_fusion_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX*/ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + deser@36 { + compatible = "ti,ds90ub960-q1"; + reg = <0x36>; + clocks = <&clk_fusion_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX*/ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy1 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-sk-rpi-hdr-ehrpwm.dtso b/arch/arm64/boot/dts/ti/k3-j721e-sk-rpi-hdr-ehrpwm.dtso --- a/arch/arm64/boot/dts/ti/k3-j721e-sk-rpi-hdr-ehrpwm.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721e-sk-rpi-hdr-ehrpwm.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for enabling EHRPWMs on RPi expansion header on J721E SK board. + * + * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include "k3-pinctrl.h" + +&main_pmx0 { + rpi_header_gpio0_pins_default: rpi-header-gpio0-pins-default { + pinctrl-single,pins = < + J721E_IOPAD(0x01C, PIN_INPUT, 7) /* (AD22) PRG1_PRU0_GPO6.GPIO0_7 */ + J721E_IOPAD(0x120, PIN_INPUT, 7) /* (AD28) PRG0_PRU1_GPO8.GPIO0_71 */ + J721E_IOPAD(0x14C, PIN_INPUT, 7) /* (AD29) PRG0_PRU1_GPO19.GPIO0_82 */ + J721E_IOPAD(0x02C, PIN_INPUT, 7) /* (AD21) PRG1_PRU0_GPO10.GPIO0_11 */ + J721E_IOPAD(0x198, PIN_INPUT, 7) /* (V25) RGMII6_TD1.GPIO0_101 */ + J721E_IOPAD(0x1B0, PIN_INPUT, 7) /* (W24) RGMII6_RD1.GPIO0_107 */ + J721E_IOPAD(0x1A0, PIN_INPUT, 7) /* (W29) RGMII6_TXC.GPIO0_103 */ + J721E_IOPAD(0x008, PIN_INPUT, 7) /* (AG22) PRG1_PRU0_GPO1.GPIO0_2 */ + J721E_IOPAD(0x1D0, PIN_INPUT, 7) /* (AA3) SPI0_D1.GPIO0_115 */ + J721E_IOPAD(0x11C, PIN_INPUT, 7) /* (AA24) PRG0_PRU1_GPO7.GPIO0_70 */ + J721E_IOPAD(0x148, PIN_INPUT, 7) /* (AA26) PRG0_PRU1_GPO18.GPIO0_81 */ + J721E_IOPAD(0x004, PIN_INPUT, 7) /* (AC23) PRG1_PRU0_GPO0.GPIO0_1 */ + J721E_IOPAD(0x014, PIN_INPUT, 7) /* (AH23) PRG1_PRU0_GPO4.GPIO0_5 */ + J721E_IOPAD(0x020, PIN_INPUT, 7) /* (AE20) PRG1_PRU0_GPO7.GPIO0_8 */ + J721E_IOPAD(0x19C, PIN_INPUT, 7) /* (W27) RGMII6_TD0.GPIO0_102 */ + J721E_IOPAD(0x1B4, PIN_INPUT, 7) /* (W25) RGMII6_RD0.GPIO0_108 */ + J721E_IOPAD(0x188, PIN_INPUT, 7) /* (Y28) RGMII6_TX_CTL.GPIO0_97 */ + J721E_IOPAD(0x00C, PIN_INPUT, 7) /* (AF22) PRG1_PRU0_GPO2.GPIO0_3 */ + J721E_IOPAD(0x010, PIN_INPUT, 7) /* (AJ23) PRG1_PRU0_GPO3.GPIO0_4 */ + >; + }; + + rpi_header_ehrpwm2_pins_default: rpi-header-ehrpwm2-pins-default { + pinctrl-single,pins = < + J721E_IOPAD(0x178, PIN_INPUT, 6) /* (U27) RGMII5_RD3.EHRPWM2_A */ + J721E_IOPAD(0x17C, PIN_INPUT, 6) /* (U24) RGMII5_RD2.EHRPWM2_B */ + >; + }; + + rpi_header_ehrpwm3_pins_default: rpi-header-ehrpwm3-pins-default { + pinctrl-single,pins = < + J721E_IOPAD(0x18C, PIN_INPUT, 6) /* (V23) RGMII6_RX_CTL.EHRPWM3_A */ + J721E_IOPAD(0x190, PIN_INPUT, 6) /* (W23) RGMII6_TD3.EHRPWM3_B */ + >; + }; +}; + +&main_ehrpwm2 { + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm2_pins_default>; + status = "okay"; +}; + +&main_ehrpwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_ehrpwm3_pins_default>; + status = "okay"; +}; + +&main_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = <&rpi_header_gpio0_pins_default>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi --- a/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -1,6 +1,6 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* - * Copyright (C) 2019-2020 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2019-2024 Texas Instruments Incorporated - https://www.ti.com/ * * Product Link: https://www.ti.com/tool/J721EXSOMXEVM */ @@ -12,6 +12,7 @@ / { memory@80000000 { device_type = "memory"; + bootph-all; /* 4G RAM */ reg = <0x00000000 0x80000000 0x00000000 0x80000000>, <0x00000008 0x80000000 0x00000000 0x80000000>; @@ -22,6 +23,14 @@ #size-cells = <2>; ranges; + /* global cma region */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x00 0x20000000>; + linux,cma-default; + }; + secure_ddr: optee@9e800000 { reg = <0x00 0x9e800000 0x00 0x01800000>; alignment = <0x1000>; @@ -152,6 +161,12 @@ >; }; + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x0d4, PIN_INPUT, 7) /* (G26) WKUP_GPIO0_9 */ + >; + }; + mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-default-pins { pinctrl-single,pins = < J721E_WKUP_IOPAD(0x0000, PIN_OUTPUT, 0) /* MCU_OSPI0_CLK */ @@ -199,6 +214,160 @@ compatible = "atmel,24c256"; reg = <0x50>; }; + + tps659413: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck12-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka12: buck12 { + regulator-name = "vdd_cpu_avs"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + regulator-always-on; + bootph-pre-ram; + }; + + bucka3: buck3 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka4: buck4 { + regulator-name = "vdd_ddr_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka5: buck5 { + regulator-name = "vdd_phyio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd1_lpddr4_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vdda_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + tps659411: pmic@4c { + compatible = "ti,tps6594-q1"; + reg = <0x4c>; + system-power-controller; + interrupt-parent = <&wkup_gpio0>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + buck1234-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + buckb1234: buck1234 { + regulator-name = "vdd_core_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb5: buck5 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob1: ldo1 { + regulator-name = "vdd_sd_dv"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob2: ldo2 { + regulator-name = "vdd_usb_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob3: ldo3 { + regulator-name = "vdd_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob4: ldo4 { + regulator-name = "vda_pll_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; }; &ospi0 { @@ -389,58 +558,58 @@ }; &mcu_r5fss0_core0 { - mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>; + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>; memory-region = <&mcu_r5fss0_core0_dma_memory_region>, <&mcu_r5fss0_core0_memory_region>; }; &mcu_r5fss0_core1 { - mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core1>; + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>; memory-region = <&mcu_r5fss0_core1_dma_memory_region>, <&mcu_r5fss0_core1_memory_region>; }; &main_r5fss0_core0 { - mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core0>; + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>; memory-region = <&main_r5fss0_core0_dma_memory_region>, <&main_r5fss0_core0_memory_region>; }; &main_r5fss0_core1 { - mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core1>; + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>; memory-region = <&main_r5fss0_core1_dma_memory_region>, <&main_r5fss0_core1_memory_region>; }; &main_r5fss1_core0 { - mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core0>; + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>; memory-region = <&main_r5fss1_core0_dma_memory_region>, <&main_r5fss1_core0_memory_region>; }; &main_r5fss1_core1 { - mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core1>; + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>; memory-region = <&main_r5fss1_core1_dma_memory_region>, <&main_r5fss1_core1_memory_region>; }; &c66_0 { status = "okay"; - mboxes = <&mailbox0_cluster3>, <&mbox_c66_0>; + mboxes = <&mailbox0_cluster3 &mbox_c66_0>; memory-region = <&c66_0_dma_memory_region>, <&c66_0_memory_region>; }; &c66_1 { status = "okay"; - mboxes = <&mailbox0_cluster3>, <&mbox_c66_1>; + mboxes = <&mailbox0_cluster3 &mbox_c66_1>; memory-region = <&c66_1_dma_memory_region>, <&c66_1_memory_region>; }; &c71_0 { status = "okay"; - mboxes = <&mailbox0_cluster4>, <&mbox_c71_0>; + mboxes = <&mailbox0_cluster4 &mbox_c71_0>; memory-region = <&c71_0_dma_memory_region>, <&c71_0_memory_region>; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721e-thermal.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-thermal.dtsi --- a/arch/arm64/boot/dts/ti/k3-j721e-thermal.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721e-thermal.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -1,4 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ #include diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts --- a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts 2024-07-07 20:37:34.632306489 -0400 @@ -128,6 +128,52 @@ standby-gpios = <&exp_som 7 GPIO_ACTIVE_HIGH>; mux-states = <&mux1 1>; }; + + dp0_pwr_3v3: fixedregulator-dp0-prw { + compatible = "regulator-fixed"; + regulator-name = "dp0-pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&exp4 0 0>; /* P0 - DP0_PWR_SW_EN */ + enable-active-high; + }; + + dp1_pwr_3v3: regulator-dp1-prw { + compatible = "regulator-fixed"; + regulator-name = "dp1-pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&exp4 1 GPIO_ACTIVE_HIGH>; /* P1 - DP1_PWR_SW_EN */ + enable-active-high; + regulator-always-on; + }; + + dp0: dp0-connector { + compatible = "dp-connector"; + label = "DP0"; + type = "full-size"; + dp-pwr-supply = <&dp0_pwr_3v3>; + + port { + dp0_connector_in: endpoint { + remote-endpoint = <&dp0_out>; + }; + }; + }; +}; + +&main_i2c4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c4_pins_default>; + clock-frequency = <400000>; + + exp4: gpio@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + }; }; &main_pmx0 { @@ -147,6 +193,13 @@ >; }; + main_i2c5_pins_default: main-i2c5-default-pins { + pinctrl-single,pins = < + J721S2_IOPAD(0x01c, PIN_INPUT, 8) /* (Y24) MCAN15_TX.I2C5_SCL */ + J721S2_IOPAD(0x018, PIN_INPUT, 8) /* (W23) MCAN14_RX.I2C5_SDA */ + >; + }; + main_mmc1_pins_default: main-mmc1-default-pins { pinctrl-single,pins = < J721S2_IOPAD(0x104, PIN_INPUT, 0) /* (P23) MMC1_CLK */ @@ -185,6 +238,19 @@ J721S2_IOPAD(0x038, PIN_OUTPUT, 0) /* (AB28) MCASP0_ACLKX.MCAN5_TX */ >; }; + + main_i2c4_pins_default: main-i2c4-pins-default { + pinctrl-single,pins = < + J721S2_IOPAD(0x014, PIN_INPUT_PULLUP, 8) /* (AD25) I2C4_SCL */ + J721S2_IOPAD(0x010, PIN_INPUT_PULLUP, 8) /* (AF28) I2C4_SDA */ + >; + }; + + dp0_pins_default: dp0-pins-default { + pinctrl-single,pins = < + J721S2_IOPAD(0x0b8, PIN_INPUT, 3) /* (AA24) MCASP1_ACLKX.DP0_HPD */ + >; + }; }; &wkup_pmx2 { @@ -354,6 +420,24 @@ }; }; +&main_i2c5 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c5_pins_default>; + clock-frequency = <400000>; + status = "okay"; + + exp5: gpio@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "CSI2_EXP_RSTZ", "CSI2_EXP_A_GPIO0", + "CSI2_EXP_A_GPIO1", "CSI2_EXP_A_GPIO2", + "CSI2_EXP_B_GPIO1", "CSI2_EXP_B_GPIO2", + "CSI2_EXP_B_GPIO3", "CSI2_EXP_B_GPIO4"; + }; +}; + &main_sdhci0 { /* eMMC */ status = "okay"; @@ -375,6 +459,11 @@ &mcu_cpsw { pinctrl-names = "default"; pinctrl-0 = <&mcu_cpsw_pins_default>, <&mcu_mdio_pins_default>; + + cpts@3d000 { + /* Map HW4_TS_PUSH to GENF1 */ + ti,pps = <3 1>; + }; }; &davinci_mdio { @@ -415,6 +504,10 @@ idle-states = <1>; /* USB0 to SERDES lane 1 */ }; +&edp_serdes_mux { + idle-states = <1>; /* EDP0 to SERDES lane 2/3 */ +}; + &usbss0 { status = "okay"; pinctrl-0 = <&main_usbss0_pins_default>; @@ -433,7 +526,7 @@ pinctrl-names = "default"; pinctrl-0 = <&mcu_fss0_ospi1_pins_default>; - flash@0 { + ospi1_nor: flash@0 { compatible = "jedec,spi-nor"; reg = <0x0>; spi-tx-bus-width = <1>; @@ -444,6 +537,47 @@ cdns,tchsh-ns = <60>; cdns,tslch-ns = <60>; cdns,read-delay = <2>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "qspi.tiboot3"; + reg = <0x0 0x80000>; + }; + + partition@80000 { + label = "qspi.tispl"; + reg = <0x80000 0x200000>; + }; + + partition@280000 { + label = "qspi.u-boot"; + reg = <0x280000 0x400000>; + }; + + partition@680000 { + label = "qspi.env"; + reg = <0x680000 0x40000>; + }; + + partition@6c0000 { + label = "qspi.env.backup"; + reg = <0x6c0000 0x40000>; + }; + + partition@800000 { + label = "qspi.rootfs"; + reg = <0x800000 0x37c0000>; + }; + + partition@3fc0000 { + label = "qspi.phypattern"; + reg = <0x3fc0000 0x40000>; + }; + }; }; }; @@ -500,3 +634,139 @@ pinctrl-0 = <&main_mcan5_pins_default>; phys = <&transceiver4>; }; + +&dss { + /* + * These clock assignments are chosen to enable the following outputs: + * + * VP0 - DisplayPort SST + * VP1 - DPI0 + * VP2 - DSI + * VP3 - DPI1 + */ + status = "okay"; + assigned-clocks = <&k3_clks 158 2>, + <&k3_clks 158 5>, + <&k3_clks 158 14>, + <&k3_clks 158 18>; + assigned-clock-parents = <&k3_clks 158 3>, + <&k3_clks 158 7>, + <&k3_clks 158 16>, + <&k3_clks 158 22>; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpi0_out: endpoint { + remote-endpoint = <&dp0_in>; + }; + }; + + port@2 { + reg = <2>; + dpi2_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; +}; + +&mhdp { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&dp0_pins_default>; + cdns,no-hpd; +}; + +&dp0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dp0_in: endpoint { + remote-endpoint = <&dpi0_out>; + }; + }; + + port@4 { + reg = <4>; + dp0_out: endpoint { + remote-endpoint = <&dp0_connector_in>; + }; + }; +}; + +&dsi0_ports { + port@0 { + reg = <0>; + dsi0_out: endpoint { + remote-endpoint = <&dp1_in>; + }; + }; + + port@1 { + reg = <1>; + dsi0_in: endpoint { + remote-endpoint = <&dpi2_out>; + }; + }; +}; + +&dsi_edp_bridge_ports { + port@0 { + reg = <0>; + dp1_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + dp1_out: endpoint { + remote-endpoint = <&dp1_panel_in>; + }; + }; +}; + +&dsi_edp_bridge { + aux-bus { + panel { + compatible = "ti,panel-edp"; + power-supply = <&dp1_pwr_3v3>; + + port { + dp1_panel_in: endpoint { + remote-endpoint = <&dp1_out>; + }; + }; + }; + }; +}; + +&dphy_tx0 { + status = "okay"; +}; + +&dsi0 { + status = "okay"; +}; + +#define K3_TS_OFFSET(pa, val) (0x4+(pa)*4) (0x10000 | val) + +×ync_router { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_cpsw_cpts>; + + /* Use Time Sync Router to map GENF1 input to HW4_TS_PUSH output */ + mcu_cpsw_cpts: mcu-cpsw-cpts { + pinctrl-single,pins = < + /* pps [mcu cpsw cpts genf1] in17 -> out25 [mcu cpsw cpts hw4_push] */ + K3_TS_OFFSET(25, 17) + >; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721s2.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2.dtsi --- a/arch/arm64/boot/dts/ti/k3-j721s2.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721s2.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -117,6 +117,8 @@ #size-cells = <2>; ranges = <0x00 0x00100000 0x00 0x00100000 0x00 0x00020000>, /* ctrl mmr */ <0x00 0x00600000 0x00 0x00600000 0x00 0x00031100>, /* GPIO */ + <0x00 0x00a40000 0x00 0x00a40000 0x00 0x00000800>, /* Time Sync Router */ + <0x00 0x00700000 0x00 0x00700000 0x00 0x00001000>, /* ESM */ <0x00 0x01000000 0x00 0x01000000 0x00 0x0d000000>, /* Most peripherals */ <0x00 0x0d800000 0x00 0x0d800000 0x00 0x00800000>, /* PCIe Core*/ <0x00 0x18000000 0x00 0x18000000 0x00 0x08000000>, /* PCIe1 DAT0 */ diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721s2-evm-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-j721s2-evm-csi2-ov5640.dtso --- a/arch/arm64/boot/dts/ti/k3-j721s2-evm-csi2-ov5640.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721s2-evm-csi2-ov5640.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LI OV5640 MIPI Camera module on MIPI CSI connector. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&main_i2c5 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + powerdown-gpios = <&exp5 0 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721s2-evm-fusion.dtso b/arch/arm64/boot/dts/ti/k3-j721s2-evm-fusion.dtso --- a/arch/arm64/boot/dts/ti/k3-j721s2-evm-fusion.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721s2-evm-fusion.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Fusion (FPD-Link III) board on J721S2 and J784S4 EVM + * https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + + +&main_i2c5 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + deser@3d { + compatible = "ti,ds90ub960-q1"; + reg = <0x3d>; + clocks = <&clk_fusion_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + deser@36 { + compatible = "ti,ds90ub960-q1"; + reg = <0x36>; + clocks = <&clk_fusion_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy1 { + status = "okay"; +}; \ No newline at end of file diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721s2-evm-pcie1-ep.dtso b/arch/arm64/boot/dts/ti/k3-j721s2-evm-pcie1-ep.dtso --- a/arch/arm64/boot/dts/ti/k3-j721s2-evm-pcie1-ep.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j721s2-evm-pcie1-ep.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for enabling PCIE1 instance in Endpoint Configuration with the + * J7 common processor board. + * + * J7 Common Processor Board Product Link: https://www.ti.com/tool/J721EXCPXEVM + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +/* + * Since Root Complex and Endpoint modes are mutually exclusive + * disable Root Complex mode. + */ +&pcie1_rc { + status = "disabled"; +}; + +&cbass_main { + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&gic500>; + + pcie1_ep: pcie-ep@2910000 { + compatible = "ti,j7200-pcie-ep", "ti,j721e-pcie-ep"; + reg = <0x00 0x02910000 0x00 0x1000>, + <0x00 0x02917000 0x00 0x400>, + <0x00 0x0d800000 0x00 0x00800000>, + <0x00 0x18000000 0x00 0x08000000>; + reg-names = "intd_cfg", "user_cfg", "reg", "mem"; + interrupt-names = "link_state"; + interrupts = ; + ti,syscon-pcie-ctrl = <&scm_conf 0x074>; + max-link-speed = <3>; + num-lanes = <1>; + power-domains = <&k3_pds 276 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 276 41>; + clock-names = "fck"; + max-functions = /bits/ 8 <6>; + max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>; + dma-coherent; + phys = <&serdes0_pcie_link>; + phy-names = "pcie-phy"; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi --- a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -4,6 +4,7 @@ * * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/ */ +#include #include #include @@ -45,7 +46,7 @@ ranges = <0x00 0x00 0x00104000 0x18000>; usb_serdes_mux: mux-controller@0 { - compatible = "mmio-mux"; + compatible = "reg-mux"; reg = <0x0 0x4>; #mux-control-cells = <1>; mux-reg-masks = <0x0 0x8000000>; /* USB0 to SERDES0 lane 1/3 mux */ @@ -58,11 +59,11 @@ }; serdes_ln_ctrl: mux-controller@80 { - compatible = "mmio-mux"; + compatible = "reg-mux"; reg = <0x80 0x10>; #mux-control-cells = <1>; - mux-reg-masks = <0x80 0x3>, <0x84 0x3>, /* SERDES0 lane0/1 select */ - <0x88 0x3>, <0x8c 0x3>; /* SERDES0 lane2/3 select */ + mux-reg-masks = <0x0 0x3>, <0x4 0x3>, /* SERDES0 lane0/1 select */ + <0x8 0x3>, <0xc 0x3>; /* SERDES0 lane2/3 select */ }; ehrpwm_tbclk: clock-controller@140 { @@ -70,6 +71,14 @@ reg = <0x140 0x18>; #clock-cells = <1>; }; + + edp_serdes_mux: mux-controller@310 { + compatible = "mmio-mux"; + reg = <0x310 0x4>; + #mux-control-cells = <1>; + /* EDP0 to SERDES0 lane 0/1 or 2/3 mux */ + mux-reg-masks = <0x310 0x10000000>; + }; }; main_ehrpwm0: pwm@3000000 { @@ -225,6 +234,7 @@ assigned-clock-parents = <&k3_clks 63 2>; power-domains = <&k3_pds 63 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer1: timer@2410000 { @@ -237,6 +247,7 @@ assigned-clock-parents = <&k3_clks 64 2>; power-domains = <&k3_pds 64 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer2: timer@2420000 { @@ -249,6 +260,7 @@ assigned-clock-parents = <&k3_clks 65 2>; power-domains = <&k3_pds 65 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer3: timer@2430000 { @@ -261,6 +273,7 @@ assigned-clock-parents = <&k3_clks 66 2>; power-domains = <&k3_pds 66 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer4: timer@2440000 { @@ -273,6 +286,7 @@ assigned-clock-parents = <&k3_clks 67 2>; power-domains = <&k3_pds 67 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer5: timer@2450000 { @@ -285,6 +299,7 @@ assigned-clock-parents = <&k3_clks 68 2>; power-domains = <&k3_pds 68 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer6: timer@2460000 { @@ -565,6 +580,19 @@ status = "disabled"; }; + gpu: gpu@4e20000000 { + compatible = "ti,j721s2-pvr", "img,pvr-bxs64"; + reg = <0x4e 0x20000000 0x00 0x80000>; + interrupts = ; + power-domains = <&k3_pds 130 TI_SCI_PD_EXCLUSIVE>, + <&k3_pds 373 TI_SCI_PD_EXCLUSIVE>; + power-domain-names = "firmware", "dust"; + clocks = <&k3_clks 130 1>; + assigned-clocks = <&k3_clks 130 1>; + assigned-clock-rates = <800000000>; + clock-names = "core"; + }; + main_gpio0: gpio@600000 { compatible = "ti,j721e-gpio", "ti,keystone-gpio"; reg = <0x00 0x00600000 0x00 0x100>; @@ -716,6 +744,16 @@ status = "disabled"; }; + vpu: video-codec@4210000 { + compatible = "ti,j721s2-wave521c", "cnm,wave521c"; + reg = <0x00 0x4210000 0x00 0x10000>; + interrupts = ; + clocks = <&k3_clks 179 2>; + power-domains = <&k3_pds 179 TI_SCI_PD_EXCLUSIVE>; + sram = <&main_navss_sram>; + sram-size = <0x10000>; + }; + main_sdhci0: mmc@4f80000 { compatible = "ti,j721e-sdhci-8bit"; reg = <0x00 0x04f80000 0x00 0x1000>, @@ -766,16 +804,15 @@ ti,itap-del-sel-sd-hs = <0x0>; ti,itap-del-sel-sdr12 = <0x0>; ti,itap-del-sel-sdr25 = <0x0>; + ti,itap-del-sel-ddr50 = <0x2>; ti,clkbuf-sel = <0x7>; ti,trm-icp = <0x8>; dma-coherent; - /* Masking support for SDR104 capability */ - sdhci-caps-mask = <0x00000003 0x00000000>; status = "disabled"; }; main_navss: bus@30000000 { - compatible = "simple-mfd"; + compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; ranges = <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>; @@ -783,6 +820,14 @@ dma-coherent; dma-ranges; + main_navss_sram: navss-sram@30000000{ + compatible = "mmio-sram"; + reg = <0x00 0x30000000 0x00 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x30000000 0x10000>; + }; + main_navss_intr: interrupt-controller@310e0000 { compatible = "ti,sci-intr"; reg = <0x00 0x310e0000 0x00 0x4000>; @@ -807,6 +852,7 @@ ti,sci = <&sms>; ti,sci-dev-id = <265>; ti,interrupt-ranges = <0 0 256>; + ti,unmapped-event-sources = <&main_bcdma_csi>; }; secure_proxy_main: mailbox@32c00000 { @@ -1085,8 +1131,12 @@ compatible = "ti,j721e-navss-main-udmap"; reg = <0x0 0x31150000 0x0 0x100>, <0x0 0x34000000 0x0 0x80000>, - <0x0 0x35000000 0x0 0x200000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x35000000 0x0 0x200000>, + <0x0 0x30b00000 0x0 0x20000>, + <0x0 0x30c00000 0x0 0x8000>, + <0x0 0x30d00000 0x0 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; @@ -1103,6 +1153,21 @@ ti,sci-rm-range-rflow = <0x00>; /* GP RFLOW */ }; + main_bcdma_csi: dma-controller@311a0000 { + compatible = "ti,j721s2-dmss-bcdma-csi"; + reg = <0x00 0x311a0000 0x00 0x100>, + <0x00 0x35d00000 0x00 0x20000>, + <0x00 0x35c00000 0x00 0x10000>, + <0x00 0x35e00000 0x00 0x80000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + msi-parent = <&main_udmass_inta>; + #dma-cells = <3>; + ti,sci = <&sms>; + ti,sci-dev-id = <225>; + ti,sci-rm-range-rchan = <0x21>; + ti,sci-rm-range-tchan = <0x22>; + }; + cpts@310d0000 { compatible = "ti,j721e-cpts"; reg = <0x0 0x310d0000 0x0 0x400>; @@ -1211,6 +1276,134 @@ }; }; + ti_csi2rx0: ticsi2rx@4500000 { + compatible = "ti,j721e-csi2rx-shim"; + reg = <0x00 0x04500000 0x00 0x1000>; + ranges; + #address-cells = <2>; + #size-cells = <2>; + dmas = <&main_bcdma_csi 0 0x4940 0>, <&main_bcdma_csi 0 0x4941 0>, + <&main_bcdma_csi 0 0x4942 0>, <&main_bcdma_csi 0 0x4943 0>, + <&main_bcdma_csi 0 0x4944 0>, <&main_bcdma_csi 0 0x4945 0>, + <&main_bcdma_csi 0 0x4946 0>, <&main_bcdma_csi 0 0x4947 0>; + dma-names = "rx0", "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7"; + power-domains = <&k3_pds 38 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + cdns_csi2rx0: csi-bridge@4504000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x04504000 0x00 0x1000>; + clocks = <&k3_clks 38 3>, <&k3_clks 38 1>, <&k3_clks 38 3>, + <&k3_clks 38 3>, <&k3_clks 38 4>, <&k3_clks 38 4>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi0_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi0_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi0_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi0_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + ti_csi2rx1: ticsi2rx@4510000 { + compatible = "ti,j721e-csi2rx-shim"; + reg = <0x00 0x04510000 0x00 0x1000>; + ranges; + #address-cells = <2>; + #size-cells = <2>; + dmas = <&main_bcdma_csi 0 0x4960 0>, <&main_bcdma_csi 0 0x4961 0>, + <&main_bcdma_csi 0 0x4962 0>, <&main_bcdma_csi 0 0x4963 0>, + <&main_bcdma_csi 0 0x4964 0>, <&main_bcdma_csi 0 0x4965 0>, + <&main_bcdma_csi 0 0x4966 0>, <&main_bcdma_csi 0 0x4967 0>; + dma-names = "rx0", "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7"; + power-domains = <&k3_pds 39 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + cdns_csi2rx1: csi-bridge@4514000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x04514000 0x00 0x1000>; + clocks = <&k3_clks 39 3>, <&k3_clks 39 1>, <&k3_clks 39 3>, + <&k3_clks 39 3>, <&k3_clks 39 4>, <&k3_clks 39 4>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy1>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi1_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi1_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi1_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi1_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + dphy0: phy@4580000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x04580000 0x00 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 152 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + dphy1: phy@4590000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x04590000 0x00 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 153 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + serdes_wiz0: wiz@5060000 { compatible = "ti,j721s2-wiz-10g"; #address-cells = <1>; @@ -1221,15 +1414,21 @@ num-lanes = <4>; #reset-cells = <1>; #clock-cells = <1>; - ranges = <0x5060000 0x0 0x5060000 0x10000>; + ranges = <0x5060000 0x0 0x5060000 0x10000>, + <0xa030a00 0x0 0xa030a00 0x40>; /* DPTX PHY */ assigned-clocks = <&k3_clks 365 3>; assigned-clock-parents = <&k3_clks 365 7>; serdes0: serdes@5060000 { + /* + * Note: we also map DPTX PHY registers as the Torrent + * needs to manage those. + */ compatible = "ti,j721e-serdes-10g"; - reg = <0x05060000 0x00010000>; - reg-names = "torrent_phy"; + reg = <0x05060000 0x00010000>, + <0xa030a00 0x40>; /* DPTX PHY */ + reg-names = "torrent_phy", "dptx_phy"; resets = <&serdes_wiz0 0>; reset-names = "torrent_reset"; clocks = <&serdes_wiz0 TI_WIZ_PLL0_REFCLK>, @@ -1246,6 +1445,15 @@ #clock-cells = <1>; status = "disabled"; /* Needs lane config */ + + torrent_phy_dp: phy@2 { + reg = <2>; + resets = <&serdes_wiz0 3>; + cdns,phy-type = ; + cdns,num-lanes = <2>; + cdns,max-bit-rate = <5400>; + #phy-cells = <0>; + }; }; }; @@ -1650,6 +1858,82 @@ status = "disabled"; }; + mhdp: dp-bridge@a000000 { + compatible = "ti,j721e-mhdp8546"; + /* + * Note: we do not map DPTX PHY area, as that is handled by + * the PHY driver. + */ + reg = <0x0 0xa000000 0x0 0x30a00>, /* DSS_EDP0_V2A_CORE_VP_REGS_APB */ + <0x0 0x4f40000 0x0 0x20>; /* DSS_EDP0_INTG_CFG_VP */ + reg-names = "mhdptx", "j721e-intg"; + + clocks = <&k3_clks 156 19>; + + phys = <&torrent_phy_dp>; + phy-names = "dpphy"; + + interrupt-parent = <&gic500>; + interrupts = ; + + power-domains = <&k3_pds 156 TI_SCI_PD_EXCLUSIVE>; + + status = "disabled"; + + dp0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + dphy_tx0: phy@4480000 { + compatible = "ti,j721e-dphy"; + reg = <0x0 0x04480000 0x0 0x1000>; + clocks = <&k3_clks 363 8>, <&k3_clks 363 14>; + clock-names = "psm", "pll_ref"; + #phy-cells = <0>; + power-domains = <&k3_pds 363 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 363 14>; + assigned-clock-parents = <&k3_clks 363 15>; + assigned-clock-rates = <19200000>; + status = "disabled"; + }; + + dsi0: dsi@4800000 { + compatible = "ti,j721e-dsi"; + reg = <0x0 0x04800000 0x0 0x100000>, <0x0 0x04710000 0x0 0x100>; + clocks = <&k3_clks 154 4>, <&k3_clks 154 1>; + clock-names = "dsi_p_clk", "dsi_sys_clk"; + power-domains = <&k3_pds 154 TI_SCI_PD_EXCLUSIVE>; + interrupt-parent = <&gic500>; + interrupts = ; + phys = <&dphy_tx0>; + phy-names = "dphy"; + status = "disabled"; + + dsi0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + }; + port@1 { + reg = <1>; + }; + }; + }; + + timesync_router: pinctrl@a40000 { + compatible = "pinctrl-single"; + reg = <0x0 0xa40000 0x0 0x800>; + #address-cells = <1>; + #size-cells = <0>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x000107ff>; + status = "disabled"; + }; + dss: dss@4a00000 { compatible = "ti,j721e-dss"; reg = <0x00 0x04a00000 0x00 0x10000>, /* common_m */ @@ -1695,4 +1979,217 @@ dss_ports: ports { }; }; + + main_r5fss0: r5fss@5c00000 { + compatible = "ti,j721s2-r5fss"; + ti,cluster-mode = <0>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x5c00000 0x00 0x5c00000 0x20000>, + <0x5d00000 0x00 0x5d00000 0x20000>; + power-domains = <&k3_pds 277 TI_SCI_PD_EXCLUSIVE>; + + main_r5fss0_core0: r5f@5c00000 { + compatible = "ti,j721s2-r5f"; + reg = <0x5c00000 0x00010000>, + <0x5c10000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <279>; + ti,sci-proc-ids = <0x06 0xff>; + resets = <&k3_reset 279 1>; + firmware-name = "j721s2-main-r5f0_0-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + + main_r5fss0_core1: r5f@5d00000 { + compatible = "ti,j721s2-r5f"; + reg = <0x5d00000 0x00010000>, + <0x5d10000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <280>; + ti,sci-proc-ids = <0x07 0xff>; + resets = <&k3_reset 280 1>; + firmware-name = "j721s2-main-r5f0_1-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + }; + + main_r5fss1: r5fss@5e00000 { + compatible = "ti,j721s2-r5fss"; + ti,cluster-mode = <0>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x5e00000 0x00 0x5e00000 0x20000>, + <0x5f00000 0x00 0x5f00000 0x20000>; + power-domains = <&k3_pds 278 TI_SCI_PD_EXCLUSIVE>; + + main_r5fss1_core0: r5f@5e00000 { + compatible = "ti,j721s2-r5f"; + reg = <0x5e00000 0x00010000>, + <0x5e10000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <281>; + ti,sci-proc-ids = <0x08 0xff>; + resets = <&k3_reset 281 1>; + firmware-name = "j721s2-main-r5f1_0-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + + main_r5fss1_core1: r5f@5f00000 { + compatible = "ti,j721s2-r5f"; + reg = <0x5f00000 0x00010000>, + <0x5f10000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <282>; + ti,sci-proc-ids = <0x09 0xff>; + resets = <&k3_reset 282 1>; + firmware-name = "j721s2-main-r5f1_1-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + }; + + c71_0: dsp@64800000 { + compatible = "ti,j721s2-c71-dsp"; + reg = <0x00 0x64800000 0x00 0x00080000>, + <0x00 0x64e00000 0x00 0x0000c000>; + reg-names = "l2sram", "l1dram"; + ti,sci = <&sms>; + ti,sci-dev-id = <8>; + ti,sci-proc-ids = <0x30 0xff>; + resets = <&k3_reset 8 1>; + firmware-name = "j721s2-c71_0-fw"; + status = "disabled"; + }; + + c71_1: dsp@65800000 { + compatible = "ti,j721s2-c71-dsp"; + reg = <0x00 0x65800000 0x00 0x00080000>, + <0x00 0x65e00000 0x00 0x0000c000>; + reg-names = "l2sram", "l1dram"; + ti,sci = <&sms>; + ti,sci-dev-id = <11>; + ti,sci-proc-ids = <0x31 0xff>; + resets = <&k3_reset 11 1>; + firmware-name = "j721s2-c71_1-fw"; + status = "disabled"; + }; + + main_esm: esm@700000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x700000 0x00 0x1000>; + ti,esm-pins = <688>, <689>; + bootph-pre-ram; + }; + + watchdog0: watchdog@2200000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2200000 0x00 0x100>; + clocks = <&k3_clks 286 1>; + power-domains = <&k3_pds 286 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 286 1>; + assigned-clock-parents = <&k3_clks 286 5>; + }; + + watchdog1: watchdog@2210000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2210000 0x00 0x100>; + clocks = <&k3_clks 287 1>; + power-domains = <&k3_pds 287 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 287 1>; + assigned-clock-parents = <&k3_clks 287 5>; + }; + + /* + * The following RTI instances are coupled with MCU R5Fs, c7x and + * GPU so keeping them reserved as these will be used by their + * respective firmware + */ + watchdog2: watchdog@22f0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x22f0000 0x00 0x100>; + clocks = <&k3_clks 290 1>; + power-domains = <&k3_pds 290 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 290 1>; + assigned-clock-parents = <&k3_clks 290 5>; + /* reserved for GPU */ + status = "reserved"; + }; + + watchdog3: watchdog@2300000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2300000 0x00 0x100>; + clocks = <&k3_clks 288 1>; + power-domains = <&k3_pds 288 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 288 1>; + assigned-clock-parents = <&k3_clks 288 5>; + /* reserved for C7X_0 */ + status = "reserved"; + }; + + watchdog4: watchdog@2310000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2310000 0x00 0x100>; + clocks = <&k3_clks 289 1>; + power-domains = <&k3_pds 289 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 289 1>; + assigned-clock-parents = <&k3_clks 289 5>; + /* reserved for C7X_1 */ + status = "reserved"; + }; + + watchdog5: watchdog@23c0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x23c0000 0x00 0x100>; + clocks = <&k3_clks 291 1>; + power-domains = <&k3_pds 291 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 291 1>; + assigned-clock-parents = <&k3_clks 291 5>; + /* reserved for MAIN_R5F0_0 */ + status = "reserved"; + }; + + watchdog6: watchdog@23d0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x23d0000 0x00 0x100>; + clocks = <&k3_clks 292 1>; + power-domains = <&k3_pds 292 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 292 1>; + assigned-clock-parents = <&k3_clks 292 5>; + /* reserved for MAIN_R5F0_1 */ + status = "reserved"; + }; + + watchdog7: watchdog@23e0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x23e0000 0x00 0x100>; + clocks = <&k3_clks 293 1>; + power-domains = <&k3_pds 293 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 293 1>; + assigned-clock-parents = <&k3_clks 293 5>; + /* reserved for MAIN_R5F1_0 */ + status = "reserved"; + }; + + watchdog8: watchdog@23f0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x23f0000 0x00 0x100>; + clocks = <&k3_clks 294 1>; + power-domains = <&k3_pds 294 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 294 1>; + assigned-clock-parents = <&k3_clks 294 5>; + /* reserved for MAIN_R5F1_1 */ + status = "reserved"; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi --- a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -34,9 +34,16 @@ }; }; - chipid@43000014 { - compatible = "ti,am654-chipid"; - reg = <0x00 0x43000014 0x00 0x4>; + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; secure_proxy_sa3: mailbox@43600000 { @@ -443,7 +450,7 @@ }; mcu_navss: bus@28380000 { - compatible = "simple-mfd"; + compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>; @@ -471,8 +478,12 @@ compatible = "ti,j721e-navss-mcu-udmap"; reg = <0x0 0x285c0000 0x0 0x100>, <0x0 0x2a800000 0x0 0x40000>, - <0x0 0x2aa00000 0x0 0x40000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x2aa00000 0x0 0x40000>, + <0x0 0x284a0000 0x0 0x4000>, + <0x0 0x284c0000 0x0 0x4000>, + <0x0 0x28400000 0x0 0x2000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; @@ -655,4 +666,84 @@ power-domains = <&k3_pds 180 TI_SCI_PD_SHARED>; #thermal-sensor-cells = <1>; }; + + mcu_r5fss0: r5fss@41000000 { + compatible = "ti,j721s2-r5fss"; + ti,cluster-mode = <1>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x41000000 0x00 0x41000000 0x20000>, + <0x41400000 0x00 0x41400000 0x20000>; + power-domains = <&k3_pds 283 TI_SCI_PD_EXCLUSIVE>; + + mcu_r5fss0_core0: r5f@41000000 { + compatible = "ti,j721s2-r5f"; + reg = <0x41000000 0x00010000>, + <0x41010000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <284>; + ti,sci-proc-ids = <0x01 0xff>; + resets = <&k3_reset 284 1>; + firmware-name = "j721s2-mcu-r5f0_0-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + + mcu_r5fss0_core1: r5f@41400000 { + compatible = "ti,j721s2-r5f"; + reg = <0x41400000 0x00010000>, + <0x41410000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <285>; + ti,sci-proc-ids = <0x02 0xff>; + resets = <&k3_reset 285 1>; + firmware-name = "j721s2-mcu-r5f0_1-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + }; + + mcu_esm: esm@40800000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x40800000 0x00 0x1000>; + ti,esm-pins = <95>; + bootph-pre-ram; + }; + + wkup_esm: esm@42080000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x42080000 0x00 0x1000>; + ti,esm-pins = <63>; + bootph-pre-ram; + }; + + /* + * The 2 RTI instances are couple with MCU R5Fs so keeping them + * reserved as these will be used by their respective firmware + */ + mcu_watchdog0: watchdog@40600000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x40600000 0x00 0x100>; + clocks = <&k3_clks 295 1>; + power-domains = <&k3_pds 295 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 295 1>; + assigned-clock-parents = <&k3_clks 295 5>; + /* reserved for MCU_R5F0_0 */ + status = "reserved"; + }; + + mcu_watchdog1: watchdog@40610000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x40610000 0x00 0x100>; + clocks = <&k3_clks 296 1>; + power-domains = <&k3_pds 296 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 296 1>; + assigned-clock-parents = <&k3_clks 296 5>; + /* reserved for MCU_R5F0_1 */ + status = "reserved"; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi --- a/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi 2024-07-07 20:37:34.632306489 -0400 @@ -13,9 +13,10 @@ / { memory@80000000 { device_type = "memory"; + bootph-all; /* 16 GB RAM */ - reg = <0x00 0x80000000 0x00 0x80000000>, - <0x08 0x80000000 0x03 0x80000000>; + reg = <0x00000000 0x80000000 0x00000000 0x80000000>, + <0x00000008 0x80000000 0x00000003 0x80000000>; }; /* Reserving memory regions still pending */ @@ -24,11 +25,121 @@ #size-cells = <2>; ranges; + /* global cma region */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x00 0x38000000>; + linux,cma-default; + }; + secure_ddr: optee@9e800000 { reg = <0x00 0x9e800000 0x00 0x01800000>; alignment = <0x1000>; no-map; }; + + mcu_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0000000 0x00 0x100000>; + no-map; + }; + + mcu_r5fss0_core0_memory_region: r5f-memory@a0100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0100000 0x00 0xf00000>; + no-map; + }; + + mcu_r5fss0_core1_dma_memory_region: r5f-dma-memory@a1000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1000000 0x00 0x100000>; + no-map; + }; + + mcu_r5fss0_core1_memory_region: r5f-memory@a1100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core0_dma_memory_region: r5f-dma-memory@a2000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core0_memory_region: r5f-memory@a2100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core1_dma_memory_region: r5f-dma-memory@a3000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core1_memory_region: r5f-memory@a3100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core0_dma_memory_region: r5f-dma-memory@a4000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core0_memory_region: r5f-memory@a4100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core1_dma_memory_region: r5f-dma-memory@a5000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa5000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core1_memory_region: r5f-memory@a5100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa5100000 0x00 0xf00000>; + no-map; + }; + + c71_0_dma_memory_region: c71-dma-memory@a6000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa6000000 0x00 0x100000>; + no-map; + }; + + c71_0_memory_region: c71-memory@a6100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa6100000 0x00 0xf00000>; + no-map; + }; + + c71_1_dma_memory_region: c71-dma-memory@a7000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa7000000 0x00 0x100000>; + no-map; + }; + + c71_1_memory_region: c71-memory@a7100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa7100000 0x00 0xf00000>; + no-map; + }; + + rtos_ipc_memory_region: ipc-memories@a8000000 { + reg = <0x00 0xa8000000 0x00 0x01c00000>; + alignment = <0x1000>; + no-map; + }; }; mux0: mux-controller { @@ -49,6 +160,30 @@ #phy-cells = <0>; max-bitrate = <5000000>; }; + + vsys_io_1v8: regulator-vsys-io-1v8 { + compatible = "regulator-fixed"; + regulator-name = "vsys_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + vsys_io_1v2: regulator-vsys-io-1v2 { + compatible = "regulator-fixed"; + regulator-name = "vsys_io_1v2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + edp1_refclk: clock-edp1-refclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; }; &wkup_pmx0 { @@ -70,6 +205,15 @@ }; }; +&wkup_pmx1 { + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + /* (C21) MCU_OSPI1_CSn1.WKUP_GPIO0_39 */ + J721S2_WKUP_IOPAD(0x028, PIN_INPUT, 7) + >; + }; +}; + &wkup_pmx2 { wkup_i2c0_pins_default: wkup-i2c0-default-pins { pinctrl-single,pins = < @@ -106,6 +250,190 @@ compatible = "atmel,24c256"; reg = <0x50>; }; + + tps659411: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <39 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck1234-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka1234: buck1234 { + regulator-name = "vdd_cpu_avs"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + regulator-always-on; + bootph-pre-ram; + }; + + bucka5: buck5 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd_mcuwk_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vdd_mcu_gpioret_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + tps659414: pmic@4c { + compatible = "ti,tps6594-q1"; + reg = <0x4c>; + system-power-controller; + interrupt-parent = <&wkup_gpio0>; + interrupts = <39 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + buck1-supply = <&vsys_3v3>; + buck2-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + buckb1: buck1 { + regulator-name = "vdd_io_1v8_reg"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + buckb2: buck2 { + regulator-name = "vdd_fpd_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb3: buck3 { + regulator-name = "vdd_phy_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb4: buck4 { + regulator-name = "vdd_ddr_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb5: buck5 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob1: ldo1 { + regulator-name = "vdd_wk_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob2: ldo2 { + regulator-name = "vdd_gpioret_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob3: ldo3 { + regulator-name = "vda_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob4: ldo4 { + regulator-name = "vda_pll_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + lp876411: pmic@58 { + compatible = "ti,lp8764-q1"; + reg = <0x58>; + system-power-controller; + interrupt-parent = <&wkup_gpio0>; + interrupts = <39 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + buck1234-supply = <&vsys_3v3>; + + regulators { + buckc1234: buck1234 { + regulator-name = "vdd_core_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; }; &main_i2c0 { @@ -138,7 +466,7 @@ pinctrl-names = "default"; pinctrl-0 = <&mcu_fss0_ospi0_pins_default>; - flash@0 { + ospi0_nor: flash@0 { compatible = "jedec,spi-nor"; reg = <0x0>; spi-tx-bus-width = <8>; @@ -149,5 +477,237 @@ cdns,tchsh-ns = <60>; cdns,tslch-ns = <60>; cdns,read-delay = <4>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "ospi.tiboot3"; + reg = <0x0 0x80000>; + }; + + partition@80000 { + label = "ospi.tispl"; + reg = <0x80000 0x200000>; + }; + + partition@280000 { + label = "ospi.u-boot"; + reg = <0x280000 0x400000>; + }; + + partition@680000 { + label = "ospi.env"; + reg = <0x680000 0x40000>; + }; + + partition@6c0000 { + label = "ospi.env.backup"; + reg = <0x6c0000 0x40000>; + }; + + partition@800000 { + label = "ospi.rootfs"; + reg = <0x800000 0x37c0000>; + }; + + partition@3fc0000 { + label = "ospi.phypattern"; + reg = <0x3fc0000 0x40000>; + }; + }; + }; + + ospi0_nand: nand@0 { + compatible = "spi-nand"; + reg = <0x0>; + spi-tx-bus-width = <8>; + spi-rx-bus-width = <8>; + spi-max-frequency = <25000000>; + cdns,tshsl-ns = <60>; + cdns,tsd2d-ns = <60>; + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <2>; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "ospi_nand.tiboot3"; + reg = <0x0 0x80000>; + }; + + partition@80000 { + label = "ospi_nand.tispl"; + reg = <0x80000 0x200000>; + }; + + partition@280000 { + label = "ospi_nand.u-boot"; + reg = <0x280000 0x400000>; + }; + + partition@680000 { + label = "ospi_nand.env"; + reg = <0x680000 0x40000>; + }; + + partition@6c0000 { + label = "ospi_nand.env.backup"; + reg = <0x6c0000 0x40000>; + }; + + partition@2000000 { + label = "ospi_nand.rootfs"; + reg = <0x2000000 0x5fc0000>; + }; + + partition@7fc0000 { + label = "ospi_nand.phypattern"; + reg = <0x7fc0000 0x40000>; + }; + }; + }; +}; + +&mailbox0_cluster0 { + status = "okay"; + interrupts = <436>; + mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_mcu_r5fss0_core1: mbox-mcu-r5fss0-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster1 { + status = "okay"; + interrupts = <432>; + mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster2 { + status = "okay"; + interrupts = <428>; + mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster4 { + status = "okay"; + interrupts = <420>; + mbox_c71_0: mbox-c71-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_c71_1: mbox-c71-1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mcu_r5fss0_core0 { + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>; + memory-region = <&mcu_r5fss0_core0_dma_memory_region>, + <&mcu_r5fss0_core0_memory_region>; +}; + +&mcu_r5fss0_core1 { + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>; + memory-region = <&mcu_r5fss0_core1_dma_memory_region>, + <&mcu_r5fss0_core1_memory_region>; +}; + +&main_r5fss0_core0 { + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>; + memory-region = <&main_r5fss0_core0_dma_memory_region>, + <&main_r5fss0_core0_memory_region>; +}; + +&main_r5fss0_core1 { + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>; + memory-region = <&main_r5fss0_core1_dma_memory_region>, + <&main_r5fss0_core1_memory_region>; +}; + +&main_r5fss1_core0 { + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>; + memory-region = <&main_r5fss1_core0_dma_memory_region>, + <&main_r5fss1_core0_memory_region>; +}; + +&main_r5fss1_core1 { + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>; + memory-region = <&main_r5fss1_core1_dma_memory_region>, + <&main_r5fss1_core1_memory_region>; +}; + +&c71_0 { + status = "okay"; + mboxes = <&mailbox0_cluster4 &mbox_c71_0>; + memory-region = <&c71_0_dma_memory_region>, + <&c71_0_memory_region>; +}; + +&c71_1 { + status = "okay"; + mboxes = <&mailbox0_cluster4 &mbox_c71_1>; + memory-region = <&c71_1_dma_memory_region>, + <&c71_1_memory_region>; +}; + +&main_i2c4 { + dsi_edp_bridge: dsi-edp-bridge@2c { + compatible = "ti,sn65dsi86"; + reg = <0x2c>; + + clock-names = "refclk"; + clocks = <&edp1_refclk>; + + enable-gpios = <&exp_som 5 0>; + + vpll-supply = <&vsys_io_1v8>; + vccio-supply = <&vsys_io_1v8>; + vcca-supply = <&vsys_io_1v2>; + vcc-supply = <&vsys_io_1v2>; + + dsi_edp_bridge_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + }; + port@1 { + reg = <1>; + }; + }; }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j722s.dtsi b/arch/arm64/boot/dts/ti/k3-j722s.dtsi --- a/arch/arm64/boot/dts/ti/k3-j722s.dtsi 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j722s.dtsi 2024-07-07 20:37:34.636306509 -0400 @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Device Tree Source for J722S SoC Family + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include +#include +#include +#include + +#include "k3-am62p5.dtsi" + +/ { + model = "Texas Instruments K3 J722S SoC"; + compatible = "ti,j722s"; + + cbass_main: bus@f0000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + + ranges = <0x00 0x000f0000 0x00 0x000f0000 0x00 0x00030000>, /* Main MMRs */ + <0x00 0x00420000 0x00 0x00420000 0x00 0x00001000>, /* ESM0 */ + <0x00 0x00600000 0x00 0x00600000 0x00 0x00001100>, /* GPIO */ + <0x00 0x00703000 0x00 0x00703000 0x00 0x00000200>, /* USB0 debug trace */ + <0x00 0x0070c000 0x00 0x0070c000 0x00 0x00000200>, /* USB1 debug trace */ + <0x00 0x00a40000 0x00 0x00a40000 0x00 0x00000800>, /* Timesync router */ + <0x00 0x01000000 0x00 0x01000000 0x00 0x01b28400>, /* First peripheral window */ + <0x00 0x08000000 0x00 0x08000000 0x00 0x00200000>, /* Main CPSW */ + <0x00 0x0d000000 0x00 0x0d000000 0x00 0x00800000>, /* PCIE_0 */ + <0x00 0x0e000000 0x00 0x0e000000 0x00 0x01d20000>, /* Second peripheral window */ + <0x00 0x0fd80000 0x00 0x0fd80000 0x00 0x00080000>, /* GPU */ + <0x00 0x0fd20000 0x00 0x0fd20000 0x00 0x00000100>, /* JPEGENC0_CORE */ + <0x00 0x0fd20200 0x00 0x0fd20200 0x00 0x00000200>, /* JPEGENC0_CORE_MMU */ + <0x00 0x20000000 0x00 0x20000000 0x00 0x0a008000>, /* Third peripheral window */ + <0x00 0x30040000 0x00 0x30040000 0x00 0x00080000>, /* PRUSS-M */ + <0x00 0x301C0000 0x00 0x301C0000 0x00 0x00001000>, /* DPHY-TX */ + <0x00 0x30101000 0x00 0x30101000 0x00 0x00080100>, /* CSI window */ + <0x00 0x30200000 0x00 0x30200000 0x00 0x00010000>, /* DSS */ + <0x00 0x30210000 0x00 0x30210000 0x00 0x00010000>, /* VPU */ + <0x00 0x30220000 0x00 0x30220000 0x00 0x00010000>, /* DSS1 */ + <0x00 0x30270000 0x00 0x30270000 0x00 0x00010000>, /* DSI-base1 */ + <0x00 0x30300000 0x00 0x30300000 0x00 0x00001000>, /* MCRC64 */ + <0x00 0x30500000 0x00 0x30500000 0x00 0x00100000>, /* DSI-base2 */ + <0x00 0x31000000 0x00 0x31000000 0x00 0x00050000>, /* USB0 DWC3 Core window */ + <0x00 0x31200000 0x00 0x31200000 0x00 0x00040000>, /* USB1 DWC3 Core window */ + <0x00 0x40900000 0x00 0x40900000 0x00 0x00030000>, /* SA3UL */ + <0x00 0x43600000 0x00 0x43600000 0x00 0x00010000>, /* SA3 sproxy data */ + <0x00 0x44043000 0x00 0x44043000 0x00 0x00000fe0>, /* TI SCI DEBUG */ + <0x00 0x44860000 0x00 0x44860000 0x00 0x00040000>, /* SA3 sproxy config */ + <0x00 0x48000000 0x00 0x48000000 0x00 0x06408000>, /* DMSS */ + <0x00 0x60000000 0x00 0x60000000 0x00 0x08000000>, /* FSS0 DAT1 */ + <0x00 0x68000000 0x00 0x68000000 0x00 0x08000000>, /* PCIe0 DAT0 */ + <0x00 0x70000000 0x00 0x70000000 0x00 0x00040000>, /* OCSRAM */ + <0x00 0x78400000 0x00 0x78400000 0x00 0x00008000>, /* MAIN R5FSS0 ATCM */ + <0x00 0x78500000 0x00 0x78500000 0x00 0x00008000>, /* MAIN R5FSS0 BTCM */ + <0x00 0x7e000000 0x00 0x7e000000 0x00 0x00200000>, /* C7X_0 L2SRAM */ + <0x00 0x7e200000 0x00 0x7e200000 0x00 0x00200000>, /* C7X_1 L2SRAM */ + <0x01 0x00000000 0x01 0x00000000 0x00 0x00310000>, /* A53 PERIPHBASE */ + <0x05 0x00000000 0x05 0x00000000 0x01 0x00000000>, /* FSS0 DAT3 */ + <0x06 0x00000000 0x06 0x00000000 0x01 0x00000000>, /* PCIe0 DAT1 */ + + /* MCU Domain Range */ + <0x00 0x04000000 0x00 0x04000000 0x00 0x01ff1400>, + <0x00 0x79000000 0x00 0x79000000 0x00 0x00008000>, + <0x00 0x79020000 0x00 0x79020000 0x00 0x00008000>, + <0x00 0x79100000 0x00 0x79100000 0x00 0x00040000>, + <0x00 0x79140000 0x00 0x79140000 0x00 0x00040000>, + + /* Wakeup Domain Range */ + <0x00 0x00b00000 0x00 0x00b00000 0x00 0x00002400>, + <0x00 0x2b000000 0x00 0x2b000000 0x00 0x00300400>, + <0x00 0x43000000 0x00 0x43000000 0x00 0x00020000>, + <0x00 0x78000000 0x00 0x78000000 0x00 0x00008000>, + <0x00 0x78100000 0x00 0x78100000 0x00 0x00008000>; + }; +}; + +/* Main domain overrides */ + +&inta_main_dmss { + ti,interrupt-ranges = <7 71 21>; +}; + +&inta_main_dmss_csi { + ti,interrupt-ranges = <0 237 8>; +}; + +&main_bcdma_csi { + compatible = "ti,j722s-dmss-bcdma-csi"; + reg = <0x00 0x4e230000 0x00 0x100>, + <0x00 0x4e180000 0x00 0x20000>, + <0x00 0x4e300000 0x00 0x10000>, + <0x00 0x4e100000 0x00 0x80000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + msi-parent = <&inta_main_dmss_csi>; + #dma-cells = <3>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <199>; + ti,sci-rm-range-rchan = <0x21>; + ti,sci-rm-range-tchan = <0x22>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; +}; + +&oc_sram { + reg = <0x00 0x70000000 0x00 0x40000>; + ranges = <0x00 0x00 0x70000000 0x40000>; +}; + +&main_pmx0 { + pinctrl-single,gpio-range = + <&main_pmx0_range 0 32 (PIN_INPUT | PIN_GPIO_MUX_MODE)>, + <&main_pmx0_range 33 55 (PIN_INPUT | PIN_GPIO_MUX_MODE)>, + <&main_pmx0_range 101 25 (PIN_INPUT | PIN_GPIO_MUX_MODE)>, + <&main_pmx0_range 137 5 (PIN_INPUT | PIN_GPIO_MUX_MODE)>, + <&main_pmx0_range 143 3 (PIN_INPUT | PIN_GPIO_MUX_MODE)>, + <&main_pmx0_range 149 2 (PIN_INPUT | PIN_GPIO_MUX_MODE)>; +}; + +&main_gpio0 { + gpio-ranges = <&main_pmx0 0 0 32>, + <&main_pmx0 32 33 38>, + <&main_pmx0 70 72 17>; + ti,ngpio = <87>; +}; + +&main_gpio1 { + gpio-ranges = <&main_pmx0 7 101 25>, + <&main_pmx0 42 137 5>, + <&main_pmx0 47 143 3>, + <&main_pmx0 50 149 2>; + ti,ngpio = <73>; +}; + +&cbass_main { + e5010: e5010@fd20000 { + compatible = "img,e5010-jpeg-enc"; + reg = <0x00 0xfd20000 0x00 0x100>, + <0x00 0xfd20200 0x00 0x200>; + reg-names = "core", "mmu"; + clocks = <&k3_clks 201 0>; + clock-names = "core_clk"; + power-domains = <&k3_pds 201 TI_SCI_PD_EXCLUSIVE>; + interrupts = ; + }; + +}; + +/* Include bus peripherals that are additionally + * present in J722S + */ + #include "k3-j722s-main.dtsi" diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j722s-evm-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-csi2-ov5640.dtso --- a/arch/arm64/boot/dts/ti/k3-j722s-evm-csi2-ov5640.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-csi2-ov5640.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LI OV5640 MIPI Camera module on MIPI CSI (CSI2-EXP-AUX) connector. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + + +&main_pmx0 { + cam0_reset_pins_default: cam0-reset-pins-default { + pinctrl-single,pins = < + J722S_IOPAD(0x0114, PIN_OUTPUT, 7) + >; + }; +}; + +&pca9543_0 { + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + pinctrl-names = "default"; + pinctrl-0 = <&cam0_reset_pins_default>; + powerdown-gpios = <&main_gpio0 68 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j722s-evm-csi2-quad-rpi-cam-imx219.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-csi2-quad-rpi-cam-imx219.dtso --- a/arch/arm64/boot/dts/ti/k3-j722s-evm-csi2-quad-rpi-cam-imx219.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-csi2-quad-rpi-cam-imx219.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for RPi Camera V2.1 on J722S-EVM board. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + * + * Schematics: https://datasheets.raspberrypi.com/camera/camera-v2-schematics.pdf + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&main_pmx0 { + cam0_reset_pins_default: cam0-reset-pins-default { + pinctrl-single,pins = < + J722S_IOPAD(0x03c, PIN_OUTPUT, 7) + >; + }; + + cam1_reset_pins_default: cam1-reset-pins-default { + pinctrl-single,pins = < + J722S_IOPAD(0x044, PIN_OUTPUT, 7) + >; + }; + + cam2_reset_pins_default: cam2-reset-pins-default { + pinctrl-single,pins = < + J722S_IOPAD(0x04c, PIN_OUTPUT, 7) + >; + }; + + cam3_reset_pins_default: cam3-reset-pins-default { + pinctrl-single,pins = < + J722S_IOPAD(0x054, PIN_OUTPUT, 7) + >; + }; +}; + +&{/} { + clk_imx219_fixed: imx219-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&exp1 { + p06-hog{ + /* P06 - CSI01_MUX_SEL_2 */ + gpio-hog; + gpios = <6 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI01_MUX_SEL_2"; + }; + + p07-hog{ + /* P01 - CSI23_MUX_SEL_2 */ + gpio-hog; + gpios = <7 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI23_MUX_SEL_2"; + }; +}; + +&pca9543_0 { + #address-cells = <1>; + #size-cells = <0>; + + i2c-alias-pool = /bits/ 16 <0x10 0x11>; + + /* CAM0 I2C */ + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + imx219_0: sensor@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed>; + clock-names = "xclk"; + + pinctrl-names = "default"; + pinctrl-0 = <&cam0_reset_pins_default>; + + reset-gpios = <&main_gpio0 15 GPIO_ACTIVE_HIGH>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + + /* CAM1 I2C */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + imx219_1: sensor@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed>; + clock-names = "xclk"; + + pinctrl-names = "default"; + pinctrl-0 = <&cam1_reset_pins_default>; + + reset-gpios = <&main_gpio0 17 GPIO_ACTIVE_HIGH>; + + port { + csi2_cam1: endpoint { + remote-endpoint = <&csi2rx1_in_sensor>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; +}; + +&pca9543_1 { + #address-cells = <1>; + #size-cells = <0>; + + i2c-alias-pool = /bits/ 16 <0x10 0x11>; + + /* CAM0 I2C */ + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + imx219_2: sensor@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed>; + clock-names = "xclk"; + + pinctrl-names = "default"; + pinctrl-0 = <&cam2_reset_pins_default>; + + reset-gpios = <&main_gpio0 19 GPIO_ACTIVE_HIGH>; + + port { + csi2_cam2: endpoint { + remote-endpoint = <&csi2rx2_in_sensor>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + + /* CAM1 I2C */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + imx219_3: sensor@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed>; + clock-names = "xclk"; + + pinctrl-names = "default"; + pinctrl-0 = <&cam3_reset_pins_default>; + + reset-gpios = <&main_gpio0 21 GPIO_ACTIVE_HIGH>; + + port { + csi2_cam3: endpoint { + remote-endpoint = <&csi2rx3_in_sensor>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx1_in_sensor: endpoint { + remote-endpoint = <&csi2_cam1>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx2 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi2_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx2_in_sensor: endpoint { + remote-endpoint = <&csi2_cam2>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx3 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi3_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx3_in_sensor: endpoint { + remote-endpoint = <&csi2_cam3>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy1 { + status = "okay"; +}; + +&ti_csi2rx2 { + status = "okay"; +}; + +&dphy2 { + status = "okay"; +}; + +&ti_csi2rx3 { + status = "okay"; +}; + +&dphy3 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j722s-evm-csi2-quad-tevi-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-csi2-quad-tevi-ov5640.dtso --- a/arch/arm64/boot/dts/ti/k3-j722s-evm-csi2-quad-tevi-ov5640.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-csi2-quad-tevi-ov5640.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 4 x TEVI OV5640 MIPI Camera module on RPI camera connector. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + + +&main_pmx0 { + cam0_reset_pins_default: cam0-reset-pins-default { + pinctrl-single,pins = < + J722S_IOPAD(0x03c, PIN_OUTPUT, 7) + >; + }; + + cam1_reset_pins_default: cam1-reset-pins-default { + pinctrl-single,pins = < + J722S_IOPAD(0x044, PIN_OUTPUT, 7) + >; + }; + + cam2_reset_pins_default: cam2-reset-pins-default { + pinctrl-single,pins = < + J722S_IOPAD(0x04c, PIN_OUTPUT, 7) + >; + }; + + cam3_reset_pins_default: cam3-reset-pins-default { + pinctrl-single,pins = < + J722S_IOPAD(0x054, PIN_OUTPUT, 7) + >; + }; +}; + +&exp1 { + p06-hog{ + /* P06 - CSI01_MUX_SEL_2 */ + gpio-hog; + gpios = <6 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI01_MUX_SEL_2"; + }; + + p07-hog{ + /* P01 - CSI23_MUX_SEL_2 */ + gpio-hog; + gpios = <7 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI23_MUX_SEL_2"; + }; +}; + +&main_gpio0 { + p15-hog { + /* P15 - CSI2_CAMERA_GPIO1 */ + gpio-hog; + gpios = <15 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI2_CAMERA_GPIO1"; + }; + + p17-hog { + /* P17 - CSI2_CAMERA_GPIO2 */ + gpio-hog; + gpios = <17 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI2_CAMERA_GPIO2"; + }; + + p19-hog { + /* P19 - CSI2_CAMERA_GPIO3 */ + gpio-hog; + gpios = <19 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI2_CAMERA_GPIO3"; + }; + + p21-hog { + /* P21 - CSI2_CAMERA_GPIO4 */ + gpio-hog; + gpios = <21 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI2_CAMERA_GPIO4"; + }; +}; + +&pca9543_0 { + #address-cells = <1>; + #size-cells = <0>; + + i2c-alias-pool = /bits/ 16 <0x3c 0x3d>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + ov5640_0: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + pinctrl-names = "default"; + pinctrl-0 = <&cam0_reset_pins_default>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ov5640_1: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + pinctrl-names = "default"; + pinctrl-0 = <&cam1_reset_pins_default>; + + port { + csi2_cam1: endpoint { + remote-endpoint = <&csi2rx1_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; +}; + +&pca9543_1 { + #address-cells = <1>; + #size-cells = <0>; + + i2c-alias-pool = /bits/ 16 <0x3c 0x3d>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + ov5640_2: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + pinctrl-names = "default"; + pinctrl-0 = <&cam2_reset_pins_default>; + + port { + csi2_cam2: endpoint { + remote-endpoint = <&csi2rx2_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ov5640_3: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + pinctrl-names = "default"; + pinctrl-0 = <&cam3_reset_pins_default>; + + port { + csi2_cam3: endpoint { + remote-endpoint = <&csi2rx3_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx1_in_sensor: endpoint { + remote-endpoint = <&csi2_cam1>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx2 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi2_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx2_in_sensor: endpoint { + remote-endpoint = <&csi2_cam2>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx3 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi3_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx3_in_sensor: endpoint { + remote-endpoint = <&csi2_cam3>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy1 { + status = "okay"; +}; + + +&ti_csi2rx2 { + status = "okay"; +}; + +&dphy2 { + status = "okay"; +}; + + +&ti_csi2rx3 { + status = "okay"; +}; + +&dphy3 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j722s-evm-dsi-rpi-7inch-panel.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-dsi-rpi-7inch-panel.dtso --- a/arch/arm64/boot/dts/ti/k3-j722s-evm-dsi-rpi-7inch-panel.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-dsi-rpi-7inch-panel.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for RPi 7inch touchscreen panel interfaced with DSI on + * J722S EVM. + * + * RPi DSI Panel: https://www.raspberrypi.com/products/raspberry-pi-touch-display/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +&{/} { + panel0 { + compatible = "raspberrypi,7inch-dsi", "simple-panel"; + backlight = <&display_reg>; + power-supply = <&display_reg>; + + port { + panel_in: endpoint { + remote-endpoint = <&panel_bridge_out>; + }; + }; + }; + + bridge_reg: bridge-regulator { + compatible = "regulator-fixed"; + regulator-name = "bridge-reg"; + gpio = <&display_reg 0 0>; + vin-supply = <&display_reg>; + enable-active-high; + }; +}; + +&exp2 { + p00-hog { + /* P00 - DSI_Mux_SEL_2 */ + gpio-hog; + gpios = <0 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "DSI_Mux_SEL_2"; + }; +}; + +&dphy_tx0 { + status = "okay"; +}; + +&main_i2c1 { + #address-cells = <1>; + #size-cells = <0>; + + display_reg: regulator@45 { + compatible = "raspberrypi,7inch-touchscreen-panel-regulator"; + reg = <0x45>; + gpio-controller; + #gpio-cells = <2>; + }; +}; + +&dsi0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dsi0_out: endpoint { + remote-endpoint = <&panel_bridge_in>; + }; + }; + + port@1 { + reg = <1>; + + dsi0_in: endpoint { + remote-endpoint = <&dss1_dpi1_out>; + }; + }; + }; + + bridge@0 { + status = "okay"; + compatible = "toshiba,tc358762"; + reg = <0>; + vddc-supply = <&bridge_reg>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + panel_bridge_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + + panel_bridge_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + }; +}; + +&dss1_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* DSS1-VP1: DSI Output */ + port@1 { + reg = <1>; + + dss1_dpi1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts --- a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,1081 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Device Tree file for the J722S EVM + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + * + * Schematics: https://www.ti.com/lit/zip/sprr495 + */ + +/dts-v1/; + +#include +#include +#include "k3-j722s.dtsi" +#include "k3-serdes.h" + +/ { + compatible = "ti,j722s-evm", "ti,j722s"; + model = "Texas Instruments J722S EVM"; + + aliases { + serial0 = &wkup_uart0; + serial2 = &main_uart0; + serial3 = &main_uart5; + mmc0 = &sdhci0; + mmc1 = &sdhci1; + }; + + chosen { + stdout-path = &main_uart0; + }; + + memory@80000000 { + /* 8G RAM */ + reg = <0x00000000 0x80000000 0x00000000 0x80000000>, + <0x00000008 0x80000000 0x00000001 0x80000000>; + device_type = "memory"; + bootph-all; + }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* global cma region */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x00 0x38000000>; + linux,cma-default; + }; + + secure_tfa_ddr: tfa@9e780000 { + reg = <0x00 0x9e780000 0x00 0x80000>; + no-map; + }; + + secure_ddr: optee@9e800000 { + reg = <0x00 0x9e800000 0x00 0x01800000>; + no-map; + }; + + wkup_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0000000 0x00 0x100000>; + no-map; + }; + + wkup_r5fss0_core0_memory_region: r5f-memory@a0100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0100000 0x00 0xf00000>; + no-map; + }; + + mcu_r5fss0_core0_dma_memory_region: mcu-r5fss-dma-memory-region@a1000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1000000 0x00 0x100000>; + no-map; + }; + + mcu_r5fss0_core0_memory_region: mcu-r5fss-memory-region@a1100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core0_dma_memory_region: main-r5fss-dma-memory-region@a2000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core0_memory_region: main-r5fss-memory-region@a2100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2100000 0x00 0xf00000>; + no-map; + }; + + c7x_0_dma_memory_region: c7x-dma-memory@a3000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3000000 0x00 0x100000>; + no-map; + }; + + c7x_0_memory_region: c7x-memory@a3100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3100000 0x00 0xf00000>; + no-map; + }; + + c7x_1_dma_memory_region: c7x-dma-memory@a4000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4000000 0x00 0x100000>; + no-map; + }; + + c7x_1_memory_region: c7x-memory@a4100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4100000 0x00 0xf00000>; + no-map; + }; + + rtos_ipc_memory_region: ipc-memories@a5000000 { + reg = <0x00 0xa5000000 0x00 0x1c00000>; + alignment = <0x1000>; + no-map; + }; + }; + + vmain_pd: regulator-0 { + /* TPS65988 PD CONTROLLER OUTPUT */ + compatible = "regulator-fixed"; + regulator-name = "vmain_pd"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + bootph-all; + }; + + vsys_5v0: regulator-vsys5v0 { + /* Output of LM5140 */ + compatible = "regulator-fixed"; + regulator-name = "vsys_5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vmain_pd>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_mmc1: regulator-mmc1 { + /* TPS22918DBVR */ + compatible = "regulator-fixed"; + regulator-name = "vdd_mmc1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + enable-active-high; + gpio = <&exp1 15 GPIO_ACTIVE_HIGH>; + bootph-all; + }; + + vdd_sd_dv: regulator-TLV71033 { + compatible = "regulator-gpio"; + regulator-name = "tlv71033"; + pinctrl-names = "default"; + pinctrl-0 = <&vdd_sd_dv_pins_default>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + vin-supply = <&vsys_5v0>; + gpios = <&main_gpio0 70 GPIO_ACTIVE_HIGH>; + states = <1800000 0x0>, + <3300000 0x1>; + }; + + vcc_3v3_aud: regulator-vcc3v3 { + /* Output of LM5140 */ + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + vsys_io_1v8: regulator-vsys-io-1v8 { + compatible = "regulator-fixed"; + regulator-name = "vsys_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + vsys_io_1v2: regulator-vsys-io-1v2 { + compatible = "regulator-fixed"; + regulator-name = "vsys_io_1v2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + hdmi0: connector-hdmi { + compatible = "hdmi-connector"; + label = "hdmi"; + type = "a"; + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&sii9022_out>; + }; + }; + }; + + transceiver0: can-phy0 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_gpio_pins_default>; + standby-gpios = <&mcu_gpio0 12 GPIO_ACTIVE_HIGH>; + }; + + transceiver1: can-phy1 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; + + transceiver2: can-phy2 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + standby-gpios = <&exp1 17 GPIO_ACTIVE_HIGH>; + }; + + codec_audio: sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "J722S-EVM"; + simple-audio-card,widgets = + "Headphone", "Headphone Jack", + "Line", "Line In", + "Microphone", "Microphone Jack"; + simple-audio-card,routing = + "Headphone Jack", "HPLOUT", + "Headphone Jack", "HPROUT", + "LINE1L", "Line In", + "LINE1R", "Line In", + "MIC3R", "Microphone Jack", + "Microphone Jack", "Mic Bias"; + simple-audio-card,format = "dsp_b"; + simple-audio-card,bitclock-master = <&sound_master>; + simple-audio-card,frame-master = <&sound_master>; + simple-audio-card,bitclock-inversion; + + simple-audio-card,cpu { + sound-dai = <&mcasp1>; + }; + + sound_master: simple-audio-card,codec { + sound-dai = <&tlv320aic3106>; + clocks = <&audio_refclk1>; + }; + }; +}; + +&main_pmx0 { + + /delete-property/ interrupts; + main_i2c0_pins_default: main-i2c0-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x01e0, PIN_INPUT_PULLUP, 0) /* (D23) I2C0_SCL */ + J722S_IOPAD(0x01e4, PIN_INPUT_PULLUP, 0) /* (B22) I2C0_SDA */ + >; + bootph-all; + }; + + main_i2c1_pins_default: main-i2c1-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x01e8, PIN_INPUT_PULLUP, 0) /* (C24) I2C1_SCL */ + J722S_IOPAD(0x01ec, PIN_INPUT_PULLUP, 0) /* (A22) I2C1_SDA */ + >; + bootph-all; + }; + + main_i2c2_pins_default: main-i2c2-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x00b0, PIN_INPUT_PULLUP, 1) /* (P22) GPMC0_CSn2.I2C2_SCL */ + J722S_IOPAD(0x00b4, PIN_INPUT_PULLUP, 1) /* (P23) GPMC0_CSn3.I2C2_SDA */ + >; + }; + + main_uart0_pins_default: main-uart0-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x01c8, PIN_INPUT, 0) /* (A22) UART0_RXD */ + J722S_IOPAD(0x01cc, PIN_OUTPUT, 0) /* (B22) UART0_TXD */ + >; + bootph-all; + }; + + main_uart5_pins_default: main-uart5-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0108, PIN_INPUT, 3) /* (J27) UART5_RXD */ + J722S_IOPAD(0x010c, PIN_OUTPUT, 3) /* (H27) UART5_TXD */ + >; + }; + + vdd_sd_dv_pins_default: vdd-sd-dv-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0120, PIN_INPUT, 7) /* (F27) MMC2_CMD.GPIO0_70 */ + >; + bootph-all; + }; + + main_mmc1_pins_default: main-mmc1-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x023c, PIN_INPUT, 0) /* (H22) MMC1_CMD */ + J722S_IOPAD(0x0234, PIN_OUTPUT, 0) /* (H24) MMC1_CLK */ + J722S_IOPAD(0x0230, PIN_INPUT, 0) /* (H23) MMC1_DAT0 */ + J722S_IOPAD(0x022c, PIN_INPUT_PULLUP, 0) /* (H20) MMC1_DAT1 */ + J722S_IOPAD(0x0228, PIN_INPUT_PULLUP, 0) /* (J23) MMC1_DAT2 */ + J722S_IOPAD(0x0224, PIN_INPUT_PULLUP, 0) /* (H25) MMC1_DAT3 */ + J722S_IOPAD(0x0240, PIN_INPUT, 0) /* (B24) MMC1_SDCD */ + >; + bootph-all; + }; + + mdio_pins_default: mdio-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0160, PIN_OUTPUT, 0) /* (AC24) MDIO0_MDC */ + J722S_IOPAD(0x015c, PIN_INPUT, 0) /* (AD25) MDIO0_MDIO */ + >; + }; + + ospi0_pins_default: ospi0-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0000, PIN_OUTPUT, 0) /* (L24) OSPI0_CLK */ + J722S_IOPAD(0x002c, PIN_OUTPUT, 0) /* (K26) OSPI0_CSn0 */ + J722S_IOPAD(0x000c, PIN_INPUT, 0) /* (K27) OSPI0_D0 */ + J722S_IOPAD(0x0010, PIN_INPUT, 0) /* (L27) OSPI0_D1 */ + J722S_IOPAD(0x0014, PIN_INPUT, 0) /* (L26) OSPI0_D2 */ + J722S_IOPAD(0x0018, PIN_INPUT, 0) /* (L25) OSPI0_D3 */ + J722S_IOPAD(0x001c, PIN_INPUT, 0) /* (L21) OSPI0_D4 */ + J722S_IOPAD(0x0020, PIN_INPUT, 0) /* (M26) OSPI0_D5 */ + J722S_IOPAD(0x0024, PIN_INPUT, 0) /* (N27) OSPI0_D6 */ + J722S_IOPAD(0x0028, PIN_INPUT, 0) /* (M27) OSPI0_D7 */ + J722S_IOPAD(0x0008, PIN_INPUT, 0) /* (L22) OSPI0_DQS */ + >; + bootph-all; + }; + + rgmii1_pins_default: rgmii1-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x014c, PIN_INPUT, 0) /* (AC25) RGMII1_RD0 */ + J722S_IOPAD(0x0150, PIN_INPUT, 0) /* (AD27) RGMII1_RD1 */ + J722S_IOPAD(0x0154, PIN_INPUT, 0) /* (AE24) RGMII1_RD2 */ + J722S_IOPAD(0x0158, PIN_INPUT, 0) /* (AE26) RGMII1_RD3 */ + J722S_IOPAD(0x0148, PIN_INPUT, 0) /* (AE27) RGMII1_RXC */ + J722S_IOPAD(0x0144, PIN_INPUT, 0) /* (AD23) RGMII1_RX_CTL */ + J722S_IOPAD(0x0134, PIN_OUTPUT, 0) /* (AF27) RGMII1_TD0 */ + J722S_IOPAD(0x0138, PIN_OUTPUT, 0) /* (AE23) RGMII1_TD1 */ + J722S_IOPAD(0x013c, PIN_OUTPUT, 0) /* (AG25) RGMII1_TD2 */ + J722S_IOPAD(0x0140, PIN_OUTPUT, 0) /* (AF24) RGMII1_TD3 */ + J722S_IOPAD(0x0130, PIN_OUTPUT, 0) /* (AG26) RGMII1_TXC */ + J722S_IOPAD(0x012c, PIN_OUTPUT, 0) /* (AF25) RGMII1_TX_CTL */ + >; + }; + + main_usb1_pins_default: main-usb1-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0258, PIN_INPUT, 0) /* (B27) USB1_DRVVBUS */ + >; + }; + + main_gpio0_ioexp_intr_pins_default: main-gpio0-ioexp-intr-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0110, PIN_INPUT, 7) /* (G27) MMC2_DAT1.GPIO0_67 */ + >; + }; + + main_dpi_pins_default: main-dpi-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0100, PIN_OUTPUT, 0) /* (AB23) VOUT0_VSYNC */ + J722S_IOPAD(0x00f8, PIN_OUTPUT, 0) /* (AB24) VOUT0_HSYNC */ + J722S_IOPAD(0x0104, PIN_OUTPUT, 0) /* (AC26) VOUT0_PCLK */ + J722S_IOPAD(0x00fc, PIN_OUTPUT, 0) /* (AC27) VOUT0_DE */ + J722S_IOPAD(0x00b8, PIN_OUTPUT, 0) /* (W27) VOUT0_DATA0 */ + J722S_IOPAD(0x00bc, PIN_OUTPUT, 0) /* (W25) VOUT0_DATA1 */ + J722S_IOPAD(0x00c0, PIN_OUTPUT, 0) /* (W24) VOUT0_DATA2 */ + J722S_IOPAD(0x00c4, PIN_OUTPUT, 0) /* (W23) VOUT0_DATA3 */ + J722S_IOPAD(0x00c8, PIN_OUTPUT, 0) /* (W22) VOUT0_DATA4 */ + J722S_IOPAD(0x00cc, PIN_OUTPUT, 0) /* (W21) VOUT0_DATA5 */ + J722S_IOPAD(0x00d0, PIN_OUTPUT, 0) /* (Y26) VOUT0_DATA6 */ + J722S_IOPAD(0x00d4, PIN_OUTPUT, 0) /* (Y27) VOUT0_DATA7 */ + J722S_IOPAD(0x00d8, PIN_OUTPUT, 0) /* (AA24) VOUT0_DATA8 */ + J722S_IOPAD(0x00dc, PIN_OUTPUT, 0) /* (AA27) VOUT0_DATA9 */ + J722S_IOPAD(0x00e0, PIN_OUTPUT, 0) /* (AA25) VOUT0_DATA10 */ + J722S_IOPAD(0x00e4, PIN_OUTPUT, 0) /* (AB25) VOUT0_DATA11 */ + J722S_IOPAD(0x00e8, PIN_OUTPUT, 0) /* (AA23) VOUT0_DATA12 */ + J722S_IOPAD(0x00ec, PIN_OUTPUT, 0) /* (AA22) VOUT0_DATA13 */ + J722S_IOPAD(0x00f0, PIN_OUTPUT, 0) /* (AB26) VOUT0_DATA14 */ + J722S_IOPAD(0x00f4, PIN_OUTPUT, 0) /* (AB27) VOUT0_DATA15 */ + J722S_IOPAD(0x005c, PIN_OUTPUT, 1) /* (U27) GPMC0_AD8.VOUT0_DATA16 */ + J722S_IOPAD(0x0060, PIN_OUTPUT, 1) /* (U26) GPMC0_AD9.VOUT0_DATA17 */ + J722S_IOPAD(0x0064, PIN_OUTPUT, 1) /* (V27) GPMC0_AD10.VOUT0_DATA18 */ + J722S_IOPAD(0x0068, PIN_OUTPUT, 1) /* (V25) GPMC0_AD11.VOUT0_DATA19 */ + J722S_IOPAD(0x006c, PIN_OUTPUT, 1) /* (V26) GPMC0_AD12.VOUT0_DATA20 */ + J722S_IOPAD(0x0070, PIN_OUTPUT, 1) /* (V24) GPMC0_AD13.VOUT0_DATA21 */ + J722S_IOPAD(0x0074, PIN_OUTPUT, 1) /* (V22) GPMC0_AD14.VOUT0_DATA22 */ + J722S_IOPAD(0x0078, PIN_OUTPUT, 1) /* (V23) GPMC0_AD15.VOUT0_DATA23 */ + J722S_IOPAD(0x009c, PIN_OUTPUT, 1) /* (W26) GPMC0_WAIT1.VOUT0_EXTPCLKIN */ + >; + }; + + main_mcan0_pins_default: main-mcan0-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x1dc, PIN_INPUT, 0) /* (C22) MCAN0_RX */ + J722S_IOPAD(0x1d8, PIN_OUTPUT, 0) /*(D22) MCAN0_TX */ + >; + }; + + main_mcasp1_pins_default: main-mcasp1-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0090, PIN_INPUT, 2) /* (U24) GPMC0_BE0n_CLE.MCASP1_ACLKX */ + J722S_IOPAD(0x0098, PIN_INPUT, 2) /* (AA24) GPMC0_WAIT0.MCASP1_AFSX */ + J722S_IOPAD(0x008c, PIN_OUTPUT, 2) /* (T25) GPMC0_WEn.MCASP1_AXR0 */ + J722S_IOPAD(0x0084, PIN_INPUT, 2) /* (R25) GPMC0_ADVn_ALE.MCASP1_AXR2 */ + >; + }; + + audio_ext_refclk1_pins_default: audio-ext-refclk1-default-pins { + pinctrl-single,pins = < + J722S_IOPAD(0x0a0, PIN_OUTPUT, 1) /* (N24) GPMC0_WPn.AUDIO_EXT_REFCLK1 */ + >; + }; +}; + +&cpsw3g { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii1_pins_default>; +}; + +&cpsw3g_mdio { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mdio_pins_default>; + + cpsw3g_phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + ti,min-output-impedance; + }; +}; + +&cpsw_port1 { + phy-mode = "rgmii-rxid"; + phy-handle = <&cpsw3g_phy0>; +}; + +&cpsw_port2 { + status = "disabled"; +}; + +&main_gpio1 { + status = "okay"; +}; + +&main_uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_uart0_pins_default>; + status = "okay"; + bootph-all; +}; + +&main_uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&main_uart5_pins_default>; + status = "reserved"; +}; + +&mcu_pmx0 { + + wkup_uart0_pins_default: wkup-uart0-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x02c, PIN_INPUT, 0) /* (C7) WKUP_UART0_CTSn */ + J722S_MCU_IOPAD(0x030, PIN_OUTPUT, 0) /* (C6) WKUP_UART0_RTSn */ + J722S_MCU_IOPAD(0x024, PIN_INPUT, 0) /* (D8) WKUP_UART0_RXD */ + J722S_MCU_IOPAD(0x028, PIN_OUTPUT, 0) /* (D7) WKUP_UART0_TXD */ + >; + bootph-all; + }; + + wkup_i2c0_pins_default: wkup-i2c0-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x04c, PIN_INPUT_PULLUP, 0) /* (C7) WKUP_I2C0_SCL */ + J722S_MCU_IOPAD(0x050, PIN_INPUT_PULLUP, 0) /* (C6) WKUP_I2C1_SDA */ + >; + bootph-all; + }; + + mcu_mcan0_pins_default: mcu-mcan0-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x038, PIN_INPUT, 0) /* (D8) MCU_MCAN0_RX */ + J722S_MCU_IOPAD(0x034, PIN_OUTPUT, 0) /* (B2) MCU_MCAN0_TX */ + >; + }; + + mcu_mcan1_pins_default: mcu-mcan1-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x040, PIN_INPUT, 0) /* (B1) MCU_MCAN1_RX */ + J722S_MCU_IOPAD(0x03C, PIN_OUTPUT, 0) /*(C1) MCU_MCAN1_TX */ + >; + }; + + mcu_mcan0_gpio_pins_default: mcu-mcan0-gpio-default-pins { + pinctrl-single,pins = < + J722S_MCU_IOPAD(0x0030, PIN_OUTPUT, 7) /* (C3) MCU_GPIO0_12 */ + >; + }; +}; + +&wkup_uart0 { + /* WKUP UART0 is used by Device Manager firmware */ + pinctrl-names = "default"; + pinctrl-0 = <&wkup_uart0_pins_default>; + status = "reserved"; + bootph-all; +}; + +&wkup_i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&wkup_i2c0_pins_default>; + clock-frequency = <400000>; + status = "okay"; + bootph-all; +}; + +&k3_clks { + /* Configure AUDIO_EXT_REFCLK1 pin as output */ + pinctrl-names = "default"; + pinctrl-0 = <&audio_ext_refclk1_pins_default>; +}; + +&main_i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c0_pins_default>; + clock-frequency = <400000>; + status = "okay"; + bootph-all; + + exp1: gpio@23 { + compatible = "ti,tca6424"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "TRC_MUX_SEL", "OSPI/ONAND_MUX_SEL", + "MCASP1_FET_SEL", "CTRL_PM_I2C_OE#", + "CSI_VIO_SEL", "USB2.0_MUX_SEL", + "CSI01_MUX_SEL_2", "CSI23_MUX_SEL_2", + "LMK1_OE1", "LMK1_OE0", + "LMK2_OE0", "LMK2_OE1", + "GPIO_RGMII1_RST#", "GPIO_AUD_RSTn", + "GPIO_eMMC_RSTn", "GPIO_uSD_PWR_EN", + "USER_LED2", "MCAN0_STB", + "PCIe0_1L_RC_RSTz", "PCIe0_1L_PRSNT#", + "ENET1_EXP_SPARE2", "ENET1_EXP_PWRDN", + "PD_I2ENET1_I2CMUX_SELC_IRQ", "ENET1_EXP_RESETZ"; + + p01_hog: p01-hog { + /* P01 - TRC_MUX_SEL */ + gpio-hog; + gpios = <0 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "TRC_MUX_SEL"; + }; + + p02_hog: p02-hog { + /* P02 - MCASP1_FET_SEL */ + gpio-hog; + gpios = <2 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "MCASP1_FET_SEL"; + }; + + p05-hog { + /* P05 - USB2.0_MUX_SEL */ + gpio-hog; + gpios = <5 GPIO_ACTIVE_LOW>; + output-high; + }; + + p13_hog: p13-hog { + /* P13 - GPIO_AUD_RSTn */ + gpio-hog; + gpios = <13 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "GPIO_AUD_RSTn"; + }; + }; + + tlv320aic3106: audio-codec@1b { + #sound-dai-cells = <0>; + compatible = "ti,tlv320aic3106"; + reg = <0x1b>; + ai3x-micbias-vg = <1>; /* 2.0V */ + AVDD-supply = <&vcc_3v3_aud>; + IOVDD-supply = <&vcc_3v3_aud>; + DRVDD-supply = <&vcc_3v3_aud>; + DVDD-supply = <&vsys_io_1v8>; + }; +}; + +&main_i2c1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_pins_default>; + clock-frequency = <100000>; + + exp2: gpio@20 { + compatible = "ti,tca6416"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "DSI_Mux_SEL_2", "GPIO_eDP_ENABLE", + "DP0_PWR_SW_EN", "GPIO_OLDI_RSTn", + "GPIO_HDMI_RSTn", "HDMI_LS_OE", + "", "", + "DSI_GPIO0", "DSI_GPIO1", + "DSI_EDID", "IO_eDP_IRQ", + "OLDI_INT#", "HDMI_INTn", + "", ""; + + interrupt-parent = <&main_gpio0>; + interrupts = <67 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&main_gpio0_ioexp_intr_pins_default>; + bootph-all; + + p04-hog { + /* P04 - GPIO_HDMI_RSTn */ + gpio-hog; + gpios = <4 GPIO_ACTIVE_LOW>; + output-low; + line-name = "GPIO_HDMI_RSTn"; + }; + + p03-hog { + /* P03 - GPIO_OLDI_RSTn */ + gpio-hog; + gpios = <3 GPIO_ACTIVE_LOW>; + output-low; + line-name = "GPIO_OLDI_RSTn"; + }; + + p05-hog { + /* P05 - HDMI_LS_OE */ + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "HDMI_LS_OE"; + }; + }; + + sii9022: bridge-hdmi@3b { + compatible = "sil,sii9022"; + reg = <0x3b>; + interrupt-parent = <&exp2>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + #sound-dai-cells = <0>; + sil,i2s-data-lanes = < 0 >; + + hdmi_tx_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* + * HDMI can be serviced with 3 potential VPs - + * (DSS0 VP1 / DSS1 VP0 / DSS1 VP1). + * For now, we will service it with DSS1 VP0. + */ + port@0 { + reg = <0>; + + sii9022_in: endpoint { + remote-endpoint = <&dss1_dpi0_out>; + }; + }; + + port@1 { + reg = <1>; + + sii9022_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; +}; + +&main_i2c2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c2_pins_default>; + clock-frequency = <400000>; + + pca9543_0: i2c-mux@70 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + }; + + pca9543_1: i2c-mux@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + }; +}; + +&ospi0 { + pinctrl-names = "default"; + pinctrl-0 = <&ospi0_pins_default>; + status = "okay"; + + ospi0_nor: flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0>; + spi-tx-bus-width = <8>; + spi-rx-bus-width = <8>; + spi-max-frequency = <25000000>; + cdns,tshsl-ns = <60>; + cdns,tsd2d-ns = <60>; + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <4>; + bootph-all; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "ospi.tiboot3"; + reg = <0x00 0x80000>; + }; + + partition@80000 { + label = "ospi.tispl"; + reg = <0x80000 0x200000>; + }; + + partition@280000 { + label = "ospi.u-boot"; + reg = <0x280000 0x400000>; + }; + + partition@680000 { + label = "ospi.env"; + reg = <0x680000 0x40000>; + }; + + partition@6c0000 { + label = "ospi.env.backup"; + reg = <0x6c0000 0x40000>; + }; + + partition@800000 { + label = "ospi.rootfs"; + reg = <0x800000 0x37c0000>; + }; + + partition@3fc0000 { + label = "ospi.phypattern"; + reg = <0x3fc0000 0x40000>; + }; + }; + }; + + ospi0_nand: nand@0 { + compatible = "spi-nand"; + reg = <0x0>; + spi-tx-bus-width = <8>; + spi-rx-bus-width = <8>; + spi-max-frequency = <25000000>; + cdns,tshsl-ns = <60>; + cdns,tsd2d-ns = <60>; + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <2>; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "ospi_nand.tiboot3"; + reg = <0x0 0x80000>; + }; + + partition@80000 { + label = "ospi_nand.tispl"; + reg = <0x80000 0x200000>; + }; + + partition@280000 { + label = "ospi_nand.u-boot"; + reg = <0x280000 0x400000>; + }; + + partition@680000 { + label = "ospi_nand.env"; + reg = <0x680000 0x40000>; + }; + + partition@6c0000 { + label = "ospi_nand.env.backup"; + reg = <0x6c0000 0x40000>; + }; + + partition@2000000 { + label = "ospi_nand.rootfs"; + reg = <0x2000000 0x5fc0000>; + }; + + partition@7fc0000 { + label = "ospi_nand.phypattern"; + reg = <0x7fc0000 0x40000>; + }; + }; + }; +}; + +&sdhci0 { + disable-wp; + bootph-all; + ti,driver-strength-ohm = <50>; + status = "okay"; +}; + +&sdhci1 { + /* SD/MMC */ + vmmc-supply = <&vdd_mmc1>; + vqmmc-supply = <&vdd_sd_dv>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mmc1_pins_default>; + ti,driver-strength-ohm = <50>; + disable-wp; + status = "okay"; + bootph-all; +}; + +&mailbox0_cluster0 { + status = "okay"; + mbox_r5_0: mbox-r5-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + +&mailbox0_cluster1 { + status = "okay"; + mbox_mcu_r5_0: mbox-mcu-r5-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + +&mailbox0_cluster2 { + status = "okay"; + mbox_c7x_0: mbox-c7x-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + +&mailbox0_cluster3 { + status = "okay"; + mbox_main_r5_0: mbox-main-r5-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_c7x_1: mbox-c7x-1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&wkup_r5fss0 { + status = "okay"; +}; + +&wkup_r5fss0_core0 { + mboxes = <&mailbox0_cluster0 &mbox_r5_0>; + memory-region = <&wkup_r5fss0_core0_dma_memory_region>, + <&wkup_r5fss0_core0_memory_region>; +}; + +&mcu_r5fss0 { + status = "okay"; +}; + +&mcu_r5fss0_core0 { + mboxes = <&mailbox0_cluster1 &mbox_mcu_r5_0>; + memory-region = <&mcu_r5fss0_core0_dma_memory_region>, + <&mcu_r5fss0_core0_memory_region>; +}; + +&main_r5fss0 { + status = "okay"; +}; + +&main_r5fss0_core0 { + mboxes = <&mailbox0_cluster3 &mbox_main_r5_0>; + memory-region = <&main_r5fss0_core0_dma_memory_region>, + <&main_r5fss0_core0_memory_region>; +}; + +&c7x_0 { + status = "okay"; + mboxes = <&mailbox0_cluster2 &mbox_c7x_0>; + memory-region = <&c7x_0_dma_memory_region>, + <&c7x_0_memory_region>; +}; + +&c7x_1 { + status = "okay"; + mboxes = <&mailbox0_cluster3 &mbox_c7x_1>; + memory-region = <&c7x_1_dma_memory_region>, + <&c7x_1_memory_region>; +}; + +&serdes_ln_ctrl { + idle-states = , + ; +}; + +&serdes0 { + status = "okay"; + serdes0_usb_link: phy@0 { + reg = <0>; + cdns,num-lanes = <1>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 1>; + }; +}; + +&serdes1 { + serdes1_pcie_link: phy@0 { + reg = <0>; + cdns,num-lanes = <1>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz1 1>; + }; +}; + +&usbss0 { + ti,vbus-divider; + status = "okay"; +}; + +&usb0 { + dr_mode = "otg"; + usb-role-switch; +}; + +&usbss1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_usb1_pins_default>; + ti,vbus-divider; + status = "okay"; +}; + +&usb1 { + dr_mode = "host"; + maximum-speed = "super-speed"; + phys = <&serdes0_usb_link>; + phy-names = "cdns3,usb3-phy"; +}; + +&pcie0_rc { + status = "okay"; + reset-gpios = <&exp1 18 GPIO_ACTIVE_HIGH>; + phys = <&serdes1_pcie_link>; + phy-names = "pcie-phy"; +}; + +&dss1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_dpi_pins_default>; + + clocks = <&k3_clks 232 8>, + <&k3_clks 232 0>, + <&k3_clks 232 4>; + + assigned-clocks = <&k3_clks 241 0>, /* DSS1-VP0 */ + <&k3_clks 240 0>, /* DSS1-VP1 */ + <&k3_clks 245 0>; /* DPI Output */ + + assigned-clock-parents = <&k3_clks 241 2>, /* PLL 17 HDMI */ + <&k3_clks 240 1>, /* PLL 18 DSI */ + <&k3_clks 245 2>; /* DSS1-DPI0 */ +}; + +&dss1_ports { + /* DSS1-VP0: DPI/HDMI Output */ + port@0 { + reg = <0>; + + dss1_dpi0_out: endpoint { + remote-endpoint = <&sii9022_in>; + }; + }; +}; + +&mcu_mcan0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_pins_default>; + phys = <&transceiver0>; +}; + +&mcu_mcan1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan1_pins_default>; + phys = <&transceiver1>; +}; + +&main_mcan0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan0_pins_default>; + phys = <&transceiver2>; +}; + +&mcu_gpio0 { + status = "okay"; +}; + +&mcasp1 { + status = "okay"; + #sound-dai-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcasp1_pins_default>; + op-mode = <0>; /* MCASP_IIS_MODE */ + tdm-slots = <2>; + serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ + 1 0 2 0 + 0 0 0 0 + 0 0 0 0 + 0 0 0 0 + >; +}; + +&main_conf { + audio_refclk1: clock@82e4 { + compatible = "ti,am62-audio-refclk"; + reg = <0x82e4 0x4>; + clocks = <&k3_clks 157 18>; + assigned-clocks = <&k3_clks 157 18>; + assigned-clock-parents = <&k3_clks 157 33>; + #clock-cells = <0>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso --- a/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Fusion (FPD-Link III) board on J721E EVM + * https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + + +&pca9543_0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + deser@3d { + compatible = "ti,ds90ub960-q1"; + reg = <0x3d>; + clocks = <&clk_fusion_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + deser@36 { + compatible = "ti,ds90ub960-q1"; + reg = <0x36>; + clocks = <&clk_fusion_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy1 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j722s-evm-microtips-mf101hie-panel.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-microtips-mf101hie-panel.dtso --- a/arch/arm64/boot/dts/ti/k3-j722s-evm-microtips-mf101hie-panel.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-microtips-mf101hie-panel.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * Microtips integrated OLDI panel (MF-101HIEBCAF0) and touch DT overlay for J722S-EVM + * + * Panel datasheet: https://simplespec.microtipsusa.com/uploads/spec/datasheetFile/2588/13-101HIEBCAF0-S_V1.1_20221104.pdf + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&{/} { + display { + compatible = "microtips,mf-101hiebcaf0", "panel-simple"; + /* + * Note that the OLDI TX 0 transmits the odd set of pixels + * while the OLDI TX 1 transmits the even set. This is a + * fixed configuration in the IP integration and is not + * changeable. The properties, "dual-lvds-odd-pixels" and + * "dual-lvds-even-pixels" have been used to merely + * identify if a Dual Link configuration is required. + * Swapping them will cause an error in the dss oldi driver. + */ + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + + lcd_in0: endpoint { + remote-endpoint = <&oldi0_dss0_out>; + }; + }; + port@1 { + reg = <1>; + dual-lvds-even-pixels; + + lcd_in1: endpoint { + remote-endpoint = <&oldi1_dss0_out>; + }; + }; + }; + }; +}; + +&dss0 { + status = "okay"; +}; + +&oldi0_dss0 { + status = "okay"; +}; + +&oldi1_dss0 { + status = "okay"; +}; + +&oldi0_dss0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + oldi0_dss0_in: endpoint { + remote-endpoint = <&dss0_dpi0_out0>; + }; + }; + + port@1 { + reg = <1>; + + oldi0_dss0_out: endpoint { + remote-endpoint = <&lcd_in0>; + }; + }; +}; + +&oldi1_dss0_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + oldi1_dss0_in: endpoint { + remote-endpoint = <&dss0_dpi0_out1>; + }; + }; + + port@1 { + reg = <1>; + + oldi1_dss0_out: endpoint { + remote-endpoint = <&lcd_in1>; + }; + }; +}; + +&dss0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VP1: Output to OLDI */ + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + dss0_dpi0_out0: endpoint@0 { + reg = <0>; + remote-endpoint = <&oldi0_dss0_in>; + }; + + dss0_dpi0_out1: endpoint@1 { + reg = <1>; + remote-endpoint = <&oldi1_dss0_in>; + }; + }; +}; + +&main_i2c1 { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@41 { + compatible = "ilitek,ili251x"; + reg = <0x41>; + interrupt-parent = <&exp2>; + interrupts = <12 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&exp2 3 GPIO_ACTIVE_LOW>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso --- a/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso 2024-07-07 20:37:34.632306489 -0400 @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Arducam V3Link UC-A09 board + * https://www.arducam.com/fpd-link-3-cameras/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&exp1 { + p06-hog { + /* P06 - CSI01_MUX_SEL_2 */ + gpio-hog; + gpios = <6 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI01_MUX_SEL_2"; + }; + + p07-hog { + /* P01 - CSI23_MUX_SEL_2 */ + gpio-hog; + gpios = <7 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI23_MUX_SEL_2"; + }; +}; + +&pca9543_0 { + #address-cells = <1>; + #size-cells = <0>; + + /* CAM0 I2C */ + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + + /* CAM1 I2C */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy1 { + status = "okay"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi b/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi --- a/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi 2024-07-07 20:37:34.636306509 -0400 @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Device Tree file for the J722S main domain peripherals + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include +#include + +/* + * USB1 controller on AM62P and J722S are of different IP. + * Delete AM62P's USBSS1 node definition and redefine it for J722S. + */ + +/delete-node/ &usbss1; + +/ { + serdes_refclk: clk-0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; +}; + +&cbass_main { + serdes_wiz0: phy@f000000 { + compatible = "ti,am64-wiz-10g"; + ranges = <0x0f000000 0x0 0x0f000000 0x00010000>; + #address-cells = <1>; + #size-cells = <1>; + power-domains = <&k3_pds 279 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 279 0>, <&k3_clks 279 1>, <&serdes_refclk>; + clock-names = "fck", "core_ref_clk", "ext_ref_clk"; + num-lanes = <1>; + #reset-cells = <1>; + #clock-cells = <1>; + + assigned-clocks = <&k3_clks 279 1>; + assigned-clock-parents = <&k3_clks 279 5>; + + serdes0: serdes@f000000 { + compatible = "ti,j721e-serdes-10g"; + reg = <0x0f000000 0x00010000>; + reg-names = "torrent_phy"; + resets = <&serdes_wiz0 0>; + reset-names = "torrent_reset"; + clocks = <&serdes_wiz0 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz0 TI_WIZ_PHY_EN_REFCLK>; + clock-names = "refclk", "phy_en_refclk"; + assigned-clocks = <&serdes_wiz0 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz0 TI_WIZ_PLL1_REFCLK>, + <&serdes_wiz0 TI_WIZ_REFCLK_DIG>; + assigned-clock-parents = <&k3_clks 279 1>, + <&k3_clks 279 1>, + <&k3_clks 279 1>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + + status = "disabled"; /* Needs lane config */ + }; + }; + + serdes_wiz1: phy@f010000 { + compatible = "ti,am64-wiz-10g"; + ranges = <0x0f010000 0x0 0x0f010000 0x00010000>; + #address-cells = <1>; + #size-cells = <1>; + power-domains = <&k3_pds 280 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 280 0>, <&k3_clks 280 1>, <&serdes_refclk>; + clock-names = "fck", "core_ref_clk", "ext_ref_clk"; + num-lanes = <1>; + #reset-cells = <1>; + #clock-cells = <1>; + + assigned-clocks = <&k3_clks 280 1>; + assigned-clock-parents = <&k3_clks 280 5>; + + serdes1: serdes@f010000 { + compatible = "ti,j721e-serdes-10g"; + reg = <0x0f010000 0x00010000>; + reg-names = "torrent_phy"; + resets = <&serdes_wiz1 0>; + reset-names = "torrent_reset"; + clocks = <&serdes_wiz1 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz1 TI_WIZ_PHY_EN_REFCLK>; + clock-names = "refclk", "phy_en_refclk"; + assigned-clocks = <&serdes_wiz1 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz1 TI_WIZ_PLL1_REFCLK>, + <&serdes_wiz1 TI_WIZ_REFCLK_DIG>; + assigned-clock-parents = <&k3_clks 280 1>, + <&k3_clks 280 1>, + <&k3_clks 280 1>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + }; + }; + + pcie0_rc: pcie@f102000 { + compatible = "ti,j722s-pcie-host", "ti,j721e-pcie-host"; + reg = <0x00 0x0f102000 0x00 0x1000>, + <0x00 0x0f100000 0x00 0x400>, + <0x00 0x0d000000 0x00 0x00800000>, + <0x00 0x68000000 0x00 0x00001000>; + reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; + ranges = <0x01000000 0x00 0x68001000 0x00 0x68001000 0x00 0x0010000>, + <0x02000000 0x00 0x68011000 0x00 0x68011000 0x00 0x7fef000>; + dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; + interrupt-names = "link_state"; + interrupts = ; + device_type = "pci"; + max-link-speed = <3>; + num-lanes = <1>; + power-domains = <&k3_pds 259 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 259 0>, <&serdes1 CDNS_TORRENT_REFCLK_DRIVER>; + clock-names = "fck", "pcie_refclk"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + vendor-id = <0x104c>; + device-id = <0xb010>; + cdns,no-bar-match-nbits = <64>; + ti,syscon-pcie-ctrl = <&pcie0_ctrl 0x0>; + msi-map = <0x0 &gic_its 0x0 0x10000>; + status = "disabled"; + }; + + usbss1: usb@f920000 { + compatible = "ti,j721e-usb"; + reg = <0x00 0x0f920000 0x00 0x100>; + power-domains = <&k3_pds 278 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 278 3>, <&k3_clks 278 1>; + clock-names = "ref", "lpm"; + assigned-clocks = <&k3_clks 278 3>; /* USB2_REFCLK */ + assigned-clock-parents = <&k3_clks 278 4>; /* HF0SC0 */ + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + usb1: usb@31200000{ + compatible = "cdns,usb3"; + reg = <0x00 0x31200000 0x00 0x10000>, + <0x00 0x31210000 0x00 0x10000>, + <0x00 0x31220000 0x00 0x10000>; + reg-names = "otg", + "xhci", + "dev"; + interrupts = , /* irq.0 */ + , /* irq.6 */ + ; /* otgirq */ + interrupt-names = "host", + "peripheral", + "otg"; + maximum-speed = "super-speed"; + dr_mode = "otg"; + }; + }; + + ti_csi2rx1: ticsi2rx@30122000 { + compatible = "ti,j721e-csi2rx-shim"; + dmas = <&main_bcdma_csi 0 0x5100 0>, <&main_bcdma_csi 0 0x5101 0>, + <&main_bcdma_csi 0 0x5102 0>, <&main_bcdma_csi 0 0x5103 0>; + dma-names = "rx0", "rx1", "rx2", "rx3"; + reg = <0x00 0x30122000 0x00 0x1000>; + power-domains = <&k3_pds 247 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + cdns_csi2rx1: csi-bridge@30121000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x30121000 0x00 0x1000>; + clocks = <&k3_clks 247 0>, <&k3_clks 247 3>, <&k3_clks 247 0>, + <&k3_clks 247 0>, <&k3_clks 247 4>, <&k3_clks 247 4>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy1>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi1_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi1_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi1_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi1_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + ti_csi2rx2: ticsi2rx@30142000 { + compatible = "ti,j721e-csi2rx-shim"; + dmas = <&main_bcdma_csi 0 0x5200 0>, <&main_bcdma_csi 0 0x5201 0>, + <&main_bcdma_csi 0 0x5202 0>, <&main_bcdma_csi 0 0x5203 0>; + dma-names = "rx0", "rx1", "rx2", "rx3"; + reg = <0x00 0x30142000 0x00 0x1000>; + power-domains = <&k3_pds 248 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + cdns_csi2rx2: csi-bridge@30141000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x30141000 0x00 0x1000>; + clocks = <&k3_clks 248 0>, <&k3_clks 248 3>, <&k3_clks 248 0>, + <&k3_clks 248 0>, <&k3_clks 248 4>, <&k3_clks 248 4>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy2>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi2_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi2_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi2_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi2_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi2_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + ti_csi2rx3: ticsi2rx@30162000 { + compatible = "ti,j721e-csi2rx-shim"; + dmas = <&main_bcdma_csi 0 0x5300 0>, <&main_bcdma_csi 0 0x5301 0>, + <&main_bcdma_csi 0 0x5302 0>, <&main_bcdma_csi 0 0x5303 0>; + dma-names = "rx0", "rx1"; + reg = <0x00 0x30162000 0x00 0x1000>; + power-domains = <&k3_pds 249 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + cdns_csi2rx3: csi-bridge@30161000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x30161000 0x00 0x1000>; + clocks = <&k3_clks 249 0>, <&k3_clks 249 3>, <&k3_clks 249 0>, + <&k3_clks 249 0>, <&k3_clks 249 4>, <&k3_clks 249 4>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy3>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi3_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi3_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi3_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi3_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi3_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + dphy1: phy@30130000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x30130000 0x00 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 251 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + dphy2: phy@30150000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x30150000 0x00 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 252 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + dphy3: phy@30170000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x30170000 0x00 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 253 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_r5fss0: r5fss@78400000 { + compatible = "ti,am62-r5fss"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x78400000 0x00 0x78400000 0x8000>, + <0x78500000 0x00 0x78500000 0x8000>; + power-domains = <&k3_pds 261 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + main_r5fss0_core0: r5f@78400000 { + compatible = "ti,am62-r5f"; + reg = <0x78400000 0x00008000>, + <0x78500000 0x00008000>; + reg-names = "atcm", "btcm"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <262>; + ti,sci-proc-ids = <0x04 0xff>; + resets = <&k3_reset 262 1>; + firmware-name = "j722s-main-r5f0_0-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + }; + + c7x_0: dsp@7e000000 { + compatible = "ti,am62a-c7xv-dsp"; + reg = <0x00 0x7e000000 0x00 0x00200000>; + reg-names = "l2sram"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <208>; + ti,sci-proc-ids = <0x30 0xff>; + resets = <&k3_reset 208 1>; + firmware-name = "j722s-c71_0-fw"; + status = "disabled"; + }; + + c7x_1: dsp@7e200000 { + compatible = "ti,am62a-c7xv-dsp"; + reg = <0x00 0x7e200000 0x00 0x00200000>; + reg-names = "l2sram"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <268>; + ti,sci-proc-ids = <0x31 0xff>; + resets = <&k3_reset 268 1>; + firmware-name = "j722s-c71_1-fw"; + status = "disabled"; + }; +}; + +/* MCU domain overrides */ + +&mcu_r5fss0_core0 { + firmware-name = "j722s-mcu-r5f0_0-fw"; +}; + +/* Wakeup domain overrides */ + +&wkup_r5fss0_core0 { + firmware-name = "j722s-wkup-r5f0_0-fw"; +}; + +&main_conf { + serdes_ln_ctrl: mux-controller@4080 { + compatible = "reg-mux"; + reg = <0x4080 0x14>; + #mux-control-cells = <1>; + mux-reg-masks = <0x0 0x3>, /* SERDES0 lane0 select */ + <0x10 0x3>; /* SERDES1 lane0 select */ + }; +}; + +&wkup_conf { + pcie0_ctrl: pcie0-ctrl@4070 { + compatible = "ti,j784s4-pcie-ctrl", "syscon"; + reg = <0x4070 0x4>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j784s4.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4.dtsi --- a/arch/arm64/boot/dts/ti/k3-j784s4.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j784s4.dtsi 2024-07-07 20:37:34.636306509 -0400 @@ -1,10 +1,10 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree Source for J784S4 SoC Family * * TRM (SPRUJ43 JULY 2022): https://www.ti.com/lit/zip/spruj52 * - * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ * */ @@ -234,8 +234,15 @@ #size-cells = <2>; ranges = <0x00 0x00100000 0x00 0x00100000 0x00 0x00020000>, /* ctrl mmr */ <0x00 0x00600000 0x00 0x00600000 0x00 0x00031100>, /* GPIO */ + <0x00 0x00a40000 0x00 0x00a40000 0x00 0x00000800>, /* Time Sync Router */ + <0x00 0x00700000 0x00 0x00700000 0x00 0x00001000>, /* ESM */ <0x00 0x01000000 0x00 0x01000000 0x00 0x0d000000>, /* Most peripherals */ - <0x00 0x0d000000 0x00 0x0d000000 0x00 0x01000000>, /* PCIe Core*/ + <0x00 0x04210000 0x00 0x04210000 0x00 0x00010000>, /* VPU0 */ + <0x00 0x04220000 0x00 0x04220000 0x00 0x00010000>, /* VPU1 */ + <0x00 0x0d000000 0x00 0x0d000000 0x00 0x00800000>, /* PCIe0 Core*/ + <0x00 0x0d800000 0x00 0x0d800000 0x00 0x00800000>, /* PCIe1 Core*/ + <0x00 0x0e000000 0x00 0x0e000000 0x00 0x00800000>, /* PCIe2 Core*/ + <0x00 0x0e800000 0x00 0x0e800000 0x00 0x00800000>, /* PCIe3 Core*/ <0x00 0x10000000 0x00 0x10000000 0x00 0x08000000>, /* PCIe0 DAT0 */ <0x00 0x18000000 0x00 0x18000000 0x00 0x08000000>, /* PCIe1 DAT0 */ <0x00 0x64800000 0x00 0x64800000 0x00 0x0070c000>, /* C71_1 */ @@ -245,7 +252,12 @@ <0x00 0x6f000000 0x00 0x6f000000 0x00 0x00310000>, /* A72 PERIPHBASE */ <0x00 0x70000000 0x00 0x70000000 0x00 0x00400000>, /* MSMC RAM */ <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>, /* MAIN NAVSS */ + <0x40 0x00000000 0x40 0x00000000 0x01 0x00000000>, /* PCIe0 DAT1 */ <0x41 0x00000000 0x41 0x00000000 0x01 0x00000000>, /* PCIe1 DAT1 */ + <0x42 0x00000000 0x42 0x00000000 0x01 0x00000000>, /* PCIe2 DAT1 */ + <0x43 0x00000000 0x43 0x00000000 0x01 0x00000000>, /* PCIe3 DAT1 */ + <0x44 0x00000000 0x44 0x00000000 0x00 0x08000000>, /* PCIe2 DAT0 */ + <0x44 0x10000000 0x44 0x10000000 0x00 0x08000000>, /* PCIe3 DAT0 */ <0x4e 0x20000000 0x4e 0x20000000 0x00 0x00080000>, /* GPU */ /* MCUSS_WKUP Range */ diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j784s4-evm-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-j784s4-evm-csi2-ov5640.dtso --- a/arch/arm64/boot/dts/ti/k3-j784s4-evm-csi2-ov5640.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j784s4-evm-csi2-ov5640.dtso 2024-07-07 20:37:34.636306509 -0400 @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LI OV5640 MIPI Camera module on MIPI CSI (CSI2-EXP-AUX) connector. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&main_i2c5 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + powerdown-gpios = <&exp5 0 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx2_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx2 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi2_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx2_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx2 { + status = "okay"; +}; + +&dphy2 { + status = "okay"; +}; \ No newline at end of file diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts b/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts --- a/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts 2024-07-07 20:37:34.636306509 -0400 @@ -1,6 +1,6 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* - * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ * * EVM Board Schematics: https://www.ti.com/lit/zip/sprr458 */ @@ -27,13 +27,16 @@ mmc1 = &main_sdhci1; i2c0 = &wkup_i2c0; i2c3 = &main_i2c0; + ethernet0 = &mcu_cpsw_port1; + ethernet1 = &main_cpsw1_port1; }; memory@80000000 { device_type = "memory"; + bootph-all; /* 32G RAM */ - reg = <0x00 0x80000000 0x00 0x80000000>, - <0x08 0x80000000 0x07 0x80000000>; + reg = <0x00000000 0x80000000 0x00000000 0x80000000>, + <0x00000008 0x80000000 0x00000007 0x80000000>; }; reserved_memory: reserved-memory { @@ -41,6 +44,14 @@ #size-cells = <2>; ranges; + /* global cma region */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x00 0x70000000>; + linux,cma-default; + }; + secure_ddr: optee@9e800000 { reg = <0x00 0x9e800000 0x00 0x01800000>; no-map; @@ -249,10 +260,147 @@ states = <1800000 0x0>, <3300000 0x1>; }; + + dp0_pwr_3v3: regulator-dp0-prw { + compatible = "regulator-fixed"; + regulator-name = "dp0-pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&exp4 0 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + dp0: connector-dp0 { + compatible = "dp-connector"; + label = "DP0"; + type = "full-size"; + dp-pwr-supply = <&dp0_pwr_3v3>; + + port { + dp0_connector_in: endpoint { + remote-endpoint = <&dp0_out>; + }; + }; + }; + + vsys_io_1v8: regulator-vsys-io-1v8 { + compatible = "regulator-fixed"; + regulator-name = "vsys_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + vsys_io_1v2: regulator-vsys-io-1v2 { + compatible = "regulator-fixed"; + regulator-name = "vsys_io_1v2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + edp1_refclk: clock-edp1-refclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + dp1_pwr_3v3: regulator-dp1-prw { + compatible = "regulator-fixed"; + regulator-name = "dp1-pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&exp4 1 GPIO_ACTIVE_HIGH>; /* P1 - DP1_PWR_SW_EN */ + enable-active-high; + regulator-always-on; + }; + + transceiver0: can-phy0 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_gpio_pins_default>; + standby-gpios = <&wkup_gpio0 69 GPIO_ACTIVE_HIGH>; + }; + + transceiver1: can-phy1 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan1_gpio_pins_default>; + standby-gpios = <&wkup_gpio0 2 GPIO_ACTIVE_HIGH>; + }; + + transceiver2: can-phy2 { + /* standby pin has been grounded by default */ + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; + + transceiver3: can-phy3 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + standby-gpios = <&exp2 7 GPIO_ACTIVE_HIGH>; + mux-states = <&mux1 1>; + }; + + mux1: mux-controller { + compatible = "gpio-mux"; + #mux-state-cells = <1>; + mux-gpios = <&exp2 14 GPIO_ACTIVE_HIGH>; + idle-state = <1>; + }; + + codec_audio: sound { + compatible = "ti,j7200-cpb-audio"; + model = "j784s4-cpb"; + + ti,cpb-mcasp = <&mcasp0>; + ti,cpb-codec = <&pcm3168a_1>; + + clocks = <&k3_clks 265 0>, <&k3_clks 265 1>, + <&k3_clks 157 34>, <&k3_clks 157 63>; + clock-names = "cpb-mcasp-auxclk", "cpb-mcasp-auxclk-48000", + "cpb-codec-scki", "cpb-codec-scki-48000"; + }; +}; + +&wkup_gpio0 { + status = "okay"; }; &main_pmx0 { bootph-all; + main_cpsw2g_default_pins: main-cpsw2g-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x0b8, PIN_INPUT, 6) /* (AC34) MCASP1_ACLKX.RGMII1_RD0 */ + J784S4_IOPAD(0x0a0, PIN_INPUT, 6) /* (AD34) MCASP0_AXR12.RGMII1_RD1 */ + J784S4_IOPAD(0x0a4, PIN_INPUT, 6) /* (AJ36) MCASP0_AXR13.RGMII1_RD2 */ + J784S4_IOPAD(0x0a8, PIN_INPUT, 6) /* (AF34) MCASP0_AXR14.RGMII1_RD3 */ + J784S4_IOPAD(0x0b0, PIN_INPUT, 6) /* (AL33) MCASP1_AXR3.RGMII1_RXC */ + J784S4_IOPAD(0x0ac, PIN_INPUT, 6) /* (AE34) MCASP0_AXR15.RGMII1_RX_CTL */ + J784S4_IOPAD(0x08c, PIN_INPUT, 6) /* (AE35) MCASP0_AXR7.RGMII1_TD0 */ + J784S4_IOPAD(0x090, PIN_INPUT, 6) /* (AC35) MCASP0_AXR8.RGMII1_TD1 */ + J784S4_IOPAD(0x094, PIN_INPUT, 6) /* (AG35) MCASP0_AXR9.RGMII1_TD2 */ + J784S4_IOPAD(0x098, PIN_INPUT, 6) /* (AH36) MCASP0_AXR10.RGMII1_TD3 */ + J784S4_IOPAD(0x0b4, PIN_INPUT, 6) /* (AL34) MCASP1_AXR4.RGMII1_TXC */ + J784S4_IOPAD(0x09c, PIN_INPUT, 6) /* (AF35) MCASP0_AXR11.RGMII1_TX_CTL */ + >; + }; + + main_cpsw2g_mdio_default_pins: main-cpsw2g-mdio-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x0c0, PIN_INPUT, 6) /* (AD38) MCASP1_AXR0.MDIO0_MDC */ + J784S4_IOPAD(0x0bc, PIN_INPUT, 6) /* (AD33) MCASP1_AFSX.MDIO0_MDIO */ + >; + }; + main_uart8_pins_default: main-uart8-default-pins { bootph-all; pinctrl-single,pins = < @@ -270,6 +418,13 @@ >; }; + main_i2c5_pins_default: main-i2c5-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x01c, PIN_INPUT, 8) /* (AG34) MCAN15_TX.I2C5_SCL */ + J784S4_IOPAD(0x018, PIN_INPUT, 8) /* (AK36) MCAN14_RX.I2C5_SDA */ + >; + }; + main_mmc1_pins_default: main-mmc1-default-pins { bootph-all; pinctrl-single,pins = < @@ -289,6 +444,62 @@ J784S4_IOPAD(0x020, PIN_INPUT, 7) /* (AJ35) MCAN15_RX.GPIO0_8 */ >; }; + + dp0_pins_default: dp0-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x0cc, PIN_INPUT, 12) /* (AM37) SPI0_CS0.DP0_HPD */ + >; + }; + + main_i2c4_pins_default: main-i2c4-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x014, PIN_INPUT_PULLUP, 8) /* (AG33) MCAN14_TX.I2C4_SCL */ + J784S4_IOPAD(0x010, PIN_INPUT_PULLUP, 8) /* (AH33) MCAN13_RX.I2C4_SDA */ + >; + }; + + main_usbss0_pins_default: main-usbss0-default-pins { + bootph-all; + pinctrl-single,pins = < + J784S4_IOPAD(0x0ec, PIN_OUTPUT, 6) /* (AN37) TIMER_IO1.USB0_DRVVBUS */ + >; + }; + + main_mcan4_pins_default: main-mcan4-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x088, PIN_INPUT, 0) /* (AF36) MCAN4_RX */ + J784S4_IOPAD(0x084, PIN_OUTPUT, 0) /* (AG38) MCAN4_TX */ + >; + }; + + main_mcan16_pins_default: main-mcan16-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x028, PIN_INPUT, 0) /* (AE33) MCAN16_RX */ + J784S4_IOPAD(0x024, PIN_OUTPUT, 0) /* (AH34) MCAN16_TX */ + >; + }; + + main_i2c3_pins_default: main-i2c3-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x064, PIN_INPUT, 13) /* (AF38) MCAN0_TX.I2C3_SCL */ + J784S4_IOPAD(0x060, PIN_INPUT, 13) /* (AE36) MCASP2_AXR1.I2C3_SDA */ + >; + }; + + mcasp0_pins_default: mcasp0-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x038, PIN_OUTPUT_PULLDOWN, 1) /* (AK35) MCASP0_ACLKX */ + J784S4_IOPAD(0x03c, PIN_OUTPUT_PULLDOWN, 1) /* (AK38) MCASP0_AFSX */ + J784S4_IOPAD(0x07c, PIN_OUTPUT_PULLDOWN, 1) /* (AJ38) MCASP0_AXR3 */ + J784S4_IOPAD(0x080, PIN_INPUT_PULLDOWN, 1) /* (AK34) MCASP0_AXR4 */ + >; + }; + + audio_ext_refclk1_pins_default: audio-ext-refclk1-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x078, PIN_OUTPUT, 1) /* (AH37) MCAN2_RX.AUDIO_EXT_REFCLK1 */ + >; + }; }; &wkup_pmx2 { @@ -368,6 +579,43 @@ J784S4_WKUP_IOPAD(0x108, PIN_INPUT, 0) /* (Y36) MCU_ADC1_AIN7 */ >; }; + + mcu_mcan0_pins_default: mcu-mcan0-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x050, PIN_OUTPUT, 0) /* (K33) MCU_MCAN0_TX */ + J784S4_WKUP_IOPAD(0x054, PIN_INPUT, 0) /* (F38) MCU_MCAN0_RX */ + >; + }; + + mcu_mcan1_pins_default: mcu-mcan1-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x068, PIN_OUTPUT, 0) /* (H35) WKUP_GPIO0_4.MCU_MCAN1_TX */ + J784S4_WKUP_IOPAD(0x06c, PIN_INPUT, 0) /* (K36) WKUP_GPIO0_5.MCU_MCAN1_RX */ + >; + }; + + mcu_mcan0_gpio_pins_default: mcu-mcan0-gpio-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x040, PIN_INPUT, 7) /* (J38) MCU_SPI0_D1.WKUP_GPIO0_69 */ + >; + }; + + mcu_mcan1_gpio_pins_default: mcu-mcan1-gpio-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x060, PIN_INPUT, 7) /* (J35) WKUP_GPIO0_2 */ + >; + }; +}; + +&wkup_pmx1 { + status = "okay"; + + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + /* (G33) MCU_OSPI1_CSn1.WKUP_GPIO0_39 */ + J784S4_WKUP_IOPAD(0x028, PIN_INPUT, 7) + >; + }; }; &wkup_pmx0 { @@ -434,6 +682,114 @@ compatible = "atmel,24c256"; reg = <0x50>; }; + + tps659413: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <39 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck12-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka12: buck12 { + regulator-name = "vdd_ddr_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka3: buck3 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka4: buck4 { + regulator-name = "vdd_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka5: buck5 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vdd_mcuio_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vds_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + tps62873a: regulator@40 { + compatible = "ti,tps62873"; + reg = <0x40>; + bootph-pre-ram; + regulator-name = "VDD_CPU_AVS"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1330000>; + regulator-boot-on; + regulator-always-on; + }; + + tps62873b: regulator@43 { + compatible = "ti,tps62873"; + reg = <0x43>; + regulator-name = "VDD_CORE_0V8"; + regulator-min-microvolt = <760000>; + regulator-max-microvolt = <840000>; + regulator-boot-on; + regulator-always-on; + }; }; &mcu_uart0 { @@ -465,8 +821,7 @@ pinctrl-names = "default"; pinctrl-0 = <&mcu_fss0_ospi0_pins_default>, <&mcu_fss0_ospi0_1_pins_default>; - flash@0 { - bootph-all; + ospi0_nor: flash@0 { compatible = "jedec,spi-nor"; reg = <0x0>; spi-tx-bus-width = <8>; @@ -520,6 +875,63 @@ }; }; }; + + ospi0_nand: nand@0 { + compatible = "spi-nand"; + reg = <0x0>; + spi-tx-bus-width = <8>; + spi-rx-bus-width = <8>; + spi-max-frequency = <25000000>; + cdns,tshsl-ns = <60>; + cdns,tsd2d-ns = <60>; + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <2>; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "ospi_nand.tiboot3"; + reg = <0x0 0x80000>; + }; + + partition@80000 { + label = "ospi_nand.tispl"; + reg = <0x80000 0x200000>; + }; + + partition@280000 { + label = "ospi_nand.u-boot"; + reg = <0x280000 0x400000>; + }; + + partition@680000 { + label = "ospi_nand.env"; + reg = <0x680000 0x40000>; + }; + + partition@6c0000 { + label = "ospi_nand.env.backup"; + reg = <0x6c0000 0x40000>; + }; + + partition@2000000 { + label = "ospi_nand.rootfs"; + reg = <0x2000000 0x5fc0000>; + }; + + partition@7fc0000 { + label = "ospi_nand.phypattern"; + reg = <0x7fc0000 0x40000>; + }; + }; + }; }; &ospi1 { @@ -603,6 +1015,14 @@ "PCIE0_4L_RC_RSTZ", "PCIE0_4L_EP_RST_EN", "PCIE1_4L_PRSNT#", "PCIE0_4L_PRSNT#", "CDCI1_OE1/OE4", "CDCI1_OE2/OE3", "AUDIO_MUX_SEL", "EXP_MUX2", "EXP_MUX3", "GESI_EXP_PHY_RSTZ"; + + p12-hog { + /* P12 - AUDIO_MUX_SEL */ + gpio-hog; + gpios = <12 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "AUDIO_MUX_SEL"; + }; }; exp2: gpio@22 { @@ -618,6 +1038,40 @@ "CANUART_MUX1_SEL1", "ENET1_EXP_PWRDN", "ENET1_EXP_RESETZ", "ENET1_I2CMUX_SEL", "ENET1_EXP_SPARE2", "ENET2_EXP_RESETZ", "USER_INPUT1", "USER_LED1", "USER_LED2"; + + p13-hog { + /* P13 - CANUART_MUX_SEL0 */ + gpio-hog; + gpios = <13 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CANUART_MUX_SEL0"; + }; + + p15-hog { + /* P15 - CANUART_MUX1_SEL1 */ + gpio-hog; + gpios = <15 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CANUART_MUX1_SEL1"; + }; + }; +}; + +&main_i2c5 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c5_pins_default>; + clock-frequency = <400000>; + status = "okay"; + + exp5: gpio@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "CSI2_EXP_RSTZ", "CSI2_EXP_A_GPIO0", + "CSI2_EXP_A_GPIO1", "CSI2_EXP_A_GPIO3", + "CSI2_EXP_B_GPIO1", "CSI2_EXP_B_GPIO2", + "CSI2_EXP_B_GPIO3", "CSI2_EXP_B_GPIO4"; }; }; @@ -649,6 +1103,11 @@ status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&mcu_cpsw_pins_default>; + + cpts@3d000 { + /* Map HW4_TS_PUSH to GENF1 */ + ti,pps = <3 1>; + }; }; &davinci_mdio { @@ -669,6 +1128,31 @@ phy-handle = <&mcu_phy0>; }; +&main_cpsw1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_cpsw2g_default_pins>; + status = "okay"; +}; + +&main_cpsw1_mdio { + pinctrl-names = "default"; + pinctrl-0 = <&main_cpsw2g_mdio_default_pins>; + status = "okay"; + + main_cpsw1_phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + ti,min-output-impedance; + }; +}; + +&main_cpsw1_port1 { + phy-mode = "rgmii-rxid"; + phy-handle = <&main_cpsw1_phy0>; + status = "okay"; +}; + &mailbox0_cluster0 { status = "okay"; interrupts = <436>; @@ -860,3 +1344,345 @@ ti,adc-channels = <0 1 2 3 4 5 6 7>; }; }; + +&serdes_refclk { + status = "okay"; + clock-frequency = <100000000>; +}; + +&dss { + status = "okay"; + assigned-clocks = <&k3_clks 218 2>, + <&k3_clks 218 5>, + <&k3_clks 218 14>, + <&k3_clks 218 18>; + assigned-clock-parents = <&k3_clks 218 3>, + <&k3_clks 218 7>, + <&k3_clks 218 16>, + <&k3_clks 218 22>; +}; + +&serdes0 { + status = "okay"; + + serdes0_usb_link: phy@3 { + reg = <3>; + cdns,num-lanes = <1>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 4>; + }; +}; + +&serdes_wiz0 { + status = "okay"; +}; + +&usb_serdes_mux { + idle-states = <0>; /* USB0 to SERDES lane 3 */ +}; + +&usbss0 { + status = "okay"; + pinctrl-0 = <&main_usbss0_pins_default>; + pinctrl-names = "default"; + ti,vbus-divider; +}; + +&usb0 { + dr_mode = "otg"; + maximum-speed = "super-speed"; + phys = <&serdes0_usb_link>; + phy-names = "cdns3,usb3-phy"; +}; + +&serdes_wiz4 { + status = "okay"; +}; + +&serdes4 { + status = "okay"; + serdes4_dp_link: phy@0 { + reg = <0>; + cdns,num-lanes = <4>; + #phy-cells = <0>; + cdns,max-bit-rate = <2700>; + cdns,phy-type = ; + resets = <&serdes_wiz4 1>, <&serdes_wiz4 2>, + <&serdes_wiz4 3>, <&serdes_wiz4 4>; + }; +}; + +&mhdp { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&dp0_pins_default>; + phys = <&serdes4_dp_link>; + phy-names = "dpphy"; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* DP */ + port@0 { + reg = <0>; + dpi0_out: endpoint { + remote-endpoint = <&dp0_in>; + }; + }; + + /* HDMI */ + port@2 { + reg = <2>; + dpi2_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; +}; + +&main_i2c4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c4_pins_default>; + clock-frequency = <400000>; + + exp4: gpio@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + }; + + dsi_edp_bridge: dsi-edp-bridge@2c { + compatible = "ti,sn65dsi86"; + reg = <0x2c>; + + clock-names = "refclk"; + clocks = <&edp1_refclk>; + + enable-gpios = <&exp4 2 GPIO_ACTIVE_HIGH>; + + vpll-supply = <&vsys_io_1v8>; + vccio-supply = <&vsys_io_1v8>; + vcca-supply = <&vsys_io_1v2>; + vcc-supply = <&vsys_io_1v2>; + + dsi_edp_bridge_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dp1_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + dp1_out: endpoint { + remote-endpoint = <&dp1_panel_in>; + }; + }; + }; + + aux-bus { + panel { + compatible = "ti,panel-edp"; + power-supply = <&dp1_pwr_3v3>; + + port { + dp1_panel_in: endpoint { + remote-endpoint = <&dp1_out>; + }; + }; + }; + }; + }; +}; + +&dsi0_ports { + port@0 { + reg = <0>; + dsi0_out: endpoint { + remote-endpoint = <&dp1_in>; + }; + }; + + port@1 { + reg = <1>; + dsi0_in: endpoint { + remote-endpoint = <&dpi2_out>; + }; + }; +}; + +&dp0_ports { + port@0 { + reg = <0>; + + dp0_in: endpoint { + remote-endpoint = <&dpi0_out>; + }; + }; + + port@4 { + reg = <4>; + + dp0_out: endpoint { + remote-endpoint = <&dp0_connector_in>; + }; + }; +}; + +&dphy_tx0 { + status = "okay"; +}; + +&dsi0 { + status = "okay"; +}; + +&serdes0 { + status = "okay"; + serdes0_pcie1_link: phy@0 { + reg = <0>; + cdns,num-lanes = <2>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 1>, <&serdes_wiz0 2>; + }; +}; + +&serdes_wiz0 { + status = "okay"; +}; + +&pcie1_rc { + status = "okay"; + num-lanes = <2>; + reset-gpios = <&exp1 2 GPIO_ACTIVE_HIGH>; + phys = <&serdes0_pcie1_link>; + phy-names = "pcie-phy"; +}; + +&serdes1 { + status = "okay"; + serdes1_pcie0_link: phy@0 { + reg = <0>; + cdns,num-lanes = <2>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz1 1>, <&serdes_wiz1 2>; + }; +}; + +&serdes_wiz1 { + status = "okay"; +}; + +&pcie0_rc { + status = "okay"; + reset-gpios = <&exp1 6 GPIO_ACTIVE_HIGH>; + phys = <&serdes1_pcie0_link>; + phy-names = "pcie-phy"; +}; + +&mcu_mcan0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_pins_default>; + phys = <&transceiver0>; +}; + +&mcu_mcan1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan1_pins_default>; + phys = <&transceiver1>; +}; + +&main_mcan16 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan16_pins_default>; + phys = <&transceiver2>; +}; + +&main_mcan4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan4_pins_default>; + phys = <&transceiver3>; +}; + +#define K3_TS_OFFSET(pa, val) (0x4+(pa)*4) (0x10000 | val) + +×ync_router { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_cpsw_cpts>; + + /* Use Time Sync Router to map GENF1 input to HW4_TS_PUSH output */ + mcu_cpsw_cpts: mcu-cpsw-cpts { + pinctrl-single,pins = < + /* pps [mcu cpsw cpts genf1] in17 -> out25 [mcu cpsw cpts hw4_push] */ + K3_TS_OFFSET(25, 17) + >; + }; +}; + +&k3_clks { + /* Confiure AUDIO_EXT_REFCLK2 pin as output */ + pinctrl-names = "default"; + pinctrl-0 = <&audio_ext_refclk1_pins_default>; +}; + +&main_i2c3 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c3_pins_default>; + clock-frequency = <400000>; + + exp3: gpio@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + }; + + pcm3168a_1: audio-codec@44 { + compatible = "ti,pcm3168a"; + reg = <0x44>; + #sound-dai-cells = <1>; + reset-gpios = <&exp3 0 GPIO_ACTIVE_LOW>; + /* C_AUDIO_REFCLK2 -> RGMII6_RXC (W26) */ + clocks = <&audio_refclk1>; + clock-names = "scki"; + VDD1-supply = <&vsys_3v3>; + VDD2-supply = <&vsys_3v3>; + VCCAD1-supply = <&vsys_5v0>; + VCCAD2-supply = <&vsys_5v0>; + VCCDA1-supply = <&vsys_5v0>; + VCCDA2-supply = <&vsys_5v0>; + }; +}; + +&mcasp0 { + status = "okay"; + #sound-dai-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&mcasp0_pins_default>; + op-mode = <0>; /* MCASP_IIS_MODE */ + tdm-slots = <2>; + auxclk-fs-ratio = <256>; + serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ + 0 0 0 1 + 2 0 0 0 + 0 0 0 0 + 0 0 0 0 + >; + tx-num-evt = <0>; + rx-num-evt = <0>; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j784s4-evm-ethfw.dtso b/arch/arm64/boot/dts/ti/k3-j784s4-evm-ethfw.dtso --- a/arch/arm64/boot/dts/ti/k3-j784s4-evm-ethfw.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j784s4-evm-ethfw.dtso 2024-07-07 20:37:34.636306509 -0400 @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT Overlay for CPSW9G functionality with Ethernet Switch Firmware (EthFw) + * and CPSW Proxy Client driver. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include "k3-serdes.h" + +&serdes_ln_ctrl { + idle-states = , , + , , + , , + , , + , , + , , + , , + , ; +}; + +/* uart2 is assigned to EthFw running on remote CPU core */ +&main_uart2 { + status = "reserved"; +}; + +/* Reserve shared memory for inter-core network communication */ +&reserved_memory { + #address-cells = <2>; + #size-cells = <2>; + + main_r5fss0_core0_shared_memory_queue_region:r5f-virtual-eth-queues@af000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xaf000000 0x00 0x200000>; + no-map; + }; + + main_r5fss0_core0_shared_memory_bufpool_region:r5f-virtual-eth-buffers@af200000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xaf200000 0x00 0x1e00000>; + no-map; + }; +}; + +&main_r5fss0_core0 { + memory-region = <&main_r5fss0_core0_dma_memory_region>, + <&main_r5fss0_core0_memory_region>, + <&main_r5fss0_core0_shared_memory_queue_region>, + <&main_r5fss0_core0_shared_memory_bufpool_region>; +}; + +/* EthFw uses timers so mark them reserved */ +&main_timer12 { + status = "reserved"; +}; + +&main_timer13 { + status = "reserved"; +}; + +/* + * Disable the following to avoid overloading exp2. + * Otherwise it will result in PHY read/write errors. + */ +&main_mcan4 { + status = "disabled"; +}; + +&transceiver3 { + status = "disabled"; +}; + +&mux1 { + status = "disabled"; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j784s4-evm-pcie0-pcie1-ep.dtso b/arch/arm64/boot/dts/ti/k3-j784s4-evm-pcie0-pcie1-ep.dtso --- a/arch/arm64/boot/dts/ti/k3-j784s4-evm-pcie0-pcie1-ep.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j784s4-evm-pcie0-pcie1-ep.dtso 2024-07-07 20:37:34.636306509 -0400 @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT Overlay for enabling PCIE0 and PCIE1 instances in Endpoint Configuration + * on J784S4 EVM. + * + * J784S4 EVM Product Link: https://www.ti.com/tool/J784S4XEVM + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +/* + * Since Root Complex and Endpoint modes are mutually exclusive + * disable Root Complex mode. + */ +&pcie0_rc { + status = "disabled"; +}; + +&pcie1_rc { + status = "disabled"; +}; + +&cbass_main { + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&gic500>; + + pcie0_ep: pcie-ep@2900000 { + compatible = "ti,j784s4-pcie-ep"; + reg = <0x00 0x02900000 0x00 0x1000>, + <0x00 0x02907000 0x00 0x400>, + <0x00 0x0d000000 0x00 0x00800000>, + <0x00 0x10000000 0x00 0x08000000>; + reg-names = "intd_cfg", "user_cfg", "reg", "mem"; + interrupt-names = "link_state"; + interrupts = ; + ti,syscon-pcie-ctrl = <&pcie0_ctrl 0x0>; + max-link-speed = <3>; + num-lanes = <4>; + power-domains = <&k3_pds 332 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 332 0>; + clock-names = "fck"; + max-functions = /bits/ 8 <6>; + max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>; + dma-coherent; + phys = <&serdes1_pcie0_link>; + phy-names = "pcie-phy"; + }; + + pcie1_ep: pcie-ep@2910000 { + compatible = "ti,j784s4-pcie-ep"; + reg = <0x00 0x02910000 0x00 0x1000>, + <0x00 0x02917000 0x00 0x400>, + <0x00 0x0d800000 0x00 0x00800000>, + <0x00 0x18000000 0x00 0x08000000>; + reg-names = "intd_cfg", "user_cfg", "reg", "mem"; + interrupt-names = "link_state"; + interrupts = ; + ti,syscon-pcie-ctrl = <&pcie1_ctrl 0x0>; + max-link-speed = <3>; + num-lanes = <2>; + power-domains = <&k3_pds 333 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 333 0>; + clock-names = "fck"; + max-functions = /bits/ 8 <6>; + max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>; + dma-coherent; + phys = <&serdes0_pcie1_link>; + phy-names = "pcie-phy"; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j784s4-evm-quad-port-eth-exp1.dtso b/arch/arm64/boot/dts/ti/k3-j784s4-evm-quad-port-eth-exp1.dtso --- a/arch/arm64/boot/dts/ti/k3-j784s4-evm-quad-port-eth-exp1.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j784s4-evm-quad-port-eth-exp1.dtso 2024-07-07 20:37:34.636306509 -0400 @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/** + * DT Overlay for CPSW9G in QSGMII mode using J7 Quad Port ETH EXP Add-On Ethernet Card with + * J784S4 EVM. The Add-On Ethernet Card has to be connected to ENET Expansion 1 slot on the + * board. + * + * Product Datasheet: https://www.ti.com/lit/ug/spruj74/spruj74.pdf + * + * Link to QSGMII Daughtercard: https://www.ti.com/tool/J721EXENETXPANEVM + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +#include "k3-pinctrl.h" +#include "k3-serdes.h" + +&{/} { + aliases { + ethernet1 = "/bus@100000/ethernet@c000000/ethernet-ports/port@5"; + ethernet2 = "/bus@100000/ethernet@c000000/ethernet-ports/port@6"; + ethernet3 = "/bus@100000/ethernet@c000000/ethernet-ports/port@7"; + ethernet4 = "/bus@100000/ethernet@c000000/ethernet-ports/port@8"; + ethernet5 = "/bus@100000/ethernet@c200000/ethernet-ports/port@1"; + }; +}; + +&main_cpsw0 { + status = "okay"; +}; + +&main_cpsw0_port5 { + phy-handle = <&cpsw9g_phy1>; + phy-mode = "qsgmii"; + mac-address = [00 00 00 00 00 00]; + phys = <&cpsw0_phy_gmii_sel 5>, <&serdes2_qsgmii_link>; + phy-names = "mac", "serdes"; + status = "okay"; +}; + +&main_cpsw0_port6 { + phy-handle = <&cpsw9g_phy2>; + phy-mode = "qsgmii"; + mac-address = [00 00 00 00 00 00]; + phys = <&cpsw0_phy_gmii_sel 6>, <&serdes2_qsgmii_link>; + phy-names = "mac", "serdes"; + status = "okay"; +}; + +&main_cpsw0_port7 { + phy-handle = <&cpsw9g_phy0>; + phy-mode = "qsgmii"; + mac-address = [00 00 00 00 00 00]; + phys = <&cpsw0_phy_gmii_sel 7>, <&serdes2_qsgmii_link>; + phy-names = "mac", "serdes"; + status = "okay"; +}; + +&main_cpsw0_port8 { + phy-handle = <&cpsw9g_phy3>; + phy-mode = "qsgmii"; + mac-address = [00 00 00 00 00 00]; + phys = <&cpsw0_phy_gmii_sel 8>, <&serdes2_qsgmii_link>; + phy-names = "mac", "serdes"; + status = "okay"; +}; + +&main_cpsw0_mdio { + pinctrl-names = "default"; + pinctrl-0 = <&mdio0_default_pins>; + bus_freq = <1000000>; + reset-gpios = <&exp2 17 GPIO_ACTIVE_LOW>; + reset-post-delay-us = <120000>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + cpsw9g_phy0: ethernet-phy@16 { + reg = <16>; + }; + cpsw9g_phy1: ethernet-phy@17 { + reg = <17>; + }; + cpsw9g_phy2: ethernet-phy@18 { + reg = <18>; + }; + cpsw9g_phy3: ethernet-phy@19 { + reg = <19>; + }; +}; + +&exp2 { + /* Power-up ENET1 EXPANDER PHY. */ + qsgmii-line-hog { + gpio-hog; + gpios = <16 GPIO_ACTIVE_HIGH>; + output-low; + }; + + /* Toggle MUX2 for MDIO lines */ + mux-sel-hog { + gpio-hog; + gpios = <13 GPIO_ACTIVE_HIGH>, <14 GPIO_ACTIVE_HIGH>, <15 GPIO_ACTIVE_HIGH>; + output-high; + }; +}; + +&main_pmx0 { + mdio0_default_pins: mdio0-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x05c, PIN_INPUT, 4) /* (AC36) MCASP2_AXR0.MDIO1_MDIO */ + J784S4_IOPAD(0x058, PIN_INPUT, 4) /* (AE37) MCASP2_AFSX.MDIO1_MDC */ + >; + }; +}; + +&serdes_ln_ctrl { + idle-states = , , + , , + , , + , , + , , + , ; +}; + +&serdes_wiz2 { + status = "okay"; +}; + +&serdes2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + serdes2_qsgmii_link: phy@0 { + reg = <2>; + cdns,num-lanes = <1>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz2 3>; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j784s4-evm-usxgmii-exp1-exp2.dtso b/arch/arm64/boot/dts/ti/k3-j784s4-evm-usxgmii-exp1-exp2.dtso --- a/arch/arm64/boot/dts/ti/k3-j784s4-evm-usxgmii-exp1-exp2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-j784s4-evm-usxgmii-exp1-exp2.dtso 2024-07-07 20:37:34.636306509 -0400 @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/** + * DT Overlay for CPSW9G in dual port fixed-link USXGMII mode using ENET-1 + * and ENET-2 Expansion slots of J784S4 EVM. + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +#include "k3-serdes.h" + +&{/} { + aliases { + ethernet1 = "/bus@100000/ethernet@c000000/ethernet-ports/port@1"; + ethernet2 = "/bus@100000/ethernet@c000000/ethernet-ports/port@2"; + ethernet3 = "/bus@100000/ethernet@c200000/ethernet-ports/port@1"; + }; +}; + +&main_cpsw0 { + pinctrl-names = "default"; + status = "okay"; +}; + +&main_cpsw0_port1 { + phy-mode = "usxgmii"; + mac-address = [00 00 00 00 00 00]; + phys = <&cpsw0_phy_gmii_sel 1>, <&serdes2_usxgmii_link>; + phy-names = "mac", "serdes"; + status = "okay"; + fixed-link { + speed = <5000>; + full-duplex; + }; +}; + +&main_cpsw0_port2 { + phy-mode = "usxgmii"; + mac-address = [00 00 00 00 00 00]; + phys = <&cpsw0_phy_gmii_sel 2>, <&serdes2_usxgmii_link>; + phy-names = "mac", "serdes"; + status = "okay"; + fixed-link { + speed = <5000>; + full-duplex; + }; +}; + +&serdes_wiz2 { + assigned-clock-parents = <&k3_clks 406 9>; /* Use 156.25 MHz clock for USXGMII */ + status = "okay"; +}; + +&serdes2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + serdes2_usxgmii_link: phy@2 { + reg = <2>; + cdns,num-lanes = <2>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz2 3>, <&serdes_wiz2 4>; + }; +}; + +&serdes_ln_ctrl { + idle-states = , , + , , + , , + , , + , , + , ; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi --- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi 2024-07-07 20:37:34.636306509 -0400 @@ -1,10 +1,26 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree Source for J784S4 SoC Family Main Domain peripherals * - * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ */ +#include +#include +#include +#include + +#include "k3-serdes.h" + +/ { + serdes_refclk: clock-serdes { + #clock-cells = <0>; + compatible = "fixed-clock"; + /* To be enabled when serdes_wiz* is functional */ + status = "disabled"; + }; +}; + &cbass_main { msmc_ram: sram@70000000 { compatible = "mmio-sram"; @@ -26,6 +42,162 @@ }; }; + main_ehrpwm0: pwm@3000000 { + compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; + #pwm-cells = <3>; + reg = <0x00 0x3000000 0x00 0x100>; + clocks = <&ehrpwm_tbclk 0>, <&k3_clks 219 0>; + clock-names = "tbclk", "fck"; + power-domains = <&k3_pds 219 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_ehrpwm1: pwm@3010000 { + compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; + #pwm-cells = <3>; + reg = <0x00 0x3010000 0x00 0x100>; + clocks = <&ehrpwm_tbclk 1>, <&k3_clks 220 0>; + clock-names = "tbclk", "fck"; + power-domains = <&k3_pds 220 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_ehrpwm2: pwm@3020000 { + compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; + #pwm-cells = <3>; + reg = <0x00 0x3020000 0x00 0x100>; + clocks = <&ehrpwm_tbclk 2>, <&k3_clks 221 0>; + clock-names = "tbclk", "fck"; + power-domains = <&k3_pds 221 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_ehrpwm3: pwm@3030000 { + compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; + #pwm-cells = <3>; + reg = <0x00 0x3030000 0x00 0x100>; + clocks = <&ehrpwm_tbclk 3>, <&k3_clks 222 0>; + clock-names = "tbclk", "fck"; + power-domains = <&k3_pds 222 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_ehrpwm4: pwm@3040000 { + compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; + #pwm-cells = <3>; + reg = <0x00 0x3040000 0x00 0x100>; + clocks = <&ehrpwm_tbclk 4>, <&k3_clks 223 0>; + clock-names = "tbclk", "fck"; + power-domains = <&k3_pds 223 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_ehrpwm5: pwm@3050000 { + compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; + #pwm-cells = <3>; + reg = <0x00 0x3050000 0x00 0x100>; + clocks = <&ehrpwm_tbclk 5>, <&k3_clks 224 0>; + clock-names = "tbclk", "fck"; + power-domains = <&k3_pds 224 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + scm_conf: bus@100000 { + compatible = "simple-bus"; + reg = <0x00 0x00100000 0x00 0x1c000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x00 0x00 0x00100000 0x1c000>; + + cpsw1_phy_gmii_sel: phy@4034 { + compatible = "ti,am654-phy-gmii-sel"; + reg = <0x4034 0x4>; + #phy-cells = <1>; + }; + + cpsw0_phy_gmii_sel: phy@4044 { + compatible = "ti,j784s4-cpsw9g-phy-gmii-sel"; + reg = <0x4044 0x20>; + #phy-cells = <1>; + ti,qsgmii-main-ports = <7>, <7>; + }; + + pcie0_ctrl: pcie0-ctrl@4070 { + compatible = "ti,j784s4-pcie-ctrl", "syscon"; + reg = <0x4070 0x4>; + }; + + pcie1_ctrl: pcie1-ctrl@4074 { + compatible = "ti,j784s4-pcie-ctrl", "syscon"; + reg = <0x4074 0x4>; + }; + + pcie2_ctrl: pcie2-ctrl@4078 { + compatible = "ti,j784s4-pcie-ctrl", "syscon"; + reg = <0x4078 0x4>; + }; + + pcie3_ctrl: pcie3-ctrl@407c { + compatible = "ti,j784s4-pcie-ctrl", "syscon"; + reg = <0x407c 0x4>; + }; + + acspcie0_proxy_ctrl: acspcie0-ctrl@1a090 { + compatible = "ti,j784s4-acspcie-proxy-ctrl", "syscon"; + reg = <0x1a090 0x4>; + }; + + serdes_ln_ctrl: mux-controller@4080 { + compatible = "reg-mux"; + reg = <0x00004080 0x30>; + #mux-control-cells = <1>; + mux-reg-masks = <0x0 0x3>, <0x4 0x3>, /* SERDES0 lane0/1 select */ + <0x8 0x3>, <0xc 0x3>, /* SERDES0 lane2/3 select */ + <0x10 0x3>, <0x14 0x3>, /* SERDES1 lane0/1 select */ + <0x18 0x3>, <0x1c 0x3>, /* SERDES1 lane2/3 select */ + <0x20 0x3>, <0x24 0x3>, /* SERDES2 lane0/1 select */ + <0x28 0x3>, <0x2c 0x3>; /* SERDES2 lane2/3 select */ + idle-states = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + + usb_serdes_mux: mux-controller@4000 { + compatible = "reg-mux"; + reg = <0x4000 0x4>; + #mux-control-cells = <1>; + mux-reg-masks = <0x0 0x8000000>; /* USB0 to SERDES0 lane 3 mux */ + }; + + ehrpwm_tbclk: clock-controller@4140 { + compatible = "ti,am654-ehrpwm-tbclk"; + reg = <0x4140 0x18>; + #clock-cells = <1>; + }; + + audio_refclk1: clock@82e4 { + compatible = "ti,am62-audio-refclk"; + reg = <0x82e4 0x4>; + clocks = <&k3_clks 157 34>; + assigned-clocks = <&k3_clks 157 34>; + assigned-clock-parents = <&k3_clks 157 63>; + #clock-cells = <0>; + }; + }; + gic500: interrupt-controller@1800000 { compatible = "arm,gic-v3"; #address-cells = <2>; @@ -119,6 +291,7 @@ assigned-clock-parents = <&k3_clks 97 3>; power-domains = <&k3_pds 97 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer1: timer@2410000 { @@ -131,6 +304,7 @@ assigned-clock-parents = <&k3_clks 98 3>; power-domains = <&k3_pds 98 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer2: timer@2420000 { @@ -143,6 +317,7 @@ assigned-clock-parents = <&k3_clks 99 3>; power-domains = <&k3_pds 99 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer3: timer@2430000 { @@ -155,6 +330,7 @@ assigned-clock-parents = <&k3_clks 100 3>; power-domains = <&k3_pds 100 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer4: timer@2440000 { @@ -167,6 +343,7 @@ assigned-clock-parents = <&k3_clks 101 3>; power-domains = <&k3_pds 101 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer5: timer@2450000 { @@ -179,6 +356,7 @@ assigned-clock-parents = <&k3_clks 102 3>; power-domains = <&k3_pds 102 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer6: timer@2460000 { @@ -191,6 +369,7 @@ assigned-clock-parents = <&k3_clks 103 3>; power-domains = <&k3_pds 103 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer7: timer@2470000 { @@ -203,6 +382,7 @@ assigned-clock-parents = <&k3_clks 104 3>; power-domains = <&k3_pds 104 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer8: timer@2480000 { @@ -215,6 +395,7 @@ assigned-clock-parents = <&k3_clks 105 3>; power-domains = <&k3_pds 105 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer9: timer@2490000 { @@ -227,6 +408,7 @@ assigned-clock-parents = <&k3_clks 106 3>; power-domains = <&k3_pds 106 TI_SCI_PD_EXCLUSIVE>; ti,timer-pwm; + status = "reserved"; }; main_timer10: timer@24a0000 { @@ -459,6 +641,19 @@ status = "disabled"; }; + gpu: gpu@4e20000000 { + compatible = "ti,j721s2-pvr", "img,pvr-bxs64"; + reg = <0x4e 0x20000000 0x00 0x80000>; + interrupts = ; + power-domains = <&k3_pds 181 TI_SCI_PD_EXCLUSIVE>, + <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + power-domain-names = "firmware", "dust"; + clocks = <&k3_clks 181 1>; + assigned-clocks = <&k3_clks 181 1>; + assigned-clock-rates = <800000000>; + clock-names = "core"; + }; + main_gpio0: gpio@600000 { compatible = "ti,j721e-gpio", "ti,keystone-gpio"; reg = <0x00 0x00600000 0x00 0x100>; @@ -527,6 +722,38 @@ status = "disabled"; }; + usbss0: usb@4104000 { + bootph-all; + compatible = "ti,j721e-usb"; + reg = <0x00 0x4104000 0x00 0x100>; + dma-coherent; + power-domains = <&k3_pds 398 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 398 21>, <&k3_clks 398 2>; + clock-names = "ref", "lpm"; + assigned-clocks = <&k3_clks 398 21>; /* USB2_REFCLK */ + assigned-clock-parents = <&k3_clks 398 22>; /* HFOSC0 */ + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; /* Needs lane config */ + + usb0: usb@6000000 { + bootph-all; + compatible = "cdns,usb3"; + reg = <0x00 0x6000000 0x00 0x10000>, + <0x00 0x6010000 0x00 0x10000>, + <0x00 0x6020000 0x00 0x10000>; + reg-names = "otg", "xhci", "dev"; + interrupts = , /* irq.0 */ + , /* irq.6 */ + ; /* otgirq.0 */ + interrupt-names = "host", + "peripheral", + "otg"; + }; + }; + main_i2c0: i2c@2000000 { compatible = "ti,j721e-i2c", "ti,omap4-i2c"; reg = <0x00 0x02000000 0x00 0x100>; @@ -611,6 +838,217 @@ status = "disabled"; }; + ti_csi2rx0: ticsi2rx@4500000 { + compatible = "ti,j721e-csi2rx-shim"; + reg = <0x00 0x04500000 0x00 0x00001000>; + ranges; + #address-cells = <2>; + #size-cells = <2>; + dmas = <&main_bcdma_csi 0 0x4940 0>, <&main_bcdma_csi 0 0x4941 0>, + <&main_bcdma_csi 0 0x4942 0>, <&main_bcdma_csi 0 0x4943 0>, + <&main_bcdma_csi 0 0x4944 0>, <&main_bcdma_csi 0 0x4945 0>, + <&main_bcdma_csi 0 0x4946 0>, <&main_bcdma_csi 0 0x4947 0>; + dma-names = "rx0", "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7"; + power-domains = <&k3_pds 72 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + cdns_csi2rx0: csi-bridge@4504000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x04504000 0x00 0x00001000>; + clocks = <&k3_clks 72 2>, <&k3_clks 72 0>, <&k3_clks 72 2>, + <&k3_clks 72 2>, <&k3_clks 72 3>, <&k3_clks 72 3>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi0_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi0_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi0_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi0_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + ti_csi2rx1: ticsi2rx@4510000 { + compatible = "ti,j721e-csi2rx-shim"; + reg = <0x00 0x04510000 0x00 0x1000>; + ranges; + #address-cells = <2>; + #size-cells = <2>; + dmas = <&main_bcdma_csi 0 0x4960 0>, <&main_bcdma_csi 0 0x4961 0>, + <&main_bcdma_csi 0 0x4962 0>, <&main_bcdma_csi 0 0x4963 0>, + <&main_bcdma_csi 0 0x4964 0>, <&main_bcdma_csi 0 0x4965 0>, + <&main_bcdma_csi 0 0x4966 0>, <&main_bcdma_csi 0 0x4967 0>; + dma-names = "rx0", "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7"; + power-domains = <&k3_pds 73 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + cdns_csi2rx1: csi-bridge@4514000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x04514000 0x00 0x00001000>; + clocks = <&k3_clks 73 2>, <&k3_clks 73 0>, <&k3_clks 73 2>, + <&k3_clks 73 2>, <&k3_clks 73 3>, <&k3_clks 73 3>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy1>; + phy-names = "dphy"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi1_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi1_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi1_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi1_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + ti_csi2rx2: ticsi2rx@4520000 { + compatible = "ti,j721e-csi2rx-shim"; + reg = <0x00 0x04520000 0x00 0x00001000>; + ranges; + #address-cells = <2>; + #size-cells = <2>; + dmas = <&main_bcdma_csi 0 0x4980 0>, <&main_bcdma_csi 0 0x4981 0>, + <&main_bcdma_csi 0 0x4982 0>, <&main_bcdma_csi 0 0x4983 0>, + <&main_bcdma_csi 0 0x4984 0>, <&main_bcdma_csi 0 0x4985 0>, + <&main_bcdma_csi 0 0x4986 0>, <&main_bcdma_csi 0 0x4987 0>; + dma-names = "rx0", "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7"; + power-domains = <&k3_pds 74 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + cdns_csi2rx2: csi-bridge@4524000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x04524000 0x00 0x00001000>; + clocks = <&k3_clks 74 2>, <&k3_clks 74 0>, <&k3_clks 74 2>, + <&k3_clks 74 2>, <&k3_clks 74 3>, <&k3_clks 74 3>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy2>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi2_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi2_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi2_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi2_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi2_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + dphy0: phy@4580000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x04580000 0x00 0x00001100>; + #phy-cells = <0>; + power-domains = <&k3_pds 212 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + dphy1: phy@4590000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x04590000 0x00 0x00001100>; + #phy-cells = <0>; + power-domains = <&k3_pds 213 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + dphy2: phy@45a0000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x045a0000 0x00 0x00001100>; + #phy-cells = <0>; + power-domains = <&k3_pds 214 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + vpu0: video-codec@4210000 { + compatible = "ti,j721s2-wave521c", "cnm,wave521c"; + reg = <0x00 0x4210000 0x00 0x10000>; + interrupts = ; + clocks = <&k3_clks 241 2>; + power-domains = <&k3_pds 241 TI_SCI_PD_EXCLUSIVE>; + sram = <&main_navss_sram>; + sram-size = <0x10000>; + }; + + vpu1: video-codec@4220000 { + compatible = "ti,j721s2-wave521c", "cnm,wave521c"; + reg = <0x00 0x4220000 0x00 0x10000>; + interrupts = ; + clocks = <&k3_clks 242 2>; + power-domains = <&k3_pds 242 TI_SCI_PD_EXCLUSIVE>; + sram = <&main_navss_sram>; + sram-size = <0x10000>; + }; + main_sdhci0: mmc@4f80000 { compatible = "ti,j721e-sdhci-8bit"; reg = <0x00 0x04f80000 0x00 0x1000>, @@ -661,14 +1099,284 @@ ti,itap-del-sel-sd-hs = <0x0>; ti,itap-del-sel-sdr12 = <0x0>; ti,itap-del-sel-sdr25 = <0x0>; + ti,itap-del-sel-ddr50 = <0x2>; ti,clkbuf-sel = <0x7>; ti,trm-icp = <0x8>; dma-coherent; - sdhci-caps-mask = <0x00000003 0x00000000>; - no-1-8-v; status = "disabled"; }; + pcie0_rc: pcie@2900000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02900000 0x00 0x1000>, + <0x00 0x02907000 0x00 0x400>, + <0x00 0x0d000000 0x00 0x00800000>, + <0x00 0x10000000 0x00 0x00001000>; + reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; + interrupt-names = "link_state"; + interrupts = ; + device_type = "pci"; + ti,syscon-pcie-ctrl = <&pcie0_ctrl 0x0>; + max-link-speed = <3>; + num-lanes = <4>; + power-domains = <&k3_pds 332 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 332 0>; + clock-names = "fck"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + vendor-id = <0x104c>; + device-id = <0xb012>; + msi-map = <0x0 &gic_its 0x0 0x10000>; + dma-coherent; + ranges = <0x01000000 0x0 0x10001000 0x0 0x10001000 0x0 0x0010000>, + <0x02000000 0x0 0x10011000 0x0 0x10011000 0x0 0x7fef000>; + dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; + status = "disabled"; + }; + + pcie1_rc: pcie@2910000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02910000 0x00 0x1000>, + <0x00 0x02917000 0x00 0x400>, + <0x00 0x0d800000 0x00 0x00800000>, + <0x00 0x18000000 0x00 0x00001000>; + reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; + interrupt-names = "link_state"; + interrupts = ; + device_type = "pci"; + ti,syscon-pcie-ctrl = <&pcie1_ctrl 0x0>; + ti,syscon-acspcie-proxy-ctrl = <&acspcie0_proxy_ctrl 0x1>; + max-link-speed = <3>; + num-lanes = <4>; + power-domains = <&k3_pds 333 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 333 0>, <&serdes0 CDNS_TORRENT_REFCLK_DRIVER>; + clock-names = "fck", "pcie_refclk"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + vendor-id = <0x104c>; + device-id = <0xb012>; + msi-map = <0x0 &gic_its 0x10000 0x10000>; + dma-coherent; + ranges = <0x01000000 0x0 0x18001000 0x00 0x18001000 0x0 0x0010000>, + <0x02000000 0x0 0x18011000 0x00 0x18011000 0x0 0x7fef000>; + dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; + status = "disabled"; + }; + + pcie2_rc: pcie@2920000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02920000 0x00 0x1000>, + <0x00 0x02927000 0x00 0x400>, + <0x00 0x0e000000 0x00 0x00800000>, + <0x44 0x00000000 0x00 0x00001000>; + reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; + interrupt-names = "link_state"; + interrupts = ; + device_type = "pci"; + ti,syscon-pcie-ctrl = <&pcie2_ctrl 0x0>; + max-link-speed = <3>; + num-lanes = <2>; + power-domains = <&k3_pds 334 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 334 0>; + clock-names = "fck"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + vendor-id = <0x104c>; + device-id = <0xb012>; + msi-map = <0x0 &gic_its 0x20000 0x10000>; + dma-coherent; + ranges = <0x01000000 0x0 0x00001000 0x44 0x00001000 0x0 0x0010000>, + <0x02000000 0x0 0x00011000 0x44 0x00011000 0x0 0x7fef000>; + dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; + status = "disabled"; + }; + + pcie3_rc: pcie@2930000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02930000 0x00 0x1000>, + <0x00 0x02937000 0x00 0x400>, + <0x00 0x0e800000 0x00 0x00800000>, + <0x44 0x10000000 0x00 0x00001000>; + reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; + interrupt-names = "link_state"; + interrupts = ; + device_type = "pci"; + ti,syscon-pcie-ctrl = <&pcie3_ctrl 0x0>; + max-link-speed = <3>; + num-lanes = <2>; + power-domains = <&k3_pds 335 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 335 0>; + clock-names = "fck"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + vendor-id = <0x104c>; + device-id = <0xb012>; + msi-map = <0x0 &gic_its 0x30000 0x10000>; + dma-coherent; + ranges = <0x01000000 0x0 0x00001000 0x44 0x10001000 0x0 0x0010000>, + <0x02000000 0x0 0x00011000 0x44 0x10011000 0x0 0x7fef000>; + dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; + status = "disabled"; + }; + + serdes_wiz0: wiz@5060000 { + compatible = "ti,j784s4-wiz-10g"; + #address-cells = <1>; + #size-cells = <1>; + power-domains = <&k3_pds 404 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 404 2>, <&k3_clks 404 6>, <&serdes_refclk>, <&k3_clks 404 5>; + clock-names = "fck", "core_ref_clk", "ext_ref_clk", "core_ref1_clk"; + assigned-clocks = <&k3_clks 404 6>; + assigned-clock-parents = <&k3_clks 404 10>; + num-lanes = <4>; + #reset-cells = <1>; + #clock-cells = <1>; + ranges = <0x5060000 0x00 0x5060000 0x10000>; + status = "disabled"; + + serdes0: serdes@5060000 { + compatible = "ti,j721e-serdes-10g"; + reg = <0x05060000 0x010000>; + reg-names = "torrent_phy"; + resets = <&serdes_wiz0 0>; + reset-names = "torrent_reset"; + clocks = <&serdes_wiz0 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz0 TI_WIZ_PHY_EN_REFCLK>; + clock-names = "refclk", "phy_en_refclk"; + assigned-clocks = <&serdes_wiz0 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz0 TI_WIZ_PLL1_REFCLK>, + <&serdes_wiz0 TI_WIZ_REFCLK_DIG>; + assigned-clock-parents = <&k3_clks 404 6>, + <&k3_clks 404 6>, + <&k3_clks 404 6>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + status = "disabled"; + }; + }; + + serdes_wiz1: wiz@5070000 { + compatible = "ti,j784s4-wiz-10g"; + #address-cells = <1>; + #size-cells = <1>; + power-domains = <&k3_pds 405 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 405 2>, <&k3_clks 405 6>, <&serdes_refclk>, <&k3_clks 405 5>; + clock-names = "fck", "core_ref_clk", "ext_ref_clk", "core_ref1_clk"; + assigned-clocks = <&k3_clks 405 6>; + assigned-clock-parents = <&k3_clks 405 10>; + num-lanes = <4>; + #reset-cells = <1>; + #clock-cells = <1>; + ranges = <0x05070000 0x00 0x05070000 0x10000>; + status = "disabled"; + + serdes1: serdes@5070000 { + compatible = "ti,j721e-serdes-10g"; + reg = <0x05070000 0x010000>; + reg-names = "torrent_phy"; + resets = <&serdes_wiz1 0>; + reset-names = "torrent_reset"; + clocks = <&serdes_wiz1 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz1 TI_WIZ_PHY_EN_REFCLK>; + clock-names = "refclk", "phy_en_refclk"; + assigned-clocks = <&serdes_wiz1 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz1 TI_WIZ_PLL1_REFCLK>, + <&serdes_wiz1 TI_WIZ_REFCLK_DIG>; + assigned-clock-parents = <&k3_clks 405 6>, + <&k3_clks 405 6>, + <&k3_clks 405 6>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + status = "disabled"; + }; + }; + + serdes_wiz2: wiz@5020000 { + compatible = "ti,j784s4-wiz-10g"; + #address-cells = <1>; + #size-cells = <1>; + power-domains = <&k3_pds 406 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 406 2>, <&k3_clks 406 6>, <&serdes_refclk>, <&k3_clks 406 5>; + clock-names = "fck", "core_ref_clk", "ext_ref_clk", "core_ref1_clk"; + assigned-clocks = <&k3_clks 406 6>; + assigned-clock-parents = <&k3_clks 406 10>; + num-lanes = <4>; + #reset-cells = <1>; + #clock-cells = <1>; + ranges = <0x05020000 0x00 0x05020000 0x10000>; + status = "disabled"; + + serdes2: serdes@5020000 { + compatible = "ti,j721e-serdes-10g"; + reg = <0x05020000 0x010000>; + reg-names = "torrent_phy"; + resets = <&serdes_wiz2 0>; + reset-names = "torrent_reset"; + clocks = <&serdes_wiz2 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz2 TI_WIZ_PHY_EN_REFCLK>; + clock-names = "refclk", "phy_en_refclk"; + assigned-clocks = <&serdes_wiz2 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz2 TI_WIZ_PLL1_REFCLK>, + <&serdes_wiz2 TI_WIZ_REFCLK_DIG>; + assigned-clock-parents = <&k3_clks 406 6>, + <&k3_clks 406 6>, + <&k3_clks 406 6>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + status = "disabled"; + }; + }; + + serdes_wiz4: wiz@5050000 { + compatible = "ti,j784s4-wiz-10g"; + #address-cells = <1>; + #size-cells = <1>; + power-domains = <&k3_pds 407 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 407 2>, <&k3_clks 407 6>, <&serdes_refclk>, <&k3_clks 407 5>; + clock-names = "fck", "core_ref_clk", "ext_ref_clk", "core_ref1_clk"; + assigned-clocks = <&k3_clks 407 6>; + assigned-clock-parents = <&k3_clks 407 10>; + num-lanes = <4>; + #reset-cells = <1>; + #clock-cells = <1>; + ranges = <0x05050000 0x00 0x05050000 0x10000>, + <0xa030a00 0x00 0xa030a00 0x40>; /* DPTX PHY */ + status = "disabled"; + + serdes4: serdes@5050000 { + /* + * Note: we also map DPTX PHY registers as the Torrent + * needs to manage those. + */ + compatible = "ti,j721e-serdes-10g"; + reg = <0x05050000 0x010000>, + <0x0a030a00 0x40>; /* DPTX PHY */ + reg-names = "torrent_phy"; + resets = <&serdes_wiz4 0>; + reset-names = "torrent_reset"; + clocks = <&serdes_wiz4 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz4 TI_WIZ_PHY_EN_REFCLK>; + clock-names = "refclk", "phy_en_refclk"; + assigned-clocks = <&serdes_wiz4 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz4 TI_WIZ_PLL1_REFCLK>, + <&serdes_wiz4 TI_WIZ_REFCLK_DIG>; + assigned-clock-parents = <&k3_clks 407 6>, + <&k3_clks 407 6>, + <&k3_clks 407 6>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + status = "disabled"; + }; + }; + main_navss: bus@30000000 { bootph-all; compatible = "simple-bus"; @@ -679,6 +1387,14 @@ dma-coherent; dma-ranges; + main_navss_sram: navss-sram@30000000{ + compatible = "mmio-sram"; + reg = <0x00 0x30000000 0x00 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x30000000 0x10000>; + }; + main_navss_intr: interrupt-controller@310e0000 { compatible = "ti,sci-intr"; reg = <0x00 0x310e0000 0x00 0x4000>; @@ -703,6 +1419,7 @@ ti,sci = <&sms>; ti,sci-dev-id = <321>; ti,interrupt-ranges = <0 0 256>; + ti,unmapped-event-sources = <&main_bcdma_csi>; }; secure_proxy_main: mailbox@32c00000 { @@ -982,8 +1699,12 @@ compatible = "ti,j721e-navss-main-udmap"; reg = <0x00 0x31150000 0x00 0x100>, <0x00 0x34000000 0x00 0x80000>, - <0x00 0x35000000 0x00 0x200000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x00 0x35000000 0x00 0x200000>, + <0x00 0x30b00000 0x00 0x20000>, + <0x00 0x30c00000 0x00 0x8000>, + <0x00 0x30d00000 0x00 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; @@ -1000,6 +1721,21 @@ ti,sci-rm-range-rflow = <0x00>; /* GP RFLOW */ }; + main_bcdma_csi: dma-controller@311a0000 { + compatible = "ti,j721s2-dmss-bcdma-csi"; + reg = <0x00 0x311a0000 0x00 0x100>, + <0x00 0x35d00000 0x00 0x20000>, + <0x00 0x35c00000 0x00 0x10000>, + <0x00 0x35e00000 0x00 0x80000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + msi-parent = <&main_udmass_inta>; + #dma-cells = <3>; + ti,sci = <&sms>; + ti,sci-dev-id = <281>; + ti,sci-rm-range-rchan = <0x21>; + ti,sci-rm-range-tchan = <0x22>; + }; + cpts@310d0000 { compatible = "ti,j721e-cpts"; reg = <0x00 0x310d0000 0x00 0x400>; @@ -1015,6 +1751,180 @@ }; }; + main_cpsw0: ethernet@c000000 { + compatible = "ti,j784s4-cpswxg-nuss"; + reg = <0x00 0xc000000 0x00 0x200000>; + reg-names = "cpsw_nuss"; + ranges = <0x00 0x00 0x00 0xc000000 0x00 0x200000>; + #address-cells = <2>; + #size-cells = <2>; + dma-coherent; + clocks = <&k3_clks 64 0>; + clock-names = "fck"; + power-domains = <&k3_pds 64 TI_SCI_PD_EXCLUSIVE>; + + dmas = <&main_udmap 0xca00>, + <&main_udmap 0xca01>, + <&main_udmap 0xca02>, + <&main_udmap 0xca03>, + <&main_udmap 0xca04>, + <&main_udmap 0xca05>, + <&main_udmap 0xca06>, + <&main_udmap 0xca07>, + <&main_udmap 0x4a00>; + dma-names = "tx0", "tx1", "tx2", "tx3", + "tx4", "tx5", "tx6", "tx7", + "rx"; + + status = "disabled"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + main_cpsw0_port1: port@1 { + reg = <1>; + label = "port1"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port2: port@2 { + reg = <2>; + label = "port2"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port3: port@3 { + reg = <3>; + label = "port3"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port4: port@4 { + reg = <4>; + label = "port4"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port5: port@5 { + reg = <5>; + label = "port5"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port6: port@6 { + reg = <6>; + label = "port6"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port7: port@7 { + reg = <7>; + label = "port7"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port8: port@8 { + reg = <8>; + label = "port8"; + ti,mac-only; + status = "disabled"; + }; + }; + + main_cpsw0_mdio: mdio@f00 { + compatible = "ti,cpsw-mdio","ti,davinci_mdio"; + reg = <0x00 0xf00 0x00 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 64 0>; + clock-names = "fck"; + bus_freq = <1000000>; + status = "disabled"; + }; + + cpts@3d000 { + compatible = "ti,am65-cpts"; + reg = <0x00 0x3d000 0x00 0x400>; + clocks = <&k3_clks 64 3>; + clock-names = "cpts"; + interrupts-extended = <&gic500 GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpts"; + ti,cpts-ext-ts-inputs = <4>; + ti,cpts-periodic-outputs = <2>; + }; + }; + + main_cpsw1: ethernet@c200000 { + compatible = "ti,j721e-cpsw-nuss"; + reg = <0x00 0xc200000 0x00 0x200000>; + reg-names = "cpsw_nuss"; + ranges = <0x00 0x00 0x00 0xc200000 0x00 0x200000>; + #address-cells = <2>; + #size-cells = <2>; + dma-coherent; + clocks = <&k3_clks 62 0>; + clock-names = "fck"; + power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>; + + dmas = <&main_udmap 0xc640>, + <&main_udmap 0xc641>, + <&main_udmap 0xc642>, + <&main_udmap 0xc643>, + <&main_udmap 0xc644>, + <&main_udmap 0xc645>, + <&main_udmap 0xc646>, + <&main_udmap 0xc647>, + <&main_udmap 0x4640>; + dma-names = "tx0", "tx1", "tx2", "tx3", + "tx4", "tx5", "tx6", "tx7", + "rx"; + + status = "disabled"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + main_cpsw1_port1: port@1 { + reg = <1>; + label = "port1"; + phys = <&cpsw1_phy_gmii_sel 1>; + ti,mac-only; + status = "disabled"; + }; + }; + + main_cpsw1_mdio: mdio@f00 { + compatible = "ti,cpsw-mdio", "ti,davinci_mdio"; + reg = <0x00 0xf00 0x00 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 62 0>; + clock-names = "fck"; + bus_freq = <1000000>; + status = "disabled"; + }; + + cpts@3d000 { + compatible = "ti,am65-cpts"; + reg = <0x00 0x3d000 0x00 0x400>; + clocks = <&k3_clks 62 3>; + clock-names = "cpts"; + interrupts-extended = <&gic500 GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpts"; + ti,cpts-ext-ts-inputs = <4>; + ti,cpts-periodic-outputs = <2>; + }; + }; + main_mcan0: can@2701000 { compatible = "bosch,m_can"; reg = <0x00 0x02701000 0x00 0x200>, @@ -1399,7 +2309,7 @@ main_r5fss0: r5fss@5c00000 { compatible = "ti,j721s2-r5fss"; - ti,cluster-mode = <1>; + ti,cluster-mode = <0>; #address-cells = <1>; #size-cells = <1>; ranges = <0x5c00000 0x00 0x5c00000 0x20000>, @@ -1439,7 +2349,7 @@ main_r5fss1: r5fss@5e00000 { compatible = "ti,j721s2-r5fss"; - ti,cluster-mode = <1>; + ti,cluster-mode = <0>; #address-cells = <1>; #size-cells = <1>; ranges = <0x5e00000 0x00 0x5e00000 0x20000>, @@ -1479,7 +2389,7 @@ main_r5fss2: r5fss@5900000 { compatible = "ti,j721s2-r5fss"; - ti,cluster-mode = <1>; + ti,cluster-mode = <0>; #address-cells = <1>; #size-cells = <1>; ranges = <0x5900000 0x00 0x5900000 0x20000>, @@ -1568,4 +2478,407 @@ firmware-name = "j784s4-c71_3-fw"; status = "disabled"; }; + + main_esm: esm@700000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x700000 0x00 0x1000>; + ti,esm-pins = <688>, <689>, <690>, <691>, <692>, <693>, <694>, + <695>; + bootph-pre-ram; + }; + + watchdog0: watchdog@2200000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2200000 0x00 0x100>; + clocks = <&k3_clks 348 1>; + power-domains = <&k3_pds 348 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 348 0>; + assigned-clock-parents = <&k3_clks 348 4>; + }; + + watchdog1: watchdog@2210000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2210000 0x00 0x100>; + clocks = <&k3_clks 349 1>; + power-domains = <&k3_pds 349 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 349 0>; + assigned-clock-parents = <&k3_clks 349 4>; + }; + + watchdog2: watchdog@2220000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2220000 0x00 0x100>; + clocks = <&k3_clks 350 1>; + power-domains = <&k3_pds 350 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 350 0>; + assigned-clock-parents = <&k3_clks 350 4>; + }; + + watchdog3: watchdog@2230000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2230000 0x00 0x100>; + clocks = <&k3_clks 351 1>; + power-domains = <&k3_pds 351 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 351 0>; + assigned-clock-parents = <&k3_clks 351 4>; + }; + + watchdog4: watchdog@2240000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2240000 0x00 0x100>; + clocks = <&k3_clks 352 1>; + power-domains = <&k3_pds 352 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 352 0>; + assigned-clock-parents = <&k3_clks 352 4>; + }; + + watchdog5: watchdog@2250000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2250000 0x00 0x100>; + clocks = <&k3_clks 353 1>; + power-domains = <&k3_pds 353 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 353 0>; + assigned-clock-parents = <&k3_clks 353 4>; + }; + + watchdog6: watchdog@2260000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2260000 0x00 0x100>; + clocks = <&k3_clks 354 1>; + power-domains = <&k3_pds 354 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 354 0>; + assigned-clock-parents = <&k3_clks 354 4>; + }; + + watchdog7: watchdog@2270000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2270000 0x00 0x100>; + clocks = <&k3_clks 355 1>; + power-domains = <&k3_pds 355 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 355 0>; + assigned-clock-parents = <&k3_clks 355 4>; + }; + + /* + * The following RTI instances are coupled with MCU R5Fs, c7x and + * GPU so keeping them reserved as these will be used by their + * respective firmware + */ + watchdog8: watchdog@22f0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x22f0000 0x00 0x100>; + clocks = <&k3_clks 360 1>; + power-domains = <&k3_pds 360 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 360 0>; + assigned-clock-parents = <&k3_clks 360 4>; + /* reserved for GPU */ + status = "reserved"; + }; + + watchdog9: watchdog@2300000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2300000 0x00 0x100>; + clocks = <&k3_clks 356 1>; + power-domains = <&k3_pds 356 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 356 0>; + assigned-clock-parents = <&k3_clks 356 4>; + /* reserved for C7X_0 DSP */ + status = "reserved"; + }; + + watchdog10: watchdog@2310000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2310000 0x00 0x100>; + clocks = <&k3_clks 357 1>; + power-domains = <&k3_pds 357 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 357 0>; + assigned-clock-parents = <&k3_clks 357 4>; + /* reserved for C7X_1 DSP */ + status = "reserved"; + }; + + watchdog11: watchdog@2320000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2320000 0x00 0x100>; + clocks = <&k3_clks 358 1>; + power-domains = <&k3_pds 358 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 358 0>; + assigned-clock-parents = <&k3_clks 358 4>; + /* reserved for C7X_2 DSP */ + status = "reserved"; + }; + + watchdog12: watchdog@2330000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2330000 0x00 0x100>; + clocks = <&k3_clks 359 1>; + power-domains = <&k3_pds 359 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 359 0>; + assigned-clock-parents = <&k3_clks 359 4>; + /* reserved for C7X_3 DSP */ + status = "reserved"; + }; + + watchdog13: watchdog@23c0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x23c0000 0x00 0x100>; + clocks = <&k3_clks 361 1>; + power-domains = <&k3_pds 361 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 361 0>; + assigned-clock-parents = <&k3_clks 361 4>; + /* reserved for MAIN_R5F0_0 */ + status = "reserved"; + }; + + watchdog14: watchdog@23d0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x23d0000 0x00 0x100>; + clocks = <&k3_clks 362 1>; + power-domains = <&k3_pds 362 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 362 0>; + assigned-clock-parents = <&k3_clks 362 4>; + /* reserved for MAIN_R5F0_1 */ + status = "reserved"; + }; + + watchdog15: watchdog@23e0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x23e0000 0x00 0x100>; + clocks = <&k3_clks 363 1>; + power-domains = <&k3_pds 363 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 363 0>; + assigned-clock-parents = <&k3_clks 363 4>; + /* reserved for MAIN_R5F1_0 */ + status = "reserved"; + }; + + watchdog16: watchdog@23f0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x23f0000 0x00 0x100>; + clocks = <&k3_clks 364 1>; + power-domains = <&k3_pds 364 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 364 0>; + assigned-clock-parents = <&k3_clks 364 4>; + /* reserved for MAIN_R5F1_1 */ + status = "reserved"; + }; + + watchdog17: watchdog@2540000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2540000 0x00 0x100>; + clocks = <&k3_clks 365 1>; + power-domains = <&k3_pds 365 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 365 0>; + assigned-clock-parents = <&k3_clks 366 4>; + /* reserved for MAIN_R5F2_0 */ + status = "reserved"; + }; + + watchdog18: watchdog@2550000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2550000 0x00 0x100>; + clocks = <&k3_clks 366 1>; + power-domains = <&k3_pds 366 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 366 0>; + assigned-clock-parents = <&k3_clks 366 4>; + /* reserved for MAIN_R5F2_1 */ + status = "reserved"; + }; + + dphy_tx0: phy@4480000 { + compatible = "ti,j721e-dphy"; + reg = <0x0 0x04480000 0x0 0x1000>; + clocks = <&k3_clks 402 20>, <&k3_clks 402 3>; + clock-names = "psm", "pll_ref"; + #phy-cells = <0>; + power-domains = <&k3_pds 402 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 402 3>; + assigned-clock-parents = <&k3_clks 402 4>; + assigned-clock-rates = <19200000>; + status = "disabled"; + }; + + dsi0: dsi@4800000 { + compatible = "ti,j721e-dsi"; + reg = <0x0 0x04800000 0x0 0x100000>, <0x0 0x04710000 0x0 0x100>; + clocks = <&k3_clks 215 2>, <&k3_clks 215 5>; + clock-names = "dsi_p_clk", "dsi_sys_clk"; + power-domains = <&k3_pds 215 TI_SCI_PD_EXCLUSIVE>; + interrupt-parent = <&gic500>; + interrupts = ; + phys = <&dphy_tx0>; + phy-names = "dphy"; + status = "disabled"; + + dsi0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + }; + port@1 { + reg = <1>; + }; + }; + }; + + timesync_router: pinctrl@a40000 { + compatible = "pinctrl-single"; + reg = <0x0 0xa40000 0x0 0x800>; + #address-cells = <1>; + #size-cells = <0>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x000107ff>; + status = "disabled"; + }; + + mhdp: bridge@a000000 { + compatible = "ti,j721e-mhdp8546"; + reg = <0x0 0xa000000 0x0 0x30a00>, + <0x0 0x4f40000 0x0 0x20>; + reg-names = "mhdptx", "j721e-intg"; + clocks = <&k3_clks 217 11>; + interrupt-parent = <&gic500>; + interrupts = ; + power-domains = <&k3_pds 217 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + dp0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + /* Remote-endpoints are on the boards so + * ports are defined in the platform dt file. + */ + }; + }; + + dss: dss@4a00000 { + compatible = "ti,j721e-dss"; + reg = <0x00 0x04a00000 0x00 0x10000>, /* common_m */ + <0x00 0x04a10000 0x00 0x10000>, /* common_s0*/ + <0x00 0x04b00000 0x00 0x10000>, /* common_s1*/ + <0x00 0x04b10000 0x00 0x10000>, /* common_s2*/ + <0x00 0x04a20000 0x00 0x10000>, /* vidl1 */ + <0x00 0x04a30000 0x00 0x10000>, /* vidl2 */ + <0x00 0x04a50000 0x00 0x10000>, /* vid1 */ + <0x00 0x04a60000 0x00 0x10000>, /* vid2 */ + <0x00 0x04a70000 0x00 0x10000>, /* ovr1 */ + <0x00 0x04a90000 0x00 0x10000>, /* ovr2 */ + <0x00 0x04ab0000 0x00 0x10000>, /* ovr3 */ + <0x00 0x04ad0000 0x00 0x10000>, /* ovr4 */ + <0x00 0x04a80000 0x00 0x10000>, /* vp1 */ + <0x00 0x04aa0000 0x00 0x10000>, /* vp1 */ + <0x00 0x04ac0000 0x00 0x10000>, /* vp1 */ + <0x00 0x04ae0000 0x00 0x10000>, /* vp4 */ + <0x00 0x04af0000 0x00 0x10000>; /* wb */ + reg-names = "common_m", "common_s0", + "common_s1", "common_s2", + "vidl1", "vidl2","vid1","vid2", + "ovr1", "ovr2", "ovr3", "ovr4", + "vp1", "vp2", "vp3", "vp4", + "wb"; + clocks = <&k3_clks 218 0>, + <&k3_clks 218 2>, + <&k3_clks 218 5>, + <&k3_clks 218 14>, + <&k3_clks 218 18>; + clock-names = "fck", "vp1", "vp2", "vp3", "vp4"; + power-domains = <&k3_pds 218 TI_SCI_PD_EXCLUSIVE>; + interrupts = , + , + , + ; + interrupt-names = "common_m", + "common_s0", + "common_s1", + "common_s2"; + status = "disabled"; + + dss_ports: ports { + /* Ports that DSS drives are platform specific + * so they are defined in platform dt file. + */ + }; + }; + + mcasp0: mcasp@2b00000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x0 0x02b00000 0x0 0x2000>, + <0x0 0x02b08000 0x0 0x1000>; + reg-names = "mpu","dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + dmas = <&main_udmap 0xc400>, <&main_udmap 0x4400>; + dma-names = "tx", "rx"; + clocks = <&k3_clks 265 1>; + clock-names = "fck"; + power-domains = <&k3_pds 265 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcasp1: mcasp@2b10000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x0 0x02b10000 0x0 0x2000>, + <0x0 0x02b18000 0x0 0x1000>; + reg-names = "mpu","dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + dmas = <&main_udmap 0xc401>, <&main_udmap 0x4401>; + dma-names = "tx", "rx"; + clocks = <&k3_clks 266 1>; + clock-names = "fck"; + power-domains = <&k3_pds 266 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcasp2: mcasp@2b20000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x0 0x02b20000 0x0 0x2000>, + <0x0 0x02b28000 0x0 0x1000>; + reg-names = "mpu","dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + dmas = <&main_udmap 0xc402>, <&main_udmap 0x4402>; + dma-names = "tx", "rx"; + clocks = <&k3_clks 267 1>; + clock-names = "fck"; + power-domains = <&k3_pds 267 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcasp3: mcasp@2b30000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x0 0x02b30000 0x0 0x2000>, + <0x0 0x02b38000 0x0 0x1000>; + reg-names = "mpu","dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + dmas = <&main_udmap 0xc500>, <&main_udmap 0x4500>; + dma-names = "tx", "rx"; + clocks = <&k3_clks 268 1>; + clock-names = "fck"; + power-domains = <&k3_pds 268 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcasp4: mcasp@2b40000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x0 0x02b40000 0x0 0x2000>, + <0x0 0x02b48000 0x0 0x1000>; + reg-names = "mpu","dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + dmas = <&main_udmap 0xc501>, <&main_udmap 0x4501>; + dma-names = "tx", "rx"; + clocks = <&k3_clks 269 1>; + clock-names = "fck"; + power-domains = <&k3_pds 269 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi --- a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi 2024-07-07 20:37:34.636306509 -0400 @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Device Tree Source for J784S4 SoC Family MCU/WAKEUP Domain peripherals * - * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ */ &cbass_mcu_wakeup { @@ -38,10 +38,18 @@ }; }; - chipid@43000014 { + wkup_conf: bus@43000000 { bootph-all; - compatible = "ti,am654-chipid"; - reg = <0x00 0x43000014 0x00 0x4>; + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + bootph-all; + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; secure_proxy_sa3: mailbox@43600000 { @@ -478,8 +486,12 @@ compatible = "ti,j721e-navss-mcu-udmap"; reg = <0x00 0x285c0000 0x00 0x100>, <0x00 0x2a800000 0x00 0x40000>, - <0x00 0x2aa00000 0x00 0x40000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x00 0x2aa00000 0x00 0x40000>, + <0x00 0x284a0000 0x00 0x4000>, + <0x00 0x284c0000 0x00 0x4000>, + <0x00 0x28400000 0x00 0x2000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; @@ -700,4 +712,44 @@ status = "disabled"; }; }; + + mcu_esm: esm@40800000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x40800000 0x00 0x1000>; + ti,esm-pins = <95>; + bootph-pre-ram; + }; + + wkup_esm: esm@42080000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x42080000 0x00 0x1000>; + ti,esm-pins = <63>; + bootph-pre-ram; + }; + + /* + * The 2 RTI instances are couple with MCU R5Fs so keeping them + * reserved as these will be used by their respective firmware + */ + mcu_watchdog0: watchdog@40600000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x40600000 0x00 0x100>; + clocks = <&k3_clks 367 1>; + power-domains = <&k3_pds 367 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 367 0>; + assigned-clock-parents = <&k3_clks 367 4>; + /* reserved for MCU_R5F0_0 */ + status = "reserved"; + }; + + mcu_watchdog1: watchdog@40610000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x40610000 0x00 0x100>; + clocks = <&k3_clks 368 1>; + power-domains = <&k3_pds 368 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 368 0>; + assigned-clock-parents = <&k3_clks 368 4>; + /* reserved for MCU_R5F0_1 */ + status = "reserved"; + }; }; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-j784s4-thermal.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-thermal.dtsi --- a/arch/arm64/boot/dts/ti/k3-j784s4-thermal.dtsi 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-j784s4-thermal.dtsi 2024-07-07 20:37:34.636306509 -0400 @@ -1,4 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ #include diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-pinctrl.h b/arch/arm64/boot/dts/ti/k3-pinctrl.h --- a/arch/arm64/boot/dts/ti/k3-pinctrl.h 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-pinctrl.h 2024-07-07 20:37:34.636306509 -0400 @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ /* * This header provides constants for pinctrl bindings for TI's K3 SoC * family. * - * Copyright (C) 2018-2023 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/ */ #ifndef DTS_ARM64_TI_K3_PINCTRL_H #define DTS_ARM64_TI_K3_PINCTRL_H @@ -12,6 +12,7 @@ #define PULLTYPESEL_SHIFT (17) #define RXACTIVE_SHIFT (18) #define DEBOUNCE_SHIFT (11) +#define WKUP_EN_SHIFT (29) #define PULL_DISABLE (1 << PULLUDEN_SHIFT) #define PULL_ENABLE (0 << PULLUDEN_SHIFT) @@ -38,6 +39,13 @@ #define PIN_DEBOUNCE_CONF5 (5 << DEBOUNCE_SHIFT) #define PIN_DEBOUNCE_CONF6 (6 << DEBOUNCE_SHIFT) +/* Default mux configuration for gpio-ranges to use with pinctrl */ +#define PIN_GPIO_RANGE_IOPAD (PIN_INPUT | 7) + +#define WKUP_EN (1 << WKUP_EN_SHIFT) + +#define PIN_GPIO_MUX_MODE (7) + #define AM62AX_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) #define AM62AX_MCU_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) @@ -59,6 +67,9 @@ #define J721S2_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) #define J721S2_WKUP_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) +#define J722S_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) +#define J722S_MCU_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) + #define J784S4_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) #define J784S4_WKUP_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-serdes.h b/arch/arm64/boot/dts/ti/k3-serdes.h --- a/arch/arm64/boot/dts/ti/k3-serdes.h 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/k3-serdes.h 2024-07-07 20:37:34.636306509 -0400 @@ -1,8 +1,8 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ /* * This header provides constants for SERDES MUX for TI SoCs * - * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ */ #ifndef DTS_ARM64_TI_K3_SERDES_H @@ -111,7 +111,7 @@ #define J721S2_SERDES0_LANE2_EDP_LANE2 0x0 #define J721S2_SERDES0_LANE2_PCIE1_LANE2 0x1 -#define J721S2_SERDES0_LANE2_IP3_UNUSED 0x2 +#define J721S2_SERDES0_LANE2_USB_SWAP 0x2 #define J721S2_SERDES0_LANE2_IP4_UNUSED 0x3 #define J721S2_SERDES0_LANE3_EDP_LANE3 0x0 @@ -201,4 +201,12 @@ #define J784S4_SERDES4_LANE3_USB 0x2 #define J784S4_SERDES4_LANE3_IP4_UNUSED 0x3 +/* J722S */ + +#define J722S_SERDES0_LANE0_USB 0x0 +#define J722S_SERDES0_LANE0_QSGMII_LANE2 0x1 + +#define J722S_SERDES1_LANE0_PCIE0_LANE0 0x0 +#define J722S_SERDES1_LANE0_QSGMII_LANE1 0x1 + #endif /* DTS_ARM64_TI_K3_SERDES_H */ diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-0.dtso b/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-0.dtso --- a/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-0.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-0.dtso 2024-07-07 20:37:34.636306509 -0400 @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX219 Camera Module for V3-Link d-ch Adapter Board + * https://docs.arducam.com/V3Link-Camera-Solution/V3Link-Camera-Solution-on-TI-Platform/Introduction/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_imx219_fixed_00: imx219-xclk-00 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&ds90ub960_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 0 */ + port@0 { + reg = <0>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@0 { + reg = <0>; + i2c-alias = <0x44>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + clock-lanes = <0>; + data-lanes = <1 2>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed_00>; + clock-names = "xclk"; + reset-gpios = <&serializer 1 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-1.dtso b/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-1.dtso --- a/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-1.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-1.dtso 2024-07-07 20:37:34.636306509 -0400 @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX219 Camera Module for V3-Link d-ch Adapter Board + * https://docs.arducam.com/V3Link-Camera-Solution/V3Link-Camera-Solution-on-TI-Platform/Introduction/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_imx219_fixed_01: imx219-xclk-01 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&ds90ub960_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 1 */ + port@1 { + reg = <1>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@1 { + reg = <1>; + i2c-alias = <0x45>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + clock-lanes = <0>; + data-lanes = <1 2>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed_01>; + clock-names = "xclk"; + reset-gpios = <&serializer 1 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-2.dtso b/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-2.dtso --- a/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-2.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-2.dtso 2024-07-07 20:37:34.636306509 -0400 @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX219 Camera Module for V3-Link d-ch Adapter Board + * https://docs.arducam.com/V3Link-Camera-Solution/V3Link-Camera-Solution-on-TI-Platform/Introduction/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_imx219_fixed_02: imx219-xclk-02 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&ds90ub960_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 2 */ + port@2 { + reg = <2>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@2 { + reg = <2>; + i2c-alias = <0x46>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + clock-lanes = <0>; + data-lanes = <1 2>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed_02>; + clock-names = "xclk"; + reset-gpios = <&serializer 1 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-3.dtso b/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-3.dtso --- a/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-3.dtso 1969-12-31 19:00:00.000000000 -0500 +++ b/arch/arm64/boot/dts/ti/k3-v3link-imx219-0-3.dtso 2024-07-07 20:37:34.636306509 -0400 @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX219 Camera Module for V3-Link d-ch Adapter Board + * https://docs.arducam.com/V3Link-Camera-Solution/V3Link-Camera-Solution-on-TI-Platform/Introduction/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_imx219_fixed_03: imx219-xclk-03 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&ds90ub960_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 3 */ + port@3 { + reg = <3>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@3 { + reg = <3>; + i2c-alias = <0x47>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + clock-lanes = <0>; + data-lanes = <1 2>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed_03>; + clock-names = "xclk"; + reset-gpios = <&serializer 1 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; + }; +}; diff -Naur --no-dereference a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile --- a/arch/arm64/boot/dts/ti/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/boot/dts/ti/Makefile 2024-07-07 20:37:34.624306449 -0400 @@ -9,76 +9,388 @@ # alphabetically. # Boards with AM62x SoC -k3-am625-sk-hdmi-audio-dtbs := k3-am625-sk.dtb k3-am62x-sk-hdmi-audio.dtbo -k3-am62-lp-sk-hdmi-audio-dtbs := k3-am62-lp-sk.dtb k3-am62x-sk-hdmi-audio.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay-csi2-tevi-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay-lincolntech-lcd185-panel.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am625-phyboard-lyra-rdk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-sk.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-dmtimer-pwm.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-ecap-capture.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-lincolntech-lcd185-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-m2-cc3301.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-microtips-mf101hie-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-pwm.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-rpi-hdr-ehrpwm.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-dahlia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-dev.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-mallow.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-yavia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dev.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-mallow.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-yavia.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am62x-phyboard-lyra-gpio-fan.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-e3-max-opp.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk.dtb -dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-hdmi-audio.dtb -dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk-hdmi-audio.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk-lincolntech-lcd185-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk-microtips-mf101hie-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-mcspi-loopback.dtbo # Boards with AM62Ax SoC dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-csi2-ox05b1s.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-ethernet-dc01.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-fusion.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-m2-cc3301.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-rpi-hdr-ehrpwm.dtbo # Boards with AM62Px SoC dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk-dsi-rpi-7inch-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk-eqep.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk-m2-cc3301.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk-mcan.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk-microtips-mf070zima-lcd3.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk-microtips-mf101hie-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk-microtips-mf103hie-lcd2.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk-rpi-hdr-ehrpwm.dtbo + +# Common overlays for SK-AM62* family of boards +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-tevi-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-imx219.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-v3link-fusion.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-eqep.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-fastboot-disable-hdmi.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-hdmi-audio.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-mcan.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-microtips-mf103hie-lcd2.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-lpm-wkup-sources.dtbo # Boards with AM64x SoC dtb-$(CONFIG_ARCH_K3) += k3-am642-evm.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am642-evm-icssg1-dualemac.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am642-evm-icssg1-dualemac-mii.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am642-phyboard-electra-rdk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am642-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am642-tqma64xxl-mbax4xxl.dtb - -k3-am642-tqma64xxl-mbax4xxl-sdcard-dtbs := \ - k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-sdcard.dtbo -k3-am642-tqma64xxl-mbax4xxl-wlan-dtbs := \ - k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-wlan.dtbo - -dtb-$(CONFIG_ARCH_K3) += k3-am642-tqma64xxl-mbax4xxl-sdcard.dtb -dtb-$(CONFIG_ARCH_K3) += k3-am642-tqma64xxl-mbax4xxl-wlan.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am64-tqma64xxl-mbax4xxl-sdcard.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am64-tqma64xxl-mbax4xxl-wlan.dtbo # Boards with AM65x SoC -k3-am654-gp-evm-dtbs := k3-am654-base-board.dtb k3-am654-base-board-rocktech-rk101-panel.dtbo +k3-am654-gp-evm-dtbs := k3-am654-base-board.dtb \ + k3-am654-base-board-rocktech-rk101-panel.dtbo \ + k3-am654-pcie-usb3.dtbo +k3-am654-evm-dtbs := k3-am654-base-board.dtb k3-am654-icssg2.dtbo +k3-am654-idk-dtbs := k3-am654-evm.dtb k3-am654-idk.dtbo k3-am654-pcie-usb2.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am6528-iot2050-basic.dtb dtb-$(CONFIG_ARCH_K3) += k3-am6528-iot2050-basic-pg2.dtb dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced.dtb dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced-m2.dtb dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced-pg2.dtb dtb-$(CONFIG_ARCH_K3) += k3-am654-base-board.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am654-base-board-toshiba-tc358867-evm.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am654-gp-evm.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am654-evm.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am654-idk.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am654-base-board-rocktech-rk101-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am654-pcie-usb2.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am654-pcie-usb3.dtbo # Boards with J7200 SoC k3-j7200-evm-dtbs := k3-j7200-common-proc-board.dtb k3-j7200-evm-quad-port-eth-exp.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j7200-evm.dtb +dtb-$(CONFIG_ARCH_K3) += k3-j7200-evm-ethfw.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j7200-evm-mcspi-loopback.dtbo # Boards with J721e SoC k3-j721e-evm-dtbs := k3-j721e-common-proc-board.dtb k3-j721e-evm-quad-port-eth-exp.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721e-beagleboneai64.dtb +dtb-$(CONFIG_ARCH_K3) += k3-j721e-beagleboneai64-dsi-rpi-7inch-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721e-beagleboneai64-microtips-mf070zima-lcd3.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721e-common-proc-board-infotainment.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm.dtb +dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm-fusion.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm-ethfw.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm-gesi-exp-board.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm-pcie0-ep.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm-ina2xx.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk.dtb +dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-csi2-dual-imx219.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-fpdlink-fusion.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-rpi-hdr-ehrpwm.dtbo # Boards with J721s2 SoC dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-base-board.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-bb-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-rpi-hdr-ehrpwm.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-v3link-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721s2-common-proc-board.dtb +dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-gesi-exp-board.dtbo k3-j721s2-evm-dtbs := k3-j721s2-common-proc-board.dtb k3-j721s2-evm-gesi-exp-board.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm.dtb +dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-pcie1-ep.dtbo + +# Boards with J722s SoC +dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm.dtb +dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-quad-rpi-cam-imx219.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-quad-tevi-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-dsi-rpi-7inch-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-fpdlink-fusion.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-microtips-mf101hie-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-v3link-fusion.dtbo # Boards with J784s4 SoC dtb-$(CONFIG_ARCH_K3) += k3-am69-sk.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-fpdlink-fusion-auxport.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm.dtb +dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm-ethfw.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm-pcie0-pcie1-ep.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm-quad-port-eth-exp1.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm-usxgmii-exp1-exp2.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-rpi-hdr-ehrpwm.dtbo + +# Build time test only, enabled by CONFIG_OF_ALL_DTBS +k3-am625-beagleplay-csi2-ov5640-dtbs := k3-am625-beagleplay.dtb \ + k3-am625-beagleplay-csi2-ov5640.dtbo +k3-am625-beagleplay-csi2-tevi-ov5640-dtbs := k3-am625-beagleplay.dtb \ + k3-am625-beagleplay-csi2-tevi-ov5640.dtbo +k3-am625-beagleplay-lincolntech-lcd185-panel-dtbs := k3-am625-beagleplay.dtb \ + k3-am625-beagleplay-lincolntech-lcd185-panel.dtbo +k3-am625-phyboard-lyra-gpio-fan-dtbs := k3-am625-phyboard-lyra-rdk.dtb \ + k3-am62x-phyboard-lyra-gpio-fan.dtbo +k3-am625-sk-csi2-imx219-dtbs := k3-am625-sk.dtb \ + k3-am62x-sk-csi2-imx219.dtbo +k3-am625-sk-csi2-ov5640-dtbs := k3-am625-sk.dtb \ + k3-am62x-sk-csi2-ov5640.dtbo +k3-am625-sk-csi2-tevi-ov5640-dtbs := k3-am625-sk.dtb \ + k3-am62x-sk-csi2-tevi-ov5640.dtbo +k3-am625-sk-fastboot-disable-hdmi-dtbs := k3-am625-sk.dtb \ + k3-am62x-sk-fastboot-disable-hdmi.dtbo +k3-am625-sk-hdmi-audio-dtbs := k3-am625-sk.dtb k3-am62x-sk-hdmi-audio.dtbo +k3-am625-sk-lincolntech-lcd185-panel-dtbs := k3-am625-sk.dtb \ + k3-am625-sk-lincolntech-lcd185-panel.dtbo +k3-am625-sk-microtips-mf101hie-panel-dtbs := k3-am625-sk.dtb \ + k3-am625-sk-microtips-mf101hie-panel.dtbo +k3-am625-sk-microtips-mf103hie-lcd2-dtbs := k3-am625-sk.dtb \ + k3-am62x-sk-microtips-mf103hie-lcd2.dtbo +k3-am62-lp-sk-fastboot-disable-hdmi-dtbs := k3-am62-lp-sk.dtb \ + k3-am62x-sk-fastboot-disable-hdmi.dtbo +k3-am62-lp-sk-hdmi-audio-dtbs := k3-am62-lp-sk.dtb k3-am62x-sk-hdmi-audio.dtbo +k3-am62-lp-sk-lincolntech-lcd185-panel-dtbs := k3-am62-lp-sk.dtb \ + k3-am62-lp-sk-lincolntech-lcd185-panel.dtbo +k3-am62-lp-sk-microtips-mf101hie-panel-dtbs := k3-am62-lp-sk.dtb \ + k3-am62-lp-sk-microtips-mf101hie-panel.dtbo +k3-am62-lp-sk-microtips-mf103hie-lcd2-dtbs := k3-am62-lp-sk.dtb \ + k3-am62x-sk-microtips-mf103hie-lcd2.dtbo +k3-am62a7-sk-csi2-imx219-dtbs := k3-am62a7-sk.dtb \ + k3-am62x-sk-csi2-imx219.dtbo +k3-am62a7-sk-csi2-ov5640-dtbs := k3-am62a7-sk.dtb \ + k3-am62x-sk-csi2-ov5640.dtbo +k3-am62a7-sk-csi2-tevi-ov5640-dtbs := k3-am62a7-sk.dtb \ + k3-am62x-sk-csi2-tevi-ov5640.dtbo +k3-am62a7-sk-ethernet-dc01-dtbs := k3-am62a7-sk.dtb \ + k3-am62a7-sk-ethernet-dc01.dtbo +k3-am62a7-sk-fastboot-disable-hdmi-dtbs := k3-am62a7-sk.dtb \ + k3-am62x-sk-fastboot-disable-hdmi.dtbo +k3-am62a7-sk-hdmi-audio-dtbs := k3-am62a7-sk.dtb k3-am62x-sk-hdmi-audio.dtbo +k3-am62p5-sk-csi2-imx219-dtbs := k3-am62p5-sk.dtb \ + k3-am62x-sk-csi2-imx219.dtbo +k3-am62p5-sk-csi2-ov5640-dtbs := k3-am62p5-sk.dtb \ + k3-am62x-sk-csi2-ov5640.dtbo +k3-am62p5-sk-csi2-tevi-ov5640-dtbs := k3-am62p5-sk.dtb \ + k3-am62x-sk-csi2-tevi-ov5640.dtbo +k3-am62p5-sk-fastboot-disable-hdmi-dtbs := k3-am62p5-sk.dtb \ + k3-am62x-sk-fastboot-disable-hdmi.dtbo +k3-am62p5-sk-dsi-rpi-7inch-panel-dtbs := k3-am62p5-sk.dtb \ + k3-am62p5-sk-dsi-rpi-7inch-panel.dtbo +k3-am62p5-sk-microtips-mf070zima-lcd3-dtbs := k3-am62p5-sk.dtb \ + k3-am62p5-sk-microtips-mf070zima-lcd3.dtbo +k3-am62p5-sk-microtips-mf101hie-panel-dtbs := k3-am62p5-sk.dtb \ + k3-am62p5-sk-microtips-mf101hie-panel.dtbo +k3-am62p5-sk-microtips-mf103hie-lcd2-dtbs := k3-am62p5-sk.dtb \ + k3-am62p5-sk-microtips-mf103hie-lcd2.dtbo +k3-am642-evm-icssg1-dualemac-dtbs := \ + k3-am642-evm.dtb k3-am642-evm-icssg1-dualemac.dtbo +k3-am642-evm-icssg1-dualemac-mii-dtbs := \ + k3-am642-evm.dtb k3-am642-evm-icssg1-dualemac-mii.dtbo +k3-am642-tqma64xxl-mbax4xxl-sdcard-dtbs := \ + k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-sdcard.dtbo +k3-am642-tqma64xxl-mbax4xxl-wlan-dtbs := \ + k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-wlan.dtbo +k3-am654-base-board-toshiba-tc358867-evm-dtbs := k3-am654-base-board.dtb \ + k3-am654-base-board-toshiba-tc358867-evm.dtbo +k3-am68-sk-base-board-csi2-dual-imx219-dtbs := k3-am68-sk-base-board.dtb \ + k3-j721e-sk-csi2-dual-imx219.dtbo +k3-am69-sk-csi2-dual-imx219-dtbs := k3-am69-sk.dtb \ + k3-j721e-sk-csi2-dual-imx219.dtbo +k3-j7200-evm-ethfw-dtbs := k3-j7200-common-proc-board.dtb \ + k3-j7200-evm-ethfw.dtbo +k3-j7200-evm-mcspi-loopback-dtbs := k3-j7200-common-proc-board.dtb \ + k3-j7200-evm-mcspi-loopback.dtbo +k3-j721e-beagleboneai64-dsi-rpi-7inch-panel-dtbs := k3-j721e-beagleboneai64.dtb \ + k3-j721e-beagleboneai64-dsi-rpi-7inch-panel.dtbo +k3-j721e-beagleboneai64-microtips-mf070zima-lcd3-dtbs := k3-j721e-beagleboneai64.dtb \ + k3-j721e-beagleboneai64-microtips-mf070zima-lcd3.dtbo +k3-j721e-common-proc-board-infotainment-dtbs := k3-j721e-common-proc-board.dtb \ + k3-j721e-common-proc-board-infotainment.dtbo +k3-j721e-evm-ethfw-dtbs := k3-j721e-common-proc-board.dtb \ + k3-j721e-evm-ethfw.dtbo +k3-j721e-evm-mcspi-loopback-dtbs := k3-j721e-common-proc-board.dtb \ + k3-j7200-evm-mcspi-loopback.dtbo +k3-j721e-evm-pcie0-ep-dtbs := k3-j721e-common-proc-board.dtb \ + k3-j721e-evm-pcie0-ep.dtbo +k3-j721e-evm-ina2xx-dtbs := k3-j721e-common-proc-board.dtb \ + k3-j721e-evm-ina2xx.dtbo +k3-j721e-sk-csi2-dual-imx219-dtbs := k3-j721e-sk.dtb \ + k3-j721e-sk-csi2-dual-imx219.dtbo +k3-j721s2-evm-mcspi-loopback-dtbs := k3-j721s2-common-proc-board.dtb \ + k3-j7200-evm-mcspi-loopback.dtbo +k3-j721s2-evm-pcie1-ep-dtbs := k3-j721s2-common-proc-board.dtb \ + k3-j721s2-evm-pcie1-ep.dtbo +k3-j722s-evm-dsi-rpi-7inch-panel-dtbs := k3-j722s-evm.dtb \ + k3-j722s-evm-dsi-rpi-7inch-panel.dtbo +k3-j722s-evm-microtips-mf101hie-panel-dtbs := k3-j722s-evm.dtb \ + k3-j722s-evm-microtips-mf101hie-panel.dtbo +k3-j784s4-evm-ethfw-dtbs := k3-j784s4-evm.dtb \ + k3-j784s4-evm-ethfw.dtbo +k3-j784s4-evm-mcspi-loopback-dtbs := k3-j784s4-evm.dtb \ + k3-j7200-evm-mcspi-loopback.dtbo +k3-j784s4-evm-pcie0-pcie1-ep-dtbs := k3-j784s4-evm.dtb \ + k3-j784s4-evm-pcie0-pcie1-ep.dtbo +k3-j784s4-evm-quad-port-eth-exp1-dtbs := k3-j784s4-evm.dtb \ + k3-j784s4-evm-quad-port-eth-exp1.dtbo +k3-j784s4-evm-usxgmii-exp1-exp2-dtbs := k3-j784s4-evm.dtb \ + k3-j784s4-evm-usxgmii-exp1-exp2.dtbo +dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \ + k3-am625-beagleplay-csi2-tevi-ov5640.dtb \ + k3-am625-beagleplay-lincolntech-lcd185-panel.dtb \ + k3-am625-sk-csi2-imx219.dtb \ + k3-am625-sk-csi2-ov5640.dtb \ + k3-am625-sk-csi2-tevi-ov5640.dtb \ + k3-am625-sk-fastboot-disable-hdmi.dtb \ + k3-am625-sk-hdmi-audio.dtb \ + k3-am625-sk-lincolntech-lcd185-panel.dtb \ + k3-am625-sk-microtips-mf101hie-panel.dtb \ + k3-am625-sk-microtips-mf103hie-lcd2.dtb \ + k3-am62-lp-sk-fastboot-disable-hdmi.dtb \ + k3-am62-lp-sk-hdmi-audio.dtb \ + k3-am62-lp-sk-lincolntech-lcd185-panel.dtb \ + k3-am62-lp-sk-microtips-mf101hie-panel.dtb \ + k3-am62-lp-sk-microtips-mf103hie-lcd2.dtb \ + k3-am62a7-sk-csi2-imx219.dtb \ + k3-am62a7-sk-csi2-ov5640.dtb \ + k3-am62a7-sk-fastboot-disable-hdmi.dtb \ + k3-am62a7-sk-hdmi-audio.dtb \ + k3-am62p5-sk-csi2-imx219.dtb \ + k3-am62p5-sk-csi2-ov5640.dtb \ + k3-am62p5-sk-csi2-tevi-ov5640.dtb \ + k3-am62p5-sk-dsi-rpi-7inch-panel.dtb \ + k3-am62p5-sk-fastboot-disable-hdmi.dtb \ + k3-am62p5-sk-microtips-mf070zima-lcd3.dtb \ + k3-am62p5-sk-microtips-mf101hie-panel.dtb \ + k3-am62p5-sk-microtips-mf103hie-lcd2.dtb \ + k3-am642-evm-icssg1-dualemac.dtb \ + k3-am642-evm-icssg1-dualemac-mii.dtb \ + k3-am642-tqma64xxl-mbax4xxl-sdcard.dtb \ + k3-am642-tqma64xxl-mbax4xxl-wlan.dtb \ + k3-am654-base-board-toshiba-tc358867-evm.dtb \ + k3-am68-sk-base-board-csi2-dual-imx219-dtbs \ + k3-am69-sk-csi2-dual-imx219-dtbs \ + k3-j7200-evm-ethfw.dtb \ + k3-j7200-evm-mcspi-loopback.dtb \ + k3-j721e-beagleboneai64-dsi-rpi-7inch-panel.dtb \ + k3-j721e-beagleboneai64-microtips-mf070zima-lcd3.dtb \ + k3-j721e-common-proc-board-infotainment.dtb \ + k3-j721e-evm-ethfw.dtb \ + k3-j721e-evm-mcspi-loopback.dtb \ + k3-j721e-evm-pcie0-ep.dtb \ + k3-j721e-evm-ina2xx.dtb \ + k3-j721e-sk-csi2-dual-imx219-dtbs \ + k3-j721s2-evm-pcie1-ep.dtb \ + k3-j721s2-evm-mcspi-loopback.dtb \ + k3-j722s-evm-dsi-rpi-7inch-panel.dtb \ + k3-j722s-evm-microtips-mf101hie-panel.dtb \ + k3-j784s4-evm-ethfw.dtb \ + k3-j784s4-evm-mcspi-loopback.dtb \ + k3-j784s4-evm-pcie0-pcie1-ep.dtb \ + k3-j784s4-evm-quad-port-eth-exp1.dtb \ + k3-j784s4-evm-usxgmii-exp1-exp2.dtb + +# FPDLink Sensors +dtb-$(CONFIG_ARCH_K3) += k3-fpdlink-imx390-rcm-0-0.dtbo \ + k3-fpdlink-imx390-rcm-0-1.dtbo \ + k3-fpdlink-imx390-rcm-0-2.dtbo \ + k3-fpdlink-imx390-rcm-0-3.dtbo \ + k3-fpdlink-imx390-rcm-1-0.dtbo \ + k3-fpdlink-imx390-rcm-1-1.dtbo \ + k3-fpdlink-imx390-rcm-1-2.dtbo \ + k3-fpdlink-imx390-rcm-1-3.dtbo \ + k3-fpdlink-imx390-rcm-2-0.dtbo \ + k3-fpdlink-imx390-rcm-2-1.dtbo \ + k3-fpdlink-imx390-rcm-2-2.dtbo \ + k3-fpdlink-imx390-rcm-2-3.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-fpdlink-ov2312-0-0.dtbo \ + k3-fpdlink-ov2312-0-1.dtbo \ + k3-fpdlink-ov2312-0-2.dtbo \ + k3-fpdlink-ov2312-0-3.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-v3link-imx219-0-0.dtbo \ + k3-v3link-imx219-0-1.dtbo \ + k3-v3link-imx219-0-2.dtbo \ + k3-v3link-imx219-0-3.dtbo + +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai.dtb +dtb-$(CONFIG_ARCH_K3) += BONE-I2C1.dtbo +dtb-$(CONFIG_ARCH_K3) += BONE-I2C2.dtbo +dtb-$(CONFIG_ARCH_K3) += BONE-I2C3.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-ecap0-gpio12.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-ecap1-gpio16.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-ecap1-gpio21.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-ecap2-gpio17.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-ecap2-gpio18.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-epwm0-gpio12.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-epwm0-gpio14.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-epwm0-gpio15.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-epwm0-gpio5.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-epwm1-gpio13.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-epwm1-gpio20.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-epwm1-gpio21.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am67a-beagley-ai-pwm-epwm1-gpio6.dtbo # Enable support for device-tree overlays +DTC_FLAGS_k3-am625-beagleplay += -@ DTC_FLAGS_k3-am625-sk += -@ DTC_FLAGS_k3-am62-lp-sk += -@ +DTC_FLAGS_k3-am62x-sk-csi2-v3link-fusion += -@ +DTC_FLAGS_k3-am62a7-sk += -@ +DTC_FLAGS_k3-am62p5-sk += -@ +DTC_FLAGS_k3-am642-evm += -@ +DTC_FLAGS_k3-am642-tqma64xxl-mbax4xxl += -@ DTC_FLAGS_k3-am6548-iot2050-advanced-m2 += -@ +DTC_FLAGS_k3-am62p5-sk += -@ +DTC_FLAGS_k3-am68-sk-base-board += -@ +DTC_FLAGS_k3-am68-sk-v3link-fusion += -@ +DTC_FLAGS_k3-am69-sk += -@ +DTC_FLAGS_k3-am69-sk-fpdlink-fusion-auxport += -@ +DTC_FLAGS_k3-j7200-common-proc-board += -@ +DTC_FLAGS_k3-j721e-beagleboneai64 += -@ +DTC_FLAGS_k3-j721e-evm-fusion += -@ DTC_FLAGS_k3-j721e-common-proc-board += -@ +DTC_FLAGS_k3-j721e-sk += -@ +DTC_FLAGS_k3-j721e-sk-fpdlink-fusion += -@ DTC_FLAGS_k3-j721s2-common-proc-board += -@ +DTC_FLAGS_k3-j721s2-evm-fusion += -@ +DTC_FLAGS_k3-j722s-evm += -@ +DTC_FLAGS_k3-j722s-evm-fpdlink-fusion += -@ +DTC_FLAGS_k3-j722s-evm-v3link-fusion += -@ +DTC_FLAGS_k3-j784s4-evm += -@ +DTC_FLAGS_k3-am67a-beagley-ai += -@ +DTC_FLAGS_k3-j721e-beagleboneai64 += -@ diff -Naur --no-dereference a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig --- a/arch/arm64/configs/defconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/arch/arm64/configs/defconfig 2024-07-07 20:37:34.636306509 -0400 @@ -30,6 +30,9 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_KALLSYMS_ALL=y CONFIG_PROFILING=y +CONFIG_KEXEC=y +CONFIG_KEXEC_FILE=y +CONFIG_CRASH_DUMP=y CONFIG_ARCH_ACTIONS=y CONFIG_ARCH_SUNXI=y CONFIG_ARCH_ALPINE=y @@ -77,9 +80,6 @@ CONFIG_SCHED_MC=y CONFIG_SCHED_SMT=y CONFIG_NUMA=y -CONFIG_KEXEC=y -CONFIG_KEXEC_FILE=y -CONFIG_CRASH_DUMP=y CONFIG_XEN=y CONFIG_COMPAT=y CONFIG_RANDOMIZE_BASE=y @@ -119,7 +119,6 @@ CONFIG_JUMP_LABEL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -CONFIG_IOSCHED_BFQ=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set # CONFIG_COMPAT_BRK is not set CONFIG_MEMORY_HOTPLUG=y @@ -129,8 +128,7 @@ CONFIG_TRANSPARENT_HUGEPAGE=y CONFIG_NET=y CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y +CONFIG_XDP_SOCKETS=y CONFIG_IP_MULTICAST=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y @@ -172,16 +170,38 @@ CONFIG_NET_SCH_MQPRIO=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_FLOW=m CONFIG_NET_CLS_FLOWER=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_GACT=m +CONFIG_NET_ACT_POLICE=m +CONFIG_GACT_PROB=y CONFIG_NET_ACT_MIRRED=m CONFIG_NET_ACT_GATE=m +CONFIG_HSR=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_NET_ACT_CSUM=m CONFIG_QRTR_SMD=m CONFIG_QRTR_TUN=m CONFIG_CAN=m -CONFIG_CAN_M_CAN=m -CONFIG_CAN_M_CAN_PLATFORM=m CONFIG_BT=m CONFIG_BT_HIDP=m # CONFIG_BT_LE is not set @@ -215,27 +235,33 @@ CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_ACPI=y CONFIG_PCI_AARDVARK=y -CONFIG_PCI_TEGRA=y -CONFIG_PCIE_RCAR_HOST=y -CONFIG_PCIE_RCAR_EP=y -CONFIG_PCI_HOST_GENERIC=y -CONFIG_PCI_XGENE=y CONFIG_PCIE_ALTERA=y CONFIG_PCIE_ALTERA_MSI=y +CONFIG_PCIE_BRCMSTB=m CONFIG_PCI_HOST_THUNDER_PEM=y CONFIG_PCI_HOST_THUNDER_ECAM=y -CONFIG_PCIE_ROCKCHIP_HOST=m +CONFIG_PCI_HOST_GENERIC=y CONFIG_PCIE_MEDIATEK_GEN3=m -CONFIG_PCIE_BRCMSTB=m +CONFIG_PCI_TEGRA=y +CONFIG_PCIE_RCAR_HOST=y +CONFIG_PCIE_RCAR_EP=y +CONFIG_PCIE_ROCKCHIP_HOST=m +CONFIG_PCI_XGENE=y +CONFIG_PCI_J721E_HOST=y +CONFIG_PCI_J721E_EP=y CONFIG_PCI_IMX6_HOST=y CONFIG_PCI_LAYERSCAPE=y CONFIG_PCI_HISI=y -CONFIG_PCIE_QCOM=y -CONFIG_PCIE_ARMADA_8K=y -CONFIG_PCIE_ROCKCHIP_DW_HOST=y CONFIG_PCIE_KIRIN=y CONFIG_PCIE_HISI_STB=y +CONFIG_PCIE_ARMADA_8K=y CONFIG_PCIE_TEGRA194_HOST=m +CONFIG_PCIE_DW_PLAT_HOST=y +CONFIG_PCIE_DW_PLAT_EP=y +CONFIG_PCIE_QCOM=y +CONFIG_PCIE_ROCKCHIP_DW_HOST=y +CONFIG_PCI_KEYSTONE_HOST=y +CONFIG_PCI_KEYSTONE_EP=y CONFIG_PCIE_VISCONTI_HOST=y CONFIG_PCIE_LAYERSCAPE_GEN4=y CONFIG_PCI_ENDPOINT=y @@ -247,7 +273,6 @@ CONFIG_HISILICON_LPC=y CONFIG_TEGRA_ACONNECT=m CONFIG_MHI_BUS_PCI_GENERIC=m -CONFIG_ARM_SCMI_PROTOCOL=y CONFIG_ARM_SCPI_PROTOCOL=y CONFIG_RASPBERRYPI_FIRMWARE=y CONFIG_INTEL_STRATIX10_SERVICE=y @@ -275,17 +300,15 @@ CONFIG_MTD_NAND_FSL_IFC=y CONFIG_MTD_NAND_QCOM=y CONFIG_MTD_SPI_NOR=y -CONFIG_MTD_UBI=m -CONFIG_UBIFS_FS=m +CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=m CONFIG_VIRTIO_BLK=y CONFIG_BLK_DEV_NVME=m CONFIG_QCOM_COINCELL=m CONFIG_QCOM_FASTRPC=m -CONFIG_BATTERY_QCOM_BATTMGR=m -CONFIG_UCSI_PMIC_GLINK=m CONFIG_SRAM=y +CONFIG_SRAM_DMA_HEAP=y CONFIG_PCI_ENDPOINT_TEST=m CONFIG_EEPROM_AT24=m CONFIG_EEPROM_AT25=m @@ -308,7 +331,6 @@ CONFIG_AHCI_QORIQ=y CONFIG_SATA_SIL24=y CONFIG_SATA_RCAR=y -CONFIG_PATA_PLATFORM=y CONFIG_PATA_OF_PLATFORM=y CONFIG_MD=y CONFIG_BLK_DEV_MD=m @@ -367,7 +389,9 @@ CONFIG_SNI_NETSEC=y CONFIG_STMMAC_ETH=m CONFIG_DWMAC_TEGRA=m +CONFIG_TI_CPSW_PROXY_CLIENT=m CONFIG_TI_K3_AM65_CPSW_NUSS=y +CONFIG_TI_ICSSG_PRUETH=m CONFIG_QCOM_IPA=m CONFIG_MESON_GXL_PHY=m CONFIG_AQUANTIA_PHY=y @@ -384,6 +408,8 @@ CONFIG_DP83TD510_PHY=y CONFIG_VITESSE_PHY=y CONFIG_CAN_FLEXCAN=m +CONFIG_CAN_M_CAN=m +CONFIG_CAN_M_CAN_PLATFORM=m CONFIG_CAN_RCAR=m CONFIG_CAN_RCAR_CANFD=m CONFIG_CAN_MCP251XFD=m @@ -413,10 +439,17 @@ CONFIG_MWIFIEX=m CONFIG_MWIFIEX_SDIO=m CONFIG_MWIFIEX_PCIE=m +CONFIG_IWLWIFI=m +CONFIG_IWLWIFI_LEDS=y +CONFIG_IWLDVM=m +CONFIG_IWLMVM=m +CONFIG_IWLWIFI_OPMODE_MODULAR=y CONFIG_MT7921E=m CONFIG_RSI_91X=m CONFIG_WL18XX=m CONFIG_WLCORE_SDIO=m +CONFIG_CC33XX=m +CONFIG_CC33XX_SDIO=m CONFIG_WWAN=m CONFIG_MHI_WWAN_CTRL=m CONFIG_MHI_WWAN_MBIM=m @@ -431,6 +464,7 @@ CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ATMEL_MXT=m CONFIG_TOUCHSCREEN_GOODIX=m +CONFIG_TOUCHSCREEN_ILI210X=m CONFIG_TOUCHSCREEN_ELAN=m CONFIG_TOUCHSCREEN_EDT_FT5X06=m CONFIG_INPUT_MISC=y @@ -447,6 +481,8 @@ CONFIG_LEGACY_PTY_COUNT=16 CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=12 +CONFIG_SERIAL_8250_RUNTIME_UARTS=12 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_8250_BCM2835AUX=y @@ -555,6 +591,7 @@ CONFIG_SPI_TEGRA210_QUAD=m CONFIG_SPI_TEGRA114=m CONFIG_SPI_SPIDEV=m +CONFIG_SPI_SLAVE=y CONFIG_SPMI=y CONFIG_SPMI_MTK_PMIF=m CONFIG_PINCTRL_MAX77620=y @@ -573,9 +610,9 @@ CONFIG_PINCTRL_IMX8ULP=y CONFIG_PINCTRL_IMX93=y CONFIG_PINCTRL_MSM=y -CONFIG_PINCTRL_IPQ8074=y CONFIG_PINCTRL_IPQ5018=y CONFIG_PINCTRL_IPQ5332=y +CONFIG_PINCTRL_IPQ8074=y CONFIG_PINCTRL_IPQ6018=y CONFIG_PINCTRL_IPQ9574=y CONFIG_PINCTRL_MSM8916=y @@ -587,12 +624,10 @@ CONFIG_PINCTRL_QCM2290=y CONFIG_PINCTRL_QCS404=y CONFIG_PINCTRL_QDF2XXX=y -CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_QDU1000=y CONFIG_PINCTRL_SA8775P=y CONFIG_PINCTRL_SC7180=y CONFIG_PINCTRL_SC7280=y -CONFIG_PINCTRL_SC7280_LPASS_LPI=m CONFIG_PINCTRL_SC8180X=y CONFIG_PINCTRL_SC8280XP=y CONFIG_PINCTRL_SDM660=y @@ -604,14 +639,16 @@ CONFIG_PINCTRL_SM6375=y CONFIG_PINCTRL_SM8150=y CONFIG_PINCTRL_SM8250=y -CONFIG_PINCTRL_SM8250_LPASS_LPI=m CONFIG_PINCTRL_SM8350=y CONFIG_PINCTRL_SM8450=y +CONFIG_PINCTRL_SM8550=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_LPASS_LPI=m +CONFIG_PINCTRL_SC7280_LPASS_LPI=m +CONFIG_PINCTRL_SM8250_LPASS_LPI=m CONFIG_PINCTRL_SM8450_LPASS_LPI=m CONFIG_PINCTRL_SC8280XP_LPASS_LPI=m -CONFIG_PINCTRL_SM8550=y CONFIG_PINCTRL_SM8550_LPASS_LPI=m -CONFIG_PINCTRL_LPASS_LPI=m CONFIG_GPIO_ALTERA=m CONFIG_GPIO_DAVINCI=y CONFIG_GPIO_DWAPB=y @@ -620,6 +657,7 @@ CONFIG_GPIO_MXC=y CONFIG_GPIO_PL061=y CONFIG_GPIO_RCAR=y +CONFIG_GPIO_SYSCON=y CONFIG_GPIO_UNIPHIER=y CONFIG_GPIO_VISCONTI=y CONFIG_GPIO_WCD934X=m @@ -631,7 +669,6 @@ CONFIG_GPIO_BD9571MWV=m CONFIG_GPIO_MAX77620=y CONFIG_GPIO_SL28CPLD=m -CONFIG_GPIO_SYSCON=y CONFIG_POWER_RESET_MSM=y CONFIG_POWER_RESET_QCOM_PON=m CONFIG_POWER_RESET_XGENE=y @@ -639,6 +676,7 @@ CONFIG_POWER_RESET_SYSCON_POWEROFF=y CONFIG_SYSCON_REBOOT_MODE=y CONFIG_NVMEM_REBOOT_MODE=m +CONFIG_BATTERY_QCOM_BATTMGR=m CONFIG_BATTERY_SBS=m CONFIG_BATTERY_BQ27XXX=y CONFIG_BATTERY_MAX17042=m @@ -663,8 +701,8 @@ CONFIG_THERMAL_EMULATION=y CONFIG_IMX_SC_THERMAL=m CONFIG_IMX8MM_THERMAL=m -CONFIG_QORIQ_THERMAL=m CONFIG_K3_THERMAL=m +CONFIG_QORIQ_THERMAL=m CONFIG_SUN8I_THERMAL=y CONFIG_ROCKCHIP_THERMAL=m CONFIG_RCAR_THERMAL=y @@ -689,6 +727,7 @@ CONFIG_ARM_SBSA_WATCHDOG=y CONFIG_S3C2410_WATCHDOG=y CONFIG_DW_WATCHDOG=y +CONFIG_K3_RTI_WATCHDOG=m CONFIG_SUNXI_WATCHDOG=m CONFIG_NPCM7XX_WATCHDOG=y CONFIG_IMX2_WDT=y @@ -704,7 +743,6 @@ CONFIG_PM8916_WATCHDOG=m CONFIG_BCM2835_WDT=y CONFIG_BCM7038_WDT=m -CONFIG_K3_RTI_WATCHDOG=m CONFIG_MFD_ALTERA_SYSMGR=y CONFIG_MFD_BD9571MWV=y CONFIG_MFD_AXP20X_I2C=y @@ -721,8 +759,9 @@ CONFIG_MFD_SEC_CORE=y CONFIG_MFD_SL28CPLD=y CONFIG_RZ_MTU3=y -CONFIG_MFD_TPS65219=y CONFIG_MFD_TI_AM335X_TSCADC=m +CONFIG_MFD_TPS65219=y +CONFIG_MFD_TPS6594_I2C=y CONFIG_MFD_ROHM_BD718XX=y CONFIG_MFD_WCD934X=m CONFIG_REGULATOR_FIXED_VOLTAGE=y @@ -751,6 +790,7 @@ CONFIG_REGULATOR_QCOM_SMD_RPM=y CONFIG_REGULATOR_QCOM_SPMI=y CONFIG_REGULATOR_RAA215300=y +CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY=m CONFIG_REGULATOR_RK808=y CONFIG_REGULATOR_S2MPS11=y CONFIG_REGULATOR_TPS65132=m @@ -774,6 +814,11 @@ CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_SDR_PLATFORM_DRIVERS=y CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_CADENCE_CSI2RX=m +CONFIG_VIDEO_WAVE_VPU=m +CONFIG_VIDEO_E5010_JPEG_ENC=m +CONFIG_VIDEO_IMG_VXD_DEC=n +CONFIG_VIDEO_IMG_VXE_ENC=m CONFIG_VIDEO_MEDIATEK_JPEG=m CONFIG_VIDEO_MEDIATEK_VCODEC=m CONFIG_VIDEO_IMX7_CSI=m @@ -795,11 +840,17 @@ CONFIG_VIDEO_SAMSUNG_S5P_JPEG=m CONFIG_VIDEO_SAMSUNG_S5P_MFC=m CONFIG_VIDEO_SUN6I_CSI=m +CONFIG_VIDEO_TI_J721E_CSI2RX=m CONFIG_VIDEO_HANTRO=m CONFIG_VIDEO_IMX219=m +CONFIG_VIDEO_IMX390=m CONFIG_VIDEO_IMX412=m +CONFIG_VIDEO_OV2312=m CONFIG_VIDEO_OV5640=m CONFIG_VIDEO_OV5645=m +CONFIG_VIDEO_OX05B1S=m +CONFIG_VIDEO_DS90UB953=m +CONFIG_VIDEO_DS90UB960=m CONFIG_DRM=m CONFIG_DRM_I2C_NXP_TDA998X=m CONFIG_DRM_HDLCD=m @@ -823,18 +874,15 @@ CONFIG_ROCKCHIP_LVDS=y CONFIG_DRM_RCAR_DU=m CONFIG_DRM_RCAR_DW_HDMI=m -CONFIG_DRM_RCAR_MIPI_DSI=m CONFIG_DRM_RZG2L_MIPI_DSI=m CONFIG_DRM_SUN4I=m -CONFIG_DRM_SUN6I_DSI=m -CONFIG_DRM_SUN8I_DW_HDMI=m -CONFIG_DRM_SUN8I_MIXER=m CONFIG_DRM_MSM=m CONFIG_DRM_TEGRA=m CONFIG_DRM_PANEL_BOE_TV101WUM_NL6=m CONFIG_DRM_PANEL_LVDS=m CONFIG_DRM_PANEL_SIMPLE=m CONFIG_DRM_PANEL_EDP=m +CONFIG_DRM_PANEL_ILITEK_ILI9881C=m CONFIG_DRM_PANEL_MANTIX_MLAF057WE51=m CONFIG_DRM_PANEL_RAYDIUM_RM67191=m CONFIG_DRM_PANEL_SITRONIX_ST7703=m @@ -849,6 +897,8 @@ CONFIG_DRM_SII902X=m CONFIG_DRM_SIMPLE_BRIDGE=m CONFIG_DRM_THINE_THC63LVD1024=m +CONFIG_DRM_TOSHIBA_TC358762=m +CONFIG_DRM_TOSHIBA_TC358767=m CONFIG_DRM_TOSHIBA_TC358768=m CONFIG_DRM_TI_TFP410=m CONFIG_DRM_TI_SN65DSI83=m @@ -856,6 +906,7 @@ CONFIG_DRM_ANALOGIX_ANX7625=m CONFIG_DRM_I2C_ADV7511=m CONFIG_DRM_I2C_ADV7511_AUDIO=y +CONFIG_DRM_CDNS_DSI=m CONFIG_DRM_CDNS_MHDP8546=m CONFIG_DRM_DW_HDMI_AHB_AUDIO=m CONFIG_DRM_DW_HDMI_CEC=m @@ -868,15 +919,15 @@ CONFIG_DRM_MEDIATEK=m CONFIG_DRM_MEDIATEK_HDMI=m CONFIG_DRM_MXSFB=m -CONFIG_DRM_MESON=m CONFIG_DRM_IMX_LCDIF=m +CONFIG_DRM_MESON=m CONFIG_DRM_PL111=m CONFIG_DRM_LIMA=m CONFIG_DRM_PANFROST=m CONFIG_DRM_TIDSS=m CONFIG_FB=y -CONFIG_FB_MODE_HELPERS=y CONFIG_FB_EFI=y +CONFIG_FB_MODE_HELPERS=y CONFIG_BACKLIGHT_PWM=m CONFIG_BACKLIGHT_LP855X=m CONFIG_LOGO=y @@ -887,6 +938,7 @@ CONFIG_SND_ALOOP=m CONFIG_SND_HDA_TEGRA=m CONFIG_SND_HDA_CODEC_HDMI=m +CONFIG_SND_USB_AUDIO=m CONFIG_SND_SOC=y CONFIG_SND_BCM2835_SOC_I2S=m CONFIG_SND_SOC_FSL_ASRC=m @@ -938,7 +990,7 @@ CONFIG_SND_SOC_TEGRA210_ADX=m CONFIG_SND_SOC_TEGRA210_MIXER=m CONFIG_SND_SOC_TEGRA_AUDIO_GRAPH_CARD=m -CONFIG_SND_SOC_DAVINCI_MCASP=m +CONFIG_SND_SOC_J721E_EVM=m CONFIG_SND_SOC_AK4613=m CONFIG_SND_SOC_DA7213=m CONFIG_SND_SOC_ES7134=m @@ -947,10 +999,8 @@ CONFIG_SND_SOC_GTM601=m CONFIG_SND_SOC_MSM8916_WCD_ANALOG=m CONFIG_SND_SOC_MSM8916_WCD_DIGITAL=m -CONFIG_SND_SOC_PCM3168A_I2C=m CONFIG_SND_SOC_RK817=m CONFIG_SND_SOC_RT5640=m -CONFIG_SND_SOC_J721E_EVM=m CONFIG_SND_SOC_RT5659=m CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m CONFIG_SND_SOC_SIMPLE_MUX=m @@ -969,8 +1019,6 @@ CONFIG_SND_SOC_NAU8822=m CONFIG_SND_SOC_LPASS_WSA_MACRO=m CONFIG_SND_SOC_LPASS_VA_MACRO=m -CONFIG_SND_SOC_LPASS_RX_MACRO=m -CONFIG_SND_SOC_LPASS_TX_MACRO=m CONFIG_SND_SIMPLE_CARD=m CONFIG_SND_AUDIO_GRAPH_CARD=m CONFIG_SND_AUDIO_GRAPH_CARD2=m @@ -1016,6 +1064,7 @@ CONFIG_USB_ONBOARD_HUB=m CONFIG_NOP_USB_XCEIV=y CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=32 CONFIG_USB_RENESAS_USBHS_UDC=m CONFIG_USB_RZV2M_USB3DRD=y CONFIG_USB_RENESAS_USB3=m @@ -1031,15 +1080,24 @@ CONFIG_USB_CONFIGFS_EEM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_G_NCM=m +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m +CONFIG_USB_CDC_COMPOSITE=m +CONFIG_USB_G_MULTI=m +CONFIG_USB_G_MULTI_CDC=y CONFIG_TYPEC=m CONFIG_TYPEC_TCPM=m CONFIG_TYPEC_TCPCI=m CONFIG_TYPEC_FUSB302=m +CONFIG_TYPEC_UCSI=m +CONFIG_UCSI_CCG=m +CONFIG_UCSI_PMIC_GLINK=m CONFIG_TYPEC_TPS6598X=m CONFIG_TYPEC_HD3SS3220=m -CONFIG_TYPEC_UCSI=m CONFIG_TYPEC_MUX_FSA4480=m -CONFIG_UCSI_CCG=m CONFIG_TYPEC_MUX_GPIO_SBU=m CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=32 @@ -1151,6 +1209,10 @@ CONFIG_RZ_DMAC=y CONFIG_TI_K3_UDMA=y CONFIG_TI_K3_UDMA_GLUE_LAYER=y +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_SYSTEM=y +CONFIG_DMABUF_HEAPS_CMA=y +CONFIG_DMABUF_HEAPS_CARVEOUT=y CONFIG_VFIO=y CONFIG_VFIO_PCI=y CONFIG_VIRTIO_PCI=y @@ -1168,7 +1230,6 @@ CONFIG_CROS_EC_SPI=y CONFIG_CROS_EC_CHARDEV=m CONFIG_COMMON_CLK_RK808=y -CONFIG_COMMON_CLK_SCMI=y CONFIG_COMMON_CLK_SCPI=y CONFIG_COMMON_CLK_CS2000_CP=y CONFIG_COMMON_CLK_FSL_SAI=y @@ -1186,18 +1247,6 @@ CONFIG_CLK_IMX8ULP=y CONFIG_CLK_IMX93=y CONFIG_TI_SCI_CLK=y -CONFIG_COMMON_CLK_MT8192_AUDSYS=y -CONFIG_COMMON_CLK_MT8192_CAMSYS=y -CONFIG_COMMON_CLK_MT8192_IMGSYS=y -CONFIG_COMMON_CLK_MT8192_IMP_IIC_WRAP=y -CONFIG_COMMON_CLK_MT8192_IPESYS=y -CONFIG_COMMON_CLK_MT8192_MDPSYS=y -CONFIG_COMMON_CLK_MT8192_MFGCFG=y -CONFIG_COMMON_CLK_MT8192_MMSYS=y -CONFIG_COMMON_CLK_MT8192_MSDC=y -CONFIG_COMMON_CLK_MT8192_SCP_ADSP=y -CONFIG_COMMON_CLK_MT8192_VDECSYS=y -CONFIG_COMMON_CLK_MT8192_VENCSYS=y CONFIG_COMMON_CLK_QCOM=y CONFIG_QCOM_A53PLL=y CONFIG_QCOM_CLK_APCS_MSM8916=y @@ -1205,24 +1254,23 @@ CONFIG_QCOM_CLK_SMD_RPM=y CONFIG_QCOM_CLK_RPMH=y CONFIG_IPQ_APSS_6018=y -CONFIG_IPQ_GCC_5332=y -CONFIG_IPQ_APSS_5018=y CONFIG_IPQ_GCC_5018=y +CONFIG_IPQ_GCC_5332=y CONFIG_IPQ_GCC_6018=y CONFIG_IPQ_GCC_8074=y CONFIG_IPQ_GCC_9574=y CONFIG_MSM_GCC_8916=y +CONFIG_MSM_MMCC_8994=m CONFIG_MSM_GCC_8994=y CONFIG_MSM_GCC_8996=y -CONFIG_MSM_MMCC_8994=m CONFIG_MSM_MMCC_8996=m -CONFIG_MSM_MMCC_8998=m CONFIG_MSM_GCC_8998=y +CONFIG_MSM_MMCC_8998=m CONFIG_QCM_GCC_2290=y CONFIG_QCM_DISPCC_2290=m CONFIG_QCS_GCC_404=y -CONFIG_SA_GCC_8775P=y CONFIG_SC_DISPCC_8280XP=m +CONFIG_SA_GCC_8775P=y CONFIG_SA_GPUCC_8775P=m CONFIG_SC_GCC_7180=y CONFIG_SC_GCC_7280=y @@ -1244,10 +1292,10 @@ CONFIG_SM_GCC_8350=y CONFIG_SM_GCC_8450=y CONFIG_SM_GCC_8550=y -CONFIG_SM_TCSRCC_8550=y CONFIG_SM_GPUCC_6115=m CONFIG_SM_GPUCC_8150=y CONFIG_SM_GPUCC_8250=y +CONFIG_SM_TCSRCC_8550=y CONFIG_SM_VIDEOCC_8250=y CONFIG_QCOM_HFPLL=y CONFIG_CLK_GFM_LPASS_SM8250=m @@ -1258,8 +1306,8 @@ CONFIG_RENESAS_OSTM=y CONFIG_ARM_MHU=y CONFIG_IMX_MBOX=y -CONFIG_OMAP2PLUS_MBOX=m CONFIG_PLATFORM_MHU=y +CONFIG_OMAP2PLUS_MBOX=y CONFIG_BCM2835_MBOX=y CONFIG_QCOM_APCS_IPC=y CONFIG_QCOM_IPCC=y @@ -1270,15 +1318,17 @@ CONFIG_MTK_IOMMU=y CONFIG_QCOM_IOMMU=y CONFIG_REMOTEPROC=y +CONFIG_REMOTEPROC_CDEV=y CONFIG_IMX_REMOTEPROC=y -CONFIG_TI_K3_R5_REMOTEPROC=m -CONFIG_TI_K3_DSP_REMOTEPROC=m CONFIG_MTK_SCP=m CONFIG_QCOM_Q6V5_ADSP=m CONFIG_QCOM_Q6V5_MSS=m CONFIG_QCOM_Q6V5_PAS=m CONFIG_QCOM_SYSMON=m CONFIG_QCOM_WCNSS_PIL=m +CONFIG_TI_K3_DSP_REMOTEPROC=m +CONFIG_TI_K3_M4_REMOTEPROC=m +CONFIG_TI_K3_R5_REMOTEPROC=m CONFIG_RPMSG_CHAR=m CONFIG_RPMSG_CTRL=m CONFIG_RPMSG_QCOM_GLINK_RPM=y @@ -1380,6 +1430,7 @@ CONFIG_PWM_MESON=m CONFIG_PWM_MTK_DISP=m CONFIG_PWM_MEDIATEK=m +CONFIG_PWM_OMAP_DMTIMER=m CONFIG_PWM_RCAR=m CONFIG_PWM_RENESAS_TPU=m CONFIG_PWM_ROCKCHIP=y @@ -1402,8 +1453,10 @@ CONFIG_PHY_XGENE=y CONFIG_PHY_CAN_TRANSCEIVER=m CONFIG_PHY_SUN4I_USB=y -CONFIG_PHY_CADENCE_TORRENT=m -CONFIG_PHY_CADENCE_SIERRA=m +CONFIG_PHY_CADENCE_TORRENT=y +CONFIG_PHY_CADENCE_DPHY=m +CONFIG_PHY_CADENCE_DPHY_RX=m +CONFIG_PHY_CADENCE_SIERRA=y CONFIG_PHY_MIXEL_MIPI_DPHY=m CONFIG_PHY_FSL_IMX8M_PCIE=y CONFIG_PHY_HI6220_USB=y @@ -1412,11 +1465,11 @@ CONFIG_PHY_MVEBU_CP110_COMPHY=y CONFIG_PHY_MTK_TPHY=y CONFIG_PHY_QCOM_EDP=m -CONFIG_PHY_QCOM_EUSB2_REPEATER=m CONFIG_PHY_QCOM_PCIE2=m CONFIG_PHY_QCOM_QMP=m CONFIG_PHY_QCOM_QUSB2=m CONFIG_PHY_QCOM_SNPS_EUSB2=m +CONFIG_PHY_QCOM_EUSB2_REPEATER=m CONFIG_PHY_QCOM_USB_HS=m CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=m CONFIG_PHY_QCOM_USB_HS_28NM=m @@ -1438,12 +1491,12 @@ CONFIG_PHY_UNIPHIER_USB2=y CONFIG_PHY_UNIPHIER_USB3=y CONFIG_PHY_TEGRA_XUSB=y -CONFIG_PHY_AM654_SERDES=m -CONFIG_PHY_J721E_WIZ=m +CONFIG_PHY_AM654_SERDES=y +CONFIG_PHY_J721E_WIZ=y +CONFIG_OMAP_USB2=m CONFIG_ARM_CCI_PMU=m CONFIG_ARM_CCN=m CONFIG_ARM_CMN=m -CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU=m CONFIG_ARM_SMMU_V3_PMU=m CONFIG_ARM_DSU_PMU=m CONFIG_FSL_IMX8_DDR_PMU=m @@ -1452,6 +1505,7 @@ CONFIG_ARM_SPE_PMU=m CONFIG_ARM_DMC620_PMU=m CONFIG_HISI_PMU=y +CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU=m CONFIG_NVMEM_LAYOUT_SL28_VPD=m CONFIG_NVMEM_IMX_OCOTP=y CONFIG_NVMEM_IMX_OCOTP_ELE=m @@ -1477,11 +1531,8 @@ CONFIG_TEE=y CONFIG_OPTEE=y CONFIG_MUX_GPIO=m -CONFIG_MUX_MMIO=y -CONFIG_SLIMBUS=m CONFIG_SLIM_QCOM_CTRL=m CONFIG_SLIM_QCOM_NGD_CTRL=m -CONFIG_INTERCONNECT=y CONFIG_INTERCONNECT_IMX=y CONFIG_INTERCONNECT_IMX8MM=m CONFIG_INTERCONNECT_IMX8MN=m @@ -1506,6 +1557,8 @@ CONFIG_INTERCONNECT_QCOM_SM8550=y CONFIG_COUNTER=m CONFIG_RZ_MTU3_CNT=m +CONFIG_TI_ECAP_CAPTURE=m +CONFIG_TI_EQEP=m CONFIG_HTE=y CONFIG_HTE_TEGRA194=y CONFIG_HTE_TEGRA194_TEST=m @@ -1524,8 +1577,10 @@ CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_HUGETLBFS=y -CONFIG_CONFIGFS_FS=y CONFIG_EFIVAR_FS=y +CONFIG_UBIFS_FS=y +CONFIG_MTD_HYPERBUS=m +CONFIG_HBMC_AM654=m CONFIG_SQUASHFS=y CONFIG_NFS_FS=y CONFIG_NFS_V4=y @@ -1541,6 +1596,7 @@ CONFIG_CRYPTO_ECHAINIV=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_CHACHA20_NEON=m CONFIG_CRYPTO_GHASH_ARM64_CE=y @@ -1564,6 +1620,7 @@ CONFIG_CRYPTO_DEV_HISI_HPRE=m CONFIG_CRYPTO_DEV_HISI_TRNG=m CONFIG_CRYPTO_DEV_SA2UL=m +CONFIG_CRYPTO_DEV_TI_MCRC64=m CONFIG_DMA_RESTRICTED_POOL=y CONFIG_CMA_SIZE_MBYTES=32 CONFIG_PRINTK_TIME=y @@ -1573,7 +1630,6 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y # CONFIG_SCHED_DEBUG is not set -# CONFIG_DEBUG_PREEMPT is not set # CONFIG_FTRACE is not set CONFIG_CORESIGHT=m CONFIG_CORESIGHT_LINK_AND_SINK_TMC=m @@ -1584,3 +1640,4 @@ CONFIG_CORESIGHT_CPU_DEBUG=m CONFIG_CORESIGHT_CTI=m CONFIG_MEMTEST=y +CONFIG_MTD_SPI_NAND=y diff -Naur --no-dereference a/crypto/crc64_iso3309_generic.c b/crypto/crc64_iso3309_generic.c --- a/crypto/crc64_iso3309_generic.c 1969-12-31 19:00:00.000000000 -0500 +++ b/crypto/crc64_iso3309_generic.c 2024-07-07 20:37:34.636306509 -0400 @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include + +static int chksum_cra_init(struct crypto_tfm *tfm) +{ + u64 *key = crypto_tfm_ctx(tfm); + + *key = 0; + return 0; +} + +static int chksum_init(struct shash_desc *desc) +{ + u64 *key = crypto_shash_ctx(desc->tfm); + u64 *crc = shash_desc_ctx(desc); + + *crc = *key; + return 0; +} + +static int chksum_update(struct shash_desc *desc, const u8 *data, + unsigned int length) +{ + u64 *crc = shash_desc_ctx(desc); + + *crc = crc64_iso3309_generic(*crc, data, length); + return 0; +} + +static int chksum_final(struct shash_desc *desc, u8 *out) +{ + u64 *crc = shash_desc_ctx(desc); + + put_unaligned_le64(*crc, out); + return 0; +} + +static int __chksum_finup(u64 crc, const u8 *data, unsigned int len, u8 *out) +{ + crc = crc64_iso3309_generic(crc, data, len); + + put_unaligned_le64(crc, out); + return 0; +} + +static int chksum_finup(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) +{ + u64 *crc = shash_desc_ctx(desc); + + return __chksum_finup(*crc, data, len, out); +} + +static int chksum_digest(struct shash_desc *desc, const u8 *data, + unsigned int length, u8 *out) +{ + u64 *key = crypto_shash_ctx(desc->tfm); + + return __chksum_finup(*key, data, length, out); +} + +/* + * Setting the seed allows arbitrary accumulators and flexible XOR policy + */ +static int chksum_setkey(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen) +{ + u64 *mctx = crypto_shash_ctx(tfm); + + if (keylen != sizeof(u64)) + return -EINVAL; + + *mctx = get_unaligned_le64(key); + return 0; +} + +static struct shash_alg alg = { + .digestsize = sizeof(u64), + .setkey = chksum_setkey, + .init = chksum_init, + .update = chksum_update, + .final = chksum_final, + .finup = chksum_finup, + .digest = chksum_digest, + .descsize = sizeof(u64), + .base = { + .cra_name = CRC64_ISO3309_STRING, + .cra_driver_name = "crc64-iso3309-generic", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(u64), + .cra_module = THIS_MODULE, + .cra_init = chksum_cra_init, + } +}; + +static int __init crc64_iso3309_init(void) +{ + return crypto_register_shash(&alg); +} + +static void __exit crc64_iso3309_exit(void) +{ + crypto_unregister_shash(&alg); +} + +module_init(crc64_iso3309_init); +module_exit(crc64_iso3309_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kamlesh Gurudasani "); +MODULE_DESCRIPTION("ISO3309 model CRC64 calculation"); +MODULE_ALIAS_CRYPTO("crc64-iso3309"); +MODULE_ALIAS_CRYPTO("crc64-iso3309-generic"); diff -Naur --no-dereference a/crypto/Kconfig b/crypto/Kconfig --- a/crypto/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/crypto/Kconfig 2024-07-07 20:37:34.636306509 -0400 @@ -1146,6 +1146,17 @@ CRC algorithm used by the SCSI Block Commands standard. +config CRYPTO_CRC64_ISO3309 + tristate "CRC64 based on ISO 3309 Model algorithm" + depends on CRC64 + select CRYPTO_HASH + help + CRC64 CRC algorithm based on the ISO 3309 Model CRC Algorithm + + Generator polynomial: x^64 + x^4 + x^3 + x + 1 + Polynomial value: 0x000000000000001b + See https://en.wikipedia.org/wiki/Cyclic_redundancy_check + config CRYPTO_CRC64_ROCKSOFT tristate "CRC64 based on Rocksoft Model algorithm" depends on CRC64 diff -Naur --no-dereference a/crypto/Makefile b/crypto/Makefile --- a/crypto/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/crypto/Makefile 2024-07-07 20:37:34.636306509 -0400 @@ -157,6 +157,7 @@ obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o obj-$(CONFIG_CRYPTO_CRC32) += crc32_generic.o obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o +obj-$(CONFIG_CRYPTO_CRC64_ISO3309) += crc64_iso3309_generic.o obj-$(CONFIG_CRYPTO_CRC64_ROCKSOFT) += crc64_rocksoft_generic.o obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o obj-$(CONFIG_CRYPTO_LZO) += lzo.o lzo-rle.o diff -Naur --no-dereference a/crypto/tcrypt.c b/crypto/tcrypt.c --- a/crypto/tcrypt.c 2024-05-25 10:22:56.000000000 -0400 +++ b/crypto/tcrypt.c 2024-07-07 20:37:34.636306509 -0400 @@ -2327,6 +2327,12 @@ generic_hash_speed_template); if (mode > 300 && mode < 400) break; fallthrough; + case 329: + test_hash_speed("crc64-iso3309", sec, + generic_hash_speed_template); + if (mode > 300 && mode < 400) + break; + fallthrough; case 399: break; diff -Naur --no-dereference a/crypto/testmgr.c b/crypto/testmgr.c --- a/crypto/testmgr.c 2024-05-25 10:22:56.000000000 -0400 +++ b/crypto/testmgr.c 2024-07-07 20:37:34.636306509 -0400 @@ -4680,6 +4680,13 @@ .hash = __VECS(crc32c_tv_template) } }, { + .alg = "crc64-iso3309", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { + .hash = __VECS(crc64_iso3309_tv_template) + } + }, { .alg = "crc64-rocksoft", .test = alg_test_hash, .fips_allowed = 1, diff -Naur --no-dereference a/crypto/testmgr.h b/crypto/testmgr.h --- a/crypto/testmgr.h 2024-05-25 10:22:56.000000000 -0400 +++ b/crypto/testmgr.h 2024-07-07 20:37:34.636306509 -0400 @@ -5209,6 +5209,410 @@ } }; +static const struct hash_testvec crc64_iso3309_tv_template[] = { + { + .psize = 0, + .digest = "\x00\x00\x00\x00\x00\x00\x00\x00", + }, + { + .plaintext = "\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18" + "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" + "\x21\x22\x23\x24\x25\x26\x27\x28", + .psize = 40, + .digest = "\xaf\x45\xba\x7d\xf2\xda\xa0\xaa", + }, + { + .plaintext = "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30" + "\x31\x32\x33\x34\x35\x36\x37\x38" + "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40" + "\x41\x42\x43\x44\x45\x46\x47\x48" + "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50", + .psize = 40, + .digest = "\x81\x55\x2e\x76\xf8\xd0\xaa\xa0", + }, + { + .plaintext = "\x51\x52\x53\x54\x55\x56\x57\x58" + "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60" + "\x61\x62\x63\x64\x65\x66\x67\x68" + "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70" + "\x71\x72\x73\x74\x75\x76\x77\x78", + .psize = 40, + .digest = "\xc6\xb6\x26\x82\x0d\x25\x5f\x55", + }, + { + .plaintext = "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80" + "\x81\x82\x83\x84\x85\x86\x87\x88" + "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90" + "\x91\x92\x93\x94\x95\x96\x97\x98" + "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0", + .psize = 40, + .digest = "\x20\x8a\xe6\x59\xdf\xf7\x8d\x87", + }, + { + .plaintext = "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8" + "\xa9\xaa\xab\xac\xad\xae\xaf\xb0" + "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8" + "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0" + "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8", + .psize = 40, + .digest = "\x19\x9e\xba\xff\x70\x58\x22\x28", + + }, + { + .plaintext = "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0" + "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8" + "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0" + "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8" + "\xe9\xea\xeb\xec\xed\xee\xef\xf0", + .psize = 40, + .digest = "\xa3\xdc\x11\x98\x16\x3e\x44\x4e", + }, + { + .plaintext = "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30" + "\x31\x32\x33\x34\x35\x36\x37\x38" + "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40" + "\x41\x42\x43\x44\x45\x46\x47\x48" + "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50", + .psize = 40, + .digest = "\x81\x55\x2e\x76\xf8\xd0\xaa\xa0", + }, + { + .plaintext = "\x51\x52\x53\x54\x55\x56\x57\x58" + "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60" + "\x61\x62\x63\x64\x65\x66\x67\x68" + "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70" + "\x71\x72\x73\x74\x75\x76\x77\x78", + .psize = 40, + .digest = "\xc6\xb6\x26\x82\x0d\x25\x5f\x55", + }, + { + .plaintext = "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80" + "\x81\x82\x83\x84\x85\x86\x87\x88" + "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90" + "\x91\x92\x93\x94\x95\x96\x97\x98" + "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0", + .psize = 40, + .digest = "\x20\x8a\xe6\x59\xdf\xf7\x8d\x87", + }, + { + .plaintext = "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8" + "\xa9\xaa\xab\xac\xad\xae\xaf\xb0" + "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8" + "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0" + "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8", + .psize = 40, + .digest = "\x19\x9e\xba\xff\x70\x58\x22\x28", + }, + { + .plaintext = "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0" + "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8" + "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0" + "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8" + "\xe9\xea\xeb\xec\xed\xee\xef\xf0", + .psize = 40, + .digest = "\xa3\xdc\x11\x98\x16\x3e\x44\x4e", + }, + { + .key = "\xff\xff\xff\xff\xff\xff\xff\xff", + .ksize = 8, + .plaintext = "\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18" + "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" + "\x21\x22\x23\x24\x25\x26\x27\x28" + "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30" + "\x31\x32\x33\x34\x35\x36\x37\x38" + "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40" + "\x41\x42\x43\x44\x45\x46\x47\x48" + "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50" + "\x51\x52\x53\x54\x55\x56\x57\x58" + "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60" + "\x61\x62\x63\x64\x65\x66\x67\x68" + "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70" + "\x71\x72\x73\x74\x75\x76\x77\x78" + "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80" + "\x81\x82\x83\x84\x85\x86\x87\x88" + "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90" + "\x91\x92\x93\x94\x95\x96\x97\x98" + "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0" + "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8" + "\xa9\xaa\xab\xac\xad\xae\xaf\xb0" + "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8" + "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0" + "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8" + "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0" + "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8" + "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0" + "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8" + "\xe9\xea\xeb\xec\xed\xee\xef\xf0", + .psize = 240, + .digest = "\x8b\xa6\xd7\x91\xb4\x74\x96\x84", + }, { + .key = "\xff\xff\xff\xff\xff\xff\xff\xff", + .ksize = 8, + .plaintext = "\x6e\x05\x79\x10\xa7\x1b\xb2\x49" + "\xe0\x54\xeb\x82\x19\x8d\x24\xbb" + "\x2f\xc6\x5d\xf4\x68\xff\x96\x0a" + "\xa1\x38\xcf\x43\xda\x71\x08\x7c" + "\x13\xaa\x1e\xb5\x4c\xe3\x57\xee" + "\x85\x1c\x90\x27\xbe\x32\xc9\x60" + "\xf7\x6b\x02\x99\x0d\xa4\x3b\xd2" + "\x46\xdd\x74\x0b\x7f\x16\xad\x21" + "\xb8\x4f\xe6\x5a\xf1\x88\x1f\x93" + "\x2a\xc1\x35\xcc\x63\xfa\x6e\x05" + "\x9c\x10\xa7\x3e\xd5\x49\xe0\x77" + "\x0e\x82\x19\xb0\x24\xbb\x52\xe9" + "\x5d\xf4\x8b\x22\x96\x2d\xc4\x38" + "\xcf\x66\xfd\x71\x08\x9f\x13\xaa" + "\x41\xd8\x4c\xe3\x7a\x11\x85\x1c" + "\xb3\x27\xbe\x55\xec\x60\xf7\x8e" + "\x02\x99\x30\xc7\x3b\xd2\x69\x00" + "\x74\x0b\xa2\x16\xad\x44\xdb\x4f" + "\xe6\x7d\x14\x88\x1f\xb6\x2a\xc1" + "\x58\xef\x63\xfa\x91\x05\x9c\x33" + "\xca\x3e\xd5\x6c\x03\x77\x0e\xa5" + "\x19\xb0\x47\xde\x52\xe9\x80\x17" + "\x8b\x22\xb9\x2d\xc4\x5b\xf2\x66" + "\xfd\x94\x08\x9f\x36\xcd\x41\xd8" + "\x6f\x06\x7a\x11\xa8\x1c\xb3\x4a" + "\xe1\x55\xec\x83\x1a\x8e\x25\xbc" + "\x30\xc7\x5e\xf5\x69\x00\x97\x0b" + "\xa2\x39\xd0\x44\xdb\x72\x09\x7d" + "\x14\xab\x1f\xb6\x4d\xe4\x58\xef" + "\x86\x1d\x91\x28\xbf\x33\xca\x61" + "\xf8\x6c\x03\x9a\x0e\xa5\x3c\xd3" + "\x47\xde\x75\x0c\x80\x17\xae\x22" + "\xb9\x50\xe7\x5b\xf2\x89\x20\x94" + "\x2b\xc2\x36\xcd\x64\xfb\x6f\x06" + "\x9d\x11\xa8\x3f\xd6\x4a\xe1\x78" + "\x0f\x83\x1a\xb1\x25\xbc\x53\xea" + "\x5e\xf5\x8c\x00\x97\x2e\xc5\x39" + "\xd0\x67\xfe\x72\x09\xa0\x14\xab" + "\x42\xd9\x4d\xe4\x7b\x12\x86\x1d" + "\xb4\x28\xbf\x56\xed\x61\xf8\x8f" + "\x03\x9a\x31\xc8\x3c\xd3\x6a\x01" + "\x75\x0c\xa3\x17\xae\x45\xdc\x50" + "\xe7\x7e\x15\x89\x20\xb7\x2b\xc2" + "\x59\xf0\x64\xfb\x92\x06\x9d\x34" + "\xcb\x3f\xd6\x6d\x04\x78\x0f\xa6" + "\x1a\xb1\x48\xdf\x53\xea\x81\x18" + "\x8c\x23\xba\x2e\xc5\x5c\xf3\x67" + "\xfe\x95\x09\xa0\x37\xce\x42\xd9" + "\x70\x07\x7b\x12\xa9\x1d\xb4\x4b" + "\xe2\x56\xed\x84\x1b\x8f\x26\xbd" + "\x31\xc8\x5f\xf6\x6a\x01\x98\x0c" + "\xa3\x3a\xd1\x45\xdc\x73\x0a\x7e" + "\x15\xac\x20\xb7\x4e\xe5\x59\xf0" + "\x87\x1e\x92\x29\xc0\x34\xcb\x62" + "\xf9\x6d\x04\x9b\x0f\xa6\x3d\xd4" + "\x48\xdf\x76\x0d\x81\x18\xaf\x23" + "\xba\x51\xe8\x5c\xf3\x8a\x21\x95" + "\x2c\xc3\x37\xce\x65\xfc\x70\x07" + "\x9e\x12\xa9\x40\xd7\x4b\xe2\x79" + "\x10\x84\x1b\xb2\x26\xbd\x54\xeb" + "\x5f\xf6\x8d\x01\x98\x2f\xc6\x3a" + "\xd1\x68\xff\x73\x0a\xa1\x15\xac" + "\x43\xda\x4e\xe5\x7c\x13\x87\x1e" + "\xb5\x29\xc0\x57\xee\x62\xf9\x90" + "\x04\x9b\x32\xc9\x3d\xd4\x6b\x02" + "\x76\x0d\xa4\x18\xaf\x46\xdd\x51" + "\xe8\x7f\x16\x8a\x21\xb8\x2c\xc3" + "\x5a\xf1\x65\xfc\x93\x07\x9e\x35" + "\xcc\x40\xd7\x6e\x05\x79\x10\xa7" + "\x1b\xb2\x49\xe0\x54\xeb\x82\x19" + "\x8d\x24\xbb\x2f\xc6\x5d\xf4\x68" + "\xff\x96\x0a\xa1\x38\xcf\x43\xda" + "\x71\x08\x7c\x13\xaa\x1e\xb5\x4c" + "\xe3\x57\xee\x85\x1c\x90\x27\xbe" + "\x32\xc9\x60\xf7\x6b\x02\x99\x0d" + "\xa4\x3b\xd2\x46\xdd\x74\x0b\x7f" + "\x16\xad\x21\xb8\x4f\xe6\x5a\xf1" + "\x88\x1f\x93\x2a\xc1\x35\xcc\x63" + "\xfa\x6e\x05\x9c\x10\xa7\x3e\xd5" + "\x49\xe0\x77\x0e\x82\x19\xb0\x24" + "\xbb\x52\xe9\x5d\xf4\x8b\x22\x96" + "\x2d\xc4\x38\xcf\x66\xfd\x71\x08" + "\x9f\x13\xaa\x41\xd8\x4c\xe3\x7a" + "\x11\x85\x1c\xb3\x27\xbe\x55\xec" + "\x60\xf7\x8e\x02\x99\x30\xc7\x3b" + "\xd2\x69\x00\x74\x0b\xa2\x16\xad" + "\x44\xdb\x4f\xe6\x7d\x14\x88\x1f" + "\xb6\x2a\xc1\x58\xef\x63\xfa\x91" + "\x05\x9c\x33\xca\x3e\xd5\x6c\x03" + "\x77\x0e\xa5\x19\xb0\x47\xde\x52" + "\xe9\x80\x17\x8b\x22\xb9\x2d\xc4" + "\x5b\xf2\x66\xfd\x94\x08\x9f\x36" + "\xcd\x41\xd8\x6f\x06\x7a\x11\xa8" + "\x1c\xb3\x4a\xe1\x55\xec\x83\x1a" + "\x8e\x25\xbc\x30\xc7\x5e\xf5\x69" + "\x00\x97\x0b\xa2\x39\xd0\x44\xdb" + "\x72\x09\x7d\x14\xab\x1f\xb6\x4d" + "\xe4\x58\xef\x86\x1d\x91\x28\xbf" + "\x33\xca\x61\xf8\x6c\x03\x9a\x0e" + "\xa5\x3c\xd3\x47\xde\x75\x0c\x80" + "\x17\xae\x22\xb9\x50\xe7\x5b\xf2" + "\x89\x20\x94\x2b\xc2\x36\xcd\x64" + "\xfb\x6f\x06\x9d\x11\xa8\x3f\xd6" + "\x4a\xe1\x78\x0f\x83\x1a\xb1\x25" + "\xbc\x53\xea\x5e\xf5\x8c\x00\x97" + "\x2e\xc5\x39\xd0\x67\xfe\x72\x09" + "\xa0\x14\xab\x42\xd9\x4d\xe4\x7b" + "\x12\x86\x1d\xb4\x28\xbf\x56\xed" + "\x61\xf8\x8f\x03\x9a\x31\xc8\x3c" + "\xd3\x6a\x01\x75\x0c\xa3\x17\xae" + "\x45\xdc\x50\xe7\x7e\x15\x89\x20" + "\xb7\x2b\xc2\x59\xf0\x64\xfb\x92" + "\x06\x9d\x34\xcb\x3f\xd6\x6d\x04" + "\x78\x0f\xa6\x1a\xb1\x48\xdf\x53" + "\xea\x81\x18\x8c\x23\xba\x2e\xc5" + "\x5c\xf3\x67\xfe\x95\x09\xa0\x37" + "\xce\x42\xd9\x70\x07\x7b\x12\xa9" + "\x1d\xb4\x4b\xe2\x56\xed\x84\x1b" + "\x8f\x26\xbd\x31\xc8\x5f\xf6\x6a" + "\x01\x98\x0c\xa3\x3a\xd1\x45\xdc" + "\x73\x0a\x7e\x15\xac\x20\xb7\x4e" + "\xe5\x59\xf0\x87\x1e\x92\x29\xc0" + "\x34\xcb\x62\xf9\x6d\x04\x9b\x0f" + "\xa6\x3d\xd4\x48\xdf\x76\x0d\x81" + "\x18\xaf\x23\xba\x51\xe8\x5c\xf3" + "\x8a\x21\x95\x2c\xc3\x37\xce\x65" + "\xfc\x70\x07\x9e\x12\xa9\x40\xd7" + "\x4b\xe2\x79\x10\x84\x1b\xb2\x26" + "\xbd\x54\xeb\x5f\xf6\x8d\x01\x98" + "\x2f\xc6\x3a\xd1\x68\xff\x73\x0a" + "\xa1\x15\xac\x43\xda\x4e\xe5\x7c" + "\x13\x87\x1e\xb5\x29\xc0\x57\xee" + "\x62\xf9\x90\x04\x9b\x32\xc9\x3d" + "\xd4\x6b\x02\x76\x0d\xa4\x18\xaf" + "\x46\xdd\x51\xe8\x7f\x16\x8a\x21" + "\xb8\x2c\xc3\x5a\xf1\x65\xfc\x93" + "\x07\x9e\x35\xcc\x40\xd7\x6e\x05" + "\x79\x10\xa7\x1b\xb2\x49\xe0\x54" + "\xeb\x82\x19\x8d\x24\xbb\x2f\xc6" + "\x5d\xf4\x68\xff\x96\x0a\xa1\x38" + "\xcf\x43\xda\x71\x08\x7c\x13\xaa" + "\x1e\xb5\x4c\xe3\x57\xee\x85\x1c" + "\x90\x27\xbe\x32\xc9\x60\xf7\x6b" + "\x02\x99\x0d\xa4\x3b\xd2\x46\xdd" + "\x74\x0b\x7f\x16\xad\x21\xb8\x4f" + "\xe6\x5a\xf1\x88\x1f\x93\x2a\xc1" + "\x35\xcc\x63\xfa\x6e\x05\x9c\x10" + "\xa7\x3e\xd5\x49\xe0\x77\x0e\x82" + "\x19\xb0\x24\xbb\x52\xe9\x5d\xf4" + "\x8b\x22\x96\x2d\xc4\x38\xcf\x66" + "\xfd\x71\x08\x9f\x13\xaa\x41\xd8" + "\x4c\xe3\x7a\x11\x85\x1c\xb3\x27" + "\xbe\x55\xec\x60\xf7\x8e\x02\x99" + "\x30\xc7\x3b\xd2\x69\x00\x74\x0b" + "\xa2\x16\xad\x44\xdb\x4f\xe6\x7d" + "\x14\x88\x1f\xb6\x2a\xc1\x58\xef" + "\x63\xfa\x91\x05\x9c\x33\xca\x3e" + "\xd5\x6c\x03\x77\x0e\xa5\x19\xb0" + "\x47\xde\x52\xe9\x80\x17\x8b\x22" + "\xb9\x2d\xc4\x5b\xf2\x66\xfd\x94" + "\x08\x9f\x36\xcd\x41\xd8\x6f\x06" + "\x7a\x11\xa8\x1c\xb3\x4a\xe1\x55" + "\xec\x83\x1a\x8e\x25\xbc\x30\xc7" + "\x5e\xf5\x69\x00\x97\x0b\xa2\x39" + "\xd0\x44\xdb\x72\x09\x7d\x14\xab" + "\x1f\xb6\x4d\xe4\x58\xef\x86\x1d" + "\x91\x28\xbf\x33\xca\x61\xf8\x6c" + "\x03\x9a\x0e\xa5\x3c\xd3\x47\xde" + "\x75\x0c\x80\x17\xae\x22\xb9\x50" + "\xe7\x5b\xf2\x89\x20\x94\x2b\xc2" + "\x36\xcd\x64\xfb\x6f\x06\x9d\x11" + "\xa8\x3f\xd6\x4a\xe1\x78\x0f\x83" + "\x1a\xb1\x25\xbc\x53\xea\x5e\xf5" + "\x8c\x00\x97\x2e\xc5\x39\xd0\x67" + "\xfe\x72\x09\xa0\x14\xab\x42\xd9" + "\x4d\xe4\x7b\x12\x86\x1d\xb4\x28" + "\xbf\x56\xed\x61\xf8\x8f\x03\x9a" + "\x31\xc8\x3c\xd3\x6a\x01\x75\x0c" + "\xa3\x17\xae\x45\xdc\x50\xe7\x7e" + "\x15\x89\x20\xb7\x2b\xc2\x59\xf0" + "\x64\xfb\x92\x06\x9d\x34\xcb\x3f" + "\xd6\x6d\x04\x78\x0f\xa6\x1a\xb1" + "\x48\xdf\x53\xea\x81\x18\x8c\x23" + "\xba\x2e\xc5\x5c\xf3\x67\xfe\x95" + "\x09\xa0\x37\xce\x42\xd9\x70\x07" + "\x7b\x12\xa9\x1d\xb4\x4b\xe2\x56" + "\xed\x84\x1b\x8f\x26\xbd\x31\xc8" + "\x5f\xf6\x6a\x01\x98\x0c\xa3\x3a" + "\xd1\x45\xdc\x73\x0a\x7e\x15\xac" + "\x20\xb7\x4e\xe5\x59\xf0\x87\x1e" + "\x92\x29\xc0\x34\xcb\x62\xf9\x6d" + "\x04\x9b\x0f\xa6\x3d\xd4\x48\xdf" + "\x76\x0d\x81\x18\xaf\x23\xba\x51" + "\xe8\x5c\xf3\x8a\x21\x95\x2c\xc3" + "\x37\xce\x65\xfc\x70\x07\x9e\x12" + "\xa9\x40\xd7\x4b\xe2\x79\x10\x84" + "\x1b\xb2\x26\xbd\x54\xeb\x5f\xf6" + "\x8d\x01\x98\x2f\xc6\x3a\xd1\x68" + "\xff\x73\x0a\xa1\x15\xac\x43\xda" + "\x4e\xe5\x7c\x13\x87\x1e\xb5\x29" + "\xc0\x57\xee\x62\xf9\x90\x04\x9b" + "\x32\xc9\x3d\xd4\x6b\x02\x76\x0d" + "\xa4\x18\xaf\x46\xdd\x51\xe8\x7f" + "\x16\x8a\x21\xb8\x2c\xc3\x5a\xf1" + "\x65\xfc\x93\x07\x9e\x35\xcc\x40" + "\xd7\x6e\x05\x79\x10\xa7\x1b\xb2" + "\x49\xe0\x54\xeb\x82\x19\x8d\x24" + "\xbb\x2f\xc6\x5d\xf4\x68\xff\x96" + "\x0a\xa1\x38\xcf\x43\xda\x71\x08" + "\x7c\x13\xaa\x1e\xb5\x4c\xe3\x57" + "\xee\x85\x1c\x90\x27\xbe\x32\xc9" + "\x60\xf7\x6b\x02\x99\x0d\xa4\x3b" + "\xd2\x46\xdd\x74\x0b\x7f\x16\xad" + "\x21\xb8\x4f\xe6\x5a\xf1\x88\x1f" + "\x93\x2a\xc1\x35\xcc\x63\xfa\x6e" + "\x05\x9c\x10\xa7\x3e\xd5\x49\xe0" + "\x77\x0e\x82\x19\xb0\x24\xbb\x52" + "\xe9\x5d\xf4\x8b\x22\x96\x2d\xc4" + "\x38\xcf\x66\xfd\x71\x08\x9f\x13" + "\xaa\x41\xd8\x4c\xe3\x7a\x11\x85" + "\x1c\xb3\x27\xbe\x55\xec\x60\xf7" + "\x8e\x02\x99\x30\xc7\x3b\xd2\x69" + "\x00\x74\x0b\xa2\x16\xad\x44\xdb" + "\x4f\xe6\x7d\x14\x88\x1f\xb6\x2a" + "\xc1\x58\xef\x63\xfa\x91\x05\x9c" + "\x33\xca\x3e\xd5\x6c\x03\x77\x0e" + "\xa5\x19\xb0\x47\xde\x52\xe9\x80" + "\x17\x8b\x22\xb9\x2d\xc4\x5b\xf2" + "\x66\xfd\x94\x08\x9f\x36\xcd\x41" + "\xd8\x6f\x06\x7a\x11\xa8\x1c\xb3" + "\x4a\xe1\x55\xec\x83\x1a\x8e\x25" + "\xbc\x30\xc7\x5e\xf5\x69\x00\x97" + "\x0b\xa2\x39\xd0\x44\xdb\x72\x09" + "\x7d\x14\xab\x1f\xb6\x4d\xe4\x58" + "\xef\x86\x1d\x91\x28\xbf\x33\xca" + "\x61\xf8\x6c\x03\x9a\x0e\xa5\x3c" + "\xd3\x47\xde\x75\x0c\x80\x17\xae" + "\x22\xb9\x50\xe7\x5b\xf2\x89\x20" + "\x94\x2b\xc2\x36\xcd\x64\xfb\x6f" + "\x06\x9d\x11\xa8\x3f\xd6\x4a\xe1" + "\x78\x0f\x83\x1a\xb1\x25\xbc\x53" + "\xea\x5e\xf5\x8c\x00\x97\x2e\xc5" + "\x39\xd0\x67\xfe\x72\x09\xa0\x14" + "\xab\x42\xd9\x4d\xe4\x7b\x12\x86" + "\x1d\xb4\x28\xbf\x56\xed\x61\xf8" + "\x8f\x03\x9a\x31\xc8\x3c\xd3\x6a" + "\x01\x75\x0c\xa3\x17\xae\x45\xdc" + "\x50\xe7\x7e\x15\x89\x20\xb7\x2b" + "\xc2\x59\xf0\x64\xfb\x92\x06\x9d" + "\x34\xcb\x3f\xd6\x6d\x04\x78\x0f" + "\xa6\x1a\xb1\x48\xdf\x53\xea\x81" + "\x18\x8c\x23\xba\x2e\xc5\x5c\xf3" + "\x67\xfe\x95\x09\xa0\x37\xce\x42" + "\xd9\x70\x07\x7b\x12\xa9\x1d\xb4" + "\x4b\xe2\x56\xed\x84\x1b\x8f\x26" + "\xbd\x31\xc8\x5f\xf6\x6a\x01\x98", + .psize = 2048, + .digest = "\x4b\x82\xa5\x0e\x72\x01\x0b\xc6", + } +}; + static const u8 zeroes[4096] = { [0 ... 4095] = 0 }; static const u8 ones[4096] = { [0 ... 4095] = 0xff }; diff -Naur --no-dereference a/Documentation/core-api/kernel-api.rst b/Documentation/core-api/kernel-api.rst --- a/Documentation/core-api/kernel-api.rst 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/core-api/kernel-api.rst 2024-07-07 20:37:34.612306389 -0400 @@ -185,6 +185,12 @@ .. kernel-doc:: lib/math/gcd.c :export: +Rounding, absolute value, division and 32-bit scaling functions +--------------------------------------------------------------- + +.. kernel-doc:: include/linux/math.h + :internal: + UUID/GUID --------- diff -Naur --no-dereference a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml --- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml 2024-07-07 20:37:34.612306389 -0400 @@ -61,9 +61,11 @@ mboxes: minItems: 2 - ti,system-reboot-controller: - description: Determines If system reboot can be triggered by SoC reboot - type: boolean + ti,partial-io-wakeup-sources: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: | + List of phandles to devicetree nodes that can wakeup the SoC from the + Partial IO poweroff mode. ti,host-id: $ref: /schemas/types.yaml#/definitions/uint32 @@ -94,7 +96,6 @@ - | pmmc: system-controller@2921800 { compatible = "ti,k2g-sci"; - ti,system-reboot-controller; mbox-names = "rx", "tx"; mboxes = <&msgmgr 5 2>, <&msgmgr 0 0>; diff -Naur --no-dereference a/Documentation/devicetree/bindings/arm/ti/k3.yaml b/Documentation/devicetree/bindings/arm/ti/k3.yaml --- a/Documentation/devicetree/bindings/arm/ti/k3.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/arm/ti/k3.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -50,6 +50,7 @@ - enum: - toradex,verdin-am62-nonwifi-dahlia # Verdin AM62 Module on Dahlia - toradex,verdin-am62-nonwifi-dev # Verdin AM62 Module on Verdin Development Board + - toradex,verdin-am62-nonwifi-mallow # Verdin AM62 Module on Mallow - toradex,verdin-am62-nonwifi-yavia # Verdin AM62 Module on Yavia - const: toradex,verdin-am62-nonwifi # Verdin AM62 Module without Wi-Fi / BT - const: toradex,verdin-am62 # Verdin AM62 Module @@ -60,6 +61,7 @@ - enum: - toradex,verdin-am62-wifi-dahlia # Verdin AM62 Wi-Fi / BT Module on Dahlia - toradex,verdin-am62-wifi-dev # Verdin AM62 Wi-Fi / BT M. on Verdin Development B. + - toradex,verdin-am62-wifi-mallow # Verdin AM62 Wi-Fi / BT Module on Mallow - toradex,verdin-am62-wifi-yavia # Verdin AM62 Wi-Fi / BT Module on Yavia - const: toradex,verdin-am62-wifi # Verdin AM62 Wi-Fi / BT Module - const: toradex,verdin-am62 # Verdin AM62 Module @@ -121,6 +123,12 @@ - ti,j721s2-evm - const: ti,j721s2 + - description: K3 J722S SoC and Boards + items: + - enum: + - ti,j722s-evm + - const: ti,j722s + - description: K3 J784s4 SoC items: - enum: diff -Naur --no-dereference a/Documentation/devicetree/bindings/counter/ti-eqep.yaml b/Documentation/devicetree/bindings/counter/ti-eqep.yaml --- a/Documentation/devicetree/bindings/counter/ti-eqep.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/counter/ti-eqep.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -11,7 +11,9 @@ properties: compatible: - const: ti,am3352-eqep + enum: + - ti,am3352-eqep + - ti,am62-eqep reg: maxItems: 1 @@ -21,19 +23,35 @@ maxItems: 1 clocks: - description: The clock that determines the SYSCLKOUT rate for the eQEP - peripheral. + description: The functional and interface clock that determines the clock + rate for the eQEP peripheral. maxItems: 1 clock-names: const: sysclkout + power-domains: + maxItems: 1 + +allOf: + - if: + properties: + compatible: + contains: + enum: + - ti,am62-eqep + then: + properties: + clock-names: false + + required: + - power-domains + required: - compatible - reg - interrupts - clocks - - clock-names additionalProperties: false @@ -43,8 +61,24 @@ compatible = "ti,am3352-eqep"; reg = <0x180 0x80>; clocks = <&l4ls_gclk>; - clock-names = "sysclkout"; interrupts = <79>; }; + - | + #include + #include + #include + + bus { + #address-cells = <2>; + #size-cells = <2>; + eqep1: counter@23210000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23210000 0x00 0x100>; + power-domains = <&k3_pds 60 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 60 0>; + interrupts = ; + status = "disabled"; + }; + }; ... diff -Naur --no-dereference a/Documentation/devicetree/bindings/crypto/ti,mcrc64.yaml b/Documentation/devicetree/bindings/crypto/ti,mcrc64.yaml --- a/Documentation/devicetree/bindings/crypto/ti,mcrc64.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/crypto/ti,mcrc64.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/crypto/ti,mcrc64.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments MCRC64 + +description: + The MCRC64 engine calculates 64-bit cyclic redundancy checks + (CRC) according to the ISO 3309 standard. + +maintainers: + - Kamlesh Gurudasani + +properties: + compatible: + const: ti,am62-mcrc64 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - power-domains + +additionalProperties: false + +examples: + - | + #include + + crc@30300000 { + compatible = "ti,am62-mcrc64"; + reg = <0x30300000 0x1000>; + clocks = <&k3_clks 116 0>; + power-domains = <&k3_pds 116 TI_SCI_PD_EXCLUSIVE>; + }; + +... diff -Naur --no-dereference a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8546.yaml b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8546.yaml --- a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8546.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8546.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -57,6 +57,12 @@ interrupts: maxItems: 1 + cdns,no-hpd: + type: boolean + description: + Set if the HPD line on the bridge isn't hooked up to anything or is + otherwise unusable. + ports: $ref: /schemas/graph.yaml#/properties/ports diff -Naur --no-dereference a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml --- a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -20,6 +20,7 @@ - feixin,k101-im2byl02 - tdo,tl050hdv35 - wanchanglong,w552946aba + - microtips,mf-070zimacaa0 - const: ilitek,ili9881c backlight: true @@ -30,7 +31,6 @@ required: - compatible - - power-supply - reg additionalProperties: false diff -Naur --no-dereference a/Documentation/devicetree/bindings/display/panel/panel-edp.yaml b/Documentation/devicetree/bindings/display/panel/panel-edp.yaml --- a/Documentation/devicetree/bindings/display/panel/panel-edp.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/display/panel/panel-edp.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -86,7 +86,11 @@ properties: compatible: - const: edp-panel + enum: + # Generic Panel EDP + - edp-panel + # TI Simple Panel EDP + - ti,panel-edp hpd-reliable-delay-ms: description: diff -Naur --no-dereference a/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml --- a/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,124 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/panel-simple-lvds-dual-ports.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Simple LVDS panels with one power supply and dual LVDS ports + +maintainers: + - Liu Ying + - Thierry Reding + - Sam Ravnborg + +description: | + This binding file is a collection of the LVDS panels that + has dual LVDS ports and requires only a single power-supply. + The first port receives odd pixels, and the second port receives even pixels. + There are optionally a backlight and an enable GPIO. + The panel may use an OF graph binding for the association to the display, + or it may be a direct child node of the display. + + If the panel is more advanced a dedicated binding file is required. + +allOf: + - $ref: panel-common.yaml# + +properties: + + compatible: + enum: + # compatible must be listed in alphabetical order, ordered by compatible. + # The description in the comment is mandatory for each compatible. + + # AU Optronics Corporation 13.3" FHD (1920x1080) TFT LCD panel + - auo,g133han01 + # AU Optronics Corporation 18.5" FHD (1920x1080) TFT LCD panel + - auo,g185han01 + # AU Optronics Corporation 19.0" (1280x1024) TFT LCD panel + - auo,g190ean01 + # Kaohsiung Opto-Electronics Inc. 10.1" WUXGA (1920 x 1200) LVDS TFT LCD panel + - koe,tx26d202vm0bwa + # Lincoln Technology Solutions, LCD185-101CT 10.1" TFT 1920x1200 + - lincolntech,lcd185-101ct + # Microtips Technology MF-101HIEBCAF0 10.1" WUXGA (1920x1200) TFT LCD panel + - microtips,mf-101hiebcaf0 + # Microtips Technology MF-103HIEB0GA0 10.25" 1920x720 TFT LCD panel + - microtips,mf-103hieb0ga0 + # NLT Technologies, Ltd. 15.6" FHD (1920x1080) LVDS TFT LCD panel + - nlt,nl192108ac18-02d + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: The first sink port. + + properties: + dual-lvds-odd-pixels: + type: boolean + description: The first sink port for odd pixels. + + required: + - dual-lvds-odd-pixels + + port@1: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: The second sink port. + + properties: + dual-lvds-even-pixels: + type: boolean + description: The second sink port for even pixels. + + required: + - dual-lvds-even-pixels + + required: + - port@0 + - port@1 + + backlight: true + enable-gpios: true + power-supply: true + +additionalProperties: false + +required: + - compatible + - ports + - power-supply + +examples: + - | + panel: panel-lvds { + compatible = "koe,tx26d202vm0bwa"; + power-supply = <&vdd_lcd_reg>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + dual-lvds-odd-pixels; + reg = <0>; + + panel_lvds0_in: endpoint { + remote-endpoint = <&lvds0_out>; + }; + }; + + port@1 { + dual-lvds-even-pixels; + reg = <1>; + + panel_lvds1_in: endpoint { + remote-endpoint = <&lvds1_out>; + }; + }; + }; + }; diff -Naur --no-dereference a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -65,14 +65,8 @@ - auo,g104sn02 # AU Optronics Corporation 12.1" (1280x800) TFT LCD panel - auo,g121ean01 - # AU Optronics Corporation 13.3" FHD (1920x1080) TFT LCD panel - - auo,g133han01 # AU Optronics Corporation 15.6" (1366x768) TFT LCD panel - auo,g156xtn01 - # AU Optronics Corporation 18.5" FHD (1920x1080) TFT LCD panel - - auo,g185han01 - # AU Optronics Corporation 19.0" (1280x1024) TFT LCD panel - - auo,g190ean01 # AU Optronics Corporation 31.5" FHD (1920x1080) TFT LCD panel - auo,p320hvn03 # AU Optronics Corporation 21.5" FHD (1920x1080) color TFT LCD panel @@ -204,8 +198,6 @@ - kingdisplay,kd116n21-30nv-a010 # Kaohsiung Opto-Electronics Inc. 5.7" QVGA (320 x 240) TFT LCD panel - koe,tx14d24vm1bpa - # Kaohsiung Opto-Electronics Inc. 10.1" WUXGA (1920 x 1200) LVDS TFT LCD panel - - koe,tx26d202vm0bwa # Kaohsiung Opto-Electronics. TX31D200VM0BAA 12.3" HSXGA LVDS panel - koe,tx31d200vm0baa # Kyocera Corporation 7" WVGA (800x480) transmissive color TFT @@ -254,8 +246,6 @@ - neweast,wjfh116008a # Newhaven Display International 480 x 272 TFT LCD panel - newhaven,nhd-4.3-480272ef-atxl - # NLT Technologies, Ltd. 15.6" FHD (1920x1080) LVDS TFT LCD panel - - nlt,nl192108ac18-02d # New Vision Display 7.0" 800 RGB x 480 TFT LCD panel - nvd,9128 # OKAYA Electric America, Inc. RS800480T-7X0GP 7" WVGA LCD panel @@ -280,6 +270,8 @@ - qiaodian,qd43003c0-40 # Shenzhen QiShenglong Industrialist Co., Ltd. Gopher 2b 4.3" 480(RGB)x272 TFT LCD panel - qishenglong,gopher2b-lcd + # Raspberry Pi 7" 800x600 LCD Panel + - raspberrypi,7inch-dsi # Rocktech Displays Ltd. RK101II01D-CT 10.1" TFT 1280x800 - rocktech,rk101ii01d-ct # Rocktech Display Ltd. RK070ER9427 800(RGB)x480 TFT LCD panel diff -Naur --no-dereference a/Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml b/Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml --- a/Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,153 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/ti/ti,am625-oldi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments AM625 OLDI Transmitter + +maintainers: + - Tomi Valkeinen + - Aradhya Bhatia + +description: | + The AM625 TI Keystone OpenLDI transmitter (OLDI TX) supports serialized RGB + pixel data transmission between host and flat panel display over LVDS (Low + Voltage Differential Sampling) interface. The OLDI TX consists of 7-to-1 data + serializers, and 4-data and 1-clock LVDS outputs. It supports the LVDS output + formats "jeida-18", "jeida-24" and "vesa-18", and can accept 24-bit RGB or + padded and un-padded 18-bit RGB bus formats as input. + +properties: + reg: + maxItems: 1 + + clocks: + maxItems: 1 + description: serial clock input for the OLDI transmitters + + clock-names: + const: s_clk + + ti,companion-oldi: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to companion OLDI transmitter. This property is mandatory for the + primarty OLDI TX if the OLDI TXes are expected to work either in dual-lvds + mode or in clone mode. This property should point to the secondary OLDI + TX. + + ti,secondary-oldi: + type: boolean + description: Boolean property to mark an OLDI TX as secondary node. + + ti,oldi-io-ctrl: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to syscon device node mapping OLDI IO_CTRL registers found in the + control MMR region. This property is needed for OLDI interface to work. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Parallel RGB input port + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: LVDS output port + + required: + - port@0 + - port@1 + +allOf: + - if: + properties: + ti,secondary-oldi: true + then: + properties: + ti,companion-oldi: false + ti,oldi-io-ctrl: false + clocks: false + clock-names: false + + else: + required: + - ti,oldi-io-ctrl + - clocks + - clock-names + +required: + - reg + - ports + +additionalProperties: false + +examples: + - | + #include + + oldi_txes { + #address-cells = <1>; + #size-cells = <0>; + oldi: oldi@0 { + reg = <0>; + clocks = <&k3_clks 186 0>; + clock-names = "s_clk"; + ti,oldi-io-ctrl = <&dss_oldi_io_ctrl>; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + oldi_in: endpoint { + remote-endpoint = <&dpi0_out>; + }; + }; + }; + }; + }; + + - | + #include + + oldi_txes { + #address-cells = <1>; + #size-cells = <0>; + oldi0: oldi@0 { + reg = <0>; + clocks = <&k3_clks 186 0>; + clock-names = "s_clk"; + ti,companion-oldi = <&oldi1>; + ti,oldi-io-ctrl = <&dss_oldi_io_ctrl>; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + oldi0_in: endpoint { + remote-endpoint = <&dpi0_out0>; + }; + }; + }; + }; + oldi1: oldi@1 { + reg = <1>; + ti,secondary-oldi; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + oldi1_in: endpoint { + remote-endpoint = <&dpi0_out1>; + }; + }; + }; + }; + }; + +... diff -Naur --no-dereference a/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml b/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml --- a/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -23,6 +23,9 @@ compatible: enum: - ti,am625-dss + - ti,am62a7,dss + - ti,am62p51,dss + - ti,am62p52,dss - ti,am65x-dss reg: @@ -36,6 +39,7 @@ - description: OVR2 overlay manager for vp2 - description: VP1 video port 1 - description: VP2 video port 2 + - description: common1 DSS register area reg-names: items: @@ -46,6 +50,7 @@ - const: ovr2 - const: vp1 - const: vp2 + - const: common1 clocks: items: @@ -71,7 +76,8 @@ maxItems: 1 power-domains: - maxItems: 1 + minItems: 1 + maxItems: 3 description: phandle to the associated power domain dma-coherent: @@ -85,13 +91,34 @@ $ref: /schemas/graph.yaml#/properties/port description: For AM65x DSS, the OLDI output port node from video port 1. - For AM625 DSS, the internal DPI output port node from video - port 1. + For AM625, and AM62P5-1/2 DSS, the internal DPI output port + node from video port 1. + For AM62A7 DSS, the port is tied off inside the SoC. + properties: + endpoint@0: + $ref: /schemas/graph.yaml#/properties/endpoint + description: + For AM625/AM62P5-1 DSS, VP Connection to OLDI0. + For AM62P5-2 DSS, VP Connection to OLDI1 or the DPI pipe. + For AM65X DSS, OLDI output from the SoC. + + endpoint@1: + $ref: /schemas/graph.yaml#/properties/endpoint + description: + For AM625/AM62P5-1 DSS, VP Connection to OLDI1. + + anyOf: + - required: + - endpoint + - required: + - endpoint@0 + - endpoint@1 port@1: $ref: /schemas/graph.yaml#/properties/port description: - The DSS DPI output port node from video port 2 + The DSS DPI output port node from video port 2. + For AM62P5-2 DSS, VP Connection to DSI Tx or the DPI pipe. ti,am65x-oldi-io-ctrl: $ref: /schemas/types.yaml#/definitions/phandle @@ -108,6 +135,49 @@ Input memory (from main memory to dispc) bandwidth limit in bytes per second + oldi-txes: + type: object + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + '^oldi_tx@[0-1]$': + type: object + $ref: ti,am625-oldi.yaml# + unevaluatedProperties: false + description: OLDI transmitters connected to the DSS VPs + +allOf: + - if: + properties: + compatible: + contains: + const: ti,am62a7-dss + then: + properties: + ports: + properties: + port@0: false + oldi_txes: false + + - if: + properties: + compatible: + contains: + enum: + - ti,am65x-dss + - ti,am62p52-dss + then: + properties: + oldi_txes: false + port@0: + properties: + endpoint@1: false + required: - compatible - reg @@ -126,31 +196,119 @@ #include dss: dss@4a00000 { - compatible = "ti,am65x-dss"; - reg = <0x04a00000 0x1000>, /* common */ - <0x04a02000 0x1000>, /* vidl1 */ - <0x04a06000 0x1000>, /* vid */ - <0x04a07000 0x1000>, /* ovr1 */ - <0x04a08000 0x1000>, /* ovr2 */ - <0x04a0a000 0x1000>, /* vp1 */ - <0x04a0b000 0x1000>; /* vp2 */ + compatible = "ti,am65x-dss"; + reg = <0x04a00000 0x1000>, /* common */ + <0x04a02000 0x1000>, /* vidl1 */ + <0x04a06000 0x1000>, /* vid */ + <0x04a07000 0x1000>, /* ovr1 */ + <0x04a08000 0x1000>, /* ovr2 */ + <0x04a0a000 0x1000>, /* vp1 */ + <0x04a0b000 0x1000>, /* vp2 */ + <0x04a01000 0x1000>; /* common1 */ + reg-names = "common", "vidl1", "vid", + "ovr1", "ovr2", "vp1", "vp2", "common1"; + ti,am65x-oldi-io-ctrl = <&dss_oldi_io_ctrl>; + power-domains = <&k3_pds 67 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 67 1>, + <&k3_clks 216 1>, + <&k3_clks 67 2>; + clock-names = "fck", "vp1", "vp2"; + interrupts = ; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + oldi_out0: endpoint { + remote-endpoint = <&lcd_in0>; + }; + }; + }; + }; + + - | + #include + #include + #include + + bus { + #address-cells = <2>; + #size-cells = <2>; + dss1: dss@30200000 { + compatible = "ti,am625-dss"; + reg = <0x00 0x30200000 0x00 0x1000>, /* common */ + <0x00 0x30202000 0x00 0x1000>, /* vidl1 */ + <0x00 0x30206000 0x00 0x1000>, /* vid */ + <0x00 0x30207000 0x00 0x1000>, /* ovr1 */ + <0x00 0x30208000 0x00 0x1000>, /* ovr2 */ + <0x00 0x3020a000 0x00 0x1000>, /* vp1 */ + <0x00 0x3020b000 0x00 0x1000>, /* vp2 */ + <0x00 0x30201000 0x00 0x1000>; /* common1 */ reg-names = "common", "vidl1", "vid", - "ovr1", "ovr2", "vp1", "vp2"; - ti,am65x-oldi-io-ctrl = <&dss_oldi_io_ctrl>; - power-domains = <&k3_pds 67 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 67 1>, - <&k3_clks 216 1>, - <&k3_clks 67 2>; + "ovr1", "ovr2", "vp1", "vp2", "common1"; + power-domains = <&k3_pds 186 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 186 6>, + <&vp1_clock>, + <&k3_clks 186 2>; clock-names = "fck", "vp1", "vp2"; - interrupts = ; + interrupts = ; + oldi-txes { + #address-cells = <1>; + #size-cells = <0>; + oldi0: oldi@0 { + reg = <0>; + clocks = <&k3_clks 186 0>; + clock-names = "s_clk"; + ti,companion-oldi = <&oldi1>; + ti,oldi-io-ctrl = <&dss_oldi_io_ctrl>; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + oldi0_in: endpoint { + remote-endpoint = <&dpi0_out0>; + }; + }; + }; + }; + oldi1: oldi@1 { + reg = <1>; + ti,secondary-oldi; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + oldi1_in: endpoint { + remote-endpoint = <&dpi0_out1>; + }; + }; + }; + }; + }; ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { #address-cells = <1>; #size-cells = <0>; - port@0 { - reg = <0>; - oldi_out0: endpoint { - remote-endpoint = <&lcd_in0>; - }; + reg = <0>; + dpi0_out0: endpoint@0 { + reg = <0>; + remote-endpoint = <&oldi0_in>; + }; + dpi0_out1: endpoint@1 { + reg = <1>; + remote-endpoint = <&oldi1_in>; + }; + }; + port@1 { + reg = <1>; + dpi1_out: endpoint { + remote-endpoint = <&hdmi_bridge>; }; + }; }; + }; }; diff -Naur --no-dereference a/Documentation/devicetree/bindings/dma/ti/k3-bcdma.yaml b/Documentation/devicetree/bindings/dma/ti/k3-bcdma.yaml --- a/Documentation/devicetree/bindings/dma/ti/k3-bcdma.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/dma/ti/k3-bcdma.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -34,14 +34,15 @@ - ti,am62a-dmss-bcdma-csirx - ti,am64-dmss-bcdma - ti,j721s2-dmss-bcdma-csi + - ti,j722s-dmss-bcdma-csi reg: minItems: 3 - maxItems: 5 + maxItems: 9 reg-names: minItems: 3 - maxItems: 5 + maxItems: 9 "#dma-cells": const: 3 @@ -141,7 +142,10 @@ ti,sci-rm-range-tchan: false reg: - maxItems: 3 + items: + - description: BCDMA Control /Status Registers region + - description: RX Channel Realtime Registers region + - description: Ring Realtime Registers region reg-names: items: @@ -161,14 +165,29 @@ properties: reg: minItems: 5 + items: + - description: BCDMA Control /Status Registers region + - description: Block Copy Channel Realtime Registers region + - description: RX Channel Realtime Registers region + - description: TX Channel Realtime Registers region + - description: Ring Realtime Registers region + - description: Ring Configuration Registers region + - description: TX Channel Configuration Registers region + - description: RX Channel Configuration Registers region + - description: Block Copy Channel Configuration Registers region reg-names: + minItems: 5 items: - const: gcfg - const: bchanrt - const: rchanrt - const: tchanrt - const: ringrt + - const: ring + - const: tchan + - const: rchan + - const: bchan required: - ti,sci-rm-range-bchan @@ -178,13 +197,19 @@ properties: compatible: contains: - const: ti,j721s2-dmss-bcdma-csi + enum: + - ti,j721s2-dmss-bcdma-csi + - ti,j722s-dmss-bcdma-csi then: properties: ti,sci-rm-range-bchan: false reg: - maxItems: 4 + items: + - description: BCDMA Control /Status Registers region + - description: RX Channel Realtime Registers region + - description: TX Channel Realtime Registers region + - description: Ring Realtime Registers region reg-names: items: @@ -220,8 +245,13 @@ <0x0 0x4c000000 0x0 0x20000>, <0x0 0x4a820000 0x0 0x20000>, <0x0 0x4aa40000 0x0 0x20000>, - <0x0 0x4bc00000 0x0 0x100000>; - reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt"; + <0x0 0x4bc00000 0x0 0x100000>, + <0x0 0x48600000 0x0 0x8000>, + <0x0 0x484a4000 0x0 0x2000>, + <0x0 0x484c2000 0x0 0x2000>, + <0x0 0x48420000 0x0 0x2000>; + reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "bchan"; msi-parent = <&inta_main_dmss>; #dma-cells = <3>; diff -Naur --no-dereference a/Documentation/devicetree/bindings/dma/ti/k3-pktdma.yaml b/Documentation/devicetree/bindings/dma/ti/k3-pktdma.yaml --- a/Documentation/devicetree/bindings/dma/ti/k3-pktdma.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/dma/ti/k3-pktdma.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -45,14 +45,28 @@ The second cell is the ASEL value for the channel reg: - maxItems: 4 + minItems: 4 + items: + - description: Packet DMA Control /Status Registers region + - description: RX Channel Realtime Registers region + - description: TX Channel Realtime Registers region + - description: Ring Realtime Registers region + - description: Ring Configuration Registers region + - description: TX Configuration Registers region + - description: RX Configuration Registers region + - description: RX Flow Configuration Registers region reg-names: + minItems: 4 items: - const: gcfg - const: rchanrt - const: tchanrt - const: ringrt + - const: ring + - const: tchan + - const: rchan + - const: rflow msi-parent: true @@ -136,8 +150,14 @@ reg = <0x0 0x485c0000 0x0 0x100>, <0x0 0x4a800000 0x0 0x20000>, <0x0 0x4aa00000 0x0 0x40000>, - <0x0 0x4b800000 0x0 0x400000>; - reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + <0x0 0x4b800000 0x0 0x400000>, + <0x0 0x485e0000 0x0 0x20000>, + <0x0 0x484a0000 0x0 0x4000>, + <0x0 0x484c0000 0x0 0x2000>, + <0x0 0x48430000 0x0 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "rflow"; + msi-parent = <&inta_main_dmss>; #dma-cells = <2>; diff -Naur --no-dereference a/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml b/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml --- a/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -69,13 +69,24 @@ - ti,j721e-navss-mcu-udmap reg: - maxItems: 3 + minItems: 3 + items: + - description: UDMA-P Control /Status Registers region + - description: RX Channel Realtime Registers region + - description: TX Channel Realtime Registers region + - description: TX Configuration Registers region + - description: RX Configuration Registers region + - description: RX Flow Configuration Registers region reg-names: + minItems: 3 items: - const: gcfg - const: rchanrt - const: tchanrt + - const: tchan + - const: rchan + - const: rflow msi-parent: true @@ -158,8 +169,11 @@ compatible = "ti,am654-navss-main-udmap"; reg = <0x0 0x31150000 0x0 0x100>, <0x0 0x34000000 0x0 0x100000>, - <0x0 0x35000000 0x0 0x100000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x35000000 0x0 0x100000>, + <0x0 0x30b00000 0x0 0x20000>, + <0x0 0x30c00000 0x0 0x8000>, + <0x0 0x30d00000 0x0 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "tchan", "rchan", "rflow"; #dma-cells = <1>; ti,ringacc = <&ringacc>; diff -Naur --no-dereference a/Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml b/Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml --- a/Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2023 Imagination Technologies Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/img,powervr-rogue.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Imagination Technologies PowerVR and IMG Rogue GPUs + +maintainers: + - Frank Binns + +properties: + compatible: + items: + - enum: + - ti,am62-gpu + - const: img,img-axe # IMG AXE GPU model/revision is fully discoverable + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + items: + - const: core + - const: mem + - const: sys + minItems: 1 + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + const: ti,am62-gpu + then: + properties: + clocks: + maxItems: 1 + +examples: + - | + #include + #include + #include + + gpu@fd00000 { + compatible = "ti,am62-gpu", "img,img-axe"; + reg = <0x0fd00000 0x20000>; + clocks = <&k3_clks 187 0>; + clock-names = "core"; + interrupts = ; + power-domains = <&k3_pds 187 TI_SCI_PD_EXCLUSIVE>; + }; diff -Naur --no-dereference a/Documentation/devicetree/bindings/gpu/img,powervr-sgx.yaml b/Documentation/devicetree/bindings/gpu/img,powervr-sgx.yaml --- a/Documentation/devicetree/bindings/gpu/img,powervr-sgx.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/gpu/img,powervr-sgx.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,138 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2023 Imagination Technologies Ltd. +# Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/img,powervr-sgx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Imagination Technologies PowerVR SGX GPUs + +maintainers: + - Frank Binns + +properties: + compatible: + oneOf: + - items: + - enum: + - ti,omap3430-gpu # Rev 121 + - ti,omap3630-gpu # Rev 125 + - const: img,powervr-sgx530 + - items: + - enum: + - ingenic,jz4780-gpu # Rev 130 + - ti,omap4430-gpu # Rev 120 + - const: img,powervr-sgx540 + - items: + - enum: + - allwinner,sun6i-a31-gpu # MP2 Rev 115 + - ti,omap4470-gpu # MP1 Rev 112 + - ti,omap5432-gpu # MP2 Rev 105 + - ti,am5728-gpu # MP2 Rev 116 + - ti,am6548-gpu # MP1 Rev 117 + - const: img,powervr-sgx544 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + minItems: 1 + items: + - const: core + - const: mem + - const: sys + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +allOf: + - if: + properties: + compatible: + contains: + const: ti,am6548-gpu + then: + required: + - power-domains + else: + properties: + power-domains: false + - if: + properties: + compatible: + contains: + enum: + - allwinner,sun6i-a31-gpu + - ingenic,jz4780-gpu + then: + required: + - clocks + - clock-names + else: + properties: + clocks: false + clock-names: false + - if: + properties: + compatible: + contains: + const: allwinner,sun6i-a31-gpu + then: + properties: + clocks: + minItems: 2 + maxItems: 2 + clock-names: + minItems: 2 + maxItems: 2 + - if: + properties: + compatible: + contains: + const: ingenic,jz4780-gpu + then: + properties: + clocks: + maxItems: 1 + clock-names: + maxItems: 1 + +additionalProperties: false + +examples: + - | + #include + #include + #include + + gpu@7000000 { + compatible = "ti,am6548-gpu", "img,powervr-sgx544"; + reg = <0x7000000 0x10000>; + interrupts = ; + power-domains = <&k3_pds 65 TI_SCI_PD_EXCLUSIVE>; + }; + + - | + #include + #include + + gpu: gpu@1c40000 { + compatible = "allwinner,sun6i-a31-gpu", "img,powervr-sgx544"; + reg = <0x01c40000 0x10000>; + interrupts = ; + clocks = <&ccu 1>, <&ccu 2>; + clock-names = "core", "mem"; + }; diff -Naur --no-dereference a/Documentation/devicetree/bindings/gpu/ti,rogue.yaml b/Documentation/devicetree/bindings/gpu/ti,rogue.yaml --- a/Documentation/devicetree/bindings/gpu/ti,rogue.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/gpu/ti,rogue.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,191 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/ti,rogue.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments PowerVR Rogue GPU + +description: | + PowerVR Rogue is a family of 3D graphics processing units from Imagination + Technologies. Texas Instruments SoCs have integrated different generations of + PowerVR GPUs and this binding describes the GPU's integrated in Texas + Instruments SoCs in the K3 generation. + +maintainers: + - Darren Etheridge + - Randolph Sapp + +properties: + $nodename: + pattern: '^gpu@[a-f0-9]+$' + + compatible: + oneOf: + - items: + - enum: + - ti,j721s2-pvr + - const: img,pvr-bxs64 + - items: + - enum: + - ti,j721e-pvr + - const: img,pvr-ge8430 + - items: + - enum: + - ti,am62p-pvr + - const: img,pvr-bxs64 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + maxItems: 1 + + power-domains: + minItems: 1 + maxItems: 2 + + power-domain-names: + maxItems: 2 + + assigned-clocks: + maxItems: 1 + + assigned-clock-rates: + maxItems: 1 + description: | + Allows users to override the default clock value used for the GPU. + Currently ignored on devices other than ti,am62p-pvr. This will be ported + to other devices soon. + +required: + - compatible + - reg + - interrupts + - power-domains + - clocks + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + enum: + - ti,am62p-pvr + - ti,j721e-pvr + - ti,j721s2-pvr + then: + required: + - power-domain-names + - assigned-clocks + - clock-names + properties: + reg: + minItems: 1 + interrupts: + minItems: 1 + clocks: + minItems: 1 + clock-names: + items: + - const: core + power-domains: + minItems: 2 + power-domain-names: + items: + - const: firmware + - const: dust + assigned-clocks: + minItems: 1 + assigned-clock-rates: + default: [800000000] + else: + properties: + assigned-clocks: false + assigned-clock-rates: false + - if: + properties: + compatible: + contains: + enum: + - ti,j721e-pvr + then: + properties: + assigned-clock-rates: + default: [750000000] + +examples: + - | + #include + #include + #include + + bus { + #address-cells = <2>; + #size-cells = <2>; + gpu@4e20000000 { + compatible = "ti,j721s2-pvr", "img,pvr-bxs64"; + reg = <0x4e 0x20000000 0x00 0x80000>; + interrupts = ; + power-domains = <&k3_pds 130 TI_SCI_PD_EXCLUSIVE>, + <&k3_pds 373 TI_SCI_PD_EXCLUSIVE>; + power-domain-names = "firmware", "dust"; + clocks = <&k3_clks 130 1>; + assigned-clocks = <&k3_clks 130 1>; + assigned-clock-rates = <800000000>; + clock-names = "core"; + }; + }; + + - | + #include + #include + #include + + bus { + #address-cells = <2>; + #size-cells = <2>; + gpu@4e20000000 { + compatible = "ti,j721e-pvr", "img,pvr-ge8430"; + reg = <0x4e 0x20000000 0x00 0x80000>; + interrupts = ; + power-domains = <&k3_pds 125 TI_SCI_PD_EXCLUSIVE>, + <&k3_pds 126 TI_SCI_PD_EXCLUSIVE>; + power-domain-names = "firmware", "dust"; + clocks = <&k3_clks 125 0>; + assigned-clocks = <&k3_clks 125 0>; + assigned-clock-rates = <750000000>; + clock-names = "core"; + }; + }; + + - | + #include + #include + #include + + bus { + #address-cells = <2>; + #size-cells = <2>; + gpu@fd80000 { + compatible = "ti,am62p-pvr", "img,pvr-bxs64"; + reg = <0x00 0x0fd80000 0x00 0x80000>; + interrupts = ; + power-domains = <&k3_pds 237 TI_SCI_PD_EXCLUSIVE>, + <&k3_pds 242 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 237 3>; + assigned-clock-rates = <720000000>; + power-domain-names = "firmware", "dust"; + clocks = <&k3_clks 237 3>; + clock-names = "core"; + }; + }; +... diff -Naur --no-dereference a/Documentation/devicetree/bindings/input/gpio-keys.yaml b/Documentation/devicetree/bindings/input/gpio-keys.yaml --- a/Documentation/devicetree/bindings/input/gpio-keys.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/input/gpio-keys.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -31,7 +31,23 @@ maxItems: 1 interrupts: - maxItems: 1 + oneOf: + - items: + - description: Optional key interrupt or wakeup interrupt + - items: + - description: Key interrupt + - description: Wakeup interrupt + + interrupt-names: + description: + Optional interrupt names, can be used to specify a separate dedicated + wake-up interrupt in addition to the gpio irq + oneOf: + - items: + - enum: [ irq, wakeup ] + - items: + - const: irq + - const: wakeup label: description: Descriptive name of the key. @@ -97,6 +113,20 @@ - required: - gpios + allOf: + - if: + properties: + interrupts: + minItems: 2 + required: + - interrupts + then: + properties: + interrupt-names: + minItems: 2 + required: + - interrupt-names + dependencies: wakeup-event-action: [ wakeup-source ] linux,input-value: [ gpios ] @@ -137,6 +167,15 @@ linux,code = <108>; interrupts = <1 IRQ_TYPE_EDGE_FALLING>; }; + + key-wakeup { + label = "GPIO Key WAKEUP"; + linux,code = <143>; + interrupts-extended = <&intc 2 IRQ_TYPE_EDGE_FALLING>, + <&intc_wakeup 0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "irq", "wakeup"; + wakeup-source; + }; }; ... diff -Naur --no-dereference a/Documentation/devicetree/bindings/media/cdns,csi2rx.yaml b/Documentation/devicetree/bindings/media/cdns,csi2rx.yaml --- a/Documentation/devicetree/bindings/media/cdns,csi2rx.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/media/cdns,csi2rx.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -18,6 +18,7 @@ items: - enum: - starfive,jh7110-csi2rx + - ti,j721e-csi2rx - const: cdns,csi2rx reg: diff -Naur --no-dereference a/Documentation/devicetree/bindings/media/cnm,wave521c.yaml b/Documentation/devicetree/bindings/media/cnm,wave521c.yaml --- a/Documentation/devicetree/bindings/media/cnm,wave521c.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/media/cnm,wave521c.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cnm,wave521c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Chips&Media Wave 5 Series multi-standard codec IP + +maintainers: + - Nas Chung + - Jackson Lee + +description: + The Chips&Media WAVE codec IP is a multi format video encoder/decoder + +properties: + compatible: + items: + - enum: + - ti,j721s2-wave521c + - const: cnm,wave521c + + reg: + maxItems: 1 + + clocks: + items: + - description: VCODEC clock + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + sram: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The VPU uses the SRAM to store some of the reference data instead of + storing it on DMA memory. It is mainly used for the purpose of reducing + bandwidth. + +required: + - compatible + - reg + - clocks + +additionalProperties: false + +examples: + - | + vpu: video-codec@12345678 { + compatible = "ti,j721s2-wave521c", "cnm,wave521c"; + reg = <0x12345678 0x1000>; + clocks = <&clks 42>; + interrupts = <42>; + sram = <&sram>; + }; diff -Naur --no-dereference a/Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov2312.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OmniVision OV2312 Camera Sensor + +maintainers: + - Jai Luthra + +description: |- + Omnvision OV2312 is a camera sensor with an active array size of 1600x1300. + It supports capture of frames with a 4x4 RGB-IR bayer pattern. This provides + both human (RGB) and machine vision (IR) capabilities in low-light scenarios. + +properties: + compatible: + enum: + - ovti,ov2312 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: xvclk + + reset-gpios: + maxItems: 1 + description: + Specifier for the GPIO connected to the RESET pin. + + port: + $ref: /schemas/graph.yaml#/properties/port + additionalProperties: false + + properties: + endpoint: + $ref: ../video-interfaces.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - clocks + - clock-names + - port + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + camera@60 { + compatible = "ovti,ov2312"; + reg = <0x60>; + + clocks = <&fixed_clock>; + clock-names = "xvclk"; + + reset-gpios = <&gpio4 17 GPIO_ACTIVE_LOW>; + + port { + camera1: endpoint { + remote-endpoint = <&vin1a_ep>; + }; + }; + }; + }; + +... diff -Naur --no-dereference a/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml --- a/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ox05b.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OmniVision OX05B1S Camera Sensor + +maintainers: + - Abhishek Sharma + +description: |- + Omnivision OX05B1S is an RGBIR camera sensor with an active array size of + 2592x1944. It is programmable through the I2C interface. The i2c client + address is fixed at 0x36 as per the sensor datasheet. Every alternate frame, + the sensor changes the exposure/gain registers to stream an - + A. IR-dominant frame on CSI-2 virtual channel 0 + B. RGB-dominant frame on CSI-2 virtual channel 1 + + Both streams are captured at a resolution 2592x1944, 30 fps each + (60 fps total). The sensor also supports a few v4l2 controls like + exposure and gain controls. + +properties: + compatible: + enum: + - ovti,ox05b + + reg: + description: I2C address + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: inck + + pwdn-gpios: + maxItems: 1 + description: + Specifier for the GPIO connected to the PWDN pin. + + port: + $ref: /schemas/graph.yaml#/properties/port + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - clocks + - clock-names + - port + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ox05b1s: camera@36 { + compatible = "ovti,ox05b"; + reg = <0x36>; + + clocks = <&clk_ox05b1s_fixed>; + clock-names = "inck"; + + pwdn-gpios = <&exp1 13 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + }; + }; + }; + }; + +... diff -Naur --no-dereference a/Documentation/devicetree/bindings/media/i2c/sony,imx390.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx390.yaml --- a/Documentation/devicetree/bindings/media/i2c/sony,imx390.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx390.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/sony,imx390.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony IMX390 Camera Sensor + +maintainers: + - Tomi Valkeinen + +description: |- + Sony IMX390 camera sensor. + +properties: + compatible: + enum: + - sony,imx390 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: inck + + xclr-gpios: + maxItems: 1 + description: + Specifier for the GPIO connected to the XCLR (System Reset) pin. + + port: + $ref: /schemas/graph.yaml#/properties/port + additionalProperties: false + + properties: + endpoint: + $ref: ../video-interfaces.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - clocks + - clock-names + - port + +additionalProperties: false + +examples: + - | + #include + + i2c { + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; + + camera@21 { + compatible = "sony,imx390"; + reg = <0x21>; + + clocks = <&fixed_clock>; + clock-names = "inck"; + + xclr-gpios = <&gpio4 17 GPIO_ACTIVE_LOW>; + + port { + camera1: endpoint { + remote-endpoint = <&vin1a_ep>; + }; + }; + }; + }; + +... diff -Naur --no-dereference a/Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml b/Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml --- a/Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -19,6 +19,7 @@ properties: compatible: enum: + - ti,ds90ub954-q1 - ti,ds90ub960-q1 - ti,ds90ub9702-q1 diff -Naur --no-dereference a/Documentation/devicetree/bindings/media/img,e5010-jpeg-enc.yaml b/Documentation/devicetree/bindings/media/img,e5010-jpeg-enc.yaml --- a/Documentation/devicetree/bindings/media/img,e5010-jpeg-enc.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/media/img,e5010-jpeg-enc.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/img,e5010-jpeg-enc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Imagination E5010 JPEG Encoder + +maintainers: + - Devarsh Thakkar + +description: | + The E5010 is a JPEG encoder from Imagination Technologies implemented on + TI's AM62A SoC. It is capable of real time encoding of YUV420 and YUV422 + inputs to JPEG and M-JPEG. It supports baseline JPEG Encoding up to + 8Kx8K resolution. + +properties: + compatible: + oneOf: + - items: + - const: ti,am62a-jpeg-enc + - const: img,e5010-jpeg-enc + - const: img,e5010-jpeg-enc + + reg: + items: + - description: The E5010 core register region + - description: The E5010 mmu register region + + reg-names: + items: + - const: core + - const: mmu + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - reg-names + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + jpeg-encoder@fd20000 { + compatible = "img,e5010-jpeg-enc"; + reg = <0x00 0xfd20000 0x00 0x100>, + <0x00 0xfd20200 0x00 0x200>; + reg-names = "core", "mmu"; + clocks = <&k3_clks 201 0>; + power-domains = <&k3_pds 201 TI_SCI_PD_EXCLUSIVE>; + interrupts = ; + }; + }; diff -Naur --no-dereference a/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml b/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml --- a/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,133 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/ti,j721e-csi2rx-shim.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI J721E CSI2RX Shim + +description: | + The TI J721E CSI2RX Shim is a wrapper around Cadence CSI2RX bridge that + enables sending captured frames to memory over PSI-L DMA. In the J721E + Technical Reference Manual (SPRUIL1B) it is referred to as "SHIM" under the + CSI_RX_IF section. + +maintainers: + - Jai Luthra + +properties: + compatible: + const: ti,j721e-csi2rx-shim + + dmas: + minItems: 1 + maxItems: 32 + + dma-names: + minItems: 1 + items: + - const: rx0 + - const: rx1 + - const: rx2 + - const: rx3 + - const: rx4 + - const: rx5 + - const: rx6 + - const: rx7 + - const: rx8 + - const: rx9 + - const: rx10 + - const: rx11 + - const: rx12 + - const: rx13 + - const: rx14 + - const: rx15 + - const: rx16 + - const: rx17 + - const: rx18 + - const: rx19 + - const: rx20 + - const: rx21 + - const: rx22 + - const: rx23 + - const: rx24 + - const: rx25 + - const: rx26 + - const: rx27 + - const: rx28 + - const: rx29 + - const: rx30 + - const: rx31 + + reg: + maxItems: 1 + + power-domains: + maxItems: 1 + + ranges: true + + "#address-cells": true + + "#size-cells": true + +patternProperties: + "^csi-bridge@": + type: object + description: CSI2 bridge node. + $ref: cdns,csi2rx.yaml# + +required: + - compatible + - reg + - dmas + - dma-names + - power-domains + - ranges + - "#address-cells" + - "#size-cells" + +additionalProperties: false + +examples: + - | + #include + + ti_csi2rx0: ticsi2rx@4500000 { + compatible = "ti,j721e-csi2rx-shim"; + dmas = <&main_udmap 0x4940>, <&main_udmap 0x4941>; + dma-names = "rx0", "rx1"; + reg = <0x4500000 0x1000>; + power-domains = <&k3_pds 26 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + cdns_csi2rx: csi-bridge@4504000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x4504000 0x1000>; + clocks = <&k3_clks 26 2>, <&k3_clks 26 0>, <&k3_clks 26 2>, + <&k3_clks 26 2>, <&k3_clks 26 3>, <&k3_clks 26 3>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi2_0: port@0 { + + reg = <0>; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; diff -Naur --no-dereference a/Documentation/devicetree/bindings/media/video-interfaces.yaml b/Documentation/devicetree/bindings/media/video-interfaces.yaml --- a/Documentation/devicetree/bindings/media/video-interfaces.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/media/video-interfaces.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -160,6 +160,7 @@ $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 1 maxItems: 8 + uniqueItems: true items: # Assume up to 9 physical lane indices maximum: 8 diff -Naur --no-dereference a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml --- a/Documentation/devicetree/bindings/mfd/syscon.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -69,6 +69,10 @@ - rockchip,rk3588-qos - rockchip,rv1126-qos - starfive,jh7100-sysmain + - ti,am625-dss-oldi-io-ctrl + - ti,am654-dss-oldi-io-ctrl + - ti,j784s4-acspcie-proxy-ctrl + - ti,j784s4-pcie-ctrl - const: syscon diff -Naur --no-dereference a/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml b/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml --- a/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -61,8 +61,6 @@ - interrupts - clocks - clock-names - - dmas - - dma-names additionalProperties: false diff -Naur --no-dereference a/Documentation/devicetree/bindings/net/can/bosch,m_can.yaml b/Documentation/devicetree/bindings/net/can/bosch,m_can.yaml --- a/Documentation/devicetree/bindings/net/can/bosch,m_can.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/net/can/bosch,m_can.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -106,6 +106,22 @@ maximum: 32 minItems: 1 + pinctrl-0: + description: Default pinctrl state + + pinctrl-1: + description: Wakeup pinctrl state + + pinctrl-names: + description: + When present should contain at least "default" describing the default pin + states. The second state called "wakeup" describes the pins in their + wakeup configuration required to exit sleep states. + minItems: 1 + items: + - const: default + - const: wakeup + power-domains: description: Power domain provider node and an args specifier containing @@ -118,6 +134,10 @@ phys: maxItems: 1 + wakeup-source: + $ref: /schemas/types.yaml#/definitions/flag + description: This device is capable to wakeup the SoC. + required: - compatible - reg diff -Naur --no-dereference a/Documentation/devicetree/bindings/net/ti,cc1352p7.yaml b/Documentation/devicetree/bindings/net/ti,cc1352p7.yaml --- a/Documentation/devicetree/bindings/net/ti,cc1352p7.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/net/ti,cc1352p7.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/ti,cc1352p7.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments Simplelink CC1352P7 wireless MCU + +description: + The CC1352P7 MCU can be connected via SPI or UART. + +maintainers: + - Ayush Singh + +properties: + compatible: + const: ti,cc1352p7 + + clocks: + items: + - description: high-frequency main system (MCU and peripherals) clock + - description: low-frequency system clock + + clock-names: + items: + - const: sclk_hf + - const: sclk_lf + + reset-gpios: + maxItems: 1 + + vdds-supply: true + +required: + - compatible + +additionalProperties: false + +examples: + - | + #include + + serial { + mcu { + compatible = "ti,cc1352p7"; + clocks = <&sclk_hf 0>, <&sclk_lf 25>; + clock-names = "sclk_hf", "sclk_lf"; + reset-gpios = <&pio 35 GPIO_ACTIVE_LOW>; + vdds-supply = <&vdds>; + }; + }; diff -Naur --no-dereference a/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml b/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml --- a/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -13,13 +13,12 @@ Ethernet based on the Programmable Real-Time Unit and Industrial Communication Subsystem. -allOf: - - $ref: /schemas/remoteproc/ti,pru-consumer.yaml# - properties: compatible: enum: - - ti,am654-icssg-prueth # for AM65x SoC family + - ti,am642-icssg-prueth # for AM64x SoC family + - ti,am654-icssg-prueth # for AM65x SoC family + - ti,am654-sr1-icssg-prueth # for AM65x SoC family, SR1.0 sram: $ref: /schemas/types.yaml#/definitions/phandle @@ -27,9 +26,11 @@ phandle to MSMC SRAM node dmas: - maxItems: 10 + minItems: 10 + maxItems: 12 dma-names: + minItems: 10 items: - const: tx0-0 - const: tx0-1 @@ -41,6 +42,8 @@ - const: tx1-3 - const: rx0 - const: rx1 + - const: rxmgm0 + - const: rxmgm1 ti,mii-g-rt: $ref: /schemas/types.yaml#/definitions/phandle @@ -52,6 +55,14 @@ description: phandle to MII_RT module's syscon regmap + ti,pa-stats: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to PA_STATS module's syscon regmap. PA_STATS is a set of + registers where different statistics related to ICSSG, are dumped by + ICSSG firmware. PA_STATS module's syscon regmap will help the device to + access/read/write those statistics. + ti,iep: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 2 @@ -106,6 +117,13 @@ phandle to system controller node and register offset to ICSSG control register for RGMII transmit delay + ti,half-duplex-capable: + type: boolean + description: + Indicates that the PHY output pin COL is routed to ICSSG GPIO pin + (PRGx_PRU0/1_GPIO10) as input so that the ICSSG MII port is + capable of half duplex operations. + required: - reg anyOf: @@ -124,6 +142,27 @@ - interrupts - interrupt-names +allOf: + - $ref: /schemas/remoteproc/ti,pru-consumer.yaml# + + - if: + properties: + compatible: + contains: + const: ti,am654-sr1-icssg-prueth + then: + properties: + dmas: + minItems: 12 + dma-names: + minItems: 12 + else: + properties: + dmas: + maxItems: 10 + dma-names: + maxItems: 10 + unevaluatedProperties: false examples: @@ -163,6 +202,7 @@ "tx1-0", "tx1-1", "tx1-2", "tx1-3", "rx0", "rx1"; ti,mii-g-rt = <&icssg2_mii_g_rt>; + ti,pa-stats = <&icssg2_pa_stats>; ti,iep = <&icssg2_iep0>, <&icssg2_iep1>; interrupt-parent = <&icssg2_intc>; interrupts = <24 0 2>, <25 1 3>; diff -Naur --no-dereference a/Documentation/devicetree/bindings/net/wireless/ti,cc33xx.yaml b/Documentation/devicetree/bindings/net/wireless/ti,cc33xx.yaml --- a/Documentation/devicetree/bindings/net/wireless/ti,cc33xx.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/net/wireless/ti,cc33xx.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/wireless/ti,cc33xx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments CC33xx Wireless LAN Controller + +maintainers: + - Michael Nemanov + +description: + These are dt entries for the IEEE 802.11ax chips CC33xx from Texas Instruments. + Currently, these chips must be connected via SDIO. + +properties: + compatible: + enum: + - ti,cc3300 + - ti,cc3301 + - ti,cc3350 + - ti,cc3351 + + reg: + description: + For WLAN communication, must be set to 2. + maxItems: 1 + + interrupts: + description: The interrupt line. Can be IRQ_TYPE_EDGE_RISING or IRQ_TYPE_LEVEL_HIGH. + When SDIO is used, the "in-band" interrupt provided by the SDIO bus is used + unless an interrupt is defined in the Device Tree. + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + // SDIO example: + mmc3 { + vmmc-supply = <&wlan_en_reg>; + bus-width = <4>; + cap-power-off-card; + keep-power-in-suspend; + + #address-cells = <1>; + #size-cells = <0>; + + cc33xx: cc33xx@0 { + compatible = "ti,cc3300"; + reg = <2>; + interrupts = <19 IRQ_TYPE_EDGE_RISING>; + }; + }; diff -Naur --no-dereference a/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml --- a/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -10,13 +10,11 @@ maintainers: - Kishon Vijay Abraham I -allOf: - - $ref: cdns-pcie-ep.yaml# - properties: compatible: oneOf: - const: ti,j721e-pcie-ep + - const: ti,j784s4-pcie-ep - description: PCIe EP controller in AM64 items: - const: ti,am64-pcie-ep @@ -65,6 +63,41 @@ items: - const: link_state +allOf: + - $ref: cdns-pcie-ep.yaml# + - if: + properties: + compatible: + enum: + - ti,am64-pcie-ep + then: + properties: + num-lanes: + const: 1 + + - if: + properties: + compatible: + enum: + - ti,j7200-pcie-ep + - ti,j721e-pcie-ep + then: + properties: + num-lanes: + minimum: 1 + maximum: 2 + + - if: + properties: + compatible: + enum: + - ti,j784s4-pcie-ep + then: + properties: + num-lanes: + minimum: 1 + maximum: 4 + required: - compatible - reg diff -Naur --no-dereference a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml --- a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -10,13 +10,11 @@ maintainers: - Kishon Vijay Abraham I -allOf: - - $ref: cdns-pcie-host.yaml# - properties: compatible: oneOf: - const: ti,j721e-pcie-host + - const: ti,j784s4-pcie-host - description: PCIe controller in AM64 items: - const: ti,am64-pcie-host @@ -25,6 +23,10 @@ items: - const: ti,j7200-pcie-host - const: ti,j721e-pcie-host + - description: PCIe controller in J722S + items: + - const: ti,j722s-pcie-host + - const: ti,j721e-pcie-host reg: maxItems: 4 @@ -36,6 +38,16 @@ - const: reg - const: cfg + ti,syscon-acspcie-proxy-ctrl: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: Phandle to the ACSPCIE Proxy Control Register + - description: Bitmask corresponding to the PAD IO Buffer + output enable fields (Active Low). + description: Specifier for enabling the ACSPCIE PAD outputs to drive + the reference clock to the Endpoint device. + ti,syscon-pcie-ctrl: $ref: /schemas/types.yaml#/definitions/phandle-array items: @@ -70,6 +82,7 @@ - 0xb00d - 0xb00f - 0xb010 + - 0xb012 - 0xb013 msi-map: true @@ -94,6 +107,41 @@ interrupts: maxItems: 1 +allOf: + - $ref: cdns-pcie-host.yaml# + - if: + properties: + compatible: + enum: + - ti,am64-pcie-host + then: + properties: + num-lanes: + const: 1 + + - if: + properties: + compatible: + enum: + - ti,j7200-pcie-host + - ti,j721e-pcie-host + then: + properties: + num-lanes: + minimum: 1 + maximum: 2 + + - if: + properties: + compatible: + enum: + - ti,j784s4-pcie-host + then: + properties: + num-lanes: + minimum: 1 + maximum: 4 + required: - compatible - reg diff -Naur --no-dereference a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml --- a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -20,6 +20,7 @@ compatible: enum: - cdns,torrent-phy + - ti,j7200-serdes-10g - ti,j721e-serdes-10g '#address-cells': @@ -35,14 +36,18 @@ minItems: 1 maxItems: 2 description: - PHY reference clock for 1 item. Must contain an entry in clock-names. - Optional Parent to enable output reference clock. + PHY input reference clocks - refclk (for PLL0) & pll1_refclk (for PLL1). + pll1_refclk is optional and used for multi-protocol configurations requiring + separate reference clock for each protocol. + Same refclk is used for both PLL0 and PLL1 if no separate pll1_refclk is used. + Optional parent clock (phy_en_refclk) to enable a reference clock output feature + on some platforms to output either derived or received reference clock. clock-names: minItems: 1 items: - const: refclk - - const: phy_en_refclk + - enum: [ pll1_refclk, phy_en_refclk ] reg: minItems: 1 diff -Naur --no-dereference a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -31,6 +31,7 @@ - ti,omap3-padconf - ti,omap4-padconf - ti,omap5-padconf + - ti,j7200-padconf - const: pinctrl-single reg: diff -Naur --no-dereference a/Documentation/devicetree/bindings/remoteproc/ti,k3-dsp-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/ti,k3-dsp-rproc.yaml --- a/Documentation/devicetree/bindings/remoteproc/ti,k3-dsp-rproc.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/remoteproc/ti,k3-dsp-rproc.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -25,9 +25,6 @@ host processor (Arm CorePac) to perform the device management of the remote processor and to communicate with the remote processor. -allOf: - - $ref: /schemas/arm/keystone/ti,k3-sci-common.yaml# - properties: compatible: enum: @@ -89,41 +86,57 @@ should be defined as per the generic bindings in, Documentation/devicetree/bindings/sram/sram.yaml -if: - properties: - compatible: - enum: - - ti,j721e-c66-dsp -then: - properties: - reg: - items: - - description: Address and Size of the L2 SRAM internal memory region - - description: Address and Size of the L1 PRAM internal memory region - - description: Address and Size of the L1 DRAM internal memory region - reg-names: - items: - - const: l2sram - - const: l1pram - - const: l1dram -else: - if: - properties: - compatible: - enum: - - ti,am62a-c7xv-dsp - - ti,j721e-c71-dsp - - ti,j721s2-c71-dsp - then: - properties: - reg: - items: - - description: Address and Size of the L2 SRAM internal memory region - - description: Address and Size of the L1 DRAM internal memory region - reg-names: - items: - - const: l2sram - - const: l1dram +allOf: + - if: + properties: + compatible: + enum: + - ti,j721e-c66-dsp + then: + properties: + reg: + items: + - description: Address and Size of the L2 SRAM internal memory region + - description: Address and Size of the L1 PRAM internal memory region + - description: Address and Size of the L1 DRAM internal memory region + reg-names: + items: + - const: l2sram + - const: l1pram + - const: l1dram + + - if: + properties: + compatible: + enum: + - ti,j721e-c71-dsp + - ti,j721s2-c71-dsp + then: + properties: + reg: + items: + - description: Address and Size of the L2 SRAM internal memory region + - description: Address and Size of the L1 DRAM internal memory region + reg-names: + items: + - const: l2sram + - const: l1dram + + - if: + properties: + compatible: + enum: + - ti,am62a-c7xv-dsp + then: + properties: + reg: + items: + - description: Address and Size of the L2 SRAM internal memory region + reg-names: + items: + - const: l2sram + + - $ref: /schemas/arm/keystone/ti,k3-sci-common.yaml# required: - compatible diff -Naur --no-dereference a/Documentation/devicetree/bindings/remoteproc/ti,k3-m4f-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/ti,k3-m4f-rproc.yaml --- a/Documentation/devicetree/bindings/remoteproc/ti,k3-m4f-rproc.yaml 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/devicetree/bindings/remoteproc/ti,k3-m4f-rproc.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,125 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/remoteproc/ti,k3-m4f-rproc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI K3 M4F processor subsystems + +maintainers: + - Hari Nagalla + - Mathieu Poirier + +description: | + Some K3 family SoCs have Arm Cortex M4F cores. AM64x is a SoC in K3 + family with a M4F core. Typically safety oriented applications may use + the M4F core in isolation without an IPC. Where as some industrial and + home automation applications, may use the M4F core as a remote processor + with IPC communications. + +$ref: /schemas/arm/keystone/ti,k3-sci-common.yaml# + +properties: + compatible: + enum: + - ti,am64-m4fss + + power-domains: + maxItems: 1 + + "#address-cells": + const: 2 + + "#size-cells": + const: 2 + + reg: + items: + - description: IRAM internal memory region + - description: DRAM internal memory region + + reg-names: + items: + - const: iram + - const: dram + + resets: + maxItems: 1 + + firmware-name: + maxItems: 1 + description: Name of firmware to load for the M4F core + + mboxes: + description: + OMAP Mailbox specifier denoting the sub-mailbox, to be used for + communication with the remote processor. This property should match + with the sub-mailbox node used in the firmware image. + maxItems: 1 + + memory-region: + description: + phandle to the reserved memory nodes to be associated with the + remoteproc device. Optional memory regions available for firmware + specific purposes. + (see reserved-memory/reserved-memory.yaml in dtschema project) + maxItems: 8 + items: + - description: regions used for DMA allocations like vrings, vring buffers + and memory dedicated to firmware's specific purposes. + additionalItems: true + +required: + - compatible + - reg + - reg-names + - ti,sci + - ti,sci-dev-id + - ti,sci-proc-ids + - resets + - firmware-name + +unevaluatedProperties: false + +examples: + - | + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + + mcu_m4fss_dma_memory_region: m4f-dma-memory@9cb00000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9cb00000 0x00 0x100000>; + no-map; + }; + + mcu_m4fss_memory_region: m4f-memory@9cc00000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9cc00000 0x00 0xe00000>; + no-map; + }; + }; + + soc { + #address-cells = <2>; + #size-cells = <2>; + + mailbox0_cluster0: mailbox-0 { + #mbox-cells = <1>; + }; + + remoteproc@5000000 { + compatible = "ti,am64-m4fss"; + reg = <0x00 0x5000000 0x00 0x30000>, + <0x00 0x5040000 0x00 0x10000>; + reg-names = "iram", "dram"; + resets = <&k3_reset 9 1>; + firmware-name = "am62-mcu-m4f0_0-fw"; + mboxes = <&mailbox0_cluster0>, <&mbox_m4_0>; + memory-region = <&mcu_m4fss_dma_memory_region>, + <&mcu_m4fss_memory_region>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <9>; + ti,sci-proc-ids = <0x18 0xff>; + }; + }; diff -Naur --no-dereference a/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml --- a/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -66,6 +66,17 @@ Should contain the name of the default firmware image file located on the firmware search path. + interrupts: + maxItems: 1 + description: + Interrupt specifiers enable the virtio/rpmsg communication between MPU + and the PRU/RTU cores. For the values of the interrupt cells please refer + to interrupt-controller/ti,pruss-intc.yaml schema. + + interrupt-names: + items: + - const: vring + if: properties: compatible: @@ -171,6 +182,9 @@ <0x22400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-pru0_0-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <16 2 2>; + interrupt-names = "vring"; }; rtu0_0: rtu@4000 { @@ -180,6 +194,9 @@ <0x23400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-rtu0_0-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <20 4 4>; + interrupt-names = "vring"; }; tx_pru0_0: txpru@a000 { @@ -198,6 +215,9 @@ <0x24400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-pru0_1-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <18 3 3>; + interrupt-names = "vring"; }; rtu0_1: rtu@6000 { @@ -207,6 +227,9 @@ <0x23c00 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-rtu0_1-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <22 5 5>; + interrupt-names = "vring"; }; tx_pru0_1: txpru@c000 { diff -Naur --no-dereference a/Documentation/devicetree/bindings/serial/8250_omap.yaml b/Documentation/devicetree/bindings/serial/8250_omap.yaml --- a/Documentation/devicetree/bindings/serial/8250_omap.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/serial/8250_omap.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -77,6 +77,22 @@ current-speed: true overrun-throttle-ms: true + pinctrl-0: + description: Default pinctrl state + + pinctrl-1: + description: Wakeup pinctrl state + + pinctrl-names: + description: + When present should contain at least "default" describing the default pin + states. The second state called "wakeup" describes the pins in their + wakeup configuration required to exit sleep states. + minItems: 1 + items: + - const: default + - const: wakeup + required: - compatible - reg diff -Naur --no-dereference a/Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml b/Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml --- a/Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -278,6 +278,26 @@ additionalProperties: false + ^pa-stats@[a-f0-9]+$: + description: | + PA-STATS sub-module represented as a SysCon. PA_STATS is a set of + registers where different statistics related to ICSSG, are dumped by + ICSSG firmware. This syscon sub-module will help the device to + access/read/write those statistics. + + type: object + + additionalProperties: false + + properties: + compatible: + items: + - const: ti,pruss-pa-st + - const: syscon + + reg: + maxItems: 1 + interrupt-controller@[a-f0-9]+$: description: | PRUSS INTC Node. Each PRUSS has a single interrupt controller instance diff -Naur --no-dereference a/Documentation/devicetree/bindings/usb/ti,am62-usb.yaml b/Documentation/devicetree/bindings/usb/ti,am62-usb.yaml --- a/Documentation/devicetree/bindings/usb/ti,am62-usb.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/usb/ti,am62-usb.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -14,7 +14,10 @@ const: ti,am62-usb reg: - maxItems: 1 + minItems: 1 + items: + - description: USB CFG register space + - description: USB PHY2 register space ranges: true @@ -82,7 +85,8 @@ usbss1: usb@f910000 { compatible = "ti,am62-usb"; - reg = <0x00 0x0f910000 0x00 0x800>; + reg = <0x00 0x0f910000 0x00 0x800>, + <0x00 0x0f918000 0x00 0x400>; clocks = <&k3_clks 162 3>; clock-names = "ref"; ti,syscon-phy-pll-refclk = <&wkup_conf 0x4018>; diff -Naur --no-dereference a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml --- a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -20,7 +20,26 @@ enum: - ti,tps6598x - apple,cd321x + - ti,tps25750 + reg: + minItems: 1 + items: + - description: main PD controller address + - description: | + I2C slave address field in PBMs input data + which is used as the device address when writing the + patch for TPS25750. + The patch address can be any value except 0x00, 0x20, + 0x21, 0x22, and 0x23 + + reg-names: + items: + - const: main + - const: patch-address + + reset-gpios: + description: GPIO used for the HRESET pin. maxItems: 1 wakeup-source: true @@ -32,14 +51,47 @@ items: - const: irq + firmware-name: + description: | + Should contain the name of the default patch binary + file located on the firmware search path which is + used to switch the controller into APP mode. + This is used when tps25750 doesn't have an EEPROM + connected to it. + maxItems: 1 + required: - compatible - reg +allOf: + - if: + properties: + compatible: + contains: + const: ti,tps25750 + then: + properties: + reg: + maxItems: 2 + + connector: + required: + - data-role + + required: + - connector + - reg-names + else: + properties: + reg: + maxItems: 1 + additionalProperties: true examples: - | + #include #include i2c { #address-cells = <1>; @@ -56,6 +108,7 @@ pinctrl-names = "default"; pinctrl-0 = <&typec_pins>; + reset-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; typec_con: connector { compatible = "usb-c-connector"; @@ -65,6 +118,38 @@ remote-endpoint = <&otg_ep>; }; }; + }; + }; + }; + + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + typec@21 { + compatible = "ti,tps25750"; + reg = <0x21>, <0x0f>; + reg-names = "main", "patch-address"; + + interrupt-parent = <&msmgpio>; + interrupts = <100 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; + firmware-name = "tps25750.bin"; + + pinctrl-names = "default"; + pinctrl-0 = <&typec_pins>; + + typec_con0: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + port { + typec_ep0: endpoint { + remote-endpoint = <&otg_ep>; + }; + }; }; }; }; diff -Naur --no-dereference a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml 2024-07-07 20:37:34.616306409 -0400 @@ -759,6 +759,8 @@ description: Lichee Pi "^linaro,.*": description: Linaro Limited + "^lincolntech,.*": + description: Lincoln Technology Solutions "^lineartechnology,.*": description: Linear Technology "^linksprite,.*": @@ -859,6 +861,8 @@ description: Microsoft Corporation "^microsys,.*": description: MicroSys Electronics GmbH + "^microtips,.*": + description: Microtips Technology USA "^mikroe,.*": description: MikroElektronika d.o.o. "^mikrotik,.*": diff -Naur --no-dereference a/Documentation/driver-api/media/v4l2-core.rst b/Documentation/driver-api/media/v4l2-core.rst --- a/Documentation/driver-api/media/v4l2-core.rst 2024-05-25 10:22:56.000000000 -0400 +++ b/Documentation/driver-api/media/v4l2-core.rst 2024-07-07 20:37:34.616306409 -0400 @@ -27,3 +27,4 @@ v4l2-tuner v4l2-common v4l2-tveeprom + v4l2-jpeg diff -Naur --no-dereference a/Documentation/driver-api/media/v4l2-jpeg.rst b/Documentation/driver-api/media/v4l2-jpeg.rst --- a/Documentation/driver-api/media/v4l2-jpeg.rst 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/driver-api/media/v4l2-jpeg.rst 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,10 @@ +.. SPDX-License-Identifier: GPL-2.0 + +V4L2 JPEG header related functions and data structures +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. kernel-doc:: include/media/v4l2-jpeg.h + :internal: + +.. kernel-doc:: drivers/media/v4l2-core/v4l2-jpeg.c + :export: diff -Naur --no-dereference a/Documentation/networking/device_drivers/ethernet/ti/cpsw_proxy_client.rst b/Documentation/networking/device_drivers/ethernet/ti/cpsw_proxy_client.rst --- a/Documentation/networking/device_drivers/ethernet/ti/cpsw_proxy_client.rst 1969-12-31 19:00:00.000000000 -0500 +++ b/Documentation/networking/device_drivers/ethernet/ti/cpsw_proxy_client.rst 2024-07-07 20:37:34.616306409 -0400 @@ -0,0 +1,182 @@ +.. SPDX-License-Identifier: GPL-2.0-only or MIT + +========================================== +Texas Instruments CPSW Proxy Client driver +========================================== + +Introduction +============ + +The CPSW (Common Platform Switch) Ethernet Switch on TI's K3 SoCs provides +Ethernet functionality. There may be multiple instances of CPSW on a single +SoC. The term "CPSWnG" is used to indicate the number of MAC Ports supported +by a specific instance of CPSW. CPSWnG indicates that the peripheral has +(n-1) MAC Ports and 1 Host Port. Examples of existing instances are: +CPSW2G => 1 MAC Port and 1 Host Port +CPSW3G => 2 MAC Ports and 1 Host Port +CPSW5G => 4 MAC Ports and 1 Host Port +CPSW9G => 8 MAC Ports and 1 Host Port + +The presence of 2 or more MAC Ports implies that Hardware Switching can +be enabled between the MAC Ports if required. + +The "am65-cpsw-nuss.c" driver in Linux at: +drivers/net/ethernet/ti/am65-cpsw-nuss.c +provides Ethernet functionality for applications on Linux. +It also handles both the control-path and data-path, namely: +Control => Configuration of the CPSW Peripheral +Data => Configuration of the DMA Channels to transmit/receive data + +The aforementioned configuration supports use-cases where all applications +which require Ethernet functionality are only running on Linux. + +However, there are use-cases where applications running on different +Operating Systems across multiple cores on the SoC require Ethernet +functionality. Such use-cases can be supported by implementing a +Client-Server model to share the data-path among Clients while the Server +owns the control-path. + +On TI's K3 SoCs (J721E, J7200 and J784S4 in particular), the Ethernet Switch +Firmware (EthFw) running on the MAIN R5F core acts as the Server and +configures the CPSWnG instance (CPSW5G on J7200 and CPSW9G on J721E, J784S4) +of the CPSW Ethernet Switch on the SoC. The Clients running on various cores +communicate with EthFw via RPMsg (Remote Processor Messaging) to request +resource allocation details during initialization, followed by requesting +EthFw to enable features supported by CPSW based on the features required +by the applications running on the respective cores. + +EthFw handles requests from the Clients and evaluates them before configuring +CPSW based on the request. Since no Client is actually in control of CPSW and +only requests EthFw for configuring CPSW, EthFw acts as the proxy for the +Clients. Thus, the Linux Client which interfaces with EthFw is named: +CPSW Proxy Client + +The data-path for the CPSW Proxy Client driver remains identical to the +"am65-cpsw-nuss.c" driver which happens to be DMA. It is only the control-path +that is different. + +Client-Server discovery occurs over the RPMsg-Bus. EthFw announces its +RPMsg Endpoint name over the RPMsg-Bus. The CPSW Proxy Client driver +registers itself with the Linux RPMsg framework to be probed for the same +Endpoint name. Following probe, the Linux Client driver begins communicating +with EthFw and queries details of the resources available for the Linux Client. + +Terminology +=========== + +Virtual Port + A Virtual Port refers to the Software View of an Ethernet MAC Port. + There are two types of Virtual Ports: + 1. Virtual MAC Only Port + 2. Virtual Switch Port + +Virtual MAC Only Port + A Virtual MAC only Port refers to a dedicated physical MAC Port for + a Client. This corresponds to MAC Mode of operation in Ethernet + Terminology. All traffic sent to or received from the Physical + MAC Port is that of the Client to which the Virtual MAC Only Port + has been allocated. + +Virtual Switch Port + A Virtual Switch Port refers to a group of physical MAC ports with + Switching enabled across them. This implies that any traffic sent + to the Port from a Client could potentially exit a Physical MAC + Port along with the traffic from other Clients. Similarly, the traffic + received on the Port by a Client could have potentially ingressed + on a Physical MAC Port along with the traffic meant for other Clients. + While the ALE (Address Lookup Engine) handles segregating the traffic, + and the CPSW Ethernet Switch places traffic on dedicated RX DMA Flows + meant for a single Client, it is worth noting that the bandwidths + of the Physical MAC Port are shared by Clients when traffic is sent to + or received from a Virtual Switch Port. + +Network Interface + The user-visible interface in Linux userspace exposed to applications + that serves as the entry/exit point for traffic to/from the Virtual + Ports. A single network interface (ethX) maps to either a Virtual + MAC Only Port or a Virtual Switch Port. + +C2S + RPMsg source is Client and destination is Server. + +S2C + RPMsg source is Server and destination is Client. + +Initialization Sequence +======================= + +The sequence of message exchanges between the Client driver and EthFw starting +from the driver probe and ending with the interfaces being brought up is as +follows: +1. C2S ETHFW_VIRT_PORT_INFO requesting details of Virtual Ports available + for the Linux Client. +2. S2C response containing requested details +3. C2S ETHFW_VIRT_PORT_ATTACH request for each Virtual Port allocated during + step 2. +4. S2C response containing details of the MTU Size, number of Tx DMA Channels + and RX DMA Flows for the specified Virtual Port. The *Features* associated + with the Virtual Port are also shared such as Multicast Filtering capability. +5. C2S ETHFW_ALLOC_RX request for each RX DMA Flow for a Virtual Port. +6. S2C response containing details of the RX PSI-L Thread ID, Flow base and + Flow offset. +7. C2S ETHFW_ALLOC_TX request for each TX DMA Channel for a Virtual Port. +8. S2C response containing details of the TX PSI-L Thread ID. +9. C2S ETHFW_ALLOC_MAC request for each Virtual Port. +10. S2C response containing the MAC Address corresponding to the Virtual Port. +11. C2S ETHFW_MAC_REGISTER request for each Virtual Port with the MAC Address + allocated in step 10. This is necessary to steer packets that ingress on + the MAC Ports of CPSW onto the RX DMA Flow for the Virtual Port in order + to allow the Client to receive the packets. +12. S2C response indicating status of request. +13. C2S ETHFW_IPv4_REGISTER request *only* for Virtual Switch Port interface. + The IPv4 address assigned to the "ethX" network interface in Linux + corresponding to the Virtual Switch Port interface has to be registered + with EthFw. This is due to the reason that all Broadcast requests including + ARP requests received by the MAC Ports corresponding to the Virtual Switch + Port are consumed solely be EthFw. Such traffic is sent to Clients by + alternate methods. Therefore EthFw needs to know the IPv4 address for the + "ethX" network interface in Linux in order to automatically respond to + ARP requests, thereby enabling Unicast communication. +14. S2C response indicating status of request. +15. C2S ETHFW_MCAST_FILTER_ADD request to register the Multicast Addresses + associated with the network interface corresponding to the Virtual Port + which has the Multicast Filtering capability. +16. S2C response indicating status of request. +17. C2S ETHFW_MCAST_FILTER_DEL request to deregister the Multicast Addresses + associated with the network interface corresponding to the Virtual Port + which has the Multicast Filtering capability. +18. S2C response indicating status of request. + +Shutdown Sequence +================= + +The sequence of message exchanges between the Client driver and EthFw on module +removal are as follows: +1. C2S ETHFW_MAC_DEREGISTER request to deregister the MAC Address for each + Virtual Port. +2. S2C response indicating status of request. +3. C2S ETHFW_MCAST_FILTER_DEL request to deregister the Multicast Addresses + associated with the network interface corresponding to the Virtual Port + which has the Multicast Filtering capability. +4. S2C response indicating status of request. +5. C2S ETHFW_FREE_MAC request to release the MAC Address allocated to each + Virtual Port. +6. S2C response indicating status of request. +7. C2S ETHFW_FREE_TX request to release the TX DMA Channel for each TX Channel + for every Virtual Port. +8. S2C response indicating status of request. +9. C2S ETHFW_FREE_RX request to release the RX DMA Flow for each RX Channel + for every Virtual Port. +10. S2C response indicating status of request. +11. C2S ETHFW_VIRT_PORT_DETACH request to release each Virtual Port. +12. S2C response indicating status of request. + +Features Supported +================== + +The set of features supported in addition to providing basic Ethernet +Functionality are: +1. Multicast Filtering +2. Determining Link Status of the network interface corresponding to the + Virtual MAC Only port via ethtool. +3. Interrupt Pacing/Coalescing diff -Naur --no-dereference a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c --- a/drivers/android/binder_alloc.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/android/binder_alloc.c 2024-07-07 20:37:34.640306529 -0400 @@ -38,7 +38,7 @@ }; static uint32_t binder_alloc_debug_mask = BINDER_DEBUG_USER_ERROR; -module_param_named(debug_mask, binder_alloc_debug_mask, +module_param_named(alloc_debug_mask, binder_alloc_debug_mask, uint, 0644); #define binder_alloc_debug(mask, x...) \ diff -Naur --no-dereference a/drivers/android/Kconfig b/drivers/android/Kconfig --- a/drivers/android/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/android/Kconfig 2024-07-07 20:37:34.640306529 -0400 @@ -2,7 +2,7 @@ menu "Android" config ANDROID_BINDER_IPC - bool "Android Binder IPC Driver" + tristate "Android Binder IPC Driver" depends on MMU default n help diff -Naur --no-dereference a/drivers/android/Makefile b/drivers/android/Makefile --- a/drivers/android/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/android/Makefile 2024-07-07 20:37:34.640306529 -0400 @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only ccflags-y += -I$(src) # needed for trace events -obj-$(CONFIG_ANDROID_BINDERFS) += binderfs.o -obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o -obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o +obj-$(CONFIG_ANDROID_BINDER_IPC) += binder_linux.o +binder_linux-y := binder.o binder_alloc.o +binder_linux-$(CONFIG_ANDROID_BINDERFS) += binderfs.o +binder_linux-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o diff -Naur --no-dereference a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c --- a/drivers/clk/keystone/sci-clk.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/clk/keystone/sci-clk.c 2024-07-07 20:37:34.640306529 -0400 @@ -516,6 +516,7 @@ struct sci_clk *sci_clk, *prev; int num_clks = 0; int num_parents; + bool state; int clk_id; const char * const clk_names[] = { "clocks", "assigned-clocks", "assigned-clock-parents", NULL @@ -586,6 +587,15 @@ clk_id = args.args[1] + 1; while (num_parents--) { + /* Check if this clock id is valid */ + ret = provider->ops->is_auto(provider->sci, + sci_clk->dev_id, clk_id, &state); + + if (ret) { + clk_id++; + continue; + } + sci_clk = devm_kzalloc(dev, sizeof(*sci_clk), GFP_KERNEL); diff -Naur --no-dereference a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c --- a/drivers/clocksource/timer-ti-dm.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/clocksource/timer-ti-dm.c 2024-07-07 20:37:34.640306529 -0400 @@ -1105,8 +1105,12 @@ return -ENOMEM; timer->irq = platform_get_irq(pdev, 0); - if (timer->irq < 0) - return timer->irq; + if (timer->irq < 0) { + if (of_property_read_bool(dev->of_node, "ti,timer-pwm")) + dev_err(dev, "Did not find timer interrupt, timer usable in PWM mode only\n"); + else + return timer->irq; + } timer->io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(timer->io_base)) diff -Naur --no-dereference a/drivers/counter/Kconfig b/drivers/counter/Kconfig --- a/drivers/counter/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/counter/Kconfig 2024-07-07 20:37:34.640306529 -0400 @@ -138,7 +138,7 @@ config TI_EQEP tristate "TI eQEP counter driver" - depends on (SOC_AM33XX || COMPILE_TEST) + depends on SOC_AM33XX || ARCH_K3 || COMPILE_TEST select REGMAP_MMIO help Select this option to enable the Texas Instruments Enhanced Quadrature diff -Naur --no-dereference a/drivers/counter/ti-eqep.c b/drivers/counter/ti-eqep.c --- a/drivers/counter/ti-eqep.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/counter/ti-eqep.c 2024-07-07 20:37:34.640306529 -0400 @@ -6,7 +6,9 @@ */ #include +#include #include +#include #include #include #include @@ -67,6 +69,59 @@ #define QEPCTL_UTE BIT(1) #define QEPCTL_WDE BIT(0) +#define QEINT_UTO BIT(11) +#define QEINT_IEL BIT(10) +#define QEINT_SEL BIT(9) +#define QEINT_PCM BIT(8) +#define QEINT_PCR BIT(7) +#define QEINT_PCO BIT(6) +#define QEINT_PCU BIT(5) +#define QEINT_WTO BIT(4) +#define QEINT_QDC BIT(3) +#define QEINT_PHE BIT(2) +#define QEINT_PCE BIT(1) + +#define QFLG_UTO BIT(11) +#define QFLG_IEL BIT(10) +#define QFLG_SEL BIT(9) +#define QFLG_PCM BIT(8) +#define QFLG_PCR BIT(7) +#define QFLG_PCO BIT(6) +#define QFLG_PCU BIT(5) +#define QFLG_WTO BIT(4) +#define QFLG_QDC BIT(3) +#define QFLG_PHE BIT(2) +#define QFLG_PCE BIT(1) +#define QFLG_INT BIT(0) + +#define QCLR_UTO BIT(11) +#define QCLR_IEL BIT(10) +#define QCLR_SEL BIT(9) +#define QCLR_PCM BIT(8) +#define QCLR_PCR BIT(7) +#define QCLR_PCO BIT(6) +#define QCLR_PCU BIT(5) +#define QCLR_WTO BIT(4) +#define QCLR_QDC BIT(3) +#define QCLR_PHE BIT(2) +#define QCLR_PCE BIT(1) +#define QCLR_INT BIT(0) + +#define QEPSTS_UPEVNT BIT(7) +#define QEPSTS_FDF BIT(6) +#define QEPSTS_QDF BIT(5) +#define QEPSTS_QDLF BIT(4) +#define QEPSTS_COEF BIT(3) +#define QEPSTS_CDEF BIT(2) +#define QEPSTS_FIMF BIT(1) +#define QEPSTS_PCEF BIT(0) + +#define QCAPCTL_CEN BIT(15) +#define QCAPCTL_CCPS_SHIFT 4 +#define QCAPCTL_CCPS GENMASK(6, 4) +#define QCAPCTL_UPPS_SHIFT 0 +#define QCAPCTL_UPPS GENMASK(3, 0) + /* EQEP Inputs */ enum { TI_EQEP_SIGNAL_QEPA, /* QEPA/XCLK */ @@ -83,6 +138,7 @@ struct ti_eqep_cnt { struct counter_device counter; + unsigned long clock_rate; struct regmap *regmap32; struct regmap *regmap16; }; @@ -238,12 +294,54 @@ } } +static int ti_eqep_events_configure(struct counter_device *counter) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + struct counter_event_node *event_node; + u32 qeint = 0; + + list_for_each_entry(event_node, &counter->events_list, l) { + switch (event_node->event) { + case COUNTER_EVENT_OVERFLOW: + qeint |= QEINT_PCO; + break; + case COUNTER_EVENT_UNDERFLOW: + qeint |= QEINT_PCU; + break; + case COUNTER_EVENT_DIRECTION_CHANGE: + qeint |= QEINT_QDC; + break; + case COUNTER_EVENT_TIMEOUT: + qeint |= QEINT_UTO; + break; + } + } + + return regmap_write_bits(priv->regmap16, QEINT, qeint, ~0); +} + +static int ti_eqep_watch_validate(struct counter_device *counter, + const struct counter_watch *watch) +{ + switch (watch->event) { + case COUNTER_EVENT_OVERFLOW: + case COUNTER_EVENT_UNDERFLOW: + case COUNTER_EVENT_DIRECTION_CHANGE: + case COUNTER_EVENT_TIMEOUT: + return 0; + default: + return -EINVAL; + } +} + static const struct counter_ops ti_eqep_counter_ops = { .count_read = ti_eqep_count_read, .count_write = ti_eqep_count_write, .function_read = ti_eqep_function_read, .function_write = ti_eqep_function_write, .action_read = ti_eqep_action_read, + .events_configure = ti_eqep_events_configure, + .watch_validate = ti_eqep_watch_validate, }; static int ti_eqep_position_ceiling_read(struct counter_device *counter, @@ -265,11 +363,17 @@ u64 ceiling) { struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 qposmax = ceiling; - if (ceiling != (u32)ceiling) + /* ensure that value fits in 32-bit register */ + if (qposmax != ceiling) return -ERANGE; - regmap_write(priv->regmap32, QPOSMAX, ceiling); + /* protect against infinite overflow interrupts */ + if (qposmax == 0) + return -EINVAL; + + regmap_write(priv->regmap32, QPOSMAX, qposmax); return 0; } @@ -297,11 +401,43 @@ return 0; } +static int ti_eqep_direction_read(struct counter_device *counter, + struct counter_count *count, + enum counter_count_direction *direction) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 qepsts; + + regmap_read(priv->regmap16, QEPSTS, &qepsts); + + *direction = (qepsts & QEPSTS_QDF) ? COUNTER_COUNT_DIRECTION_FORWARD + : COUNTER_COUNT_DIRECTION_BACKWARD; + + return 0; +} + +static int ti_eqep_position_latched_count_read(struct counter_device *counter, + struct counter_count *count, + u64 *value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 qposlat; + + regmap_read(priv->regmap32, QPOSLAT, &qposlat); + + *value = qposlat; + + return 0; +} + static struct counter_comp ti_eqep_position_ext[] = { COUNTER_COMP_CEILING(ti_eqep_position_ceiling_read, ti_eqep_position_ceiling_write), COUNTER_COMP_ENABLE(ti_eqep_position_enable_read, ti_eqep_position_enable_write), + COUNTER_COMP_DIRECTION(ti_eqep_direction_read), + COUNTER_COMP_COUNT_U64("latched_count", + ti_eqep_position_latched_count_read, NULL), }; static struct counter_signal ti_eqep_signals[] = { @@ -354,6 +490,314 @@ }, }; +static int ti_eqep_edge_capture_unit_enable_read(struct counter_device *counter, + u8 *value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 qcapctl; + + regmap_read(priv->regmap16, QCAPCTL, &qcapctl); + *value = !!(qcapctl & QCAPCTL_CEN); + + return 0; +} + +static int ti_eqep_edge_capture_unit_enable_write(struct counter_device *counter, + u8 value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + + if (value) + regmap_set_bits(priv->regmap16, QCAPCTL, QCAPCTL_CEN); + else + regmap_clear_bits(priv->regmap16, QCAPCTL, QCAPCTL_CEN); + + return 0; +} + +static int ti_eqep_edge_capture_unit_latched_period_read(struct counter_device *counter, + u64 *value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 qcprdlat, qcapctl; + u8 ccps; + + regmap_read(priv->regmap16, QCPRDLAT, &qcprdlat); + regmap_read(priv->regmap16, QCAPCTL, &qcapctl); + ccps = (qcapctl & QCAPCTL_CCPS) >> QCAPCTL_CCPS_SHIFT; + + /* convert timer ticks to nanoseconds */ + *value = mul_u64_u32_div(qcprdlat << ccps, NSEC_PER_SEC, priv->clock_rate); + + return 0; +} + +static int ti_eqep_edge_capture_unit_max_period_read(struct counter_device *counter, + u64 *value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 qcapctl; + u8 ccps; + + regmap_read(priv->regmap16, QCAPCTL, &qcapctl); + ccps = (qcapctl & QCAPCTL_CCPS) >> QCAPCTL_CCPS_SHIFT; + + /* convert timer ticks to nanoseconds */ + *value = mul_u64_u32_div(USHRT_MAX << ccps, NSEC_PER_SEC, + priv->clock_rate); + + return 0; +} + +static int ti_eqep_edge_capture_unit_max_period_write(struct counter_device *counter, + u64 value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 period; + u8 ccps; + + /* convert nanoseconds to timer ticks */ + period = value = mul_u64_u32_div(value, priv->clock_rate, NSEC_PER_SEC); + if (period != value) + return -ERANGE; + + /* find the smallest divider that will fit the requested period */ + for (ccps = 0; ccps <= 7; ccps++) + if (USHRT_MAX << ccps >= period) + break; + + if (ccps > 7) + return -EINVAL; + + regmap_write_bits(priv->regmap16, QCAPCTL, QCAPCTL_CCPS, + ccps << QCAPCTL_CCPS_SHIFT); + + return 0; +} + +static int ti_eqep_edge_capture_unit_prescaler_read(struct counter_device *counter, + u32 *value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 qcapctl; + + regmap_read(priv->regmap16, QCAPCTL, &qcapctl); + *value = (qcapctl & QCAPCTL_UPPS) >> QCAPCTL_UPPS_SHIFT; + + return 0; +} + +static int ti_eqep_edge_capture_unit_prescaler_write(struct counter_device *counter, + u32 value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + + regmap_write_bits(priv->regmap16, QCAPCTL, QCAPCTL_UPPS, + value << QCAPCTL_UPPS_SHIFT); + + return 0; +} + +static const char *const ti_eqep_edge_capture_unit_prescaler_values[] = { + "1", + "2", + "4", + "8", + "16", + "32", + "64", + "128", + "256", + "512", + "1024", + "2048", +}; + +static DEFINE_COUNTER_ENUM(ti_eqep_edge_capture_unit_prescaler_available, + ti_eqep_edge_capture_unit_prescaler_values); + +static int ti_eqep_latch_mode_read(struct counter_device *counter, + u32 *value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 qepctl; + + regmap_read(priv->regmap16, QEPCTL, &qepctl); + *value = !!(qepctl & QEPCTL_QCLM); + + return 0; +} + +static int ti_eqep_latch_mode_write(struct counter_device *counter, + u32 value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + + if (value) + regmap_set_bits(priv->regmap16, QEPCTL, QEPCTL_QCLM); + else + regmap_clear_bits(priv->regmap16, QEPCTL, QEPCTL_QCLM); + + return 0; +} + +static const char *const ti_eqep_latch_mode_names[] = { + "Read count", + "Unit timeout", +}; + +static DEFINE_COUNTER_ENUM(ti_eqep_latch_modes, ti_eqep_latch_mode_names); + +static int ti_eqep_unit_timer_time_read(struct counter_device *counter, + u64 *value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 qutmr; + + regmap_read(priv->regmap32, QUTMR, &qutmr); + + /* convert timer ticks to nanoseconds */ + *value = mul_u64_u32_div(qutmr, NSEC_PER_SEC, priv->clock_rate); + + return 0; +} + +static int ti_eqep_unit_timer_time_write(struct counter_device *counter, + u64 value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 qutmr; + + /* convert nanoseconds to timer ticks */ + qutmr = value = mul_u64_u32_div(value, priv->clock_rate, NSEC_PER_SEC); + if (qutmr != value) + return -ERANGE; + + regmap_write(priv->regmap32, QUTMR, qutmr); + + return 0; +} + +static int ti_eqep_unit_timer_period_read(struct counter_device *counter, + u64 *value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 quprd; + + regmap_read(priv->regmap32, QUPRD, &quprd); + + /* convert timer ticks to nanoseconds */ + *value = mul_u64_u32_div(quprd, NSEC_PER_SEC, priv->clock_rate); + + return 0; +} + +static int ti_eqep_unit_timer_period_write(struct counter_device *counter, + u64 value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 quprd; + + /* convert nanoseconds to timer ticks */ + quprd = value = mul_u64_u32_div(value, priv->clock_rate, NSEC_PER_SEC); + if (quprd != value) + return -ERANGE; + + /* protect against infinite unit timeout interrupts */ + if (quprd == 0) + return -EINVAL; + + regmap_write(priv->regmap32, QUPRD, quprd); + + return 0; +} + +static int ti_eqep_unit_timer_enable_read(struct counter_device *counter, + u8 *value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + u32 qepctl; + + regmap_read(priv->regmap16, QEPCTL, &qepctl); + *value = !!(qepctl & QEPCTL_UTE); + + return 0; +} + +static int ti_eqep_unit_timer_enable_write(struct counter_device *counter, + u8 value) +{ + struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + + if (value) + regmap_set_bits(priv->regmap16, QEPCTL, QEPCTL_UTE); + else + regmap_clear_bits(priv->regmap16, QEPCTL, QEPCTL_UTE); + + return 0; +} + +static struct counter_comp ti_eqep_device_ext[] = { + COUNTER_COMP_DEVICE_BOOL("edge_capture_unit_enable", + ti_eqep_edge_capture_unit_enable_read, + ti_eqep_edge_capture_unit_enable_write), + COUNTER_COMP_DEVICE_U64("edge_capture_unit_latched_period", + ti_eqep_edge_capture_unit_latched_period_read, + NULL), + COUNTER_COMP_DEVICE_U64("edge_capture_unit_max_period", + ti_eqep_edge_capture_unit_max_period_read, + ti_eqep_edge_capture_unit_max_period_write), + COUNTER_COMP_DEVICE_ENUM("edge_capture_unit_prescaler", + ti_eqep_edge_capture_unit_prescaler_read, + ti_eqep_edge_capture_unit_prescaler_write, + ti_eqep_edge_capture_unit_prescaler_available), + COUNTER_COMP_DEVICE_ENUM("latch_mode", ti_eqep_latch_mode_read, + ti_eqep_latch_mode_write, ti_eqep_latch_modes), + COUNTER_COMP_DEVICE_U64("unit_timer_time", ti_eqep_unit_timer_time_read, + ti_eqep_unit_timer_time_write), + COUNTER_COMP_DEVICE_U64("unit_timer_period", + ti_eqep_unit_timer_period_read, + ti_eqep_unit_timer_period_write), + COUNTER_COMP_DEVICE_BOOL("unit_timer_enable", + ti_eqep_unit_timer_enable_read, + ti_eqep_unit_timer_enable_write), +}; + +static irqreturn_t ti_eqep_irq_handler(int irq, void *dev_id) +{ + struct ti_eqep_cnt *priv = dev_id; + struct counter_device *counter = &priv->counter; + u32 qflg; + u32 qclr = 0; + + regmap_read(priv->regmap16, QFLG, &qflg); + + if (qflg & QFLG_PCO) { + qclr |= QFLG_PCO; + counter_push_event(counter, COUNTER_EVENT_OVERFLOW, 0); + } + + if (qflg & QFLG_PCU) { + qclr |= QFLG_PCU; + counter_push_event(counter, COUNTER_EVENT_UNDERFLOW, 0); + } + + if (qflg & QFLG_QDC) { + qclr |= QFLG_QDC; + counter_push_event(counter, COUNTER_EVENT_DIRECTION_CHANGE, 0); + } + + if (qflg & QFLG_UTO) { + qclr |= QFLG_UTO; + counter_push_event(counter, COUNTER_EVENT_TIMEOUT, 0); + } + + qclr |= QCLR_INT; + regmap_write_bits(priv->regmap16, QCLR, qclr, ~0); + + return IRQ_HANDLED; +} + static const struct regmap_config ti_eqep_regmap32_config = { .name = "32-bit", .reg_bits = 32, @@ -375,14 +819,29 @@ struct device *dev = &pdev->dev; struct counter_device *counter; struct ti_eqep_cnt *priv; + struct clk *clk; void __iomem *base; int err; + int irq; counter = devm_counter_alloc(dev, sizeof(*priv)); if (!counter) return -ENOMEM; priv = counter_priv(counter); + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(dev, "failed to get clock"); + return PTR_ERR(clk); + } + + priv->clock_rate = clk_get_rate(clk); + if (priv->clock_rate == 0) { + dev_err(dev, "failed to get clock rate"); + return -EINVAL; + } + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); @@ -397,11 +856,22 @@ if (IS_ERR(priv->regmap16)) return PTR_ERR(priv->regmap16); + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + err = devm_request_threaded_irq(dev, irq, NULL, ti_eqep_irq_handler, + IRQF_ONESHOT, dev_name(dev), priv); + if (err < 0) + return err; + counter->name = dev_name(dev); counter->parent = dev; counter->ops = &ti_eqep_counter_ops; counter->counts = ti_eqep_counts; counter->num_counts = ARRAY_SIZE(ti_eqep_counts); + counter->ext = ti_eqep_device_ext; + counter->num_ext = ARRAY_SIZE(ti_eqep_device_ext); counter->signals = ti_eqep_signals; counter->num_signals = ARRAY_SIZE(ti_eqep_signals); @@ -415,6 +885,14 @@ pm_runtime_enable(dev); pm_runtime_get_sync(dev); + /* + * We can end up with an interrupt infinite loop (interrupts triggered + * as soon as they are cleared) if we leave these at the default value + * of 0 and events are enabled. + */ + regmap_write(priv->regmap32, QPOSMAX, UINT_MAX); + regmap_write(priv->regmap32, QUPRD, UINT_MAX); + err = counter_add(counter); if (err < 0) { pm_runtime_put_sync(dev); @@ -439,6 +917,7 @@ static const struct of_device_id ti_eqep_of_match[] = { { .compatible = "ti,am3352-eqep", }, + { .compatible = "ti,am62-eqep", }, { }, }; MODULE_DEVICE_TABLE(of, ti_eqep_of_match); diff -Naur --no-dereference a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c --- a/drivers/cpufreq/cpufreq-dt-platdev.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/cpufreq/cpufreq-dt-platdev.c 2024-07-07 20:37:34.640306529 -0400 @@ -176,6 +176,7 @@ { .compatible = "ti,omap3", }, { .compatible = "ti,am625", }, { .compatible = "ti,am62a7", }, + { .compatible = "ti,am62p5", }, { .compatible = "qcom,ipq8064", }, { .compatible = "qcom,apq8064", }, diff -Naur --no-dereference a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c --- a/drivers/cpufreq/ti-cpufreq.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/cpufreq/ti-cpufreq.c 2024-07-07 20:37:34.640306529 -0400 @@ -42,6 +42,8 @@ #define AM625_EFUSE_K_MPU_OPP 11 #define AM625_EFUSE_S_MPU_OPP 19 #define AM625_EFUSE_T_MPU_OPP 20 +#define AM625_EFUSE_U_MPU_OPP 21 +#define AM625_EFUSE_V_MPU_OPP 22 #define AM625_SUPPORT_K_MPU_OPP BIT(0) #define AM625_SUPPORT_S_MPU_OPP BIT(1) @@ -118,6 +120,8 @@ unsigned long calculated_efuse = AM625_SUPPORT_K_MPU_OPP; switch (efuse) { + case AM625_EFUSE_V_MPU_OPP: + case AM625_EFUSE_U_MPU_OPP: case AM625_EFUSE_T_MPU_OPP: calculated_efuse |= AM625_SUPPORT_T_MPU_OPP; fallthrough; @@ -338,6 +342,7 @@ { .compatible = "ti,omap36xx", .data = &omap36xx_soc_data, }, { .compatible = "ti,am625", .data = &am625_soc_data, }, { .compatible = "ti,am62a7", .data = &am625_soc_data, }, + { .compatible = "ti,am62p5", .data = &am625_soc_data, }, /* legacy */ { .compatible = "ti,omap3430", .data = &omap34xx_soc_data, }, { .compatible = "ti,omap3630", .data = &omap36xx_soc_data, }, diff -Naur --no-dereference a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig --- a/drivers/crypto/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/crypto/Kconfig 2024-07-07 20:37:34.640306529 -0400 @@ -796,5 +796,6 @@ source "drivers/crypto/aspeed/Kconfig" source "drivers/crypto/starfive/Kconfig" +source "drivers/crypto/ti/Kconfig" endif # CRYPTO_HW diff -Naur --no-dereference a/drivers/crypto/Makefile b/drivers/crypto/Makefile --- a/drivers/crypto/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/crypto/Makefile 2024-07-07 20:37:34.640306529 -0400 @@ -41,6 +41,7 @@ obj-$(CONFIG_CRYPTO_DEV_SL3516) += gemini/ obj-y += stm32/ obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o +obj-$(CONFIG_CRYPTO_DEV_TI_MCRC64) += ti/ obj-$(CONFIG_CRYPTO_DEV_VIRTIO) += virtio/ obj-$(CONFIG_CRYPTO_DEV_VMX) += vmx/ obj-$(CONFIG_CRYPTO_DEV_BCM_SPU) += bcm/ diff -Naur --no-dereference a/drivers/crypto/ti/Kconfig b/drivers/crypto/ti/Kconfig --- a/drivers/crypto/ti/Kconfig 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/crypto/ti/Kconfig 2024-07-07 20:37:34.640306529 -0400 @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only +config CRYPTO_DEV_TI_MCRC64 + tristate "Texas Instruments MCRC64 engine support" + depends on ARCH_K3 || COMPILE_TEST + select CRYPTO_HASH + select CRYPTO_CRC64_ISO3309 + help + This enables support for the MCRC64 engine + which can be found on all AM62* and J722S devices. + MCRC64 engine calculates 64-bit cyclic redundancy checks (CRC) + according to the ISO 3309 standard. diff -Naur --no-dereference a/drivers/crypto/ti/Makefile b/drivers/crypto/ti/Makefile --- a/drivers/crypto/ti/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/crypto/ti/Makefile 2024-07-07 20:37:34.640306529 -0400 @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_CRYPTO_DEV_TI_MCRC64) += mcrc64.o diff -Naur --no-dereference a/drivers/crypto/ti/mcrc64.c b/drivers/crypto/ti/mcrc64.c --- a/drivers/crypto/ti/mcrc64.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/crypto/ti/mcrc64.c 2024-07-07 20:37:34.640306529 -0400 @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) Texas Instruments 2023 - http://www.ti.com + * Author: Kamlesh Gurudasani + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define DRIVER_NAME "mcrc64" +#define CHKSUM_DIGEST_SIZE 8 +#define CHKSUM_BLOCK_SIZE 1 + +/* Registers */ +#define CRC_CTRL0 0x0000 /* CRC Global Control Register 0 */ +#define CH_PSA_SWRE(ch) BIT(((ch) - 1) << 3) /* PSA Software Reset */ + +#define CRC_CTRL1 0x0008 /* CRC Global Control Register 1 */ +#define PWDN BIT(0) /* Power Down */ + +#define CRC_CTRL2 0x0010 /* CRC Global Control Register 2 */ +#define CH_MODE(ch, m) ((m) << (((ch) - 1) << 3)) + +#define PSA_SIGREGL(ch) ((0x6 + (4 * ((ch) - 1))) << 4) /* Signature register */ + +#define MCRC64_ALG_MASK 0x8000000000000000 +#define MCRC64_CRC64_POLY 0x000000000000001b + +#define MCRC64_AUTOSUSPEND_DELAY 50 + +enum mcrc64_mode { + MCRC64_MODE_DATA_CAPTURE = 0, + MCRC64_MODE_AUTO, + MCRC64_MODE_SEMI_CPU, + MCRC64_MODE_FULL_CPU, + MCRC64_MODE_INVALID, +}; + +enum mcrc64_channel { + MCRC64_CHANNEL_1 = 1, + MCRC64_CHANNEL_2, + MCRC64_CHANNEL_3, + MCRC64_CHANNEL_4, + MCRC64_CHANNEL_INVALID, +}; + +struct mcrc64_data { + struct list_head list; + struct device *dev; + void __iomem *regs; +}; + +struct mcrc64_list { + struct list_head dev_list; + spinlock_t lock; /* protect dev_list */ +}; + +static struct mcrc64_list mcrc64_dev_list = { + .dev_list = LIST_HEAD_INIT(mcrc64_dev_list.dev_list), + .lock = __SPIN_LOCK_UNLOCKED(mcrc64_dev_list.lock), +}; + +struct mcrc64_tfm_ctx { + struct mcrc64_data *dev_data; + u64 key; +}; + +struct mcrc64_desc_ctx { + u64 signature; +}; + +static struct mcrc64_data *mcrc64_get_dev(struct mcrc64_tfm_ctx *tctx) +{ + struct mcrc64_data *dev_data; + + if (tctx->dev_data) + return tctx->dev_data; + + spin_lock_bh(&mcrc64_dev_list.lock); + dev_data = list_first_entry(&mcrc64_dev_list.dev_list, struct mcrc64_data, list); + if (dev_data) + list_move_tail(&dev_data->list, &mcrc64_dev_list.dev_list); + spin_unlock_bh(&mcrc64_dev_list.lock); + + return dev_data; +} + +static int mcrc64_set_mode(void __iomem *regs, u32 channel, u32 mode) +{ + u32 mode_set_val; + u32 crc_ctrl2_reg = 0; + + if (mode < 0 || mode >= MCRC64_MODE_INVALID) + return -EINVAL; + + if (channel <= 0 || channel >= MCRC64_CHANNEL_INVALID) + return -EINVAL; + + mode_set_val = crc_ctrl2_reg | CH_MODE(channel, mode); + + /* Write CRC_CTRL2, set mode */ + writel_relaxed(mode_set_val, regs + CRC_CTRL2); + + return 0; +} + +static int mcrc64_reset_signature(void __iomem *regs, u32 channel) +{ + u32 crc_ctrl0_reg, reset_val, reset_undo_val; + + if (channel <= 0 || channel >= MCRC64_CHANNEL_INVALID) + return -EINVAL; + + /* reset PSA */ + crc_ctrl0_reg = readl_relaxed(regs + CRC_CTRL0); + + reset_val = crc_ctrl0_reg | CH_PSA_SWRE(channel); + reset_undo_val = crc_ctrl0_reg & ~CH_PSA_SWRE(channel); + + /* Write CRC_CTRL0 register, reset PSA register */ + writel_relaxed(reset_val, regs + CRC_CTRL0); + writel_relaxed(reset_undo_val, regs + CRC_CTRL0); + + return 0; +} + +/* This helper implements crc64 calculation using CPU */ +static u64 mcrc64_calculate_sw_crc(u64 crc, u8 byte) +{ + u64 bit = 0; + u8 j; + + for (j = 0; j < 8; j++) { + bit = crc & MCRC64_ALG_MASK; + crc <<= 1; + if (byte & (0x80 >> j)) + bit ^= MCRC64_ALG_MASK; + if (bit) + crc ^= MCRC64_CRC64_POLY; + } + + return crc; +} + +static int mcrc64_calculate_crc(void __iomem *regs, u32 channel, + const u8 *d8, size_t length, u64 *crc64) +{ + void __iomem *psa_reg; + u64 signature = 0; + + if (channel <= 0 || channel >= MCRC64_CHANNEL_INVALID) + return -EINVAL; + + psa_reg = regs + PSA_SIGREGL(channel); + + for (; length >= sizeof(u64); d8 += sizeof(u64), length -= sizeof(u64)) + writeq_relaxed(cpu_to_be64p((u64 *)d8), psa_reg); + + signature = readq_relaxed(psa_reg); + + if (length) { + while (length--) + signature = mcrc64_calculate_sw_crc(signature, *d8++); + + /* set capture mode */ + int ret = mcrc64_set_mode(regs, MCRC64_CHANNEL_1, + MCRC64_MODE_DATA_CAPTURE); + if (ret) + return ret; + + ret = mcrc64_reset_signature(regs, MCRC64_CHANNEL_1); + if (ret) + return ret; + + writeq_relaxed(signature, psa_reg); + + ret = mcrc64_set_mode(regs, MCRC64_CHANNEL_1, + MCRC64_MODE_FULL_CPU); + if (ret) + return ret; + } + + *crc64 = signature; + + return 0; +} + +static int mcrc64_cra_init(struct crypto_tfm *tfm) +{ + struct mcrc64_tfm_ctx *tctx = crypto_tfm_ctx(tfm); + struct mcrc64_data *dev_data; + + dev_data = mcrc64_get_dev(tctx); + if (!dev_data) + return -ENODEV; + + pm_runtime_get_sync(dev_data->dev); + + tctx->key = 0; + + return 0; +} + +static void mcrc64_cra_exit(struct crypto_tfm *tfm) +{ + struct mcrc64_tfm_ctx *tctx = crypto_tfm_ctx(tfm); + struct mcrc64_data *dev_data; + + dev_data = mcrc64_get_dev(tctx); + + pm_runtime_mark_last_busy(dev_data->dev); + pm_runtime_put_autosuspend(dev_data->dev); +} + +static int mcrc64_setkey(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen) +{ + struct mcrc64_tfm_ctx *tctx = crypto_shash_ctx(tfm); + + if (keylen != sizeof(u64)) + return -EINVAL; + + tctx->key = get_unaligned_le64(key); + + return 0; +} + +static int mcrc64_init(struct shash_desc *desc) +{ + struct mcrc64_desc_ctx *ctx = shash_desc_ctx(desc); + struct mcrc64_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + struct mcrc64_data *dev_data; + void __iomem *psa_reg; + + dev_data = mcrc64_get_dev(tctx); + if (!dev_data) + return -ENODEV; + + pm_runtime_get_sync(dev_data->dev); + + /* set capture mode */ + int ret = mcrc64_set_mode(dev_data->regs, MCRC64_CHANNEL_1, + MCRC64_MODE_DATA_CAPTURE); + if (ret) + return ret; + + /* reset PSA */ + psa_reg = dev_data->regs + PSA_SIGREGL(MCRC64_CHANNEL_1); + ret = mcrc64_reset_signature(dev_data->regs, MCRC64_CHANNEL_1); + if (ret) + return ret; + + /* write key */ + writeq_relaxed(tctx->key, psa_reg); + + /* set full cpu mode */ + ret = mcrc64_set_mode(dev_data->regs, MCRC64_CHANNEL_1, + MCRC64_MODE_FULL_CPU); + if (ret) + return ret; + + ctx->signature = readq_relaxed(psa_reg); + + return 0; +} + +static int mcrc64_update(struct shash_desc *desc, const u8 *d8, + unsigned int length) +{ + struct mcrc64_desc_ctx *ctx = shash_desc_ctx(desc); + struct mcrc64_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + struct mcrc64_data *dev_data; + + dev_data = mcrc64_get_dev(tctx); + if (!dev_data) + return -ENODEV; + + return mcrc64_calculate_crc(dev_data->regs, MCRC64_CHANNEL_1, + d8, length, &ctx->signature); +} + +static int mcrc64_final(struct shash_desc *desc, u8 *out) +{ + struct mcrc64_desc_ctx *ctx = shash_desc_ctx(desc); + + /* Send computed CRC */ + put_unaligned_le64(ctx->signature, out); + return 0; +} + +static int mcrc64_finup(struct shash_desc *desc, const u8 *data, + unsigned int length, u8 *out) +{ + return mcrc64_update(desc, data, length) ?: + mcrc64_final(desc, out); +} + +static int mcrc64_digest(struct shash_desc *desc, const u8 *data, + unsigned int length, u8 *out) +{ + return mcrc64_init(desc) ?: mcrc64_finup(desc, data, length, out); +} + +static unsigned int refcnt; +static DEFINE_MUTEX(refcnt_lock); +static struct shash_alg algs[] = { + /* CRC-64 */ + { + .setkey = mcrc64_setkey, + .init = mcrc64_init, + .update = mcrc64_update, + .final = mcrc64_final, + .finup = mcrc64_finup, + .digest = mcrc64_digest, + .descsize = sizeof(struct mcrc64_desc_ctx), + .digestsize = CHKSUM_DIGEST_SIZE, + .base = { + .cra_name = CRC64_ISO3309_STRING, + .cra_driver_name = "mcrc64", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, + .cra_blocksize = CHKSUM_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct mcrc64_tfm_ctx), + .cra_module = THIS_MODULE, + .cra_init = mcrc64_cra_init, + .cra_exit = mcrc64_cra_exit, + } + } +}; + +static int mcrc64_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mcrc64_data *dev_data; + int ret; + + dev_data = devm_kzalloc(dev, sizeof(*dev_data), GFP_KERNEL); + if (!dev_data) + return -ENOMEM; + + dev_data->dev = dev; + dev_data->regs = devm_platform_ioremap_resource(pdev, 0); + + platform_set_drvdata(pdev, dev_data); + + spin_lock(&mcrc64_dev_list.lock); + list_add(&dev_data->list, &mcrc64_dev_list.dev_list); + spin_unlock(&mcrc64_dev_list.lock); + + mutex_lock(&refcnt_lock); + if (!refcnt) { + ret = crypto_register_shashes(algs, ARRAY_SIZE(algs)); + if (ret) { + mutex_unlock(&refcnt_lock); + dev_err(dev, "Failed to register\n"); + return ret; + } + } + refcnt++; + mutex_unlock(&refcnt_lock); + + pm_runtime_set_autosuspend_delay(dev, MCRC64_AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); + + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + pm_runtime_put_sync(dev); + + return 0; +} + +static int mcrc64_remove(struct platform_device *pdev) +{ + struct mcrc64_data *dev_data = platform_get_drvdata(pdev); + int ret; + + ret = pm_runtime_resume_and_get(dev_data->dev); + if (ret < 0) + return ret; + + spin_lock(&mcrc64_dev_list.lock); + list_del(&dev_data->list); + spin_unlock(&mcrc64_dev_list.lock); + + mutex_lock(&refcnt_lock); + if (!--refcnt) + crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); + mutex_unlock(&refcnt_lock); + + pm_runtime_disable(dev_data->dev); + pm_runtime_put_noidle(dev_data->dev); + + return 0; +} + +static int __maybe_unused mcrc64_suspend(struct device *dev) +{ + return pm_runtime_force_suspend(dev); +} + +static int __maybe_unused mcrc64_resume(struct device *dev) +{ + return pm_runtime_force_resume(dev); +} + +static const struct dev_pm_ops mcrc64_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(mcrc64_suspend, + mcrc64_resume) +}; + +static const struct of_device_id of_match[] = { + { .compatible = "ti,am62-mcrc64", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_match); + +static struct platform_driver mcrc64_driver = { + .probe = mcrc64_probe, + .remove = mcrc64_remove, + .driver = { + .name = DRIVER_NAME, + .pm = &mcrc64_pm_ops, + .of_match_table = of_match, + }, +}; + +module_platform_driver(mcrc64_driver); + +MODULE_AUTHOR("Kamlesh Gurudasani "); +MODULE_DESCRIPTION("Texas Instruments MCRC64 driver"); +MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/drivers/dma/ti/k3-psil-am62p.c b/drivers/dma/ti/k3-psil-am62p.c --- a/drivers/dma/ti/k3-psil-am62p.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/dma/ti/k3-psil-am62p.c 2024-07-07 20:37:34.644306549 -0400 @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com + */ + +#include + +#include "k3-psil-priv.h" + +#define PSIL_PDMA_XY_TR(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_PDMA_XY, \ + .mapped_channel_id = -1, \ + .default_flow_id = -1, \ + }, \ + } + +#define PSIL_PDMA_XY_PKT(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_PDMA_XY, \ + .mapped_channel_id = -1, \ + .default_flow_id = -1, \ + .pkt_mode = 1, \ + }, \ + } + +#define PSIL_ETHERNET(x, ch, flow_base, flow_cnt) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_NATIVE, \ + .pkt_mode = 1, \ + .needs_epib = 1, \ + .psd_size = 16, \ + .mapped_channel_id = ch, \ + .flow_start = flow_base, \ + .flow_num = flow_cnt, \ + .default_flow_id = flow_base, \ + }, \ + } + +#define PSIL_SAUL(x, ch, flow_base, flow_cnt, default_flow, tx) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_NATIVE, \ + .pkt_mode = 1, \ + .needs_epib = 1, \ + .psd_size = 64, \ + .mapped_channel_id = ch, \ + .flow_start = flow_base, \ + .flow_num = flow_cnt, \ + .default_flow_id = default_flow, \ + .notdpkt = tx, \ + }, \ + } + +#define PSIL_PDMA_MCASP(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_PDMA_XY, \ + .pdma_acc32 = 1, \ + .pdma_burst = 1, \ + }, \ + } + +#define PSIL_CSI2RX(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_NATIVE, \ + }, \ + } + +/* PSI-L source thread IDs, used for RX (DMA_DEV_TO_MEM) */ +static struct psil_ep am62p_src_ep_map[] = { + /* SAUL */ + PSIL_SAUL(0x7504, 20, 35, 8, 35, 0), + PSIL_SAUL(0x7505, 21, 35, 8, 36, 0), + PSIL_SAUL(0x7506, 22, 43, 8, 43, 0), + PSIL_SAUL(0x7507, 23, 43, 8, 44, 0), + /* PDMA_MAIN0 - SPI0-2 */ + PSIL_PDMA_XY_PKT(0x4300), + PSIL_PDMA_XY_PKT(0x4301), + PSIL_PDMA_XY_PKT(0x4302), + PSIL_PDMA_XY_PKT(0x4303), + PSIL_PDMA_XY_PKT(0x4304), + PSIL_PDMA_XY_PKT(0x4305), + PSIL_PDMA_XY_PKT(0x4306), + PSIL_PDMA_XY_PKT(0x4307), + PSIL_PDMA_XY_PKT(0x4308), + PSIL_PDMA_XY_PKT(0x4309), + PSIL_PDMA_XY_PKT(0x430a), + PSIL_PDMA_XY_PKT(0x430b), + /* PDMA_MAIN1 - UART0-6 */ + PSIL_PDMA_XY_PKT(0x4400), + PSIL_PDMA_XY_PKT(0x4401), + PSIL_PDMA_XY_PKT(0x4402), + PSIL_PDMA_XY_PKT(0x4403), + PSIL_PDMA_XY_PKT(0x4404), + PSIL_PDMA_XY_PKT(0x4405), + PSIL_PDMA_XY_PKT(0x4406), + /* PDMA_MAIN2 - MCASP0-2 */ + PSIL_PDMA_MCASP(0x4500), + PSIL_PDMA_MCASP(0x4501), + PSIL_PDMA_MCASP(0x4502), + /* CPSW3G */ + PSIL_ETHERNET(0x4600, 19, 19, 16), + /* CSI2RX */ + PSIL_CSI2RX(0x5000), + PSIL_CSI2RX(0x5001), + PSIL_CSI2RX(0x5002), + PSIL_CSI2RX(0x5003), + PSIL_CSI2RX(0x5004), + PSIL_CSI2RX(0x5005), + PSIL_CSI2RX(0x5006), + PSIL_CSI2RX(0x5007), + PSIL_CSI2RX(0x5008), + PSIL_CSI2RX(0x5009), + PSIL_CSI2RX(0x500a), + PSIL_CSI2RX(0x500b), + PSIL_CSI2RX(0x500c), + PSIL_CSI2RX(0x500d), + PSIL_CSI2RX(0x500e), + PSIL_CSI2RX(0x500f), + PSIL_CSI2RX(0x5010), + PSIL_CSI2RX(0x5011), + PSIL_CSI2RX(0x5012), + PSIL_CSI2RX(0x5013), + PSIL_CSI2RX(0x5014), + PSIL_CSI2RX(0x5015), + PSIL_CSI2RX(0x5016), + PSIL_CSI2RX(0x5017), + PSIL_CSI2RX(0x5018), + PSIL_CSI2RX(0x5019), + PSIL_CSI2RX(0x501a), + PSIL_CSI2RX(0x501b), + PSIL_CSI2RX(0x501c), + PSIL_CSI2RX(0x501d), + PSIL_CSI2RX(0x501e), + PSIL_CSI2RX(0x501f), + PSIL_CSI2RX(0x5000), + PSIL_CSI2RX(0x5001), + PSIL_CSI2RX(0x5002), + PSIL_CSI2RX(0x5003), + PSIL_CSI2RX(0x5004), + PSIL_CSI2RX(0x5005), + PSIL_CSI2RX(0x5006), + PSIL_CSI2RX(0x5007), + PSIL_CSI2RX(0x5008), + PSIL_CSI2RX(0x5009), + PSIL_CSI2RX(0x500a), + PSIL_CSI2RX(0x500b), + PSIL_CSI2RX(0x500c), + PSIL_CSI2RX(0x500d), + PSIL_CSI2RX(0x500e), + PSIL_CSI2RX(0x500f), + PSIL_CSI2RX(0x5010), + PSIL_CSI2RX(0x5011), + PSIL_CSI2RX(0x5012), + PSIL_CSI2RX(0x5013), + PSIL_CSI2RX(0x5014), + PSIL_CSI2RX(0x5015), + PSIL_CSI2RX(0x5016), + PSIL_CSI2RX(0x5017), + PSIL_CSI2RX(0x5018), + PSIL_CSI2RX(0x5019), + PSIL_CSI2RX(0x501a), + PSIL_CSI2RX(0x501b), + PSIL_CSI2RX(0x501c), + PSIL_CSI2RX(0x501d), + PSIL_CSI2RX(0x501e), + PSIL_CSI2RX(0x501f), + /* CSIRX 1-3 (only for J722S) */ + PSIL_CSI2RX(0x5100), + PSIL_CSI2RX(0x5101), + PSIL_CSI2RX(0x5102), + PSIL_CSI2RX(0x5103), + PSIL_CSI2RX(0x5104), + PSIL_CSI2RX(0x5105), + PSIL_CSI2RX(0x5106), + PSIL_CSI2RX(0x5107), + PSIL_CSI2RX(0x5108), + PSIL_CSI2RX(0x5109), + PSIL_CSI2RX(0x510a), + PSIL_CSI2RX(0x510b), + PSIL_CSI2RX(0x510c), + PSIL_CSI2RX(0x510d), + PSIL_CSI2RX(0x510e), + PSIL_CSI2RX(0x510f), + PSIL_CSI2RX(0x5110), + PSIL_CSI2RX(0x5111), + PSIL_CSI2RX(0x5112), + PSIL_CSI2RX(0x5113), + PSIL_CSI2RX(0x5114), + PSIL_CSI2RX(0x5115), + PSIL_CSI2RX(0x5116), + PSIL_CSI2RX(0x5117), + PSIL_CSI2RX(0x5118), + PSIL_CSI2RX(0x5119), + PSIL_CSI2RX(0x511a), + PSIL_CSI2RX(0x511b), + PSIL_CSI2RX(0x511c), + PSIL_CSI2RX(0x511d), + PSIL_CSI2RX(0x511e), + PSIL_CSI2RX(0x511f), + PSIL_CSI2RX(0x5200), + PSIL_CSI2RX(0x5201), + PSIL_CSI2RX(0x5202), + PSIL_CSI2RX(0x5203), + PSIL_CSI2RX(0x5204), + PSIL_CSI2RX(0x5205), + PSIL_CSI2RX(0x5206), + PSIL_CSI2RX(0x5207), + PSIL_CSI2RX(0x5208), + PSIL_CSI2RX(0x5209), + PSIL_CSI2RX(0x520a), + PSIL_CSI2RX(0x520b), + PSIL_CSI2RX(0x520c), + PSIL_CSI2RX(0x520d), + PSIL_CSI2RX(0x520e), + PSIL_CSI2RX(0x520f), + PSIL_CSI2RX(0x5210), + PSIL_CSI2RX(0x5211), + PSIL_CSI2RX(0x5212), + PSIL_CSI2RX(0x5213), + PSIL_CSI2RX(0x5214), + PSIL_CSI2RX(0x5215), + PSIL_CSI2RX(0x5216), + PSIL_CSI2RX(0x5217), + PSIL_CSI2RX(0x5218), + PSIL_CSI2RX(0x5219), + PSIL_CSI2RX(0x521a), + PSIL_CSI2RX(0x521b), + PSIL_CSI2RX(0x521c), + PSIL_CSI2RX(0x521d), + PSIL_CSI2RX(0x521e), + PSIL_CSI2RX(0x521f), + PSIL_CSI2RX(0x5300), + PSIL_CSI2RX(0x5301), + PSIL_CSI2RX(0x5302), + PSIL_CSI2RX(0x5303), + PSIL_CSI2RX(0x5304), + PSIL_CSI2RX(0x5305), + PSIL_CSI2RX(0x5306), + PSIL_CSI2RX(0x5307), + PSIL_CSI2RX(0x5308), + PSIL_CSI2RX(0x5309), + PSIL_CSI2RX(0x530a), + PSIL_CSI2RX(0x530b), + PSIL_CSI2RX(0x530c), + PSIL_CSI2RX(0x530d), + PSIL_CSI2RX(0x530e), + PSIL_CSI2RX(0x530f), + PSIL_CSI2RX(0x5310), + PSIL_CSI2RX(0x5311), + PSIL_CSI2RX(0x5312), + PSIL_CSI2RX(0x5313), + PSIL_CSI2RX(0x5314), + PSIL_CSI2RX(0x5315), + PSIL_CSI2RX(0x5316), + PSIL_CSI2RX(0x5317), + PSIL_CSI2RX(0x5318), + PSIL_CSI2RX(0x5319), + PSIL_CSI2RX(0x531a), + PSIL_CSI2RX(0x531b), + PSIL_CSI2RX(0x531c), + PSIL_CSI2RX(0x531d), + PSIL_CSI2RX(0x531e), + PSIL_CSI2RX(0x531f), +}; + +/* PSI-L destination thread IDs, used for TX (DMA_MEM_TO_DEV) */ +static struct psil_ep am62p_dst_ep_map[] = { + /* SAUL */ + PSIL_SAUL(0xf500, 27, 83, 8, 83, 1), + PSIL_SAUL(0xf501, 28, 91, 8, 91, 1), + /* PDMA_MAIN0 - SPI0-2 */ + PSIL_PDMA_XY_PKT(0xc300), + PSIL_PDMA_XY_PKT(0xc301), + PSIL_PDMA_XY_PKT(0xc302), + PSIL_PDMA_XY_PKT(0xc303), + PSIL_PDMA_XY_PKT(0xc304), + PSIL_PDMA_XY_PKT(0xc305), + PSIL_PDMA_XY_PKT(0xc306), + PSIL_PDMA_XY_PKT(0xc307), + PSIL_PDMA_XY_PKT(0xc308), + PSIL_PDMA_XY_PKT(0xc309), + PSIL_PDMA_XY_PKT(0xc30a), + PSIL_PDMA_XY_PKT(0xc30b), + /* PDMA_MAIN1 - UART0-6 */ + PSIL_PDMA_XY_PKT(0xc400), + PSIL_PDMA_XY_PKT(0xc401), + PSIL_PDMA_XY_PKT(0xc402), + PSIL_PDMA_XY_PKT(0xc403), + PSIL_PDMA_XY_PKT(0xc404), + PSIL_PDMA_XY_PKT(0xc405), + PSIL_PDMA_XY_PKT(0xc406), + /* PDMA_MAIN2 - MCASP0-2 */ + PSIL_PDMA_MCASP(0xc500), + PSIL_PDMA_MCASP(0xc501), + PSIL_PDMA_MCASP(0xc502), + /* CPSW3G */ + PSIL_ETHERNET(0xc600, 19, 19, 8), + PSIL_ETHERNET(0xc601, 20, 27, 8), + PSIL_ETHERNET(0xc602, 21, 35, 8), + PSIL_ETHERNET(0xc603, 22, 43, 8), + PSIL_ETHERNET(0xc604, 23, 51, 8), + PSIL_ETHERNET(0xc605, 24, 59, 8), + PSIL_ETHERNET(0xc606, 25, 67, 8), + PSIL_ETHERNET(0xc607, 26, 75, 8), +}; + +struct psil_ep_map am62p_ep_map = { + .name = "am62p", + .src = am62p_src_ep_map, + .src_count = ARRAY_SIZE(am62p_src_ep_map), + .dst = am62p_dst_ep_map, + .dst_count = ARRAY_SIZE(am62p_dst_ep_map), +}; diff -Naur --no-dereference a/drivers/dma/ti/k3-psil.c b/drivers/dma/ti/k3-psil.c --- a/drivers/dma/ti/k3-psil.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/dma/ti/k3-psil.c 2024-07-07 20:37:34.644306549 -0400 @@ -26,6 +26,8 @@ { .family = "AM62X", .data = &am62_ep_map }, { .family = "AM62AX", .data = &am62a_ep_map }, { .family = "J784S4", .data = &j784s4_ep_map }, + { .family = "AM62PX", .data = &am62p_ep_map }, + { .family = "J722S", .data = &am62p_ep_map }, { /* sentinel */ } }; diff -Naur --no-dereference a/drivers/dma/ti/k3-psil-j721s2.c b/drivers/dma/ti/k3-psil-j721s2.c --- a/drivers/dma/ti/k3-psil-j721s2.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/dma/ti/k3-psil-j721s2.c 2024-07-07 20:37:34.644306549 -0400 @@ -57,6 +57,14 @@ }, \ } +#define PSIL_CSI2RX(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_NATIVE, \ + }, \ + } + /* PSI-L source thread IDs, used for RX (DMA_DEV_TO_MEM) */ static struct psil_ep j721s2_src_ep_map[] = { /* PDMA_MCASP - McASP0-4 */ @@ -114,6 +122,71 @@ PSIL_PDMA_XY_PKT(0x4707), PSIL_PDMA_XY_PKT(0x4708), PSIL_PDMA_XY_PKT(0x4709), + /* CSI2RX */ + PSIL_CSI2RX(0x4940), + PSIL_CSI2RX(0x4941), + PSIL_CSI2RX(0x4942), + PSIL_CSI2RX(0x4943), + PSIL_CSI2RX(0x4944), + PSIL_CSI2RX(0x4945), + PSIL_CSI2RX(0x4946), + PSIL_CSI2RX(0x4947), + PSIL_CSI2RX(0x4948), + PSIL_CSI2RX(0x4949), + PSIL_CSI2RX(0x494a), + PSIL_CSI2RX(0x494b), + PSIL_CSI2RX(0x494c), + PSIL_CSI2RX(0x494d), + PSIL_CSI2RX(0x494e), + PSIL_CSI2RX(0x494f), + PSIL_CSI2RX(0x4950), + PSIL_CSI2RX(0x4951), + PSIL_CSI2RX(0x4952), + PSIL_CSI2RX(0x4953), + PSIL_CSI2RX(0x4954), + PSIL_CSI2RX(0x4955), + PSIL_CSI2RX(0x4956), + PSIL_CSI2RX(0x4957), + PSIL_CSI2RX(0x4958), + PSIL_CSI2RX(0x4959), + PSIL_CSI2RX(0x495a), + PSIL_CSI2RX(0x495b), + PSIL_CSI2RX(0x495c), + PSIL_CSI2RX(0x495d), + PSIL_CSI2RX(0x495e), + PSIL_CSI2RX(0x495f), + PSIL_CSI2RX(0x4960), + PSIL_CSI2RX(0x4961), + PSIL_CSI2RX(0x4962), + PSIL_CSI2RX(0x4963), + PSIL_CSI2RX(0x4964), + PSIL_CSI2RX(0x4965), + PSIL_CSI2RX(0x4966), + PSIL_CSI2RX(0x4967), + PSIL_CSI2RX(0x4968), + PSIL_CSI2RX(0x4969), + PSIL_CSI2RX(0x496a), + PSIL_CSI2RX(0x496b), + PSIL_CSI2RX(0x496c), + PSIL_CSI2RX(0x496d), + PSIL_CSI2RX(0x496e), + PSIL_CSI2RX(0x496f), + PSIL_CSI2RX(0x4970), + PSIL_CSI2RX(0x4971), + PSIL_CSI2RX(0x4972), + PSIL_CSI2RX(0x4973), + PSIL_CSI2RX(0x4974), + PSIL_CSI2RX(0x4975), + PSIL_CSI2RX(0x4976), + PSIL_CSI2RX(0x4977), + PSIL_CSI2RX(0x4978), + PSIL_CSI2RX(0x4979), + PSIL_CSI2RX(0x497a), + PSIL_CSI2RX(0x497b), + PSIL_CSI2RX(0x497c), + PSIL_CSI2RX(0x497d), + PSIL_CSI2RX(0x497e), + PSIL_CSI2RX(0x497f), /* MAIN SA2UL */ PSIL_SA2UL(0x4a40, 0), PSIL_SA2UL(0x4a41, 0), diff -Naur --no-dereference a/drivers/dma/ti/k3-psil-priv.h b/drivers/dma/ti/k3-psil-priv.h --- a/drivers/dma/ti/k3-psil-priv.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/dma/ti/k3-psil-priv.h 2024-07-07 20:37:34.644306549 -0400 @@ -45,5 +45,6 @@ extern struct psil_ep_map am62_ep_map; extern struct psil_ep_map am62a_ep_map; extern struct psil_ep_map j784s4_ep_map; +extern struct psil_ep_map am62p_ep_map; #endif /* K3_PSIL_PRIV_H_ */ diff -Naur --no-dereference a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c --- a/drivers/dma/ti/k3-udma.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/dma/ti/k3-udma.c 2024-07-07 20:37:34.644306549 -0400 @@ -54,6 +54,8 @@ #define UDMA_RFLOW_DSTTAG_DST_TAG_LO 4 #define UDMA_RFLOW_DSTTAG_DST_TAG_HI 5 +#define UDMA_J722S_BCDMA_PSIL_BASE 0x3100 + struct udma_chan; enum k3_dma_type { @@ -135,6 +137,7 @@ u32 statictr_z_mask; u8 burst_size[3]; struct udma_soc_data *soc_data; + u8 order_id; }; struct udma_soc_data { @@ -2110,6 +2113,7 @@ static int bcdma_tisci_rx_channel_config(struct udma_chan *uc) { struct udma_dev *ud = uc->ud; + const struct udma_match_data *match_data = ud->match_data; struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops; struct udma_rchan *rchan = uc->rchan; @@ -2120,6 +2124,11 @@ req_rx.nav_id = tisci_rm->tisci_dev_id; req_rx.index = rchan->id; + if (match_data->order_id) { + req_rx.valid_params |= TI_SCI_MSG_VALUE_RM_UDMAP_CH_ORDER_ID_VALID; + req_rx.rx_orderid = match_data->order_id; + } + ret = tisci_ops->rx_ch_cfg(tisci_rm->tisci, &req_rx); if (ret) dev_err(ud->dev, "rchan%d cfg failed %d\n", rchan->id, ret); @@ -3185,27 +3194,39 @@ d->static_tr.elcnt = elcnt; - /* - * PDMA must to close the packet when the channel is in packet mode. - * For TR mode when the channel is not cyclic we also need PDMA to close - * the packet otherwise the transfer will stall because PDMA holds on - * the data it has received from the peripheral. - */ if (uc->config.pkt_mode || !uc->cyclic) { + /* + * PDMA must close the packet when the channel is in packet mode. + * For TR mode when the channel is not cyclic we also need PDMA + * to close the packet otherwise the transfer will stall because + * PDMA holds on the data it has received from the peripheral. + */ unsigned int div = dev_width * elcnt; if (uc->cyclic) d->static_tr.bstcnt = d->residue / d->sglen / div; else d->static_tr.bstcnt = d->residue / div; + } else if (uc->ud->match_data->type == DMA_TYPE_BCDMA && + uc->config.dir == DMA_DEV_TO_MEM && !uc->config.pkt_mode && + uc->cyclic) { + /* + * For cyclic TR mode PDMA must close the packet after every TR + * transfer, as we have to set EOP in each TR to prevent short + * packet errors seen on channel teardown. + */ + struct cppi5_tr_type1_t *tr_req = d->hwdesc[0].tr_req_base; - if (uc->config.dir == DMA_DEV_TO_MEM && - d->static_tr.bstcnt > uc->ud->match_data->statictr_z_mask) - return -EINVAL; + d->static_tr.bstcnt = + (tr_req->icnt0 * tr_req->icnt1) / dev_width; } else { d->static_tr.bstcnt = 0; } + if (uc->config.dir == DMA_DEV_TO_MEM && + d->static_tr.bstcnt > uc->ud->match_data->statictr_z_mask) + return -EINVAL; + return 0; } @@ -3450,8 +3471,9 @@ /* static TR for remote PDMA */ if (udma_configure_statictr(uc, d, dev_width, burst)) { dev_err(uc->ud->dev, - "%s: StaticTR Z is limited to maximum 4095 (%u)\n", - __func__, d->static_tr.bstcnt); + "%s: StaticTR Z is limited to maximum %u (%u)\n", + __func__, uc->ud->match_data->statictr_z_mask, + d->static_tr.bstcnt); udma_free_hwdesc(uc, d); kfree(d); @@ -3476,6 +3498,7 @@ u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; unsigned int i; int num_tr; + u32 period_csf = 0; num_tr = udma_get_tr_counters(period_len, __ffs(buf_addr), &tr0_cnt0, &tr0_cnt1, &tr1_cnt0); @@ -3498,6 +3521,20 @@ period_addr = buf_addr | ((u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT); + /* + * For BCDMA <-> PDMA transfers, the EOP flag needs to be set on the + * last TR of a descriptor, to mark the packet as complete. + * This is required for getting the teardown completion message in case + * of TX, and to avoid short-packet error in case of RX. + * + * As we are in cyclic mode, we do not know which period might be the + * last one, so set the flag for each period. + */ + if (uc->config.ep_type == PSIL_EP_PDMA_XY && + uc->ud->match_data->type == DMA_TYPE_BCDMA) { + period_csf = CPPI5_TR_CSF_EOP; + } + for (i = 0; i < periods; i++) { int tr_idx = i * num_tr; @@ -3525,8 +3562,10 @@ } if (!(flags & DMA_PREP_INTERRUPT)) - cppi5_tr_csf_set(&tr_req[tr_idx].flags, - CPPI5_TR_CSF_SUPR_EVT); + period_csf |= CPPI5_TR_CSF_SUPR_EVT; + + if (period_csf) + cppi5_tr_csf_set(&tr_req[tr_idx].flags, period_csf); period_addr += period_len; } @@ -3655,8 +3694,9 @@ /* static TR for remote PDMA */ if (udma_configure_statictr(uc, d, dev_width, burst)) { dev_err(uc->ud->dev, - "%s: StaticTR Z is limited to maximum 4095 (%u)\n", - __func__, d->static_tr.bstcnt); + "%s: StaticTR Z is limited to maximum %u (%u)\n", + __func__, uc->ud->match_data->statictr_z_mask, + d->static_tr.bstcnt); udma_free_hwdesc(uc, d); kfree(d); @@ -4332,6 +4372,20 @@ 0, /* No UH Channels */ }, .soc_data = &am62a_dmss_csi_soc_data, + .order_id = 8, +}; + +static struct udma_match_data j722s_bcdma_data = { + .type = DMA_TYPE_BCDMA, + .psil_base = UDMA_J722S_BCDMA_PSIL_BASE, + .enable_memcpy_support = false, + .burst_size = { + TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */ + 0, /* No H Channels */ + 0, /* No UH Channels */ + }, + .soc_data = &j721s2_bcdma_csi_soc_data, + .order_id = 15, }; static struct udma_match_data am64_bcdma_data = { @@ -4370,6 +4424,7 @@ 0, /* No UH Channels */ }, .soc_data = &j721s2_bcdma_csi_soc_data, + .order_id = 15, }; static const struct of_device_id udma_of_match[] = { @@ -4403,6 +4458,10 @@ .compatible = "ti,j721s2-dmss-bcdma-csi", .data = &j721s2_bcdma_csi_data, }, + { + .compatible = "ti,j722s-dmss-bcdma-csi", + .data = &j722s_bcdma_data, + }, { /* Sentinel */ }, }; @@ -4447,6 +4506,8 @@ { .family = "AM62X", .data = &am64_soc_data }, { .family = "AM62AX", .data = &am64_soc_data }, { .family = "J784S4", .data = &j721e_soc_data }, + { .family = "AM62PX", .data = &am64_soc_data }, + { .family = "J722S", .data = &am64_soc_data }, { /* sentinel */ } }; @@ -4471,6 +4532,7 @@ break; case DMA_TYPE_BCDMA: ud->bchan_cnt = BCDMA_CAP2_BCHAN_CNT(cap2); + ud->bchan_cnt += BCDMA_CAP3_HBCHAN_CNT(cap3) + BCDMA_CAP3_UBCHAN_CNT(cap3); ud->tchan_cnt = BCDMA_CAP2_TCHAN_CNT(cap2); ud->rchan_cnt = BCDMA_CAP2_RCHAN_CNT(cap2); ud->rflow_cnt = ud->rchan_cnt; diff -Naur --no-dereference a/drivers/dma/ti/k3-udma-glue.c b/drivers/dma/ti/k3-udma-glue.c --- a/drivers/dma/ti/k3-udma-glue.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/dma/ti/k3-udma-glue.c 2024-07-07 20:37:34.644306549 -0400 @@ -111,6 +111,35 @@ return 0; } +static int of_k3_udma_glue_parse_chn_common(struct k3_udma_glue_common *common, u32 thread_id, + bool tx_chn) +{ + if (tx_chn && !(thread_id & K3_PSIL_DST_THREAD_ID_OFFSET)) + return -EINVAL; + + if (!tx_chn && (thread_id & K3_PSIL_DST_THREAD_ID_OFFSET)) + return -EINVAL; + + /* get psil endpoint config */ + common->ep_config = psil_get_ep_config(thread_id); + if (IS_ERR(common->ep_config)) { + dev_err(common->dev, + "No configuration for psi-l thread 0x%04x\n", + thread_id); + return PTR_ERR(common->ep_config); + } + + common->epib = common->ep_config->needs_epib; + common->psdata_size = common->ep_config->psd_size; + + if (tx_chn) + common->dst_thread = thread_id; + else + common->src_thread = thread_id; + + return 0; +} + static int of_k3_udma_glue_parse_chn(struct device_node *chn_np, const char *name, struct k3_udma_glue_common *common, bool tx_chn) @@ -153,38 +182,32 @@ common->atype_asel = dma_spec.args[1]; } - if (tx_chn && !(thread_id & K3_PSIL_DST_THREAD_ID_OFFSET)) { - ret = -EINVAL; - goto out_put_spec; - } + ret = of_k3_udma_glue_parse_chn_common(common, thread_id, tx_chn); - if (!tx_chn && (thread_id & K3_PSIL_DST_THREAD_ID_OFFSET)) { - ret = -EINVAL; - goto out_put_spec; - } +out_put_spec: + of_node_put(dma_spec.np); + return ret; +} - /* get psil endpoint config */ - common->ep_config = psil_get_ep_config(thread_id); - if (IS_ERR(common->ep_config)) { - dev_err(common->dev, - "No configuration for psi-l thread 0x%04x\n", - thread_id); - ret = PTR_ERR(common->ep_config); - goto out_put_spec; - } +static int +of_k3_udma_glue_parse_chn_by_id(struct device_node *udmax_np, struct k3_udma_glue_common *common, + bool tx_chn, u32 thread_id) +{ + int ret = 0; - common->epib = common->ep_config->needs_epib; - common->psdata_size = common->ep_config->psd_size; + if (unlikely(!udmax_np)) + return -EINVAL; - if (tx_chn) - common->dst_thread = thread_id; - else - common->src_thread = thread_id; + ret = of_k3_udma_glue_parse(udmax_np, common); + if (ret) + goto out_put_spec; + + ret = of_k3_udma_glue_parse_chn_common(common, thread_id, tx_chn); out_put_spec: - of_node_put(dma_spec.np); + of_node_put(udmax_np); return ret; -}; +} static void k3_udma_glue_dump_tx_chn(struct k3_udma_glue_tx_channel *tx_chn) { @@ -251,29 +274,13 @@ return tisci_rm->tisci_udmap_ops->tx_ch_cfg(tisci_rm->tisci, &req); } -struct k3_udma_glue_tx_channel *k3_udma_glue_request_tx_chn(struct device *dev, - const char *name, struct k3_udma_glue_tx_channel_cfg *cfg) +static int +k3_udma_glue_request_tx_chn_common(struct device *dev, + struct k3_udma_glue_tx_channel *tx_chn, + struct k3_udma_glue_tx_channel_cfg *cfg) { - struct k3_udma_glue_tx_channel *tx_chn; int ret; - tx_chn = devm_kzalloc(dev, sizeof(*tx_chn), GFP_KERNEL); - if (!tx_chn) - return ERR_PTR(-ENOMEM); - - tx_chn->common.dev = dev; - tx_chn->common.swdata_size = cfg->swdata_size; - tx_chn->tx_pause_on_err = cfg->tx_pause_on_err; - tx_chn->tx_filt_einfo = cfg->tx_filt_einfo; - tx_chn->tx_filt_pswords = cfg->tx_filt_pswords; - tx_chn->tx_supr_tdpkt = cfg->tx_supr_tdpkt; - - /* parse of udmap channel */ - ret = of_k3_udma_glue_parse_chn(dev->of_node, name, - &tx_chn->common, true); - if (ret) - goto err; - tx_chn->common.hdesc_size = cppi5_hdesc_calc_size(tx_chn->common.epib, tx_chn->common.psdata_size, tx_chn->common.swdata_size); @@ -289,7 +296,7 @@ if (IS_ERR(tx_chn->udma_tchanx)) { ret = PTR_ERR(tx_chn->udma_tchanx); dev_err(dev, "UDMAX tchanx get err %d\n", ret); - goto err; + return ret; } tx_chn->udma_tchan_id = xudma_tchan_get_id(tx_chn->udma_tchanx); @@ -302,7 +309,7 @@ dev_err(dev, "Channel Device registration failed %d\n", ret); put_device(&tx_chn->common.chan_dev); tx_chn->common.chan_dev.parent = NULL; - goto err; + return ret; } if (xudma_is_pktdma(tx_chn->common.udmax)) { @@ -326,7 +333,7 @@ &tx_chn->ringtxcq); if (ret) { dev_err(dev, "Failed to get TX/TXCQ rings %d\n", ret); - goto err; + return ret; } /* Set the dma_dev for the rings to be configured */ @@ -342,13 +349,13 @@ ret = k3_ringacc_ring_cfg(tx_chn->ringtx, &cfg->tx_cfg); if (ret) { dev_err(dev, "Failed to cfg ringtx %d\n", ret); - goto err; + return ret; } ret = k3_ringacc_ring_cfg(tx_chn->ringtxcq, &cfg->txcq_cfg); if (ret) { dev_err(dev, "Failed to cfg ringtx %d\n", ret); - goto err; + return ret; } /* request and cfg psi-l */ @@ -359,11 +366,42 @@ ret = k3_udma_glue_cfg_tx_chn(tx_chn); if (ret) { dev_err(dev, "Failed to cfg tchan %d\n", ret); - goto err; + return ret; } k3_udma_glue_dump_tx_chn(tx_chn); + return 0; +} + +struct k3_udma_glue_tx_channel * +k3_udma_glue_request_tx_chn(struct device *dev, const char *name, + struct k3_udma_glue_tx_channel_cfg *cfg) +{ + struct k3_udma_glue_tx_channel *tx_chn; + int ret; + + tx_chn = devm_kzalloc(dev, sizeof(*tx_chn), GFP_KERNEL); + if (!tx_chn) + return ERR_PTR(-ENOMEM); + + tx_chn->common.dev = dev; + tx_chn->common.swdata_size = cfg->swdata_size; + tx_chn->tx_pause_on_err = cfg->tx_pause_on_err; + tx_chn->tx_filt_einfo = cfg->tx_filt_einfo; + tx_chn->tx_filt_pswords = cfg->tx_filt_pswords; + tx_chn->tx_supr_tdpkt = cfg->tx_supr_tdpkt; + + /* parse of udmap channel */ + ret = of_k3_udma_glue_parse_chn(dev->of_node, name, + &tx_chn->common, true); + if (ret) + goto err; + + ret = k3_udma_glue_request_tx_chn_common(dev, tx_chn, cfg); + if (ret) + goto err; + return tx_chn; err: @@ -372,6 +410,41 @@ } EXPORT_SYMBOL_GPL(k3_udma_glue_request_tx_chn); +struct k3_udma_glue_tx_channel * +k3_udma_glue_request_tx_chn_for_thread_id(struct device *dev, + struct k3_udma_glue_tx_channel_cfg *cfg, + struct device_node *udmax_np, u32 thread_id) +{ + struct k3_udma_glue_tx_channel *tx_chn; + int ret; + + tx_chn = devm_kzalloc(dev, sizeof(*tx_chn), GFP_KERNEL); + if (!tx_chn) + return ERR_PTR(-ENOMEM); + + tx_chn->common.dev = dev; + tx_chn->common.swdata_size = cfg->swdata_size; + tx_chn->tx_pause_on_err = cfg->tx_pause_on_err; + tx_chn->tx_filt_einfo = cfg->tx_filt_einfo; + tx_chn->tx_filt_pswords = cfg->tx_filt_pswords; + tx_chn->tx_supr_tdpkt = cfg->tx_supr_tdpkt; + + ret = of_k3_udma_glue_parse_chn_by_id(udmax_np, &tx_chn->common, true, thread_id); + if (ret) + goto err; + + ret = k3_udma_glue_request_tx_chn_common(dev, tx_chn, cfg); + if (ret) + goto err; + + return tx_chn; + +err: + k3_udma_glue_release_tx_chn(tx_chn); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(k3_udma_glue_request_tx_chn_for_thread_id); + void k3_udma_glue_release_tx_chn(struct k3_udma_glue_tx_channel *tx_chn) { if (tx_chn->psil_paired) { @@ -1000,12 +1073,59 @@ return ERR_PTR(ret); } +static int +k3_udma_glue_request_remote_rx_chn_common(struct k3_udma_glue_rx_channel *rx_chn, + struct k3_udma_glue_rx_channel_cfg *cfg, + struct device *dev) +{ + int ret, i; + + rx_chn->common.hdesc_size = cppi5_hdesc_calc_size(rx_chn->common.epib, + rx_chn->common.psdata_size, + rx_chn->common.swdata_size); + + rx_chn->flows = devm_kcalloc(dev, rx_chn->flow_num, + sizeof(*rx_chn->flows), GFP_KERNEL); + if (!rx_chn->flows) + return -ENOMEM; + + rx_chn->common.chan_dev.class = &k3_udma_glue_devclass; + rx_chn->common.chan_dev.parent = xudma_get_device(rx_chn->common.udmax); + dev_set_name(&rx_chn->common.chan_dev, "rchan_remote-0x%04x-0x%02x", + rx_chn->common.src_thread, rx_chn->flow_id_base); + ret = device_register(&rx_chn->common.chan_dev); + if (ret) { + dev_err(dev, "Channel Device registration failed %d\n", ret); + put_device(&rx_chn->common.chan_dev); + rx_chn->common.chan_dev.parent = NULL; + return ret; + } + + if (xudma_is_pktdma(rx_chn->common.udmax)) { + /* prepare the channel device as coherent */ + rx_chn->common.chan_dev.dma_coherent = true; + dma_coerce_mask_and_coherent(&rx_chn->common.chan_dev, + DMA_BIT_MASK(48)); + } + + ret = k3_udma_glue_allocate_rx_flows(rx_chn, cfg); + if (ret) + return ret; + + for (i = 0; i < rx_chn->flow_num; i++) + rx_chn->flows[i].udma_rflow_id = rx_chn->flow_id_base + i; + + k3_udma_glue_dump_rx_chn(rx_chn); + + return 0; +} + static struct k3_udma_glue_rx_channel * k3_udma_glue_request_remote_rx_chn(struct device *dev, const char *name, struct k3_udma_glue_rx_channel_cfg *cfg) { struct k3_udma_glue_rx_channel *rx_chn; - int ret, i; + int ret; if (cfg->flow_id_num <= 0 || cfg->flow_id_use_rxchan_id || @@ -1036,44 +1156,55 @@ if (ret) goto err; - rx_chn->common.hdesc_size = cppi5_hdesc_calc_size(rx_chn->common.epib, - rx_chn->common.psdata_size, - rx_chn->common.swdata_size); - - rx_chn->flows = devm_kcalloc(dev, rx_chn->flow_num, - sizeof(*rx_chn->flows), GFP_KERNEL); - if (!rx_chn->flows) { - ret = -ENOMEM; + ret = k3_udma_glue_request_remote_rx_chn_common(rx_chn, cfg, dev); + if (ret) goto err; - } - rx_chn->common.chan_dev.class = &k3_udma_glue_devclass; - rx_chn->common.chan_dev.parent = xudma_get_device(rx_chn->common.udmax); - dev_set_name(&rx_chn->common.chan_dev, "rchan_remote-0x%04x", - rx_chn->common.src_thread); - ret = device_register(&rx_chn->common.chan_dev); - if (ret) { - dev_err(dev, "Channel Device registration failed %d\n", ret); - put_device(&rx_chn->common.chan_dev); - rx_chn->common.chan_dev.parent = NULL; - goto err; - } + return rx_chn; - if (xudma_is_pktdma(rx_chn->common.udmax)) { - /* prepare the channel device as coherent */ - rx_chn->common.chan_dev.dma_coherent = true; - dma_coerce_mask_and_coherent(&rx_chn->common.chan_dev, - DMA_BIT_MASK(48)); - } +err: + k3_udma_glue_release_rx_chn(rx_chn); + return ERR_PTR(ret); +} - ret = k3_udma_glue_allocate_rx_flows(rx_chn, cfg); +struct k3_udma_glue_rx_channel * +k3_udma_glue_request_remote_rx_chn_for_thread_id(struct device *dev, + struct k3_udma_glue_rx_channel_cfg *cfg, + struct device_node *udmax_np, u32 thread_id) +{ + struct k3_udma_glue_rx_channel *rx_chn; + int ret; + + if (cfg->flow_id_num <= 0 || + cfg->flow_id_use_rxchan_id || + cfg->def_flow_cfg || + cfg->flow_id_base < 0) + return ERR_PTR(-EINVAL); + + /* + * Remote RX channel is under control of Remote CPU core, so + * Linux can only request and manipulate by dedicated RX flows + */ + + rx_chn = devm_kzalloc(dev, sizeof(*rx_chn), GFP_KERNEL); + if (!rx_chn) + return ERR_PTR(-ENOMEM); + + rx_chn->common.dev = dev; + rx_chn->common.swdata_size = cfg->swdata_size; + rx_chn->remote = true; + rx_chn->udma_rchan_id = -1; + rx_chn->flow_num = cfg->flow_id_num; + rx_chn->flow_id_base = cfg->flow_id_base; + rx_chn->psil_paired = false; + + ret = of_k3_udma_glue_parse_chn_by_id(udmax_np, &rx_chn->common, false, thread_id); if (ret) goto err; - for (i = 0; i < rx_chn->flow_num; i++) - rx_chn->flows[i].udma_rflow_id = rx_chn->flow_id_base + i; - - k3_udma_glue_dump_rx_chn(rx_chn); + ret = k3_udma_glue_request_remote_rx_chn_common(rx_chn, cfg, dev); + if (ret) + goto err; return rx_chn; @@ -1081,6 +1212,7 @@ k3_udma_glue_release_rx_chn(rx_chn); return ERR_PTR(ret); } +EXPORT_SYMBOL_GPL(k3_udma_glue_request_remote_rx_chn_for_thread_id); struct k3_udma_glue_rx_channel * k3_udma_glue_request_rx_chn(struct device *dev, const char *name, diff -Naur --no-dereference a/drivers/dma/ti/Makefile b/drivers/dma/ti/Makefile --- a/drivers/dma/ti/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/dma/ti/Makefile 2024-07-07 20:37:34.644306549 -0400 @@ -12,6 +12,7 @@ k3-psil-j721s2.o \ k3-psil-am62.o \ k3-psil-am62a.o \ - k3-psil-j784s4.o + k3-psil-j784s4.o \ + k3-psil-am62p.o obj-$(CONFIG_TI_K3_PSIL) += k3-psil-lib.o obj-$(CONFIG_TI_DMA_CROSSBAR) += dma-crossbar.o diff -Naur --no-dereference a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c --- a/drivers/dma-buf/dma-heap.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/dma-buf/dma-heap.c 2024-07-07 20:37:34.640306529 -0400 @@ -323,4 +323,4 @@ return 0; } -subsys_initcall(dma_heap_init); +core_initcall(dma_heap_init); diff -Naur --no-dereference a/drivers/dma-buf/heaps/carveout-heap.c b/drivers/dma-buf/heaps/carveout-heap.c --- a/drivers/dma-buf/heaps/carveout-heap.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/dma-buf/heaps/carveout-heap.c 2024-07-07 20:37:34.640306529 -0400 @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Carveout DMA-Heap userspace exporter + * + * Copyright (C) 2019-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Andrew Davis + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct carveout_dma_heap { + struct dma_heap *heap; + struct gen_pool *pool; + bool cached; +}; + +struct carveout_dma_heap_buffer { + struct gen_pool *pool; + struct list_head attachments; + struct mutex attachments_lock; + struct mutex vmap_lock; + int vmap_cnt; + unsigned long len; + void *vaddr; + phys_addr_t paddr; + bool cached; +}; + +struct dma_heap_attachment { + struct device *dev; + struct sg_table *table; + struct list_head list; +}; + +static int dma_heap_attach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct carveout_dma_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + struct sg_table *table; + + a = kzalloc(sizeof(*a), GFP_KERNEL); + if (!a) + return -ENOMEM; + + table = kmalloc(sizeof(*table), GFP_KERNEL); + if (!table) { + kfree(a); + return -ENOMEM; + } + if (sg_alloc_table(table, 1, GFP_KERNEL)) { + kfree(a); + return -ENOMEM; + } + sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(buffer->paddr)), buffer->len, 0); + + a->table = table; + a->dev = attachment->dev; + INIT_LIST_HEAD(&a->list); + + attachment->priv = a; + + mutex_lock(&buffer->attachments_lock); + list_add(&a->list, &buffer->attachments); + mutex_unlock(&buffer->attachments_lock); + + return 0; +} + +static void dma_heap_detatch(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct carveout_dma_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a = attachment->priv; + + mutex_lock(&buffer->attachments_lock); + list_del(&a->list); + mutex_unlock(&buffer->attachments_lock); + + sg_free_table(a->table); + kfree(a->table); + kfree(a); +} + +static struct sg_table *dma_heap_map_dma_buf(struct dma_buf_attachment *attachment, + enum dma_data_direction direction) +{ + struct carveout_dma_heap_buffer *buffer = attachment->dmabuf->priv; + struct dma_heap_attachment *a = attachment->priv; + struct sg_table *table = a->table; + + unsigned long attrs = buffer->cached ? 0 : DMA_ATTR_SKIP_CPU_SYNC; + + if (!dma_map_sg_attrs(attachment->dev, table->sgl, table->nents, + direction, attrs)) + return ERR_PTR(-ENOMEM); + + return table; +} + +static void dma_heap_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *table, + enum dma_data_direction direction) +{ + struct carveout_dma_heap_buffer *buffer = attachment->dmabuf->priv; + unsigned long attrs = buffer->cached ? 0 : DMA_ATTR_SKIP_CPU_SYNC; + + dma_unmap_sg_attrs(attachment->dev, table->sgl, table->nents, + direction, attrs); +} + +static void dma_heap_dma_buf_release(struct dma_buf *dmabuf) +{ + struct carveout_dma_heap_buffer *buffer = dmabuf->priv; + + if (buffer->vmap_cnt > 0) { + WARN(1, "%s: buffer still mapped in the kernel\n", __func__); + memunmap(buffer->vaddr); + } + + gen_pool_free(buffer->pool, buffer->paddr, buffer->len); + kfree(buffer); +} + +static int dma_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + struct carveout_dma_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + + if (!buffer->cached) + return 0; + + mutex_lock(&buffer->vmap_lock); + if (buffer->vmap_cnt) + invalidate_kernel_vmap_range(buffer->vaddr, buffer->len); + mutex_unlock(&buffer->vmap_lock); + + mutex_lock(&buffer->attachments_lock); + list_for_each_entry(a, &buffer->attachments, list) { + dma_sync_sg_for_cpu(a->dev, a->table->sgl, a->table->nents, + direction); + } + mutex_unlock(&buffer->attachments_lock); + + return 0; +} + +static int dma_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + struct carveout_dma_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + + if (!buffer->cached) + return 0; + + mutex_lock(&buffer->vmap_lock); + if (buffer->vmap_cnt) + flush_kernel_vmap_range(buffer->vaddr, buffer->len); + mutex_unlock(&buffer->vmap_lock); + + mutex_lock(&buffer->attachments_lock); + list_for_each_entry(a, &buffer->attachments, list) { + dma_sync_sg_for_device(a->dev, a->table->sgl, a->table->nents, + direction); + } + mutex_unlock(&buffer->attachments_lock); + + return 0; +} + +static int dma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) +{ + struct carveout_dma_heap_buffer *buffer = dmabuf->priv; + int ret; + + if (!buffer->cached) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + ret = vm_iomap_memory(vma, buffer->paddr, buffer->len); + if (ret) + pr_err("Could not map buffer to userspace\n"); + + return ret; +} + +static int dma_heap_vmap(struct dma_buf *dmabuf, struct iosys_map *map) +{ + struct carveout_dma_heap_buffer *buffer = dmabuf->priv; + void *vaddr; + int ret = 0; + + mutex_lock(&buffer->vmap_lock); + + if (buffer->vmap_cnt) { + buffer->vmap_cnt++; + iosys_map_set_vaddr(map, buffer->vaddr); + goto exit; + } + if (buffer->cached) + vaddr = memremap(buffer->paddr, buffer->len, MEMREMAP_WB); + else + vaddr = memremap(buffer->paddr, buffer->len, MEMREMAP_WC); + if (!vaddr) { + pr_err("Could not memremap buffer\n"); + ret = -ENOMEM; + goto exit; + } + if (IS_ERR(vaddr)) { + ret = PTR_ERR(vaddr); + goto exit; + } + + buffer->vaddr = vaddr; + buffer->vmap_cnt++; + iosys_map_set_vaddr(map, buffer->vaddr); +exit: + mutex_unlock(&buffer->vmap_lock); + + return ret; +} + +static void dma_heap_vunmap(struct dma_buf *dmabuf, struct iosys_map *map) +{ + struct carveout_dma_heap_buffer *buffer = dmabuf->priv; + + mutex_lock(&buffer->vmap_lock); + if (!--buffer->vmap_cnt) { + memunmap(buffer->vaddr); + buffer->vaddr = NULL; + } + mutex_unlock(&buffer->vmap_lock); +} + +static const struct dma_buf_ops carveout_dma_heap_buf_ops = { + .attach = dma_heap_attach, + .detach = dma_heap_detatch, + .map_dma_buf = dma_heap_map_dma_buf, + .unmap_dma_buf = dma_heap_unmap_dma_buf, + .release = dma_heap_dma_buf_release, + .begin_cpu_access = dma_heap_dma_buf_begin_cpu_access, + .end_cpu_access = dma_heap_dma_buf_end_cpu_access, + .mmap = dma_heap_mmap, + .vmap = dma_heap_vmap, + .vunmap = dma_heap_vunmap, +}; + +static struct dma_buf *carveout_dma_heap_allocate(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + struct carveout_dma_heap *carveout_dma_heap = dma_heap_get_drvdata(heap); + struct carveout_dma_heap_buffer *buffer; + + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + struct dma_buf *dmabuf; + int ret = 0; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return ERR_PTR(-ENOMEM); + buffer->pool = carveout_dma_heap->pool; + buffer->cached = carveout_dma_heap->cached; + INIT_LIST_HEAD(&buffer->attachments); + mutex_init(&buffer->attachments_lock); + mutex_init(&buffer->vmap_lock); + buffer->len = len; + + buffer->paddr = gen_pool_alloc(buffer->pool, buffer->len); + if (!buffer->paddr) { + ret = -ENOMEM; + goto free_buffer; + } + + /* create the dmabuf */ + exp_info.exp_name = dma_heap_get_name(heap); + exp_info.ops = &carveout_dma_heap_buf_ops; + exp_info.size = buffer->len; + exp_info.flags = fd_flags; + exp_info.priv = buffer; + dmabuf = dma_buf_export(&exp_info); + if (IS_ERR(dmabuf)) { + ret = PTR_ERR(dmabuf); + goto free_pool; + } + + return dmabuf; + +free_pool: + gen_pool_free(buffer->pool, buffer->paddr, buffer->len); +free_buffer: + kfree(buffer); + + return ERR_PTR(ret); +} + +static struct dma_heap_ops carveout_dma_heap_ops = { + .allocate = carveout_dma_heap_allocate, +}; + +static int carveout_dma_heap_export(phys_addr_t base, size_t size, const char *name, bool cached) +{ + struct carveout_dma_heap *carveout_dma_heap; + struct dma_heap_export_info exp_info; + int ret; + + carveout_dma_heap = kzalloc(sizeof(*carveout_dma_heap), GFP_KERNEL); + if (!carveout_dma_heap) + return -ENOMEM; + + carveout_dma_heap->pool = gen_pool_create(PAGE_SHIFT, NUMA_NO_NODE); + if (IS_ERR(carveout_dma_heap->pool)) { + pr_err("Carveout Heap: Could not create memory pool\n"); + ret = PTR_ERR(carveout_dma_heap->pool); + goto free_carveout_dma_heap; + } + ret = gen_pool_add(carveout_dma_heap->pool, base, size, NUMA_NO_NODE); + if (ret) { + pr_err("Carveout Heap: Could not add memory to pool\n"); + goto free_pool; + } + + carveout_dma_heap->cached = cached; + + exp_info.name = kasprintf(GFP_KERNEL, "carveout_%s", name); + exp_info.ops = &carveout_dma_heap_ops; + exp_info.priv = carveout_dma_heap; + carveout_dma_heap->heap = dma_heap_add(&exp_info); + if (IS_ERR(carveout_dma_heap->heap)) { + pr_err("Carveout Heap: Could not add DMA-Heap\n"); + ret = PTR_ERR(carveout_dma_heap->heap); + goto free_pool; + } + + pr_info("Carveout Heap: Exported %zu MiB at %pa\n", size / SZ_1M, &base); + + return 0; + +free_pool: + gen_pool_destroy(carveout_dma_heap->pool); +free_carveout_dma_heap: + kfree(carveout_dma_heap); + return ret; +} + +#ifdef CONFIG_OF_RESERVED_MEM +#include +#include +#include + +#define MAX_HEAP_AREAS 7 +static struct reserved_mem heap_areas[MAX_HEAP_AREAS]; +static size_t heap_area_count; + +static int __init carveout_dma_heap_init_areas(void) +{ + int i; + + for (i = 0; i < heap_area_count; i++) { + struct reserved_mem *rmem = &heap_areas[i]; + bool cached = !of_get_flat_dt_prop(rmem->fdt_node, "no-map", NULL); + int ret = carveout_dma_heap_export(rmem->base, rmem->size, rmem->name, cached); + if (ret) { + pr_err("Carveout Heap: could not export as DMA-Heap\n"); + return ret; + } + } + + return 0; +} +fs_initcall(carveout_dma_heap_init_areas); + +static int __init rmem_dma_heap_carveout_setup(struct reserved_mem *rmem) +{ + phys_addr_t align = PAGE_SIZE; + phys_addr_t mask = align - 1; + + if ((rmem->base & mask) || (rmem->size & mask)) { + pr_err("Carveout Heap: incorrect alignment of region\n"); + return -EINVAL; + } + + /* Sanity check */ + if (heap_area_count == ARRAY_SIZE(heap_areas)) { + pr_err("Not enough slots for DMA-Heap reserved regions!\n"); + return -ENOSPC; + } + + /* + * Each reserved area must be initialized later, when more kernel + * subsystems (like slab allocator) are available. + */ + heap_areas[heap_area_count] = *rmem; + heap_area_count++; + + return 0; +} +RESERVEDMEM_OF_DECLARE(dma_heap_carveout, "dma-heap-carveout", rmem_dma_heap_carveout_setup); + +#endif diff -Naur --no-dereference a/drivers/dma-buf/heaps/Kconfig b/drivers/dma-buf/heaps/Kconfig --- a/drivers/dma-buf/heaps/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/dma-buf/heaps/Kconfig 2024-07-07 20:37:34.640306529 -0400 @@ -12,3 +12,13 @@ Choose this option to enable dma-buf CMA heap. This heap is backed by the Contiguous Memory Allocator (CMA). If your system has these regions, you should say Y here. + +config DMABUF_HEAPS_CARVEOUT + bool "DMA-BUF Carveout Heap" + depends on DMABUF_HEAPS && HAS_IOMEM + depends on OF_RESERVED_MEM + select GENERIC_ALLOCATOR + help + Choose this option to enable dma-buf Carveout heap. This heap is + backed by the a carved-out of memory. If your system has these + regions, you should say Y here. diff -Naur --no-dereference a/drivers/dma-buf/heaps/Makefile b/drivers/dma-buf/heaps/Makefile --- a/drivers/dma-buf/heaps/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/dma-buf/heaps/Makefile 2024-07-07 20:37:34.640306529 -0400 @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o obj-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o +obj-$(CONFIG_DMABUF_HEAPS_CARVEOUT) += carveout-heap.o diff -Naur --no-dereference a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c --- a/drivers/firmware/ti_sci.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/firmware/ti_sci.c 2024-07-07 20:37:34.644306549 -0400 @@ -10,21 +10,30 @@ #include #include +#include #include #include #include #include #include #include -#include +#include +#include +#include +#include #include #include #include #include +#include +#include #include #include "ti_sci.h" +/* Low power mode memory context size */ +#define LPM_CTX_MEM_SIZE 0x80000 + /* List of all TI SCI devices active in system */ static LIST_HEAD(ti_sci_list); /* Protection for the entire list */ @@ -84,7 +93,6 @@ * struct ti_sci_info - Structure representing a TI SCI instance * @dev: Device pointer * @desc: SoC description for this instance - * @nb: Reboot Notifier block * @d: Debugfs file entry * @debug_region: Memory region where the debug message are available * @debug_region_size: Debug region size @@ -96,11 +104,13 @@ * @minfo: Message info * @node: list head * @host_id: Host ID + * @ctx_mem_addr: Low power context memory phys address + * @ctx_mem_buf: Low power context memory buffer + * @fw_caps: FW/SoC low power capabilities * @users: Number of users of this instance */ struct ti_sci_info { struct device *dev; - struct notifier_block nb; const struct ti_sci_desc *desc; struct dentry *d; void __iomem *debug_region; @@ -113,13 +123,18 @@ struct ti_sci_xfers_info minfo; struct list_head node; u8 host_id; + dma_addr_t ctx_mem_addr; + void *ctx_mem_buf; + u64 fw_caps; /* protected by ti_sci_list_mutex */ int users; + + int nr_wakeup_sources; + struct device_node **wakeup_source_nodes; }; #define cl_to_ti_sci_info(c) container_of(c, struct ti_sci_info, cl) #define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle) -#define reboot_to_ti_sci_info(n) container_of(n, struct ti_sci_info, nb) #ifdef CONFIG_DEBUG_FS @@ -381,6 +396,28 @@ } /** + * ti_sci_do_send() - Do one send, do not expect a response + * @info: Pointer to SCI entity information + * @xfer: Transfer to initiate + * + * Return: If send error, return corresponding error, else + * if all goes well, return 0. + */ +static inline int ti_sci_do_send(struct ti_sci_info *info, + struct ti_sci_xfer *xfer) +{ + int ret; + + ret = mbox_send_message(info->chan_tx, &xfer->tx_message); + if (ret < 0) + return ret; + + mbox_client_txdone(info->chan_tx, ret); + + return 0; +} + +/** * ti_sci_do_xfer() - Do one transfer * @info: Pointer to SCI entity information * @xfer: Transfer to initiate and wait for response @@ -472,7 +509,7 @@ ver->abi_major = rev_info->abi_major; ver->abi_minor = rev_info->abi_minor; ver->firmware_revision = rev_info->firmware_revision; - strncpy(ver->firmware_description, rev_info->firmware_description, + strscpy(ver->firmware_description, rev_info->firmware_description, sizeof(ver->firmware_description)); fail: @@ -1651,6 +1688,258 @@ return ret; } +/** + * ti_sci_cmd_prepare_sleep() - Prepare system for system suspend + * @handle: pointer to TI SCI handle + * @mode: Device identifier + * @ctx_lo: Low part of address for context save + * @ctx_hi: High part of address for context save + * @debug_flags: Debug flags to pass to firmware + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode, + u32 ctx_lo, u32 ctx_hi, u32 debug_flags) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_prepare_sleep *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PREPARE_SLEEP, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + + req = (struct ti_sci_msg_req_prepare_sleep *)xfer->xfer_buf; + req->mode = mode; + req->ctx_lo = ctx_lo; + req->ctx_hi = ctx_hi; + req->debug_flags = debug_flags; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_msg_cmd_lpm_wake_reason() - Get the wakeup source from LPM + * @handle: Pointer to TI SCI handle + * @source: The wakeup source that woke the SoC from LPM + * @timestamp: Timestamp of the wakeup event + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_msg_cmd_lpm_wake_reason(const struct ti_sci_handle *handle, + u32 *source, u64 *timestamp) +{ + struct ti_sci_info *info; + struct ti_sci_xfer *xfer; + struct ti_sci_msg_resp_lpm_wake_reason *resp; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_LPM_WAKE_REASON, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(struct ti_sci_msg_hdr), + sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_resp_lpm_wake_reason *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) { + ret = -ENODEV; + goto fail; + } + + if (source) + *source = resp->wake_source; + if (timestamp) + *timestamp = resp->wake_timestamp; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_set_io_isolation() - Enable IO isolation in LPM + * @handle: Pointer to TI SCI handle + * @state: The desired state of the IO isolation + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_set_io_isolation(const struct ti_sci_handle *handle, + u8 state) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_set_io_isolation *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_IO_ISOLATION, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_set_io_isolation *)xfer->xfer_buf; + req->state = state; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/* + * This is the list of SoCs not affected by SYSFW Bug causing the fw_caps + * to return garbage values. + * As and when new SoC's start supporting low power modes, this struct can + * be updated with those new SOC family entries. + */ +static const struct soc_device_attribute has_lpm[] = { + { .family = "AM62X" }, + { .family = "AM62AX" }, + { .family = "AM62PX" }, + { /* sentinel */ } +}; + +/** + * ti_sci_msg_cmd_query_fw_caps() - Get the FW/SoC capabilities + * @handle: Pointer to TI SCI handle + * @fw_caps: Each bit in fw_caps indicating one FW/SOC capability + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_msg_cmd_query_fw_caps(const struct ti_sci_handle *handle, + u64 *fw_caps) +{ + struct ti_sci_info *info; + struct ti_sci_xfer *xfer; + struct ti_sci_msg_resp_query_fw_caps *resp; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_QUERY_FW_CAPS, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(struct ti_sci_msg_hdr), + sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_resp_query_fw_caps *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) { + ret = -ENODEV; + goto fail; + } + + /* + * fw_caps 1st bit is used to check Generic capability. Other than + * that the 1:4 bits are used for various LPM capabilities. + * The API is buggy on SYSFW 9.00 and below, on some devices. + * Hence, to avoid any sort of bugs arising due to garbage values + * Let's allow the fw_caps to be set to whatever the firmware + * says only on devices listed under has_lpm. These devices should + * have lpm features tested and implemented in the firmware + * and only then should they be added to has_lpm struct. + * Otherwise, set the value to 1 that is the default. + */ + if (fw_caps && soc_device_match(has_lpm)) + *fw_caps = resp->fw_caps; + else + *fw_caps = resp->fw_caps & MSG_FLAG_CAPS_GENERIC; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle) { struct ti_sci_info *info; @@ -2793,6 +3082,7 @@ struct ti_sci_core_ops *core_ops = &ops->core_ops; struct ti_sci_dev_ops *dops = &ops->dev_ops; struct ti_sci_clk_ops *cops = &ops->clk_ops; + struct ti_sci_pm_ops *pmops = &ops->pm_ops; struct ti_sci_rm_core_ops *rm_core_ops = &ops->rm_core_ops; struct ti_sci_rm_irq_ops *iops = &ops->rm_irq_ops; struct ti_sci_rm_ringacc_ops *rops = &ops->rm_ring_ops; @@ -2832,6 +3122,10 @@ cops->set_freq = ti_sci_cmd_clk_set_freq; cops->get_freq = ti_sci_cmd_clk_get_freq; + pmops->prepare_sleep = ti_sci_cmd_prepare_sleep; + pmops->lpm_wake_reason = ti_sci_msg_cmd_lpm_wake_reason; + pmops->set_io_isolation = ti_sci_cmd_set_io_isolation; + rm_core_ops->get_range = ti_sci_cmd_get_resource_range; rm_core_ops->get_range_from_shost = ti_sci_cmd_get_resource_range_from_shost; @@ -2873,7 +3167,6 @@ const struct ti_sci_handle *ti_sci_get_handle(struct device *dev) { struct device_node *ti_sci_np; - struct list_head *p; struct ti_sci_handle *handle = NULL; struct ti_sci_info *info; @@ -2888,8 +3181,7 @@ } mutex_lock(&ti_sci_list_mutex); - list_for_each(p, &ti_sci_list) { - info = list_entry(p, struct ti_sci_info, node); + list_for_each_entry(info, &ti_sci_list, node) { if (ti_sci_np == info->dev->of_node) { handle = &info->handle; info->users++; @@ -2999,7 +3291,6 @@ struct ti_sci_handle *handle = NULL; struct device_node *ti_sci_np; struct ti_sci_info *info; - struct list_head *p; if (!np) { pr_err("I need a device pointer\n"); @@ -3011,8 +3302,7 @@ return ERR_PTR(-ENODEV); mutex_lock(&ti_sci_list_mutex); - list_for_each(p, &ti_sci_list) { - info = list_entry(p, struct ti_sci_info, node); + list_for_each_entry(info, &ti_sci_list, node) { if (ti_sci_np == info->dev->of_node) { handle = &info->handle; info->users++; @@ -3255,10 +3545,9 @@ } EXPORT_SYMBOL_GPL(devm_ti_sci_get_resource); -static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode, - void *cmd) +static int tisci_reboot_handler(struct sys_off_data *data) { - struct ti_sci_info *info = reboot_to_ti_sci_info(nb); + struct ti_sci_info *info = data->cb_data; const struct ti_sci_handle *handle = &info->handle; ti_sci_cmd_core_reboot(handle); @@ -3267,6 +3556,167 @@ return NOTIFY_BAD; } +static int ti_sci_prepare_system_suspend(struct ti_sci_info *info) +{ +#if IS_ENABLED(CONFIG_SUSPEND) + u8 mode; + + /* Map and validate the target Linux suspend state to TISCI LPM. */ + switch (pm_suspend_target_state) { + case PM_SUSPEND_MEM: + /* S2MEM is not supported by the firmware. */ + if (!(info->fw_caps & MSG_FLAG_CAPS_LPM_DEEP_SLEEP)) + return 0; + mode = TISCI_MSG_VALUE_SLEEP_MODE_DEEP_SLEEP; + break; + default: + /* + * Do not fail if we don't have action to take for a + * specific suspend mode. + */ + return 0; + } + + return ti_sci_cmd_prepare_sleep(&info->handle, mode, + (u32)(info->ctx_mem_addr & 0xffffffff), + (u32)((u64)info->ctx_mem_addr >> 32), 0); +#else + return 0; +#endif +} + +static int ti_sci_suspend(struct device *dev) +{ + struct ti_sci_info *info = dev_get_drvdata(dev); + int ret; + + ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_ENABLE); + if (ret) + return ret; + dev_dbg(dev, "%s: set isolation: %d\n", __func__, ret); + + ret = ti_sci_prepare_system_suspend(info); + if (ret) + return ret; + + return 0; +} + +static int ti_sci_resume(struct device *dev) +{ + struct ti_sci_info *info = dev_get_drvdata(dev); + u32 source; + u64 time; + int ret = 0; + + ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_DISABLE); + if (ret) + return ret; + dev_dbg(dev, "%s: disable isolation: %d\n", __func__, ret); + + ti_sci_msg_cmd_lpm_wake_reason(&info->handle, &source, &time); + dev_info(dev, "%s: wakeup source: 0x%X\n", __func__, source); + + return 0; +} + +static const struct dev_pm_ops ti_sci_pm_ops = { + .suspend_noirq = ti_sci_suspend, + .resume_noirq = ti_sci_resume, +}; + +static int ti_sci_init_suspend(struct platform_device *pdev, + struct ti_sci_info *info) +{ + struct device *dev = &pdev->dev; + + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + info->ctx_mem_buf = dma_alloc_attrs(info->dev, LPM_CTX_MEM_SIZE, + &info->ctx_mem_addr, + GFP_KERNEL, + DMA_ATTR_NO_KERNEL_MAPPING | + DMA_ATTR_FORCE_CONTIGUOUS); + if (!info->ctx_mem_buf) { + dev_err(info->dev, "Failed to allocate LPM context memory\n"); + return -ENOMEM; + } + + return 0; +} + +/* Does not return if successful */ +static int tisci_enter_partial_io(struct ti_sci_info *info) +{ + struct ti_sci_msg_req_prepare_sleep *req; + struct ti_sci_xfer *xfer; + struct device *dev = info->dev; + int ret = 0; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PREPARE_SLEEP, + TI_SCI_FLAG_REQ_GENERIC_NORESPONSE, + sizeof(*req), sizeof(struct ti_sci_msg_hdr)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + + req = (struct ti_sci_msg_req_prepare_sleep *)xfer->xfer_buf; + req->mode = TISCI_MSG_VALUE_SLEEP_MODE_PARTIAL_IO; + req->ctx_lo = 0; + req->ctx_hi = 0; + req->debug_flags = 0; + + ret = ti_sci_do_send(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +static int tisci_sys_off_handler(struct sys_off_data *data) +{ + struct ti_sci_info *info = data->cb_data; + int i; + int ret; + bool enter_partial_io = false; + + for (i = 0; i != info->nr_wakeup_sources; ++i) { + struct platform_device *pdev = + of_find_device_by_node(info->wakeup_source_nodes[i]); + + if (!pdev) + continue; + + if (device_may_wakeup(&pdev->dev)) { + dev_dbg(info->dev, "%pOFp identified as wakeup source\n", + info->wakeup_source_nodes[i]); + enter_partial_io = true; + } + } + + if (!enter_partial_io) + return NOTIFY_DONE; + + ret = tisci_enter_partial_io(info); + + if (ret) + dev_err(info->dev, + "Failed to enter Partial-IO %pe, halting system\n", + ERR_PTR(ret)); + + /* Halt system/code execution */ + while (1) + ; + + return NOTIFY_DONE; +} + /* Description for K2G */ static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = { .default_host_id = 2, @@ -3297,7 +3747,6 @@ static int ti_sci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct of_device_id *of_id; const struct ti_sci_desc *desc; struct ti_sci_xfer *xfer; struct ti_sci_info *info = NULL; @@ -3305,15 +3754,9 @@ struct mbox_client *cl; int ret = -EINVAL; int i; - int reboot = 0; u32 h_id; - of_id = of_match_device(ti_sci_of_match, dev); - if (!of_id) { - dev_err(dev, "OF data missing\n"); - return -EINVAL; - } - desc = of_id->data; + desc = device_get_match_data(dev); info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) @@ -3334,8 +3777,6 @@ } } - reboot = of_property_read_bool(dev->of_node, - "ti,system-reboot-controller"); INIT_LIST_HEAD(&info->node); minfo = &info->minfo; @@ -3406,13 +3847,46 @@ ti_sci_setup_ops(info); - if (reboot) { - info->nb.notifier_call = tisci_reboot_handler; - info->nb.priority = 128; + ret = devm_register_restart_handler(dev, tisci_reboot_handler, info); + if (ret) { + dev_err(dev, "reboot registration fail(%d)\n", ret); + goto out; + } + + /* + * Check if the firmware supports any optional low power modes + * and initialize them if present. Old revisions of TIFS (< 08.04) + * will NACK the request. + */ + ret = ti_sci_msg_cmd_query_fw_caps(&info->handle, &info->fw_caps); + if (!ret && (info->fw_caps & MSG_MASK_CAPS_LPM)) + ti_sci_init_suspend(pdev, info); + + if (of_property_read_bool(dev->of_node, "ti,partial-io-wakeup-sources")) { + info->nr_wakeup_sources = + of_count_phandle_with_args(dev->of_node, + "ti,partial-io-wakeup-sources", + NULL); + info->wakeup_source_nodes = + devm_kzalloc(dev, sizeof(*info->wakeup_source_nodes), + GFP_KERNEL); + + for (i = 0; i != info->nr_wakeup_sources; ++i) { + struct device_node *devnode = + of_parse_phandle(dev->of_node, + "ti,partial-io-wakeup-sources", + i); + info->wakeup_source_nodes[i] = devnode; + } - ret = register_restart_handler(&info->nb); + ret = devm_register_sys_off_handler(dev, + SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_FIRMWARE, + tisci_sys_off_handler, + info); if (ret) { - dev_err(dev, "reboot registration fail(%d)\n", ret); + dev_err(dev, "Failed to register sys_off_handler %pe\n", + ERR_PTR(ret)); goto out; } } @@ -3426,7 +3900,13 @@ list_add_tail(&info->node, &ti_sci_list); mutex_unlock(&ti_sci_list_mutex); - return of_platform_populate(dev->of_node, NULL, NULL, dev); + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); + if (ret) { + dev_err(dev, "platform_populate failed %pe\n", ERR_PTR(ret)); + goto out; + } + return 0; + out: if (!IS_ERR(info->chan_tx)) mbox_free_channel(info->chan_tx); @@ -3442,6 +3922,7 @@ .name = "ti-sci", .of_match_table = of_match_ptr(ti_sci_of_match), .suppress_bind_attrs = true, + .pm = &ti_sci_pm_ops, }, }; module_platform_driver(ti_sci_driver); diff -Naur --no-dereference a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h --- a/drivers/firmware/ti_sci.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/firmware/ti_sci.h 2024-07-07 20:37:34.644306549 -0400 @@ -6,7 +6,7 @@ * The system works in a message response protocol * See: http://processors.wiki.ti.com/index.php/TISCI for details * - * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2015-2022 Texas Instruments Incorporated - https://www.ti.com/ */ #ifndef __TI_SCI_H @@ -19,6 +19,7 @@ #define TI_SCI_MSG_WAKE_REASON 0x0003 #define TI_SCI_MSG_GOODBYE 0x0004 #define TI_SCI_MSG_SYS_RESET 0x0005 +#define TI_SCI_MSG_QUERY_FW_CAPS 0x0022 /* Device requests */ #define TI_SCI_MSG_SET_DEVICE_STATE 0x0200 @@ -35,6 +36,11 @@ #define TI_SCI_MSG_QUERY_CLOCK_FREQ 0x010d #define TI_SCI_MSG_GET_CLOCK_FREQ 0x010e +/* Low Power Mode Requests */ +#define TI_SCI_MSG_PREPARE_SLEEP 0x0300 +#define TI_SCI_MSG_LPM_WAKE_REASON 0x0306 +#define TI_SCI_MSG_SET_IO_ISOLATION 0x0307 + /* Resource Management Requests */ #define TI_SCI_MSG_GET_RESOURCE_RANGE 0x1500 @@ -133,6 +139,31 @@ } __packed; /** + * struct ti_sci_msg_resp_query_fw_caps - Response for query firmware caps + * @hdr: Generic header + * @fw_caps: Each bit in fw_caps indicating one FW/SOC capability + * MSG_FLAG_CAPS_GENERIC: Generic capability (LPM not supported) + * MSG_FLAG_CAPS_LPM_DEEP_SLEEP: Deep Sleep LPM + * MSG_FLAG_CAPS_LPM_MCU_ONLY: MCU only LPM + * MSG_FLAG_CAPS_LPM_STANDBY: Standby LPM + * MSG_FLAG_CAPS_LPM_PARTIAL_IO: Partial IO in LPM + * + * Response to a generic message with message type TI_SCI_MSG_QUERY_FW_CAPS + * providing currently available SOC/firmware capabilities. SoC that don't + * support low power modes return only MSG_FLAG_CAPS_GENERIC capability. + */ +struct ti_sci_msg_resp_query_fw_caps { + struct ti_sci_msg_hdr hdr; +#define MSG_FLAG_CAPS_GENERIC TI_SCI_MSG_FLAG(0) +#define MSG_FLAG_CAPS_LPM_DEEP_SLEEP TI_SCI_MSG_FLAG(1) +#define MSG_FLAG_CAPS_LPM_MCU_ONLY TI_SCI_MSG_FLAG(2) +#define MSG_FLAG_CAPS_LPM_STANDBY TI_SCI_MSG_FLAG(3) +#define MSG_FLAG_CAPS_LPM_PARTIAL_IO TI_SCI_MSG_FLAG(4) +#define MSG_MASK_CAPS_LPM GENMASK_ULL(4, 1) + u64 fw_caps; +} __packed; + +/** * struct ti_sci_msg_req_set_device_state - Set the desired state of the device * @hdr: Generic header * @id: Indicates which device to modify @@ -545,6 +576,64 @@ u64 freq_hz; } __packed; +#define TISCI_MSG_VALUE_SLEEP_MODE_DEEP_SLEEP 0x0 +#define TISCI_MSG_VALUE_SLEEP_MODE_MCU_ONLY 0x1 +#define TISCI_MSG_VALUE_SLEEP_MODE_STANDBY 0x2 +#define TISCI_MSG_VALUE_SLEEP_MODE_PARTIAL_IO 0x3 + +/** + * struct tisci_msg_prepare_sleep_req - Request for TISCI_MSG_PREPARE_SLEEP. + * + * @hdr TISCI header to provide ACK/NAK flags to the host. + * @mode Low power mode to enter. + * @ctx_lo Low 32-bits of physical pointer to address to use for context save. + * @ctx_hi High 32-bits of physical pointer to address to use for context save. + * @debug_flags Flags that can be set to halt the sequence during suspend or + * resume to allow JTAG connection and debug. + * + * This message is used as the first step of entering a low power mode. It + * allows configurable information, including which state to enter to be + * easily shared from the application, as this is a non-secure message and + * therefore can be sent by anyone. + */ +struct ti_sci_msg_req_prepare_sleep { + struct ti_sci_msg_hdr hdr; + u8 mode; + u32 ctx_lo; + u32 ctx_hi; + u32 debug_flags; +} __packed; + +/** + * struct ti_sci_msg_resp_lpm_wake_reason - Response for TI_SCI_MSG_LPM_WAKE_REASON. + * + * @hdr: Generic header. + * @wake_source: The wake up source that woke soc from LPM. + * @wake_timestamp: Timestamp at which soc woke. + * + * Response to a generic message with message type TI_SCI_MSG_LPM_WAKE_REASON, + * used to query the wake up source from low power mode. + */ +struct ti_sci_msg_resp_lpm_wake_reason { + struct ti_sci_msg_hdr hdr; + u32 wake_source; + u64 wake_timestamp; +} __packed; + +/** + * struct tisci_msg_set_io_isolation_req - Request for TI_SCI_MSG_SET_IO_ISOLATION. + * + * @hdr: Generic header + * @state: The deseared state of the IO isolation. + * + * This message is used to enable/disable IO isolation for low power modes. + * Response is generic ACK / NACK message. + */ +struct ti_sci_msg_req_set_io_isolation { + struct ti_sci_msg_hdr hdr; + u8 state; +} __packed; + #define TI_SCI_IRQ_SECONDARY_HOST_INVALID 0xff /** diff -Naur --no-dereference a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c --- a/drivers/gpio/gpio-pca953x.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpio/gpio-pca953x.c 2024-07-07 20:37:34.644306549 -0400 @@ -1201,7 +1201,6 @@ regulator_disable(chip->regulator); } -#ifdef CONFIG_PM_SLEEP static int pca953x_regcache_sync(struct device *dev) { struct pca953x_chip *chip = dev_get_drvdata(dev); @@ -1251,7 +1250,7 @@ return 0; } -static int pca953x_suspend(struct device *dev) +static int pca953x_suspend_noirq(struct device *dev) { struct pca953x_chip *chip = dev_get_drvdata(dev); @@ -1267,7 +1266,7 @@ return 0; } -static int pca953x_resume(struct device *dev) +static int pca953x_resume_noirq(struct device *dev) { struct pca953x_chip *chip = dev_get_drvdata(dev); int ret; @@ -1298,7 +1297,6 @@ return 0; } -#endif /* convenience to stop overlong match-table lines */ #define OF_653X(__nrgpio, __int) ((void *)(__nrgpio | PCAL653X_TYPE | __int)) @@ -1356,7 +1354,8 @@ MODULE_DEVICE_TABLE(of, pca953x_dt_ids); -static SIMPLE_DEV_PM_OPS(pca953x_pm_ops, pca953x_suspend, pca953x_resume); +static DEFINE_NOIRQ_DEV_PM_OPS(pca953x_pm_ops, + pca953x_suspend_noirq, pca953x_resume_noirq); static struct i2c_driver pca953x_driver = { .driver = { diff -Naur --no-dereference a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c --- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c 2024-07-07 20:37:34.644306549 -0400 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -574,7 +575,7 @@ if (ret) return ret; - phy_mipi_dphy_get_default_config(mode->crtc_clock * 1000, + phy_mipi_dphy_get_default_config((mode_valid_check ? mode->clock : mode->crtc_clock) * 1000, mipi_dsi_pixel_format_to_bpp(output->dev->format), nlanes, phy_cfg); @@ -655,7 +656,8 @@ return MODE_OK; } -static void cdns_dsi_bridge_disable(struct drm_bridge *bridge) +static void cdns_dsi_bridge_atomic_late_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); struct cdns_dsi *dsi = input_to_dsi(input); @@ -675,14 +677,6 @@ pm_runtime_put(dsi->base.dev); } -static void cdns_dsi_bridge_post_disable(struct drm_bridge *bridge) -{ - struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); - struct cdns_dsi *dsi = input_to_dsi(input); - - pm_runtime_put(dsi->base.dev); -} - static void cdns_dsi_hs_init(struct cdns_dsi *dsi) { struct cdns_dsi_output *output = &dsi->output; @@ -752,7 +746,8 @@ dsi->link_initialized = true; } -static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) +static void cdns_dsi_bridge_atomic_early_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); struct cdns_dsi *dsi = input_to_dsi(input); @@ -761,7 +756,7 @@ struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy; unsigned long tx_byte_period; struct cdns_dsi_cfg dsi_cfg; - u32 tmp, reg_wakeup, div; + u32 tmp, reg_wakeup, div, status; int nlanes; if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0)) @@ -775,8 +770,19 @@ WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, false)); - cdns_dsi_hs_init(dsi); cdns_dsi_init_link(dsi); + cdns_dsi_hs_init(dsi); + + /* + * Now that the DSI Link and DSI Phy are initialized, + * wait for the CLK and Data Lanes to be ready. + */ + tmp = CLK_LANE_RDY; + for (int i = 0; i < nlanes; i++) + tmp |= DATA_LANE_RDY(i); + + WARN_ON_ONCE(readl_poll_timeout(dsi->regs + MCTL_MAIN_STS, status, + status & tmp, 100, 0)); writel(HBP_LEN(dsi_cfg.hbp) | HSA_LEN(dsi_cfg.hsa), dsi->regs + VID_HSIZE1); @@ -892,25 +898,60 @@ writel(tmp, dsi->regs + MCTL_MAIN_EN); } -static void cdns_dsi_bridge_pre_enable(struct drm_bridge *bridge) +static u32 *cdns_dsi_bridge_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) { struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); struct cdns_dsi *dsi = input_to_dsi(input); + struct cdns_dsi_output *output = &dsi->output; + u32 *input_fmts; - if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0)) - return; + *num_input_fmts = 0; - cdns_dsi_init_link(dsi); - cdns_dsi_hs_init(dsi); + input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL); + if (!input_fmts) + return NULL; + + switch (output->dev->format) { + case MIPI_DSI_FMT_RGB888: + input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; + break; + + case MIPI_DSI_FMT_RGB666: + input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; + break; + + case MIPI_DSI_FMT_RGB666_PACKED: + input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X18; + break; + + case MIPI_DSI_FMT_RGB565: + input_fmts[0] = MEDIA_BUS_FMT_RGB565_1X16; + break; + + default: + /* Unsupported DSI Format */ + return NULL; + } + + *num_input_fmts = 1; + + return input_fmts; } static const struct drm_bridge_funcs cdns_dsi_bridge_funcs = { .attach = cdns_dsi_bridge_attach, .mode_valid = cdns_dsi_bridge_mode_valid, - .disable = cdns_dsi_bridge_disable, - .pre_enable = cdns_dsi_bridge_pre_enable, - .enable = cdns_dsi_bridge_enable, - .post_disable = cdns_dsi_bridge_post_disable, + .atomic_early_enable = cdns_dsi_bridge_atomic_early_enable, + .atomic_late_disable = cdns_dsi_bridge_atomic_late_disable, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_get_input_bus_fmts = cdns_dsi_bridge_get_input_bus_fmts, }; static int cdns_dsi_attach(struct mipi_dsi_host *host, @@ -952,7 +993,7 @@ bridge = drm_panel_bridge_add_typed(panel, DRM_MODE_CONNECTOR_DSI); } else { - bridge = of_drm_find_bridge(dev->dev.of_node); + bridge = of_drm_find_bridge(np); if (!bridge) bridge = ERR_PTR(-EINVAL); } @@ -1026,6 +1067,9 @@ cdns_dsi_init_link(dsi); + /* Reset the DCS Write FIFO */ + writel(0x00, dsi->regs + DIRECT_CMD_FIFO_RST); + ret = mipi_dsi_create_packet(&packet, msg); if (ret) goto out; @@ -1153,6 +1197,7 @@ clk_disable_unprepare(dsi->dsi_p_clk); reset_control_assert(dsi->dsi_p_rst); dsi->link_initialized = false; + dsi->phy_initialized = false; return 0; } diff -Naur --no-dereference a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c 2024-07-07 20:37:34.644306549 -0400 @@ -53,6 +53,8 @@ #include "cdns-mhdp8546-hdcp.h" #include "cdns-mhdp8546-j721e.h" +static int cdns_mhdp_update_link_status(struct cdns_mhdp_device *mhdp); + static void cdns_mhdp_bridge_hpd_enable(struct drm_bridge *bridge) { struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); @@ -768,7 +770,8 @@ * MHDP_HW_STOPPED happens only due to driver removal when * bridge should already be detached. */ - cdns_mhdp_bridge_hpd_enable(&mhdp->bridge); + if (!mhdp->no_hpd) + cdns_mhdp_bridge_hpd_enable(&mhdp->bridge); spin_unlock(&mhdp->start_lock); @@ -862,7 +865,7 @@ ret = cdns_mhdp_dpcd_read(mhdp, msg->address, msg->buffer, msg->size); if (ret) { - dev_err(mhdp->dev, + dev_dbg(mhdp->dev, "Failed to read DPCD addr %u\n", msg->address); @@ -1615,24 +1618,6 @@ return true; } -static -enum drm_mode_status cdns_mhdp_mode_valid(struct drm_connector *conn, - struct drm_display_mode *mode) -{ - struct cdns_mhdp_device *mhdp = connector_to_mhdp(conn); - - mutex_lock(&mhdp->link_mutex); - - if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes, - mhdp->link.rate)) { - mutex_unlock(&mhdp->link_mutex); - return MODE_CLOCK_HIGH; - } - - mutex_unlock(&mhdp->link_mutex); - return MODE_OK; -} - static int cdns_mhdp_connector_atomic_check(struct drm_connector *conn, struct drm_atomic_state *state) { @@ -1676,7 +1661,6 @@ static const struct drm_connector_helper_funcs cdns_mhdp_conn_helper_funcs = { .detect_ctx = cdns_mhdp_connector_detect, .get_modes = cdns_mhdp_get_modes, - .mode_valid = cdns_mhdp_mode_valid, .atomic_check = cdns_mhdp_connector_atomic_check, }; @@ -1755,6 +1739,19 @@ spin_unlock(&mhdp->start_lock); + if (mhdp->no_hpd) { + ret = wait_event_timeout(mhdp->fw_load_wq, + mhdp->hw_state == MHDP_HW_READY, + msecs_to_jiffies(100)); + if (ret == 0) { + dev_err(mhdp->dev, "%s: Timeout waiting for fw loading\n", + __func__); + return -ETIMEDOUT; + } + + cdns_mhdp_update_link_status(mhdp); + return 0; + } /* Enable SW event interrupts */ if (hw_ready) cdns_mhdp_bridge_hpd_enable(bridge); @@ -2228,6 +2225,25 @@ return cdns_mhdp_get_edid(mhdp, connector); } +static enum drm_mode_status +cdns_mhdp_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); + + mutex_lock(&mhdp->link_mutex); + + if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes, + mhdp->link.rate)) { + mutex_unlock(&mhdp->link_mutex); + return MODE_CLOCK_HIGH; + } + + mutex_unlock(&mhdp->link_mutex); + return MODE_OK; +} + static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { .atomic_enable = cdns_mhdp_atomic_enable, .atomic_disable = cdns_mhdp_atomic_disable, @@ -2242,6 +2258,7 @@ .get_edid = cdns_mhdp_bridge_get_edid, .hpd_enable = cdns_mhdp_bridge_hpd_enable, .hpd_disable = cdns_mhdp_bridge_hpd_disable, + .mode_valid = cdns_mhdp_bridge_mode_valid, }; static bool cdns_mhdp_detect_hpd(struct cdns_mhdp_device *mhdp, bool *hpd_pulse) @@ -2284,7 +2301,16 @@ mutex_lock(&mhdp->link_mutex); - mhdp->plugged = cdns_mhdp_detect_hpd(mhdp, &hpd_pulse); + if (mhdp->no_hpd) { + ret = drm_dp_dpcd_read_link_status(&mhdp->aux, status); + hpd_pulse = false; + if (ret < 0) + mhdp->plugged = false; + else + mhdp->plugged = true; + } else { + mhdp->plugged = cdns_mhdp_detect_hpd(mhdp, &hpd_pulse); + } if (!mhdp->plugged) { cdns_mhdp_link_down(mhdp); @@ -2479,6 +2505,8 @@ mhdp->aux.dev = dev; mhdp->aux.transfer = cdns_mhdp_transfer; + mhdp->no_hpd = of_property_read_bool(dev->of_node, "cdns,no-hpd"); + mhdp->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mhdp->regs)) { dev_err(dev, "Failed to get memory resource\n"); @@ -2554,8 +2582,9 @@ mhdp->bridge.of_node = pdev->dev.of_node; mhdp->bridge.funcs = &cdns_mhdp_bridge_funcs; - mhdp->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | - DRM_BRIDGE_OP_HPD; + mhdp->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID; + if (!mhdp->no_hpd) + mhdp->bridge.ops |= DRM_BRIDGE_OP_HPD; mhdp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; ret = phy_init(mhdp->phy); diff -Naur --no-dereference a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h 2024-07-07 20:37:34.644306549 -0400 @@ -388,6 +388,7 @@ bool link_up; bool plugged; + bool no_hpd; /* * "start_lock" protects the access to bridge_attached and diff -Naur --no-dereference a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c --- a/drivers/gpu/drm/bridge/ite-it66121.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/bridge/ite-it66121.c 2024-07-07 20:37:34.644306549 -0400 @@ -1505,7 +1505,6 @@ static int it66121_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); u32 revision_id, vendor_ids[2] = { 0 }, device_ids[2] = { 0 }; struct device_node *ep; int ret; @@ -1527,7 +1526,7 @@ ctx->dev = dev; ctx->client = client; - ctx->info = (const struct it66121_chip_info *) id->driver_data; + ctx->info = i2c_get_match_data(client); of_property_read_u32(ep, "bus-width", &ctx->bus_width); of_node_put(ep); @@ -1613,13 +1612,6 @@ mutex_destroy(&ctx->lock); } -static const struct of_device_id it66121_dt_match[] = { - { .compatible = "ite,it66121" }, - { .compatible = "ite,it6610" }, - { } -}; -MODULE_DEVICE_TABLE(of, it66121_dt_match); - static const struct it66121_chip_info it66121_chip_info = { .id = ID_IT66121, .vid = 0x4954, @@ -1632,6 +1624,13 @@ .pid = 0x0611, }; +static const struct of_device_id it66121_dt_match[] = { + { .compatible = "ite,it66121", &it66121_chip_info }, + { .compatible = "ite,it6610", &it6610_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, it66121_dt_match); + static const struct i2c_device_id it66121_id[] = { { "it66121", (kernel_ulong_t) &it66121_chip_info }, { "it6610", (kernel_ulong_t) &it6610_chip_info }, diff -Naur --no-dereference a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c --- a/drivers/gpu/drm/bridge/sii902x.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/bridge/sii902x.c 2024-07-07 20:37:34.644306549 -0400 @@ -163,6 +163,14 @@ #define SII902X_AUDIO_PORT_INDEX 3 +/* + * The maximum resolution supported by the HDMI bridge is 1080p@60Hz + * and 1920x1200 requiring a pixel clock of 165MHz and the minimum + * resolution supported is 480p@60Hz requiring a pixel clock of 25MHz + */ +#define SII902X_MIN_PIXEL_CLOCK_KHZ 25000 +#define SII902X_MAX_PIXEL_CLOCK_KHZ 165000 + struct sii902x { struct i2c_client *i2c; struct regmap *regmap; @@ -172,6 +180,10 @@ struct gpio_desc *reset_gpio; struct i2c_mux_core *i2cmux; bool sink_is_hdmi; + struct device_link *link; + unsigned int ctx_tpi; + unsigned int ctx_interrupt; + /* * Mutex protects audio and video functions from interfering * each other, by keeping their i2c command sequences atomic. @@ -314,17 +326,8 @@ return num; } -static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - /* TODO: check mode */ - - return MODE_OK; -} - static const struct drm_connector_helper_funcs sii902x_connector_helper_funcs = { .get_modes = sii902x_get_modes, - .mode_valid = sii902x_mode_valid, }; static void sii902x_bridge_disable(struct drm_bridge *bridge) @@ -422,8 +425,15 @@ struct sii902x *sii902x = bridge_to_sii902x(bridge); u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; struct drm_device *drm = bridge->dev; + struct device *dev = &sii902x->i2c->dev; int ret; + sii902x->link = device_link_add(drm->dev, dev, DL_FLAG_STATELESS); + if (!sii902x->link) { + dev_err(dev, "failed to create device link"); + return -EINVAL; + } + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) return drm_bridge_attach(bridge->encoder, sii902x->next_bridge, bridge, flags); @@ -432,16 +442,17 @@ &sii902x_connector_helper_funcs); if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) { - dev_err(&sii902x->i2c->dev, + dev_err(dev, "sii902x driver is only compatible with DRM devices supporting atomic updates\n"); - return -ENOTSUPP; + ret = -EOPNOTSUPP; + goto err_bridge_attach; } ret = drm_connector_init(drm, &sii902x->connector, &sii902x_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); if (ret) - return ret; + goto err_bridge_attach; if (sii902x->i2c->irq > 0) sii902x->connector.polled = DRM_CONNECTOR_POLL_HPD; @@ -451,11 +462,24 @@ ret = drm_display_info_set_bus_formats(&sii902x->connector.display_info, &bus_format, 1); if (ret) - return ret; + goto err_bridge_attach; drm_connector_attach_encoder(&sii902x->connector, bridge->encoder); return 0; + +err_bridge_attach: + device_link_del(sii902x->link); + + return ret; +} + +static void sii902x_bridge_detach(struct drm_bridge *bridge) +{ + struct sii902x *sii902x = bridge_to_sii902x(bridge); + + if (sii902x->link) + device_link_del(sii902x->link); } static enum drm_connector_status sii902x_bridge_detect(struct drm_bridge *bridge) @@ -499,6 +523,12 @@ struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { + if (crtc_state->mode.clock < SII902X_MIN_PIXEL_CLOCK_KHZ) + return MODE_CLOCK_LOW; + + if (crtc_state->mode.clock > SII902X_MAX_PIXEL_CLOCK_KHZ) + return MODE_CLOCK_HIGH; + /* * There might be flags negotiation supported in future but * set the bus flags in atomic_check statically for now. @@ -508,8 +538,23 @@ return 0; } +static enum drm_mode_status +sii902x_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + if (mode->clock < SII902X_MIN_PIXEL_CLOCK_KHZ) + return MODE_CLOCK_LOW; + + if (mode->clock > SII902X_MAX_PIXEL_CLOCK_KHZ) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + static const struct drm_bridge_funcs sii902x_bridge_funcs = { .attach = sii902x_bridge_attach, + .detach = sii902x_bridge_detach, .mode_set = sii902x_bridge_mode_set, .disable = sii902x_bridge_disable, .enable = sii902x_bridge_enable, @@ -520,6 +565,7 @@ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_get_input_bus_fmts = sii902x_bridge_atomic_get_input_bus_fmts, .atomic_check = sii902x_bridge_atomic_check, + .mode_valid = sii902x_bridge_mode_valid, }; static int sii902x_mute(struct sii902x *sii902x, bool mute) @@ -1038,6 +1084,58 @@ | DRM_BUS_FLAG_DE_HIGH, }; +static int __maybe_unused sii902x_resume(struct device *dev) +{ + struct sii902x *sii902x = dev_get_drvdata(dev); + unsigned int tpi_reg, status; + int ret; + + ret = regmap_read(sii902x->regmap, SII902X_REG_TPI_RQB, &tpi_reg); + if (ret) + return ret; + + if (tpi_reg != sii902x->ctx_tpi) { + /* + * TPI register context has changed. SII902X power supply + * device has been turned off and on. + */ + + sii902x_reset(sii902x); + + /* Configure the device to enter TPI mode. */ + ret = regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x0); + if (ret) + return ret; + + /* Re enable the interrupts */ + regmap_write(sii902x->regmap, SII902X_INT_ENABLE, + sii902x->ctx_interrupt); + } + + /* Clear all pending interrupts */ + regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); + regmap_write(sii902x->regmap, SII902X_INT_STATUS, status); + + return 0; +} + +static int __maybe_unused sii902x_suspend(struct device *dev) +{ + struct sii902x *sii902x = dev_get_drvdata(dev); + + regmap_read(sii902x->regmap, SII902X_REG_TPI_RQB, + &sii902x->ctx_tpi); + + regmap_read(sii902x->regmap, SII902X_INT_ENABLE, + &sii902x->ctx_interrupt); + + return 0; +} + +static const struct dev_pm_ops sii902x_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sii902x_suspend, sii902x_resume) +}; + static int sii902x_init(struct sii902x *sii902x) { struct device *dev = &sii902x->i2c->dev; @@ -1211,6 +1309,7 @@ .remove = sii902x_remove, .driver = { .name = "sii902x", + .pm = &sii902x_pm_ops, .of_match_table = sii902x_dt_ids, }, .id_table = sii902x_i2c_ids, diff -Naur --no-dereference a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c --- a/drivers/gpu/drm/bridge/tc358767.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/bridge/tc358767.c 2024-07-07 20:37:34.644306549 -0400 @@ -1579,6 +1579,13 @@ struct drm_connector *connector) { struct tc_data *tc = bridge_to_tc(bridge); + int ret; + + ret = tc_get_display_props(tc); + if (ret < 0) { + dev_err(tc->dev, "failed to read display props: %d\n", ret); + return 0; + } return drm_get_edid(connector, &tc->aux.ddc); } @@ -1726,6 +1733,7 @@ } #define MAX_INPUT_SEL_FORMATS 1 +#define MAX_OUTPUT_SEL_FORMATS 1 static u32 * tc_dpi_atomic_get_input_bus_fmts(struct drm_bridge *bridge, @@ -1751,6 +1759,28 @@ return input_fmts; } +static u32 * +tc_edp_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + unsigned int *num_output_fmts) +{ + u32 *output_fmts; + + *num_output_fmts = 0; + + output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts), + GFP_KERNEL); + if (!output_fmts) + return NULL; + + output_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; + *num_output_fmts = 1; + + return output_fmts; +} + static const struct drm_bridge_funcs tc_dpi_bridge_funcs = { .attach = tc_dpi_bridge_attach, .mode_valid = tc_dpi_mode_valid, @@ -1777,6 +1807,8 @@ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt, + .atomic_get_output_bus_fmts = tc_edp_atomic_get_output_bus_fmts, }; static bool tc_readable_reg(struct device *dev, unsigned int reg) diff -Naur --no-dereference a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c 2024-07-07 20:37:34.644306549 -0400 @@ -152,6 +152,7 @@ * @ln_assign: Value to program to the LN_ASSIGN register. * @ln_polrs: Value for the 4-bit LN_POLRS field of SN_ENH_FRAME_REG. * @comms_enabled: If true then communication over the aux channel is enabled. + * @plugged: Plug connection status * @comms_mutex: Protects modification of comms_enabled. * * @gchip: If we expose our GPIOs, this is used. @@ -190,6 +191,7 @@ u8 ln_assign; u8 ln_polrs; bool comms_enabled; + bool plugged; struct mutex comms_mutex; #if defined(CONFIG_OF_GPIO) @@ -713,10 +715,11 @@ if (IS_ERR(dsi)) return PTR_ERR(dsi); - /* TODO: setting to 4 MIPI lanes always for now */ - dsi->lanes = 4; + /* TODO: setting to 2 MIPI lanes always for now */ + dsi->lanes = 2; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; /* check if continuous dsi clock is required or not */ pm_runtime_get_sync(dev); @@ -1091,6 +1094,15 @@ return; } + /* + * Disable ASSR Display Authentication, since its supported only in eDP + * and not spupperted in DP + */ + regmap_write(pdata->regmap, 0xFF, 0x7); + regmap_write(pdata->regmap, 0x16, 0x1); + regmap_write(pdata->regmap, 0xFF, 0x0); + regmap_update_bits(pdata->regmap, 0x5A, BIT(0), 0); + max_dp_lanes = ti_sn_get_max_lanes(pdata); pdata->dp_lanes = min(pdata->dp_lanes, max_dp_lanes); @@ -1106,26 +1118,6 @@ /* set dsi clk frequency value */ ti_sn_bridge_set_dsi_rate(pdata); - /* - * The SN65DSI86 only supports ASSR Display Authentication method and - * this method is enabled for eDP panels. An eDP panel must support this - * authentication method. We need to enable this method in the eDP panel - * at DisplayPort address 0x0010A prior to link training. - * - * As only ASSR is supported by SN65DSI86, for full DisplayPort displays - * we need to disable the scrambler. - */ - if (pdata->bridge.type == DRM_MODE_CONNECTOR_eDP) { - drm_dp_dpcd_writeb(&pdata->aux, DP_EDP_CONFIGURATION_SET, - DP_ALTERNATE_SCRAMBLER_RESET_ENABLE); - - regmap_update_bits(pdata->regmap, SN_TRAINING_SETTING_REG, - SCRAMBLE_DISABLE, 0); - } else { - regmap_update_bits(pdata->regmap, SN_TRAINING_SETTING_REG, - SCRAMBLE_DISABLE, SCRAMBLE_DISABLE); - } - bpp = ti_sn_bridge_get_bpp(connector); /* Set the DP output format (18 bpp or 24 bpp) */ val = bpp == 18 ? BPP_18_RGB : 0; @@ -1197,14 +1189,19 @@ static enum drm_connector_status ti_sn_bridge_detect(struct drm_bridge *bridge) { struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); - int val = 0; + int val; + u8 link_status[DP_LINK_STATUS_SIZE]; - pm_runtime_get_sync(pdata->dev); - regmap_read(pdata->regmap, SN_HPD_DISABLE_REG, &val); - pm_runtime_put_autosuspend(pdata->dev); + if (!pdata->plugged) { + pm_runtime_get_sync(pdata->dev); + val = drm_dp_dpcd_read_link_status(&pdata->aux, link_status); + pm_runtime_put_autosuspend(pdata->dev); + if (val > 0) + pdata->plugged = true; + } - return val & HPD_DEBOUNCED_STATE ? connector_status_connected - : connector_status_disconnected; + return pdata->plugged ? connector_status_connected + : connector_status_disconnected; } static struct edid *ti_sn_bridge_get_edid(struct drm_bridge *bridge, @@ -1316,8 +1313,11 @@ pdata->bridge.type = pdata->next_bridge->type == DRM_MODE_CONNECTOR_DisplayPort ? DRM_MODE_CONNECTOR_DisplayPort : DRM_MODE_CONNECTOR_eDP; + pdata->plugged = false; + pdata->bridge.ops |= DRM_BRIDGE_OP_DETECT; + if (pdata->bridge.type == DRM_MODE_CONNECTOR_DisplayPort) - pdata->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT; + pdata->bridge.ops |= DRM_BRIDGE_OP_EDID; drm_bridge_add(&pdata->bridge); diff -Naur --no-dereference a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c --- a/drivers/gpu/drm/drm_atomic_helper.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/drm_atomic_helper.c 2024-07-07 20:37:34.644306549 -0400 @@ -1231,6 +1231,49 @@ if (ret == 0) drm_crtc_vblank_put(crtc); } + + for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, + new_conn_state, i) { + struct drm_encoder *encoder; + struct drm_bridge *bridge; + + /* + * Shut down everything that's in the changeset and currently + * still on. So need to check the old, saved state. + */ + if (!old_conn_state->crtc) + continue; + + old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc); + + if (new_conn_state->crtc) + new_crtc_state = drm_atomic_get_new_crtc_state(old_state, + new_conn_state->crtc); + else + new_crtc_state = NULL; + + if (!crtc_needs_disable(old_crtc_state, new_crtc_state) || + !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state)) + continue; + + encoder = old_conn_state->best_encoder; + + /* We shouldn't get this far if we didn't previously have + * an encoder.. but WARN_ON() rather than explode. + */ + if (WARN_ON(!encoder)) + continue; + + drm_dbg_atomic(dev, "disabling [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); + + /* + * Each encoder has at most one connector (since we always steal + * it away), so we won't call disable hooks twice. + */ + bridge = drm_bridge_chain_get_first_bridge(encoder); + drm_atomic_bridge_chain_late_disable(bridge, old_state); + } } /** @@ -1466,6 +1509,30 @@ struct drm_connector_state *new_conn_state; int i; + for_each_new_connector_in_state(old_state, connector, new_conn_state, i) { + struct drm_encoder *encoder; + struct drm_bridge *bridge; + + if (!new_conn_state->best_encoder) + continue; + + if (!new_conn_state->crtc->state->active || + !drm_atomic_crtc_needs_modeset(new_conn_state->crtc->state)) + continue; + + encoder = new_conn_state->best_encoder; + + drm_dbg_atomic(dev, "enabling [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); + + /* + * Each encoder has at most one connector (since we always steal + * it away), so we won't call enable hooks twice. + */ + bridge = drm_bridge_chain_get_first_bridge(encoder); + drm_atomic_bridge_chain_early_enable(bridge, old_state); + } + for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) { const struct drm_crtc_helper_funcs *funcs; diff -Naur --no-dereference a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c --- a/drivers/gpu/drm/drm_bridge.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/drm_bridge.c 2024-07-07 20:37:34.644306549 -0400 @@ -623,6 +623,47 @@ } EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); +/** + * drm_atomic_bridge_chain_late_disable - disables all bridges in the encoder + * chain after crtc is disabled. + * @bridge: bridge control structure + * @old_state: old atomic state + * + * Calls &drm_bridge_funcs.atomic_late_disable op for all the bridges in the + * encoder chain, starting from the last bridge to the first. These are called + * after calling &drm_crtc_helper_funcs.atomic_disable. + * + * Note: the bridge passed should be the one closest to the encoder + */ +void drm_atomic_bridge_chain_late_disable(struct drm_bridge *bridge, + struct drm_atomic_state *old_state) +{ + struct drm_encoder *encoder; + struct drm_bridge *iter; + + if (!bridge) + return; + + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + if (iter->funcs->atomic_late_disable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + iter); + if (WARN_ON(!old_bridge_state)) + return; + + iter->funcs->atomic_late_disable(iter, old_bridge_state); + } + + if (iter == bridge) + break; + } +} +EXPORT_SYMBOL(drm_atomic_bridge_chain_late_disable); + static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge, struct drm_atomic_state *old_state) { @@ -715,6 +756,43 @@ } EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); +/** + * drm_atomic_bridge_chain_early_enable - enables all bridges in the encoder + * chain before it's crtc is enabled + * @bridge: bridge control structure + * @old_state: old atomic state + * + * Calls &drm_bridge_funcs.atomic_early_enable op for all the bridges in the + * encoder chain, starting from the first bridge to the last. These are called + * before even the &drm_crtc_helper_funcs.atomic_enable is called. + * + * Note: the bridge passed should be the one closest to the encoder. + */ +void drm_atomic_bridge_chain_early_enable(struct drm_bridge *bridge, + struct drm_atomic_state *old_state) +{ + struct drm_encoder *encoder; + + if (!bridge) + return; + + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->atomic_early_enable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + bridge); + if (WARN_ON(!old_bridge_state)) + return; + + bridge->funcs->atomic_early_enable(bridge, old_bridge_state); + } + } +} +EXPORT_SYMBOL(drm_atomic_bridge_chain_early_enable); + static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge, struct drm_atomic_state *old_state) { diff -Naur --no-dereference a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c --- a/drivers/gpu/drm/omapdrm/omap_gem.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/omapdrm/omap_gem.c 2024-07-07 20:37:34.644306549 -0400 @@ -48,7 +48,7 @@ * OMAP_BO_MEM_DMA_API flag set) * * - buffers imported from dmabuf (with the OMAP_BO_MEM_DMABUF flag set) - * if they are physically contiguous (when sgt->orig_nents == 1) + * if they are physically contiguous * * - buffers mapped through the TILER when pin_cnt is not zero, in which * case the DMA address points to the TILER aperture @@ -148,12 +148,18 @@ return drm_vma_node_offset_addr(&obj->vma_node); } +static bool omap_gem_sgt_is_contiguous(struct sg_table *sgt, size_t size) +{ + return !(drm_prime_get_contiguous_size(sgt) < size); +} + static bool omap_gem_is_contiguous(struct omap_gem_object *omap_obj) { if (omap_obj->flags & OMAP_BO_MEM_DMA_API) return true; - if ((omap_obj->flags & OMAP_BO_MEM_DMABUF) && omap_obj->sgt->nents == 1) + if ((omap_obj->flags & OMAP_BO_MEM_DMABUF) && + omap_gem_sgt_is_contiguous(omap_obj->sgt, omap_obj->base.size)) return true; return false; @@ -1385,7 +1391,7 @@ union omap_gem_size gsize; /* Without a DMM only physically contiguous buffers can be supported. */ - if (sgt->orig_nents != 1 && !priv->has_dmm) + if (!omap_gem_sgt_is_contiguous(sgt, size) && !priv->has_dmm) return ERR_PTR(-EINVAL); gsize.bytes = PAGE_ALIGN(size); @@ -1399,7 +1405,7 @@ omap_obj->sgt = sgt; - if (sgt->orig_nents == 1) { + if (omap_gem_sgt_is_contiguous(sgt, size)) { omap_obj->dma_addr = sg_dma_address(sgt->sgl); } else { /* Create pages list from sgt */ diff -Naur --no-dereference a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c --- a/drivers/gpu/drm/panel/panel-edp.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/panel/panel-edp.c 2024-07-07 20:37:34.644306549 -0400 @@ -912,13 +912,15 @@ dev_warn(dev, "Expected bpc in {6,8,10} but got: %u\n", desc->bpc); } - if (!panel->base.backlight && panel->aux) { - pm_runtime_get_sync(dev); - err = drm_panel_dp_aux_backlight(&panel->base, panel->aux); - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - if (err) - goto err_finished_pm_runtime; + if (!of_device_is_compatible(dev->of_node, "ti,panel-edp")) { + if (!panel->base.backlight && panel->aux) { + pm_runtime_get_sync(dev); + err = drm_panel_dp_aux_backlight(&panel->base, panel->aux); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + if (err) + goto err_finished_pm_runtime; + } } drm_panel_add(&panel->base); @@ -1723,6 +1725,36 @@ }, }; +static const struct drm_display_mode ti_panel_edp_mode = { + .clock = 40000, + .hdisplay = 800, + .hsync_start = 800 + 40, + .hsync_end = 800 + 40 + 128, + .htotal = 800 + 40 + 128 + 88, + .vdisplay = 600, + .vsync_start = 600 + 1, + .vsync_end = 600 + 1 + 4, + .vtotal = 600 + 1 + 4 + 23, + + .crtc_clock = 40000, + .crtc_hdisplay = 800, + .crtc_hsync_start = 800 + 40, + .crtc_hsync_end = 800 + 40 + 128, + .crtc_htotal = 800 + 40 + 128 + 88, + .crtc_vdisplay = 600, + .crtc_vsync_start = 600 + 1, + .crtc_vsync_end = 600 + 1 + 4, + .crtc_vtotal = 600 + 1 + 4 + 23, + + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, +}; + +static const struct panel_desc ti_panel_edp = { + .modes = &ti_panel_edp_mode, + .num_modes = 1, + .bpc = 8, +}; + static const struct of_device_id platform_of_match[] = { { /* Must be first */ @@ -1812,6 +1844,9 @@ .compatible = "starry,kr122ea0sra", .data = &starry_kr122ea0sra, }, { + .compatible = "ti,panel-edp", + .data = &ti_panel_edp, + }, { /* sentinel */ } }; diff -Naur --no-dereference a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c 2024-07-07 20:37:34.644306549 -0400 @@ -455,6 +455,206 @@ ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */ }; +static const struct ili9881c_instr mf_070zimacaa0_init[] = { + ILI9881C_SWITCH_PAGE_INSTR(3), + ILI9881C_COMMAND_INSTR(0x01, 0x00), + ILI9881C_COMMAND_INSTR(0x02, 0x00), + ILI9881C_COMMAND_INSTR(0x03, 0x72), + ILI9881C_COMMAND_INSTR(0x04, 0x00), + ILI9881C_COMMAND_INSTR(0x05, 0x00), + ILI9881C_COMMAND_INSTR(0x06, 0x09), + ILI9881C_COMMAND_INSTR(0x07, 0x00), + ILI9881C_COMMAND_INSTR(0x08, 0x00), + ILI9881C_COMMAND_INSTR(0x09, 0x00), + ILI9881C_COMMAND_INSTR(0x0A, 0x00), + ILI9881C_COMMAND_INSTR(0x0B, 0x00), + ILI9881C_COMMAND_INSTR(0x0C, 0x00), + ILI9881C_COMMAND_INSTR(0x0D, 0x00), + ILI9881C_COMMAND_INSTR(0x0E, 0x00), + ILI9881C_COMMAND_INSTR(0x0F, 0x00), + ILI9881C_COMMAND_INSTR(0x10, 0x00), + ILI9881C_COMMAND_INSTR(0x11, 0x00), + ILI9881C_COMMAND_INSTR(0x12, 0x00), + ILI9881C_COMMAND_INSTR(0x13, 0x00), + ILI9881C_COMMAND_INSTR(0x14, 0x00), + ILI9881C_COMMAND_INSTR(0x15, 0x00), + ILI9881C_COMMAND_INSTR(0x16, 0x00), + ILI9881C_COMMAND_INSTR(0x17, 0x00), + ILI9881C_COMMAND_INSTR(0x18, 0x00), + ILI9881C_COMMAND_INSTR(0x19, 0x00), + ILI9881C_COMMAND_INSTR(0x1A, 0x00), + ILI9881C_COMMAND_INSTR(0x1B, 0x00), + ILI9881C_COMMAND_INSTR(0x1C, 0x00), + ILI9881C_COMMAND_INSTR(0x1D, 0x00), + ILI9881C_COMMAND_INSTR(0x1E, 0x40), + ILI9881C_COMMAND_INSTR(0x1F, 0x80), + ILI9881C_COMMAND_INSTR(0x20, 0x05), + ILI9881C_COMMAND_INSTR(0x21, 0x02), + ILI9881C_COMMAND_INSTR(0x22, 0x00), + ILI9881C_COMMAND_INSTR(0x23, 0x00), + ILI9881C_COMMAND_INSTR(0x24, 0x00), + ILI9881C_COMMAND_INSTR(0x25, 0x00), + ILI9881C_COMMAND_INSTR(0x26, 0x00), + ILI9881C_COMMAND_INSTR(0x27, 0x00), + ILI9881C_COMMAND_INSTR(0x28, 0x33), + ILI9881C_COMMAND_INSTR(0x29, 0x22), + ILI9881C_COMMAND_INSTR(0x2A, 0x00), + ILI9881C_COMMAND_INSTR(0x2B, 0x00), + ILI9881C_COMMAND_INSTR(0x2C, 0x00), + ILI9881C_COMMAND_INSTR(0x2D, 0x00), + ILI9881C_COMMAND_INSTR(0x2E, 0x00), + ILI9881C_COMMAND_INSTR(0x2F, 0x00), + ILI9881C_COMMAND_INSTR(0x30, 0x00), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x32, 0x00), + ILI9881C_COMMAND_INSTR(0x33, 0x00), + ILI9881C_COMMAND_INSTR(0x34, 0x04), + ILI9881C_COMMAND_INSTR(0x35, 0x00), + ILI9881C_COMMAND_INSTR(0x36, 0x00), + ILI9881C_COMMAND_INSTR(0x37, 0x00), + ILI9881C_COMMAND_INSTR(0x38, 0x3C), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x3A, 0x00), + ILI9881C_COMMAND_INSTR(0x3B, 0x00), + ILI9881C_COMMAND_INSTR(0x3C, 0x00), + ILI9881C_COMMAND_INSTR(0x3D, 0x00), + ILI9881C_COMMAND_INSTR(0x3E, 0x00), + ILI9881C_COMMAND_INSTR(0x3F, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x00), + ILI9881C_COMMAND_INSTR(0x41, 0x00), + ILI9881C_COMMAND_INSTR(0x42, 0x00), + ILI9881C_COMMAND_INSTR(0x43, 0x00), + ILI9881C_COMMAND_INSTR(0x44, 0x00), + ILI9881C_COMMAND_INSTR(0x50, 0x10), + ILI9881C_COMMAND_INSTR(0x51, 0x32), + ILI9881C_COMMAND_INSTR(0x52, 0x54), + ILI9881C_COMMAND_INSTR(0x53, 0x76), + ILI9881C_COMMAND_INSTR(0x54, 0x98), + ILI9881C_COMMAND_INSTR(0x55, 0xBA), + ILI9881C_COMMAND_INSTR(0x56, 0x10), + ILI9881C_COMMAND_INSTR(0x57, 0x32), + ILI9881C_COMMAND_INSTR(0x58, 0x54), + ILI9881C_COMMAND_INSTR(0x59, 0x76), + ILI9881C_COMMAND_INSTR(0x5A, 0x98), + ILI9881C_COMMAND_INSTR(0x5B, 0xBA), + ILI9881C_COMMAND_INSTR(0x5C, 0xDC), + ILI9881C_COMMAND_INSTR(0x5D, 0xFE), + ILI9881C_COMMAND_INSTR(0x5E, 0x00), + ILI9881C_COMMAND_INSTR(0x5F, 0x01), + ILI9881C_COMMAND_INSTR(0x60, 0x00), + ILI9881C_COMMAND_INSTR(0x61, 0x15), + ILI9881C_COMMAND_INSTR(0x62, 0x14), + ILI9881C_COMMAND_INSTR(0x63, 0x0E), + ILI9881C_COMMAND_INSTR(0x64, 0x0F), + ILI9881C_COMMAND_INSTR(0x65, 0x0C), + ILI9881C_COMMAND_INSTR(0x66, 0x0D), + ILI9881C_COMMAND_INSTR(0x67, 0x06), + ILI9881C_COMMAND_INSTR(0x68, 0x02), + ILI9881C_COMMAND_INSTR(0x69, 0x02), + ILI9881C_COMMAND_INSTR(0x6A, 0x02), + ILI9881C_COMMAND_INSTR(0x6B, 0x02), + ILI9881C_COMMAND_INSTR(0x6C, 0x02), + ILI9881C_COMMAND_INSTR(0x6D, 0x02), + ILI9881C_COMMAND_INSTR(0x6E, 0x07), + ILI9881C_COMMAND_INSTR(0x6F, 0x02), + ILI9881C_COMMAND_INSTR(0x70, 0x02), + ILI9881C_COMMAND_INSTR(0x71, 0x02), + ILI9881C_COMMAND_INSTR(0x72, 0x02), + ILI9881C_COMMAND_INSTR(0x73, 0x02), + ILI9881C_COMMAND_INSTR(0x74, 0x02), + ILI9881C_COMMAND_INSTR(0x75, 0x01), + ILI9881C_COMMAND_INSTR(0x76, 0x00), + ILI9881C_COMMAND_INSTR(0x77, 0x14), + ILI9881C_COMMAND_INSTR(0x78, 0x15), + ILI9881C_COMMAND_INSTR(0x79, 0x0E), + ILI9881C_COMMAND_INSTR(0x7A, 0x0F), + ILI9881C_COMMAND_INSTR(0x7B, 0x0C), + ILI9881C_COMMAND_INSTR(0x7C, 0x0D), + ILI9881C_COMMAND_INSTR(0x7D, 0x06), + ILI9881C_COMMAND_INSTR(0x7E, 0x02), + ILI9881C_COMMAND_INSTR(0x7F, 0x02), + ILI9881C_COMMAND_INSTR(0x80, 0x02), + ILI9881C_COMMAND_INSTR(0x81, 0x02), + ILI9881C_COMMAND_INSTR(0x82, 0x02), + ILI9881C_COMMAND_INSTR(0x83, 0x02), + ILI9881C_COMMAND_INSTR(0x84, 0x07), + ILI9881C_COMMAND_INSTR(0x85, 0x02), + ILI9881C_COMMAND_INSTR(0x86, 0x02), + ILI9881C_COMMAND_INSTR(0x87, 0x02), + ILI9881C_COMMAND_INSTR(0x88, 0x02), + ILI9881C_COMMAND_INSTR(0x89, 0x02), + ILI9881C_COMMAND_INSTR(0x8A, 0x02), + ILI9881C_SWITCH_PAGE_INSTR(4), + ILI9881C_COMMAND_INSTR(0x6C, 0x15), + ILI9881C_COMMAND_INSTR(0x6E, 0x2A), + ILI9881C_COMMAND_INSTR(0x6F, 0x35), + ILI9881C_COMMAND_INSTR(0x3A, 0x24), + ILI9881C_COMMAND_INSTR(0x8D, 0x14), + ILI9881C_COMMAND_INSTR(0x87, 0xBA), + ILI9881C_COMMAND_INSTR(0x26, 0x76), + ILI9881C_COMMAND_INSTR(0xB2, 0xD1), + ILI9881C_COMMAND_INSTR(0xB5, 0x27), + ILI9881C_COMMAND_INSTR(0x31, 0x75), + ILI9881C_COMMAND_INSTR(0x30, 0x03), + ILI9881C_COMMAND_INSTR(0x3B, 0x98), + ILI9881C_COMMAND_INSTR(0x35, 0x1F), + ILI9881C_COMMAND_INSTR(0x33, 0x14), + ILI9881C_COMMAND_INSTR(0x7A, 0x0F), + ILI9881C_COMMAND_INSTR(0x38, 0x02), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_SWITCH_PAGE_INSTR(1), + ILI9881C_COMMAND_INSTR(0x22, 0x0A), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x53, 0x40), + ILI9881C_COMMAND_INSTR(0x55, 0x4E), + ILI9881C_COMMAND_INSTR(0x50, 0xC7), + ILI9881C_COMMAND_INSTR(0x51, 0xC2), + ILI9881C_COMMAND_INSTR(0x60, 0x26), + ILI9881C_COMMAND_INSTR(0x63, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x33), + ILI9881C_COMMAND_INSTR(0x43, 0x74), + ILI9881C_COMMAND_INSTR(0xA0, 0x00), + ILI9881C_COMMAND_INSTR(0xA1, 0x16), + ILI9881C_COMMAND_INSTR(0xA2, 0x24), + ILI9881C_COMMAND_INSTR(0xA3, 0x13), + ILI9881C_COMMAND_INSTR(0xA4, 0x16), + ILI9881C_COMMAND_INSTR(0xA5, 0x2A), + ILI9881C_COMMAND_INSTR(0xA6, 0x1E), + ILI9881C_COMMAND_INSTR(0xA7, 0x20), + ILI9881C_COMMAND_INSTR(0xA8, 0x8D), + ILI9881C_COMMAND_INSTR(0xA9, 0x1D), + ILI9881C_COMMAND_INSTR(0xAA, 0x29), + ILI9881C_COMMAND_INSTR(0xAB, 0x82), + ILI9881C_COMMAND_INSTR(0xAC, 0x1F), + ILI9881C_COMMAND_INSTR(0xAD, 0x20), + ILI9881C_COMMAND_INSTR(0xAE, 0x54), + ILI9881C_COMMAND_INSTR(0xAF, 0x29), + ILI9881C_COMMAND_INSTR(0xB0, 0x2C), + ILI9881C_COMMAND_INSTR(0xB1, 0x51), + ILI9881C_COMMAND_INSTR(0xB2, 0x5C), + ILI9881C_COMMAND_INSTR(0xB3, 0x23), + ILI9881C_COMMAND_INSTR(0xC0, 0x00), + ILI9881C_COMMAND_INSTR(0xC1, 0x15), + ILI9881C_COMMAND_INSTR(0xC2, 0x24), + ILI9881C_COMMAND_INSTR(0xC3, 0x13), + ILI9881C_COMMAND_INSTR(0xC4, 0x17), + ILI9881C_COMMAND_INSTR(0xC5, 0x29), + ILI9881C_COMMAND_INSTR(0xC6, 0x1E), + ILI9881C_COMMAND_INSTR(0xC7, 0x1F), + ILI9881C_COMMAND_INSTR(0xC8, 0x8C), + ILI9881C_COMMAND_INSTR(0xC9, 0x1D), + ILI9881C_COMMAND_INSTR(0xCA, 0x29), + ILI9881C_COMMAND_INSTR(0xCB, 0x81), + ILI9881C_COMMAND_INSTR(0xCC, 0x1F), + ILI9881C_COMMAND_INSTR(0xCD, 0x20), + ILI9881C_COMMAND_INSTR(0xCE, 0x55), + ILI9881C_COMMAND_INSTR(0xCF, 0x29), + ILI9881C_COMMAND_INSTR(0xD0, 0x2D), + ILI9881C_COMMAND_INSTR(0xD1, 0x51), + ILI9881C_COMMAND_INSTR(0xD2, 0x5C), + ILI9881C_COMMAND_INSTR(0xD3, 0x23), +}; + static const struct ili9881c_instr tl050hdv35_init[] = { ILI9881C_SWITCH_PAGE_INSTR(3), ILI9881C_COMMAND_INSTR(0x01, 0x00), @@ -980,6 +1180,23 @@ .height_mm = 217, }; +static const struct drm_display_mode mf_070zimacaa0_default_mode = { + .clock = 82550, + + .hdisplay = 800, + .hsync_start = 800 + 100, + .hsync_end = 800 + 100 + 32, + .htotal = 800 + 100 + 32 + 100, + + .vdisplay = 1280, + .vsync_start = 1280 + 20, + .vsync_end = 1280 + 20 + 3, + .vtotal = 1280 + 20 + 3 + 30, + + .width_mm = 94, + .height_mm = 151, +}; + static const struct drm_display_mode tl050hdv35_default_mode = { .clock = 59400, @@ -1129,6 +1346,14 @@ .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, }; +static const struct ili9881c_desc mf_070zimacaa0_data = { + .init = mf_070zimacaa0_init, + .init_length = ARRAY_SIZE(mf_070zimacaa0_init), + .mode = &mf_070zimacaa0_default_mode, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_CLOCK_NON_CONTINUOUS, +}; + static const struct ili9881c_desc tl050hdv35_desc = { .init = tl050hdv35_init, .init_length = ARRAY_SIZE(tl050hdv35_init), @@ -1148,6 +1373,7 @@ static const struct of_device_id ili9881c_of_match[] = { { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc }, { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc }, + { .compatible = "microtips,mf-070zimacaa0", .data = &mf_070zimacaa0_data }, { .compatible = "tdo,tl050hdv35", .data = &tl050hdv35_desc }, { .compatible = "wanchanglong,w552946aba", .data = &w552946aba_desc }, { } diff -Naur --no-dereference a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c --- a/drivers/gpu/drm/panel/panel-simple.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/panel/panel-simple.c 2024-07-07 20:37:34.644306549 -0400 @@ -2638,6 +2638,35 @@ .connector_type = DRM_MODE_CONNECTOR_LVDS, }; +static const struct drm_display_mode lincolntech_lcd185_101ct_mode = { + .clock = 155127, + .hdisplay = 1920, + .hsync_start = 1920 + 128, + .hsync_end = 1920 + 128 + 20, + .htotal = 1920 + 128 + 20 + 12, + .vdisplay = 1200, + .vsync_start = 1200 + 19, + .vsync_end = 1200 + 19 + 4, + .vtotal = 1200 + 19 + 4 + 20, +}; + +static const struct panel_desc lincolntech_lcd185_101ct = { + .modes = &lincolntech_lcd185_101ct_mode, + .bpc = 8, + .num_modes = 1, + .size = { + .width = 217, + .height = 136, + }, + .delay = { + .prepare = 50, + .disable = 50, + }, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct display_timing logictechno_lt161010_2nh_timing = { .pixelclock = { 26400000, 33300000, 46800000 }, .hactive = { 800, 800, 800 }, @@ -2794,6 +2823,64 @@ .connector_type = DRM_MODE_CONNECTOR_DPI, }; +static const struct drm_display_mode microtips_mf_101hiebcaf0_c_mode = { + .clock = 150275, + .hdisplay = 1920, + .hsync_start = 1920 + 32, + .hsync_end = 1920 + 32 + 52, + .htotal = 1920 + 32 + 52 + 24, + .vdisplay = 1200, + .vsync_start = 1200 + 24, + .vsync_end = 1200 + 24 + 8, + .vtotal = 1200 + 24 + 8 + 3, +}; + +static const struct panel_desc microtips_mf_101hiebcaf0_c = { + .modes = µtips_mf_101hiebcaf0_c_mode, + .bpc = 8, + .num_modes = 1, + .size = { + .width = 217, + .height = 136, + }, + .delay = { + .prepare = 50, + .disable = 50, + }, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + +static const struct drm_display_mode microtips_mf_103hieb0ga0_mode = { + .clock = 93301, + .hdisplay = 1920, + .hsync_start = 1920 + 72, + .hsync_end = 1920 + 72 + 72, + .htotal = 1920 + 72 + 72 + 72, + .vdisplay = 720, + .vsync_start = 720 + 3, + .vsync_end = 720 + 3 + 3, + .vtotal = 720 + 3 + 3 + 2, +}; + +static const struct panel_desc microtips_mf_103hieb0ga0 = { + .modes = µtips_mf_103hieb0ga0_mode, + .bpc = 8, + .num_modes = 1, + .size = { + .width = 244, + .height = 92, + }, + .delay = { + .prepare = 50, + .disable = 50, + }, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct drm_display_mode mitsubishi_aa070mc01_mode = { .clock = 30400, .hdisplay = 800, @@ -3372,6 +3459,32 @@ .connector_type = DRM_MODE_CONNECTOR_DPI, }; +static const struct drm_display_mode raspberrypi_7inch_mode = { + .clock = 28569600 / 1000, + .hdisplay = 800, + .hsync_start = 800 + 48, + .hsync_end = 800 + 48 + 32, + .htotal = 800 + 48 + 32 + 80, + .vdisplay = 480, + .vsync_start = 480 + 3, + .vsync_end = 480 + 3 + 7, + .vtotal = 480 + 3 + 7 + 6, + + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, +}; + +static const struct panel_desc raspberrypi_7inch = { + .modes = &raspberrypi_7inch_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 154, + .height = 86, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .connector_type = DRM_MODE_CONNECTOR_DSI, +}; + static const struct display_timing rocktech_rk070er9427_timing = { .pixelclock = { 26400000, 33300000, 46800000 }, .hactive = { 800, 800, 800 }, @@ -4339,6 +4452,9 @@ .compatible = "lg,lb070wv8", .data = &lg_lb070wv8, }, { + .compatible = "lincolntech,lcd185-101ct", + .data = &lincolntech_lcd185_101ct, + }, { .compatible = "logicpd,type28", .data = &logicpd_type_28, }, { @@ -4357,6 +4473,12 @@ .compatible = "logictechno,lttd800480070-l6wh-rt", .data = &logictechno_lttd800480070_l6wh_rt, }, { + .compatible = "microtips,mf-101hiebcaf0", + .data = µtips_mf_101hiebcaf0_c, + }, { + .compatible = "microtips,mf-103hieb0ga0", + .data = µtips_mf_103hieb0ga0, + }, { .compatible = "mitsubishi,aa070mc01-ca1", .data = &mitsubishi_aa070mc01, }, { @@ -4423,6 +4545,9 @@ .compatible = "rocktech,rk043fn48h", .data = &rocktech_rk043fn48h, }, { + .compatible = "raspberrypi,7inch-dsi", + .data = &raspberrypi_7inch, + }, { .compatible = "rocktech,rk070er9427", .data = &rocktech_rk070er9427, }, { diff -Naur --no-dereference a/drivers/gpu/drm/tidss/Makefile b/drivers/gpu/drm/tidss/Makefile --- a/drivers/gpu/drm/tidss/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/tidss/Makefile 2024-07-07 20:37:34.644306549 -0400 @@ -7,6 +7,7 @@ tidss_irq.o \ tidss_plane.o \ tidss_scale_coefs.o \ - tidss_dispc.o + tidss_dispc.o \ + tidss_oldi.o obj-$(CONFIG_DRM_TIDSS) += tidss.o diff -Naur --no-dereference a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c --- a/drivers/gpu/drm/tidss/tidss_crtc.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/tidss/tidss_crtc.c 2024-07-07 20:37:34.644306549 -0400 @@ -108,6 +108,7 @@ return -EINVAL; } + drm_mode_set_crtcinfo(&crtc_state->adjusted_mode, 0); return dispc_vp_bus_check(dispc, hw_videoport, crtc_state); } @@ -174,10 +175,6 @@ drm_atomic_crtc_needs_modeset(crtc->state) ? "needs" : "doesn't need", crtc->state->event); - /* There is nothing to do if CRTC is not going to be enabled. */ - if (!crtc->state->active) - return; - /* * Flush CRTC changes with go bit only if new modeset is not * coming, so CRTC is enabled trough out the commit. diff -Naur --no-dereference a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c --- a/drivers/gpu/drm/tidss/tidss_dispc.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/tidss/tidss_dispc.c 2024-07-07 20:37:34.644306549 -0400 @@ -322,6 +322,158 @@ .vid_order = { 1, 0 }, }; +const struct dispc_features dispc_am62a7_feats = { + /* + * if the code reaches dispc_mode_valid with VP1, + * it should return MODE_BAD. + */ + .max_pclk_khz = { + [DISPC_VP_TIED_OFF] = 0, + [DISPC_VP_DPI] = 165000, + }, + + .scaling = { + .in_width_max_5tap_rgb = 1280, + .in_width_max_3tap_rgb = 2560, + .in_width_max_5tap_yuv = 2560, + .in_width_max_3tap_yuv = 4096, + .upscale_limit = 16, + .downscale_limit_5tap = 4, + .downscale_limit_3tap = 2, + /* + * The max supported pixel inc value is 255. The value + * of pixel inc is calculated like this: 1+(xinc-1)*bpp. + * The maximum bpp of all formats supported by the HW + * is 8. So the maximum supported xinc value is 32, + * because 1+(32-1)*8 < 255 < 1+(33-1)*4. + */ + .xinc_max = 32, + }, + + .subrev = DISPC_AM62A7, + + .common = "common", + .common_regs = tidss_am65x_common_regs, + + .num_vps = 2, + .vp_name = { "vp1", "vp2" }, + .ovr_name = { "ovr1", "ovr2" }, + .vpclk_name = { "vp1", "vp2" }, + /* VP1 of the DSS in AM62A7 SoC is tied off internally */ + .vp_bus_type = { DISPC_VP_TIED_OFF, DISPC_VP_DPI }, + + .vp_feat = { .color = { + .has_ctm = true, + .gamma_size = 256, + .gamma_type = TIDSS_GAMMA_8BIT, + }, + }, + + .num_planes = 2, + /* note: vid is plane_id 0 and vidl1 is plane_id 1 */ + .vid_name = { "vid", "vidl1" }, + .vid_lite = { false, true, }, + .vid_order = { 1, 0 }, +}; + +const struct dispc_features dispc_am62p51_feats = { + .max_pclk_khz = { + [DISPC_VP_DPI] = 165000, + [DISPC_VP_INTERNAL] = 300000, + }, + + .scaling = { + .in_width_max_5tap_rgb = 1280, + .in_width_max_3tap_rgb = 2560, + .in_width_max_5tap_yuv = 2560, + .in_width_max_3tap_yuv = 4096, + .upscale_limit = 16, + .downscale_limit_5tap = 4, + .downscale_limit_3tap = 2, + /* + * The max supported pixel inc value is 255. The value + * of pixel inc is calculated like this: 1+(xinc-1)*bpp. + * The maximum bpp of all formats supported by the HW + * is 8. So the maximum supported xinc value is 32, + * because 1+(32-1)*8 < 255 < 1+(33-1)*4. + */ + .xinc_max = 32, + }, + + .subrev = DISPC_AM62P51, + + .common = "common", + .common_regs = tidss_am65x_common_regs, + + .num_vps = 2, + .vp_name = { "vp1", "vp2" }, + .ovr_name = { "ovr1", "ovr2" }, + .vpclk_name = { "vp1", "vp2" }, + .vp_bus_type = { DISPC_VP_INTERNAL, DISPC_VP_DPI }, + + .vp_feat = { .color = { + .has_ctm = true, + .gamma_size = 256, + .gamma_type = TIDSS_GAMMA_8BIT, + }, + }, + + .num_planes = 2, + /* note: vid is plane_id 0 and vidl1 is plane_id 1 */ + .vid_name = { "vid", "vidl1" }, + .vid_lite = { false, true, }, + .vid_order = { 1, 0 }, +}; + +const struct dispc_features dispc_am62p52_feats = { + .max_pclk_khz = { + [DISPC_VP_DPI] = 165000, + [DISPC_VP_INTERNAL] = 300000, + }, + + .scaling = { + .in_width_max_5tap_rgb = 1280, + .in_width_max_3tap_rgb = 2560, + .in_width_max_5tap_yuv = 2560, + .in_width_max_3tap_yuv = 4096, + .upscale_limit = 16, + .downscale_limit_5tap = 4, + .downscale_limit_3tap = 2, + /* + * The max supported pixel inc value is 255. The value + * of pixel inc is calculated like this: 1+(xinc-1)*bpp. + * The maximum bpp of all formats supported by the HW + * is 8. So the maximum supported xinc value is 32, + * because 1+(32-1)*8 < 255 < 1+(33-1)*4. + */ + .xinc_max = 32, + }, + + .subrev = DISPC_AM62P52, + + .common = "common", + .common_regs = tidss_am65x_common_regs, + + .num_vps = 2, + .vp_name = { "vp1", "vp2" }, + .ovr_name = { "ovr1", "ovr2" }, + .vpclk_name = { "vp1", "vp2" }, + .vp_bus_type = { DISPC_VP_INTERNAL, DISPC_VP_INTERNAL }, + + .vp_feat = { .color = { + .has_ctm = true, + .gamma_size = 256, + .gamma_type = TIDSS_GAMMA_8BIT, + }, + }, + + .num_planes = 2, + /* note: vid is plane_id 0 and vidl1 is plane_id 1 */ + .vid_name = { "vid", "vidl1" }, + .vid_lite = { false, true, }, + .vid_order = { 1, 0 }, +}; + static const u16 *dispc_common_regmap; struct dss_vp_data { @@ -412,6 +564,16 @@ return ioread32(base + reg); } +u32 tidss_get_status(struct tidss_device *tidss) +{ + return dispc_read(tidss->dispc, DSS_SYSSTATUS); +} + +void tidss_configure_oldi(struct tidss_device *tidss, u32 hw_videoport, u32 val) +{ + return dispc_vp_write(tidss->dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, val); +} + /* * TRM gives bitfields as start:end, where start is the higher bit * number. For example 7:0 @@ -824,6 +986,9 @@ case DISPC_K2G: return dispc_k2g_read_and_clear_irqstatus(dispc); case DISPC_AM625: + case DISPC_AM62A7: + case DISPC_AM62P51: + case DISPC_AM62P52: case DISPC_AM65X: case DISPC_J721E: return dispc_k3_read_and_clear_irqstatus(dispc); @@ -840,6 +1005,9 @@ dispc_k2g_set_irqenable(dispc, mask); break; case DISPC_AM625: + case DISPC_AM62A7: + case DISPC_AM62P51: + case DISPC_AM62P52: case DISPC_AM65X: case DISPC_J721E: dispc_k3_set_irqenable(dispc, mask); @@ -1254,7 +1422,6 @@ * Calculate the percentage difference between the requested pixel clock rate * and the effective rate resulting from calculating the clock divider value. */ -static unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate) { int r = rate / 100, rr = real_rate / 100; @@ -1269,6 +1436,7 @@ unsigned long new_rate; r = clk_set_rate(dispc->vp_clk[hw_videoport], rate); + if (r) { dev_err(dispc->dev, "vp%d: failed to set clk rate to %lu\n", hw_videoport, rate); @@ -1331,6 +1499,9 @@ x, y, layer); break; case DISPC_AM625: + case DISPC_AM62A7: + case DISPC_AM62P51: + case DISPC_AM62P52: case DISPC_AM65X: dispc_am65x_ovr_set_plane(dispc, hw_plane, hw_videoport, x, y, layer); @@ -2250,6 +2421,9 @@ dispc_k2g_plane_init(dispc); break; case DISPC_AM625: + case DISPC_AM62A7: + case DISPC_AM62P51: + case DISPC_AM62P52: case DISPC_AM65X: case DISPC_J721E: dispc_k3_plane_init(dispc); @@ -2357,6 +2531,9 @@ dispc_k2g_vp_write_gamma_table(dispc, hw_videoport); break; case DISPC_AM625: + case DISPC_AM62A7: + case DISPC_AM62P51: + case DISPC_AM62P52: case DISPC_AM65X: dispc_am65x_vp_write_gamma_table(dispc, hw_videoport); break; @@ -2603,10 +2780,18 @@ dispc_vp_set_color_mgmt(dispc, hw_videoport, state, newmodeset); } +static bool dispc_is_idle(struct dispc_device *dispc) +{ + return REG_GET(dispc, DSS_SYSSTATUS, 9, 9); +} + int dispc_runtime_suspend(struct dispc_device *dispc) { dev_dbg(dispc->dev, "suspend\n"); + if (!dispc_is_idle(dispc)) + dev_warn(dispc->dev, "Bad HW state: DSS not idle when suspending"); + dispc->is_enabled = false; clk_disable_unprepare(dispc->fclk); @@ -2620,6 +2805,9 @@ clk_prepare_enable(dispc->fclk); + if (!dispc_is_idle(dispc)) + dev_warn(dispc->dev, "Bad HW state: DSS not idle when resuming"); + if (REG_GET(dispc, DSS_SYSSTATUS, 0, 0) == 0) dev_warn(dispc->dev, "DSS FUNC RESET not done!\n"); @@ -2702,14 +2890,28 @@ } } +/* + * K2G display controller does not support soft reset, so we do a basic manual + * reset here: make sure the IRQs are masked and VPs are disabled. + */ +static void dispc_softreset_k2g(struct dispc_device *dispc) +{ + dispc_set_irqenable(dispc, 0); + dispc_read_and_clear_irqstatus(dispc); + + for (unsigned int vp_idx = 0; vp_idx < dispc->feat->num_vps; ++vp_idx) + VP_REG_FLD_MOD(dispc, vp_idx, DISPC_VP_CONTROL, 0, 0, 0); +} + static int dispc_softreset(struct dispc_device *dispc) { u32 val; - int ret = 0; + int ret; - /* K2G display controller does not support soft reset */ - if (dispc->feat->subrev == DISPC_K2G) + if (dispc->feat->subrev == DISPC_K2G) { + dispc_softreset_k2g(dispc); return 0; + } /* Soft reset */ REG_FLD_MOD(dispc, DSS_SYSCONFIG, 1, 1, 1); diff -Naur --no-dereference a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h --- a/drivers/gpu/drm/tidss/tidss_dispc.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/tidss/tidss_dispc.h 2024-07-07 20:37:34.644306549 -0400 @@ -54,12 +54,16 @@ DISPC_VP_DPI, /* DPI output */ DISPC_VP_OLDI, /* OLDI (LVDS) output */ DISPC_VP_INTERNAL, /* SoC internal routing */ + DISPC_VP_TIED_OFF, /* Tied off / Unavailable */ DISPC_VP_MAX_BUS_TYPE, }; enum dispc_dss_subrevision { DISPC_K2G, DISPC_AM625, + DISPC_AM62A7, + DISPC_AM62P51, + DISPC_AM62P52, DISPC_AM65X, DISPC_J721E, }; @@ -88,9 +92,16 @@ extern const struct dispc_features dispc_k2g_feats; extern const struct dispc_features dispc_am625_feats; +extern const struct dispc_features dispc_am62a7_feats; +extern const struct dispc_features dispc_am62p51_feats; +extern const struct dispc_features dispc_am62p52_feats; extern const struct dispc_features dispc_am65x_feats; extern const struct dispc_features dispc_j721e_feats; +u32 tidss_get_status(struct tidss_device *tidss); +void tidss_configure_oldi(struct tidss_device *tidss, u32 hw_videoport, u32 val); +unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate); + void dispc_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask); dispc_irq_t dispc_read_and_clear_irqstatus(struct dispc_device *dispc); diff -Naur --no-dereference a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c --- a/drivers/gpu/drm/tidss/tidss_drv.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/tidss/tidss_drv.c 2024-07-07 20:37:34.644306549 -0400 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,7 @@ #include "tidss_drv.h" #include "tidss_kms.h" #include "tidss_irq.h" +#include "tidss_oldi.h" /* Power management */ @@ -32,9 +34,9 @@ dev_dbg(tidss->dev, "%s\n", __func__); - r = pm_runtime_get_sync(tidss->dev); + r = pm_runtime_resume_and_get(tidss->dev); WARN_ON(r < 0); - return r < 0 ? r : 0; + return r; } void tidss_runtime_put(struct tidss_device *tidss) @@ -43,7 +45,9 @@ dev_dbg(tidss->dev, "%s\n", __func__); - r = pm_runtime_put_sync(tidss->dev); + pm_runtime_mark_last_busy(tidss->dev); + + r = pm_runtime_put_autosuspend(tidss->dev); WARN_ON(r < 0); } @@ -114,6 +118,72 @@ .minor = 0, }; +static int tidss_detach_pm_domains(struct tidss_device *tidss) +{ + int i; + + if (tidss->num_domains <= 1) + return 0; + + for (i = 0; i < tidss->num_domains; i++) { + if (tidss->pd_link[i] && !IS_ERR(tidss->pd_link[i])) + device_link_del(tidss->pd_link[i]); + if (tidss->pd_dev[i] && !IS_ERR(tidss->pd_dev[i])) + dev_pm_domain_detach(tidss->pd_dev[i], true); + tidss->pd_dev[i] = NULL; + tidss->pd_link[i] = NULL; + } + + return 0; +} + +static int tidss_attach_pm_domains(struct tidss_device *tidss) +{ + struct device *dev = tidss->dev; + int i; + int ret; + struct platform_device *pdev = to_platform_device(dev); + struct device_node *np = pdev->dev.of_node; + + tidss->num_domains = of_count_phandle_with_args(np, "power-domains", + "#power-domain-cells"); + if (tidss->num_domains <= 1) { + dev_dbg(dev, "One or less power domains, no need to do attach domains\n"); + return 0; + } + + tidss->pd_dev = devm_kmalloc_array(dev, tidss->num_domains, + sizeof(*tidss->pd_dev), GFP_KERNEL); + if (!tidss->pd_dev) + return -ENOMEM; + + tidss->pd_link = devm_kmalloc_array(dev, tidss->num_domains, + sizeof(*tidss->pd_link), GFP_KERNEL); + if (!tidss->pd_link) + return -ENOMEM; + + for (i = 0; i < tidss->num_domains; i++) { + tidss->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); + if (IS_ERR(tidss->pd_dev[i])) { + ret = PTR_ERR(tidss->pd_dev[i]); + goto fail; + } + + tidss->pd_link[i] = device_link_add(dev, tidss->pd_dev[i], + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); + if (!tidss->pd_link[i]) { + ret = -EINVAL; + goto fail; + } + } + + return 0; +fail: + tidss_detach_pm_domains(tidss); + return ret; +} + static int tidss_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -136,14 +206,30 @@ platform_set_drvdata(pdev, tidss); + spin_lock_init(&tidss->wait_lock); + + ret = tidss_oldi_init(tidss); + if (ret) + return dev_err_probe(dev, ret, "failed to init OLDI\n"); + + /* powering up associated OLDI domains */ + ret = tidss_attach_pm_domains(tidss); + if (ret < 0) { + dev_err(dev, "failed to attach power domains %d\n", ret); + goto err_oldi_deinit; + } + ret = dispc_init(tidss); if (ret) { dev_err(dev, "failed to initialize dispc: %d\n", ret); - return ret; + goto err_oldi_deinit; } pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + #ifndef CONFIG_PM /* If we don't have PM, we need to call resume manually */ dispc_runtime_resume(tidss->dispc); @@ -192,8 +278,13 @@ #ifndef CONFIG_PM dispc_runtime_suspend(tidss->dispc); #endif + pm_runtime_dont_use_autosuspend(dev); pm_runtime_disable(dev); +err_oldi_deinit: + tidss_detach_pm_domains(tidss); + tidss_oldi_deinit(tidss); + return ret; } @@ -215,11 +306,13 @@ /* If we don't have PM, we need to call suspend manually */ dispc_runtime_suspend(tidss->dispc); #endif + pm_runtime_dont_use_autosuspend(dev); pm_runtime_disable(dev); /* devm allocated dispc goes away with the dev so mark it NULL */ dispc_remove(tidss); + tidss_detach_pm_domains(tidss); dev_dbg(dev, "%s done\n", __func__); } @@ -231,6 +324,9 @@ static const struct of_device_id tidss_of_table[] = { { .compatible = "ti,k2g-dss", .data = &dispc_k2g_feats, }, { .compatible = "ti,am625-dss", .data = &dispc_am625_feats, }, + { .compatible = "ti,am62a7-dss", .data = &dispc_am62a7_feats, }, + { .compatible = "ti,am62p51-dss", .data = &dispc_am62p51_feats, }, + { .compatible = "ti,am62p52-dss", .data = &dispc_am62p52_feats, }, { .compatible = "ti,am65x-dss", .data = &dispc_am65x_feats, }, { .compatible = "ti,j721e-dss", .data = &dispc_j721e_feats, }, { } diff -Naur --no-dereference a/drivers/gpu/drm/tidss/tidss_drv.h b/drivers/gpu/drm/tidss/tidss_drv.h --- a/drivers/gpu/drm/tidss/tidss_drv.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/tidss/tidss_drv.h 2024-07-07 20:37:34.644306549 -0400 @@ -11,6 +11,7 @@ #define TIDSS_MAX_PORTS 4 #define TIDSS_MAX_PLANES 4 +#define TIDSS_MAX_OLDI_TXES 2 typedef u32 dispc_irq_t; @@ -27,10 +28,17 @@ unsigned int num_planes; struct drm_plane *planes[TIDSS_MAX_PLANES]; + unsigned int num_oldis; + struct tidss_oldi *oldis[TIDSS_MAX_OLDI_TXES]; + unsigned int irq; spinlock_t wait_lock; /* protects the irq masks */ dispc_irq_t irq_mask; /* enabled irqs in addition to wait_list */ + + int num_domains; /* Handle attached PM domains */ + struct device **pd_dev; + struct device_link **pd_link; }; #define to_tidss(__dev) container_of(__dev, struct tidss_device, ddev) diff -Naur --no-dereference a/drivers/gpu/drm/tidss/tidss_irq.c b/drivers/gpu/drm/tidss/tidss_irq.c --- a/drivers/gpu/drm/tidss/tidss_irq.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/tidss/tidss_irq.c 2024-07-07 20:37:34.644306549 -0400 @@ -93,33 +93,21 @@ spin_unlock_irqrestore(&tidss->wait_lock, flags); } -static void tidss_irq_preinstall(struct drm_device *ddev) -{ - struct tidss_device *tidss = to_tidss(ddev); - - spin_lock_init(&tidss->wait_lock); - - tidss_runtime_get(tidss); - - dispc_set_irqenable(tidss->dispc, 0); - dispc_read_and_clear_irqstatus(tidss->dispc); - - tidss_runtime_put(tidss); -} - -static void tidss_irq_postinstall(struct drm_device *ddev) +int tidss_irq_install(struct drm_device *ddev, unsigned int irq) { struct tidss_device *tidss = to_tidss(ddev); - unsigned long flags; - unsigned int i; + int ret; - tidss_runtime_get(tidss); + if (irq == IRQ_NOTCONNECTED) + return -ENOTCONN; - spin_lock_irqsave(&tidss->wait_lock, flags); + ret = request_irq(irq, tidss_irq_handler, 0, ddev->driver->name, ddev); + if (ret) + return ret; tidss->irq_mask = DSS_IRQ_DEVICE_OCP_ERR; - for (i = 0; i < tidss->num_crtcs; ++i) { + for (unsigned int i = 0; i < tidss->num_crtcs; ++i) { struct tidss_crtc *tcrtc = to_tidss_crtc(tidss->crtcs[i]); tidss->irq_mask |= DSS_IRQ_VP_SYNC_LOST(tcrtc->hw_videoport); @@ -127,28 +115,6 @@ tidss->irq_mask |= DSS_IRQ_VP_FRAME_DONE(tcrtc->hw_videoport); } - tidss_irq_update(tidss); - - spin_unlock_irqrestore(&tidss->wait_lock, flags); - - tidss_runtime_put(tidss); -} - -int tidss_irq_install(struct drm_device *ddev, unsigned int irq) -{ - int ret; - - if (irq == IRQ_NOTCONNECTED) - return -ENOTCONN; - - tidss_irq_preinstall(ddev); - - ret = request_irq(irq, tidss_irq_handler, 0, ddev->driver->name, ddev); - if (ret) - return ret; - - tidss_irq_postinstall(ddev); - return 0; } @@ -156,9 +122,5 @@ { struct tidss_device *tidss = to_tidss(ddev); - tidss_runtime_get(tidss); - dispc_set_irqenable(tidss->dispc, 0); - tidss_runtime_put(tidss); - free_irq(tidss->irq, ddev); } diff -Naur --no-dereference a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c --- a/drivers/gpu/drm/tidss/tidss_kms.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/drm/tidss/tidss_kms.c 2024-07-07 20:37:34.644306549 -0400 @@ -29,7 +29,7 @@ tidss_runtime_get(tidss); drm_atomic_helper_commit_modeset_disables(ddev, old_state); - drm_atomic_helper_commit_planes(ddev, old_state, 0); + drm_atomic_helper_commit_planes(ddev, old_state, DRM_PLANE_COMMIT_ACTIVE_ONLY); drm_atomic_helper_commit_modeset_enables(ddev, old_state); drm_atomic_helper_commit_hw_done(old_state); diff -Naur --no-dereference a/drivers/gpu/drm/tidss/tidss_oldi.c b/drivers/gpu/drm/tidss/tidss_oldi.c --- a/drivers/gpu/drm/tidss/tidss_oldi.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/gpu/drm/tidss/tidss_oldi.c 2024-07-07 20:37:34.644306549 -0400 @@ -0,0 +1,566 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2024 - Texas Instruments Incorporated + * + * Aradhya Bhatia + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "tidss_drv.h" +#include "tidss_oldi.h" + +struct tidss_oldi { + struct tidss_device *tidss; + struct device *dev; + + struct drm_bridge bridge; + struct drm_bridge *next_bridge; + + struct drm_panel *panel; + + enum tidss_oldi_link_type link_type; + const struct oldi_bus_format *bus_format; + u32 oldi_instance; + u32 parent_vp; + + struct clk *s_clk; + struct regmap *io_ctrl; +}; + +static const struct oldi_bus_format oldi_bus_formats[] = { + { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 18, SPWG_18, MEDIA_BUS_FMT_RGB666_1X18 }, + { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 24, SPWG_24, MEDIA_BUS_FMT_RGB888_1X24 }, + { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, JEIDA_24, MEDIA_BUS_FMT_RGB888_1X24 }, +}; + +#define OLDI_IDLE_CLK_HZ 25000000 /*25 MHz */ + +static inline struct tidss_oldi * +drm_bridge_to_tidss_oldi(struct drm_bridge *bridge) +{ + return container_of(bridge, struct tidss_oldi, bridge); +} + +static int tidss_oldi_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge); + + if (!oldi->next_bridge) { + dev_err(oldi->dev, + "%s: OLDI%d Failure attach next bridge\n", + __func__, oldi->oldi_instance); + return -ENODEV; + } + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { + dev_err(oldi->dev, + "%s: OLDI%d DRM_BRIDGE_ATTACH_NO_CONNECTOR is mandatory.\n", + __func__, oldi->oldi_instance); + return -EINVAL; + } + + return drm_bridge_attach(bridge->encoder, oldi->next_bridge, + bridge, flags); +} + +static int +oldi_set_serial_clk(struct tidss_oldi *oldi, unsigned long rate) +{ + unsigned long new_rate; + int ret; + + ret = clk_set_rate(oldi->s_clk, rate); + if (ret) { + dev_err(oldi->dev, + "OLDI%d: failed to set serial clk rate to %lu Hz\n", + oldi->oldi_instance, rate); + return ret; + } + + new_rate = clk_get_rate(oldi->s_clk); + + if (dispc_pclk_diff(rate, new_rate) > 5) + dev_warn(oldi->dev, + "OLDI%d Clock rate %lu differs over 5%% from requested %lu\n", + oldi->oldi_instance, new_rate, rate); + + dev_dbg(oldi->dev, "OLDI%d: new rate %lu Hz (requested %lu Hz)\n", + oldi->oldi_instance, clk_get_rate(oldi->s_clk), rate); + + return 0; +} + +static void tidss_oldi_tx_power(struct tidss_oldi *oldi, bool power) +{ + u32 val = 0, mask; + + if (WARN_ON(!oldi->io_ctrl)) + return; + + /* + * The power control bits are Active Low, and remain powered off by + * default. That is, the bits are set to 1. To power on the OLDI TXes, + * the bits must be cleared to 0. Since there are cases where not all + * OLDI TXes are being used, the power logic selectively powers them + * on. + * Setting the variable 'val' to particular bit masks, makes sure that + * the unrequired OLDI TXes remain powered off. + */ + + if (power) { + val = 0; + switch (oldi->link_type) { + case OLDI_MODE_SINGLE_LINK: + if (oldi->oldi_instance == OLDI(0)) + mask = OLDI_PWRDN_TX(0) | OLDI_PWRDN_BG; + else if (oldi->oldi_instance == OLDI(1)) + mask = OLDI_PWRDN_TX(1) | OLDI_PWRDN_BG; + + break; + case OLDI_MODE_CLONE_SINGLE_LINK: + case OLDI_MODE_DUAL_LINK: + mask = OLDI_PWRDN_TX(0) | OLDI_PWRDN_TX(1) | OLDI_PWRDN_BG; + break; + default: + if (oldi->oldi_instance == OLDI(0)) + mask = OLDI_PWRDN_TX(0); + else if (oldi->oldi_instance == OLDI(1)) + mask = OLDI_PWRDN_TX(1); + + val = mask; + break; + } + } else { + switch (oldi->link_type) { + case OLDI_MODE_CLONE_SINGLE_LINK: + case OLDI_MODE_DUAL_LINK: + mask = OLDI_PWRDN_TX(0) | OLDI_PWRDN_TX(1) | OLDI_PWRDN_BG; + break; + case OLDI_MODE_SINGLE_LINK: + default: + if (oldi->oldi_instance == OLDI(0)) + mask = OLDI_PWRDN_TX(0); + else if (oldi->oldi_instance == OLDI(1)) + mask = OLDI_PWRDN_TX(1); + + break; + } + val = mask; + } + + regmap_update_bits(oldi->io_ctrl, OLDI_PD_CTRL, mask, val); +} + +static int tidss_oldi_config(struct tidss_oldi *oldi) +{ + const struct oldi_bus_format *bus_fmt = NULL; + u32 oldi_reset_bit = BIT(5); + int count = 0; + u32 oldi_cfg = 0; + + bus_fmt = oldi->bus_format; + + /* + * MASTERSLAVE and SRC bits of OLDI Config are always set to 0. + */ + + if (bus_fmt->data_width == 24) + oldi_cfg |= OLDI_MSB; + else if (bus_fmt->data_width != 18) + dev_warn(oldi->dev, + "OLDI%d: DSS port width %d not supported\n", + oldi->oldi_instance, bus_fmt->data_width); + + oldi_cfg |= OLDI_DEPOL; + + oldi_cfg = (oldi_cfg & (~OLDI_MAP)) | (bus_fmt->oldi_mode_reg_val << 1); + + oldi_cfg |= OLDI_SOFTRST; + + oldi_cfg |= OLDI_ENABLE; + + switch (oldi->link_type) { + case OLDI_MODE_SINGLE_LINK: + /* All configuration is done for this mode. */ + break; + + case OLDI_MODE_CLONE_SINGLE_LINK: + oldi_cfg |= OLDI_CLONE_MODE; + break; + + case OLDI_MODE_DUAL_LINK: + /* data-mapping field also indicates dual-link mode */ + oldi_cfg |= BIT(3); + oldi_cfg |= OLDI_DUALMODESYNC; + break; + + default: + dev_err(oldi->dev, "OLDI%d: Unsupported mode.\n", + oldi->oldi_instance); + return -EINVAL; + } + + tidss_configure_oldi(oldi->tidss, oldi->parent_vp, oldi_cfg); + while (!(oldi_reset_bit & tidss_get_status(oldi->tidss)) && + count < 10000) + count++; + + if (!(oldi_reset_bit & tidss_get_status(oldi->tidss))) + dev_warn(oldi->dev, "%s: OLDI%d timeout waiting OLDI reset done\n", + __func__, oldi->oldi_instance); + + return 0; +} + +static void tidss_oldi_atomic_early_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge); + struct drm_atomic_state *state = old_bridge_state->base.state; + struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; + struct drm_display_mode *mode; + + connector = drm_atomic_get_new_connector_for_encoder(state, + bridge->encoder); + if (WARN_ON(!connector)) + return; + + conn_state = drm_atomic_get_new_connector_state(state, connector); + if (WARN_ON(!conn_state)) + return; + + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + if (WARN_ON(!crtc_state)) + return; + + mode = &crtc_state->adjusted_mode; + + /* Configure the OLDI params*/ + tidss_oldi_config(oldi); + + /* Enable the OLDI serial clock (7 times the pixel clock) */ + oldi_set_serial_clk(oldi, mode->clock * 7 * 1000); + + /* Enable OLDI IO power */ + tidss_oldi_tx_power(oldi, true); +} + +static void tidss_oldi_atomic_late_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge); + + /* Disable OLDI IO power */ + tidss_oldi_tx_power(oldi, false); + + /* Disable OLDI clock by setting IDLE Frequency */ + oldi_set_serial_clk(oldi, OLDI_IDLE_CLK_HZ); + + /* Clear OLDI Config */ + tidss_configure_oldi(oldi->tidss, oldi->parent_vp, 0); +} + +#define MAX_INPUT_SEL_FORMATS 1 + +static u32 *tidss_oldi_atomic_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge); + u32 *input_fmts; + int i; + + *num_input_fmts = 0; + + for (i = 0; i < ARRAY_SIZE(oldi_bus_formats); i++) + if (oldi_bus_formats[i].bus_fmt == output_fmt) + break; + + if (i == ARRAY_SIZE(oldi_bus_formats)) + return NULL; + + input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts), + GFP_KERNEL); + if (!input_fmts) + return NULL; + + *num_input_fmts = 1; + input_fmts[0] = oldi_bus_formats[i].input_bus_fmt; + oldi->bus_format = &oldi_bus_formats[i]; + + return input_fmts; +} + +static int tidss_oldi_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + /* + * There might be flags negotiation supported in future but + * set the bus flags in atomic_check statically for now. + */ + + /* Not sure what this is required for, at the moment */ + bridge_state->input_bus_cfg.flags = bridge->timings->input_bus_flags; + + return 0; +} + +static const struct drm_bridge_funcs tidss_oldi_bridge_funcs = { + .attach = tidss_oldi_bridge_attach, + .atomic_check = tidss_oldi_atomic_check, + .atomic_early_enable = tidss_oldi_atomic_early_enable, + .atomic_late_disable = tidss_oldi_atomic_late_disable, + .atomic_get_input_bus_fmts = tidss_oldi_atomic_get_input_bus_fmts, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, +}; + +static int get_oldi_mode(struct device_node *oldi_tx) +{ + struct device_node *companion; + struct device_node *port0, *port1; + int pixel_order; + + /* + * Find if the OLDI is paired with another OLDI for combined OLDI + * operation (dual-lvds or clone). + */ + companion = of_parse_phandle(oldi_tx, "ti,companion-oldi", 0); + if (!companion) { + if (of_property_read_bool(oldi_tx, "ti,secondary-oldi")) + return OLDI_MODE_SECONDARY; + + /* + * The OLDI TX does not have a companion, nor is it a + * secondary OLDI. It will operate independently. + */ + return OLDI_MODE_SINGLE_LINK; + } + + /* + * We need to work out if the sink is expecting us to function in + * dual-link mode. We do this by looking at the DT port nodes we are + * connected to, if they are marked as expecting even pixels and + * odd pixels than we need to enable vertical stripe output. + */ + port0 = of_graph_get_port_by_id(oldi_tx, 1); + port1 = of_graph_get_port_by_id(companion, 1); + pixel_order = drm_of_lvds_get_dual_link_pixel_order(port0, port1); + of_node_put(port0); + of_node_put(port1); + of_node_put(companion); + + switch (pixel_order) { + case -EINVAL: + /* + * The dual link properties were not found in at least + * one of the sink nodes. Since 2 OLDI ports are present + * in the DT, it can be safely assumed that the required + * configuration is Clone Mode. + */ + return OLDI_MODE_CLONE_SINGLE_LINK; + + case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS: + return OLDI_MODE_DUAL_LINK; + + /* Unsupported OLDI Modes */ + case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS: + default: + return OLDI_MODE_UNSUPPORTED; + } +} + +static u32 get_parent_dss_vp(struct device_node *oldi_tx, u32 *parent_vp) +{ + struct device_node *ep, *dss_port; + int ret = 0; + + ep = of_graph_get_endpoint_by_regs(oldi_tx, OLDI_INPUT_PORT, -1); + if (ep) { + dss_port = of_graph_get_remote_port(ep); + if (!dss_port) { + ret = -ENODEV; + goto err_return_ep_port; + } + + ret = of_property_read_u32(dss_port, "reg", parent_vp); + + of_node_put(dss_port); +err_return_ep_port: + of_node_put(ep); + return ret; + } + + return -ENODEV; +} + +static const struct drm_bridge_timings default_tidss_oldi_timings = { + .input_bus_flags = DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE + | DRM_BUS_FLAG_DE_HIGH, +}; + +void tidss_oldi_deinit(struct tidss_device *tidss) +{ + for (int i = 0; i < tidss->num_oldis; i++) { + if (tidss->oldis[i]) { + drm_bridge_remove(&tidss->oldis[i]->bridge); + tidss->oldis[i] = NULL; + } + } +} + +int tidss_oldi_init(struct tidss_device *tidss) +{ + struct tidss_oldi *oldi; + struct device_node *child; + struct drm_bridge *bridge; + struct drm_panel *panel; + u32 parent_vp, oldi_instance; + enum tidss_oldi_link_type link_type = OLDI_MODE_UNSUPPORTED; + struct device_node *oldi_parent; + int ret = 0; + + tidss->num_oldis = 0; + + oldi_parent = of_get_child_by_name(tidss->dev->of_node, "oldi-txes"); + if (!oldi_parent) + /* Return gracefully */ + return 0; + + for_each_child_of_node(oldi_parent, child) { + ret = get_parent_dss_vp(child, &parent_vp); + if (ret) { + if (ret == -ENODEV) { + /* + * ENODEV means that this particular OLDI node + * is not connected with the DSS, which is not + * a harmful case. There could be another OLDI + * which may still be connected. + * Continue to search for that. + */ + ret = 0; + continue; + } + goto err_put_node; + } + + ret = of_property_read_u32(child, "reg", &oldi_instance); + if (ret) + goto err_put_node; + + /* + * Now that its confirmed that OLDI is connected with DSS, let's + * continue getting the OLDI sinks ahead and other OLDI + * properties. + */ + ret = drm_of_find_panel_or_bridge(child, OLDI_OURPUT_PORT, -1, + &panel, &bridge); + if (ret) { + /* + * Either there was no OLDI sink in the devicetree, or + * the OLDI sink has not been added yet. In any case, + * return. + * We don't want to have an OLDI node connected to DSS + * but not to any sink. + */ + dev_err_probe(tidss->dev, ret, "no panel/bridge for OLDI%d.\n", + oldi_instance); + goto err_put_node; + } + + if (panel) { + bridge = devm_drm_panel_bridge_add(tidss->dev, panel); + if (IS_ERR(bridge)) { + ret = PTR_ERR(bridge); + goto err_put_node; + } + } + + link_type = get_oldi_mode(child); + if (link_type == OLDI_MODE_UNSUPPORTED) { + ret = dev_err_probe(tidss->dev, -EINVAL, + "OLDI%d: Unsupported OLDI connection.\n", + oldi_instance); + goto err_put_node; + } else if (link_type == OLDI_MODE_SECONDARY) { + /* + * This is the secondary OLDI node, which serves as a + * companinon to the primary OLDI, when it is configured + * for the dual-lvds mode. Since the primary OLDI will + * be a part of bridge chain, no need to put this one + * too. Continue onto the next OLDI node. + */ + continue; + } + + oldi = devm_kzalloc(tidss->dev, sizeof(*oldi), GFP_KERNEL); + if (!oldi) { + ret = -ENOMEM; + goto err_put_node; + } + + oldi->parent_vp = parent_vp; + oldi->link_type = link_type; + oldi->oldi_instance = oldi_instance; + oldi->dev = tidss->dev; + oldi->next_bridge = bridge; + oldi->panel = panel; + + oldi->io_ctrl = syscon_regmap_lookup_by_phandle(child, + "ti,oldi-io-ctrl"); + if (IS_ERR(oldi->io_ctrl)) { + ret = dev_err_probe(oldi->dev, PTR_ERR(oldi->io_ctrl), + "OLDI%d: syscon_regmap_lookup_by_phandle failed.\n", + oldi_instance); + goto err_put_node; + } + + oldi->s_clk = of_clk_get_by_name(child, "s_clk"); + if (IS_ERR(oldi->s_clk)) { + ret = dev_err_probe(oldi->dev, PTR_ERR(oldi->s_clk), + "OLDI%d: Failed to get serial clock (s_clk).\n", + oldi_instance); + goto err_put_node; + } + + /* Register the bridge. */ + oldi->bridge.of_node = child; + oldi->bridge.driver_private = oldi; + oldi->bridge.funcs = &tidss_oldi_bridge_funcs; + oldi->bridge.timings = &default_tidss_oldi_timings; + + tidss->oldis[tidss->num_oldis++] = oldi; + oldi->tidss = tidss; + + drm_bridge_add(&oldi->bridge); + } + +err_put_node: + of_node_put(child); + of_node_put(oldi_parent); + return ret; +} diff -Naur --no-dereference a/drivers/gpu/drm/tidss/tidss_oldi.h b/drivers/gpu/drm/tidss/tidss_oldi.h --- a/drivers/gpu/drm/tidss/tidss_oldi.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/gpu/drm/tidss/tidss_oldi.h 2024-07-07 20:37:34.644306549 -0400 @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024 - Texas Instruments Incorporated + * + * Aradhya Bhatia + */ + +#ifndef __TIDSS_OLDI_H__ +#define __TIDSS_OLDI_H__ + +#include + +#include "tidss_drv.h" +#include "tidss_dispc.h" + +struct tidss_oldi; + +/* OLDI Instances */ +#define OLDI(n) n + +/* OLDI PORTS */ +#define OLDI_INPUT_PORT 0 +#define OLDI_OURPUT_PORT 1 + +/* OLDI Config Bits */ +#define OLDI_ENABLE BIT(0) +#define OLDI_MAP (BIT(1) | BIT(2) | BIT(3)) +#define OLDI_SRC BIT(4) +#define OLDI_CLONE_MODE BIT(5) +#define OLDI_MASTERSLAVE BIT(6) +#define OLDI_DEPOL BIT(7) +#define OLDI_MSB BIT(8) +#define OLDI_LBEN BIT(9) +#define OLDI_LBDATA BIT(10) +#define OLDI_DUALMODESYNC BIT(11) +#define OLDI_SOFTRST BIT(12) +#define OLDI_TPATCFG BIT(13) + +/* Control MMR Register */ + +/* Register offsets */ +#define OLDI_PD_CTRL 0x100 +#define OLDI_LB_CTRL 0x104 + +/* Power control bits */ +#define OLDI_PWRDN_TX(n) BIT(n) + +/* LVDS Bandgap reference Enable/Disable */ +#define OLDI_PWRDN_BG BIT(8) + +enum tidss_oldi_link_type { + OLDI_MODE_UNSUPPORTED, + OLDI_MODE_SINGLE_LINK, + OLDI_MODE_CLONE_SINGLE_LINK, + OLDI_MODE_DUAL_LINK, + OLDI_MODE_SECONDARY, +}; + +enum oldi_mode_reg_val { SPWG_18 = 0, JEIDA_24 = 1, SPWG_24 = 2 }; + +struct oldi_bus_format { + u32 bus_fmt; + u32 data_width; + enum oldi_mode_reg_val oldi_mode_reg_val; + u32 input_bus_fmt; +}; + +int tidss_oldi_init(struct tidss_device *tidss); +void tidss_oldi_deinit(struct tidss_device *tidss); + +#endif /* __TIDSS_OLDI_H__ */ diff -Naur --no-dereference a/drivers/gpu/ipu-v3/ipu-image-convert.c b/drivers/gpu/ipu-v3/ipu-image-convert.c --- a/drivers/gpu/ipu-v3/ipu-image-convert.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/gpu/ipu-v3/ipu-image-convert.c 2024-07-07 20:37:34.644306549 -0400 @@ -477,8 +477,6 @@ return 0; } -#define round_closest(x, y) round_down((x) + (y)/2, (y)) - /* * Find the best aligned seam position for the given column / row index. * Rotation and image offsets are out of scope. @@ -565,7 +563,7 @@ * The closest input sample position that we could actually * start the input tile at, 19.13 fixed point. */ - in_pos_aligned = round_closest(in_pos, 8192U * in_align); + in_pos_aligned = round_closest_up(in_pos, 8192U * in_align); /* Convert 19.13 fixed point to integer */ in_pos_rounded = in_pos_aligned / 8192U; diff -Naur --no-dereference a/drivers/greybus/gb-beagleplay.c b/drivers/greybus/gb-beagleplay.c --- a/drivers/greybus/gb-beagleplay.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/greybus/gb-beagleplay.c 2024-07-07 20:37:34.644306549 -0400 @@ -0,0 +1,501 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Beagleplay Linux Driver for Greybus + * + * Copyright (c) 2023 Ayush Singh + * Copyright (c) 2023 BeagleBoard.org Foundation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RX_HDLC_PAYLOAD 256 +#define CRC_LEN 2 +#define MAX_RX_HDLC (1 + RX_HDLC_PAYLOAD + CRC_LEN) +#define TX_CIRC_BUF_SIZE 1024 + +#define ADDRESS_GREYBUS 0x01 +#define ADDRESS_DBG 0x02 +#define ADDRESS_CONTROL 0x03 + +#define HDLC_FRAME 0x7E +#define HDLC_ESC 0x7D +#define HDLC_XOR 0x20 + +#define CONTROL_SVC_START 0x01 +#define CONTROL_SVC_STOP 0x02 + +/* The maximum number of CPorts supported by Greybus Host Device */ +#define GB_MAX_CPORTS 32 + +/** + * struct gb_beagleplay - BeaglePlay Greybus driver + * + * @sd: underlying serdev device + * + * @gb_hd: greybus host device + * + * @tx_work: hdlc transmit work + * @tx_producer_lock: hdlc transmit data producer lock. acquired when appending data to buffer. + * @tx_consumer_lock: hdlc transmit data consumer lock. acquired when sending data over uart. + * @tx_circ_buf: hdlc transmit circular buffer. + * @tx_crc: hdlc transmit crc-ccitt fcs + * + * @rx_buffer_len: length of receive buffer filled. + * @rx_buffer: hdlc frame receive buffer + * @rx_in_esc: hdlc rx flag to indicate ESC frame + */ +struct gb_beagleplay { + struct serdev_device *sd; + + struct gb_host_device *gb_hd; + + struct work_struct tx_work; + spinlock_t tx_producer_lock; + spinlock_t tx_consumer_lock; + struct circ_buf tx_circ_buf; + u16 tx_crc; + + u16 rx_buffer_len; + bool rx_in_esc; + u8 rx_buffer[MAX_RX_HDLC]; +}; + +/** + * struct hdlc_payload - Structure to represent part of HDCL frame payload data. + * + * @len: buffer length in bytes + * @buf: payload buffer + */ +struct hdlc_payload { + u16 len; + void *buf; +}; + +static void hdlc_rx_greybus_frame(struct gb_beagleplay *bg, u8 *buf, u16 len) +{ + u16 cport_id; + struct gb_operation_msg_hdr *hdr = (struct gb_operation_msg_hdr *)buf; + + memcpy(&cport_id, hdr->pad, sizeof(cport_id)); + + dev_dbg(&bg->sd->dev, "Greybus Operation %u type %X cport %u status %u received", + hdr->operation_id, hdr->type, cport_id, hdr->result); + + greybus_data_rcvd(bg->gb_hd, cport_id, buf, len); +} + +static void hdlc_rx_dbg_frame(const struct gb_beagleplay *bg, const char *buf, u16 len) +{ + dev_dbg(&bg->sd->dev, "CC1352 Log: %.*s", (int)len, buf); +} + +/** + * hdlc_write() - Consume HDLC Buffer. + * @bg: beagleplay greybus driver + * + * Assumes that consumer lock has been acquired. + */ +static void hdlc_write(struct gb_beagleplay *bg) +{ + int written; + /* Start consuming HDLC data */ + int head = smp_load_acquire(&bg->tx_circ_buf.head); + int tail = bg->tx_circ_buf.tail; + int count = CIRC_CNT_TO_END(head, tail, TX_CIRC_BUF_SIZE); + const unsigned char *buf = &bg->tx_circ_buf.buf[tail]; + + if (count > 0) { + written = serdev_device_write_buf(bg->sd, buf, count); + + /* Finish consuming HDLC data */ + smp_store_release(&bg->tx_circ_buf.tail, (tail + written) & (TX_CIRC_BUF_SIZE - 1)); + } +} + +/** + * hdlc_append() - Queue HDLC data for sending. + * @bg: beagleplay greybus driver + * @value: hdlc byte to transmit + * + * Assumes that producer lock as been acquired. + */ +static void hdlc_append(struct gb_beagleplay *bg, u8 value) +{ + int tail, head = bg->tx_circ_buf.head; + + while (true) { + tail = READ_ONCE(bg->tx_circ_buf.tail); + + if (CIRC_SPACE(head, tail, TX_CIRC_BUF_SIZE) >= 1) { + bg->tx_circ_buf.buf[head] = value; + + /* Finish producing HDLC byte */ + smp_store_release(&bg->tx_circ_buf.head, + (head + 1) & (TX_CIRC_BUF_SIZE - 1)); + return; + } + dev_warn(&bg->sd->dev, "Tx circ buf full"); + usleep_range(3000, 5000); + } +} + +static void hdlc_append_escaped(struct gb_beagleplay *bg, u8 value) +{ + if (value == HDLC_FRAME || value == HDLC_ESC) { + hdlc_append(bg, HDLC_ESC); + value ^= HDLC_XOR; + } + hdlc_append(bg, value); +} + +static void hdlc_append_tx_frame(struct gb_beagleplay *bg) +{ + bg->tx_crc = 0xFFFF; + hdlc_append(bg, HDLC_FRAME); +} + +static void hdlc_append_tx_u8(struct gb_beagleplay *bg, u8 value) +{ + bg->tx_crc = crc_ccitt(bg->tx_crc, &value, 1); + hdlc_append_escaped(bg, value); +} + +static void hdlc_append_tx_buf(struct gb_beagleplay *bg, const u8 *buf, u16 len) +{ + size_t i; + + for (i = 0; i < len; i++) + hdlc_append_tx_u8(bg, buf[i]); +} + +static void hdlc_append_tx_crc(struct gb_beagleplay *bg) +{ + bg->tx_crc ^= 0xffff; + hdlc_append_escaped(bg, bg->tx_crc & 0xff); + hdlc_append_escaped(bg, (bg->tx_crc >> 8) & 0xff); +} + +static void hdlc_transmit(struct work_struct *work) +{ + struct gb_beagleplay *bg = container_of(work, struct gb_beagleplay, tx_work); + + spin_lock_bh(&bg->tx_consumer_lock); + hdlc_write(bg); + spin_unlock_bh(&bg->tx_consumer_lock); +} + +static void hdlc_tx_frames(struct gb_beagleplay *bg, u8 address, u8 control, + const struct hdlc_payload payloads[], size_t count) +{ + size_t i; + + spin_lock(&bg->tx_producer_lock); + + hdlc_append_tx_frame(bg); + hdlc_append_tx_u8(bg, address); + hdlc_append_tx_u8(bg, control); + + for (i = 0; i < count; ++i) + hdlc_append_tx_buf(bg, payloads[i].buf, payloads[i].len); + + hdlc_append_tx_crc(bg); + hdlc_append_tx_frame(bg); + + spin_unlock(&bg->tx_producer_lock); + + schedule_work(&bg->tx_work); +} + +static void hdlc_tx_s_frame_ack(struct gb_beagleplay *bg) +{ + hdlc_tx_frames(bg, bg->rx_buffer[0], (bg->rx_buffer[1] >> 1) & 0x7, NULL, 0); +} + +static void hdlc_rx_frame(struct gb_beagleplay *bg) +{ + u16 crc, len; + u8 ctrl, *buf; + u8 address = bg->rx_buffer[0]; + + crc = crc_ccitt(0xffff, bg->rx_buffer, bg->rx_buffer_len); + if (crc != 0xf0b8) { + dev_warn_ratelimited(&bg->sd->dev, "CRC failed from %02x: 0x%04x", address, crc); + return; + } + + ctrl = bg->rx_buffer[1]; + buf = &bg->rx_buffer[2]; + len = bg->rx_buffer_len - 4; + + /* I-Frame, send S-Frame ACK */ + if ((ctrl & 1) == 0) + hdlc_tx_s_frame_ack(bg); + + switch (address) { + case ADDRESS_DBG: + hdlc_rx_dbg_frame(bg, buf, len); + break; + case ADDRESS_GREYBUS: + hdlc_rx_greybus_frame(bg, buf, len); + break; + default: + dev_warn_ratelimited(&bg->sd->dev, "unknown frame %u", address); + } +} + +static int hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count) +{ + size_t i; + u8 c; + + for (i = 0; i < count; ++i) { + c = data[i]; + + switch (c) { + case HDLC_FRAME: + if (bg->rx_buffer_len) + hdlc_rx_frame(bg); + + bg->rx_buffer_len = 0; + break; + case HDLC_ESC: + bg->rx_in_esc = true; + break; + default: + if (bg->rx_in_esc) { + c ^= 0x20; + bg->rx_in_esc = false; + } + + if (bg->rx_buffer_len < MAX_RX_HDLC) { + bg->rx_buffer[bg->rx_buffer_len] = c; + bg->rx_buffer_len++; + } else { + dev_err_ratelimited(&bg->sd->dev, "RX Buffer Overflow"); + bg->rx_buffer_len = 0; + } + } + } + + return count; +} + +static int hdlc_init(struct gb_beagleplay *bg) +{ + INIT_WORK(&bg->tx_work, hdlc_transmit); + spin_lock_init(&bg->tx_producer_lock); + spin_lock_init(&bg->tx_consumer_lock); + bg->tx_circ_buf.head = 0; + bg->tx_circ_buf.tail = 0; + + bg->tx_circ_buf.buf = devm_kmalloc(&bg->sd->dev, TX_CIRC_BUF_SIZE, GFP_KERNEL); + if (!bg->tx_circ_buf.buf) + return -ENOMEM; + + bg->rx_buffer_len = 0; + bg->rx_in_esc = false; + + return 0; +} + +static void hdlc_deinit(struct gb_beagleplay *bg) +{ + flush_work(&bg->tx_work); +} + +static int gb_tty_receive(struct serdev_device *sd, const unsigned char *data, size_t count) +{ + struct gb_beagleplay *bg = serdev_device_get_drvdata(sd); + + return hdlc_rx(bg, data, count); +} + +static void gb_tty_wakeup(struct serdev_device *serdev) +{ + struct gb_beagleplay *bg = serdev_device_get_drvdata(serdev); + + schedule_work(&bg->tx_work); +} + +static struct serdev_device_ops gb_beagleplay_ops = { + .receive_buf = gb_tty_receive, + .write_wakeup = gb_tty_wakeup, +}; + +static int gb_message_send(struct gb_host_device *hd, u16 cport, struct gb_message *msg, gfp_t mask) +{ + struct gb_beagleplay *bg = dev_get_drvdata(&hd->dev); + struct hdlc_payload payloads[2]; + + dev_dbg(&hd->dev, "Sending greybus message with Operation %u, Type: %X on Cport %u", + msg->header->operation_id, msg->header->type, cport); + + if (msg->header->size > RX_HDLC_PAYLOAD) + return dev_err_probe(&hd->dev, -E2BIG, "Greybus message too big"); + + memcpy(msg->header->pad, &cport, sizeof(cport)); + + payloads[0].buf = msg->header; + payloads[0].len = sizeof(*msg->header); + payloads[1].buf = msg->payload; + payloads[1].len = msg->payload_size; + + hdlc_tx_frames(bg, ADDRESS_GREYBUS, 0x03, payloads, 2); + greybus_message_sent(bg->gb_hd, msg, 0); + + return 0; +} + +static void gb_message_cancel(struct gb_message *message) +{ +} + +static struct gb_hd_driver gb_hdlc_driver = { .message_send = gb_message_send, + .message_cancel = gb_message_cancel }; + +static void gb_beagleplay_start_svc(struct gb_beagleplay *bg) +{ + const u8 command = CONTROL_SVC_START; + const struct hdlc_payload payload = { .len = 1, .buf = (void *)&command }; + + hdlc_tx_frames(bg, ADDRESS_CONTROL, 0x03, &payload, 1); +} + +static void gb_beagleplay_stop_svc(struct gb_beagleplay *bg) +{ + const u8 command = CONTROL_SVC_STOP; + const struct hdlc_payload payload = { .len = 1, .buf = (void *)&command }; + + hdlc_tx_frames(bg, ADDRESS_CONTROL, 0x03, &payload, 1); +} + +static void gb_greybus_deinit(struct gb_beagleplay *bg) +{ + gb_hd_del(bg->gb_hd); + gb_hd_put(bg->gb_hd); +} + +static int gb_greybus_init(struct gb_beagleplay *bg) +{ + int ret; + + bg->gb_hd = gb_hd_create(&gb_hdlc_driver, &bg->sd->dev, TX_CIRC_BUF_SIZE, GB_MAX_CPORTS); + if (IS_ERR(bg->gb_hd)) { + dev_err(&bg->sd->dev, "Failed to create greybus host device"); + return PTR_ERR(bg->gb_hd); + } + + ret = gb_hd_add(bg->gb_hd); + if (ret) { + dev_err(&bg->sd->dev, "Failed to add greybus host device"); + goto free_gb_hd; + } + dev_set_drvdata(&bg->gb_hd->dev, bg); + + return 0; + +free_gb_hd: + gb_greybus_deinit(bg); + return ret; +} + +static void gb_serdev_deinit(struct gb_beagleplay *bg) +{ + serdev_device_close(bg->sd); +} + +static int gb_serdev_init(struct gb_beagleplay *bg) +{ + int ret; + + serdev_device_set_drvdata(bg->sd, bg); + serdev_device_set_client_ops(bg->sd, &gb_beagleplay_ops); + ret = serdev_device_open(bg->sd); + if (ret) + return dev_err_probe(&bg->sd->dev, ret, "Unable to open serial device"); + + serdev_device_set_baudrate(bg->sd, 115200); + serdev_device_set_flow_control(bg->sd, false); + + return 0; +} + +static int gb_beagleplay_probe(struct serdev_device *serdev) +{ + int ret = 0; + struct gb_beagleplay *bg; + + bg = devm_kmalloc(&serdev->dev, sizeof(*bg), GFP_KERNEL); + if (!bg) + return -ENOMEM; + + bg->sd = serdev; + ret = gb_serdev_init(bg); + if (ret) + return ret; + + ret = hdlc_init(bg); + if (ret) + goto free_serdev; + + ret = gb_greybus_init(bg); + if (ret) + goto free_hdlc; + + gb_beagleplay_start_svc(bg); + + return 0; + +free_hdlc: + hdlc_deinit(bg); +free_serdev: + gb_serdev_deinit(bg); + return ret; +} + +static void gb_beagleplay_remove(struct serdev_device *serdev) +{ + struct gb_beagleplay *bg = serdev_device_get_drvdata(serdev); + + gb_greybus_deinit(bg); + gb_beagleplay_stop_svc(bg); + hdlc_deinit(bg); + gb_serdev_deinit(bg); +} + +static const struct of_device_id gb_beagleplay_of_match[] = { + { + .compatible = "ti,cc1352p7", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, gb_beagleplay_of_match); + +static struct serdev_device_driver gb_beagleplay_driver = { + .probe = gb_beagleplay_probe, + .remove = gb_beagleplay_remove, + .driver = { + .name = "gb_beagleplay", + .of_match_table = gb_beagleplay_of_match, + }, +}; + +module_serdev_device_driver(gb_beagleplay_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ayush Singh "); +MODULE_DESCRIPTION("A Greybus driver for BeaglePlay"); diff -Naur --no-dereference a/drivers/greybus/Kconfig b/drivers/greybus/Kconfig --- a/drivers/greybus/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/greybus/Kconfig 2024-07-07 20:37:34.644306549 -0400 @@ -17,6 +17,16 @@ if GREYBUS +config GREYBUS_BEAGLEPLAY + tristate "Greybus BeaglePlay driver" + depends on SERIAL_DEV_BUS + help + Select this option if you have a BeaglePlay where CC1352 + co-processor acts as Greybus SVC. + + To compile this code as a module, chose M here: the module + will be called gb-beagleplay.ko + config GREYBUS_ES2 tristate "Greybus ES3 USB host controller" depends on USB diff -Naur --no-dereference a/drivers/greybus/Makefile b/drivers/greybus/Makefile --- a/drivers/greybus/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/greybus/Makefile 2024-07-07 20:37:34.644306549 -0400 @@ -18,6 +18,8 @@ # needed for trace events ccflags-y += -I$(src) +obj-$(CONFIG_GREYBUS_BEAGLEPLAY) += gb-beagleplay.o + # Greybus Host controller drivers gb-es2-y := es2.o diff -Naur --no-dereference a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c --- a/drivers/i2c/busses/i2c-omap.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/i2c/busses/i2c-omap.c 2024-07-07 20:37:34.644306549 -0400 @@ -1537,7 +1537,7 @@ pm_runtime_disable(&pdev->dev); } -static int __maybe_unused omap_i2c_runtime_suspend(struct device *dev) +static int omap_i2c_runtime_suspend(struct device *dev) { struct omap_i2c_dev *omap = dev_get_drvdata(dev); @@ -1563,7 +1563,7 @@ return 0; } -static int __maybe_unused omap_i2c_runtime_resume(struct device *dev) +static int omap_i2c_runtime_resume(struct device *dev) { struct omap_i2c_dev *omap = dev_get_drvdata(dev); @@ -1577,11 +1577,33 @@ return 0; } +static int omap_i2c_suspend(struct device *dev) +{ + /* + * If the controller is autosuspended, there is no way to wakeup it once + * runtime pm is disabled (in suspend_late()). + * But a device may need the controller up during suspend_noirq() or + * resume_noirq(). + * Wakeup the controller while runtime pm is enabled, so it is available + * until its suspend_noirq(), and from resume_noirq(). + */ + return pm_runtime_resume_and_get(dev); +} + +static int omap_i2c_resume(struct device *dev) +{ + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; +} + static const struct dev_pm_ops omap_i2c_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, - omap_i2c_runtime_resume, NULL) + NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(omap_i2c_suspend, omap_i2c_resume) + RUNTIME_PM_OPS(omap_i2c_runtime_suspend, + omap_i2c_runtime_resume, NULL) }; static struct platform_driver omap_i2c_driver = { @@ -1589,7 +1611,7 @@ .remove_new = omap_i2c_remove, .driver = { .name = "omap_i2c", - .pm = &omap_i2c_pm_ops, + .pm = pm_ptr(&omap_i2c_pm_ops), .of_match_table = of_match_ptr(omap_i2c_of_match), }, }; diff -Naur --no-dereference a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c --- a/drivers/input/keyboard/gpio_keys.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/input/keyboard/gpio_keys.c 2024-07-07 20:37:34.644306549 -0400 @@ -45,7 +45,9 @@ unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */ unsigned int irq; + unsigned int wakeirq; unsigned int wakeup_trigger_type; + spinlock_t lock; bool disabled; bool key_pressed; @@ -511,6 +513,7 @@ struct gpio_button_data *bdata = &ddata->data[idx]; irq_handler_t isr; unsigned long irqflags; + const char *wakedesc; int irq; int error; @@ -575,6 +578,14 @@ !gpiod_cansleep(bdata->gpiod); } + /* + * If an interrupt was specified, use it instead of the gpio + * interrupt and use the gpio for reading the state. A separate + * interrupt may be used as the main button interrupt for + * runtime PM to detect events also in deeper idle states. If a + * dedicated wakeirq is used for system suspend only, see below + * for bdata->wakeirq setup. + */ if (button->irq) { bdata->irq = button->irq; } else { @@ -672,6 +683,36 @@ return error; } + if (!button->wakeirq) + return 0; + + /* Use :wakeup suffix like drivers/base/power/wakeirq.c does */ + wakedesc = devm_kasprintf(dev, GFP_KERNEL, "%s:wakeup", desc); + if (!wakedesc) + return -ENOMEM; + + bdata->wakeirq = button->wakeirq; + irqflags |= IRQF_NO_SUSPEND; + + /* + * Wakeirq shares the handler with the main interrupt, it's only + * active during system suspend. See gpio_keys_button_enable_wakeup() + * and gpio_keys_button_disable_wakeup(). + */ + error = devm_request_any_context_irq(dev, bdata->wakeirq, isr, + irqflags, wakedesc, bdata); + if (error < 0) { + dev_err(dev, "Unable to claim wakeirq %d; error %d\n", + bdata->irq, error); + return error; + } + + /* + * Disable wakeirq until suspend. IRQF_NO_AUTOEN won't work if + * IRQF_SHARED was set based on !button->can_disable. + */ + disable_irq_nosync(bdata->wakeirq); + return 0; } @@ -728,7 +769,7 @@ struct gpio_keys_platform_data *pdata; struct gpio_keys_button *button; struct fwnode_handle *child; - int nbuttons; + int nbuttons, irq; nbuttons = device_get_child_node_count(dev); if (nbuttons == 0) @@ -750,9 +791,19 @@ device_property_read_string(dev, "label", &pdata->name); device_for_each_child_node(dev, child) { - if (is_of_node(child)) - button->irq = - irq_of_parse_and_map(to_of_node(child), 0); + if (is_of_node(child)) { + irq = of_irq_get_byname(to_of_node(child), "irq"); + if (irq > 0) + button->irq = irq; + + irq = of_irq_get_byname(to_of_node(child), "wakeup"); + if (irq > 0) + button->wakeirq = irq; + + if (!button->irq && !button->wakeirq) + button->irq = + irq_of_parse_and_map(to_of_node(child), 0); + } if (fwnode_property_read_u32(child, "linux,code", &button->code)) { @@ -921,6 +972,11 @@ } } + if (bdata->wakeirq) { + enable_irq(bdata->wakeirq); + disable_irq_nosync(bdata->irq); + } + return 0; } @@ -929,6 +985,11 @@ { int error; + if (bdata->wakeirq) { + enable_irq(bdata->irq); + disable_irq_nosync(bdata->wakeirq); + } + /* * The trigger type is always both edges for gpio-based keys and we do * not support changing wakeup trigger for interrupt-based keys. diff -Naur --no-dereference a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c --- a/drivers/input/touchscreen/edt-ft5x06.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/input/touchscreen/edt-ft5x06.c 2024-07-07 20:37:34.644306549 -0400 @@ -69,6 +69,7 @@ #define TOUCH_EVENT_RESERVED 0x03 #define EDT_NAME_LEN 23 +#define EDT_NAME_PREFIX_LEN 8 #define EDT_SWITCH_MODE_RETRIES 10 #define EDT_SWITCH_MODE_DELAY 5 /* msec */ #define EDT_RAW_DATA_RETRIES 100 @@ -80,6 +81,10 @@ #define M06_REG_CMD(factory) ((factory) ? 0xf3 : 0xfc) #define M06_REG_ADDR(factory, addr) ((factory) ? (addr) & 0x7f : (addr) & 0x3f) +#define RESET_DELAY_MS 300 /* reset deassert to I2C */ +#define FIRST_POLL_DELAY_MS 300 /* in addition to the above */ +#define POLL_INTERVAL_MS 17 /* 17ms = 60fps */ + enum edt_pmode { EDT_PMODE_NOT_SUPPORTED, EDT_PMODE_HIBERNATE, @@ -139,14 +144,19 @@ u8 tdata_cmd; int tdata_len; int tdata_offset; + unsigned int known_ids; - char name[EDT_NAME_LEN]; + char name[EDT_NAME_PREFIX_LEN + EDT_NAME_LEN]; char fw_version[EDT_NAME_LEN]; + int init_td_status; struct edt_reg_addr reg_addr; enum edt_ver version; unsigned int crc_errors; unsigned int header_errors; + + struct timer_list timer; + struct work_struct work_i2c_poll; }; struct edt_i2c_chip_data { @@ -303,17 +313,49 @@ u8 rdbuf[63]; int i, type, x, y, id; int error; + int num_points; + unsigned int active_ids = 0, known_ids = tsdata->known_ids; + long released_ids; + int b = 0; memset(rdbuf, 0, sizeof(rdbuf)); error = regmap_bulk_read(tsdata->regmap, tsdata->tdata_cmd, rdbuf, tsdata->tdata_len); + if (tsdata->version == EDT_M06) { + num_points = tsdata->max_support_points; + } else { + /* Register 2 is TD_STATUS, containing the number of touch + * points. + */ + num_points = min(rdbuf[2] & 0xf, tsdata->max_support_points); + + /* When polling FT5x06 without IRQ: initial register contents + * could be stale or undefined; discard all readings until + * TD_STATUS changes for the first time (or num_points is 0). + */ + if (tsdata->init_td_status) { + if (tsdata->init_td_status < 0) + tsdata->init_td_status = rdbuf[2]; + + if (num_points && rdbuf[2] == tsdata->init_td_status) + goto out; + + tsdata->init_td_status = 0; + } + + if (!error && num_points) + error = regmap_bulk_read(tsdata->regmap, + tsdata->tdata_offset, + &rdbuf[tsdata->tdata_offset], + tsdata->point_len * num_points); + } if (error) { dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", error); goto out; } - for (i = 0; i < tsdata->max_support_points; i++) { + for (i = 0; i < num_points; i++) { u8 *buf = &rdbuf[i * tsdata->point_len + tsdata->tdata_offset]; type = buf[0] >> 6; @@ -335,10 +377,25 @@ input_mt_slot(tsdata->input, id); if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, - type != TOUCH_EVENT_UP)) + type != TOUCH_EVENT_UP)) { touchscreen_report_pos(tsdata->input, &tsdata->prop, x, y, true); + active_ids |= BIT(id); + } else { + known_ids &= ~BIT(id); + } + } + + /* One issue with the device is the TOUCH_UP message is not always + * returned. Instead track which ids we know about and report when they + * are no longer updated + */ + released_ids = known_ids & ~active_ids; + for_each_set_bit_from(b, &released_ids, tsdata->max_support_points) { + input_mt_slot(tsdata->input, b); + input_mt_report_slot_inactive(tsdata->input); } + tsdata->known_ids = active_ids; input_mt_report_pointer_emulation(tsdata->input, true); input_sync(tsdata->input); @@ -347,6 +404,22 @@ return IRQ_HANDLED; } +static void edt_ft5x06_ts_irq_poll_timer(struct timer_list *t) +{ + struct edt_ft5x06_ts_data *tsdata = from_timer(tsdata, t, timer); + + schedule_work(&tsdata->work_i2c_poll); + mod_timer(&tsdata->timer, jiffies + msecs_to_jiffies(POLL_INTERVAL_MS)); +} + +static void edt_ft5x06_ts_work_i2c_poll(struct work_struct *work) +{ + struct edt_ft5x06_ts_data *tsdata = container_of(work, + struct edt_ft5x06_ts_data, work_i2c_poll); + + edt_ft5x06_ts_isr(0, tsdata); +} + struct edt_ft5x06_attribute { struct device_attribute dattr; size_t field_offset; @@ -865,6 +938,9 @@ char *model_name = tsdata->name; char *fw_version = tsdata->fw_version; + snprintf(model_name, EDT_NAME_PREFIX_LEN + 1, "%s ", dev_name(&client->dev)); + model_name += strlen(model_name); + /* see what we find if we assume it is a M06 * * if we get less than EDT_NAME_LEN, we don't want * to have garbage in there @@ -1053,20 +1129,23 @@ static void edt_ft5x06_ts_set_tdata_parameters(struct edt_ft5x06_ts_data *tsdata) { int crclen; + int points; if (tsdata->version == EDT_M06) { tsdata->tdata_cmd = 0xf9; tsdata->tdata_offset = 5; tsdata->point_len = 4; crclen = 1; + points = tsdata->max_support_points; } else { tsdata->tdata_cmd = 0x0; tsdata->tdata_offset = 3; tsdata->point_len = 6; crclen = 0; + points = 0; } - tsdata->tdata_len = tsdata->point_len * tsdata->max_support_points + + tsdata->tdata_len = tsdata->point_len * points + tsdata->tdata_offset + crclen; } @@ -1243,7 +1322,7 @@ if (tsdata->reset_gpio) { usleep_range(5000, 6000); gpiod_set_value_cansleep(tsdata->reset_gpio, 0); - msleep(300); + msleep(RESET_DELAY_MS); } input = devm_input_allocate_device(&client->dev); @@ -1317,17 +1396,28 @@ return error; } - irq_flags = irq_get_trigger_type(client->irq); - if (irq_flags == IRQF_TRIGGER_NONE) - irq_flags = IRQF_TRIGGER_FALLING; - irq_flags |= IRQF_ONESHOT; - - error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, edt_ft5x06_ts_isr, irq_flags, - client->name, tsdata); - if (error) { - dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); - return error; + if (client->irq) { + irq_flags = irq_get_trigger_type(client->irq); + if (irq_flags == IRQF_TRIGGER_NONE) + irq_flags = IRQF_TRIGGER_FALLING; + irq_flags |= IRQF_ONESHOT; + + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, edt_ft5x06_ts_isr, + irq_flags, client->name, + tsdata); + if (error) { + dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); + return error; + } + } else { + tsdata->init_td_status = -1; /* filter bogus initial data */ + INIT_WORK(&tsdata->work_i2c_poll, + edt_ft5x06_ts_work_i2c_poll); + timer_setup(&tsdata->timer, edt_ft5x06_ts_irq_poll_timer, 0); + tsdata->timer.expires = + jiffies + msecs_to_jiffies(FIRST_POLL_DELAY_MS); + add_timer(&tsdata->timer); } error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group); @@ -1353,6 +1443,10 @@ { struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + if (!client->irq) { + del_timer(&tsdata->timer); + cancel_work_sync(&tsdata->work_i2c_poll); + } edt_ft5x06_ts_teardown_debugfs(tsdata); regmap_exit(tsdata->regmap); } diff -Naur --no-dereference a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c --- a/drivers/irqchip/irq-pruss-intc.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/irqchip/irq-pruss-intc.c 2024-07-07 20:37:34.644306549 -0400 @@ -70,6 +70,8 @@ #define MAX_PRU_SYS_EVENTS 160 #define MAX_PRU_CHANNELS 20 +#define MAX_PRU_INT_EVENTS 64 + /** * struct pruss_intc_map_record - keeps track of actual mapping state * @value: The currently mapped value (channel or host) @@ -85,10 +87,13 @@ * @num_system_events: number of input system events handled by the PRUSS INTC * @num_host_events: number of host events (which is equal to number of * channels) supported by the PRUSS INTC + * @quirky_events: bitmask of events that need quirky IRQ handling (limited to + * (internal sources only for now, so 64 bits suffice) */ struct pruss_intc_match_data { u8 num_system_events; u8 num_host_events; + u64 quirky_events; }; /** @@ -101,6 +106,7 @@ * @soc_config: cached PRUSS INTC IP configuration data * @dev: PRUSS INTC device pointer * @lock: mutex to serialize interrupts mapping + * @irqs_reserved: bit-mask of reserved host interrupts */ struct pruss_intc { struct pruss_intc_map_record event_channel[MAX_PRU_SYS_EVENTS]; @@ -111,6 +117,7 @@ const struct pruss_intc_match_data *soc_config; struct device *dev; struct mutex lock; /* PRUSS INTC lock */ + u8 irqs_reserved; }; /** @@ -178,6 +185,7 @@ static void pruss_intc_map(struct pruss_intc *intc, unsigned long hwirq) { struct device *dev = intc->dev; + bool enable_hwirq = false; u8 ch, host, reg_idx; u32 val; @@ -187,6 +195,9 @@ ch = intc->event_channel[hwirq].value; host = intc->channel_host[ch].value; + enable_hwirq = (host < FIRST_PRU_HOST_INT || + host >= FIRST_PRU_HOST_INT + MAX_NUM_HOST_IRQS || + intc->irqs_reserved & BIT(host - FIRST_PRU_HOST_INT)); pruss_intc_update_cmr(intc, hwirq, ch); @@ -194,8 +205,10 @@ val = BIT(hwirq % 32); /* clear and enable system event */ - pruss_intc_write_reg(intc, PRU_INTC_ESR(reg_idx), val); pruss_intc_write_reg(intc, PRU_INTC_SECR(reg_idx), val); + /* unmask only events going to various PRU and other cores by default */ + if (enable_hwirq) + pruss_intc_write_reg(intc, PRU_INTC_ESR(reg_idx), val); if (++intc->channel_host[ch].ref_count == 1) { pruss_intc_update_hmr(intc, ch, host); @@ -204,7 +217,8 @@ pruss_intc_write_reg(intc, PRU_INTC_HIEISR, host); } - dev_dbg(dev, "mapped system_event = %lu channel = %d host = %d", + dev_dbg(dev, "mapped%s system_event = %lu channel = %d host = %d", + enable_hwirq ? " and enabled" : "", hwirq, ch, host); mutex_unlock(&intc->lock); @@ -268,11 +282,14 @@ /* * configure polarity (SIPR register) to active high and - * type (SITR register) to level interrupt for all system events + * type (SITR register) to level interrupt for all system events, + * and disable and clear all the system events */ for (i = 0; i < num_event_type_regs; i++) { pruss_intc_write_reg(intc, PRU_INTC_SIPR(i), 0xffffffff); pruss_intc_write_reg(intc, PRU_INTC_SITR(i), 0); + pruss_intc_write_reg(intc, PRU_INTC_ECR(i), 0xffffffff); + pruss_intc_write_reg(intc, PRU_INTC_SECR(i), 0xffffffff); } /* clear all interrupt channel map registers, 4 events per register */ @@ -292,6 +309,10 @@ struct pruss_intc *intc = irq_data_get_irq_chip_data(data); unsigned int hwirq = data->hwirq; + if (hwirq < MAX_PRU_INT_EVENTS && + intc->soc_config->quirky_events & BIT_ULL(hwirq)) + return; + pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq); } @@ -308,6 +329,9 @@ struct pruss_intc *intc = irq_data_get_irq_chip_data(data); unsigned int hwirq = data->hwirq; + if (hwirq < MAX_PRU_INT_EVENTS && + intc->soc_config->quirky_events & BIT_ULL(hwirq)) + pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq); pruss_intc_write_reg(intc, PRU_INTC_EISR, hwirq); } @@ -361,6 +385,14 @@ return 0; } +static int pruss_intc_irq_irq_set_type(struct irq_data *data, unsigned int type) +{ + if (type != IRQ_TYPE_LEVEL_HIGH) + return -EINVAL; + + return 0; +} + static struct irq_chip pruss_irqchip = { .name = "pruss-intc", .irq_ack = pruss_intc_irq_ack, @@ -370,6 +402,7 @@ .irq_release_resources = pruss_intc_irq_relres, .irq_get_irqchip_state = pruss_intc_irq_get_irqchip_state, .irq_set_irqchip_state = pruss_intc_irq_set_irqchip_state, + .irq_set_type = pruss_intc_irq_irq_set_type, }; static int pruss_intc_validate_mapping(struct pruss_intc *intc, int event, @@ -521,7 +554,7 @@ struct pruss_intc *intc; struct pruss_host_irq_data *host_data; int i, irq, ret; - u8 max_system_events, irqs_reserved = 0; + u8 max_system_events; data = of_device_get_match_data(dev); if (!data) @@ -542,7 +575,7 @@ return PTR_ERR(intc->base); ret = of_property_read_u8(dev->of_node, "ti,irqs-reserved", - &irqs_reserved); + &intc->irqs_reserved); /* * The irqs-reserved is used only for some SoC's therefore not having @@ -561,7 +594,7 @@ return -ENOMEM; for (i = 0; i < MAX_NUM_HOST_IRQS; i++) { - if (irqs_reserved & BIT(i)) + if (intc->irqs_reserved & BIT(i)) continue; irq = platform_get_irq_byname(pdev, irq_names[i]); @@ -623,11 +656,13 @@ static const struct pruss_intc_match_data pruss_intc_data = { .num_system_events = 64, .num_host_events = 10, + .quirky_events = BIT_ULL(7), /* IEP capture/compare event */ }; static const struct pruss_intc_match_data icssg_intc_data = { .num_system_events = 160, .num_host_events = 20, + .quirky_events = BIT_ULL(7) | BIT_ULL(56), /* IEP{0,1} capture/compare events */ }; static const struct of_device_id pruss_intc_of_match[] = { diff -Naur --no-dereference a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c --- a/drivers/irqchip/irq-ti-sci-inta.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/irqchip/irq-ti-sci-inta.c 2024-07-07 20:37:34.644306549 -0400 @@ -64,6 +64,7 @@ * @events: Array of event descriptors assigned to this vint. * @parent_virq: Linux IRQ number that gets attached to parent * @vint_id: TISCI vint ID + * @affinity_managed: flag to indicate VINT affinity is managed */ struct ti_sci_inta_vint_desc { struct irq_domain *domain; @@ -72,6 +73,7 @@ struct ti_sci_inta_event_desc events[MAX_EVENTS_PER_VINT]; unsigned int parent_virq; u16 vint_id; + bool affinity_managed; }; /** @@ -199,10 +201,12 @@ /** * ti_sci_inta_alloc_parent_irq() - Allocate parent irq to Interrupt aggregator * @domain: IRQ domain corresponding to Interrupt Aggregator + * @vint_id: vint_id to which event is to be mapped to * * Return 0 if all went well else corresponding error value. */ -static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_domain *domain) +static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_domain *domain, + u16 vint_id) { struct ti_sci_inta_irq_domain *inta = domain->host_data; struct ti_sci_inta_vint_desc *vint_desc; @@ -210,11 +214,6 @@ struct device_node *parent_node; unsigned int parent_virq; int p_hwirq, ret; - u16 vint_id; - - vint_id = ti_sci_get_free_resource(inta->vint); - if (vint_id == TI_SCI_RESOURCE_NULL) - return ERR_PTR(-EINVAL); p_hwirq = ti_sci_inta_xlate_irq(inta, vint_id); if (p_hwirq < 0) { @@ -328,29 +327,42 @@ struct ti_sci_inta_vint_desc *vint_desc = NULL; struct ti_sci_inta_event_desc *event_desc; u16 free_bit; + u16 vint_id; mutex_lock(&inta->vint_mutex); - list_for_each_entry(vint_desc, &inta->vint_list, list) { + /* + * Allocate new VINT each time until we runout, then start + * aggregating + */ + vint_id = ti_sci_get_free_resource(inta->vint); + if (vint_id == TI_SCI_RESOURCE_NULL) { + list_for_each_entry(vint_desc, &inta->vint_list, list) { + if (vint_desc->affinity_managed) + continue; + free_bit = find_first_zero_bit(vint_desc->event_map, + MAX_EVENTS_PER_VINT); + if (free_bit != MAX_EVENTS_PER_VINT) { + set_bit(free_bit, vint_desc->event_map); + break; + } + } + } else { + vint_desc = ti_sci_inta_alloc_parent_irq(domain, vint_id); + if (IS_ERR(vint_desc)) { + event_desc = ERR_CAST(vint_desc); + goto unlock; + } + free_bit = find_first_zero_bit(vint_desc->event_map, MAX_EVENTS_PER_VINT); - if (free_bit != MAX_EVENTS_PER_VINT) { - set_bit(free_bit, vint_desc->event_map); - goto alloc_event; - } + set_bit(free_bit, vint_desc->event_map); } - /* No free bits available. Allocate a new vint */ - vint_desc = ti_sci_inta_alloc_parent_irq(domain); - if (IS_ERR(vint_desc)) { - event_desc = ERR_CAST(vint_desc); + if (free_bit == MAX_EVENTS_PER_VINT) { + event_desc = ERR_PTR(-EINVAL); goto unlock; } - free_bit = find_first_zero_bit(vint_desc->event_map, - MAX_EVENTS_PER_VINT); - set_bit(free_bit, vint_desc->event_map); - -alloc_event: event_desc = ti_sci_inta_alloc_event(vint_desc, free_bit, hwirq); if (IS_ERR(event_desc)) clear_bit(free_bit, vint_desc->event_map); @@ -429,6 +441,7 @@ return PTR_ERR(event_desc); data->chip_data = event_desc; + irq_data_update_effective_affinity(data, cpu_online_mask); return 0; } @@ -499,11 +512,48 @@ ti_sci_inta_manage_event(data, VINT_STATUS_OFFSET); } +#ifdef CONFIG_SMP +static int ti_sci_inta_set_affinity(struct irq_data *d, + const struct cpumask *mask_val, bool force) +{ + struct ti_sci_inta_event_desc *event_desc; + struct ti_sci_inta_vint_desc *vint_desc; + struct irq_data *parent_irq_data; + + if (cpumask_equal(irq_data_get_effective_affinity_mask(d), mask_val)) + return 0; + + event_desc = irq_data_get_irq_chip_data(d); + if (event_desc) { + vint_desc = to_vint_desc(event_desc, event_desc->vint_bit); + parent_irq_data = irq_get_irq_data(vint_desc->parent_virq); + + if (!parent_irq_data || !parent_irq_data->chip->irq_set_affinity) + return -EINVAL; + + /* + * Cannot set affinity if there is more than one event + * mapped to same VINT + */ + if (bitmap_weight(vint_desc->event_map, MAX_EVENTS_PER_VINT) > 1) + return -EINVAL; + + vint_desc->affinity_managed = true; + + irq_data_update_effective_affinity(d, mask_val); + + return parent_irq_data->chip->irq_set_affinity(parent_irq_data, mask_val, force); + } + + return -EINVAL; +} +#else static int ti_sci_inta_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { return -EINVAL; } +#endif /** * ti_sci_inta_set_type() - Update the trigger type of the irq. diff -Naur --no-dereference a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c --- a/drivers/media/i2c/ds90ub960.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/i2c/ds90ub960.c 2024-07-07 20:37:34.648306569 -0400 @@ -59,6 +59,7 @@ #define UB960_MAX_RX_NPORTS 4 #define UB960_MAX_TX_NPORTS 2 #define UB960_MAX_NPORTS (UB960_MAX_RX_NPORTS + UB960_MAX_TX_NPORTS) +#define UB960_MAX_VC 4 #define UB960_MAX_PORT_ALIASES 8 @@ -408,6 +409,7 @@ u8 num_txports; bool is_ub9702; bool is_fpdlink4; + bool ignore_strobe_pos; }; enum ub960_rxport_mode { @@ -578,6 +580,24 @@ { .code = MEDIA_BUS_FMT_SGBRG12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, { .code = MEDIA_BUS_FMT_SGRBG12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, { .code = MEDIA_BUS_FMT_SRGGB12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, + + { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, .datatype = MIPI_CSI2_DT_RAW8, }, + { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, .datatype = MIPI_CSI2_DT_RAW8, }, + { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, .datatype = MIPI_CSI2_DT_RAW8, }, + { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, .datatype = MIPI_CSI2_DT_RAW8, }, + { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + + { .code = MEDIA_BUS_FMT_SRGGI10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SGRIG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SBGGI10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SGBIG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SGIRG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SIGGR10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SGIBG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SIGGB10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, }; static const struct ub960_format_info *ub960_find_format(u32 code) @@ -1413,7 +1433,7 @@ if (priv->strobe.manual) ub960_rxport_set_strobe_pos(priv, nport, rxport->eq.strobe_pos); - else + else if (!priv->hw_data->ignore_strobe_pos) ub960_rxport_set_strobe_pos(priv, nport, 0); if (rxport->eq.manual_eq) { @@ -2274,40 +2294,78 @@ */ /* - * The current implementation only supports a simple VC mapping, where all VCs - * from a one RX port will be mapped to the same VC. Also, the hardware - * dictates that all streams from an RX port must go to a single TX port. + * Map incoming streams with different virtual channels from 1-4 sensors to + * unique VCs on CSI TX0. Sensors using multiple VCs will work, but due to + * limited total channels (4) this will reduce the total number of sensors that + * can work simultaneously. * - * This function decides the target VC numbers for each RX port with a simple - * algorithm, so that for each TX port, we get VC numbers starting from 0, - * and counting up. - * - * E.g. if all four RX ports are in use, of which the first two go to the - * first TX port and the secont two go to the second TX port, we would get - * the following VCs for the four RX ports: 0, 1, 0, 1. + * The current implementation is limited to using a single CSI TX port (TX0), + * as that is the most common HW configuration found on boards with DS90UB960. + * For using both CSI TX0 & TX1 the below method will need significant changes. * * TODO: implement a more sophisticated VC mapping. As the driver cannot know * what VCs the sinks expect (say, an FPGA with hardcoded VC routing), this * probably needs to be somehow configurable. Device tree? */ -static void ub960_get_vc_maps(struct ub960_data *priv, - struct v4l2_subdev_state *state, u8 *vc) +static void ub960_get_vc_maps(struct ub960_data *priv, u8 *vc_map) { - u8 cur_vc[UB960_MAX_TX_NPORTS] = {}; - struct v4l2_subdev_route *route; - u8 handled_mask = 0; + struct device *dev = &priv->client->dev; + u8 nport, available_vc = 0; - for_each_active_route(&state->routing, route) { - unsigned int rx, tx; + for (nport = 0; + nport < priv->hw_data->num_rxports && priv->rxports[nport]; + ++nport) { + struct v4l2_mbus_frame_desc source_fd; + bool used_vc[UB960_MAX_VC] = {false}; + u8 vc, cur_vc = available_vc; + int j, ret; + u8 map; - rx = ub960_pad_to_port(priv, route->sink_pad); - if (BIT(rx) & handled_mask) + ret = v4l2_subdev_call(priv->rxports[nport]->source.sd, pad, + get_frame_desc, + priv->rxports[nport]->source.pad, + &source_fd); + /* Mark channels used in source in used_vc[] */ + if (!ret) { + for (j = 0; j < source_fd.num_entries; ++j) { + u8 source_vc = source_fd.entry[j].bus.csi2.vc; + + if (source_vc < UB960_MAX_VC) + used_vc[source_vc] = true; + } + } else if (ret == -ENOIOCTLCMD) { + /* assume VC=0 is used if sensor driver doesn't provide info */ + used_vc[0] = true; + } else { continue; + } - tx = ub960_pad_to_port(priv, route->source_pad); + /* Start with all channels mapped to first free output */ + map = (cur_vc << 6) | (cur_vc << 4) | (cur_vc << 2) | + (cur_vc << 0); + + /* Map actually used to channels to distinct free outputs */ + for (vc = 0; vc < UB960_MAX_VC; ++vc) { + if (used_vc[vc]) { + map &= ~(0x03 << (2 * vc)); + map |= (cur_vc << (2 * vc)); + ++cur_vc; + } + } + + /* Don't enable port if we ran out of available channels */ + if (cur_vc > UB960_MAX_VC) { + dev_err(dev, + "No VCs available for RX port %d\n", + nport); + continue; + } - vc[rx] = cur_vc[tx]++; - handled_mask |= BIT(rx); + /* Enable port and update map */ + vc_map[nport] = map; + available_vc = cur_vc; + dev_dbg(dev, "%s: VC map for port %d is 0x%02x", + __func__, nport, map); } } @@ -2355,51 +2413,6 @@ UB960_SR_FWD_CTL1_PORT_DIS(nport)); } -/* - * The driver only supports using a single VC for each source. This function - * checks that each source only provides streams using a single VC. - */ -static int ub960_validate_stream_vcs(struct ub960_data *priv) -{ - unsigned int nport; - unsigned int i; - - for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { - struct ub960_rxport *rxport = priv->rxports[nport]; - struct v4l2_mbus_frame_desc desc; - int ret; - u8 vc; - - if (!rxport) - continue; - - ret = v4l2_subdev_call(rxport->source.sd, pad, get_frame_desc, - rxport->source.pad, &desc); - if (ret) - return ret; - - if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) - continue; - - if (desc.num_entries == 0) - continue; - - vc = desc.entry[0].bus.csi2.vc; - - for (i = 1; i < desc.num_entries; i++) { - if (vc == desc.entry[i].bus.csi2.vc) - continue; - - dev_err(&priv->client->dev, - "rx%u: source with multiple virtual-channels is not supported\n", - nport); - return -ENODEV; - } - } - - return 0; -} - static int ub960_configure_ports_for_streaming(struct ub960_data *priv, struct v4l2_subdev_state *state) { @@ -2414,13 +2427,8 @@ u8 vc_map[UB960_MAX_RX_NPORTS] = {}; struct v4l2_subdev_route *route; unsigned int nport; - int ret; - ret = ub960_validate_stream_vcs(priv); - if (ret) - return ret; - - ub960_get_vc_maps(priv, state, vc_map); + ub960_get_vc_maps(priv, vc_map); for_each_active_route(&state->routing, route) { struct ub960_rxport *rxport; @@ -2486,7 +2494,6 @@ for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct ub960_rxport *rxport = priv->rxports[nport]; - u8 vc = vc_map[nport]; if (rx_data[nport].num_streams == 0) continue; @@ -2494,7 +2501,7 @@ switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: ub960_rxport_write(priv, nport, UB960_RR_RAW10_ID, - rx_data[nport].pixel_dt | (vc << UB960_RR_RAW10_ID_VC_SHIFT)); + rx_data[nport].pixel_dt | (nport << UB960_RR_RAW10_ID_VC_SHIFT)); ub960_rxport_write(priv, rxport->nport, UB960_RR_RAW_EMBED_DTYPE, @@ -2511,12 +2518,9 @@ case RXPORT_MODE_CSI2_SYNC: case RXPORT_MODE_CSI2_NONSYNC: if (!priv->hw_data->is_ub9702) { - /* Map all VCs from this port to the same VC */ - ub960_rxport_write(priv, nport, UB960_RR_CSI_VC_MAP, - (vc << UB960_RR_CSI_VC_MAP_SHIFT(3)) | - (vc << UB960_RR_CSI_VC_MAP_SHIFT(2)) | - (vc << UB960_RR_CSI_VC_MAP_SHIFT(1)) | - (vc << UB960_RR_CSI_VC_MAP_SHIFT(0))); + ub960_rxport_write(priv, nport, + UB960_RR_CSI_VC_MAP, + vc_map[nport]); } else { unsigned int i; @@ -2773,6 +2777,11 @@ return _ub960_set_routing(sd, state, routing); } +static inline u8 ub960_get_output_vc(u8 map, u8 input_vc) +{ + return (map >> (2 * input_vc)) & 0x03; +} + static int ub960_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_mbus_frame_desc *fd) { @@ -2792,7 +2801,7 @@ state = v4l2_subdev_lock_and_get_active_state(&priv->sd); - ub960_get_vc_maps(priv, state, vc_map); + ub960_get_vc_maps(priv, vc_map); for_each_active_route(&state->routing, route) { struct v4l2_mbus_frame_desc_entry *source_entry = NULL; @@ -2835,7 +2844,12 @@ fd->entry[fd->num_entries].length = source_entry->length; fd->entry[fd->num_entries].pixelcode = source_entry->pixelcode; - fd->entry[fd->num_entries].bus.csi2.vc = vc_map[nport]; + fd->entry[fd->num_entries].bus.csi2.vc = + ub960_get_output_vc(vc_map[nport], + source_entry->bus.csi2.vc); + dev_dbg(dev, "Mapping sink %d/%d to output VC %d", + route->sink_pad, route->sink_stream, + fd->entry[fd->num_entries].bus.csi2.vc); if (source_fd.type == V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { fd->entry[fd->num_entries].bus.csi2.dt = @@ -4013,6 +4027,13 @@ mutex_destroy(&priv->reg_lock); } +static const struct ub960_hw_data ds90ub954_hw = { + .model = "ub954", + .num_rxports = 2, + .num_txports = 1, + .ignore_strobe_pos = true, +}; + static const struct ub960_hw_data ds90ub960_hw = { .model = "ub960", .num_rxports = 4, @@ -4028,6 +4049,7 @@ }; static const struct i2c_device_id ub960_id[] = { + { "ds90ub954-q1", (kernel_ulong_t)&ds90ub954_hw }, { "ds90ub960-q1", (kernel_ulong_t)&ds90ub960_hw }, { "ds90ub9702-q1", (kernel_ulong_t)&ds90ub9702_hw }, {} @@ -4035,6 +4057,7 @@ MODULE_DEVICE_TABLE(i2c, ub960_id); static const struct of_device_id ub960_dt_ids[] = { + { .compatible = "ti,ds90ub954-q1", .data = &ds90ub954_hw }, { .compatible = "ti,ds90ub960-q1", .data = &ds90ub960_hw }, { .compatible = "ti,ds90ub9702-q1", .data = &ds90ub9702_hw }, {} diff -Naur --no-dereference a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c --- a/drivers/media/i2c/imx219.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/i2c/imx219.c 2024-07-07 20:37:34.648306569 -0400 @@ -28,6 +28,7 @@ #include #include #include +#include /* Chip ID */ #define IMX219_REG_CHIP_ID CCI_REG16(0x0000) @@ -595,6 +596,48 @@ fmt->xfer_func = V4L2_XFER_FUNC_NONE; } +static int imx219_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + u32 bpp; + int ret = 0; + + if (pad != 0) + return -EINVAL; + + memset(fd, 0, sizeof(*fd)); + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; + + state = v4l2_subdev_lock_and_get_active_state(sd); + format = v4l2_subdev_get_pad_format(sd, state, 0); + + /* pixel stream */ + + if (format->code == MEDIA_BUS_FMT_SRGGB10_1X10) + bpp = 10; + else + bpp = 8; + + fd->entry[fd->num_entries].stream = 0; + + fd->entry[fd->num_entries].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->entry[fd->num_entries].length = (format->width * format->height * bpp) / 8; + fd->entry[fd->num_entries].pixelcode = format->code; + fd->entry[fd->num_entries].bus.csi2.vc = 0; + if (format->code == MEDIA_BUS_FMT_SRGGB8_1X8) + fd->entry[fd->num_entries].bus.csi2.dt = 0x2a; /* SRGGB8 */ + else if (format->code == MEDIA_BUS_FMT_SRGGB10_1X10) + fd->entry[fd->num_entries].bus.csi2.dt = 0x2b; /* SRGGB10 */ + fd->num_entries++; + + v4l2_subdev_unlock_state(state); + + return ret; +} + static int imx219_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *state) { @@ -1043,6 +1086,7 @@ .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx219_set_pad_format, .get_selection = imx219_get_selection, + .get_frame_desc = imx219_get_frame_desc, .enum_frame_size = imx219_enum_frame_size, }; diff -Naur --no-dereference a/drivers/media/i2c/imx390.c b/drivers/media/i2c/imx390.c --- a/drivers/media/i2c/imx390.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/i2c/imx390.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,888 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sony IMX390 CMOS Image Sensor Driver + * + * Copyright (c) 2021 Apurva Nandan + * + * Copyright (c) 2021 Tomi Valkeinen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imx390.h" + +static inline struct imx390 *to_imx390(struct v4l2_subdev *sd) +{ + return container_of(sd, struct imx390, subdev); +} + +static int imx390_read(struct imx390 *imx390, u16 addr, u32 *val, size_t nbytes) +{ + int ret; + __le32 val_le = 0; + + ret = regmap_bulk_read(imx390->regmap, addr, &val_le, nbytes); + if (ret < 0) { + dev_err(imx390->dev, "%s: failed to read reg 0x%04x: %d\n", + __func__, addr, ret); + return ret; + } + + *val = le32_to_cpu(val_le); + return 0; +} + +static int imx390_write(struct imx390 *imx390, u16 addr, u32 val, size_t nbytes) +{ + int ret; + __le32 val_le = cpu_to_le32(val); + + ret = regmap_bulk_write(imx390->regmap, addr, &val_le, nbytes); + if (ret < 0) + dev_err(imx390->dev, "%s: failed to write reg 0x%04x: %d\n", + __func__, addr, ret); + return ret; +} + +static int imx390_update_bits(struct imx390 *imx390, u16 addr, u32 val, + u32 mask, size_t nbytes) +{ + int ret; + u32 cfg; + + ret = imx390_read(imx390, addr, &cfg, nbytes); + if (ret < 0) + return ret; + + cfg = (val) ? (cfg | mask) : (cfg & (~mask)); + + return imx390_write(imx390, addr, cfg, nbytes); +} + +static int imx390_write_table(struct imx390 *imx390, + const struct reg_sequence *regs, + unsigned int nr_regs) +{ + int ret; + + ret = regmap_multi_reg_write(imx390->regmap, regs, nr_regs); + if (ret < 0) + dev_err(imx390->dev, + "%s: failed to write reg table (%d)!\n", __func__, ret); + return ret; +} + +static void imx390_init_formats(struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_state_get_stream_format(state, 0, 0); + format->code = imx390_mbus_formats[0]; + format->width = imx390_framesizes[0].width; + format->height = imx390_framesizes[0].height; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SMPTE170M; +} + +static int _imx390_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route routes[] = { + { + .source_pad = 0, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + { + .source_pad = 0, + .source_stream = 1, + } + }; + + struct v4l2_subdev_krouting routing = { + .num_routes = ARRAY_SIZE(routes), + .routes = routes, + }; + + int ret; + + ret = v4l2_subdev_set_routing(sd, state, &routing); + if (ret < 0) + return ret; + + imx390_init_formats(state); + + return 0; +} + +static int imx390_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + int ret; + + ret = _imx390_set_routing(sd, state); + + return ret; +} + +static int imx390_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(imx390_mbus_formats)) + return -EINVAL; + + code->code = imx390_mbus_formats[code->index]; + + return 0; +} + +static int imx390_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(imx390_mbus_formats); ++i) { + if (imx390_mbus_formats[i] == fse->code) + break; + } + + if (i == ARRAY_SIZE(imx390_mbus_formats)) + return -EINVAL; + + if (fse->index >= ARRAY_SIZE(imx390_framesizes)) + return -EINVAL; + + fse->min_width = imx390_framesizes[fse->index].width; + fse->max_width = fse->min_width; + fse->max_height = imx390_framesizes[fse->index].height; + fse->min_height = fse->max_height; + + return 0; +} + +static int imx390_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct imx390 *imx390 = to_imx390(sd); + struct v4l2_mbus_framefmt *format; + const struct v4l2_area *fsize; + unsigned int i; + u32 code; + int ret = 0; + + if (fmt->pad != 0) + return -EINVAL; + + if (fmt->stream != 0) + return -EINVAL; + + /* + * Validate the media bus code, defaulting to the first one if the + * requested code isn't supported. + */ + for (i = 0; i < ARRAY_SIZE(imx390_mbus_formats); ++i) { + if (imx390_mbus_formats[i] == fmt->format.code) { + code = fmt->format.code; + break; + } + } + + if (i == ARRAY_SIZE(imx390_mbus_formats)) + code = imx390_mbus_formats[0]; + + /* Find the nearest supported frame size. */ + fsize = v4l2_find_nearest_size(imx390_framesizes, + ARRAY_SIZE(imx390_framesizes), width, + height, fmt->format.width, + fmt->format.height); + + v4l2_subdev_lock_state(state); + + /* Update the stored format and return it. */ + format = v4l2_subdev_state_get_stream_format(state, fmt->pad, + fmt->stream); + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && imx390->streaming) { + ret = -EBUSY; + goto done; + } + + format->code = code; + format->width = fsize->width; + format->height = fsize->height; + + fmt->format = *format; + +done: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int imx390_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *fmt; + u32 bpp; + int ret = 0; + + if (pad != 0) + return -EINVAL; + + state = v4l2_subdev_lock_and_get_active_state(sd); + + fmt = v4l2_subdev_state_get_stream_format(state, 0, 0); + if (!fmt) { + ret = -EPIPE; + goto out; + } + + memset(fd, 0, sizeof(*fd)); + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; + + /* pixel stream */ + + bpp = 12; + + fd->entry[fd->num_entries].stream = 0; + + fd->entry[fd->num_entries].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->entry[fd->num_entries].length = fmt->width * fmt->height * bpp / 8; + fd->entry[fd->num_entries].pixelcode = fmt->code; + fd->entry[fd->num_entries].bus.csi2.vc = 0; + fd->entry[fd->num_entries].bus.csi2.dt = 0x2c; /* SRGGB12 */ + + fd->num_entries++; + +out: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int imx390_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + int ret; + + if (routing->num_routes == 0 || routing->num_routes > 1) + return -EINVAL; + + ret = _imx390_set_routing(sd, state); + + return ret; +} + +static int imx390_check_non_wdr_mode_fps(struct imx390 *imx390, bool enable) +{ + if (!enable && imx390->fps > IMX390_FRAMERATE_MAX_LINEAR) { + dev_err(imx390->dev, + "%s: failed, %dFPS unsupported in non-WDR mode\n", + __func__, imx390->fps); + return -EINVAL; + } + return 0; +} + +static int imx390_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx390 *imx390 = container_of(ctrl->handler, + struct imx390, ctrl.handler); + int ret; + + dev_dbg(imx390->dev, + "%s: %s, value: %d\n", __func__, ctrl->name, ctrl->val); + + /* V4L2 controls values will be applied only when power is already up */ + if (!pm_runtime_get_if_in_use(imx390->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_WIDE_DYNAMIC_RANGE: + ret = imx390_check_non_wdr_mode_fps(imx390, ctrl->val); + break; + + case V4L2_CID_EXPOSURE: + ret = imx390_write(imx390, IMX390_REG_CAT0_SHS1, + IMX390_EXPOSURE_SHS_VAL(ctrl->val, + imx390->fps), 3); + break; + + case V4L2_CID_ANALOGUE_GAIN: + ret = imx390_write(imx390, IMX390_REG_CAT0_AGAIN_SP1H, + ctrl->val, 2); + if (ret < 0) + break; + + ret = imx390_write(imx390, IMX390_REG_CAT0_AGAIN_SP1L, + ctrl->val / IMX390_AGAIN_CONV_GAIN_RATIO, 2); + break; + + case V4L2_CID_DIGITAL_GAIN: + ret = imx390_write(imx390, IMX390_REG_CAT0_PGA_GAIN, + ctrl->val, 2); + break; + + case V4L2_CID_RED_BALANCE: + ret = imx390_write(imx390, IMX390_REG_CAT0_WBGAIN_R, + ctrl->val, 2); + break; + + case V4L2_CID_BLUE_BALANCE: + ret = imx390_write(imx390, IMX390_REG_CAT0_WBGAIN_B, + ctrl->val, 2); + break; + + case V4L2_CID_HFLIP: + ret = imx390_update_bits(imx390, IMX390_REG_CAT0_V_H_REVERSE, + ctrl->val, IMX390_H_REV_MASK, 1); + if (ret < 0) + break; + + ret = imx390_update_bits(imx390, IMX390_REG_SM_CFG_REVERSE_APL, + ctrl->val, IMX390_H_REV_APL_MASK, 1); + break; + + case V4L2_CID_VFLIP: + ret = imx390_update_bits(imx390, IMX390_REG_CAT0_V_H_REVERSE, + ctrl->val, IMX390_V_REV_MASK, 1); + if (ret < 0) + break; + + ret = imx390_update_bits(imx390, IMX390_REG_SM_CFG_REVERSE_APL, + ctrl->val, IMX390_V_REV_APL_MASK, 1); + break; + + case V4L2_CID_TEST_PATTERN: + ret = imx390_write(imx390, IMX390_REG_CAT0_PGMODE_PGREGEN, + imx390_pg_mode_reg_val[ctrl->val], 1); + if (ret < 0) + break; + + ret = imx390_update_bits(imx390, IMX390_SM_CFG_SM_PGREGEN_APL, + ctrl->val, IMX390_SM_PG_APL_MASK, 1); + break; + + default: + ret = -EINVAL; + } + + pm_runtime_put_noidle(imx390->dev); + return ret; +} + +static int imx390_detect(struct imx390 *imx390) +{ + int ret; + u32 id; + + ret = imx390_read(imx390, IMX390_REG_VERSION_ROM_VERSION, &id, 2); + if (ret < 0) + return ret; + + if (id != IMX390_ROM_VERSION) { + dev_err(imx390->dev, + "%s: unknown chip ID 0x%04x\n", __func__, id); + return -ENODEV; + } + + dev_dbg(imx390->dev, "%s: detected chip ID 0x%04x\n", __func__, id); + return 0; +} + +static int imx390_power_on(struct imx390 *imx390) +{ + int ret; + + ret = clk_prepare_enable(imx390->clk); + if (ret < 0) + return ret; + + if (imx390->xclr_gpio) { + gpiod_set_value_cansleep(imx390->xclr_gpio, 1); + /* Keep the XCLR pin on Low for 100 us or longer */ + usleep_range(100, 1000); + gpiod_set_value_cansleep(imx390->xclr_gpio, 0); + /* It takes max 30 ms for the sensor to be ready */ + msleep(30); + } + return 0; +} + +static void imx390_power_off(struct imx390 *imx390) +{ + if (imx390->xclr_gpio) { + gpiod_set_value_cansleep(imx390->xclr_gpio, 1); + /* Wait for the XCLR pin to be Low for at least 1 us */ + usleep_range(1, 10); + } + + clk_disable_unprepare(imx390->clk); +} + +static int imx390_get_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct imx390 *imx390 = to_imx390(sd); + + fi->interval.numerator = 1; + fi->interval.denominator = imx390->fps; + return 0; +} + +static int imx390_set_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct imx390 *imx390 = to_imx390(sd); + struct v4l2_ctrl *ctrl = imx390->ctrl.exposure; + u32 req_fps; + int ret; + + mutex_lock(&imx390->lock); + + if (fi->interval.numerator == 0 || fi->interval.denominator == 0) { + fi->interval.denominator = IMX390_FRAMERATE_DEFAULT; + fi->interval.numerator = 1; + } + + req_fps = clamp_val(DIV_ROUND_CLOSEST(fi->interval.denominator, + fi->interval.numerator), + IMX390_FRAMERATE_MIN, IMX390_FRAMERATE_MAX); + + fi->interval.numerator = 1; + fi->interval.denominator = req_fps; + + imx390->fps = req_fps; + + ret = __v4l2_ctrl_modify_range(ctrl, 0, IMX390_EXPOSURE_MAX(req_fps), 1, + IMX390_EXPOSURE_DEFAULT); + if (ret < 0) { + dev_err(imx390->dev, + "%s: exposure ctrl range update failed %d\n", + __func__, ret); + } + + mutex_unlock(&imx390->lock); + dev_dbg(imx390->dev, "%s frame rate = %d\n", __func__, imx390->fps); + + return ret; +} + +static int imx390_start_stream(struct imx390 *imx390) +{ + int ret; + + if (!imx390->ctrl.wdr->val && + imx390->fps <= IMX390_FRAMERATE_MAX_LINEAR) + ret = imx390_write_table(imx390, imx390_linear_1936x1096, + ARRAY_SIZE(imx390_linear_1936x1096)); + else + ret = imx390_write_table(imx390, imx390_wdr_1936x1096, + ARRAY_SIZE(imx390_wdr_1936x1096)); + if (ret < 0) + return ret; + + msleep(100); + + /* Restore the V4L2 control values into the registers */ + ret = __v4l2_ctrl_handler_setup(imx390->subdev.ctrl_handler); + if (ret < 0) { + dev_err(imx390->dev, + "%s: failed to apply v4l2 ctrls: %d\n", __func__, ret); + return ret; + } + + ret = imx390_write(imx390, IMX390_REG_MODE_HMAX, + (u32)IMX390_FPS_TO_MODE_HMAX(imx390->fps), 2); + if (ret < 0) + return ret; + + /* Set active */ + ret = imx390_write(imx390, IMX390_REG_CAT0_STANDBY, 0, 1); + if (ret < 0) + return ret; + + /* No communication is possible for a while after exiting standby */ + msleep(20); + + return 0; +} + +static int imx390_stop_stream(struct imx390 *imx390) +{ + int ret; + + /* Set standby */ + ret = imx390_write(imx390, IMX390_REG_CAT0_STANDBY, 1, 1); + if (ret < 0) + return ret; + + /* No communication is possible for a while after entering standby */ + usleep_range(10000, 20000); + return 0; +} + +static int imx390_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx390 *imx390 = to_imx390(sd); + int ret; + + mutex_lock(&imx390->lock); + if (imx390->streaming == enable) { + mutex_unlock(&imx390->lock); + return 0; + } + + if (enable) { + ret = pm_runtime_get_sync(imx390->dev); + if (ret < 0) { + pm_runtime_put_noidle(imx390->dev); + goto err_unlock; + } + + ret = imx390_start_stream(imx390); + if (ret < 0) + goto err_runtime_put; + } else { + ret = imx390_stop_stream(imx390); + if (ret < 0) + goto err_runtime_put; + pm_runtime_mark_last_busy(imx390->dev); + pm_runtime_put_autosuspend(imx390->dev); + } + + imx390->streaming = enable; + /* WDR, HFLIP, VFLIP, TEST PATTERN cannot change during streaming */ + __v4l2_ctrl_grab(imx390->ctrl.wdr, enable); + __v4l2_ctrl_grab(imx390->ctrl.h_flip, enable); + __v4l2_ctrl_grab(imx390->ctrl.v_flip, enable); + __v4l2_ctrl_grab(imx390->ctrl.pg_mode, enable); + + mutex_unlock(&imx390->lock); + return 0; + +err_runtime_put: + pm_runtime_put(imx390->dev); + +err_unlock: + mutex_unlock(&imx390->lock); + dev_err(imx390->dev, + "%s: failed to setup streaming %d\n", __func__, ret); + return ret; +} + +static const struct v4l2_subdev_video_ops imx390_subdev_video_ops = { + .g_frame_interval = imx390_get_frame_interval, + .s_frame_interval = imx390_set_frame_interval, + .s_stream = imx390_set_stream, +}; + +static const struct v4l2_subdev_pad_ops imx390_subdev_pad_ops = { + .init_cfg = imx390_init_cfg, + .enum_mbus_code = imx390_enum_mbus_code, + .enum_frame_size = imx390_enum_frame_sizes, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = imx390_set_fmt, + .set_routing = imx390_set_routing, + .get_frame_desc = imx390_get_frame_desc, +}; + +static const struct v4l2_subdev_ops imx390_subdev_ops = { + .video = &imx390_subdev_video_ops, + .pad = &imx390_subdev_pad_ops, +}; + +static const struct v4l2_ctrl_ops imx390_ctrl_ops = { + .s_ctrl = imx390_set_ctrl, +}; + +static int imx390_probe(struct i2c_client *client) +{ + struct imx390 *imx390; + struct v4l2_subdev *sd; + struct v4l2_ctrl_handler *ctrl_hdr; + int ret; + + imx390 = devm_kzalloc(&client->dev, sizeof(*imx390), GFP_KERNEL); + if (!imx390) + return -ENOMEM; + + imx390->dev = &client->dev; + + imx390->regmap = devm_regmap_init_i2c(client, &imx390_regmap_config); + if (IS_ERR(imx390->regmap)) + return PTR_ERR(imx390->regmap); + + imx390->xclr_gpio = devm_gpiod_get_optional(imx390->dev, + "xclr", GPIOD_OUT_LOW); + if (IS_ERR(imx390->xclr_gpio)) + return PTR_ERR(imx390->xclr_gpio); + + imx390->clk = devm_clk_get(imx390->dev, "inck"); + if (IS_ERR(imx390->clk)) + return PTR_ERR(imx390->clk); + + imx390->clk_rate = clk_get_rate(imx390->clk); + dev_info(imx390->dev, "inck rate: %lu Hz\n", imx390->clk_rate); + + if (imx390->clk_rate < 5900000 || imx390->clk_rate > 27100000) + return -EINVAL; + + ret = imx390_power_on(imx390); + if (ret < 0) + return ret; + + ret = imx390_detect(imx390); + if (ret < 0) + return ret; + + /* Initialize the subdev and its controls. */ + sd = &imx390->subdev; + v4l2_i2c_subdev_init(sd, client, &imx390_subdev_ops); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS | + V4L2_SUBDEV_FL_STREAMS; + + /* Initialize the media entity. */ + imx390->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &imx390->pad); + if (ret < 0) { + dev_err(imx390->dev, + "%s: media entity init failed %d\n", __func__, ret); + return ret; + } + + /* Initialize controls */ + ctrl_hdr = &imx390->ctrl.handler; + ret = v4l2_ctrl_handler_init(ctrl_hdr, 9); + if (ret < 0) { + dev_err(imx390->dev, + "%s: ctrl handler init failed: %d\n", __func__, ret); + goto err_media_cleanup; + } + + mutex_init(&imx390->lock); + imx390->ctrl.handler.lock = &imx390->lock; + imx390->fps = IMX390_FRAMERATE_DEFAULT; + + /* Add new controls */ + imx390->ctrl.exposure = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops, + V4L2_CID_EXPOSURE, 0, + IMX390_EXPOSURE_MAX(imx390->fps), + 1, IMX390_EXPOSURE_DEFAULT); + + imx390->ctrl.again = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 0, + IMX390_ANALOG_GAIN_MAX, 1, + IMX390_ANALOG_GAIN_DEFAULT); + + imx390->ctrl.dgain = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops, + V4L2_CID_DIGITAL_GAIN, 0, + IMX390_DIGITAL_GAIN_MAX, 1, + IMX390_DIGITAL_GAIN_DEFAULT); + + imx390->ctrl.r_balance = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, + IMX390_R_B_BALANCE_MAX, 1, + IMX390_R_B_BALANCE_DEFAULT); + + imx390->ctrl.b_balance = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, + IMX390_R_B_BALANCE_MAX, 1, + IMX390_R_B_BALANCE_DEFAULT); + + imx390->ctrl.wdr = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops, + V4L2_CID_WIDE_DYNAMIC_RANGE, + 0, 1, 1, 1); + + imx390->ctrl.h_flip = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + imx390->ctrl.v_flip = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + imx390->ctrl.pg_mode = + v4l2_ctrl_new_std_menu_items(ctrl_hdr, &imx390_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx390_ctrl_pg_qmenu) - 1, + 0, 0, imx390_ctrl_pg_qmenu); + + imx390->subdev.ctrl_handler = ctrl_hdr; + if (imx390->ctrl.handler.error) { + ret = imx390->ctrl.handler.error; + dev_err(imx390->dev, + "%s: failed to add the ctrls: %d\n", __func__, ret); + goto err_ctrl_free; + } + + pm_runtime_set_active(imx390->dev); + pm_runtime_enable(imx390->dev); + pm_runtime_set_autosuspend_delay(imx390->dev, IMX390_PM_IDLE_TIMEOUT); + pm_runtime_use_autosuspend(imx390->dev); + pm_runtime_get_noresume(imx390->dev); + + ret = v4l2_subdev_init_finalize(sd); + if (ret < 0) + goto err_pm_disable; + + /* Finally, register the subdev. */ + ret = v4l2_async_register_subdev(sd); + if (ret < 0) { + dev_err(imx390->dev, + "%s: v4l2 subdev register failed %d\n", __func__, ret); + goto err_subdev_cleanup; + } + + dev_info(imx390->dev, "imx390 probed\n"); + pm_runtime_mark_last_busy(imx390->dev); + pm_runtime_put_autosuspend(imx390->dev); + return 0; + +err_subdev_cleanup: + v4l2_subdev_cleanup(&imx390->subdev); + +err_pm_disable: + pm_runtime_dont_use_autosuspend(imx390->dev); + pm_runtime_put_noidle(imx390->dev); + pm_runtime_disable(imx390->dev); + +err_ctrl_free: + v4l2_ctrl_handler_free(ctrl_hdr); + mutex_destroy(&imx390->lock); + +err_media_cleanup: + media_entity_cleanup(&imx390->subdev.entity); + + return ret; +} + +static int __maybe_unused imx390_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx390 *imx390 = to_imx390(sd); + int ret; + + ret = imx390_power_on(imx390); + if (ret < 0) + return ret; + + return 0; +} + +static int __maybe_unused imx390_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx390 *imx390 = to_imx390(sd); + + imx390_power_off(imx390); + + return 0; +} + +static int __maybe_unused imx390_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx390 *imx390 = to_imx390(sd); + int ret; + + if (imx390->streaming) + imx390_stop_stream(imx390); + + ret = pm_runtime_force_suspend(dev); + if (ret < 0) + dev_warn(dev, "%s: failed to suspend: %i\n", __func__, ret); + + return 0; +} + +static int __maybe_unused imx390_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx390 *imx390 = to_imx390(sd); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret < 0) + dev_warn(dev, "%s: failed to resume: %i\n", __func__, ret); + + if (imx390->streaming) + ret = imx390_start_stream(imx390); + + if (ret < 0) { + imx390_stop_stream(imx390); + imx390->streaming = 0; + return ret; + } + + return 0; +} + +static void imx390_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx390 *imx390 = to_imx390(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_ctrl_handler_free(&imx390->ctrl.handler); + v4l2_subdev_cleanup(&imx390->subdev); + media_entity_cleanup(&sd->entity); + mutex_destroy(&imx390->lock); + + pm_runtime_disable(imx390->dev); + pm_runtime_dont_use_autosuspend(imx390->dev); + pm_runtime_set_suspended(imx390->dev); +} + +static const struct dev_pm_ops imx390_pm_ops = { + SET_RUNTIME_PM_OPS(imx390_runtime_suspend, + imx390_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(imx390_suspend, imx390_resume) +}; + +static const struct of_device_id imx390_dt_id[] = { + { .compatible = "sony,imx390" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, imx390_dt_id); + +static struct i2c_driver imx390_i2c_driver = { + .driver = { + .name = "imx390", + .of_match_table = of_match_ptr(imx390_dt_id), + .pm = &imx390_pm_ops, + }, + .probe = imx390_probe, + .remove = imx390_remove, +}; + +module_i2c_driver(imx390_i2c_driver); + +MODULE_DESCRIPTION("Camera Sensor Driver for Sony IMX390"); +MODULE_AUTHOR("Apurva Nandan "); +MODULE_AUTHOR("Tomi Valkeinen "); +MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/drivers/media/i2c/imx390.h b/drivers/media/i2c/imx390.h --- a/drivers/media/i2c/imx390.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/i2c/imx390.h 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,7158 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Sony IMX390 CMOS Image Sensor Driver + * + * Copyright (c) 2021 Apurva Nandan + * + * Copyright (c) 2021 Tomi Valkeinen + */ + +#include + +#define IMX390_ACTIVE_AREA_WIDTH 1936 +#define IMX390_ACTIVE_AREA_HEIGHT 1096 + +/* SMPG cannot be disabled, and datatype is the same as the pixel data */ +#define IMX390_SMPG_HEIGHT 4 + +#define IMX390_OUT_WIDTH IMX390_ACTIVE_AREA_WIDTH +#define IMX390_OUT_HEIGHT (IMX390_ACTIVE_AREA_HEIGHT + IMX390_SMPG_HEIGHT) + +#define IMX390_FRAMERATE_DEFAULT 30 +#define IMX390_FRAMERATE_MIN 25 +#define IMX390_FRAMERATE_MAX 60 +#define IMX390_FRAMERATE_MAX_LINEAR 30 + +#define IMX390_MODE_VMAX 0x465 +#define IMX390_MODE_HMAX_DEFAULT 0x1130 +#define IMX390_REG_MODE_HMAX 0x200C +#define IMX390_FPS_TO_MODE_HMAX(_fps) \ + ((IMX390_MODE_HMAX_DEFAULT * IMX390_FRAMERATE_DEFAULT) / (_fps)) + +#define IMX390_REG_VERSION_ROM_VERSION 0x0330 +#define IMX390_ROM_VERSION 0x3815 + +#define IMX390_REG_CAT0_STANDBY 0x0000 + +/* Exposure control */ +#define IMX390_REG_CAT0_SHS1 0x000C +#define IMX390_EXPOSURE_LINES_MAX (IMX390_MODE_VMAX - 2) +#define IMX390_EXPOSURE_MAX(_fps) \ + ((IMX390_EXPOSURE_LINES_MAX * 1000000) / (IMX390_MODE_VMAX * (_fps))) + +#define IMX390_EXPOSURE_SHS_VAL(_exp, _fps) \ + (IMX390_MODE_VMAX - ((_exp) * (_fps) * IMX390_MODE_VMAX) / 1000000) + +#define IMX390_EXPOSURE_DEFAULT 11111 + +/* Analog gain control */ +#define IMX390_REG_CAT0_AGAIN_SP1H 0x0018 +#define IMX390_REG_CAT0_AGAIN_SP1L 0x001A +#define IMX390_ANALOG_GAIN_MAX 0x3FF +#define IMX390_ANALOG_GAIN_DEFAULT 0x20 +#define IMX390_AGAIN_CONV_GAIN_RATIO 4 + +/* Digital gain control */ +#define IMX390_REG_CAT0_PGA_GAIN 0x0024 +#define IMX390_DIGITAL_GAIN_MAX 0x1FF +#define IMX390_DIGITAL_GAIN_DEFAULT 0x20 + +/* White Balance control */ +#define IMX390_REG_CAT0_WBGAIN_R 0x0030 +#define IMX390_REG_CAT0_WBGAIN_B 0x0036 +#define IMX390_R_B_BALANCE_MAX 0xFFF +#define IMX390_R_B_BALANCE_DEFAULT 0x200 + +/* Vertical and Horizontal Flip control */ +#define IMX390_REG_CAT0_V_H_REVERSE 0x0074 +#define IMX390_V_REV_MASK BIT(0) +#define IMX390_H_REV_MASK BIT(1) +#define IMX390_REG_SM_CFG_REVERSE_APL 0x03C0 +#define IMX390_V_REV_APL_MASK BIT(2) +#define IMX390_H_REV_APL_MASK BIT(3) + +/* Test Pattern control */ +#define IMX390_REG_CAT0_PGMODE_PGREGEN 0x01DB +#define IMX390_SM_CFG_SM_PGREGEN_APL 0x03C0 +#define IMX390_SM_PG_APL_MASK BIT(1) + +#define IMX390_PM_IDLE_TIMEOUT 1000 + +struct imx390_ctrl { + struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *wdr; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *again; + struct v4l2_ctrl *dgain; + struct v4l2_ctrl *r_balance; + struct v4l2_ctrl *b_balance; + struct v4l2_ctrl *h_flip; + struct v4l2_ctrl *v_flip; + struct v4l2_ctrl *pg_mode; +}; + +/* + * struct im390 - imx390 device structure + * @dev: Device handle + * @clk: Pointer to imx390 clock + * @client: Pointer to I2C client + * @regmap: Pointer to regmap structure + * @xclr_gpio: Pointer to XCLR gpio + * @subddev: V4L2 subdevice structure + * @format: V4L2 media bus frame format structure + * (width and height are in sync with the compose rect) + * @pad: Media pad structure + * @ctrl: imx390 control structure + * @frame_interval: Time period of one frame in seconds + * @clk_rate: Frequency of imx390 clock + * @lock: Mutex structure for V4L2 ctrl handler + * @streaming: Flag to store the streaming on/off status + */ +struct imx390 { + struct device *dev; + + struct clk *clk; + struct i2c_client *client; + struct regmap *regmap; + struct gpio_desc *xclr_gpio; + + struct v4l2_subdev subdev; + struct v4l2_mbus_framefmt format; + struct media_pad pad; + + struct imx390_ctrl ctrl; + + unsigned long clk_rate; + u32 fps; + + /* mutex for V4L2 ctrl handler */ + struct mutex lock; + bool streaming; +}; + +static const struct v4l2_area imx390_framesizes[] = { + { + .width = IMX390_OUT_WIDTH, + .height = IMX390_OUT_HEIGHT, + }, +}; + +static const u32 imx390_mbus_formats[] = { + MEDIA_BUS_FMT_SRGGB12_1X12, +}; + +static const struct regmap_config imx390_regmap_config = { + .reg_bits = 16, + .val_bits = 8, +}; + +static const u32 imx390_pg_mode_reg_val[] = { + 0x00, + 0x32, + 0x33, + 0x35, + 0x3D, +}; + +static const char *const imx390_ctrl_pg_qmenu[] = { + "Disabled", + "Horizontal Color Bars", + "Vertical Color Bars", + "Gradation", + "Checker Pattern", +}; + +static const struct reg_sequence imx390_wdr_1936x1096[] = { + { 0x000C, 0x7F }, + { 0x000D, 0x01 }, + { 0x000E, 0x00 }, + { 0x0010, 0x7F }, + { 0x0011, 0x01 }, + { 0x0012, 0x00 }, + { 0x0018, 0x20 }, + { 0x0019, 0x00 }, + { 0x001A, 0x0C }, + { 0x001B, 0x00 }, + { 0x0038, 0x00 }, + { 0x003C, 0x00 }, + { 0x003D, 0x00 }, + { 0x003E, 0x00 }, + { 0x0040, 0x00 }, + { 0x0041, 0x00 }, + { 0x0042, 0x00 }, + { 0x0044, 0x00 }, + { 0x0045, 0x00 }, + { 0x0046, 0x00 }, + { 0x0048, 0x00 }, + { 0x0049, 0x00 }, + { 0x004A, 0x00 }, + { 0x004C, 0x00 }, + { 0x004D, 0x00 }, + { 0x004E, 0x00 }, + { 0x0050, 0x00 }, + { 0x0051, 0x00 }, + { 0x0052, 0x00 }, + { 0x0054, 0x00 }, + { 0x0055, 0x00 }, + { 0x0056, 0x00 }, + { 0x0058, 0x00 }, + { 0x0059, 0x00 }, + { 0x005A, 0x00 }, + { 0x005C, 0x00 }, + { 0x005D, 0x00 }, + { 0x005E, 0x00 }, + { 0x0060, 0x00 }, + { 0x0061, 0x00 }, + { 0x0062, 0x00 }, + { 0x0064, 0x00 }, + { 0x0065, 0x00 }, + { 0x0066, 0x00 }, + { 0x0068, 0x00 }, + { 0x0069, 0x00 }, + { 0x006A, 0x00 }, + { 0x0078, 0x01 }, + { 0x007C, 0x08 }, + { 0x007D, 0x00 }, + { 0x0080, 0x08 }, + { 0x0081, 0x00 }, + { 0x0090, 0x00 }, + { 0x00F4, 0x1C }, + { 0x00F5, 0xF8 }, + { 0x00F6, 0x01 }, + { 0x00F8, 0x03 }, + { 0x00F9, 0x01 }, + { 0x00FA, 0x00 }, + { 0x00FB, 0x02 }, + { 0x0114, 0x00 }, + { 0x0115, 0x01 }, + { 0x0118, 0x20 }, + { 0x0119, 0x03 }, + { 0x011A, 0x00 }, + { 0x011B, 0x41 }, + { 0x011C, 0x80 }, + { 0x011D, 0x00 }, + { 0x0120, 0x20 }, + { 0x0121, 0x00 }, + { 0x0122, 0x00 }, + { 0x0123, 0x44 }, + { 0x0124, 0x00 }, + { 0x0125, 0x01 }, + { 0x0128, 0xAC }, + { 0x0129, 0x0D }, + { 0x012A, 0x00 }, + { 0x012B, 0xA4 }, + { 0x012C, 0x00 }, + { 0x012D, 0x01 }, + { 0x0130, 0xC4 }, + { 0x0131, 0x09 }, + { 0x0132, 0x00 }, + { 0x0133, 0xDA }, + { 0x0138, 0x00 }, /* DB_CMN_POST_PEDESTAL (0x0138: 0x0139) = 0 */ + { 0x0139, 0x00 }, /* DB_CMN_POST_PEDESTAL (0x0138: 0x0139) = 0 */ + { 0x013A, 0x00 }, + { 0x013B, 0x00 }, + { 0x013C, 0x00 }, + { 0x013D, 0x00 }, + { 0x013E, 0x00 }, + { 0x0140, 0x00 }, + { 0x0141, 0x00 }, + { 0x0142, 0x00 }, + /* Start of PWL Registers */ + { 0x0144, 0x00 }, /* pwl_cp1_x 2048 */ + { 0x0145, 0x08 }, /* pwl_cp1_x 2048 */ + { 0x0146, 0x00 }, /* pwl_cp1_x 2048 */ + { 0x0147, 0x00 }, /* pwl_cp1_x 2048 */ + { 0x0148, 0x00 }, /* pwl_cp1_y 51 */ + { 0x0149, 0x02 }, /* pwl_cp1_y 51 */ + { 0x014A, 0x00 }, /* pwl_cp1_y 51 */ + { 0x014B, 0x00 }, /* pwl_cp1_y 51 */ + { 0x014C, 0x00 }, /* pwl_cp2_x 1638 */ + { 0x014D, 0x40 }, /* pwl_cp2_x 1638 */ + { 0x014E, 0x00 }, /* pwl_cp2_x 1638 */ + { 0x014F, 0x00 }, /* pwl_cp2_x 1638 */ + { 0x0150, 0x80 }, /* pwl_cp2_y 1408 */ + { 0x0151, 0x05 }, /* pwl_cp2_y 1408 */ + { 0x0152, 0x00 }, /* pwl_cp2_y 1408 */ + { 0x0153, 0x00 }, /* pwl_cp2_y 1408 */ + { 0x0154, 0x00 }, /* pwl_cp3_x 6553 */ + { 0x0155, 0x00 }, /* pwl_cp3_x 6553 */ + { 0x0156, 0x01 }, /* pwl_cp3_x 6553 */ + { 0x0157, 0x00 }, /* pwl_cp3_x 6553 */ + { 0x0158, 0x80 }, /* pwl_cp3_y 2176 */ + { 0x0159, 0x08 }, /* pwl_cp3_y 2176 */ + { 0x015A, 0x00 }, /* pwl_cp3_y 2176 */ + { 0x015B, 0x00 }, /* pwl_cp3_y 2176 */ + { 0x015C, 0x00 }, /* pwl_cp4_x 0x100000 */ + { 0x015D, 0x00 }, /* pwl_cp4_x 0x100000 */ + { 0x015E, 0x10 }, /* pwl_cp4_x 0x100000 */ + { 0x015F, 0x00 }, /* pwl_cp4_x 0x100000 */ + { 0x0160, 0x00 }, /* pwl_cp4_y 0x1000 */ + { 0x0161, 0x10 }, /* pwl_cp4_y 0x1000 */ + { 0x0162, 0x00 }, /* pwl_cp4_y 0x1000 */ + { 0x0163, 0x00 }, /* pwl_cp4_y 0x1000 */ + { 0x0164, 0x00 }, /* pwl_cp5_x 0x100000 */ + { 0x0165, 0x00 }, /* pwl_cp5_x 0x100000 */ + { 0x0166, 0x10 }, /* pwl_cp5_x 0x100000 */ + { 0x0167, 0x00 }, /* pwl_cp5_x 0x100000 */ + { 0x0168, 0x00 }, /* pwl_cp5_y 0x1000 */ + { 0x0169, 0x10 }, /* pwl_cp5_y 0x1000 */ + { 0x016A, 0x00 }, /* pwl_cp5_y 0x1000 */ + { 0x016B, 0x00 }, /* pwl_cp5_y 0x1000 */ + { 0x016C, 0x00 }, /* pwl_cp6_x 0x100000 */ + { 0x016D, 0x00 }, /* pwl_cp6_x 0x100000 */ + { 0x016E, 0x10 }, /* pwl_cp6_x 0x100000 */ + { 0x016F, 0x00 }, /* pwl_cp6_x 0x100000 */ + { 0x0170, 0x00 }, /* pwl_cp6_y 0x1000 */ + { 0x0171, 0x10 }, /* pwl_cp6_y 0x1000 */ + { 0x0172, 0x00 }, /* pwl_cp6_y 0x1000 */ + { 0x0173, 0x00 }, /* pwl_cp6_y 0x1000 */ + { 0x0174, 0x00 }, /* pwl_cp7_x 0x100000 */ + { 0x0175, 0x00 }, /* pwl_cp7_x 0x100000 */ + { 0x0176, 0x10 }, /* pwl_cp7_x 0x100000 */ + { 0x0177, 0x00 }, /* pwl_cp7_x 0x100000 */ + { 0x0178, 0x00 }, /* pwl_cp7_y 0x1000 */ + { 0x0179, 0x10 }, /* pwl_cp7_y 0x1000 */ + { 0x017A, 0x00 }, /* pwl_cp7_y 0x1000 */ + { 0x017B, 0x00 }, /* pwl_cp7_y 0x1000 */ + { 0x017C, 0x00 }, /* pwl_cp8_x 0x100000 */ + { 0x017D, 0x00 }, /* pwl_cp8_x 0x100000 */ + { 0x017E, 0x10 }, /* pwl_cp8_x 0x100000 */ + { 0x017F, 0x00 }, /* pwl_cp8_x 0x100000 */ + { 0x0180, 0x00 }, /* pwl_cp8_y 0x1000 */ + { 0x0181, 0x10 }, /* pwl_cp8_y 0x1000 */ + { 0x0182, 0x00 }, /* pwl_cp8_y 0x1000 */ + { 0x0183, 0x00 }, /* pwl_cp8_y 0x1000 */ + { 0x0184, 0x00 }, /* pwl_cp9_x 0x100000 */ + { 0x0185, 0x00 }, /* pwl_cp9_x 0x100000 */ + { 0x0186, 0x10 }, /* pwl_cp9_x 0x100000 */ + { 0x0187, 0x00 }, /* pwl_cp9_x 0x100000 */ + { 0x0188, 0x00 }, /* pwl_cp9_y 0x1000 */ + { 0x0189, 0x10 }, /* pwl_cp9_y 0x1000 */ + { 0x018A, 0x00 }, /* pwl_cp9_y 0x1000 */ + { 0x018B, 0x00 }, /* pwl_cp9_y 0x1000 */ + { 0x018C, 0x00 }, /* pwl_cp10_x 0x10000 */ + { 0x018D, 0x00 }, /* pwl_cp10_x 0x10000 */ + { 0x018E, 0x10 }, /* pwl_cp10_x 0x10000 */ + { 0x018F, 0x00 }, /* pwl_cp10_x 0x10000 */ + { 0x0190, 0x00 }, /* pwl_cp10_y 0x100 */ + { 0x0191, 0x10 }, /* pwl_cp10_y 0x100 */ + { 0x0192, 0x00 }, /* pwl_cp10_y 0x100 */ + { 0x0193, 0x00 }, /* pwl_cp10_y 0x100 */ + { 0x0198, 0x00 }, /* pwl gain0 0x040 0000 */ + { 0x0199, 0x00 }, + { 0x019A, 0x40 }, + { 0x019B, 0x00 }, + { 0x019C, 0x00 }, /* pwl gain1 0x010 0000 */ + { 0x019D, 0x00 }, + { 0x019E, 0x10 }, + { 0x019F, 0x00 }, + { 0x01A0, 0x00 }, /* pwl gain2 0x004 0000 */ + { 0x01A1, 0x00 }, + { 0x01A2, 0x04 }, + { 0x01A3, 0x00 }, + { 0x01A4, 0x00 }, /* pwl gain3 0x000 8000 */ + { 0x01A5, 0x80 }, + { 0x01A6, 0x00 }, + { 0x01A7, 0x00 }, + { 0x01A8, 0x00 }, + { 0x01A9, 0x00 }, + { 0x01AA, 0x00 }, + { 0x01AB, 0x00 }, + /* End of PWL Registers*/ + { 0x01AC, 0x00 }, + { 0x01AD, 0x00 }, + { 0x01AE, 0x00 }, + { 0x01AF, 0x00 }, + { 0x01B0, 0x00 }, + { 0x01B1, 0x00 }, + { 0x01B2, 0x00 }, + { 0x01B3, 0x00 }, + { 0x01B4, 0x00 }, + { 0x01B5, 0x00 }, + { 0x01B6, 0x00 }, + { 0x01B7, 0x00 }, + { 0x01B8, 0x00 }, + { 0x01B9, 0x00 }, + { 0x01BA, 0x00 }, + { 0x01BB, 0x00 }, + { 0x01BC, 0x00 }, + { 0x01BD, 0x00 }, + { 0x01BE, 0x00 }, + { 0x01BF, 0x00 }, + { 0x01C0, 0x00 }, + { 0x01C1, 0x00 }, + { 0x01C2, 0x00 }, + { 0x01C3, 0x00 }, + { 0x01C4, 0x00 }, + { 0x01C5, 0x00 }, + { 0x01CC, 0x01 }, + { 0x01D0, 0x09 }, + { 0x01D4, 0x01 }, + { 0x0332, 0x67 }, + { 0x0333, 0x02 }, + { 0x0390, 0x00 }, + { 0x0391, 0x00 }, + { 0x0392, 0x00 }, + { 0x03C0, 0x01 }, + { 0x2000, 0x55 }, + { 0x2001, 0x55 }, + { 0x2002, 0x55 }, + { 0x2003, 0x05 }, + { 0x2004, 0x02 }, + { 0x2008, 0x65 }, + { 0x2009, 0x04 }, + { 0x200A, 0x00 }, + { 0x200C, 0x98 }, + { 0x200D, 0x08 }, + { 0x2010, 0x04 }, + { 0x2014, 0x00 }, + { 0x2018, 0x02 }, + { 0x2019, 0x04 }, + { 0x201A, 0x00 }, + { 0x201C, 0x21 }, + { 0x201D, 0x11 }, + { 0x201E, 0x00 }, + { 0x201F, 0x00 }, + { 0x2020, 0xBC }, + { 0x2021, 0x00 }, + { 0x2022, 0x7F }, + { 0x2023, 0x00 }, + { 0x2024, 0xBA }, + { 0x2025, 0x00 }, + { 0x2026, 0x81 }, + { 0x2027, 0x00 }, + { 0x2028, 0x7D }, + { 0x2029, 0x90 }, + { 0x202A, 0x05 }, + { 0x202C, 0xFC }, + { 0x202D, 0x02 }, + { 0x202E, 0x25 }, + { 0x202F, 0x03 }, + { 0x2030, 0x05 }, + { 0x2031, 0x02 }, + { 0x2032, 0xCA }, + { 0x2033, 0x02 }, + { 0x2034, 0xFC }, + { 0x2035, 0x02 }, + { 0x2036, 0x25 }, + { 0x2037, 0x03 }, + { 0x2038, 0xF8 }, + { 0x2039, 0xE4 }, + { 0x203A, 0xE3 }, + { 0x203B, 0x01 }, + { 0x203C, 0xF5 }, + { 0x203D, 0x8E }, + { 0x203E, 0x0C }, + { 0x203F, 0x2D }, + { 0x2040, 0x69 }, + { 0x2041, 0x01 }, + { 0x2042, 0x8E }, + { 0x2043, 0x01 }, + { 0x2044, 0x0C }, + { 0x2045, 0x02 }, + { 0x2046, 0x31 }, + { 0x2047, 0x02 }, + { 0x2048, 0x6A }, + { 0x2049, 0x01 }, + { 0x204A, 0x8E }, + { 0x204B, 0x01 }, + { 0x204C, 0x0D }, + { 0x204D, 0x02 }, + { 0x204E, 0x31 }, + { 0x204F, 0x02 }, + { 0x2050, 0x7B }, + { 0x2051, 0x00 }, + { 0x2052, 0x7D }, + { 0x2053, 0x00 }, + { 0x2054, 0x95 }, + { 0x2055, 0x00 }, + { 0x2056, 0x97 }, + { 0x2057, 0x00 }, + { 0x2058, 0xAD }, + { 0x2059, 0x00 }, + { 0x205A, 0xAF }, + { 0x205B, 0x00 }, + { 0x205C, 0x92 }, + { 0x205D, 0x00 }, + { 0x205E, 0x94 }, + { 0x205F, 0x00 }, + { 0x2060, 0x8E }, + { 0x2061, 0x00 }, + { 0x2062, 0x90 }, + { 0x2063, 0x00 }, + { 0x2064, 0xB1 }, + { 0x2065, 0x00 }, + { 0x2066, 0xB3 }, + { 0x2067, 0x00 }, + { 0x2068, 0x08 }, + { 0x2069, 0x00 }, + { 0x206A, 0x04 }, + { 0x206B, 0x00 }, + { 0x206C, 0x84 }, + { 0x206D, 0x00 }, + { 0x206E, 0x80 }, + { 0x206F, 0x00 }, + { 0x2070, 0x04 }, + { 0x2071, 0x00 }, + { 0x2072, 0x46 }, + { 0x2073, 0x00 }, + { 0x2074, 0xE9 }, + { 0x2075, 0x01 }, + { 0x2076, 0x74 }, + { 0x2077, 0x02 }, + { 0x2078, 0x80 }, + { 0x2079, 0x00 }, + { 0x207A, 0xC1 }, + { 0x207B, 0x00 }, + { 0x207C, 0xFF }, + { 0x207D, 0x03 }, + { 0x207E, 0xFF }, + { 0x207F, 0x03 }, + { 0x2080, 0x78 }, + { 0x2081, 0x00 }, + { 0x2082, 0x6A }, + { 0x2083, 0x01 }, + { 0x2084, 0xE4 }, + { 0x2085, 0x01 }, + { 0x2086, 0x2B }, + { 0x2087, 0x03 }, + { 0x2088, 0x00 }, + { 0x2089, 0x00 }, + { 0x208A, 0xFF }, + { 0x208B, 0x03 }, + { 0x208C, 0xFF }, + { 0x208D, 0x03 }, + { 0x208E, 0xFF }, + { 0x208F, 0x03 }, + { 0x2090, 0x7D }, + { 0x2091, 0x00 }, + { 0x2092, 0x62 }, + { 0x2093, 0x01 }, + { 0x2094, 0xE9 }, + { 0x2095, 0x01 }, + { 0x2096, 0x00 }, + { 0x2097, 0x00 }, + { 0x2098, 0x7C }, + { 0x2099, 0x00 }, + { 0x209A, 0x21 }, + { 0x209B, 0x03 }, + { 0x209C, 0xE9 }, + { 0x209D, 0x01 }, + { 0x209E, 0x21 }, + { 0x209F, 0x03 }, + { 0x20A0, 0xFF }, + { 0x20A1, 0x03 }, + { 0x20A2, 0xFF }, + { 0x20A3, 0x03 }, + { 0x20A4, 0xFF }, + { 0x20A5, 0x03 }, + { 0x20A6, 0xFF }, + { 0x20A7, 0x03 }, + { 0x20A8, 0xFF }, + { 0x20A9, 0x03 }, + { 0x20AA, 0xFF }, + { 0x20AB, 0x03 }, + { 0x20AC, 0xFF }, + { 0x20AD, 0x03 }, + { 0x20AE, 0xFF }, + { 0x20AF, 0x03 }, + { 0x20B0, 0xFF }, + { 0x20B1, 0x03 }, + { 0x20B2, 0xFF }, + { 0x20B3, 0x03 }, + { 0x20B4, 0x87 }, + { 0x20B5, 0xCC }, + { 0x20B6, 0x87 }, + { 0x20B7, 0x08 }, + { 0x20B8, 0xF4 }, + { 0x20B9, 0xA5 }, + { 0x20BA, 0x07 }, + { 0x20BC, 0x1F }, + { 0x20BD, 0x01 }, + { 0x20BE, 0xF6 }, + { 0x20BF, 0x00 }, + { 0x20C0, 0x90 }, + { 0x20C1, 0x01 }, + { 0x20C2, 0x67 }, + { 0x20C3, 0x01 }, + { 0x20C4, 0xFF }, + { 0x20C5, 0x03 }, + { 0x20C6, 0xFF }, + { 0x20C7, 0x03 }, + { 0x20C8, 0x33 }, + { 0x20C9, 0x02 }, + { 0x20CA, 0x0A }, + { 0x20CB, 0x02 }, + { 0x20CC, 0x7F }, + { 0x20CD, 0x00 }, + { 0x20CE, 0xD2 }, + { 0x20CF, 0x00 }, + { 0x20D0, 0x81 }, + { 0x20D1, 0x00 }, + { 0x20D2, 0x87 }, + { 0x20D3, 0x00 }, + { 0x20D4, 0x09 }, + { 0x20D5, 0x00 }, + { 0x20D8, 0x7F }, + { 0x20D9, 0x00 }, + { 0x20DA, 0x62 }, + { 0x20DB, 0x01 }, + { 0x20DC, 0x7F }, + { 0x20DD, 0x00 }, + { 0x20DE, 0x62 }, + { 0x20DF, 0x01 }, + { 0x20E0, 0x65 }, + { 0x20E1, 0x00 }, + { 0x20E2, 0x75 }, + { 0x20E3, 0x00 }, + { 0x20E4, 0xE0 }, + { 0x20E5, 0x00 }, + { 0x20E6, 0xF0 }, + { 0x20E7, 0x00 }, + { 0x20E8, 0x4C }, + { 0x20E9, 0x01 }, + { 0x20EA, 0x5C }, + { 0x20EB, 0x01 }, + { 0x20EC, 0xD1 }, + { 0x20ED, 0x01 }, + { 0x20EE, 0xE1 }, + { 0x20EF, 0x01 }, + { 0x20F0, 0x93 }, + { 0x20F1, 0x02 }, + { 0x20F2, 0xA3 }, + { 0x20F3, 0x02 }, + { 0x20F4, 0x0D }, + { 0x20F5, 0x03 }, + { 0x20F6, 0x1D }, + { 0x20F7, 0x03 }, + { 0x20F8, 0x57 }, + { 0x20F9, 0x00 }, + { 0x20FA, 0x7B }, + { 0x20FB, 0x00 }, + { 0x20FC, 0xD2 }, + { 0x20FD, 0x00 }, + { 0x20FE, 0xF6 }, + { 0x20FF, 0x00 }, + { 0x2100, 0x3E }, + { 0x2101, 0x01 }, + { 0x2102, 0x60 }, + { 0x2103, 0x01 }, + { 0x2104, 0xC3 }, + { 0x2105, 0x01 }, + { 0x2106, 0xE5 }, + { 0x2107, 0x01 }, + { 0x2108, 0x85 }, + { 0x2109, 0x02 }, + { 0x210A, 0xA9 }, + { 0x210B, 0x02 }, + { 0x210C, 0xFF }, + { 0x210D, 0x02 }, + { 0x210E, 0x21 }, + { 0x210F, 0x03 }, + { 0x2110, 0xFF }, + { 0x2111, 0x03 }, + { 0x2112, 0x00 }, + { 0x2113, 0x00 }, + { 0x2114, 0xFF }, + { 0x2115, 0x03 }, + { 0x2116, 0xFF }, + { 0x2117, 0x03 }, + { 0x2118, 0xFF }, + { 0x2119, 0x03 }, + { 0x211A, 0xFF }, + { 0x211B, 0x03 }, + { 0x211C, 0xFF }, + { 0x211D, 0x03 }, + { 0x211E, 0xFF }, + { 0x211F, 0x03 }, + { 0x2120, 0xFF }, + { 0x2121, 0x03 }, + { 0x2122, 0xFF }, + { 0x2123, 0x03 }, + { 0x2124, 0xFF }, + { 0x2125, 0x03 }, + { 0x2126, 0xFF }, + { 0x2127, 0x03 }, + { 0x2128, 0x7D }, + { 0x2129, 0x90 }, + { 0x212A, 0xD5 }, + { 0x212B, 0x07 }, + { 0x212C, 0x64 }, + { 0x212D, 0x01 }, + { 0x2130, 0x5F }, + { 0x2131, 0x7D }, + { 0x2132, 0x05 }, + { 0x2134, 0x78 }, + { 0x2135, 0x00 }, + { 0x2136, 0x76 }, + { 0x2137, 0x00 }, + { 0x2138, 0xF3 }, + { 0x2139, 0x00 }, + { 0x213A, 0xF1 }, + { 0x213B, 0x00 }, + { 0x213C, 0xA6 }, + { 0x213D, 0x02 }, + { 0x213E, 0xA4 }, + { 0x213F, 0x02 }, + { 0x2140, 0x7D }, + { 0x2141, 0x00 }, + { 0x2142, 0x8D }, + { 0x2143, 0x00 }, + { 0x2144, 0xA1 }, + { 0x2145, 0x01 }, + { 0x2146, 0xB1 }, + { 0x2147, 0x01 }, + { 0x2148, 0xAB }, + { 0x2149, 0x02 }, + { 0x214A, 0xBB }, + { 0x214B, 0x02 }, + { 0x214C, 0x17 }, + { 0x214D, 0x5C }, + { 0x214E, 0x00 }, + { 0x2150, 0x00 }, + { 0x2151, 0x00 }, + { 0x2152, 0xF8 }, + { 0x2153, 0x00 }, + { 0x2154, 0xBE }, + { 0x2155, 0x00 }, + { 0x2156, 0x7D }, + { 0x2157, 0x00 }, + { 0x2158, 0x25 }, + { 0x2159, 0x00 }, + { 0x215A, 0x7D }, + { 0x215B, 0x00 }, + { 0x215C, 0x62 }, + { 0x215D, 0x01 }, + { 0x215E, 0xFF }, + { 0x215F, 0x03 }, + { 0x2160, 0x26 }, + { 0x2161, 0x00 }, + { 0x2162, 0x7D }, + { 0x2163, 0x00 }, + { 0x2164, 0x63 }, + { 0x2165, 0x01 }, + { 0x2166, 0xFF }, + { 0x2167, 0x03 }, + { 0x2168, 0xCB }, + { 0x2169, 0x02 }, + { 0x216A, 0xCF }, + { 0x216B, 0x02 }, + { 0x216C, 0xFF }, + { 0x216D, 0x03 }, + { 0x216E, 0xFF }, + { 0x216F, 0x03 }, + { 0x2170, 0xFF }, + { 0x2171, 0x03 }, + { 0x2172, 0xFF }, + { 0x2173, 0x03 }, + { 0x2174, 0xFF }, + { 0x2175, 0x03 }, + { 0x2176, 0xFF }, + { 0x2177, 0x03 }, + { 0x2178, 0x7E }, + { 0x2179, 0x00 }, + { 0x217A, 0xBD }, + { 0x217B, 0x00 }, + { 0x217C, 0xEC }, + { 0x217D, 0x01 }, + { 0x217E, 0x7B }, + { 0x217F, 0x02 }, + { 0x2180, 0xD1 }, + { 0x2181, 0x02 }, + { 0x2182, 0x25 }, + { 0x2183, 0x03 }, + { 0x2184, 0x7F }, + { 0x2185, 0x00 }, + { 0x2186, 0xBD }, + { 0x2187, 0x00 }, + { 0x2188, 0xED }, + { 0x2189, 0x01 }, + { 0x218A, 0x7B }, + { 0x218B, 0x02 }, + { 0x218C, 0xD2 }, + { 0x218D, 0x02 }, + { 0x218E, 0x25 }, + { 0x218F, 0x03 }, + { 0x2190, 0xFF }, + { 0x2191, 0x03 }, + { 0x2192, 0xFF }, + { 0x2193, 0x03 }, + { 0x2194, 0xE9 }, + { 0x2195, 0x01 }, + { 0x2196, 0x21 }, + { 0x2197, 0x03 }, + { 0x2198, 0x17 }, + { 0x2199, 0xFC }, + { 0x219A, 0x7F }, + { 0x219B, 0x01 }, + { 0x219C, 0xFF }, + { 0x219D, 0x03 }, + { 0x21A0, 0x1B }, + { 0x21A1, 0x1B }, + { 0x21A2, 0x1B }, + { 0x21A3, 0x1B }, + { 0x21A4, 0x2B }, + { 0x21A5, 0x80 }, + { 0x21A6, 0x00 }, + { 0x21A8, 0x04 }, + { 0x21A9, 0x98 }, + { 0x21AA, 0x60 }, + { 0x21AB, 0x03 }, + { 0x21AC, 0x7F }, + { 0x21AD, 0x80 }, + { 0x21AE, 0x09 }, + { 0x21B0, 0x1C }, + { 0x21B1, 0x00 }, + { 0x21B2, 0xA0 }, + { 0x21B3, 0x00 }, + { 0x21B4, 0x0C }, + { 0x21B5, 0x00 }, + { 0x21B6, 0x2D }, + { 0x21B7, 0x00 }, + { 0x21B8, 0x20 }, + { 0x21B9, 0x00 }, + { 0x21BA, 0x02 }, + { 0x21BB, 0x00 }, + { 0x21BC, 0xCC }, + { 0x21BD, 0x00 }, + { 0x21BE, 0x4A }, + { 0x21BF, 0x00 }, + { 0x21C0, 0xD0 }, + { 0x21C1, 0x00 }, + { 0x21C2, 0x44 }, + { 0x21C3, 0x00 }, + { 0x21C4, 0x00 }, + { 0x21C5, 0xE0 }, + { 0x21C6, 0x00 }, + { 0x21C8, 0x11 }, + { 0x21C9, 0x00 }, + { 0x21CA, 0x02 }, + { 0x21CC, 0x08 }, + { 0x21CD, 0xC0 }, + { 0x21CE, 0x0C }, + { 0x21D0, 0x44 }, + { 0x21D1, 0x00 }, + { 0x21D2, 0x02 }, + { 0x21D4, 0x02 }, + { 0x21D5, 0x20 }, + { 0x21D6, 0x2C }, + { 0x21D8, 0xFE }, + { 0x21D9, 0x9D }, + { 0x21DA, 0xDF }, + { 0x21DB, 0x03 }, + { 0x21DC, 0x62 }, + { 0x21DD, 0x01 }, + { 0x21DE, 0x7F }, + { 0x21DF, 0x00 }, + { 0x21E0, 0xB7 }, + { 0x21E1, 0x01 }, + { 0x21E2, 0xB5 }, + { 0x21E3, 0x01 }, + { 0x21E4, 0xC1 }, + { 0x21E5, 0x02 }, + { 0x21E6, 0xBF }, + { 0x21E7, 0x02 }, + { 0x21E8, 0xB3 }, + { 0x21E9, 0x0D }, + { 0x21EA, 0x00 }, + { 0x21EB, 0x04 }, + { 0x21EC, 0x90 }, + { 0x21ED, 0x07 }, + { 0x21EE, 0x58 }, + { 0x21EF, 0x04 }, + { 0x21F0, 0x54 }, + { 0x21F1, 0x04 }, + { 0x21F4, 0x02 }, + { 0x21F5, 0x00 }, + { 0x21F6, 0x00 }, + { 0x21F8, 0x3C }, + { 0x21F9, 0x00 }, + { 0x21FC, 0x28 }, + { 0x21FD, 0x00 }, + { 0x21FE, 0x3C }, + { 0x21FF, 0x00 }, + { 0x2200, 0x00 }, + { 0x2204, 0x4C }, + { 0x2205, 0x04 }, + { 0x2206, 0x65 }, + { 0x2207, 0x04 }, + { 0x2208, 0x0A }, + { 0x2209, 0x00 }, + { 0x220C, 0x57 }, + { 0x220D, 0x00 }, + { 0x220E, 0x37 }, + { 0x220F, 0x00 }, + { 0x2210, 0x1F }, + { 0x2211, 0x00 }, + { 0x2212, 0x1F }, + { 0x2213, 0x00 }, + { 0x2214, 0x1F }, + { 0x2215, 0x00 }, + { 0x2216, 0x77 }, + { 0x2217, 0x00 }, + { 0x2218, 0x1F }, + { 0x2219, 0x00 }, + { 0x221A, 0x17 }, + { 0x221B, 0x00 }, + { 0x221C, 0x03 }, + { 0x2220, 0x24 }, + { 0x2221, 0x00 }, + { 0x2222, 0x00 }, + { 0x2223, 0x00 }, + { 0x2224, 0xA7 }, + { 0x2225, 0xAA }, + { 0x2226, 0x80 }, + { 0x2227, 0x08 }, + { 0x2228, 0x01 }, + { 0x2260, 0xFF }, + { 0x2261, 0x1F }, + { 0x2262, 0x00 }, + { 0x2263, 0x00 }, + { 0x2264, 0x00 }, + { 0x2265, 0x00 }, + { 0x2266, 0xFF }, + { 0x2267, 0x1F }, + { 0x2268, 0x00 }, + { 0x2269, 0x00 }, + { 0x226A, 0xFF }, + { 0x226B, 0x1F }, + { 0x226C, 0x00 }, + { 0x226D, 0x00 }, + { 0x226E, 0xFF }, + { 0x226F, 0x1F }, + { 0x227C, 0xB2 }, + { 0x227D, 0x0C }, + { 0x227E, 0x6A }, + { 0x227F, 0x09 }, + { 0x2280, 0xD2 }, + { 0x2281, 0x0C }, + { 0x2282, 0x5A }, + { 0x2283, 0x09 }, + { 0x2284, 0xC4 }, + { 0x2285, 0x0C }, + { 0x2286, 0x54 }, + { 0x2287, 0x09 }, + { 0x22B2, 0x92 }, + { 0x22B4, 0x20 }, + { 0x22B5, 0x00 }, + { 0x22B6, 0x20 }, + { 0x22B7, 0x00 }, + { 0x22B8, 0x20 }, + { 0x22B9, 0x00 }, + { 0x22BA, 0x20 }, + { 0x22BB, 0x00 }, + { 0x22BC, 0x20 }, + { 0x22BD, 0x00 }, + { 0x22BE, 0x20 }, + { 0x22BF, 0x00 }, + { 0x22C0, 0x20 }, + { 0x22C1, 0x00 }, + { 0x22C2, 0x20 }, + { 0x22C3, 0x00 }, + { 0x22C4, 0x20 }, + { 0x22C5, 0x00 }, + { 0x22C6, 0x20 }, + { 0x22C7, 0x00 }, + { 0x22C8, 0x20 }, + { 0x22C9, 0x00 }, + { 0x22CA, 0x20 }, + { 0x22CB, 0x00 }, + { 0x22CC, 0x20 }, + { 0x22CD, 0x00 }, + { 0x22CE, 0x20 }, + { 0x22CF, 0x00 }, + { 0x22DA, 0x00 }, + { 0x22EF, 0x82 }, + { 0x2308, 0x01 }, + { 0x2310, 0x4B }, + { 0x2311, 0x09 }, + { 0x2318, 0x40 }, + { 0x2319, 0xCD }, + { 0x231A, 0x54 }, + { 0x2324, 0x20 }, + { 0x2325, 0x00 }, + { 0x2328, 0x00 }, + { 0x234A, 0x9F }, + { 0x234B, 0x07 }, + { 0x2354, 0x0C }, + { 0x23C0, 0x5D }, + { 0x244C, 0xFF }, + { 0x244D, 0x03 }, + { 0x244E, 0xFF }, + { 0x244F, 0x03 }, + { 0x24A0, 0x00 }, + { 0x24A4, 0x16 }, + { 0x24A5, 0x01 }, + { 0x24A6, 0xA6 }, + { 0x24A7, 0x02 }, + { 0x24A8, 0xD5 }, + { 0x24A9, 0x02 }, + { 0x24BC, 0x17 }, + { 0x24BD, 0x01 }, + { 0x24BE, 0xA7 }, + { 0x24BF, 0x02 }, + { 0x24C0, 0xD5 }, + { 0x24C1, 0x02 }, + { 0x24DA, 0x6F }, + { 0x24DB, 0x00 }, + { 0x24DC, 0x62 }, + { 0x24DD, 0x01 }, + { 0x24EA, 0x32 }, + { 0x24EB, 0x00 }, + { 0x24EC, 0xDC }, + { 0x24ED, 0x00 }, + { 0x24FA, 0x32 }, + { 0x24FB, 0x00 }, + { 0x24FC, 0xDD }, + { 0x24FD, 0x00 }, + { 0x254A, 0x15 }, + { 0x254B, 0x01 }, + { 0x255A, 0x15 }, + { 0x255B, 0x01 }, + { 0x2560, 0x01 }, + { 0x2561, 0x00 }, + { 0x2562, 0x2A }, + { 0x2563, 0x00 }, + { 0x2564, 0xF8 }, + { 0x2565, 0x00 }, + { 0x2566, 0x15 }, + { 0x2567, 0x01 }, + { 0x2568, 0x0C }, + { 0x2569, 0x02 }, + { 0x256A, 0x31 }, + { 0x256B, 0x02 }, + { 0x2578, 0x90 }, + { 0x2579, 0x01 }, + { 0x257A, 0x92 }, + { 0x257B, 0x01 }, + { 0x257C, 0xB8 }, + { 0x257D, 0x02 }, + { 0x257E, 0xBA }, + { 0x257F, 0x02 }, + { 0x2584, 0x90 }, + { 0x2585, 0x01 }, + { 0x2586, 0x92 }, + { 0x2587, 0x01 }, + { 0x2588, 0xB8 }, + { 0x2589, 0x02 }, + { 0x258A, 0xBA }, + { 0x258B, 0x02 }, + { 0x267A, 0xF8 }, + { 0x267B, 0x00 }, + { 0x267C, 0x16 }, + { 0x267D, 0x01 }, + { 0x267E, 0xA6 }, + { 0x267F, 0x02 }, + { 0x2680, 0xD5 }, + { 0x2681, 0x02 }, + { 0x2690, 0xF8 }, + { 0x2691, 0x00 }, + { 0x2694, 0xA6 }, + { 0x2695, 0x02 }, + { 0x2696, 0x16 }, + { 0x2697, 0x01 }, + { 0x269A, 0xD5 }, + { 0x269B, 0x02 }, + { 0x26B8, 0x10 }, + { 0x26B9, 0x00 }, + { 0x26BA, 0x33 }, + { 0x26BB, 0x00 }, + { 0x26BC, 0x89 }, + { 0x26BD, 0x00 }, + { 0x26BE, 0xB0 }, + { 0x26BF, 0x00 }, + { 0x26C4, 0x4E }, + { 0x26C5, 0x00 }, + { 0x26C8, 0xC9 }, + { 0x26C9, 0x00 }, + { 0x26CC, 0x35 }, + { 0x26CD, 0x01 }, + { 0x26D0, 0xBA }, + { 0x26D1, 0x01 }, + { 0x26D4, 0x7C }, + { 0x26D5, 0x02 }, + { 0x26D8, 0xF6 }, + { 0x26D9, 0x02 }, + { 0x26DE, 0x51 }, + { 0x26DF, 0x00 }, + { 0x26E0, 0x7F }, + { 0x26E1, 0x00 }, + { 0x26E2, 0xCC }, + { 0x26E3, 0x00 }, + { 0x26E4, 0xF8 }, + { 0x26E5, 0x00 }, + { 0x26E6, 0x38 }, + { 0x26E7, 0x01 }, + { 0x26E8, 0x65 }, + { 0x26E9, 0x01 }, + { 0x26EA, 0xBD }, + { 0x26EB, 0x01 }, + { 0x26EE, 0x7F }, + { 0x26EF, 0x02 }, + { 0x26F0, 0xAB }, + { 0x26F1, 0x02 }, + { 0x26F2, 0xF9 }, + { 0x26F3, 0x02 }, + { 0x2722, 0x59 }, + { 0x2723, 0x02 }, + { 0x2938, 0x55 }, + { 0x2939, 0x00 }, + { 0x293A, 0x17 }, + { 0x293B, 0x00 }, + { 0x293C, 0xD0 }, + { 0x293D, 0x00 }, + { 0x293E, 0x91 }, + { 0x293F, 0x00 }, + { 0x2940, 0x3C }, + { 0x2941, 0x01 }, + { 0x2942, 0x0C }, + { 0x2943, 0x01 }, + { 0x2944, 0xC1 }, + { 0x2945, 0x01 }, + { 0x2946, 0x76 }, + { 0x2947, 0x01 }, + { 0x2948, 0x83 }, + { 0x2949, 0x02 }, + { 0x294A, 0xFB }, + { 0x294B, 0x01 }, + { 0x294C, 0xFD }, + { 0x294D, 0x02 }, + { 0x294E, 0xBF }, + { 0x294F, 0x02 }, + { 0x2A06, 0x25 }, + { 0x2A07, 0x03 }, + { 0x2A0C, 0x45 }, + { 0x2A0D, 0x00 }, + { 0x2A0E, 0x00 }, + { 0x2A0F, 0x00 }, + { 0x2A20, 0x00 }, + { 0x2A21, 0x00 }, + { 0x2A22, 0x7D }, + { 0x2A23, 0x00 }, + { 0x2B11, 0x1A }, + { 0x2B13, 0x11 }, + { 0x2B14, 0x11 }, + { 0x2B15, 0x11 }, + { 0x2B16, 0x11 }, + { 0x2B17, 0x10 }, + { 0x2B18, 0x0F }, + { 0x2B19, 0x0E }, + { 0x2B1A, 0x0D }, + { 0x2B1B, 0x0C }, + { 0x2B1C, 0x0B }, + { 0x2B1D, 0x0B }, + { 0x2B1E, 0x0A }, + { 0x2B1F, 0x09 }, + { 0x2B20, 0x08 }, + { 0x2B21, 0x07 }, + { 0x2B22, 0x06 }, + { 0x2B23, 0x05 }, + { 0x2B24, 0x04 }, + { 0x2B25, 0x03 }, + { 0x2B26, 0x03 }, + { 0x2B38, 0x01 }, + { 0x2B45, 0xE3 }, + { 0x2B50, 0x01 }, + { 0x2B51, 0x00 }, + { 0x2B62, 0x66 }, + { 0x2B6D, 0x47 }, + { 0x2B70, 0x03 }, + { 0x2B71, 0x02 }, + { 0x2B72, 0x02 }, + { 0x2B7B, 0x42 }, + { 0x2B7F, 0x7F }, + { 0x2B80, 0x94 }, + { 0x2B81, 0x06 }, + { 0x2B87, 0x1B }, + { 0x2B88, 0x1A }, + { 0x2B89, 0x17 }, + { 0x2B8A, 0x17 }, + { 0x2B8B, 0x12 }, + { 0x2B8D, 0x2B }, + { 0x2B8E, 0x2B }, + { 0x2B8F, 0x2B }, + { 0x2B90, 0x7F }, + { 0x2B91, 0x0F }, + { 0x2B92, 0x31 }, + { 0x2B93, 0x07 }, + { 0x2B94, 0xFE }, + { 0x2B95, 0x26 }, + { 0x2B96, 0x84 }, + { 0x2B97, 0x0C }, + { 0x2B98, 0xFE }, + { 0x2B99, 0x56 }, + { 0x2B9B, 0x2A }, + { 0x2BA8, 0xBC }, + { 0x2BA9, 0x62 }, + { 0x2BC1, 0x70 }, + { 0x2BC5, 0x80 }, + { 0x2BD5, 0x30 }, + { 0x2BD6, 0xF0 }, + { 0x2BD8, 0xDB }, + { 0x2BD9, 0xF6 }, + { 0x2BDA, 0x21 }, + { 0x2BDB, 0x06 }, + { 0x2BDC, 0x57 }, + { 0x2BFE, 0x00 }, + { 0x2BFF, 0x00 }, + { 0x2C98, 0xE1 }, + { 0x2C99, 0x2E }, + { 0x2C9B, 0x80 }, + { 0x2CA9, 0x80 }, + { 0x2CAA, 0x01 }, + { 0x2CBF, 0x08 }, + { 0x2D39, 0x0E }, + { 0x2D50, 0x80 }, + { 0x2D54, 0x00 }, + { 0x2D5B, 0x58 }, + { 0x2DFD, 0x01 }, + { 0x2D64, 0x64 }, + { 0x2D65, 0x80 }, + { 0x3000, 0x00 }, + { 0x3001, 0x00 }, + { 0x3002, 0x23 }, + { 0x3003, 0xA1 }, + { 0x3004, 0x00 }, + { 0x3005, 0x20 }, + { 0x3006, 0x58 }, + { 0x3007, 0x00 }, + { 0x3008, 0x06 }, + { 0x3009, 0xB4 }, + { 0x300A, 0x1F }, + { 0x300B, 0x00 }, + { 0x300C, 0x00 }, + { 0x300D, 0x1B }, + { 0x300E, 0x90 }, + { 0x300F, 0x97 }, + { 0x3010, 0x00 }, + { 0x3011, 0x00 }, + { 0x3012, 0x20 }, + { 0x3013, 0x21 }, + { 0x3014, 0x00 }, + { 0x3015, 0x20 }, + { 0x3016, 0x84 }, + { 0x3017, 0x00 }, + { 0x3018, 0x30 }, + { 0x3019, 0x09 }, + { 0x301A, 0x46 }, + { 0x301B, 0x00 }, + { 0x3070, 0xC1 }, + { 0x3071, 0x81 }, + { 0x3072, 0x29 }, + { 0x3073, 0x81 }, + { 0x3080, 0xC4 }, + { 0x3081, 0x0C }, + { 0x3082, 0xD2 }, + { 0x3083, 0x0C }, + { 0x3084, 0x5C }, + { 0x3085, 0x00 }, + { 0x3086, 0x90 }, + { 0x3087, 0x00 }, + { 0x3088, 0x07 }, + { 0x3089, 0x0A }, + { 0x308A, 0x52 }, + { 0x308B, 0x09 }, + { 0x308C, 0x44 }, + { 0x308D, 0x03 }, + { 0x308E, 0x70 }, + { 0x308F, 0x03 }, + { 0x3090, 0x54 }, + { 0x3091, 0x09 }, + { 0x3092, 0x5A }, + { 0x3093, 0x09 }, + { 0x3094, 0x1C }, + { 0x3095, 0x00 }, + { 0x3096, 0x10 }, + { 0x3097, 0x00 }, + { 0x3098, 0x70 }, + { 0x3099, 0x03 }, + { 0x309A, 0xF8 }, + { 0x309B, 0x04 }, + { 0x309C, 0x74 }, + { 0x309D, 0x01 }, + { 0x309E, 0x60 }, + { 0x309F, 0x01 }, + { 0x3370, 0x01 }, + { 0x3374, 0xF0 }, + { 0x3375, 0x00 }, + { 0x3376, 0x01 }, + { 0x3377, 0x00 }, + { 0x3410, (IMX390_OUT_WIDTH & 0xFF) }, + { 0x3411, (IMX390_OUT_WIDTH >> 8) }, + { 0x3418, (IMX390_OUT_HEIGHT & 0xFF) }, + { 0x3419, (IMX390_OUT_HEIGHT >> 8) }, + { 0x34A0, 0x30 }, + { 0x34BE, 0x6A }, + { 0x34BF, 0x01 }, + { 0x34C0, 0x40 }, + { 0x34C1, 0x00 }, + { 0x34C2, 0x40 }, + { 0x34C3, 0x00 }, + { 0x34C4, 0x40 }, + { 0x34C5, 0x00 }, + { 0x34C6, 0x40 }, + { 0x34C7, 0x00 }, + { 0x34C8, 0x40 }, + { 0x34C9, 0x00 }, + { 0x34CA, 0x40 }, + { 0x34CB, 0x00 }, + { 0x34CC, 0x40 }, + { 0x34CD, 0x00 }, + { 0x34CE, 0x40 }, + { 0x34CF, 0x00 }, + { 0x3584, 0x00 }, + { 0x3586, 0x00 }, + { 0x3587, 0x01 }, + { 0x3588, 0xE6 }, + { 0x3589, 0x00 }, + { 0x3590, 0x00 }, + { 0x3591, 0x00 }, + { 0x3594, 0x40 }, + { 0x3598, 0x03 }, + { 0x3599, 0x00 }, + { 0x359A, 0x80 }, + { 0x359B, 0x00 }, + { 0x359C, 0x00 }, + { 0x359D, 0x01 }, + { 0x359E, 0x00 }, + { 0x359F, 0x02 }, + { 0x35A0, 0x00 }, + { 0x35A1, 0x04 }, + { 0x35A2, 0x20 }, + { 0x35A3, 0x00 }, + { 0x35A4, 0x40 }, + { 0x35A5, 0x00 }, + { 0x35A6, 0x80 }, + { 0x35A7, 0x00 }, + { 0x35A8, 0x00 }, + { 0x35A9, 0x01 }, + { 0x35AC, 0x80 }, + { 0x35AD, 0x00 }, + { 0x35AE, 0x00 }, + { 0x35AF, 0x01 }, + { 0x35B0, 0x00 }, + { 0x35B1, 0x02 }, + { 0x35B2, 0x00 }, + { 0x35B3, 0x04 }, + { 0x35B4, 0x02 }, + { 0x35B5, 0x00 }, + { 0x35B6, 0x04 }, + { 0x35B7, 0x00 }, + { 0x35B8, 0x08 }, + { 0x35B9, 0x00 }, + { 0x35BA, 0x10 }, + { 0x35BB, 0x00 }, + { 0x35C8, 0x00 }, + { 0x35C9, 0x01 }, + { 0x35CA, 0x00 }, + { 0x35CB, 0x04 }, + { 0x35CC, 0x00 }, + { 0x35CD, 0x10 }, + { 0x35CE, 0x00 }, + { 0x35CF, 0x40 }, + { 0x35D0, 0x00 }, + { 0x35D1, 0x0C }, + { 0x35D2, 0x00 }, + { 0x35D3, 0x0C }, + { 0x35D4, 0x00 }, + { 0x35D5, 0x0C }, + { 0x35D6, 0x00 }, + { 0x35D7, 0x0C }, + { 0x35D8, 0x00 }, + { 0x35D9, 0x00 }, + { 0x35DA, 0x08 }, + { 0x35DB, 0x00 }, + { 0x35DC, 0xD8 }, + { 0x35DD, 0x0E }, + { 0x35F0, 0x00 }, + { 0x35F1, 0x10 }, + { 0x35F2, 0x00 }, + { 0x35F3, 0x10 }, + { 0x35F4, 0x00 }, + { 0x35F5, 0x10 }, + { 0x35F6, 0x00 }, + { 0x35F7, 0x03 }, + { 0x35F8, 0x00 }, + { 0x35F9, 0x02 }, + { 0x35FA, 0x38 }, + { 0x35FB, 0x00 }, + { 0x35FC, 0xB3 }, + { 0x35FD, 0x01 }, + { 0x35FE, 0x00 }, + { 0x35FF, 0x00 }, + { 0x3600, 0x05 }, + { 0x3601, 0x06 }, + { 0x3604, 0x03 }, + { 0x3605, 0x00 }, + { 0x3608, 0x03 }, + { 0x3609, 0x00 }, + { 0x360C, 0x00 }, + { 0x360D, 0x00 }, + { 0x3610, 0x10 }, + { 0x3611, 0x01 }, + { 0x3612, 0x00 }, + { 0x3613, 0x00 }, + { 0x3614, 0x00 }, + { 0x3615, 0x00 }, + { 0x361C, 0x00 }, + { 0x361D, 0x01 }, + { 0x361E, 0x00 }, + { 0x361F, 0x01 }, + { 0x3620, 0x00 }, + { 0x3621, 0x00 }, + { 0x3622, 0xB0 }, + { 0x3623, 0x04 }, + { 0x3624, 0xDC }, + { 0x3625, 0x05 }, + { 0x3626, 0x00 }, + { 0x3627, 0x01 }, + { 0x3628, 0xFF }, + { 0x3629, 0x0F }, + { 0x362A, 0x00 }, + { 0x362B, 0x10 }, + { 0x362C, 0x00 }, + { 0x362D, 0x01 }, + { 0x3630, 0x41 }, + { 0x3631, 0x00 }, + { 0x3632, 0x41 }, + { 0x3633, 0x00 }, + { 0x3634, 0x41 }, + { 0x3635, 0x00 }, + { 0x3636, 0x41 }, + { 0x3637, 0x00 }, + { 0x3638, 0x44 }, + { 0x3639, 0x00 }, + { 0x363A, 0x47 }, + { 0x363B, 0x00 }, + { 0x363C, 0x47 }, + { 0x363D, 0x00 }, + { 0x363E, 0x44 }, + { 0x363F, 0x00 }, + { 0x36C4, 0xFF }, + { 0x36C5, 0x0F }, + { 0x36C6, 0xFF }, + { 0x36C7, 0x0F }, + { 0x36C8, 0xFF }, + { 0x36C9, 0x0F }, + { 0x36CC, 0x00 }, + { 0x36CD, 0x00 }, + { 0x36CE, 0x00 }, + { 0x36CF, 0x00 }, + { 0x36D0, 0x00 }, + { 0x36D1, 0x00 }, + { 0x36D4, 0xFF }, + { 0x36D5, 0x0F }, + { 0x36D6, 0xFF }, + { 0x36D7, 0x0F }, + { 0x36D8, 0xFF }, + { 0x36D9, 0x0F }, + { 0x36DC, 0xFF }, + { 0x36DD, 0x0F }, + { 0x36DE, 0xFF }, + { 0x36DF, 0x0F }, + { 0x36E0, 0xFF }, + { 0x36E1, 0x0F }, + { 0x36E4, 0xFF }, + { 0x36E5, 0x0F }, + { 0x36E6, 0xFF }, + { 0x36E7, 0x0F }, + { 0x36E8, 0xFF }, + { 0x36E9, 0x0F }, + { 0x36EE, 0x00 }, + { 0x36EF, 0x00 }, + { 0x36F0, 0x00 }, + { 0x36F1, 0x80 }, + { 0x36F8, 0x01 }, + { 0x3700, 0x03 }, + { 0x3701, 0x05 }, + { 0x3702, 0x03 }, + { 0x3703, 0x04 }, + { 0x3704, 0x08 }, + { 0x3705, 0x03 }, + { 0x3706, 0x03 }, + { 0x3707, 0x03 }, + { 0x3708, 0x03 }, + { 0x3709, 0x03 }, + { 0x370A, 0x03 }, + { 0x370B, 0x03 }, + { 0x370C, 0x03 }, + { 0x370D, 0x03 }, + { 0x370E, 0x0E }, + { 0x3718, 0x64 }, + { 0x3719, 0x47 }, + { 0x371A, 0x36 }, + { 0x371B, 0x1E }, + { 0x371C, 0x50 }, + { 0x371D, 0x41 }, + { 0x371E, 0x2F }, + { 0x371F, 0x1A }, + { 0x3720, 0x95 }, + { 0x3721, 0x9D }, + { 0x3722, 0xA5 }, + { 0x3723, 0xAD }, + { 0x3748, 0xA8 }, + { 0x3749, 0x9E }, + { 0x374A, 0x94 }, + { 0x374B, 0x80 }, + { 0x37C0, 0x00 }, + { 0x37C1, 0x00 }, + { 0x37C2, 0x00 }, + { 0x37C4, 0x00 }, + { 0x37C5, 0x00 }, + { 0x37C6, 0x00 }, + { 0x37C8, 0x00 }, + { 0x37C9, 0x00 }, + { 0x37CA, 0x00 }, + { 0x37CC, 0x00 }, + { 0x37CD, 0x00 }, + { 0x37CE, 0x00 }, + { 0x37D0, 0x00 }, + { 0x37D1, 0x00 }, + { 0x37D2, 0x00 }, + { 0x37D4, 0x00 }, + { 0x37D5, 0x00 }, + { 0x37D6, 0x00 }, + { 0x37D8, 0x00 }, + { 0x37D9, 0x00 }, + { 0x37DA, 0x00 }, + { 0x37DC, 0x00 }, + { 0x37DD, 0x00 }, + { 0x37DE, 0x00 }, + { 0x37E0, 0x00 }, + { 0x37E1, 0x00 }, + { 0x37E2, 0x00 }, + { 0x37E4, 0x00 }, + { 0x37E5, 0x00 }, + { 0x37E6, 0x00 }, + { 0x37E8, 0x00 }, + { 0x37E9, 0x00 }, + { 0x37EA, 0x00 }, + { 0x37EC, 0x00 }, + { 0x37ED, 0x00 }, + { 0x37EE, 0x00 }, + { 0x37F0, 0x00 }, + { 0x37F4, 0x00 }, + { 0x37F5, 0x1E }, + { 0x37F6, 0x34 }, + { 0x37F7, 0x00 }, + { 0x37F8, 0xFF }, + { 0x37F9, 0xFF }, + { 0x37FA, 0x03 }, + { 0x37FC, 0x00 }, + { 0x37FD, 0x00 }, + { 0x37FE, 0x04 }, + { 0x3800, 0xFF }, + { 0x3801, 0xFF }, + { 0x3802, 0x03 }, + { 0x3804, 0x00 }, + { 0x3805, 0x00 }, + { 0x3806, 0x04 }, + { 0x3808, 0x00 }, + { 0x3809, 0x00 }, + { 0x380A, 0x00 }, + { 0x380C, 0x00 }, + { 0x380D, 0x00 }, + { 0x380E, 0x00 }, + { 0x3810, 0x00 }, + { 0x3811, 0x00 }, + { 0x3812, 0x00 }, + { 0x3814, 0x00 }, + { 0x3815, 0x00 }, + { 0x3816, 0x00 }, + { 0x3818, 0x00 }, + { 0x3819, 0x00 }, + { 0x381A, 0x00 }, + { 0x381C, 0x00 }, + { 0x381D, 0x00 }, + { 0x381E, 0x00 }, + { 0x3820, 0x00 }, + { 0x3821, 0x00 }, + { 0x3822, 0x00 }, + { 0x3824, 0x00 }, + { 0x3825, 0x00 }, + { 0x3826, 0x00 }, + { 0x3828, 0x00 }, + { 0x3829, 0x00 }, + { 0x382A, 0x00 }, + { 0x382C, 0x00 }, + { 0x382D, 0x00 }, + { 0x382E, 0x00 }, + { 0x3830, 0x00 }, + { 0x3831, 0x00 }, + { 0x3832, 0x00 }, + { 0x3834, 0x00 }, + { 0x3835, 0x00 }, + { 0x3836, 0x00 }, + { 0x3838, 0x47 }, + { 0x3839, 0x00 }, + { 0x383A, 0x34 }, + { 0x383B, 0x00 }, + { 0x383C, 0x48 }, + { 0x383D, 0x00 }, + { 0x383E, 0x39 }, + { 0x383F, 0x00 }, + { 0x3840, 0x13 }, + { 0x3841, 0x00 }, + { 0x3842, 0x13 }, + { 0x3843, 0x00 }, + { 0x3844, 0x1D }, + { 0x3845, 0x00 }, + { 0x3846, 0x1D }, + { 0x3847, 0x00 }, + { 0x3848, 0x08 }, + { 0x3849, 0x00 }, + { 0x384A, 0x07 }, + { 0x384B, 0x00 }, + { 0x384C, 0x05 }, + { 0x384D, 0x00 }, + { 0x384E, 0x00 }, + { 0x384F, 0x00 }, + { 0x3850, 0xFF }, + { 0x3851, 0x0F }, + { 0x3852, 0x00 }, + { 0x3853, 0x10 }, + { 0x3854, 0xFF }, + { 0x3855, 0x0F }, + { 0x3856, 0x00 }, + { 0x3857, 0x10 }, + { 0x3858, 0xFF }, + { 0x3859, 0x0F }, + { 0x385A, 0x00 }, + { 0x385B, 0x10 }, + { 0x385C, 0x02 }, + { 0x385D, 0x00 }, + { 0x385E, 0x06 }, + { 0x385F, 0x00 }, + { 0x3860, 0x06 }, + { 0x3861, 0x00 }, + { 0x3862, 0x08 }, + { 0x3863, 0x00 }, + { 0x3864, 0x02 }, + { 0x3865, 0x00 }, + { 0x3870, 0x00 }, + { 0x3871, 0x01 }, + { 0x38A0, 0x01 }, + { 0x38A1, 0x01 }, + { 0x38A2, 0x00 }, + { 0x38A3, 0x01 }, + { 0x38A4, 0x07 }, + { 0x38A5, 0x00 }, + { 0x38A6, 0x04 }, + { 0x38A7, 0x04 }, + { 0x38A8, 0x00 }, + { 0x38A9, 0x00 }, + { 0x38AC, 0x00 }, + { 0x38AD, 0x00 }, + { 0x38AE, 0x01 }, + { 0x38B0, 0x02 }, + { 0x38B2, 0x43 }, + { 0x38B3, 0x00 }, + { 0x38B4, 0x10 }, + { 0x38B5, 0x00 }, + { 0x38B6, 0x09 }, + { 0x38B7, 0x00 }, + { 0x38B8, 0x09 }, + { 0x38B9, 0x00 }, + { 0x38BA, 0x47 }, + { 0x38BB, 0x00 }, + { 0x38BC, 0x16 }, + { 0x38BD, 0x00 }, + { 0x38BE, 0x0E }, + { 0x38BF, 0x00 }, + { 0x38C0, 0x0B }, + { 0x38C1, 0x00 }, + { 0x38C2, 0x4A }, + { 0x38C3, 0x00 }, + { 0x38C4, 0x1C }, + { 0x38C5, 0x00 }, + { 0x38C6, 0x12 }, + { 0x38C7, 0x00 }, + { 0x38C8, 0x0D }, + { 0x38C9, 0x00 }, + { 0x38CA, 0x51 }, + { 0x38CB, 0x00 }, + { 0x38CC, 0x24 }, + { 0x38CD, 0x00 }, + { 0x38CE, 0x19 }, + { 0x38CF, 0x00 }, + { 0x38D0, 0x10 }, + { 0x38D1, 0x00 }, + { 0x38D2, 0x5D }, + { 0x38D3, 0x00 }, + { 0x38D4, 0x30 }, + { 0x38D5, 0x00 }, + { 0x38D6, 0x23 }, + { 0x38D7, 0x00 }, + { 0x38D8, 0x17 }, + { 0x38D9, 0x00 }, + { 0x38DA, 0x72 }, + { 0x38DB, 0x00 }, + { 0x38DC, 0x43 }, + { 0x38DD, 0x00 }, + { 0x38DE, 0x31 }, + { 0x38DF, 0x00 }, + { 0x38E0, 0x20 }, + { 0x38E1, 0x00 }, + { 0x38E2, 0x96 }, + { 0x38E3, 0x00 }, + { 0x38E4, 0x5E }, + { 0x38E5, 0x00 }, + { 0x38E6, 0x46 }, + { 0x38E7, 0x00 }, + { 0x38E8, 0x2E }, + { 0x38E9, 0x00 }, + { 0x38EA, 0xD4 }, + { 0x38EB, 0x00 }, + { 0x38EC, 0x87 }, + { 0x38ED, 0x00 }, + { 0x38EE, 0x65 }, + { 0x38EF, 0x00 }, + { 0x38F0, 0x43 }, + { 0x38F1, 0x00 }, + { 0x38F2, 0x3F }, + { 0x38F3, 0x01 }, + { 0x38F4, 0xC4 }, + { 0x38F5, 0x00 }, + { 0x38F6, 0x94 }, + { 0x38F7, 0x00 }, + { 0x38F8, 0x64 }, + { 0x38F9, 0x00 }, + { 0x38FA, 0x00 }, + { 0x38FB, 0x01 }, + { 0x38FC, 0x00 }, + { 0x38FD, 0x01 }, + { 0x38FE, 0x00 }, + { 0x38FF, 0x01 }, + { 0x3900, 0x00 }, + { 0x3901, 0x01 }, + { 0x3902, 0x60 }, + { 0x3903, 0x00 }, + { 0x3904, 0x25 }, + { 0x3905, 0x00 }, + { 0x3906, 0x18 }, + { 0x3907, 0x00 }, + { 0x3908, 0x10 }, + { 0x3909, 0x00 }, + { 0x390A, 0xE6 }, + { 0x390B, 0x00 }, + { 0x390C, 0xD5 }, + { 0x390D, 0x00 }, + { 0x390E, 0xAA }, + { 0x390F, 0x00 }, + { 0x3910, 0x85 }, + { 0x3911, 0x00 }, + { 0x3912, 0xE6 }, + { 0x3913, 0x00 }, + { 0x3914, 0xD5 }, + { 0x3915, 0x00 }, + { 0x3916, 0xAA }, + { 0x3917, 0x00 }, + { 0x3918, 0x85 }, + { 0x3919, 0x00 }, + { 0x391A, 0xE6 }, + { 0x391B, 0x00 }, + { 0x391C, 0xD5 }, + { 0x391D, 0x00 }, + { 0x391E, 0xAA }, + { 0x391F, 0x00 }, + { 0x3920, 0x85 }, + { 0x3921, 0x00 }, + { 0x3922, 0x40 }, + { 0x3923, 0x00 }, + { 0x3924, 0x40 }, + { 0x3925, 0x00 }, + { 0x3926, 0x40 }, + { 0x3927, 0x00 }, + { 0x3928, 0x40 }, + { 0x3929, 0x00 }, + { 0x392A, 0x80 }, + { 0x392B, 0x00 }, + { 0x392C, 0x80 }, + { 0x392D, 0x00 }, + { 0x392E, 0x80 }, + { 0x392F, 0x00 }, + { 0x3930, 0x80 }, + { 0x3931, 0x00 }, + { 0x3932, 0x4C }, + { 0x3933, 0x4C }, + { 0x3934, 0x4C }, + { 0x3940, 0x01 }, + { 0x3941, 0x01 }, + { 0x3942, 0x00 }, + { 0x3943, 0x01 }, + { 0x3944, 0x07 }, + { 0x3945, 0x00 }, + { 0x3946, 0x04 }, + { 0x3947, 0x04 }, + { 0x3948, 0x00 }, + { 0x3949, 0x00 }, + { 0x394C, 0x00 }, + { 0x394D, 0x00 }, + { 0x394E, 0x01 }, + { 0x3950, 0x03 }, + { 0x3952, 0x1B }, + { 0x3953, 0x00 }, + { 0x3954, 0x0C }, + { 0x3955, 0x00 }, + { 0x3956, 0x09 }, + { 0x3957, 0x00 }, + { 0x3958, 0x07 }, + { 0x3959, 0x00 }, + { 0x395A, 0x1D }, + { 0x395B, 0x00 }, + { 0x395C, 0x0E }, + { 0x395D, 0x00 }, + { 0x395E, 0x0B }, + { 0x395F, 0x00 }, + { 0x3960, 0x08 }, + { 0x3961, 0x00 }, + { 0x3962, 0x1E }, + { 0x3963, 0x00 }, + { 0x3964, 0x10 }, + { 0x3965, 0x00 }, + { 0x3966, 0x0C }, + { 0x3967, 0x00 }, + { 0x3968, 0x09 }, + { 0x3969, 0x00 }, + { 0x396A, 0x21 }, + { 0x396B, 0x00 }, + { 0x396C, 0x13 }, + { 0x396D, 0x00 }, + { 0x396E, 0x0E }, + { 0x396F, 0x00 }, + { 0x3970, 0x0A }, + { 0x3971, 0x00 }, + { 0x3972, 0x25 }, + { 0x3973, 0x00 }, + { 0x3974, 0x19 }, + { 0x3975, 0x00 }, + { 0x3976, 0x12 }, + { 0x3977, 0x00 }, + { 0x3978, 0x0D }, + { 0x3979, 0x00 }, + { 0x397A, 0x2E }, + { 0x397B, 0x00 }, + { 0x397C, 0x21 }, + { 0x397D, 0x00 }, + { 0x397E, 0x19 }, + { 0x397F, 0x00 }, + { 0x3980, 0x11 }, + { 0x3981, 0x00 }, + { 0x3982, 0x3C }, + { 0x3983, 0x00 }, + { 0x3984, 0x2F }, + { 0x3985, 0x00 }, + { 0x3986, 0x23 }, + { 0x3987, 0x00 }, + { 0x3988, 0x19 }, + { 0x3989, 0x00 }, + { 0x398A, 0x56 }, + { 0x398B, 0x00 }, + { 0x398C, 0x44 }, + { 0x398D, 0x00 }, + { 0x398E, 0x35 }, + { 0x398F, 0x00 }, + { 0x3990, 0x27 }, + { 0x3991, 0x00 }, + { 0x3992, 0x84 }, + { 0x3993, 0x00 }, + { 0x3994, 0x68 }, + { 0x3995, 0x00 }, + { 0x3996, 0x53 }, + { 0x3997, 0x00 }, + { 0x3998, 0x40 }, + { 0x3999, 0x00 }, + { 0x399A, 0x00 }, + { 0x399B, 0x01 }, + { 0x399C, 0x00 }, + { 0x399D, 0x01 }, + { 0x399E, 0x00 }, + { 0x399F, 0x01 }, + { 0x39A0, 0x00 }, + { 0x39A1, 0x01 }, + { 0x39A2, 0x60 }, + { 0x39A3, 0x00 }, + { 0x39A4, 0x20 }, + { 0x39A5, 0x00 }, + { 0x39A6, 0x15 }, + { 0x39A7, 0x00 }, + { 0x39A8, 0x10 }, + { 0x39A9, 0x00 }, + { 0x39AA, 0xE6 }, + { 0x39AB, 0x00 }, + { 0x39AC, 0xD5 }, + { 0x39AD, 0x00 }, + { 0x39AE, 0xAA }, + { 0x39AF, 0x00 }, + { 0x39B0, 0x85 }, + { 0x39B1, 0x00 }, + { 0x39B2, 0xE6 }, + { 0x39B3, 0x00 }, + { 0x39B4, 0xD5 }, + { 0x39B5, 0x00 }, + { 0x39B6, 0xAA }, + { 0x39B7, 0x00 }, + { 0x39B8, 0x85 }, + { 0x39B9, 0x00 }, + { 0x39BA, 0xE6 }, + { 0x39BB, 0x00 }, + { 0x39BC, 0xD5 }, + { 0x39BD, 0x00 }, + { 0x39BE, 0xAA }, + { 0x39BF, 0x00 }, + { 0x39C0, 0x85 }, + { 0x39C1, 0x00 }, + { 0x39C2, 0x40 }, + { 0x39C3, 0x00 }, + { 0x39C4, 0x40 }, + { 0x39C5, 0x00 }, + { 0x39C6, 0x40 }, + { 0x39C7, 0x00 }, + { 0x39C8, 0x40 }, + { 0x39C9, 0x00 }, + { 0x39CA, 0x80 }, + { 0x39CB, 0x00 }, + { 0x39CC, 0x80 }, + { 0x39CD, 0x00 }, + { 0x39CE, 0x80 }, + { 0x39CF, 0x00 }, + { 0x39D0, 0x80 }, + { 0x39D1, 0x00 }, + { 0x39D2, 0x4C }, + { 0x39D3, 0x4C }, + { 0x39D4, 0x4C }, + { 0x39E0, 0x01 }, + { 0x39E1, 0x00 }, + { 0x39E4, 0x40 }, + { 0x39E5, 0x01 }, + { 0x39E6, 0x01 }, + { 0x39E8, 0x00 }, + { 0x39E9, 0x01 }, + { 0x39EA, 0x00 }, + { 0x39EB, 0x00 }, + { 0x39EC, 0x01 }, + { 0x39ED, 0x00 }, + { 0x39EE, 0x01 }, + { 0x39F0, 0x03 }, + { 0x39F1, 0x04 }, + { 0x39F2, 0x0E }, + { 0x39F4, 0x19 }, + { 0x39F5, 0x00 }, + { 0x39F6, 0x12 }, + { 0x39F7, 0x00 }, + { 0x39F8, 0x0D }, + { 0x39F9, 0x00 }, + { 0x39FA, 0x07 }, + { 0x39FB, 0x00 }, + { 0x39FC, 0x2B }, + { 0x39FD, 0x00 }, + { 0x39FE, 0x1B }, + { 0x39FF, 0x00 }, + { 0x3A00, 0x11 }, + { 0x3A01, 0x00 }, + { 0x3A02, 0x08 }, + { 0x3A03, 0x00 }, + { 0x3A04, 0x37 }, + { 0x3A05, 0x00 }, + { 0x3A06, 0x21 }, + { 0x3A07, 0x00 }, + { 0x3A08, 0x14 }, + { 0x3A09, 0x00 }, + { 0x3A0A, 0x09 }, + { 0x3A0B, 0x00 }, + { 0x3A0C, 0x4A }, + { 0x3A0D, 0x00 }, + { 0x3A0E, 0x2C }, + { 0x3A0F, 0x00 }, + { 0x3A10, 0x18 }, + { 0x3A11, 0x00 }, + { 0x3A12, 0x0B }, + { 0x3A13, 0x00 }, + { 0x3A14, 0x66 }, + { 0x3A15, 0x00 }, + { 0x3A16, 0x3B }, + { 0x3A17, 0x00 }, + { 0x3A18, 0x20 }, + { 0x3A19, 0x00 }, + { 0x3A1A, 0x0F }, + { 0x3A1B, 0x00 }, + { 0x3A1C, 0x8E }, + { 0x3A1D, 0x00 }, + { 0x3A1E, 0x51 }, + { 0x3A1F, 0x00 }, + { 0x3A20, 0x2B }, + { 0x3A21, 0x00 }, + { 0x3A22, 0x14 }, + { 0x3A23, 0x00 }, + { 0x3A24, 0xC8 }, + { 0x3A25, 0x00 }, + { 0x3A26, 0x72 }, + { 0x3A27, 0x00 }, + { 0x3A28, 0x3C }, + { 0x3A29, 0x00 }, + { 0x3A2A, 0x1B }, + { 0x3A2B, 0x00 }, + { 0x3A2C, 0x19 }, + { 0x3A2D, 0x01 }, + { 0x3A2E, 0xA0 }, + { 0x3A2F, 0x00 }, + { 0x3A30, 0x54 }, + { 0x3A31, 0x00 }, + { 0x3A32, 0x25 }, + { 0x3A33, 0x00 }, + { 0x3A34, 0x8D }, + { 0x3A35, 0x01 }, + { 0x3A36, 0xE1 }, + { 0x3A37, 0x00 }, + { 0x3A38, 0x76 }, + { 0x3A39, 0x00 }, + { 0x3A3A, 0x35 }, + { 0x3A3B, 0x00 }, + { 0x3A3C, 0x00 }, + { 0x3A3D, 0x01 }, + { 0x3A3E, 0x00 }, + { 0x3A3F, 0x01 }, + { 0x3A40, 0x00 }, + { 0x3A41, 0x01 }, + { 0x3A42, 0x00 }, + { 0x3A43, 0x01 }, + { 0x3A44, 0x70 }, + { 0x3A45, 0x00 }, + { 0x3A46, 0x25 }, + { 0x3A47, 0x00 }, + { 0x3A48, 0x18 }, + { 0x3A49, 0x00 }, + { 0x3A4A, 0x10 }, + { 0x3A4B, 0x00 }, + { 0x3A4C, 0xE6 }, + { 0x3A4D, 0x00 }, + { 0x3A4E, 0xD5 }, + { 0x3A4F, 0x00 }, + { 0x3A50, 0xAA }, + { 0x3A51, 0x00 }, + { 0x3A52, 0x85 }, + { 0x3A53, 0x00 }, + { 0x3A54, 0xE6 }, + { 0x3A55, 0x00 }, + { 0x3A56, 0xD5 }, + { 0x3A57, 0x00 }, + { 0x3A58, 0xAA }, + { 0x3A59, 0x00 }, + { 0x3A5A, 0x85 }, + { 0x3A5B, 0x00 }, + { 0x3A5C, 0xE6 }, + { 0x3A5D, 0x00 }, + { 0x3A5E, 0xD5 }, + { 0x3A5F, 0x00 }, + { 0x3A60, 0xAA }, + { 0x3A61, 0x00 }, + { 0x3A62, 0x85 }, + { 0x3A63, 0x00 }, + { 0x3A64, 0x19 }, + { 0x3A65, 0x00 }, + { 0x3A66, 0x12 }, + { 0x3A67, 0x00 }, + { 0x3A68, 0x0D }, + { 0x3A69, 0x00 }, + { 0x3A6A, 0x07 }, + { 0x3A6B, 0x00 }, + { 0x3A6C, 0x0C }, + { 0x3A6D, 0x00 }, + { 0x3A6E, 0x07 }, + { 0x3A6F, 0x00 }, + { 0x3A70, 0x05 }, + { 0x3A71, 0x00 }, + { 0x3A72, 0x04 }, + { 0x3A73, 0x00 }, + { 0x3A74, 0x1B }, + { 0x3A75, 0x00 }, + { 0x3A76, 0x15 }, + { 0x3A77, 0x00 }, + { 0x3A78, 0x0C }, + { 0x3A79, 0x00 }, + { 0x3A7A, 0x08 }, + { 0x3A7B, 0x00 }, + { 0x3A7C, 0x80 }, + { 0x3A7D, 0x00 }, + { 0x3A7E, 0x80 }, + { 0x3A7F, 0x00 }, + { 0x3A80, 0x80 }, + { 0x3A81, 0x00 }, + { 0x3A82, 0x80 }, + { 0x3A83, 0x00 }, + { 0x3A84, 0x09 }, + { 0x3A85, 0x00 }, + { 0x3A86, 0x06 }, + { 0x3A87, 0x00 }, + { 0x3A88, 0x04 }, + { 0x3A89, 0x00 }, + { 0x3A8A, 0x03 }, + { 0x3A8B, 0x00 }, + { 0x3A8C, 0xFA }, + { 0x3A8D, 0x00 }, + { 0x3A8E, 0xC8 }, + { 0x3A8F, 0x00 }, + { 0x3A90, 0x96 }, + { 0x3A91, 0x00 }, + { 0x3A92, 0x64 }, + { 0x3A93, 0x00 }, + { 0x3A94, 0xE1 }, + { 0x3A95, 0x00 }, + { 0x3A96, 0xC8 }, + { 0x3A97, 0x00 }, + { 0x3A98, 0x96 }, + { 0x3A99, 0x00 }, + { 0x3A9A, 0x64 }, + { 0x3A9B, 0x00 }, + { 0x3A9C, 0x08 }, + { 0x3A9D, 0x10 }, + { 0x3A9E, 0x4C }, + { 0x3A9F, 0x4C }, + { 0x3AA0, 0x4C }, + { 0x3AA1, 0x04 }, + { 0x3AA2, 0x04 }, + { 0x3AC0, 0x01 }, + { 0x3AC4, 0x81 }, + { 0x3AC5, 0x00 }, + { 0x3AC6, 0x00 }, + { 0x3AC7, 0x00 }, + { 0x3AC8, 0x00 }, + { 0x3AC9, 0x00 }, + { 0x3ACA, 0x00 }, + { 0x3ACB, 0x00 }, + { 0x3ACC, 0x02 }, + { 0x3ACD, 0x00 }, + { 0x3ACE, 0x81 }, + { 0x3ACF, 0x00 }, + { 0x3AD0, 0x00 }, + { 0x3AD1, 0x00 }, + { 0x3AD2, 0xFD }, + { 0x3AD3, 0x03 }, + { 0x3AD4, 0x02 }, + { 0x3AD5, 0x00 }, + { 0x3AD6, 0x00 }, + { 0x3AD7, 0x00 }, + { 0x3AD8, 0x81 }, + { 0x3AD9, 0x00 }, + { 0x3ADA, 0xFD }, + { 0x3ADB, 0x03 }, + { 0x3ADC, 0xFF }, + { 0x3ADD, 0x03 }, + { 0x3ADE, 0x01 }, + { 0x3ADF, 0x00 }, + { 0x3AE0, 0x01 }, + { 0x3AE1, 0x00 }, + { 0x3AE2, 0x7E }, + { 0x3AE3, 0x00 }, + { 0x3AF4, 0x00 }, + { 0x3AF6, 0x40 }, + { 0x3AF7, 0x1E }, + { 0x3AF8, 0x00 }, + { 0x3AFA, 0x00 }, + { 0x3AFB, 0x00 }, + { 0x3AFC, 0x00 }, + { 0x3AFD, 0x00 }, + { 0x3AFE, 0x00 }, + { 0x3AFF, 0x00 }, + { 0x3B00, 0x00 }, + { 0x3B01, 0x00 }, + { 0x3B02, 0x00 }, + { 0x3B03, 0x00 }, + { 0x3B04, 0x00 }, + { 0x3B05, 0x00 }, + { 0x3B06, 0x00 }, + { 0x3B07, 0x00 }, + { 0x3B08, 0x00 }, + { 0x3B09, 0x00 }, + { 0x3B0A, 0x00 }, + { 0x3B0B, 0x00 }, + { 0x3B0C, 0x00 }, + { 0x3B0D, 0x00 }, + { 0x3B0E, 0x00 }, + { 0x3B0F, 0x00 }, + { 0x3B10, 0x00 }, + { 0x3B11, 0x00 }, + { 0x3B12, 0x00 }, + { 0x3B13, 0x00 }, + { 0x3B14, 0x00 }, + { 0x3B15, 0x00 }, + { 0x3B16, 0x00 }, + { 0x3B17, 0x00 }, + { 0x3B18, 0x00 }, + { 0x3B19, 0x00 }, + { 0x3B1A, 0x00 }, + { 0x3B1B, 0x00 }, + { 0x3B1C, 0x00 }, + { 0x3B1D, 0x00 }, + { 0x3B1E, 0x00 }, + { 0x3B1F, 0x00 }, + { 0x3B20, 0x00 }, + { 0x3B21, 0x00 }, + { 0x3B22, 0x00 }, + { 0x3B23, 0x00 }, + { 0x3B24, 0x00 }, + { 0x3B25, 0x00 }, + { 0x3B26, 0x00 }, + { 0x3B27, 0x00 }, + { 0x3B28, 0x00 }, + { 0x3B29, 0x00 }, + { 0x3B2A, 0x00 }, + { 0x3B2C, 0x00 }, + { 0x3B2E, 0x00 }, + { 0x3B30, 0x00 }, + { 0x3B32, 0x0C }, + { 0x4000, 0xAF }, + { 0x4001, 0xA7 }, + { 0x4002, 0xA8 }, + { 0x4003, 0xA5 }, + { 0x4004, 0x98 }, + { 0x4005, 0x93 }, + { 0x4006, 0x94 }, + { 0x4007, 0x93 }, + { 0x4008, 0x8E }, + { 0x4009, 0x8C }, + { 0x400A, 0x8C }, + { 0x400B, 0x8C }, + { 0x400C, 0x89 }, + { 0x400D, 0x88 }, + { 0x400E, 0x89 }, + { 0x400F, 0x89 }, + { 0x4010, 0x87 }, + { 0x4011, 0x87 }, + { 0x4012, 0x87 }, + { 0x4013, 0x86 }, + { 0x4014, 0x88 }, + { 0x4015, 0x87 }, + { 0x4016, 0x87 }, + { 0x4017, 0x87 }, + { 0x4018, 0x8B }, + { 0x4019, 0x89 }, + { 0x401A, 0x89 }, + { 0x401B, 0x8A }, + { 0x401C, 0x92 }, + { 0x401D, 0x8F }, + { 0x401E, 0x8F }, + { 0x401F, 0x8F }, + { 0x4020, 0xA2 }, + { 0x4021, 0x9C }, + { 0x4022, 0x9B }, + { 0x4023, 0x9C }, + { 0x4024, 0xA1 }, + { 0x4025, 0x9A }, + { 0x4026, 0x9B }, + { 0x4027, 0x99 }, + { 0x4028, 0x94 }, + { 0x4029, 0x90 }, + { 0x402A, 0x90 }, + { 0x402B, 0x90 }, + { 0x402C, 0x8B }, + { 0x402D, 0x89 }, + { 0x402E, 0x89 }, + { 0x402F, 0x89 }, + { 0x4030, 0x86 }, + { 0x4031, 0x85 }, + { 0x4032, 0x86 }, + { 0x4033, 0x85 }, + { 0x4034, 0x84 }, + { 0x4035, 0x84 }, + { 0x4036, 0x84 }, + { 0x4037, 0x84 }, + { 0x4038, 0x85 }, + { 0x4039, 0x85 }, + { 0x403A, 0x85 }, + { 0x403B, 0x85 }, + { 0x403C, 0x88 }, + { 0x403D, 0x87 }, + { 0x403E, 0x87 }, + { 0x403F, 0x87 }, + { 0x4040, 0x8E }, + { 0x4041, 0x8C }, + { 0x4042, 0x8C }, + { 0x4043, 0x8C }, + { 0x4044, 0x98 }, + { 0x4045, 0x93 }, + { 0x4046, 0x93 }, + { 0x4047, 0x94 }, + { 0x4048, 0x9D }, + { 0x4049, 0x96 }, + { 0x404A, 0x97 }, + { 0x404B, 0x96 }, + { 0x404C, 0x91 }, + { 0x404D, 0x8C }, + { 0x404E, 0x8D }, + { 0x404F, 0x8C }, + { 0x4050, 0x89 }, + { 0x4051, 0x86 }, + { 0x4052, 0x87 }, + { 0x4053, 0x86 }, + { 0x4054, 0x83 }, + { 0x4055, 0x82 }, + { 0x4056, 0x82 }, + { 0x4057, 0x82 }, + { 0x4058, 0x80 }, + { 0x4059, 0x80 }, + { 0x405A, 0x80 }, + { 0x405B, 0x80 }, + { 0x405C, 0x82 }, + { 0x405D, 0x82 }, + { 0x405E, 0x82 }, + { 0x405F, 0x82 }, + { 0x4060, 0x86 }, + { 0x4061, 0x85 }, + { 0x4062, 0x85 }, + { 0x4063, 0x85 }, + { 0x4064, 0x8B }, + { 0x4065, 0x8A }, + { 0x4066, 0x89 }, + { 0x4067, 0x89 }, + { 0x4068, 0x94 }, + { 0x4069, 0x91 }, + { 0x406A, 0x90 }, + { 0x406B, 0x91 }, + { 0x406C, 0x9E }, + { 0x406D, 0x95 }, + { 0x406E, 0x96 }, + { 0x406F, 0x95 }, + { 0x4070, 0x91 }, + { 0x4071, 0x8C }, + { 0x4072, 0x8C }, + { 0x4073, 0x8C }, + { 0x4074, 0x89 }, + { 0x4075, 0x86 }, + { 0x4076, 0x86 }, + { 0x4077, 0x86 }, + { 0x4078, 0x83 }, + { 0x4079, 0x82 }, + { 0x407A, 0x82 }, + { 0x407B, 0x82 }, + { 0x407C, 0x80 }, + { 0x407D, 0x80 }, + { 0x407E, 0x80 }, + { 0x407F, 0x80 }, + { 0x4080, 0x82 }, + { 0x4081, 0x81 }, + { 0x4082, 0x81 }, + { 0x4083, 0x81 }, + { 0x4084, 0x85 }, + { 0x4085, 0x85 }, + { 0x4086, 0x85 }, + { 0x4087, 0x84 }, + { 0x4088, 0x8B }, + { 0x4089, 0x8A }, + { 0x408A, 0x89 }, + { 0x408B, 0x89 }, + { 0x408C, 0x93 }, + { 0x408D, 0x90 }, + { 0x408E, 0x8F }, + { 0x408F, 0x8F }, + { 0x4090, 0xA3 }, + { 0x4091, 0x99 }, + { 0x4092, 0x9A }, + { 0x4093, 0x99 }, + { 0x4094, 0x95 }, + { 0x4095, 0x8F }, + { 0x4096, 0x8F }, + { 0x4097, 0x8F }, + { 0x4098, 0x8B }, + { 0x4099, 0x87 }, + { 0x409A, 0x87 }, + { 0x409B, 0x87 }, + { 0x409C, 0x86 }, + { 0x409D, 0x84 }, + { 0x409E, 0x84 }, + { 0x409F, 0x84 }, + { 0x40A0, 0x84 }, + { 0x40A1, 0x83 }, + { 0x40A2, 0x83 }, + { 0x40A3, 0x82 }, + { 0x40A4, 0x84 }, + { 0x40A5, 0x84 }, + { 0x40A6, 0x83 }, + { 0x40A7, 0x83 }, + { 0x40A8, 0x88 }, + { 0x40A9, 0x87 }, + { 0x40AA, 0x86 }, + { 0x40AB, 0x86 }, + { 0x40AC, 0x8E }, + { 0x40AD, 0x8C }, + { 0x40AE, 0x8C }, + { 0x40AF, 0x8B }, + { 0x40B0, 0x9A }, + { 0x40B1, 0x96 }, + { 0x40B2, 0x96 }, + { 0x40B3, 0x95 }, + { 0x40B4, 0xBA }, + { 0x40B5, 0xAC }, + { 0x40B6, 0xAD }, + { 0x40B7, 0xAC }, + { 0x40B8, 0x99 }, + { 0x40B9, 0x90 }, + { 0x40BA, 0x91 }, + { 0x40BB, 0x90 }, + { 0x40BC, 0x90 }, + { 0x40BD, 0x8A }, + { 0x40BE, 0x8A }, + { 0x40BF, 0x8A }, + { 0x40C0, 0x89 }, + { 0x40C1, 0x86 }, + { 0x40C2, 0x86 }, + { 0x40C3, 0x87 }, + { 0x40C4, 0x87 }, + { 0x40C5, 0x85 }, + { 0x40C6, 0x85 }, + { 0x40C7, 0x85 }, + { 0x40C8, 0x87 }, + { 0x40C9, 0x86 }, + { 0x40CA, 0x85 }, + { 0x40CB, 0x85 }, + { 0x40CC, 0x8A }, + { 0x40CD, 0x88 }, + { 0x40CE, 0x88 }, + { 0x40CF, 0x87 }, + { 0x40D0, 0x92 }, + { 0x40D1, 0x8F }, + { 0x40D2, 0x8E }, + { 0x40D3, 0x8E }, + { 0x40D4, 0xA2 }, + { 0x40D5, 0x9D }, + { 0x40D6, 0x9D }, + { 0x40D7, 0x9B }, + { 0x4100, 0x80 }, + { 0x4101, 0x80 }, + { 0x4102, 0x80 }, + { 0x4103, 0x80 }, + { 0x4104, 0x80 }, + { 0x4105, 0x80 }, + { 0x4106, 0x80 }, + { 0x4107, 0x80 }, + { 0x4108, 0x80 }, + { 0x4109, 0x80 }, + { 0x410A, 0x80 }, + { 0x410B, 0x80 }, + { 0x410C, 0x80 }, + { 0x410D, 0x80 }, + { 0x410E, 0x80 }, + { 0x410F, 0x80 }, + { 0x4110, 0x80 }, + { 0x4111, 0x80 }, + { 0x4112, 0x80 }, + { 0x4113, 0x80 }, + { 0x4114, 0x80 }, + { 0x4115, 0x80 }, + { 0x4116, 0x80 }, + { 0x4117, 0x80 }, + { 0x4118, 0x80 }, + { 0x4119, 0x80 }, + { 0x411A, 0x80 }, + { 0x411B, 0x80 }, + { 0x411C, 0x80 }, + { 0x411D, 0x80 }, + { 0x411E, 0x80 }, + { 0x411F, 0x80 }, + { 0x4120, 0x80 }, + { 0x4121, 0x80 }, + { 0x4122, 0x80 }, + { 0x4123, 0x80 }, + { 0x4124, 0x80 }, + { 0x4125, 0x80 }, + { 0x4126, 0x80 }, + { 0x4127, 0x80 }, + { 0x4128, 0x80 }, + { 0x4129, 0x80 }, + { 0x412A, 0x80 }, + { 0x412B, 0x80 }, + { 0x412C, 0x80 }, + { 0x412D, 0x80 }, + { 0x412E, 0x80 }, + { 0x412F, 0x80 }, + { 0x4130, 0x80 }, + { 0x4131, 0x80 }, + { 0x4132, 0x80 }, + { 0x4133, 0x80 }, + { 0x4134, 0x80 }, + { 0x4135, 0x80 }, + { 0x4136, 0x80 }, + { 0x4137, 0x80 }, + { 0x4138, 0x80 }, + { 0x4139, 0x80 }, + { 0x413A, 0x80 }, + { 0x413B, 0x80 }, + { 0x413C, 0x80 }, + { 0x413D, 0x80 }, + { 0x413E, 0x80 }, + { 0x413F, 0x80 }, + { 0x4140, 0x80 }, + { 0x4141, 0x80 }, + { 0x4142, 0x80 }, + { 0x4143, 0x80 }, + { 0x4144, 0x80 }, + { 0x4145, 0x80 }, + { 0x4146, 0x80 }, + { 0x4147, 0x80 }, + { 0x4148, 0x80 }, + { 0x4149, 0x80 }, + { 0x414A, 0x80 }, + { 0x414B, 0x80 }, + { 0x414C, 0x80 }, + { 0x414D, 0x80 }, + { 0x414E, 0x80 }, + { 0x414F, 0x80 }, + { 0x4150, 0x80 }, + { 0x4151, 0x80 }, + { 0x4152, 0x80 }, + { 0x4153, 0x80 }, + { 0x4154, 0x80 }, + { 0x4155, 0x80 }, + { 0x4156, 0x80 }, + { 0x4157, 0x80 }, + { 0x4158, 0x80 }, + { 0x4159, 0x80 }, + { 0x415A, 0x80 }, + { 0x415B, 0x80 }, + { 0x415C, 0x80 }, + { 0x415D, 0x80 }, + { 0x415E, 0x80 }, + { 0x415F, 0x80 }, + { 0x4160, 0x80 }, + { 0x4161, 0x80 }, + { 0x4162, 0x80 }, + { 0x4163, 0x80 }, + { 0x4164, 0x80 }, + { 0x4165, 0x80 }, + { 0x4166, 0x80 }, + { 0x4167, 0x80 }, + { 0x4168, 0x80 }, + { 0x4169, 0x80 }, + { 0x416A, 0x80 }, + { 0x416B, 0x80 }, + { 0x416C, 0x80 }, + { 0x416D, 0x80 }, + { 0x416E, 0x80 }, + { 0x416F, 0x80 }, + { 0x4170, 0x80 }, + { 0x4171, 0x80 }, + { 0x4172, 0x80 }, + { 0x4173, 0x80 }, + { 0x4174, 0x80 }, + { 0x4175, 0x80 }, + { 0x4176, 0x80 }, + { 0x4177, 0x80 }, + { 0x4178, 0x80 }, + { 0x4179, 0x80 }, + { 0x417A, 0x80 }, + { 0x417B, 0x80 }, + { 0x417C, 0x80 }, + { 0x417D, 0x80 }, + { 0x417E, 0x80 }, + { 0x417F, 0x80 }, + { 0x4180, 0x80 }, + { 0x4181, 0x80 }, + { 0x4182, 0x80 }, + { 0x4183, 0x80 }, + { 0x4184, 0x80 }, + { 0x4185, 0x80 }, + { 0x4186, 0x80 }, + { 0x4187, 0x80 }, + { 0x4188, 0x80 }, + { 0x4189, 0x80 }, + { 0x418A, 0x80 }, + { 0x418B, 0x80 }, + { 0x418C, 0x80 }, + { 0x418D, 0x80 }, + { 0x418E, 0x80 }, + { 0x418F, 0x80 }, + { 0x4190, 0x80 }, + { 0x4191, 0x80 }, + { 0x4192, 0x80 }, + { 0x4193, 0x80 }, + { 0x4194, 0x80 }, + { 0x4195, 0x80 }, + { 0x4196, 0x80 }, + { 0x4197, 0x80 }, + { 0x4198, 0x80 }, + { 0x4199, 0x80 }, + { 0x419A, 0x80 }, + { 0x419B, 0x80 }, + { 0x419C, 0x80 }, + { 0x419D, 0x80 }, + { 0x419E, 0x80 }, + { 0x419F, 0x80 }, + { 0x41A0, 0x80 }, + { 0x41A1, 0x80 }, + { 0x41A2, 0x80 }, + { 0x41A3, 0x80 }, + { 0x41A4, 0x80 }, + { 0x41A5, 0x80 }, + { 0x41A6, 0x80 }, + { 0x41A7, 0x80 }, + { 0x41A8, 0x80 }, + { 0x41A9, 0x80 }, + { 0x41AA, 0x80 }, + { 0x41AB, 0x80 }, + { 0x41AC, 0x80 }, + { 0x41AD, 0x80 }, + { 0x41AE, 0x80 }, + { 0x41AF, 0x80 }, + { 0x41B0, 0x80 }, + { 0x41B1, 0x80 }, + { 0x41B2, 0x80 }, + { 0x41B3, 0x80 }, + { 0x41B4, 0x80 }, + { 0x41B5, 0x80 }, + { 0x41B6, 0x80 }, + { 0x41B7, 0x80 }, + { 0x41B8, 0x80 }, + { 0x41B9, 0x80 }, + { 0x41BA, 0x80 }, + { 0x41BB, 0x80 }, + { 0x41BC, 0x80 }, + { 0x41BD, 0x80 }, + { 0x41BE, 0x80 }, + { 0x41BF, 0x80 }, + { 0x41C0, 0x80 }, + { 0x41C1, 0x80 }, + { 0x41C2, 0x80 }, + { 0x41C3, 0x80 }, + { 0x41C4, 0x80 }, + { 0x41C5, 0x80 }, + { 0x41C6, 0x80 }, + { 0x41C7, 0x80 }, + { 0x41C8, 0x80 }, + { 0x41C9, 0x80 }, + { 0x41CA, 0x80 }, + { 0x41CB, 0x80 }, + { 0x41CC, 0x80 }, + { 0x41CD, 0x80 }, + { 0x41CE, 0x80 }, + { 0x41CF, 0x80 }, + { 0x41D0, 0x80 }, + { 0x41D1, 0x80 }, + { 0x41D2, 0x80 }, + { 0x41D3, 0x80 }, + { 0x41D4, 0x80 }, + { 0x41D5, 0x80 }, + { 0x41D6, 0x80 }, + { 0x41D7, 0x80 }, + { 0x4200, 0x80 }, + { 0x4201, 0x80 }, + { 0x4202, 0x80 }, + { 0x4203, 0x80 }, + { 0x4204, 0x80 }, + { 0x4205, 0x80 }, + { 0x4206, 0x80 }, + { 0x4207, 0x80 }, + { 0x4208, 0x80 }, + { 0x4209, 0x80 }, + { 0x420A, 0x80 }, + { 0x420B, 0x80 }, + { 0x420C, 0x80 }, + { 0x420D, 0x80 }, + { 0x420E, 0x80 }, + { 0x420F, 0x80 }, + { 0x4210, 0x80 }, + { 0x4211, 0x80 }, + { 0x4212, 0x80 }, + { 0x4213, 0x80 }, + { 0x4214, 0x80 }, + { 0x4215, 0x80 }, + { 0x4216, 0x80 }, + { 0x4217, 0x80 }, + { 0x4218, 0x80 }, + { 0x4219, 0x80 }, + { 0x421A, 0x80 }, + { 0x421B, 0x80 }, + { 0x421C, 0x80 }, + { 0x421D, 0x80 }, + { 0x421E, 0x80 }, + { 0x421F, 0x80 }, + { 0x4220, 0x80 }, + { 0x4221, 0x80 }, + { 0x4222, 0x80 }, + { 0x4223, 0x80 }, + { 0x4224, 0x80 }, + { 0x4225, 0x80 }, + { 0x4226, 0x80 }, + { 0x4227, 0x80 }, + { 0x4228, 0x80 }, + { 0x4229, 0x80 }, + { 0x422A, 0x80 }, + { 0x422B, 0x80 }, + { 0x422C, 0x80 }, + { 0x422D, 0x80 }, + { 0x422E, 0x80 }, + { 0x422F, 0x80 }, + { 0x4230, 0x80 }, + { 0x4231, 0x80 }, + { 0x4232, 0x80 }, + { 0x4233, 0x80 }, + { 0x4234, 0x80 }, + { 0x4235, 0x80 }, + { 0x4236, 0x80 }, + { 0x4237, 0x80 }, + { 0x4238, 0x80 }, + { 0x4239, 0x80 }, + { 0x423A, 0x80 }, + { 0x423B, 0x80 }, + { 0x423C, 0x80 }, + { 0x423D, 0x80 }, + { 0x423E, 0x80 }, + { 0x423F, 0x80 }, + { 0x4240, 0x80 }, + { 0x4241, 0x80 }, + { 0x4242, 0x80 }, + { 0x4243, 0x80 }, + { 0x4244, 0x80 }, + { 0x4245, 0x80 }, + { 0x4246, 0x80 }, + { 0x4247, 0x80 }, + { 0x4248, 0x80 }, + { 0x4249, 0x80 }, + { 0x424A, 0x80 }, + { 0x424B, 0x80 }, + { 0x424C, 0x80 }, + { 0x424D, 0x80 }, + { 0x424E, 0x80 }, + { 0x424F, 0x80 }, + { 0x4250, 0x80 }, + { 0x4251, 0x80 }, + { 0x4252, 0x80 }, + { 0x4253, 0x80 }, + { 0x4254, 0x80 }, + { 0x4255, 0x80 }, + { 0x4256, 0x80 }, + { 0x4257, 0x80 }, + { 0x4258, 0x80 }, + { 0x4259, 0x80 }, + { 0x425A, 0x80 }, + { 0x425B, 0x80 }, + { 0x425C, 0x80 }, + { 0x425D, 0x80 }, + { 0x425E, 0x80 }, + { 0x425F, 0x80 }, + { 0x4260, 0x80 }, + { 0x4261, 0x80 }, + { 0x4262, 0x80 }, + { 0x4263, 0x80 }, + { 0x4264, 0x80 }, + { 0x4265, 0x80 }, + { 0x4266, 0x80 }, + { 0x4267, 0x80 }, + { 0x4268, 0x80 }, + { 0x4269, 0x80 }, + { 0x426A, 0x80 }, + { 0x426B, 0x80 }, + { 0x426C, 0x80 }, + { 0x426D, 0x80 }, + { 0x426E, 0x80 }, + { 0x426F, 0x80 }, + { 0x4270, 0x80 }, + { 0x4271, 0x80 }, + { 0x4272, 0x80 }, + { 0x4273, 0x80 }, + { 0x4274, 0x80 }, + { 0x4275, 0x80 }, + { 0x4276, 0x80 }, + { 0x4277, 0x80 }, + { 0x4278, 0x80 }, + { 0x4279, 0x80 }, + { 0x427A, 0x80 }, + { 0x427B, 0x80 }, + { 0x427C, 0x80 }, + { 0x427D, 0x80 }, + { 0x427E, 0x80 }, + { 0x427F, 0x80 }, + { 0x4280, 0x80 }, + { 0x4281, 0x80 }, + { 0x4282, 0x80 }, + { 0x4283, 0x80 }, + { 0x4284, 0x80 }, + { 0x4285, 0x80 }, + { 0x4286, 0x80 }, + { 0x4287, 0x80 }, + { 0x4288, 0x80 }, + { 0x4289, 0x80 }, + { 0x428A, 0x80 }, + { 0x428B, 0x80 }, + { 0x428C, 0x80 }, + { 0x428D, 0x80 }, + { 0x428E, 0x80 }, + { 0x428F, 0x80 }, + { 0x4290, 0x80 }, + { 0x4291, 0x80 }, + { 0x4292, 0x80 }, + { 0x4293, 0x80 }, + { 0x4294, 0x80 }, + { 0x4295, 0x80 }, + { 0x4296, 0x80 }, + { 0x4297, 0x80 }, + { 0x4298, 0x80 }, + { 0x4299, 0x80 }, + { 0x429A, 0x80 }, + { 0x429B, 0x80 }, + { 0x429C, 0x80 }, + { 0x429D, 0x80 }, + { 0x429E, 0x80 }, + { 0x429F, 0x80 }, + { 0x42A0, 0x80 }, + { 0x42A1, 0x80 }, + { 0x42A2, 0x80 }, + { 0x42A3, 0x80 }, + { 0x42A4, 0x80 }, + { 0x42A5, 0x80 }, + { 0x42A6, 0x80 }, + { 0x42A7, 0x80 }, + { 0x42A8, 0x80 }, + { 0x42A9, 0x80 }, + { 0x42AA, 0x80 }, + { 0x42AB, 0x80 }, + { 0x42AC, 0x80 }, + { 0x42AD, 0x80 }, + { 0x42AE, 0x80 }, + { 0x42AF, 0x80 }, + { 0x42B0, 0x80 }, + { 0x42B1, 0x80 }, + { 0x42B2, 0x80 }, + { 0x42B3, 0x80 }, + { 0x42B4, 0x80 }, + { 0x42B5, 0x80 }, + { 0x42B6, 0x80 }, + { 0x42B7, 0x80 }, + { 0x42B8, 0x80 }, + { 0x42B9, 0x80 }, + { 0x42BA, 0x80 }, + { 0x42BB, 0x80 }, + { 0x42BC, 0x80 }, + { 0x42BD, 0x80 }, + { 0x42BE, 0x80 }, + { 0x42BF, 0x80 }, + { 0x42C0, 0x80 }, + { 0x42C1, 0x80 }, + { 0x42C2, 0x80 }, + { 0x42C3, 0x80 }, + { 0x42C4, 0x80 }, + { 0x42C5, 0x80 }, + { 0x42C6, 0x80 }, + { 0x42C7, 0x80 }, + { 0x42C8, 0x80 }, + { 0x42C9, 0x80 }, + { 0x42CA, 0x80 }, + { 0x42CB, 0x80 }, + { 0x42CC, 0x80 }, + { 0x42CD, 0x80 }, + { 0x42CE, 0x80 }, + { 0x42CF, 0x80 }, + { 0x42D0, 0x80 }, + { 0x42D1, 0x80 }, + { 0x42D2, 0x80 }, + { 0x42D3, 0x80 }, + { 0x42D4, 0x80 }, + { 0x42D5, 0x80 }, + { 0x42D6, 0x80 }, + { 0x42D7, 0x80 }, + { 0x42D8, 0x00 }, + { 0x42D9, 0x00 }, + { 0x4300, 0xA2 }, + { 0x4301, 0xAA }, + { 0x4302, 0xA7 }, + { 0x4303, 0xAD }, + { 0x4304, 0x8E }, + { 0x4305, 0x92 }, + { 0x4306, 0x90 }, + { 0x4307, 0x93 }, + { 0x4308, 0x86 }, + { 0x4309, 0x89 }, + { 0x430A, 0x87 }, + { 0x430B, 0x88 }, + { 0x430C, 0x82 }, + { 0x430D, 0x84 }, + { 0x430E, 0x83 }, + { 0x430F, 0x84 }, + { 0x4310, 0x80 }, + { 0x4311, 0x82 }, + { 0x4312, 0x82 }, + { 0x4313, 0x82 }, + { 0x4314, 0x83 }, + { 0x4315, 0x85 }, + { 0x4316, 0x84 }, + { 0x4317, 0x85 }, + { 0x4318, 0x8D }, + { 0x4319, 0x8D }, + { 0x431A, 0x8D }, + { 0x431B, 0x8D }, + { 0x431C, 0x99 }, + { 0x431D, 0x9A }, + { 0x431E, 0x9A }, + { 0x431F, 0x9A }, + { 0x4320, 0xAE }, + { 0x4321, 0xB4 }, + { 0x4322, 0xB4 }, + { 0x4323, 0xB5 }, + { 0x4324, 0x9A }, + { 0x4325, 0x9D }, + { 0x4326, 0x9B }, + { 0x4327, 0x9E }, + { 0x4328, 0x8C }, + { 0x4329, 0x8F }, + { 0x432A, 0x8D }, + { 0x432B, 0x8F }, + { 0x432C, 0x83 }, + { 0x432D, 0x85 }, + { 0x432E, 0x85 }, + { 0x432F, 0x85 }, + { 0x4330, 0x80 }, + { 0x4331, 0x81 }, + { 0x4332, 0x81 }, + { 0x4333, 0x81 }, + { 0x4334, 0x80 }, + { 0x4335, 0x80 }, + { 0x4336, 0x80 }, + { 0x4337, 0x81 }, + { 0x4338, 0x83 }, + { 0x4339, 0x83 }, + { 0x433A, 0x83 }, + { 0x433B, 0x83 }, + { 0x433C, 0x88 }, + { 0x433D, 0x88 }, + { 0x433E, 0x88 }, + { 0x433F, 0x88 }, + { 0x4340, 0x93 }, + { 0x4341, 0x93 }, + { 0x4342, 0x93 }, + { 0x4343, 0x93 }, + { 0x4344, 0xA2 }, + { 0x4345, 0xA4 }, + { 0x4346, 0xA4 }, + { 0x4347, 0xA4 }, + { 0x4348, 0x97 }, + { 0x4349, 0x99 }, + { 0x434A, 0x97 }, + { 0x434B, 0x97 }, + { 0x434C, 0x89 }, + { 0x434D, 0x8C }, + { 0x434E, 0x8B }, + { 0x434F, 0x8A }, + { 0x4350, 0x81 }, + { 0x4351, 0x83 }, + { 0x4352, 0x83 }, + { 0x4353, 0x83 }, + { 0x4354, 0x7F }, + { 0x4355, 0x80 }, + { 0x4356, 0x80 }, + { 0x4357, 0x80 }, + { 0x4358, 0x7F }, + { 0x4359, 0x7F }, + { 0x435A, 0x7F }, + { 0x435B, 0x7F }, + { 0x435C, 0x82 }, + { 0x435D, 0x81 }, + { 0x435E, 0x81 }, + { 0x435F, 0x82 }, + { 0x4360, 0x86 }, + { 0x4361, 0x86 }, + { 0x4362, 0x86 }, + { 0x4363, 0x87 }, + { 0x4364, 0x8F }, + { 0x4365, 0x8F }, + { 0x4366, 0x8F }, + { 0x4367, 0x90 }, + { 0x4368, 0x9E }, + { 0x4369, 0x9E }, + { 0x436A, 0x9E }, + { 0x436B, 0x9F }, + { 0x436C, 0x99 }, + { 0x436D, 0x9B }, + { 0x436E, 0x9A }, + { 0x436F, 0x98 }, + { 0x4370, 0x8B }, + { 0x4371, 0x8D }, + { 0x4372, 0x8D }, + { 0x4373, 0x8B }, + { 0x4374, 0x83 }, + { 0x4375, 0x84 }, + { 0x4376, 0x84 }, + { 0x4377, 0x83 }, + { 0x4378, 0x80 }, + { 0x4379, 0x81 }, + { 0x437A, 0x81 }, + { 0x437B, 0x80 }, + { 0x437C, 0x81 }, + { 0x437D, 0x80 }, + { 0x437E, 0x80 }, + { 0x437F, 0x80 }, + { 0x4380, 0x83 }, + { 0x4381, 0x83 }, + { 0x4382, 0x83 }, + { 0x4383, 0x83 }, + { 0x4384, 0x88 }, + { 0x4385, 0x87 }, + { 0x4386, 0x87 }, + { 0x4387, 0x88 }, + { 0x4388, 0x91 }, + { 0x4389, 0x90 }, + { 0x438A, 0x90 }, + { 0x438B, 0x91 }, + { 0x438C, 0x9E }, + { 0x438D, 0x9E }, + { 0x438E, 0x9E }, + { 0x438F, 0xA0 }, + { 0x4390, 0xA0 }, + { 0x4391, 0xA2 }, + { 0x4392, 0xA2 }, + { 0x4393, 0xA0 }, + { 0x4394, 0x92 }, + { 0x4395, 0x94 }, + { 0x4396, 0x94 }, + { 0x4397, 0x91 }, + { 0x4398, 0x89 }, + { 0x4399, 0x8A }, + { 0x439A, 0x89 }, + { 0x439B, 0x88 }, + { 0x439C, 0x85 }, + { 0x439D, 0x85 }, + { 0x439E, 0x85 }, + { 0x439F, 0x84 }, + { 0x43A0, 0x85 }, + { 0x43A1, 0x84 }, + { 0x43A2, 0x84 }, + { 0x43A3, 0x84 }, + { 0x43A4, 0x88 }, + { 0x43A5, 0x86 }, + { 0x43A6, 0x86 }, + { 0x43A7, 0x87 }, + { 0x43A8, 0x8E }, + { 0x43A9, 0x8B }, + { 0x43AA, 0x8B }, + { 0x43AB, 0x8D }, + { 0x43AC, 0x97 }, + { 0x43AD, 0x96 }, + { 0x43AE, 0x96 }, + { 0x43AF, 0x98 }, + { 0x43B0, 0xA5 }, + { 0x43B1, 0xA5 }, + { 0x43B2, 0xA5 }, + { 0x43B3, 0xA9 }, + { 0x43B4, 0xB7 }, + { 0x43B5, 0xBB }, + { 0x43B6, 0xBB }, + { 0x43B7, 0xB8 }, + { 0x43B8, 0x9C }, + { 0x43B9, 0x9C }, + { 0x43BA, 0x9C }, + { 0x43BB, 0x9A }, + { 0x43BC, 0x92 }, + { 0x43BD, 0x92 }, + { 0x43BE, 0x92 }, + { 0x43BF, 0x8F }, + { 0x43C0, 0x8B }, + { 0x43C1, 0x8B }, + { 0x43C2, 0x8B }, + { 0x43C3, 0x89 }, + { 0x43C4, 0x8A }, + { 0x43C5, 0x89 }, + { 0x43C6, 0x89 }, + { 0x43C7, 0x88 }, + { 0x43C8, 0x8D }, + { 0x43C9, 0x8B }, + { 0x43CA, 0x8B }, + { 0x43CB, 0x8C }, + { 0x43CC, 0x94 }, + { 0x43CD, 0x91 }, + { 0x43CE, 0x92 }, + { 0x43CF, 0x93 }, + { 0x43D0, 0x9E }, + { 0x43D1, 0x9D }, + { 0x43D2, 0x9D }, + { 0x43D3, 0xA1 }, + { 0x43D4, 0xB2 }, + { 0x43D5, 0xB4 }, + { 0x43D6, 0xB5 }, + { 0x43D7, 0xBD }, + { 0x4400, 0x80 }, + { 0x4401, 0x80 }, + { 0x4402, 0x80 }, + { 0x4403, 0x80 }, + { 0x4404, 0x80 }, + { 0x4405, 0x80 }, + { 0x4406, 0x80 }, + { 0x4407, 0x80 }, + { 0x4408, 0x80 }, + { 0x4409, 0x80 }, + { 0x440A, 0x80 }, + { 0x440B, 0x80 }, + { 0x440C, 0x80 }, + { 0x440D, 0x80 }, + { 0x440E, 0x80 }, + { 0x440F, 0x80 }, + { 0x4410, 0x80 }, + { 0x4411, 0x80 }, + { 0x4412, 0x80 }, + { 0x4413, 0x80 }, + { 0x4414, 0x80 }, + { 0x4415, 0x80 }, + { 0x4416, 0x80 }, + { 0x4417, 0x80 }, + { 0x4418, 0x80 }, + { 0x4419, 0x80 }, + { 0x441A, 0x80 }, + { 0x441B, 0x80 }, + { 0x441C, 0x80 }, + { 0x441D, 0x80 }, + { 0x441E, 0x80 }, + { 0x441F, 0x80 }, + { 0x4420, 0x80 }, + { 0x4421, 0x80 }, + { 0x4422, 0x80 }, + { 0x4423, 0x80 }, + { 0x4424, 0x80 }, + { 0x4425, 0x80 }, + { 0x4426, 0x80 }, + { 0x4427, 0x80 }, + { 0x4428, 0x80 }, + { 0x4429, 0x80 }, + { 0x442A, 0x80 }, + { 0x442B, 0x80 }, + { 0x442C, 0x80 }, + { 0x442D, 0x80 }, + { 0x442E, 0x80 }, + { 0x442F, 0x80 }, + { 0x4430, 0x80 }, + { 0x4431, 0x80 }, + { 0x4432, 0x80 }, + { 0x4433, 0x80 }, + { 0x4434, 0x80 }, + { 0x4435, 0x80 }, + { 0x4436, 0x80 }, + { 0x4437, 0x80 }, + { 0x4438, 0x80 }, + { 0x4439, 0x80 }, + { 0x443A, 0x80 }, + { 0x443B, 0x80 }, + { 0x443C, 0x80 }, + { 0x443D, 0x80 }, + { 0x443E, 0x80 }, + { 0x443F, 0x80 }, + { 0x4440, 0x80 }, + { 0x4441, 0x80 }, + { 0x4442, 0x80 }, + { 0x4443, 0x80 }, + { 0x4444, 0x80 }, + { 0x4445, 0x80 }, + { 0x4446, 0x80 }, + { 0x4447, 0x80 }, + { 0x4448, 0x80 }, + { 0x4449, 0x80 }, + { 0x444A, 0x80 }, + { 0x444B, 0x80 }, + { 0x444C, 0x80 }, + { 0x444D, 0x80 }, + { 0x444E, 0x80 }, + { 0x444F, 0x80 }, + { 0x4450, 0x80 }, + { 0x4451, 0x80 }, + { 0x4452, 0x80 }, + { 0x4453, 0x80 }, + { 0x4454, 0x80 }, + { 0x4455, 0x80 }, + { 0x4456, 0x80 }, + { 0x4457, 0x80 }, + { 0x4458, 0x80 }, + { 0x4459, 0x80 }, + { 0x445A, 0x80 }, + { 0x445B, 0x80 }, + { 0x445C, 0x80 }, + { 0x445D, 0x80 }, + { 0x445E, 0x80 }, + { 0x445F, 0x80 }, + { 0x4460, 0x80 }, + { 0x4461, 0x80 }, + { 0x4462, 0x80 }, + { 0x4463, 0x80 }, + { 0x4464, 0x80 }, + { 0x4465, 0x80 }, + { 0x4466, 0x80 }, + { 0x4467, 0x80 }, + { 0x4468, 0x80 }, + { 0x4469, 0x80 }, + { 0x446A, 0x80 }, + { 0x446B, 0x80 }, + { 0x446C, 0x80 }, + { 0x446D, 0x80 }, + { 0x446E, 0x80 }, + { 0x446F, 0x80 }, + { 0x4470, 0x80 }, + { 0x4471, 0x80 }, + { 0x4472, 0x80 }, + { 0x4473, 0x80 }, + { 0x4474, 0x80 }, + { 0x4475, 0x80 }, + { 0x4476, 0x80 }, + { 0x4477, 0x80 }, + { 0x4478, 0x80 }, + { 0x4479, 0x80 }, + { 0x447A, 0x80 }, + { 0x447B, 0x80 }, + { 0x447C, 0x80 }, + { 0x447D, 0x80 }, + { 0x447E, 0x80 }, + { 0x447F, 0x80 }, + { 0x4480, 0x80 }, + { 0x4481, 0x80 }, + { 0x4482, 0x80 }, + { 0x4483, 0x80 }, + { 0x4484, 0x80 }, + { 0x4485, 0x80 }, + { 0x4486, 0x80 }, + { 0x4487, 0x80 }, + { 0x4488, 0x80 }, + { 0x4489, 0x80 }, + { 0x448A, 0x80 }, + { 0x448B, 0x80 }, + { 0x448C, 0x80 }, + { 0x448D, 0x80 }, + { 0x448E, 0x80 }, + { 0x448F, 0x80 }, + { 0x4490, 0x80 }, + { 0x4491, 0x80 }, + { 0x4492, 0x80 }, + { 0x4493, 0x80 }, + { 0x4494, 0x80 }, + { 0x4495, 0x80 }, + { 0x4496, 0x80 }, + { 0x4497, 0x80 }, + { 0x4498, 0x80 }, + { 0x4499, 0x80 }, + { 0x449A, 0x80 }, + { 0x449B, 0x80 }, + { 0x449C, 0x80 }, + { 0x449D, 0x80 }, + { 0x449E, 0x80 }, + { 0x449F, 0x80 }, + { 0x44A0, 0x80 }, + { 0x44A1, 0x80 }, + { 0x44A2, 0x80 }, + { 0x44A3, 0x80 }, + { 0x44A4, 0x80 }, + { 0x44A5, 0x80 }, + { 0x44A6, 0x80 }, + { 0x44A7, 0x80 }, + { 0x44A8, 0x80 }, + { 0x44A9, 0x80 }, + { 0x44AA, 0x80 }, + { 0x44AB, 0x80 }, + { 0x44AC, 0x80 }, + { 0x44AD, 0x80 }, + { 0x44AE, 0x80 }, + { 0x44AF, 0x80 }, + { 0x44B0, 0x80 }, + { 0x44B1, 0x80 }, + { 0x44B2, 0x80 }, + { 0x44B3, 0x80 }, + { 0x44B4, 0x80 }, + { 0x44B5, 0x80 }, + { 0x44B6, 0x80 }, + { 0x44B7, 0x80 }, + { 0x44B8, 0x80 }, + { 0x44B9, 0x80 }, + { 0x44BA, 0x80 }, + { 0x44BB, 0x80 }, + { 0x44BC, 0x80 }, + { 0x44BD, 0x80 }, + { 0x44BE, 0x80 }, + { 0x44BF, 0x80 }, + { 0x44C0, 0x80 }, + { 0x44C1, 0x80 }, + { 0x44C2, 0x80 }, + { 0x44C3, 0x80 }, + { 0x44C4, 0x80 }, + { 0x44C5, 0x80 }, + { 0x44C6, 0x80 }, + { 0x44C7, 0x80 }, + { 0x44C8, 0x80 }, + { 0x44C9, 0x80 }, + { 0x44CA, 0x80 }, + { 0x44CB, 0x80 }, + { 0x44CC, 0x80 }, + { 0x44CD, 0x80 }, + { 0x44CE, 0x80 }, + { 0x44CF, 0x80 }, + { 0x44D0, 0x80 }, + { 0x44D1, 0x80 }, + { 0x44D2, 0x80 }, + { 0x44D3, 0x80 }, + { 0x44D4, 0x80 }, + { 0x44D5, 0x80 }, + { 0x44D6, 0x80 }, + { 0x44D7, 0x80 }, + { 0x4500, 0x80 }, + { 0x4501, 0x80 }, + { 0x4502, 0x80 }, + { 0x4503, 0x80 }, + { 0x4504, 0x80 }, + { 0x4505, 0x80 }, + { 0x4506, 0x80 }, + { 0x4507, 0x80 }, + { 0x4508, 0x80 }, + { 0x4509, 0x80 }, + { 0x450A, 0x80 }, + { 0x450B, 0x80 }, + { 0x450C, 0x80 }, + { 0x450D, 0x80 }, + { 0x450E, 0x80 }, + { 0x450F, 0x80 }, + { 0x4510, 0x80 }, + { 0x4511, 0x80 }, + { 0x4512, 0x80 }, + { 0x4513, 0x80 }, + { 0x4514, 0x80 }, + { 0x4515, 0x80 }, + { 0x4516, 0x80 }, + { 0x4517, 0x80 }, + { 0x4518, 0x80 }, + { 0x4519, 0x80 }, + { 0x451A, 0x80 }, + { 0x451B, 0x80 }, + { 0x451C, 0x80 }, + { 0x451D, 0x80 }, + { 0x451E, 0x80 }, + { 0x451F, 0x80 }, + { 0x4520, 0x80 }, + { 0x4521, 0x80 }, + { 0x4522, 0x80 }, + { 0x4523, 0x80 }, + { 0x4524, 0x80 }, + { 0x4525, 0x80 }, + { 0x4526, 0x80 }, + { 0x4527, 0x80 }, + { 0x4528, 0x80 }, + { 0x4529, 0x80 }, + { 0x452A, 0x80 }, + { 0x452B, 0x80 }, + { 0x452C, 0x80 }, + { 0x452D, 0x80 }, + { 0x452E, 0x80 }, + { 0x452F, 0x80 }, + { 0x4530, 0x80 }, + { 0x4531, 0x80 }, + { 0x4532, 0x80 }, + { 0x4533, 0x80 }, + { 0x4534, 0x80 }, + { 0x4535, 0x80 }, + { 0x4536, 0x80 }, + { 0x4537, 0x80 }, + { 0x4538, 0x80 }, + { 0x4539, 0x80 }, + { 0x453A, 0x80 }, + { 0x453B, 0x80 }, + { 0x453C, 0x80 }, + { 0x453D, 0x80 }, + { 0x453E, 0x80 }, + { 0x453F, 0x80 }, + { 0x4540, 0x80 }, + { 0x4541, 0x80 }, + { 0x4542, 0x80 }, + { 0x4543, 0x80 }, + { 0x4544, 0x80 }, + { 0x4545, 0x80 }, + { 0x4546, 0x80 }, + { 0x4547, 0x80 }, + { 0x4548, 0x80 }, + { 0x4549, 0x80 }, + { 0x454A, 0x80 }, + { 0x454B, 0x80 }, + { 0x454C, 0x80 }, + { 0x454D, 0x80 }, + { 0x454E, 0x80 }, + { 0x454F, 0x80 }, + { 0x4550, 0x80 }, + { 0x4551, 0x80 }, + { 0x4552, 0x80 }, + { 0x4553, 0x80 }, + { 0x4554, 0x80 }, + { 0x4555, 0x80 }, + { 0x4556, 0x80 }, + { 0x4557, 0x80 }, + { 0x4558, 0x80 }, + { 0x4559, 0x80 }, + { 0x455A, 0x80 }, + { 0x455B, 0x80 }, + { 0x455C, 0x80 }, + { 0x455D, 0x80 }, + { 0x455E, 0x80 }, + { 0x455F, 0x80 }, + { 0x4560, 0x80 }, + { 0x4561, 0x80 }, + { 0x4562, 0x80 }, + { 0x4563, 0x80 }, + { 0x4564, 0x80 }, + { 0x4565, 0x80 }, + { 0x4566, 0x80 }, + { 0x4567, 0x80 }, + { 0x4568, 0x80 }, + { 0x4569, 0x80 }, + { 0x456A, 0x80 }, + { 0x456B, 0x80 }, + { 0x456C, 0x80 }, + { 0x456D, 0x80 }, + { 0x456E, 0x80 }, + { 0x456F, 0x80 }, + { 0x4570, 0x80 }, + { 0x4571, 0x80 }, + { 0x4572, 0x80 }, + { 0x4573, 0x80 }, + { 0x4574, 0x80 }, + { 0x4575, 0x80 }, + { 0x4576, 0x80 }, + { 0x4577, 0x80 }, + { 0x4578, 0x80 }, + { 0x4579, 0x80 }, + { 0x457A, 0x80 }, + { 0x457B, 0x80 }, + { 0x457C, 0x80 }, + { 0x457D, 0x80 }, + { 0x457E, 0x80 }, + { 0x457F, 0x80 }, + { 0x4580, 0x80 }, + { 0x4581, 0x80 }, + { 0x4582, 0x80 }, + { 0x4583, 0x80 }, + { 0x4584, 0x80 }, + { 0x4585, 0x80 }, + { 0x4586, 0x80 }, + { 0x4587, 0x80 }, + { 0x4588, 0x80 }, + { 0x4589, 0x80 }, + { 0x458A, 0x80 }, + { 0x458B, 0x80 }, + { 0x458C, 0x80 }, + { 0x458D, 0x80 }, + { 0x458E, 0x80 }, + { 0x458F, 0x80 }, + { 0x4590, 0x80 }, + { 0x4591, 0x80 }, + { 0x4592, 0x80 }, + { 0x4593, 0x80 }, + { 0x4594, 0x80 }, + { 0x4595, 0x80 }, + { 0x4596, 0x80 }, + { 0x4597, 0x80 }, + { 0x4598, 0x80 }, + { 0x4599, 0x80 }, + { 0x459A, 0x80 }, + { 0x459B, 0x80 }, + { 0x459C, 0x80 }, + { 0x459D, 0x80 }, + { 0x459E, 0x80 }, + { 0x459F, 0x80 }, + { 0x45A0, 0x80 }, + { 0x45A1, 0x80 }, + { 0x45A2, 0x80 }, + { 0x45A3, 0x80 }, + { 0x45A4, 0x80 }, + { 0x45A5, 0x80 }, + { 0x45A6, 0x80 }, + { 0x45A7, 0x80 }, + { 0x45A8, 0x80 }, + { 0x45A9, 0x80 }, + { 0x45AA, 0x80 }, + { 0x45AB, 0x80 }, + { 0x45AC, 0x80 }, + { 0x45AD, 0x80 }, + { 0x45AE, 0x80 }, + { 0x45AF, 0x80 }, + { 0x45B0, 0x80 }, + { 0x45B1, 0x80 }, + { 0x45B2, 0x80 }, + { 0x45B3, 0x80 }, + { 0x45B4, 0x80 }, + { 0x45B5, 0x80 }, + { 0x45B6, 0x80 }, + { 0x45B7, 0x80 }, + { 0x45B8, 0x80 }, + { 0x45B9, 0x80 }, + { 0x45BA, 0x80 }, + { 0x45BB, 0x80 }, + { 0x45BC, 0x80 }, + { 0x45BD, 0x80 }, + { 0x45BE, 0x80 }, + { 0x45BF, 0x80 }, + { 0x45C0, 0x80 }, + { 0x45C1, 0x80 }, + { 0x45C2, 0x80 }, + { 0x45C3, 0x80 }, + { 0x45C4, 0x80 }, + { 0x45C5, 0x80 }, + { 0x45C6, 0x80 }, + { 0x45C7, 0x80 }, + { 0x45C8, 0x80 }, + { 0x45C9, 0x80 }, + { 0x45CA, 0x80 }, + { 0x45CB, 0x80 }, + { 0x45CC, 0x80 }, + { 0x45CD, 0x80 }, + { 0x45CE, 0x80 }, + { 0x45CF, 0x80 }, + { 0x45D0, 0x80 }, + { 0x45D1, 0x80 }, + { 0x45D2, 0x80 }, + { 0x45D3, 0x80 }, + { 0x45D4, 0x80 }, + { 0x45D5, 0x80 }, + { 0x45D6, 0x80 }, + { 0x45D7, 0x80 }, + { 0x7000, 0xAB }, + { 0x7001, 0xBA }, + { 0x7002, 0x40 }, + { 0x7003, 0x02 }, + { 0x7004, 0x00 }, + { 0x7005, 0x00 }, + { 0x7006, 0x00 }, + { 0x7007, 0x00 }, + { 0x7008, 0x00 }, + { 0x7009, 0x00 }, + { 0x700A, 0x00 }, + { 0x700B, 0x00 }, + { 0x700C, 0x00 }, + { 0x700D, 0x00 }, + { 0x700E, 0x00 }, + { 0x700F, 0x00 }, + { 0x7010, 0x55 }, + { 0x7011, 0x88 }, + { 0x7012, 0x40 }, + { 0x7013, 0x01 }, + { 0x7014, 0x72 }, + { 0x7015, 0xF1 }, + { 0x7016, 0x02 }, + { 0x7017, 0xF8 }, + { 0x7018, 0x00 }, + { 0x7019, 0x00 }, + { 0x701A, 0x00 }, + { 0x701B, 0x00 }, + { 0x701C, 0x00 }, + { 0x701D, 0x00 }, + { 0x701E, 0x00 }, + { 0x701F, 0x00 }, + { 0x7020, 0x00 }, + { 0x7021, 0x00 }, + { 0x7022, 0x00 }, + { 0x7023, 0x00 }, + { 0x7024, 0x00 }, + { 0x7025, 0x00 }, + { 0x7026, 0x00 }, + { 0x7027, 0x00 }, + { 0x7028, 0x00 }, + { 0x7029, 0x00 }, + { 0x702A, 0x00 }, + { 0x702B, 0x00 }, + { 0x702C, 0x00 }, + { 0x702D, 0x00 }, + { 0x702E, 0x00 }, + { 0x702F, 0x00 }, + { 0x7030, 0x00 }, + { 0x7031, 0x00 }, + { 0x7032, 0x00 }, + { 0x7033, 0x00 }, + { 0x7034, 0x00 }, + { 0x7035, 0x00 }, + { 0x7036, 0x00 }, + { 0x7037, 0x00 }, + { 0x7038, 0x00 }, + { 0x7039, 0x00 }, + { 0x703A, 0x00 }, + { 0x703B, 0x00 }, + { 0x703C, 0x00 }, + { 0x703D, 0x00 }, + { 0x703E, 0x00 }, + { 0x703F, 0x00 }, + { 0x7040, 0x00 }, + { 0x7041, 0x00 }, + { 0x7042, 0x00 }, + { 0x7043, 0x00 }, + { 0x7044, 0x00 }, + { 0x7045, 0x00 }, + { 0x7046, 0x00 }, + { 0x7047, 0x00 }, + { 0x7048, 0x00 }, + { 0x7049, 0x00 }, + { 0x704A, 0x00 }, + { 0x704B, 0x00 }, + { 0x704C, 0x00 }, + { 0x704D, 0x00 }, + { 0x704E, 0x00 }, + { 0x704F, 0x00 }, + { 0x7050, 0x00 }, + { 0x7051, 0x00 }, + { 0x7052, 0x00 }, + { 0x7053, 0x00 }, + { 0x7054, 0x00 }, + { 0x7055, 0x00 }, + { 0x7056, 0x00 }, + { 0x7057, 0x00 }, + { 0x7058, 0x00 }, + { 0x7059, 0x00 }, + { 0x705A, 0x00 }, + { 0x705B, 0x00 }, + { 0x705C, 0x00 }, + { 0x705D, 0x00 }, + { 0x705E, 0x00 }, + { 0x705F, 0x00 }, + { 0x7060, 0x00 }, + { 0x7061, 0x00 }, + { 0x7062, 0x00 }, + { 0x7063, 0x00 }, + { 0x7064, 0x00 }, + { 0x7065, 0x00 }, + { 0x7066, 0x00 }, + { 0x7067, 0x00 }, + { 0x7068, 0x00 }, + { 0x7069, 0x00 }, + { 0x706A, 0x00 }, + { 0x706B, 0x00 }, + { 0x706C, 0x00 }, + { 0x706D, 0x00 }, + { 0x706E, 0x00 }, + { 0x706F, 0x00 }, + { 0x7070, 0x00 }, + { 0x7071, 0x00 }, + { 0x7072, 0x00 }, + { 0x7073, 0x00 }, + { 0x7074, 0x00 }, + { 0x7075, 0x00 }, + { 0x7076, 0x00 }, + { 0x7077, 0x00 }, + { 0x7078, 0x00 }, + { 0x7079, 0x00 }, + { 0x707A, 0x00 }, + { 0x707B, 0x00 }, + { 0x707C, 0x00 }, + { 0x707D, 0x00 }, + { 0x707E, 0x00 }, + { 0x707F, 0x00 }, + { 0x7080, 0x00 }, + { 0x7081, 0x00 }, + { 0x7082, 0x00 }, + { 0x7083, 0x00 }, + { 0x7084, 0x00 }, + { 0x7085, 0x00 }, + { 0x7086, 0x00 }, + { 0x7087, 0x00 }, + { 0x7088, 0x00 }, + { 0x7089, 0x00 }, + { 0x708A, 0x00 }, + { 0x708B, 0x00 }, + { 0x708C, 0x00 }, + { 0x708D, 0x00 }, + { 0x708E, 0x00 }, + { 0x708F, 0x00 }, + { 0x7090, 0x00 }, + { 0x7091, 0xF0 }, + { 0x7092, 0x02 }, + { 0x7093, 0xF8 }, + { 0x7094, 0x8D }, + { 0x7095, 0xF6 }, + { 0x7096, 0xFA }, + { 0x7097, 0xFF }, + { 0x7098, 0xF0 }, + { 0x7099, 0xB5 }, + { 0x709A, 0x04 }, + { 0x709B, 0x46 }, + { 0x709C, 0x8F }, + { 0x709D, 0xB0 }, + { 0x709E, 0x5F }, + { 0x709F, 0x48 }, + { 0x70A0, 0x0C }, + { 0x70A1, 0x90 }, + { 0x70A2, 0x5F }, + { 0x70A3, 0x48 }, + { 0x70A4, 0x06 }, + { 0x70A5, 0x90 }, + { 0x70A6, 0x20 }, + { 0x70A7, 0x46 }, + { 0x70A8, 0x34 }, + { 0x70A9, 0x30 }, + { 0x70AA, 0x0B }, + { 0x70AB, 0x90 }, + { 0x70AC, 0x5B }, + { 0x70AD, 0x48 }, + { 0x70AE, 0x5A }, + { 0x70AF, 0x49 }, + { 0x70B0, 0x26 }, + { 0x70B1, 0x46 }, + { 0x70B2, 0x66 }, + { 0x70B3, 0x30 }, + { 0x70B4, 0x3A }, + { 0x70B5, 0x31 }, + { 0x70B6, 0x3C }, + { 0x70B7, 0x36 }, + { 0x70B8, 0x05 }, + { 0x70B9, 0x90 }, + { 0x70BA, 0x0A }, + { 0x70BB, 0x30 }, + { 0x70BC, 0x04 }, + { 0x70BD, 0x90 }, + { 0x70BE, 0x59 }, + { 0x70BF, 0x48 }, + { 0x70C0, 0x55 }, + { 0x70C1, 0x4A }, + { 0x70C2, 0x40 }, + { 0x70C3, 0x6E }, + { 0x70C4, 0xC0 }, + { 0x70C5, 0x07 }, + { 0x70C6, 0x7D }, + { 0x70C7, 0xD1 }, + { 0x70C8, 0x17 }, + { 0x70C9, 0x88 }, + { 0x70CA, 0x0A }, + { 0x70CB, 0x5E }, + { 0x70CC, 0x0D }, + { 0x70CD, 0x92 }, + { 0x70CE, 0x53 }, + { 0x70CF, 0x49 }, + { 0x70D0, 0x55 }, + { 0x70D1, 0x48 }, + { 0x70D2, 0x94 }, + { 0x70D3, 0x31 }, + { 0x70D4, 0x89 }, + { 0x70D5, 0x6B }, + { 0x70D6, 0x80 }, + { 0x70D7, 0x68 }, + { 0x70D8, 0x09 }, + { 0x70D9, 0x02 }, + { 0x70DA, 0x00 }, + { 0x70DB, 0x03 }, + { 0x70DC, 0x09 }, + { 0x70DD, 0x0E }, + { 0x70DE, 0x00 }, + { 0x70DF, 0x0B }, + { 0x70E0, 0x49 }, + { 0x70E1, 0x1C }, + { 0x70E2, 0x48 }, + { 0x70E3, 0x43 }, + { 0x70E4, 0x4D }, + { 0x70E5, 0x49 }, + { 0x70E6, 0x6C }, + { 0x70E7, 0x39 }, + { 0x70E8, 0x8A }, + { 0x70E9, 0x6A }, + { 0x70EA, 0x07 }, + { 0x70EB, 0x92 }, + { 0x70EC, 0xCA }, + { 0x70ED, 0x6A }, + { 0x70EE, 0x00 }, + { 0x70EF, 0x21 }, + { 0x70F0, 0xC9 }, + { 0x70F1, 0x43 }, + { 0x70F2, 0x03 }, + { 0x70F3, 0x92 }, + { 0x70F4, 0x00 }, + { 0x70F5, 0x22 }, + { 0x70F6, 0x00 }, + { 0x70F7, 0x91 }, + { 0x70F8, 0x01 }, + { 0x70F9, 0x92 }, + { 0x70FA, 0x39 }, + { 0x70FB, 0x46 }, + { 0x70FC, 0x8F }, + { 0x70FD, 0xF6 }, + { 0x70FE, 0xCE }, + { 0x70FF, 0xFB }, + { 0x7100, 0x01 }, + { 0x7101, 0x22 }, + { 0x7102, 0x00 }, + { 0x7103, 0x23 }, + { 0x7104, 0x8C }, + { 0x7105, 0xF6 }, + { 0x7106, 0x02 }, + { 0x7107, 0xFA }, + { 0x7108, 0x00 }, + { 0x7109, 0x21 }, + { 0x710A, 0x05 }, + { 0x710B, 0x46 }, + { 0x710C, 0x01 }, + { 0x710D, 0x91 }, + { 0x710E, 0x00 }, + { 0x710F, 0x90 }, + { 0x7110, 0x39 }, + { 0x7111, 0x46 }, + { 0x7112, 0x07 }, + { 0x7113, 0x98 }, + { 0x7114, 0x8F }, + { 0x7115, 0xF6 }, + { 0x7116, 0xC2 }, + { 0x7117, 0xFB }, + { 0x7118, 0x0D }, + { 0x7119, 0x9A }, + { 0x711A, 0xD3 }, + { 0x711B, 0x17 }, + { 0x711C, 0x80 }, + { 0x711D, 0x18 }, + { 0x711E, 0x59 }, + { 0x711F, 0x41 }, + { 0x7120, 0x01 }, + { 0x7121, 0x22 }, + { 0x7122, 0x00 }, + { 0x7123, 0x23 }, + { 0x7124, 0x8C }, + { 0x7125, 0xF6 }, + { 0x7126, 0xCD }, + { 0x7127, 0xF9 }, + { 0x7128, 0x07 }, + { 0x7129, 0x90 }, + { 0x712A, 0x00 }, + { 0x712B, 0x20 }, + { 0x712C, 0x01 }, + { 0x712D, 0x90 }, + { 0x712E, 0x00 }, + { 0x712F, 0x95 }, + { 0x7130, 0x39 }, + { 0x7131, 0x46 }, + { 0x7132, 0x03 }, + { 0x7133, 0x98 }, + { 0x7134, 0x8F }, + { 0x7135, 0xF6 }, + { 0x7136, 0xB2 }, + { 0x7137, 0xFB }, + { 0x7138, 0x01 }, + { 0x7139, 0x22 }, + { 0x713A, 0x00 }, + { 0x713B, 0x23 }, + { 0x713C, 0x8C }, + { 0x713D, 0xF6 }, + { 0x713E, 0xE6 }, + { 0x713F, 0xF9 }, + { 0x7140, 0x02 }, + { 0x7141, 0x46 }, + { 0x7142, 0x07 }, + { 0x7143, 0x98 }, + { 0x7144, 0x00 }, + { 0x7145, 0x23 }, + { 0x7146, 0x81 }, + { 0x7147, 0x0B }, + { 0x7148, 0x80 }, + { 0x7149, 0x04 }, + { 0x714A, 0x7A }, + { 0x714B, 0xF6 }, + { 0x714C, 0x54 }, + { 0x714D, 0xF8 }, + { 0x714E, 0x37 }, + { 0x714F, 0x4A }, + { 0x7150, 0x00 }, + { 0x7151, 0x23 }, + { 0x7152, 0x00 }, + { 0x7153, 0x92 }, + { 0x7154, 0x01 }, + { 0x7155, 0x93 }, + { 0x7156, 0x01 }, + { 0x7157, 0x22 }, + { 0x7158, 0x8C }, + { 0x7159, 0xF6 }, + { 0x715A, 0xD8 }, + { 0x715B, 0xF9 }, + { 0x715C, 0x05 }, + { 0x715D, 0x46 }, + { 0x715E, 0x60 }, + { 0x715F, 0x68 }, + { 0x7160, 0x00 }, + { 0x7161, 0x23 }, + { 0x7162, 0x01 }, + { 0x7163, 0x0C }, + { 0x7164, 0x00 }, + { 0x7165, 0x04 }, + { 0x7166, 0xE2 }, + { 0x7167, 0x68 }, + { 0x7168, 0x7A }, + { 0x7169, 0xF6 }, + { 0x716A, 0x45 }, + { 0x716B, 0xF8 }, + { 0x716C, 0x00 }, + { 0x716D, 0x22 }, + { 0x716E, 0xD2 }, + { 0x716F, 0x43 }, + { 0x7170, 0x00 }, + { 0x7171, 0x23 }, + { 0x7172, 0x00 }, + { 0x7173, 0x92 }, + { 0x7174, 0x01 }, + { 0x7175, 0x93 }, + { 0x7176, 0x1A }, + { 0x7177, 0x46 }, + { 0x7178, 0x8C }, + { 0x7179, 0xF6 }, + { 0x717A, 0xC8 }, + { 0x717B, 0xF9 }, + { 0x717C, 0x29 }, + { 0x717D, 0x46 }, + { 0x717E, 0x8F }, + { 0x717F, 0xF6 }, + { 0x7180, 0x8D }, + { 0x7181, 0xFB }, + { 0x7182, 0x8A }, + { 0x7183, 0x03 }, + { 0x7184, 0x80 }, + { 0x7185, 0x0C }, + { 0x7186, 0x10 }, + { 0x7187, 0x43 }, + { 0x7188, 0x00 }, + { 0x7189, 0x22 }, + { 0x718A, 0xD2 }, + { 0x718B, 0x43 }, + { 0x718C, 0x00 }, + { 0x718D, 0x23 }, + { 0x718E, 0x00 }, + { 0x718F, 0x92 }, + { 0x7190, 0x89 }, + { 0x7191, 0x0C }, + { 0x7192, 0x01 }, + { 0x7193, 0x93 }, + { 0x7194, 0x1A }, + { 0x7195, 0x46 }, + { 0x7196, 0x8C }, + { 0x7197, 0xF6 }, + { 0x7198, 0xB9 }, + { 0x7199, 0xF9 }, + { 0x719A, 0x00 }, + { 0x719B, 0x24 }, + { 0x719C, 0x03 }, + { 0x719D, 0x90 }, + { 0x719E, 0x0C }, + { 0x719F, 0x98 }, + { 0x71A0, 0x61 }, + { 0x71A1, 0x00 }, + { 0x71A2, 0x45 }, + { 0x71A3, 0x5A }, + { 0x71A4, 0x06 }, + { 0x71A5, 0x98 }, + { 0x71A6, 0x22 }, + { 0x71A7, 0x4A }, + { 0x71A8, 0x40 }, + { 0x71A9, 0x5A }, + { 0x71AA, 0x00 }, + { 0x71AB, 0x21 }, + { 0x71AC, 0x8C }, + { 0x71AD, 0xF6 }, + { 0x71AE, 0xBE }, + { 0x71AF, 0xF9 }, + { 0x71B0, 0x07 }, + { 0x71B1, 0x46 }, + { 0x71B2, 0x28 }, + { 0x71B3, 0x46 }, + { 0x71B4, 0x03 }, + { 0x71B5, 0x99 }, + { 0x71B6, 0x8F }, + { 0x71B7, 0xF6 }, + { 0x71B8, 0x71 }, + { 0x71B9, 0xFB }, + { 0x71BA, 0x3A }, + { 0x71BB, 0x46 }, + { 0x71BC, 0x00 }, + { 0x71BD, 0x23 }, + { 0x71BE, 0x79 }, + { 0x71BF, 0xF6 }, + { 0x71C0, 0xCA }, + { 0x71C1, 0xFF }, + { 0x71C2, 0x00 }, + { 0x71C3, 0xE0 }, + { 0x71C4, 0x0F }, + { 0x71C5, 0xE0 }, + { 0x71C6, 0x8A }, + { 0x71C7, 0x02 }, + { 0x71C8, 0x80 }, + { 0x71C9, 0x0D }, + { 0x71CA, 0x10 }, + { 0x71CB, 0x43 }, + { 0x71CC, 0x19 }, + { 0x71CD, 0x4A }, + { 0x71CE, 0x00 }, + { 0x71CF, 0x23 }, + { 0x71D0, 0x00 }, + { 0x71D1, 0x92 }, + { 0x71D2, 0x89 }, + { 0x71D3, 0x0D }, + { 0x71D4, 0x01 }, + { 0x71D5, 0x93 }, + { 0x71D6, 0x40 }, + { 0x71D7, 0x22 }, + { 0x71D8, 0x8C }, + { 0x71D9, 0xF6 }, + { 0x71DA, 0x98 }, + { 0x71DB, 0xF9 }, + { 0x71DC, 0xA1 }, + { 0x71DD, 0x00 }, + { 0x71DE, 0x64 }, + { 0x71DF, 0x1C }, + { 0x71E0, 0x70 }, + { 0x71E1, 0x50 }, + { 0x71E2, 0x04 }, + { 0x71E3, 0x2C }, + { 0x71E4, 0xDB }, + { 0x71E5, 0xD3 }, + { 0x71E6, 0x14 }, + { 0x71E7, 0x4D }, + { 0x71E8, 0x00 }, + { 0x71E9, 0x24 }, + { 0x71EA, 0x0B }, + { 0x71EB, 0x98 }, + { 0x71EC, 0x67 }, + { 0x71ED, 0x00 }, + { 0x71EE, 0xC0 }, + { 0x71EF, 0x5B }, + { 0x71F0, 0x2A }, + { 0x71F1, 0x46 }, + { 0x71F2, 0x40 }, + { 0x71F3, 0x21 }, + { 0x71F4, 0x8C }, + { 0x71F5, 0xF6 }, + { 0x71F6, 0x9A }, + { 0x71F7, 0xF9 }, + { 0x71F8, 0x05 }, + { 0x71F9, 0x99 }, + { 0x71FA, 0x0E }, + { 0x71FB, 0x4A }, + { 0x71FC, 0xC8 }, + { 0x71FD, 0x53 }, + { 0x71FE, 0xA7 }, + { 0x71FF, 0x00 }, + { 0x7200, 0xF0 }, + { 0x7201, 0x59 }, + { 0x7202, 0x40 }, + { 0x7203, 0x21 }, + { 0x7204, 0x8C }, + { 0x7205, 0xF6 }, + { 0x7206, 0x7B }, + { 0x7207, 0xF9 }, + { 0x7208, 0x04 }, + { 0x7209, 0x99 }, + { 0x720A, 0x64 }, + { 0x720B, 0x1C }, + { 0x720C, 0xC8 }, + { 0x720D, 0x51 }, + { 0x720E, 0x04 }, + { 0x720F, 0x2C }, + { 0x7210, 0xEB }, + { 0x7211, 0xD3 }, + { 0x7212, 0x0F }, + { 0x7213, 0xB0 }, + { 0x7214, 0xF0 }, + { 0x7215, 0xBD }, + { 0x7216, 0x00 }, + { 0x7217, 0x00 }, + { 0x7218, 0x76 }, + { 0x7219, 0x69 }, + { 0x721A, 0x18 }, + { 0x721B, 0x00 }, + { 0x721C, 0xEC }, + { 0x721D, 0x58 }, + { 0x721E, 0x18 }, + { 0x721F, 0x00 }, + { 0x7220, 0x38 }, + { 0x7221, 0x36 }, + { 0x7222, 0x18 }, + { 0x7223, 0x00 }, + { 0x7224, 0x00 }, + { 0x7225, 0x35 }, + { 0x7226, 0x18 }, + { 0x7227, 0x00 }, + { 0x7228, 0x00 }, + { 0x7229, 0x20 }, + { 0x722A, 0x18 }, + { 0x722B, 0x00 }, + { 0x722C, 0xFF }, + { 0x722D, 0xFF }, + { 0x722E, 0xFF }, + { 0x722F, 0x3F }, + { 0x7230, 0xFF }, + { 0x7231, 0x07 }, + { 0x7232, 0x00 }, + { 0x7233, 0x00 }, + { 0x7234, 0xFF }, + { 0x7235, 0xFF }, + { 0x7236, 0x07 }, + { 0x7237, 0x00 }, + { 0x7238, 0xFF }, + { 0x7239, 0x1F }, + { 0x723A, 0x00 }, + { 0x723B, 0x00 }, + { 0x723C, 0x01 }, + { 0x723D, 0xF6 }, + { 0x723E, 0x45 }, + { 0x723F, 0x12 }, +}; + +static const struct reg_sequence imx390_linear_1936x1096[] = { + { 0x000C, 0xF2 }, + { 0x000D, 0x02 }, + { 0x000E, 0x00 }, + { 0x0010, 0xF2 }, + { 0x0011, 0x02 }, + { 0x0012, 0x00 }, + { 0x0018, 0x0F }, + { 0x0019, 0x00 }, + { 0x001A, 0x0C }, + { 0x001B, 0x00 }, + { 0x0038, 0x00 }, + { 0x003C, 0x00 }, /* OBB_CLAMP_R_SP1H */ + { 0x003D, 0x00 }, /* OBB_CLAMP_R_SP1H */ + { 0x003E, 0x00 }, + { 0x0040, 0x00 }, /* OBB_CLAMP_GR_SP1H */ + { 0x0041, 0x00 }, /* OBB_CLAMP_GR_SP1H */ + { 0x0042, 0x00 }, + { 0x0044, 0x00 }, /* OBB_CLAMP_GB_SP1H */ + { 0x0045, 0x00 }, /* OBB_CLAMP_GB_SP1H */ + { 0x0046, 0x00 }, + { 0x0048, 0x00 }, + { 0x0049, 0x00 }, + { 0x004A, 0x00 }, + { 0x004C, 0x00 }, + { 0x004D, 0x00 }, + { 0x004E, 0x00 }, + { 0x0050, 0x00 }, + { 0x0051, 0x00 }, + { 0x0052, 0x00 }, + { 0x0054, 0x00 }, + { 0x0055, 0x00 }, + { 0x0056, 0x00 }, + { 0x0058, 0x00 }, + { 0x0059, 0x00 }, + { 0x005A, 0x00 }, + { 0x005C, 0x00 }, + { 0x005D, 0x00 }, + { 0x005E, 0x00 }, + { 0x0060, 0x00 }, + { 0x0061, 0x00 }, + { 0x0062, 0x00 }, + { 0x0064, 0x00 }, + { 0x0065, 0x00 }, + { 0x0066, 0x00 }, + { 0x0068, 0x00 }, + { 0x0069, 0x00 }, + { 0x006A, 0x00 }, + { 0x0074, 0x00 }, + { 0x0078, 0x00 }, + { 0x007C, 0x00 }, + { 0x007D, 0x00 }, + { 0x0080, 0x00 }, + { 0x0081, 0x00 }, + { 0x00F4, 0x1C }, + { 0x00F5, 0xF8 }, + { 0x00F6, 0x01 }, + { 0x00F8, 0x03 }, + { 0x00F9, 0x00 }, + { 0x00FA, 0x00 }, + { 0x00FB, 0x00 }, + { 0x0114, 0x00 }, + { 0x0115, 0x01 }, + { 0x0118, 0x20 }, + { 0x0119, 0x03 }, + { 0x011A, 0x00 }, + { 0x011B, 0x41 }, + { 0x011C, 0x80 }, + { 0x011D, 0x00 }, + { 0x0120, 0x20 }, + { 0x0121, 0x00 }, + { 0x0122, 0x00 }, + { 0x0123, 0x44 }, + { 0x0124, 0x00 }, + { 0x0125, 0x01 }, + { 0x0128, 0xAC }, + { 0x0129, 0x0D }, + { 0x012A, 0x00 }, + { 0x012B, 0xA4 }, + { 0x012C, 0x00 }, + { 0x012D, 0x01 }, + { 0x0130, 0xC4 }, + { 0x0131, 0x09 }, + { 0x0132, 0x00 }, + { 0x0133, 0xDA }, + { 0x013B, 0x01 }, + { 0x01C4, 0x00 }, + { 0x01C5, 0x00 }, + { 0x01CC, 0x01 }, + { 0x01D0, 0x09 }, + { 0x01D4, 0x01 }, + { 0x0232, 0x18 }, + { 0x0233, 0x00 }, + { 0x0390, 0x00 }, + { 0x0391, 0x00 }, + { 0x0392, 0x00 }, + { 0x03C0, 0x04 }, + { 0x2000, 0x55 }, + { 0x2001, 0x55 }, + { 0x2002, 0x55 }, + { 0x2003, 0x05 }, + { 0x2004, 0x02 }, + { 0x2008, 0x65 }, + { 0x2009, 0x04 }, + { 0x200A, 0x00 }, + { 0x200C, 0x30 }, + { 0x200D, 0x11 }, + { 0x2010, 0x04 }, + { 0x2014, 0x01 }, + { 0x2018, 0x02 }, + { 0x2019, 0x04 }, + { 0x201A, 0x00 }, + { 0x201C, 0x21 }, + { 0x201D, 0x11 }, + { 0x201E, 0x00 }, + { 0x201F, 0x00 }, + { 0x2020, 0xBC }, + { 0x2021, 0x00 }, + { 0x2022, 0x7F }, + { 0x2023, 0x00 }, + { 0x2024, 0xBA }, + { 0x2025, 0x00 }, + { 0x2026, 0x81 }, + { 0x2027, 0x00 }, + { 0x2028, 0x7D }, + { 0x2029, 0x90 }, + { 0x202A, 0x05 }, + { 0x202C, 0xFC }, + { 0x202D, 0x02 }, + { 0x202E, 0x25 }, + { 0x202F, 0x03 }, + { 0x2030, 0x05 }, + { 0x2031, 0x02 }, + { 0x2032, 0xCA }, + { 0x2033, 0x02 }, + { 0x2034, 0xFC }, + { 0x2035, 0x02 }, + { 0x2036, 0x25 }, + { 0x2037, 0x03 }, + { 0x2038, 0x25 }, + { 0x2039, 0x97 }, + { 0x203A, 0xEC }, + { 0x203B, 0x01 }, + { 0x203C, 0xF5 }, + { 0x203D, 0x8E }, + { 0x203E, 0x0C }, + { 0x203F, 0x2D }, + { 0x2040, 0x69 }, + { 0x2041, 0x01 }, + { 0x2042, 0x8E }, + { 0x2043, 0x01 }, + { 0x2044, 0x0C }, + { 0x2045, 0x02 }, + { 0x2046, 0x31 }, + { 0x2047, 0x02 }, + { 0x2048, 0x6A }, + { 0x2049, 0x01 }, + { 0x204A, 0x8E }, + { 0x204B, 0x01 }, + { 0x204C, 0x0D }, + { 0x204D, 0x02 }, + { 0x204E, 0x31 }, + { 0x204F, 0x02 }, + { 0x2050, 0x7B }, + { 0x2051, 0x00 }, + { 0x2052, 0x7D }, + { 0x2053, 0x00 }, + { 0x2054, 0x95 }, + { 0x2055, 0x00 }, + { 0x2056, 0x97 }, + { 0x2057, 0x00 }, + { 0x2058, 0xAD }, + { 0x2059, 0x00 }, + { 0x205A, 0xAF }, + { 0x205B, 0x00 }, + { 0x205C, 0x92 }, + { 0x205D, 0x00 }, + { 0x205E, 0x94 }, + { 0x205F, 0x00 }, + { 0x2060, 0x8E }, + { 0x2061, 0x00 }, + { 0x2062, 0x90 }, + { 0x2063, 0x00 }, + { 0x2064, 0xB1 }, + { 0x2065, 0x00 }, + { 0x2066, 0xB3 }, + { 0x2067, 0x00 }, + { 0x2068, 0x08 }, + { 0x2069, 0x00 }, + { 0x206A, 0x04 }, + { 0x206B, 0x00 }, + { 0x206C, 0x84 }, + { 0x206D, 0x00 }, + { 0x206E, 0x80 }, + { 0x206F, 0x00 }, + { 0x2070, 0x04 }, + { 0x2071, 0x00 }, + { 0x2072, 0x46 }, + { 0x2073, 0x00 }, + { 0x2074, 0xE9 }, + { 0x2075, 0x01 }, + { 0x2076, 0x74 }, + { 0x2077, 0x02 }, + { 0x2078, 0x80 }, + { 0x2079, 0x00 }, + { 0x207A, 0xC1 }, + { 0x207B, 0x00 }, + { 0x207C, 0xFF }, + { 0x207D, 0x03 }, + { 0x207E, 0xFF }, + { 0x207F, 0x03 }, + { 0x2080, 0x78 }, + { 0x2081, 0x00 }, + { 0x2082, 0x6A }, + { 0x2083, 0x01 }, + { 0x2084, 0xE4 }, + { 0x2085, 0x01 }, + { 0x2086, 0x2B }, + { 0x2087, 0x03 }, + { 0x2088, 0x00 }, + { 0x2089, 0x00 }, + { 0x208A, 0xFF }, + { 0x208B, 0x03 }, + { 0x208C, 0xFF }, + { 0x208D, 0x03 }, + { 0x208E, 0xFF }, + { 0x208F, 0x03 }, + { 0x2090, 0x7D }, + { 0x2091, 0x00 }, + { 0x2092, 0x62 }, + { 0x2093, 0x01 }, + { 0x2094, 0xE9 }, + { 0x2095, 0x01 }, + { 0x2096, 0x00 }, + { 0x2097, 0x00 }, + { 0x2098, 0x7C }, + { 0x2099, 0x00 }, + { 0x209A, 0x21 }, + { 0x209B, 0x03 }, + { 0x209C, 0xE9 }, + { 0x209D, 0x01 }, + { 0x209E, 0x21 }, + { 0x209F, 0x03 }, + { 0x20A0, 0xFF }, + { 0x20A1, 0x03 }, + { 0x20A2, 0xFF }, + { 0x20A3, 0x03 }, + { 0x20A4, 0xFF }, + { 0x20A5, 0x03 }, + { 0x20A6, 0xFF }, + { 0x20A7, 0x03 }, + { 0x20A8, 0xFF }, + { 0x20A9, 0x03 }, + { 0x20AA, 0xFF }, + { 0x20AB, 0x03 }, + { 0x20AC, 0xFF }, + { 0x20AD, 0x03 }, + { 0x20AE, 0xFF }, + { 0x20AF, 0x03 }, + { 0x20B0, 0xFF }, + { 0x20B1, 0x03 }, + { 0x20B2, 0xFF }, + { 0x20B3, 0x03 }, + { 0x20B4, 0x87 }, + { 0x20B5, 0xCC }, + { 0x20B6, 0x87 }, + { 0x20B7, 0x08 }, + { 0x20B8, 0xF4 }, + { 0x20B9, 0xA5 }, + { 0x20BA, 0x07 }, + { 0x20BC, 0x1F }, + { 0x20BD, 0x01 }, + { 0x20BE, 0xF6 }, + { 0x20BF, 0x00 }, + { 0x20C0, 0x90 }, + { 0x20C1, 0x01 }, + { 0x20C2, 0x67 }, + { 0x20C3, 0x01 }, + { 0x20C4, 0xFF }, + { 0x20C5, 0x03 }, + { 0x20C6, 0xFF }, + { 0x20C7, 0x03 }, + { 0x20C8, 0x33 }, + { 0x20C9, 0x02 }, + { 0x20CA, 0x0A }, + { 0x20CB, 0x02 }, + { 0x20CC, 0x7F }, + { 0x20CD, 0x00 }, + { 0x20CE, 0xD2 }, + { 0x20CF, 0x00 }, + { 0x20D0, 0x81 }, + { 0x20D1, 0x00 }, + { 0x20D2, 0x87 }, + { 0x20D3, 0x00 }, + { 0x20D4, 0x09 }, + { 0x20D5, 0x00 }, + { 0x20D8, 0x7F }, + { 0x20D9, 0x00 }, + { 0x20DA, 0x62 }, + { 0x20DB, 0x01 }, + { 0x20DC, 0x7F }, + { 0x20DD, 0x00 }, + { 0x20DE, 0x62 }, + { 0x20DF, 0x01 }, + { 0x20E0, 0x65 }, + { 0x20E1, 0x00 }, + { 0x20E2, 0x75 }, + { 0x20E3, 0x00 }, + { 0x20E4, 0xE0 }, + { 0x20E5, 0x00 }, + { 0x20E6, 0xF0 }, + { 0x20E7, 0x00 }, + { 0x20E8, 0x4C }, + { 0x20E9, 0x01 }, + { 0x20EA, 0x5C }, + { 0x20EB, 0x01 }, + { 0x20EC, 0xD1 }, + { 0x20ED, 0x01 }, + { 0x20EE, 0xE1 }, + { 0x20EF, 0x01 }, + { 0x20F0, 0x93 }, + { 0x20F1, 0x02 }, + { 0x20F2, 0xA3 }, + { 0x20F3, 0x02 }, + { 0x20F4, 0x0D }, + { 0x20F5, 0x03 }, + { 0x20F6, 0x1D }, + { 0x20F7, 0x03 }, + { 0x20F8, 0x57 }, + { 0x20F9, 0x00 }, + { 0x20FA, 0x7B }, + { 0x20FB, 0x00 }, + { 0x20FC, 0xD2 }, + { 0x20FD, 0x00 }, + { 0x20FE, 0xF6 }, + { 0x20FF, 0x00 }, + { 0x2100, 0x3E }, + { 0x2101, 0x01 }, + { 0x2102, 0x60 }, + { 0x2103, 0x01 }, + { 0x2104, 0xC3 }, + { 0x2105, 0x01 }, + { 0x2106, 0xE5 }, + { 0x2107, 0x01 }, + { 0x2108, 0x85 }, + { 0x2109, 0x02 }, + { 0x210A, 0xA9 }, + { 0x210B, 0x02 }, + { 0x210C, 0xFF }, + { 0x210D, 0x02 }, + { 0x210E, 0x21 }, + { 0x210F, 0x03 }, + { 0x2110, 0xFF }, + { 0x2111, 0x03 }, + { 0x2112, 0x00 }, + { 0x2113, 0x00 }, + { 0x2114, 0xFF }, + { 0x2115, 0x03 }, + { 0x2116, 0xFF }, + { 0x2117, 0x03 }, + { 0x2118, 0xFF }, + { 0x2119, 0x03 }, + { 0x211A, 0xFF }, + { 0x211B, 0x03 }, + { 0x211C, 0xFF }, + { 0x211D, 0x03 }, + { 0x211E, 0xFF }, + { 0x211F, 0x03 }, + { 0x2120, 0xFF }, + { 0x2121, 0x03 }, + { 0x2122, 0xFF }, + { 0x2123, 0x03 }, + { 0x2124, 0xFF }, + { 0x2125, 0x03 }, + { 0x2126, 0xFF }, + { 0x2127, 0x03 }, + { 0x2128, 0x7D }, + { 0x2129, 0x90 }, + { 0x212A, 0xD5 }, + { 0x212B, 0x07 }, + { 0x212C, 0x64 }, + { 0x212D, 0x01 }, + { 0x2130, 0x5F }, + { 0x2131, 0x7D }, + { 0x2132, 0x05 }, + { 0x2134, 0x78 }, + { 0x2135, 0x00 }, + { 0x2136, 0x76 }, + { 0x2137, 0x00 }, + { 0x2138, 0xF3 }, + { 0x2139, 0x00 }, + { 0x213A, 0xF1 }, + { 0x213B, 0x00 }, + { 0x213C, 0xA6 }, + { 0x213D, 0x02 }, + { 0x213E, 0xA4 }, + { 0x213F, 0x02 }, + { 0x2140, 0x7D }, + { 0x2141, 0x00 }, + { 0x2142, 0x8D }, + { 0x2143, 0x00 }, + { 0x2144, 0xA1 }, + { 0x2145, 0x01 }, + { 0x2146, 0xB1 }, + { 0x2147, 0x01 }, + { 0x2148, 0xAB }, + { 0x2149, 0x02 }, + { 0x214A, 0xBB }, + { 0x214B, 0x02 }, + { 0x214C, 0x17 }, + { 0x214D, 0x5C }, + { 0x214E, 0x00 }, + { 0x2150, 0x00 }, + { 0x2151, 0x00 }, + { 0x2152, 0xF8 }, + { 0x2153, 0x00 }, + { 0x2154, 0xBE }, + { 0x2155, 0x00 }, + { 0x2156, 0x7D }, + { 0x2157, 0x00 }, + { 0x2158, 0x25 }, + { 0x2159, 0x00 }, + { 0x215A, 0x7D }, + { 0x215B, 0x00 }, + { 0x215C, 0x62 }, + { 0x215D, 0x01 }, + { 0x215E, 0xFF }, + { 0x215F, 0x03 }, + { 0x2160, 0x26 }, + { 0x2161, 0x00 }, + { 0x2162, 0x7D }, + { 0x2163, 0x00 }, + { 0x2164, 0x63 }, + { 0x2165, 0x01 }, + { 0x2166, 0xFF }, + { 0x2167, 0x03 }, + { 0x2168, 0xCB }, + { 0x2169, 0x02 }, + { 0x216A, 0xCF }, + { 0x216B, 0x02 }, + { 0x216C, 0xFF }, + { 0x216D, 0x03 }, + { 0x216E, 0xFF }, + { 0x216F, 0x03 }, + { 0x2170, 0xFF }, + { 0x2171, 0x03 }, + { 0x2172, 0xFF }, + { 0x2173, 0x03 }, + { 0x2174, 0xFF }, + { 0x2175, 0x03 }, + { 0x2176, 0xFF }, + { 0x2177, 0x03 }, + { 0x2178, 0x7E }, + { 0x2179, 0x00 }, + { 0x217A, 0xBD }, + { 0x217B, 0x00 }, + { 0x217C, 0xEC }, + { 0x217D, 0x01 }, + { 0x217E, 0x7B }, + { 0x217F, 0x02 }, + { 0x2180, 0xD1 }, + { 0x2181, 0x02 }, + { 0x2182, 0x25 }, + { 0x2183, 0x03 }, + { 0x2184, 0x7F }, + { 0x2185, 0x00 }, + { 0x2186, 0xBD }, + { 0x2187, 0x00 }, + { 0x2188, 0xED }, + { 0x2189, 0x01 }, + { 0x218A, 0x7B }, + { 0x218B, 0x02 }, + { 0x218C, 0xD2 }, + { 0x218D, 0x02 }, + { 0x218E, 0x25 }, + { 0x218F, 0x03 }, + { 0x2190, 0xFF }, + { 0x2191, 0x03 }, + { 0x2192, 0xFF }, + { 0x2193, 0x03 }, + { 0x2194, 0xE9 }, + { 0x2195, 0x01 }, + { 0x2196, 0x21 }, + { 0x2197, 0x03 }, + { 0x2198, 0x17 }, + { 0x2199, 0xFC }, + { 0x219A, 0x7F }, + { 0x219B, 0x01 }, + { 0x219C, 0xFF }, + { 0x219D, 0x03 }, + { 0x21A0, 0x1B }, + { 0x21A1, 0x1B }, + { 0x21A2, 0x1B }, + { 0x21A3, 0x1B }, + { 0x21A4, 0x2E }, + { 0x21A5, 0x80 }, + { 0x21A6, 0x00 }, + { 0x21A8, 0x04 }, + { 0x21A9, 0x98 }, + { 0x21AA, 0x60 }, + { 0x21AB, 0x03 }, + { 0x21AC, 0x7F }, + { 0x21AD, 0x80 }, + { 0x21AE, 0x09 }, + { 0x21B0, 0x1C }, + { 0x21B1, 0x00 }, + { 0x21B2, 0xA0 }, + { 0x21B3, 0x00 }, + { 0x21B4, 0x0C }, + { 0x21B5, 0x00 }, + { 0x21B6, 0x2D }, + { 0x21B7, 0x00 }, + { 0x21B8, 0x20 }, + { 0x21B9, 0x00 }, + { 0x21BA, 0x02 }, + { 0x21BB, 0x00 }, + { 0x21BC, 0xCC }, + { 0x21BD, 0x00 }, + { 0x21BE, 0x4A }, + { 0x21BF, 0x00 }, + { 0x21C0, 0xD0 }, + { 0x21C1, 0x00 }, + { 0x21C2, 0x44 }, + { 0x21C3, 0x00 }, + { 0x21C4, 0x00 }, + { 0x21C5, 0xE0 }, + { 0x21C6, 0x00 }, + { 0x21C8, 0x11 }, + { 0x21C9, 0x00 }, + { 0x21CA, 0x02 }, + { 0x21CC, 0x08 }, + { 0x21CD, 0xC0 }, + { 0x21CE, 0x0C }, + { 0x21D0, 0x44 }, + { 0x21D1, 0x00 }, + { 0x21D2, 0x02 }, + { 0x21D4, 0x02 }, + { 0x21D5, 0x20 }, + { 0x21D6, 0x2C }, + { 0x21D8, 0xFE }, + { 0x21D9, 0x9D }, + { 0x21DA, 0xDF }, + { 0x21DB, 0x03 }, + { 0x21DC, 0x62 }, + { 0x21DD, 0x01 }, + { 0x21DE, 0x7F }, + { 0x21DF, 0x00 }, + { 0x21E0, 0xB7 }, + { 0x21E1, 0x01 }, + { 0x21E2, 0xB5 }, + { 0x21E3, 0x01 }, + { 0x21E4, 0xC1 }, + { 0x21E5, 0x02 }, + { 0x21E6, 0xBF }, + { 0x21E7, 0x02 }, + { 0x21E8, 0xB3 }, + { 0x21E9, 0x0D }, + { 0x21EA, 0x00 }, + { 0x21EB, 0x04 }, + { 0x21EC, 0x90 }, + { 0x21ED, 0x07 }, + { 0x21EE, 0x58 }, + { 0x21EF, 0x04 }, + { 0x21F0, 0x54 }, + { 0x21F1, 0x04 }, + { 0x21F4, 0x02 }, + { 0x21F5, 0x00 }, + { 0x21F6, 0x00 }, + { 0x21F8, 0x3C }, + { 0x21F9, 0x00 }, + { 0x21FC, 0x28 }, + { 0x21FD, 0x00 }, + { 0x21FE, 0x3C }, + { 0x21FF, 0x00 }, + { 0x2200, 0x00 }, + { 0x2204, 0x4C }, + { 0x2205, 0x04 }, + { 0x2206, 0x65 }, + { 0x2207, 0x04 }, + { 0x2208, 0x0A }, + { 0x2209, 0x00 }, + { 0x220C, 0x47 }, + { 0x220D, 0x00 }, + { 0x220E, 0x1F }, + { 0x220F, 0x00 }, + { 0x2210, 0x17 }, + { 0x2211, 0x00 }, + { 0x2212, 0x0F }, + { 0x2213, 0x00 }, + { 0x2214, 0x17 }, + { 0x2215, 0x00 }, + { 0x2216, 0x47 }, + { 0x2217, 0x00 }, + { 0x2218, 0x0F }, + { 0x2219, 0x00 }, + { 0x221A, 0x0F }, + { 0x221B, 0x00 }, + { 0x221C, 0x03 }, + { 0x2220, 0x20 }, + { 0x2221, 0x20 }, + { 0x2222, 0x22 }, + { 0x2223, 0x02 }, + { 0x2224, 0xA7 }, + { 0x2225, 0xAA }, + { 0x2226, 0x80 }, + { 0x2227, 0x08 }, + { 0x2228, 0x01 }, + { 0x22B2, 0x92 }, + { 0x22B4, 0x20 }, + { 0x22B5, 0x00 }, + { 0x22B6, 0x20 }, + { 0x22B7, 0x00 }, + { 0x22B8, 0x20 }, + { 0x22B9, 0x00 }, + { 0x22BA, 0x20 }, + { 0x22BB, 0x00 }, + { 0x22BC, 0x20 }, + { 0x22BD, 0x00 }, + { 0x22BE, 0x20 }, + { 0x22BF, 0x00 }, + { 0x22C0, 0x20 }, + { 0x22C1, 0x00 }, + { 0x22C2, 0x20 }, + { 0x22C3, 0x00 }, + { 0x22C4, 0x20 }, + { 0x22C5, 0x00 }, + { 0x22C6, 0x20 }, + { 0x22C7, 0x00 }, + { 0x22C8, 0x20 }, + { 0x22C9, 0x00 }, + { 0x22CA, 0x20 }, + { 0x22CB, 0x00 }, + { 0x22CC, 0x20 }, + { 0x22CD, 0x00 }, + { 0x22CE, 0x20 }, + { 0x22CF, 0x00 }, + { 0x22DA, 0x00 }, + { 0x2308, 0x01 }, + { 0x2311, 0x09 }, + { 0x2318, 0x40 }, + { 0x2319, 0xCD }, + { 0x231A, 0x54 }, + { 0x2324, 0x10 }, + { 0x2325, 0x00 }, + { 0x2328, 0x00 }, + { 0x2354, 0x0C }, + { 0x23C0, 0x5D }, + { 0x244C, 0x00 }, + { 0x244D, 0x02 }, + { 0x244E, 0x54 }, + { 0x244F, 0x02 }, + { 0x24A0, 0x00 }, + { 0x24DA, 0x6F }, + { 0x24DB, 0x00 }, + { 0x24DC, 0x62 }, + { 0x24DD, 0x01 }, + { 0x24EA, 0x32 }, + { 0x24EB, 0x00 }, + { 0x24EC, 0xDC }, + { 0x24ED, 0x00 }, + { 0x24FA, 0x32 }, + { 0x24FB, 0x00 }, + { 0x24FC, 0xDD }, + { 0x24FD, 0x00 }, + { 0x254A, 0x15 }, + { 0x254B, 0x01 }, + { 0x255A, 0x15 }, + { 0x255B, 0x01 }, + { 0x2560, 0x01 }, + { 0x2561, 0x00 }, + { 0x2562, 0x2A }, + { 0x2563, 0x00 }, + { 0x2564, 0xF8 }, + { 0x2565, 0x00 }, + { 0x2566, 0x15 }, + { 0x2567, 0x01 }, + { 0x2568, 0x0C }, + { 0x2569, 0x02 }, + { 0x256A, 0x31 }, + { 0x256B, 0x02 }, + { 0x2578, 0x90 }, + { 0x2579, 0x01 }, + { 0x257A, 0x92 }, + { 0x257B, 0x01 }, + { 0x257C, 0xB8 }, + { 0x257D, 0x02 }, + { 0x257E, 0xBA }, + { 0x257F, 0x02 }, + { 0x2584, 0x90 }, + { 0x2585, 0x01 }, + { 0x2586, 0x92 }, + { 0x2587, 0x01 }, + { 0x2588, 0xB8 }, + { 0x2589, 0x02 }, + { 0x258A, 0xBA }, + { 0x258B, 0x02 }, + { 0x26B8, 0x10 }, + { 0x26B9, 0x00 }, + { 0x26BA, 0x33 }, + { 0x26BB, 0x00 }, + { 0x26BC, 0x89 }, + { 0x26BD, 0x00 }, + { 0x26BE, 0xB0 }, + { 0x26BF, 0x00 }, + { 0x26C4, 0x4E }, + { 0x26C5, 0x00 }, + { 0x26C8, 0xC9 }, + { 0x26C9, 0x00 }, + { 0x26CC, 0x35 }, + { 0x26CD, 0x01 }, + { 0x26D0, 0xBA }, + { 0x26D1, 0x01 }, + { 0x26D4, 0x7C }, + { 0x26D5, 0x02 }, + { 0x26D8, 0xF6 }, + { 0x26D9, 0x02 }, + { 0x26DE, 0x51 }, + { 0x26DF, 0x00 }, + { 0x26E0, 0x7F }, + { 0x26E1, 0x00 }, + { 0x26E2, 0xCC }, + { 0x26E3, 0x00 }, + { 0x26E4, 0xF8 }, + { 0x26E5, 0x00 }, + { 0x26E6, 0x38 }, + { 0x26E7, 0x01 }, + { 0x26E8, 0x65 }, + { 0x26E9, 0x01 }, + { 0x26EA, 0xBD }, + { 0x26EB, 0x01 }, + { 0x26EE, 0x7F }, + { 0x26EF, 0x02 }, + { 0x26F0, 0xAB }, + { 0x26F1, 0x02 }, + { 0x26F2, 0xF9 }, + { 0x26F3, 0x02 }, + { 0x2722, 0x59 }, + { 0x2723, 0x02 }, + { 0x2938, 0x55 }, + { 0x2939, 0x00 }, + { 0x293A, 0x17 }, + { 0x293B, 0x00 }, + { 0x293C, 0xD0 }, + { 0x293D, 0x00 }, + { 0x293E, 0x91 }, + { 0x293F, 0x00 }, + { 0x2940, 0x3C }, + { 0x2941, 0x01 }, + { 0x2942, 0x0C }, + { 0x2943, 0x01 }, + { 0x2944, 0xC1 }, + { 0x2945, 0x01 }, + { 0x2946, 0x76 }, + { 0x2947, 0x01 }, + { 0x2948, 0x83 }, + { 0x2949, 0x02 }, + { 0x294A, 0xFB }, + { 0x294B, 0x01 }, + { 0x294C, 0xFD }, + { 0x294D, 0x02 }, + { 0x294E, 0xBF }, + { 0x294F, 0x02 }, + { 0x2A06, 0xFF }, + { 0x2A07, 0x03 }, + { 0x2A20, 0x00 }, + { 0x2A21, 0x00 }, + { 0x2A22, 0x7D }, + { 0x2A23, 0x00 }, + { 0x2B11, 0x19 }, + { 0x2B13, 0x15 }, + { 0x2B14, 0x14 }, + { 0x2B15, 0x13 }, + { 0x2B16, 0x12 }, + { 0x2B17, 0x11 }, + { 0x2B18, 0x10 }, + { 0x2B19, 0x0F }, + { 0x2B1A, 0x0E }, + { 0x2B1B, 0x0D }, + { 0x2B1C, 0x0C }, + { 0x2B1D, 0x0B }, + { 0x2B1E, 0x0A }, + { 0x2B1F, 0x09 }, + { 0x2B20, 0x08 }, + { 0x2B21, 0x07 }, + { 0x2B22, 0x06 }, + { 0x2B23, 0x05 }, + { 0x2B24, 0x04 }, + { 0x2B25, 0x03 }, + { 0x2B26, 0x03 }, + { 0x2B38, 0x01 }, + { 0x2B45, 0xE3 }, + { 0x2B50, 0x01 }, + { 0x2B51, 0x00 }, + { 0x2B6D, 0x47 }, + { 0x2B70, 0x02 }, + { 0x2B71, 0x02 }, + { 0x2B72, 0x02 }, + { 0x2B7F, 0x7F }, + { 0x2B80, 0x94 }, + { 0x2B81, 0x06 }, + { 0x2B87, 0x1B }, + { 0x2B88, 0x1B }, + { 0x2B89, 0x17 }, + { 0x2B8A, 0x12 }, + { 0x2B8B, 0x12 }, + { 0x2B8D, 0x2B }, + { 0x2B8E, 0x2B }, + { 0x2B8F, 0x2B }, + { 0x2B90, 0x7F }, + { 0x2B91, 0x1F }, + { 0x2B94, 0x7F }, + { 0x2B95, 0x27 }, + { 0x2B98, 0x7F }, + { 0x2B99, 0x57 }, + { 0x2BA8, 0xBC }, + { 0x2BA9, 0x62 }, + { 0x2BC1, 0x70 }, + { 0x2BC5, 0x80 }, + { 0x2BD5, 0x30 }, + { 0x2BD6, 0xF0 }, + { 0x2BD8, 0xDB }, + { 0x2BD9, 0xF6 }, + { 0x2BDA, 0x63 }, + { 0x2BDB, 0x0C }, + { 0x2BDC, 0x5C }, + { 0x2C98, 0xE1 }, + { 0x2C99, 0x2E }, + { 0x2C9B, 0x86 }, + { 0x2CA9, 0x80 }, + { 0x2CAA, 0x01 }, + { 0x2D39, 0x0E }, + { 0x2D54, 0x00 }, + { 0x2D5B, 0x58 }, + { 0x2D64, 0x64 }, + { 0x2D65, 0x80 }, + { 0x3000, 0x00 }, + { 0x3001, 0x00 }, + { 0x3002, 0x23 }, + { 0x3003, 0xA1 }, + { 0x3004, 0x00 }, + { 0x3005, 0x20 }, + { 0x3006, 0x84 }, + { 0x3007, 0x00 }, + { 0x3008, 0x06 }, + { 0x3009, 0xB4 }, + { 0x300A, 0x1F }, + { 0x300B, 0x00 }, + { 0x300C, 0x00 }, + { 0x300D, 0x1B }, + { 0x300E, 0x90 }, + { 0x300F, 0x97 }, + { 0x3010, 0x00 }, + { 0x3011, 0x00 }, + { 0x3012, 0x21 }, + { 0x3013, 0x21 }, + { 0x3014, 0x00 }, + { 0x3015, 0x20 }, + { 0x3016, 0x84 }, + { 0x3017, 0x00 }, + { 0x3018, 0x30 }, + { 0x3019, 0x09 }, + { 0x301A, 0x46 }, + { 0x301B, 0x00 }, + { 0x3070, 0xC1 }, + { 0x3071, 0x81 }, + { 0x3072, 0x29 }, + { 0x3073, 0x81 }, + { 0x3410, (IMX390_OUT_WIDTH & 0xFF) }, + { 0x3411, (IMX390_OUT_WIDTH >> 8) }, + { 0x3418, (IMX390_OUT_HEIGHT & 0xFF) }, + { 0x3419, (IMX390_OUT_HEIGHT >> 8) }, + { 0x34A0, 0x30 }, + { 0x34C0, 0xD3 }, + { 0x34C1, 0x00 }, + { 0x34C2, 0xD3 }, + { 0x34C3, 0x00 }, + { 0x34C4, 0xD3 }, + { 0x34C5, 0x00 }, + { 0x34C6, 0xD3 }, + { 0x34C7, 0x00 }, + { 0x34C8, 0xE2 }, + { 0x34C9, 0x21 }, + { 0x34CA, 0xE0 }, + { 0x34CB, 0x1F }, + { 0x34CC, 0x06 }, + { 0x34CD, 0x20 }, + { 0x34CE, 0x28 }, + { 0x34CF, 0x1F }, + { 0x3584, 0x00 }, + { 0x3586, 0x00 }, + { 0x3587, 0x01 }, + { 0x3588, 0xE6 }, + { 0x3589, 0x00 }, + { 0x3590, 0x00 }, + { 0x3591, 0x00 }, + { 0x3594, 0x40 }, + { 0x3598, 0x03 }, + { 0x3599, 0x00 }, + { 0x359A, 0x80 }, + { 0x359B, 0x00 }, + { 0x359C, 0x00 }, + { 0x359D, 0x01 }, + { 0x359E, 0x00 }, + { 0x359F, 0x02 }, + { 0x35A0, 0x00 }, + { 0x35A1, 0x04 }, + { 0x35A2, 0x20 }, + { 0x35A3, 0x00 }, + { 0x35A4, 0x40 }, + { 0x35A5, 0x00 }, + { 0x35A6, 0x80 }, + { 0x35A7, 0x00 }, + { 0x35A8, 0x00 }, + { 0x35A9, 0x01 }, + { 0x35AA, 0x3A }, + { 0x35AB, 0x00 }, + { 0x35AC, 0x80 }, + { 0x35AD, 0x00 }, + { 0x35AE, 0x00 }, + { 0x35AF, 0x01 }, + { 0x35B0, 0x00 }, + { 0x35B1, 0x02 }, + { 0x35B2, 0x00 }, + { 0x35B3, 0x04 }, + { 0x35B4, 0x02 }, + { 0x35B5, 0x00 }, + { 0x35B6, 0x04 }, + { 0x35B7, 0x00 }, + { 0x35B8, 0x08 }, + { 0x35B9, 0x00 }, + { 0x35BA, 0x10 }, + { 0x35BB, 0x00 }, + { 0x35BC, 0x03 }, + { 0x35BD, 0x00 }, + { 0x35C8, 0x00 }, + { 0x35C9, 0x01 }, + { 0x35CA, 0x00 }, + { 0x35CB, 0x04 }, + { 0x35CC, 0x00 }, + { 0x35CD, 0x10 }, + { 0x35CE, 0x00 }, + { 0x35CF, 0x40 }, + { 0x35D0, 0x00 }, + { 0x35D1, 0x0C }, + { 0x35D2, 0x00 }, + { 0x35D3, 0x0C }, + { 0x35D4, 0x00 }, + { 0x35D5, 0x0C }, + { 0x35D6, 0x00 }, + { 0x35D7, 0x0C }, + { 0x35D8, 0x00 }, + { 0x35D9, 0x00 }, + { 0x35DA, 0x08 }, + { 0x35DB, 0x00 }, + { 0x35DC, 0xD8 }, + { 0x35DD, 0x0E }, + { 0x35F0, 0x00 }, + { 0x35F1, 0x10 }, + { 0x35F2, 0x00 }, + { 0x35F3, 0x10 }, + { 0x35F4, 0x00 }, + { 0x35F5, 0x10 }, + { 0x35F6, 0x00 }, + { 0x35F7, 0x03 }, + { 0x35F8, 0x00 }, + { 0x35F9, 0x01 }, + { 0x35FA, 0x38 }, + { 0x35FB, 0x00 }, + { 0x35FC, 0xB3 }, + { 0x35FD, 0x01 }, + { 0x35FE, 0x00 }, + { 0x35FF, 0x00 }, + { 0x3600, 0x04 }, + { 0x3601, 0x06 }, + { 0x3604, 0x03 }, + { 0x3605, 0x00 }, + { 0x3608, 0x03 }, + { 0x3609, 0x00 }, + { 0x360C, 0x00 }, + { 0x360D, 0x00 }, + { 0x3610, 0x10 }, + { 0x3611, 0x01 }, + { 0x3612, 0x00 }, + { 0x3613, 0x00 }, + { 0x3614, 0x00 }, + { 0x3615, 0x00 }, + { 0x361C, 0x00 }, + { 0x361D, 0x01 }, + { 0x361E, 0x00 }, + { 0x361F, 0x01 }, + { 0x3620, 0x01 }, + { 0x3621, 0x00 }, + { 0x3622, 0xB0 }, + { 0x3623, 0x04 }, + { 0x3624, 0xDC }, + { 0x3625, 0x05 }, + { 0x3626, 0x00 }, + { 0x3627, 0x01 }, + { 0x3628, 0xFF }, + { 0x3629, 0x0F }, + { 0x362A, 0x00 }, + { 0x362B, 0x10 }, + { 0x362C, 0x00 }, + { 0x362D, 0x01 }, + { 0x3630, 0x40 }, + { 0x3631, 0x00 }, + { 0x3632, 0x40 }, + { 0x3633, 0x00 }, + { 0x3634, 0x40 }, + { 0x3635, 0x00 }, + { 0x3636, 0x40 }, + { 0x3637, 0x00 }, + { 0x3638, 0x40 }, + { 0x3639, 0x00 }, + { 0x363A, 0x40 }, + { 0x363B, 0x00 }, + { 0x363C, 0x40 }, + { 0x363D, 0x00 }, + { 0x363E, 0x40 }, + { 0x363F, 0x00 }, + { 0x36C4, 0x99 }, + { 0x36C5, 0x09 }, + { 0x36C6, 0x18 }, + { 0x36C7, 0x07 }, + { 0x36C8, 0x65 }, + { 0x36C9, 0x0E }, + { 0x36CC, 0x99 }, + { 0x36CD, 0x01 }, + { 0x36CE, 0x47 }, + { 0x36CF, 0x00 }, + { 0x36D0, 0x04 }, + { 0x36D1, 0x00 }, + { 0x36D4, 0x65 }, + { 0x36D5, 0x0E }, + { 0x36D6, 0xA4 }, + { 0x36D7, 0x0A }, + { 0x36D8, 0x65 }, + { 0x36D9, 0x0E }, + { 0x36DC, 0x65 }, + { 0x36DD, 0x0E }, + { 0x36DE, 0xA4 }, + { 0x36DF, 0x0A }, + { 0x36E0, 0x65 }, + { 0x36E1, 0x0E }, + { 0x36E4, 0x65 }, + { 0x36E5, 0x0E }, + { 0x36E6, 0xA4 }, + { 0x36E7, 0x0A }, + { 0x36E8, 0x65 }, + { 0x36E9, 0x0E }, + { 0x36EE, 0x00 }, + { 0x36EF, 0x00 }, + { 0x36F0, 0x00 }, + { 0x36F1, 0x80 }, + { 0x36F8, 0x00 }, + { 0x3702, 0x03 }, + { 0x3703, 0x04 }, + { 0x3704, 0x08 }, + { 0x370E, 0x0E }, + { 0x3718, 0x62 }, + { 0x3719, 0x4A }, + { 0x371A, 0x38 }, + { 0x371B, 0x20 }, + { 0x371C, 0x64 }, + { 0x371D, 0x42 }, + { 0x371E, 0x32 }, + { 0x371F, 0x1B }, + { 0x3720, 0x9C }, + { 0x3721, 0xA4 }, + { 0x3722, 0xAC }, + { 0x3723, 0xB4 }, + { 0x3748, 0xAA }, + { 0x3749, 0x96 }, + { 0x374A, 0x7D }, + { 0x374B, 0x69 }, + { 0x37C0, 0x00 }, + { 0x37C1, 0x00 }, + { 0x37C2, 0x00 }, + { 0x37C4, 0x00 }, + { 0x37C5, 0x00 }, + { 0x37C6, 0x00 }, + { 0x37C8, 0x00 }, + { 0x37C9, 0x00 }, + { 0x37CA, 0x00 }, + { 0x37CC, 0x00 }, + { 0x37CD, 0x00 }, + { 0x37CE, 0x00 }, + { 0x37D0, 0x00 }, + { 0x37D1, 0x00 }, + { 0x37D2, 0x00 }, + { 0x37D4, 0x00 }, + { 0x37D5, 0x00 }, + { 0x37D6, 0x00 }, + { 0x37D8, 0x00 }, + { 0x37D9, 0x00 }, + { 0x37DA, 0x00 }, + { 0x37DC, 0x00 }, + { 0x37DD, 0x00 }, + { 0x37DE, 0x00 }, + { 0x37E0, 0x00 }, + { 0x37E1, 0x00 }, + { 0x37E2, 0x00 }, + { 0x37E4, 0x00 }, + { 0x37E5, 0x00 }, + { 0x37E6, 0x00 }, + { 0x37E8, 0x00 }, + { 0x37E9, 0x00 }, + { 0x37EA, 0x00 }, + { 0x37EC, 0x00 }, + { 0x37ED, 0x00 }, + { 0x37EE, 0x00 }, + { 0x37F0, 0x00 }, + { 0x37F4, 0x00 }, + { 0x37F5, 0x1E }, + { 0x37F6, 0x34 }, + { 0x37F7, 0x00 }, + { 0x37F8, 0xFF }, + { 0x37F9, 0xFF }, + { 0x37FA, 0x03 }, + { 0x37FC, 0x00 }, + { 0x37FD, 0x00 }, + { 0x37FE, 0x04 }, + { 0x3800, 0xFF }, + { 0x3801, 0xFF }, + { 0x3802, 0x03 }, + { 0x3804, 0x00 }, + { 0x3805, 0x00 }, + { 0x3806, 0x04 }, + { 0x3808, 0x00 }, + { 0x3809, 0x00 }, + { 0x380A, 0x00 }, + { 0x380C, 0x00 }, + { 0x380D, 0x00 }, + { 0x380E, 0x00 }, + { 0x3810, 0x00 }, + { 0x3811, 0x00 }, + { 0x3812, 0x00 }, + { 0x3814, 0x00 }, + { 0x3815, 0x00 }, + { 0x3816, 0x00 }, + { 0x3818, 0x00 }, + { 0x3819, 0x00 }, + { 0x381A, 0x00 }, + { 0x381C, 0x00 }, + { 0x381D, 0x00 }, + { 0x381E, 0x00 }, + { 0x3820, 0x00 }, + { 0x3821, 0x00 }, + { 0x3822, 0x00 }, + { 0x3824, 0x00 }, + { 0x3825, 0x00 }, + { 0x3826, 0x00 }, + { 0x3828, 0x00 }, + { 0x3829, 0x00 }, + { 0x382A, 0x00 }, + { 0x382C, 0x00 }, + { 0x382D, 0x00 }, + { 0x382E, 0x00 }, + { 0x3830, 0x00 }, + { 0x3831, 0x00 }, + { 0x3832, 0x00 }, + { 0x3834, 0x00 }, + { 0x3835, 0x00 }, + { 0x3836, 0x00 }, + { 0x3838, 0x00 }, + { 0x3839, 0x00 }, + { 0x383A, 0x00 }, + { 0x383B, 0x00 }, + { 0x383C, 0x00 }, + { 0x383D, 0x00 }, + { 0x383E, 0x00 }, + { 0x383F, 0x00 }, + { 0x3840, 0x00 }, + { 0x3841, 0x00 }, + { 0x3842, 0x00 }, + { 0x3843, 0x00 }, + { 0x3844, 0x00 }, + { 0x3845, 0x00 }, + { 0x3846, 0x00 }, + { 0x3847, 0x00 }, + { 0x3848, 0x00 }, + { 0x3849, 0x00 }, + { 0x384A, 0x00 }, + { 0x384B, 0x00 }, + { 0x384C, 0x00 }, + { 0x384D, 0x00 }, + { 0x384E, 0x00 }, + { 0x384F, 0x00 }, + { 0x3850, 0xFF }, + { 0x3851, 0x0F }, + { 0x3852, 0x00 }, + { 0x3853, 0x10 }, + { 0x3854, 0xFF }, + { 0x3855, 0x0F }, + { 0x3856, 0x00 }, + { 0x3857, 0x10 }, + { 0x3858, 0xFF }, + { 0x3859, 0x0F }, + { 0x385A, 0x00 }, + { 0x385B, 0x10 }, + { 0x385C, 0x02 }, + { 0x385D, 0x00 }, + { 0x385E, 0x06 }, + { 0x385F, 0x00 }, + { 0x3860, 0x06 }, + { 0x3861, 0x00 }, + { 0x3862, 0x08 }, + { 0x3863, 0x00 }, + { 0x3864, 0x02 }, + { 0x3865, 0x00 }, + { 0x38A0, 0x01 }, + { 0x38A1, 0x01 }, + { 0x38A2, 0x00 }, + { 0x38A3, 0x01 }, + { 0x38A4, 0x07 }, + { 0x38A5, 0x00 }, + { 0x38A6, 0x04 }, + { 0x38A7, 0x05 }, + { 0x38A8, 0x00 }, + { 0x38A9, 0x00 }, + { 0x38AC, 0x00 }, + { 0x38AD, 0x00 }, + { 0x38AE, 0x01 }, + { 0x38B0, 0x02 }, + { 0x38B2, 0x22 }, + { 0x38B3, 0x00 }, + { 0x38B4, 0x17 }, + { 0x38B5, 0x00 }, + { 0x38B6, 0x11 }, + { 0x38B7, 0x00 }, + { 0x38B8, 0x0E }, + { 0x38B9, 0x00 }, + { 0x38BA, 0x2A }, + { 0x38BB, 0x00 }, + { 0x38BC, 0x1C }, + { 0x38BD, 0x00 }, + { 0x38BE, 0x14 }, + { 0x38BF, 0x00 }, + { 0x38C0, 0x10 }, + { 0x38C1, 0x00 }, + { 0x38C2, 0x31 }, + { 0x38C3, 0x00 }, + { 0x38C4, 0x21 }, + { 0x38C5, 0x00 }, + { 0x38C6, 0x18 }, + { 0x38C7, 0x00 }, + { 0x38C8, 0x12 }, + { 0x38C9, 0x00 }, + { 0x38CA, 0x3C }, + { 0x38CB, 0x00 }, + { 0x38CC, 0x29 }, + { 0x38CD, 0x00 }, + { 0x38CE, 0x1D }, + { 0x38CF, 0x00 }, + { 0x38D0, 0x15 }, + { 0x38D1, 0x00 }, + { 0x38D2, 0x4E }, + { 0x38D3, 0x00 }, + { 0x38D4, 0x35 }, + { 0x38D5, 0x00 }, + { 0x38D6, 0x26 }, + { 0x38D7, 0x00 }, + { 0x38D8, 0x1A }, + { 0x38D9, 0x00 }, + { 0x38DA, 0x69 }, + { 0x38DB, 0x00 }, + { 0x38DC, 0x48 }, + { 0x38DD, 0x00 }, + { 0x38DE, 0x33 }, + { 0x38DF, 0x00 }, + { 0x38E0, 0x22 }, + { 0x38E1, 0x00 }, + { 0x38E2, 0x93 }, + { 0x38E3, 0x00 }, + { 0x38E4, 0x64 }, + { 0x38E5, 0x00 }, + { 0x38E6, 0x48 }, + { 0x38E7, 0x00 }, + { 0x38E8, 0x30 }, + { 0x38E9, 0x00 }, + { 0x38EA, 0xD3 }, + { 0x38EB, 0x00 }, + { 0x38EC, 0x90 }, + { 0x38ED, 0x00 }, + { 0x38EE, 0x69 }, + { 0x38EF, 0x00 }, + { 0x38F0, 0x49 }, + { 0x38F1, 0x00 }, + { 0x38F2, 0x39 }, + { 0x38F3, 0x01 }, + { 0x38F4, 0xD5 }, + { 0x38F5, 0x00 }, + { 0x38F6, 0x9F }, + { 0x38F7, 0x00 }, + { 0x38F8, 0x75 }, + { 0x38F9, 0x00 }, + { 0x38FA, 0x00 }, + { 0x38FB, 0x01 }, + { 0x38FC, 0x00 }, + { 0x38FD, 0x01 }, + { 0x38FE, 0x00 }, + { 0x38FF, 0x01 }, + { 0x3900, 0x00 }, + { 0x3901, 0x01 }, + { 0x3902, 0x70 }, + { 0x3903, 0x00 }, + { 0x3904, 0x30 }, + { 0x3905, 0x00 }, + { 0x3906, 0x25 }, + { 0x3907, 0x00 }, + { 0x3908, 0x20 }, + { 0x3909, 0x00 }, + { 0x390A, 0xB2 }, + { 0x390B, 0x00 }, + { 0x390C, 0x80 }, + { 0x390D, 0x00 }, + { 0x390E, 0x70 }, + { 0x390F, 0x00 }, + { 0x3910, 0x50 }, + { 0x3911, 0x00 }, + { 0x3912, 0xB2 }, + { 0x3913, 0x00 }, + { 0x3914, 0x80 }, + { 0x3915, 0x00 }, + { 0x3916, 0x70 }, + { 0x3917, 0x00 }, + { 0x3918, 0x50 }, + { 0x3919, 0x00 }, + { 0x391A, 0xB2 }, + { 0x391B, 0x00 }, + { 0x391C, 0x80 }, + { 0x391D, 0x00 }, + { 0x391E, 0x70 }, + { 0x391F, 0x00 }, + { 0x3920, 0x50 }, + { 0x3921, 0x00 }, + { 0x3922, 0x40 }, + { 0x3923, 0x00 }, + { 0x3924, 0x40 }, + { 0x3925, 0x00 }, + { 0x3926, 0x40 }, + { 0x3927, 0x00 }, + { 0x3928, 0x40 }, + { 0x3929, 0x00 }, + { 0x392A, 0x80 }, + { 0x392B, 0x00 }, + { 0x392C, 0x80 }, + { 0x392D, 0x00 }, + { 0x392E, 0x80 }, + { 0x392F, 0x00 }, + { 0x3930, 0x80 }, + { 0x3931, 0x00 }, + { 0x3932, 0x80 }, + { 0x3933, 0x80 }, + { 0x3934, 0x80 }, + { 0x3940, 0x01 }, + { 0x3941, 0x01 }, + { 0x3942, 0x00 }, + { 0x3943, 0x01 }, + { 0x3944, 0x07 }, + { 0x3945, 0x00 }, + { 0x3946, 0x04 }, + { 0x3947, 0x05 }, + { 0x3948, 0x00 }, + { 0x3949, 0x00 }, + { 0x394C, 0x00 }, + { 0x394D, 0x00 }, + { 0x394E, 0x01 }, + { 0x3950, 0x03 }, + { 0x3952, 0x14 }, + { 0x3953, 0x00 }, + { 0x3954, 0x0F }, + { 0x3955, 0x00 }, + { 0x3956, 0x0E }, + { 0x3957, 0x00 }, + { 0x3958, 0x0E }, + { 0x3959, 0x00 }, + { 0x395A, 0x19 }, + { 0x395B, 0x00 }, + { 0x395C, 0x11 }, + { 0x395D, 0x00 }, + { 0x395E, 0x0F }, + { 0x395F, 0x00 }, + { 0x3960, 0x0E }, + { 0x3961, 0x00 }, + { 0x3962, 0x1C }, + { 0x3963, 0x00 }, + { 0x3964, 0x13 }, + { 0x3965, 0x00 }, + { 0x3966, 0x0F }, + { 0x3967, 0x00 }, + { 0x3968, 0x0E }, + { 0x3969, 0x00 }, + { 0x396A, 0x23 }, + { 0x396B, 0x00 }, + { 0x396C, 0x15 }, + { 0x396D, 0x00 }, + { 0x396E, 0x11 }, + { 0x396F, 0x00 }, + { 0x3970, 0x0E }, + { 0x3971, 0x00 }, + { 0x3972, 0x2E }, + { 0x3973, 0x00 }, + { 0x3974, 0x1A }, + { 0x3975, 0x00 }, + { 0x3976, 0x14 }, + { 0x3977, 0x00 }, + { 0x3978, 0x0F }, + { 0x3979, 0x00 }, + { 0x397A, 0x3E }, + { 0x397B, 0x00 }, + { 0x397C, 0x23 }, + { 0x397D, 0x00 }, + { 0x397E, 0x1A }, + { 0x397F, 0x00 }, + { 0x3980, 0x12 }, + { 0x3981, 0x00 }, + { 0x3982, 0x56 }, + { 0x3983, 0x00 }, + { 0x3984, 0x31 }, + { 0x3985, 0x00 }, + { 0x3986, 0x25 }, + { 0x3987, 0x00 }, + { 0x3988, 0x1A }, + { 0x3989, 0x00 }, + { 0x398A, 0x7B }, + { 0x398B, 0x00 }, + { 0x398C, 0x49 }, + { 0x398D, 0x00 }, + { 0x398E, 0x39 }, + { 0x398F, 0x00 }, + { 0x3990, 0x2C }, + { 0x3991, 0x00 }, + { 0x3992, 0xB4 }, + { 0x3993, 0x00 }, + { 0x3994, 0x75 }, + { 0x3995, 0x00 }, + { 0x3996, 0x61 }, + { 0x3997, 0x00 }, + { 0x3998, 0x53 }, + { 0x3999, 0x00 }, + { 0x399A, 0x00 }, + { 0x399B, 0x01 }, + { 0x399C, 0x00 }, + { 0x399D, 0x01 }, + { 0x399E, 0x00 }, + { 0x399F, 0x01 }, + { 0x39A0, 0x00 }, + { 0x39A1, 0x01 }, + { 0x39A2, 0x70 }, + { 0x39A3, 0x00 }, + { 0x39A4, 0x30 }, + { 0x39A5, 0x00 }, + { 0x39A6, 0x25 }, + { 0x39A7, 0x00 }, + { 0x39A8, 0x20 }, + { 0x39A9, 0x00 }, + { 0x39AA, 0xB2 }, + { 0x39AB, 0x00 }, + { 0x39AC, 0x80 }, + { 0x39AD, 0x00 }, + { 0x39AE, 0x70 }, + { 0x39AF, 0x00 }, + { 0x39B0, 0x80 }, + { 0x39B1, 0x00 }, + { 0x39B2, 0xB2 }, + { 0x39B3, 0x00 }, + { 0x39B4, 0x80 }, + { 0x39B5, 0x00 }, + { 0x39B6, 0x70 }, + { 0x39B7, 0x00 }, + { 0x39B8, 0x80 }, + { 0x39B9, 0x00 }, + { 0x39BA, 0xB2 }, + { 0x39BB, 0x00 }, + { 0x39BC, 0x80 }, + { 0x39BD, 0x00 }, + { 0x39BE, 0x70 }, + { 0x39BF, 0x00 }, + { 0x39C0, 0x80 }, + { 0x39C1, 0x00 }, + { 0x39C2, 0x40 }, + { 0x39C3, 0x00 }, + { 0x39C4, 0x40 }, + { 0x39C5, 0x00 }, + { 0x39C6, 0x40 }, + { 0x39C7, 0x00 }, + { 0x39C8, 0x40 }, + { 0x39C9, 0x00 }, + { 0x39CA, 0x80 }, + { 0x39CB, 0x00 }, + { 0x39CC, 0x80 }, + { 0x39CD, 0x00 }, + { 0x39CE, 0x80 }, + { 0x39CF, 0x00 }, + { 0x39D0, 0x80 }, + { 0x39D1, 0x00 }, + { 0x39D2, 0x80 }, + { 0x39D3, 0x80 }, + { 0x39D4, 0x80 }, + { 0x39E0, 0x01 }, + { 0x39E1, 0x00 }, + { 0x39E4, 0x40 }, + { 0x39E5, 0x01 }, + { 0x39E6, 0x01 }, + { 0x39E8, 0x00 }, + { 0x39E9, 0x01 }, + { 0x39EA, 0x00 }, + { 0x39EB, 0x00 }, + { 0x39EC, 0x01 }, + { 0x39ED, 0x00 }, + { 0x39EE, 0x01 }, + { 0x39F0, 0x03 }, + { 0x39F1, 0x04 }, + { 0x39F2, 0x0E }, + { 0x39F4, 0x1C }, + { 0x39F5, 0x00 }, + { 0x39F6, 0x13 }, + { 0x39F7, 0x00 }, + { 0x39F8, 0x0D }, + { 0x39F9, 0x00 }, + { 0x39FA, 0x07 }, + { 0x39FB, 0x00 }, + { 0x39FC, 0x38 }, + { 0x39FD, 0x00 }, + { 0x39FE, 0x1C }, + { 0x39FF, 0x00 }, + { 0x3A00, 0x11 }, + { 0x3A01, 0x00 }, + { 0x3A02, 0x08 }, + { 0x3A03, 0x00 }, + { 0x3A04, 0x4A }, + { 0x3A05, 0x00 }, + { 0x3A06, 0x23 }, + { 0x3A07, 0x00 }, + { 0x3A08, 0x15 }, + { 0x3A09, 0x00 }, + { 0x3A0A, 0x09 }, + { 0x3A0B, 0x00 }, + { 0x3A0C, 0x65 }, + { 0x3A0D, 0x00 }, + { 0x3A0E, 0x2D }, + { 0x3A0F, 0x00 }, + { 0x3A10, 0x1A }, + { 0x3A11, 0x00 }, + { 0x3A12, 0x0B }, + { 0x3A13, 0x00 }, + { 0x3A14, 0x8D }, + { 0x3A15, 0x00 }, + { 0x3A16, 0x3D }, + { 0x3A17, 0x00 }, + { 0x3A18, 0x23 }, + { 0x3A19, 0x00 }, + { 0x3A1A, 0x0E }, + { 0x3A1B, 0x00 }, + { 0x3A1C, 0xC5 }, + { 0x3A1D, 0x00 }, + { 0x3A1E, 0x55 }, + { 0x3A1F, 0x00 }, + { 0x3A20, 0x30 }, + { 0x3A21, 0x00 }, + { 0x3A22, 0x13 }, + { 0x3A23, 0x00 }, + { 0x3A24, 0x16 }, + { 0x3A25, 0x01 }, + { 0x3A26, 0x76 }, + { 0x3A27, 0x00 }, + { 0x3A28, 0x42 }, + { 0x3A29, 0x00 }, + { 0x3A2A, 0x1A }, + { 0x3A2B, 0x00 }, + { 0x3A2C, 0x88 }, + { 0x3A2D, 0x01 }, + { 0x3A2E, 0xA7 }, + { 0x3A2F, 0x00 }, + { 0x3A30, 0x5D }, + { 0x3A31, 0x00 }, + { 0x3A32, 0x24 }, + { 0x3A33, 0x00 }, + { 0x3A34, 0x2A }, + { 0x3A35, 0x02 }, + { 0x3A36, 0xEB }, + { 0x3A37, 0x00 }, + { 0x3A38, 0x83 }, + { 0x3A39, 0x00 }, + { 0x3A3A, 0x32 }, + { 0x3A3B, 0x00 }, + { 0x3A3C, 0x00 }, + { 0x3A3D, 0x01 }, + { 0x3A3E, 0x00 }, + { 0x3A3F, 0x01 }, + { 0x3A40, 0x00 }, + { 0x3A41, 0x01 }, + { 0x3A42, 0x00 }, + { 0x3A43, 0x01 }, + { 0x3A44, 0x80 }, + { 0x3A45, 0x00 }, + { 0x3A46, 0x50 }, + { 0x3A47, 0x00 }, + { 0x3A48, 0x30 }, + { 0x3A49, 0x00 }, + { 0x3A4A, 0x20 }, + { 0x3A4B, 0x00 }, + { 0x3A4C, 0x99 }, + { 0x3A4D, 0x00 }, + { 0x3A4E, 0x80 }, + { 0x3A4F, 0x00 }, + { 0x3A50, 0x80 }, + { 0x3A51, 0x00 }, + { 0x3A52, 0x80 }, + { 0x3A53, 0x00 }, + { 0x3A54, 0x99 }, + { 0x3A55, 0x00 }, + { 0x3A56, 0x80 }, + { 0x3A57, 0x00 }, + { 0x3A58, 0x80 }, + { 0x3A59, 0x00 }, + { 0x3A5A, 0x80 }, + { 0x3A5B, 0x00 }, + { 0x3A5C, 0x99 }, + { 0x3A5D, 0x00 }, + { 0x3A5E, 0x80 }, + { 0x3A5F, 0x00 }, + { 0x3A60, 0x80 }, + { 0x3A61, 0x00 }, + { 0x3A62, 0x80 }, + { 0x3A63, 0x00 }, + { 0x3A64, 0x1C }, + { 0x3A65, 0x00 }, + { 0x3A66, 0x13 }, + { 0x3A67, 0x00 }, + { 0x3A68, 0x0D }, + { 0x3A69, 0x00 }, + { 0x3A6A, 0x07 }, + { 0x3A6B, 0x00 }, + { 0x3A6C, 0x0C }, + { 0x3A6D, 0x00 }, + { 0x3A6E, 0x09 }, + { 0x3A6F, 0x00 }, + { 0x3A70, 0x06 }, + { 0x3A71, 0x00 }, + { 0x3A72, 0x03 }, + { 0x3A73, 0x00 }, + { 0x3A74, 0x1F }, + { 0x3A75, 0x00 }, + { 0x3A76, 0x1B }, + { 0x3A77, 0x00 }, + { 0x3A78, 0x0F }, + { 0x3A79, 0x00 }, + { 0x3A7A, 0x08 }, + { 0x3A7B, 0x00 }, + { 0x3A7C, 0x80 }, + { 0x3A7D, 0x00 }, + { 0x3A7E, 0x80 }, + { 0x3A7F, 0x00 }, + { 0x3A80, 0x80 }, + { 0x3A81, 0x00 }, + { 0x3A82, 0x80 }, + { 0x3A83, 0x00 }, + { 0x3A84, 0x09 }, + { 0x3A85, 0x00 }, + { 0x3A86, 0x04 }, + { 0x3A87, 0x00 }, + { 0x3A88, 0x03 }, + { 0x3A89, 0x00 }, + { 0x3A8A, 0x01 }, + { 0x3A8B, 0x00 }, + { 0x3A8C, 0x19 }, + { 0x3A8D, 0x01 }, + { 0x3A8E, 0xD2 }, + { 0x3A8F, 0x00 }, + { 0x3A90, 0x8C }, + { 0x3A91, 0x00 }, + { 0x3A92, 0x64 }, + { 0x3A93, 0x00 }, + { 0x3A94, 0xFF }, + { 0x3A95, 0x00 }, + { 0x3A96, 0xD2 }, + { 0x3A97, 0x00 }, + { 0x3A98, 0x8C }, + { 0x3A99, 0x00 }, + { 0x3A9A, 0x64 }, + { 0x3A9B, 0x00 }, + { 0x3A9C, 0x08 }, + { 0x3A9D, 0x10 }, + { 0x3A9E, 0x80 }, + { 0x3A9F, 0x80 }, + { 0x3AA0, 0x80 }, + { 0x3AA1, 0x04 }, + { 0x3AA2, 0x05 }, + { 0x3AC0, 0x01 }, + { 0x3AC4, 0x81 }, + { 0x3AC5, 0x00 }, + { 0x3AC6, 0x00 }, + { 0x3AC7, 0x00 }, + { 0x3AC8, 0x00 }, + { 0x3AC9, 0x00 }, + { 0x3ACA, 0x00 }, + { 0x3ACB, 0x00 }, + { 0x3ACC, 0x02 }, + { 0x3ACD, 0x00 }, + { 0x3ACE, 0x81 }, + { 0x3ACF, 0x00 }, + { 0x3AD0, 0x00 }, + { 0x3AD1, 0x00 }, + { 0x3AD2, 0xFD }, + { 0x3AD3, 0x03 }, + { 0x3AD4, 0x02 }, + { 0x3AD5, 0x00 }, + { 0x3AD6, 0x00 }, + { 0x3AD7, 0x00 }, + { 0x3AD8, 0x81 }, + { 0x3AD9, 0x00 }, + { 0x3ADA, 0xFD }, + { 0x3ADB, 0x03 }, + { 0x3ADC, 0xFF }, + { 0x3ADD, 0x03 }, + { 0x3ADE, 0x01 }, + { 0x3ADF, 0x00 }, + { 0x3AE0, 0x01 }, + { 0x3AE1, 0x00 }, + { 0x3AE2, 0x7E }, + { 0x3AE3, 0x00 }, + { 0x3AF4, 0x00 }, + { 0x3AF6, 0x40 }, + { 0x3AF7, 0x1E }, + { 0x3AF8, 0x01 }, + { 0x3AFA, 0x63 }, + { 0x3AFB, 0x09 }, + { 0x3AFC, 0x11 }, + { 0x3AFD, 0x09 }, + { 0x3AFE, 0x00 }, + { 0x3AFF, 0x00 }, + { 0x3B00, 0x00 }, + { 0x3B01, 0x00 }, + { 0x3B02, 0x84 }, + { 0x3B03, 0x06 }, + { 0x3B04, 0x30 }, + { 0x3B05, 0x06 }, + { 0x3B06, 0x00 }, + { 0x3B07, 0x00 }, + { 0x3B08, 0x00 }, + { 0x3B09, 0x00 }, + { 0x3B0A, 0x00 }, + { 0x3B0B, 0x00 }, + { 0x3B0C, 0x00 }, + { 0x3B0D, 0x00 }, + { 0x3B0E, 0x00 }, + { 0x3B0F, 0x00 }, + { 0x3B10, 0x00 }, + { 0x3B11, 0x00 }, + { 0x3B12, 0x00 }, + { 0x3B13, 0x00 }, + { 0x3B14, 0x00 }, + { 0x3B15, 0x00 }, + { 0x3B16, 0x00 }, + { 0x3B17, 0x00 }, + { 0x3B18, 0x00 }, + { 0x3B19, 0x00 }, + { 0x3B1A, 0x00 }, + { 0x3B1B, 0x00 }, + { 0x3B1C, 0x00 }, + { 0x3B1D, 0x00 }, + { 0x3B1E, 0x00 }, + { 0x3B1F, 0x00 }, + { 0x3B20, 0x00 }, + { 0x3B21, 0x00 }, + { 0x3B22, 0x00 }, + { 0x3B23, 0x00 }, + { 0x3B24, 0x00 }, + { 0x3B25, 0x00 }, + { 0x3B26, 0x00 }, + { 0x3B27, 0x00 }, + { 0x3B28, 0x00 }, + { 0x3B29, 0x00 }, + { 0x3B2A, 0x00 }, + { 0x3B2C, 0x00 }, + { 0x3B2E, 0x00 }, + { 0x3B30, 0x00 }, + { 0x3B32, 0x0C }, + { 0x4000, 0xD1 }, + { 0x4001, 0xC0 }, + { 0x4002, 0xC0 }, + { 0x4003, 0xB8 }, + { 0x4004, 0xC0 }, + { 0x4005, 0xB8 }, + { 0x4006, 0xB9 }, + { 0x4007, 0xB7 }, + { 0x4008, 0xB0 }, + { 0x4009, 0xAB }, + { 0x400A, 0xAC }, + { 0x400B, 0xAB }, + { 0x400C, 0xA8 }, + { 0x400D, 0xA6 }, + { 0x400E, 0xA6 }, + { 0x400F, 0xA5 }, + { 0x4010, 0xA2 }, + { 0x4011, 0xA0 }, + { 0x4012, 0xA0 }, + { 0x4013, 0x9F }, + { 0x4014, 0xA4 }, + { 0x4015, 0xA2 }, + { 0x4016, 0xA2 }, + { 0x4017, 0x9C }, + { 0x4018, 0xA8 }, + { 0x4019, 0xA6 }, + { 0x401A, 0xA8 }, + { 0x401B, 0xAA }, + { 0x401C, 0xB0 }, + { 0x401D, 0xAE }, + { 0x401E, 0xAE }, + { 0x401F, 0xAE }, + { 0x4020, 0xBA }, + { 0x4021, 0xAE }, + { 0x4022, 0xAF }, + { 0x4023, 0xAE }, + { 0x4024, 0xC6 }, + { 0x4025, 0xBD }, + { 0x4026, 0xBD }, + { 0x4027, 0xBA }, + { 0x4028, 0xB0 }, + { 0x4029, 0xA9 }, + { 0x402A, 0xAA }, + { 0x402B, 0xA8 }, + { 0x402C, 0x9F }, + { 0x402D, 0x9C }, + { 0x402E, 0x9C }, + { 0x402F, 0x9B }, + { 0x4030, 0x93 }, + { 0x4031, 0x91 }, + { 0x4032, 0x92 }, + { 0x4033, 0x91 }, + { 0x4034, 0x8D }, + { 0x4035, 0x8C }, + { 0x4036, 0x8C }, + { 0x4037, 0x8C }, + { 0x4038, 0x8F }, + { 0x4039, 0x8E }, + { 0x403A, 0x8E }, + { 0x403B, 0x8E }, + { 0x403C, 0x98 }, + { 0x403D, 0x96 }, + { 0x403E, 0x96 }, + { 0x403F, 0x95 }, + { 0x4040, 0xA4 }, + { 0x4041, 0xA0 }, + { 0x4042, 0xA0 }, + { 0x4043, 0x9E }, + { 0x4044, 0xB3 }, + { 0x4045, 0xAE }, + { 0x4046, 0xAF }, + { 0x4047, 0xAB }, + { 0x4048, 0xC2 }, + { 0x4049, 0xB7 }, + { 0x404A, 0xB8 }, + { 0x404B, 0xB5 }, + { 0x404C, 0xAB }, + { 0x404D, 0xA4 }, + { 0x404E, 0xA5 }, + { 0x404F, 0xA3 }, + { 0x4050, 0x99 }, + { 0x4051, 0x96 }, + { 0x4052, 0x96 }, + { 0x4053, 0x96 }, + { 0x4054, 0x8B }, + { 0x4055, 0x8A }, + { 0x4056, 0x8A }, + { 0x4057, 0x8A }, + { 0x4058, 0x82 }, + { 0x4059, 0x81 }, + { 0x405A, 0x81 }, + { 0x405B, 0x81 }, + { 0x405C, 0x85 }, + { 0x405D, 0x86 }, + { 0x405E, 0x85 }, + { 0x405F, 0x85 }, + { 0x4060, 0x90 }, + { 0x4061, 0x90 }, + { 0x4062, 0x8F }, + { 0x4063, 0x8F }, + { 0x4064, 0x9D }, + { 0x4065, 0x9B }, + { 0x4066, 0x9B }, + { 0x4067, 0x9A }, + { 0x4068, 0xAF }, + { 0x4069, 0xAA }, + { 0x406A, 0xAC }, + { 0x406B, 0xAA }, + { 0x406C, 0xC2 }, + { 0x406D, 0xB7 }, + { 0x406E, 0xB8 }, + { 0x406F, 0xB5 }, + { 0x4070, 0xAB }, + { 0x4071, 0xA4 }, + { 0x4072, 0xA4 }, + { 0x4073, 0xA3 }, + { 0x4074, 0x99 }, + { 0x4075, 0x96 }, + { 0x4076, 0x96 }, + { 0x4077, 0x96 }, + { 0x4078, 0x8B }, + { 0x4079, 0x8A }, + { 0x407A, 0x8A }, + { 0x407B, 0x8A }, + { 0x407C, 0x82 }, + { 0x407D, 0x82 }, + { 0x407E, 0x82 }, + { 0x407F, 0x82 }, + { 0x4080, 0x85 }, + { 0x4081, 0x86 }, + { 0x4082, 0x86 }, + { 0x4083, 0x86 }, + { 0x4084, 0x90 }, + { 0x4085, 0x90 }, + { 0x4086, 0x8F }, + { 0x4087, 0x8F }, + { 0x4088, 0x9D }, + { 0x4089, 0x9B }, + { 0x408A, 0x9B }, + { 0x408B, 0x99 }, + { 0x408C, 0xAE }, + { 0x408D, 0xAA }, + { 0x408E, 0xAA }, + { 0x408F, 0xA7 }, + { 0x4090, 0xC7 }, + { 0x4091, 0xBA }, + { 0x4092, 0xBC }, + { 0x4093, 0xB9 }, + { 0x4094, 0xB1 }, + { 0x4095, 0xA8 }, + { 0x4096, 0xA8 }, + { 0x4097, 0xA7 }, + { 0x4098, 0x9F }, + { 0x4099, 0x9B }, + { 0x409A, 0x9B }, + { 0x409B, 0x9B }, + { 0x409C, 0x93 }, + { 0x409D, 0x91 }, + { 0x409E, 0x91 }, + { 0x409F, 0x91 }, + { 0x40A0, 0x8D }, + { 0x40A1, 0x8C }, + { 0x40A2, 0x8C }, + { 0x40A3, 0x8C }, + { 0x40A4, 0x8E }, + { 0x40A5, 0x8E }, + { 0x40A6, 0x8D }, + { 0x40A7, 0x8D }, + { 0x40A8, 0x96 }, + { 0x40A9, 0x95 }, + { 0x40AA, 0x95 }, + { 0x40AB, 0x94 }, + { 0x40AC, 0xA2 }, + { 0x40AD, 0x9F }, + { 0x40AE, 0x9F }, + { 0x40AF, 0x9D }, + { 0x40B0, 0xB1 }, + { 0x40B1, 0xAC }, + { 0x40B2, 0xAB }, + { 0x40B3, 0xAA }, + { 0x40B4, 0xD3 }, + { 0x40B5, 0xBC }, + { 0x40B6, 0xBD }, + { 0x40B7, 0xBC }, + { 0x40B8, 0xC1 }, + { 0x40B9, 0xB7 }, + { 0x40BA, 0xB7 }, + { 0x40BB, 0xB5 }, + { 0x40BC, 0xB0 }, + { 0x40BD, 0xAA }, + { 0x40BE, 0xAA }, + { 0x40BF, 0xAA }, + { 0x40C0, 0xA8 }, + { 0x40C1, 0xA4 }, + { 0x40C2, 0xA4 }, + { 0x40C3, 0xA4 }, + { 0x40C4, 0xA2 }, + { 0x40C5, 0x9F }, + { 0x40C6, 0x9F }, + { 0x40C7, 0x9F }, + { 0x40C8, 0xA3 }, + { 0x40C9, 0xA0 }, + { 0x40CA, 0xA0 }, + { 0x40CB, 0xA0 }, + { 0x40CC, 0xA6 }, + { 0x40CD, 0xA3 }, + { 0x40CE, 0xA3 }, + { 0x40CF, 0xA2 }, + { 0x40D0, 0xAF }, + { 0x40D1, 0xAB }, + { 0x40D2, 0xAA }, + { 0x40D3, 0xA8 }, + { 0x40D4, 0xBA }, + { 0x40D5, 0xAE }, + { 0x40D6, 0xAE }, + { 0x40D7, 0xAB }, + { 0x4100, 0xBD }, + { 0x4101, 0xBA }, + { 0x4102, 0xBD }, + { 0x4103, 0xB7 }, + { 0x4104, 0xB7 }, + { 0x4105, 0xB7 }, + { 0x4106, 0xB8 }, + { 0x4107, 0xB5 }, + { 0x4108, 0xAB }, + { 0x4109, 0xAA }, + { 0x410A, 0xAC }, + { 0x410B, 0xAB }, + { 0x410C, 0xA4 }, + { 0x410D, 0xA5 }, + { 0x410E, 0xA5 }, + { 0x410F, 0xA4 }, + { 0x4110, 0x9F }, + { 0x4111, 0xA0 }, + { 0x4112, 0xA0 }, + { 0x4113, 0x9F }, + { 0x4114, 0xA0 }, + { 0x4115, 0xA0 }, + { 0x4116, 0xA0 }, + { 0x4117, 0x9F }, + { 0x4118, 0xA1 }, + { 0x4119, 0xA1 }, + { 0x411A, 0xA1 }, + { 0x411B, 0xA0 }, + { 0x411C, 0xA7 }, + { 0x411D, 0xA6 }, + { 0x411E, 0xA6 }, + { 0x411F, 0xA6 }, + { 0x4120, 0xA7 }, + { 0x4121, 0xA6 }, + { 0x4122, 0xA6 }, + { 0x4123, 0xA3 }, + { 0x4124, 0xB9 }, + { 0x4125, 0xB9 }, + { 0x4126, 0xBA }, + { 0x4127, 0xB8 }, + { 0x4128, 0xA6 }, + { 0x4129, 0xA7 }, + { 0x412A, 0xA7 }, + { 0x412B, 0xA6 }, + { 0x412C, 0x9B }, + { 0x412D, 0x9B }, + { 0x412E, 0x9B }, + { 0x412F, 0x9B }, + { 0x4130, 0x91 }, + { 0x4131, 0x92 }, + { 0x4132, 0x92 }, + { 0x4133, 0x91 }, + { 0x4134, 0x8C }, + { 0x4135, 0x8C }, + { 0x4136, 0x8C }, + { 0x4137, 0x8C }, + { 0x4138, 0x8D }, + { 0x4139, 0x8D }, + { 0x413A, 0x8D }, + { 0x413B, 0x8D }, + { 0x413C, 0x93 }, + { 0x413D, 0x93 }, + { 0x413E, 0x93 }, + { 0x413F, 0x92 }, + { 0x4140, 0x9A }, + { 0x4141, 0x9A }, + { 0x4142, 0x9A }, + { 0x4143, 0x99 }, + { 0x4144, 0xA7 }, + { 0x4145, 0xA5 }, + { 0x4146, 0xA6 }, + { 0x4147, 0xA6 }, + { 0x4148, 0xB8 }, + { 0x4149, 0xB4 }, + { 0x414A, 0xB4 }, + { 0x414B, 0xB3 }, + { 0x414C, 0xA3 }, + { 0x414D, 0xA2 }, + { 0x414E, 0xA3 }, + { 0x414F, 0xA2 }, + { 0x4150, 0x96 }, + { 0x4151, 0x96 }, + { 0x4152, 0x96 }, + { 0x4153, 0x96 }, + { 0x4154, 0x8A }, + { 0x4155, 0x8A }, + { 0x4156, 0x8A }, + { 0x4157, 0x8A }, + { 0x4158, 0x82 }, + { 0x4159, 0x82 }, + { 0x415A, 0x82 }, + { 0x415B, 0x82 }, + { 0x415C, 0x84 }, + { 0x415D, 0x85 }, + { 0x415E, 0x84 }, + { 0x415F, 0x84 }, + { 0x4160, 0x8D }, + { 0x4161, 0x8D }, + { 0x4162, 0x8D }, + { 0x4163, 0x8D }, + { 0x4164, 0x96 }, + { 0x4165, 0x96 }, + { 0x4166, 0x96 }, + { 0x4167, 0x95 }, + { 0x4168, 0xA5 }, + { 0x4169, 0xA2 }, + { 0x416A, 0xA3 }, + { 0x416B, 0xA2 }, + { 0x416C, 0xB7 }, + { 0x416D, 0xB3 }, + { 0x416E, 0xB5 }, + { 0x416F, 0xB4 }, + { 0x4170, 0xA4 }, + { 0x4171, 0xA2 }, + { 0x4172, 0xA3 }, + { 0x4173, 0xA2 }, + { 0x4174, 0x97 }, + { 0x4175, 0x96 }, + { 0x4176, 0x96 }, + { 0x4177, 0x96 }, + { 0x4178, 0x8B }, + { 0x4179, 0x8A }, + { 0x417A, 0x8A }, + { 0x417B, 0x8A }, + { 0x417C, 0x81 }, + { 0x417D, 0x81 }, + { 0x417E, 0x81 }, + { 0x417F, 0x81 }, + { 0x4180, 0x84 }, + { 0x4181, 0x84 }, + { 0x4182, 0x84 }, + { 0x4183, 0x84 }, + { 0x4184, 0x8C }, + { 0x4185, 0x8D }, + { 0x4186, 0x8D }, + { 0x4187, 0x8D }, + { 0x4188, 0x95 }, + { 0x4189, 0x96 }, + { 0x418A, 0x96 }, + { 0x418B, 0x95 }, + { 0x418C, 0xA1 }, + { 0x418D, 0xA1 }, + { 0x418E, 0xA1 }, + { 0x418F, 0xA0 }, + { 0x4190, 0xBC }, + { 0x4191, 0xB8 }, + { 0x4192, 0xB8 }, + { 0x4193, 0xB9 }, + { 0x4194, 0xA8 }, + { 0x4195, 0xA5 }, + { 0x4196, 0xA6 }, + { 0x4197, 0xA5 }, + { 0x4198, 0x9C }, + { 0x4199, 0x9A }, + { 0x419A, 0x9A }, + { 0x419B, 0x9A }, + { 0x419C, 0x91 }, + { 0x419D, 0x91 }, + { 0x419E, 0x91 }, + { 0x419F, 0x91 }, + { 0x41A0, 0x8B }, + { 0x41A1, 0x8B }, + { 0x41A2, 0x8B }, + { 0x41A3, 0x8B }, + { 0x41A4, 0x8C }, + { 0x41A5, 0x8C }, + { 0x41A6, 0x8C }, + { 0x41A7, 0x8C }, + { 0x41A8, 0x91 }, + { 0x41A9, 0x92 }, + { 0x41AA, 0x91 }, + { 0x41AB, 0x91 }, + { 0x41AC, 0x98 }, + { 0x41AD, 0x99 }, + { 0x41AE, 0x99 }, + { 0x41AF, 0x98 }, + { 0x41B0, 0xA3 }, + { 0x41B1, 0xA3 }, + { 0x41B2, 0xA3 }, + { 0x41B3, 0xA2 }, + { 0x41B4, 0xC1 }, + { 0x41B5, 0xB8 }, + { 0x41B6, 0xB9 }, + { 0x41B7, 0xBA }, + { 0x41B8, 0xB8 }, + { 0x41B9, 0xB4 }, + { 0x41BA, 0xB4 }, + { 0x41BB, 0xB4 }, + { 0x41BC, 0xAA }, + { 0x41BD, 0xA7 }, + { 0x41BE, 0xA7 }, + { 0x41BF, 0xA8 }, + { 0x41C0, 0xA4 }, + { 0x41C1, 0xA2 }, + { 0x41C2, 0xA2 }, + { 0x41C3, 0xA3 }, + { 0x41C4, 0x9E }, + { 0x41C5, 0x9D }, + { 0x41C6, 0x9D }, + { 0x41C7, 0x9D }, + { 0x41C8, 0x9E }, + { 0x41C9, 0x9D }, + { 0x41CA, 0x9D }, + { 0x41CB, 0x9D }, + { 0x41CC, 0x9E }, + { 0x41CD, 0x9E }, + { 0x41CE, 0x9E }, + { 0x41CF, 0x9E }, + { 0x41D0, 0xA3 }, + { 0x41D1, 0xA3 }, + { 0x41D2, 0xA2 }, + { 0x41D3, 0xA1 }, + { 0x41D4, 0xA7 }, + { 0x41D5, 0xA7 }, + { 0x41D6, 0xA7 }, + { 0x41D7, 0xA3 }, + { 0x4200, 0xCE }, + { 0x4201, 0xC0 }, + { 0x4202, 0xC1 }, + { 0x4203, 0xB9 }, + { 0x4204, 0xC3 }, + { 0x4205, 0xB9 }, + { 0x4206, 0xBC }, + { 0x4207, 0xBD }, + { 0x4208, 0xB3 }, + { 0x4209, 0xAE }, + { 0x420A, 0xAF }, + { 0x420B, 0xAE }, + { 0x420C, 0xAA }, + { 0x420D, 0xA8 }, + { 0x420E, 0xA8 }, + { 0x420F, 0xA6 }, + { 0x4210, 0xA4 }, + { 0x4211, 0xA2 }, + { 0x4212, 0xA2 }, + { 0x4213, 0xA0 }, + { 0x4214, 0xA4 }, + { 0x4215, 0xA3 }, + { 0x4216, 0xA2 }, + { 0x4217, 0xA0 }, + { 0x4218, 0xA7 }, + { 0x4219, 0xA5 }, + { 0x421A, 0xA3 }, + { 0x421B, 0xA1 }, + { 0x421C, 0xB0 }, + { 0x421D, 0xA8 }, + { 0x421E, 0xA8 }, + { 0x421F, 0xA6 }, + { 0x4220, 0xB4 }, + { 0x4221, 0xAA }, + { 0x4222, 0xA5 }, + { 0x4223, 0xA3 }, + { 0x4224, 0xC7 }, + { 0x4225, 0xBC }, + { 0x4226, 0xBE }, + { 0x4227, 0xBC }, + { 0x4228, 0xB0 }, + { 0x4229, 0xA9 }, + { 0x422A, 0xA9 }, + { 0x422B, 0xA8 }, + { 0x422C, 0xA0 }, + { 0x422D, 0x9D }, + { 0x422E, 0x9D }, + { 0x422F, 0x9C }, + { 0x4230, 0x94 }, + { 0x4231, 0x93 }, + { 0x4232, 0x93 }, + { 0x4233, 0x92 }, + { 0x4234, 0x8E }, + { 0x4235, 0x8D }, + { 0x4236, 0x8D }, + { 0x4237, 0x8C }, + { 0x4238, 0x8F }, + { 0x4239, 0x8E }, + { 0x423A, 0x8E }, + { 0x423B, 0x8D }, + { 0x423C, 0x96 }, + { 0x423D, 0x94 }, + { 0x423E, 0x94 }, + { 0x423F, 0x92 }, + { 0x4240, 0xA1 }, + { 0x4241, 0x9C }, + { 0x4242, 0x9C }, + { 0x4243, 0x99 }, + { 0x4244, 0xB0 }, + { 0x4245, 0xA8 }, + { 0x4246, 0xAB }, + { 0x4247, 0xA7 }, + { 0x4248, 0xC3 }, + { 0x4249, 0xB7 }, + { 0x424A, 0xB7 }, + { 0x424B, 0xBC }, + { 0x424C, 0xAB }, + { 0x424D, 0xA4 }, + { 0x424E, 0xA5 }, + { 0x424F, 0xA5 }, + { 0x4250, 0x9A }, + { 0x4251, 0x97 }, + { 0x4252, 0x97 }, + { 0x4253, 0x98 }, + { 0x4254, 0x8C }, + { 0x4255, 0x8B }, + { 0x4256, 0x8B }, + { 0x4257, 0x8B }, + { 0x4258, 0x82 }, + { 0x4259, 0x82 }, + { 0x425A, 0x82 }, + { 0x425B, 0x82 }, + { 0x425C, 0x85 }, + { 0x425D, 0x85 }, + { 0x425E, 0x85 }, + { 0x425F, 0x84 }, + { 0x4260, 0x8F }, + { 0x4261, 0x8E }, + { 0x4262, 0x8E }, + { 0x4263, 0x8D }, + { 0x4264, 0x9B }, + { 0x4265, 0x98 }, + { 0x4266, 0x98 }, + { 0x4267, 0x95 }, + { 0x4268, 0xAE }, + { 0x4269, 0xA5 }, + { 0x426A, 0xA7 }, + { 0x426B, 0xA2 }, + { 0x426C, 0xC2 }, + { 0x426D, 0xB7 }, + { 0x426E, 0xB8 }, + { 0x426F, 0xB9 }, + { 0x4270, 0xAA }, + { 0x4271, 0xA4 }, + { 0x4272, 0xA4 }, + { 0x4273, 0xA5 }, + { 0x4274, 0x99 }, + { 0x4275, 0x96 }, + { 0x4276, 0x97 }, + { 0x4277, 0x98 }, + { 0x4278, 0x8B }, + { 0x4279, 0x8A }, + { 0x427A, 0x8A }, + { 0x427B, 0x8B }, + { 0x427C, 0x81 }, + { 0x427D, 0x81 }, + { 0x427E, 0x81 }, + { 0x427F, 0x82 }, + { 0x4280, 0x84 }, + { 0x4281, 0x84 }, + { 0x4282, 0x84 }, + { 0x4283, 0x84 }, + { 0x4284, 0x8E }, + { 0x4285, 0x8E }, + { 0x4286, 0x8D }, + { 0x4287, 0x8C }, + { 0x4288, 0x9A }, + { 0x4289, 0x97 }, + { 0x428A, 0x97 }, + { 0x428B, 0x95 }, + { 0x428C, 0xAA }, + { 0x428D, 0xA3 }, + { 0x428E, 0xA3 }, + { 0x428F, 0xA2 }, + { 0x4290, 0xC7 }, + { 0x4291, 0xBA }, + { 0x4292, 0xC0 }, + { 0x4293, 0xC3 }, + { 0x4294, 0xB0 }, + { 0x4295, 0xA7 }, + { 0x4296, 0xA7 }, + { 0x4297, 0xA9 }, + { 0x4298, 0x9F }, + { 0x4299, 0x9B }, + { 0x429A, 0x9B }, + { 0x429B, 0x9D }, + { 0x429C, 0x93 }, + { 0x429D, 0x91 }, + { 0x429E, 0x91 }, + { 0x429F, 0x92 }, + { 0x42A0, 0x8C }, + { 0x42A1, 0x8B }, + { 0x42A2, 0x8B }, + { 0x42A3, 0x8C }, + { 0x42A4, 0x8D }, + { 0x42A5, 0x8C }, + { 0x42A6, 0x8C }, + { 0x42A7, 0x8C }, + { 0x42A8, 0x94 }, + { 0x42A9, 0x93 }, + { 0x42AA, 0x92 }, + { 0x42AB, 0x91 }, + { 0x42AC, 0x9E }, + { 0x42AD, 0x9B }, + { 0x42AE, 0x9B }, + { 0x42AF, 0x98 }, + { 0x42B0, 0xAC }, + { 0x42B1, 0xA6 }, + { 0x42B2, 0xA6 }, + { 0x42B3, 0xA2 }, + { 0x42B4, 0xCE }, + { 0x42B5, 0xBA }, + { 0x42B6, 0xBC }, + { 0x42B7, 0xB7 }, + { 0x42B8, 0xC5 }, + { 0x42B9, 0xB5 }, + { 0x42BA, 0xBA }, + { 0x42BB, 0xC0 }, + { 0x42BC, 0xB1 }, + { 0x42BD, 0xA8 }, + { 0x42BE, 0xAE }, + { 0x42BF, 0xAF }, + { 0x42C0, 0xA7 }, + { 0x42C1, 0xA3 }, + { 0x42C2, 0xA3 }, + { 0x42C3, 0xA5 }, + { 0x42C4, 0xA0 }, + { 0x42C5, 0x9D }, + { 0x42C6, 0x9D }, + { 0x42C7, 0x9F }, + { 0x42C8, 0xA0 }, + { 0x42C9, 0x9E }, + { 0x42CA, 0x9E }, + { 0x42CB, 0x9F }, + { 0x42CC, 0xA2 }, + { 0x42CD, 0xA0 }, + { 0x42CE, 0xA0 }, + { 0x42CF, 0xA0 }, + { 0x42D0, 0xA8 }, + { 0x42D1, 0xA5 }, + { 0x42D2, 0xA5 }, + { 0x42D3, 0xA2 }, + { 0x42D4, 0xB3 }, + { 0x42D5, 0xAA }, + { 0x42D6, 0xAB }, + { 0x42D7, 0xA3 }, + { 0x42D8, 0x00 }, + { 0x42D9, 0x00 }, + { 0x4300, 0xA2 }, + { 0x4301, 0xAE }, + { 0x4302, 0xAD }, + { 0x4303, 0xB5 }, + { 0x4304, 0x95 }, + { 0x4305, 0x9A }, + { 0x4306, 0x98 }, + { 0x4307, 0x9B }, + { 0x4308, 0x8D }, + { 0x4309, 0x90 }, + { 0x430A, 0x8F }, + { 0x430B, 0x91 }, + { 0x430C, 0x86 }, + { 0x430D, 0x88 }, + { 0x430E, 0x87 }, + { 0x430F, 0x89 }, + { 0x4310, 0x86 }, + { 0x4311, 0x87 }, + { 0x4312, 0x86 }, + { 0x4313, 0x88 }, + { 0x4314, 0x89 }, + { 0x4315, 0x88 }, + { 0x4316, 0x88 }, + { 0x4317, 0x8E }, + { 0x4318, 0x90 }, + { 0x4319, 0x8F }, + { 0x431A, 0x8C }, + { 0x431B, 0x8C }, + { 0x431C, 0x9C }, + { 0x431D, 0x99 }, + { 0x431E, 0x98 }, + { 0x431F, 0x99 }, + { 0x4320, 0xAB }, + { 0x4321, 0xB0 }, + { 0x4322, 0xAD }, + { 0x4323, 0xAF }, + { 0x4324, 0x9B }, + { 0x4325, 0x9F }, + { 0x4326, 0x9E }, + { 0x4327, 0xA1 }, + { 0x4328, 0x8E }, + { 0x4329, 0x91 }, + { 0x432A, 0x90 }, + { 0x432B, 0x93 }, + { 0x432C, 0x86 }, + { 0x432D, 0x88 }, + { 0x432E, 0x87 }, + { 0x432F, 0x89 }, + { 0x4330, 0x82 }, + { 0x4331, 0x84 }, + { 0x4332, 0x83 }, + { 0x4333, 0x84 }, + { 0x4334, 0x82 }, + { 0x4335, 0x82 }, + { 0x4336, 0x82 }, + { 0x4337, 0x83 }, + { 0x4338, 0x85 }, + { 0x4339, 0x84 }, + { 0x433A, 0x84 }, + { 0x433B, 0x85 }, + { 0x433C, 0x8A }, + { 0x433D, 0x89 }, + { 0x433E, 0x88 }, + { 0x433F, 0x89 }, + { 0x4340, 0x93 }, + { 0x4341, 0x91 }, + { 0x4342, 0x91 }, + { 0x4343, 0x93 }, + { 0x4344, 0xA0 }, + { 0x4345, 0x9E }, + { 0x4346, 0x9D }, + { 0x4347, 0xA1 }, + { 0x4348, 0x95 }, + { 0x4349, 0x9B }, + { 0x434A, 0x9A }, + { 0x434B, 0x9C }, + { 0x434C, 0x8A }, + { 0x434D, 0x8D }, + { 0x434E, 0x8C }, + { 0x434F, 0x8D }, + { 0x4350, 0x83 }, + { 0x4351, 0x85 }, + { 0x4352, 0x84 }, + { 0x4353, 0x85 }, + { 0x4354, 0x80 }, + { 0x4355, 0x81 }, + { 0x4356, 0x81 }, + { 0x4357, 0x81 }, + { 0x4358, 0x80 }, + { 0x4359, 0x80 }, + { 0x435A, 0x80 }, + { 0x435B, 0x80 }, + { 0x435C, 0x82 }, + { 0x435D, 0x81 }, + { 0x435E, 0x81 }, + { 0x435F, 0x81 }, + { 0x4360, 0x85 }, + { 0x4361, 0x84 }, + { 0x4362, 0x84 }, + { 0x4363, 0x85 }, + { 0x4364, 0x8D }, + { 0x4365, 0x8B }, + { 0x4366, 0x8B }, + { 0x4367, 0x8D }, + { 0x4368, 0x98 }, + { 0x4369, 0x98 }, + { 0x436A, 0x95 }, + { 0x436B, 0x98 }, + { 0x436C, 0x95 }, + { 0x436D, 0x9A }, + { 0x436E, 0x99 }, + { 0x436F, 0x9A }, + { 0x4370, 0x8A }, + { 0x4371, 0x8D }, + { 0x4372, 0x8C }, + { 0x4373, 0x8C }, + { 0x4374, 0x83 }, + { 0x4375, 0x85 }, + { 0x4376, 0x84 }, + { 0x4377, 0x84 }, + { 0x4378, 0x80 }, + { 0x4379, 0x80 }, + { 0x437A, 0x80 }, + { 0x437B, 0x80 }, + { 0x437C, 0x7F }, + { 0x437D, 0x7F }, + { 0x437E, 0x7F }, + { 0x437F, 0x7F }, + { 0x4380, 0x81 }, + { 0x4381, 0x80 }, + { 0x4382, 0x80 }, + { 0x4383, 0x81 }, + { 0x4384, 0x84 }, + { 0x4385, 0x83 }, + { 0x4386, 0x83 }, + { 0x4387, 0x84 }, + { 0x4388, 0x8B }, + { 0x4389, 0x8A }, + { 0x438A, 0x8A }, + { 0x438B, 0x8C }, + { 0x438C, 0x97 }, + { 0x438D, 0x96 }, + { 0x438E, 0x96 }, + { 0x438F, 0x99 }, + { 0x4390, 0x99 }, + { 0x4391, 0x9F }, + { 0x4392, 0x9E }, + { 0x4393, 0x9D }, + { 0x4394, 0x8D }, + { 0x4395, 0x90 }, + { 0x4396, 0x90 }, + { 0x4397, 0x8F }, + { 0x4398, 0x85 }, + { 0x4399, 0x87 }, + { 0x439A, 0x87 }, + { 0x439B, 0x86 }, + { 0x439C, 0x81 }, + { 0x439D, 0x83 }, + { 0x439E, 0x82 }, + { 0x439F, 0x82 }, + { 0x43A0, 0x80 }, + { 0x43A1, 0x81 }, + { 0x43A2, 0x81 }, + { 0x43A3, 0x81 }, + { 0x43A4, 0x82 }, + { 0x43A5, 0x82 }, + { 0x43A6, 0x82 }, + { 0x43A7, 0x82 }, + { 0x43A8, 0x86 }, + { 0x43A9, 0x85 }, + { 0x43AA, 0x85 }, + { 0x43AB, 0x87 }, + { 0x43AC, 0x8D }, + { 0x43AD, 0x8D }, + { 0x43AE, 0x8D }, + { 0x43AF, 0x90 }, + { 0x43B0, 0x9A }, + { 0x43B1, 0x9A }, + { 0x43B2, 0x9B }, + { 0x43B3, 0x9D }, + { 0x43B4, 0xA0 }, + { 0x43B5, 0xAD }, + { 0x43B6, 0xAC }, + { 0x43B7, 0xAA }, + { 0x43B8, 0x93 }, + { 0x43B9, 0x97 }, + { 0x43BA, 0x97 }, + { 0x43BB, 0x96 }, + { 0x43BC, 0x8B }, + { 0x43BD, 0x8E }, + { 0x43BE, 0x8E }, + { 0x43BF, 0x8C }, + { 0x43C0, 0x83 }, + { 0x43C1, 0x85 }, + { 0x43C2, 0x85 }, + { 0x43C3, 0x84 }, + { 0x43C4, 0x82 }, + { 0x43C5, 0x84 }, + { 0x43C6, 0x83 }, + { 0x43C7, 0x83 }, + { 0x43C8, 0x83 }, + { 0x43C9, 0x84 }, + { 0x43CA, 0x84 }, + { 0x43CB, 0x85 }, + { 0x43CC, 0x8A }, + { 0x43CD, 0x8A }, + { 0x43CE, 0x8A }, + { 0x43CF, 0x8C }, + { 0x43D0, 0x92 }, + { 0x43D1, 0x93 }, + { 0x43D2, 0x93 }, + { 0x43D3, 0x96 }, + { 0x43D4, 0x9F }, + { 0x43D5, 0xA6 }, + { 0x43D6, 0xA5 }, + { 0x43D7, 0xAA }, + { 0x4400, 0xA1 }, + { 0x4401, 0xAB }, + { 0x4402, 0xA7 }, + { 0x4403, 0xB0 }, + { 0x4404, 0x91 }, + { 0x4405, 0x96 }, + { 0x4406, 0x94 }, + { 0x4407, 0x99 }, + { 0x4408, 0x8A }, + { 0x4409, 0x8E }, + { 0x440A, 0x8C }, + { 0x440B, 0x8F }, + { 0x440C, 0x85 }, + { 0x440D, 0x86 }, + { 0x440E, 0x86 }, + { 0x440F, 0x88 }, + { 0x4410, 0x85 }, + { 0x4411, 0x86 }, + { 0x4412, 0x85 }, + { 0x4413, 0x87 }, + { 0x4414, 0x88 }, + { 0x4415, 0x87 }, + { 0x4416, 0x87 }, + { 0x4417, 0x89 }, + { 0x4418, 0x91 }, + { 0x4419, 0x8F }, + { 0x441A, 0x8F }, + { 0x441B, 0x90 }, + { 0x441C, 0x9C }, + { 0x441D, 0x9B }, + { 0x441E, 0x9A }, + { 0x441F, 0x9A }, + { 0x4420, 0xB3 }, + { 0x4421, 0xB1 }, + { 0x4422, 0xB0 }, + { 0x4423, 0xB2 }, + { 0x4424, 0x96 }, + { 0x4425, 0x9C }, + { 0x4426, 0x9A }, + { 0x4427, 0x9E }, + { 0x4428, 0x8B }, + { 0x4429, 0x8F }, + { 0x442A, 0x8E }, + { 0x442B, 0x91 }, + { 0x442C, 0x84 }, + { 0x442D, 0x87 }, + { 0x442E, 0x86 }, + { 0x442F, 0x88 }, + { 0x4430, 0x82 }, + { 0x4431, 0x83 }, + { 0x4432, 0x82 }, + { 0x4433, 0x84 }, + { 0x4434, 0x82 }, + { 0x4435, 0x82 }, + { 0x4436, 0x82 }, + { 0x4437, 0x83 }, + { 0x4438, 0x84 }, + { 0x4439, 0x84 }, + { 0x443A, 0x84 }, + { 0x443B, 0x84 }, + { 0x443C, 0x8B }, + { 0x443D, 0x89 }, + { 0x443E, 0x89 }, + { 0x443F, 0x89 }, + { 0x4440, 0x95 }, + { 0x4441, 0x93 }, + { 0x4442, 0x93 }, + { 0x4443, 0x93 }, + { 0x4444, 0xA2 }, + { 0x4445, 0xA2 }, + { 0x4446, 0xA1 }, + { 0x4447, 0xA0 }, + { 0x4448, 0x8F }, + { 0x4449, 0x97 }, + { 0x444A, 0x97 }, + { 0x444B, 0x98 }, + { 0x444C, 0x87 }, + { 0x444D, 0x8B }, + { 0x444E, 0x8A }, + { 0x444F, 0x8B }, + { 0x4450, 0x81 }, + { 0x4451, 0x83 }, + { 0x4452, 0x83 }, + { 0x4453, 0x84 }, + { 0x4454, 0x7F }, + { 0x4455, 0x80 }, + { 0x4456, 0x80 }, + { 0x4457, 0x81 }, + { 0x4458, 0x80 }, + { 0x4459, 0x80 }, + { 0x445A, 0x80 }, + { 0x445B, 0x80 }, + { 0x445C, 0x82 }, + { 0x445D, 0x81 }, + { 0x445E, 0x81 }, + { 0x445F, 0x81 }, + { 0x4460, 0x87 }, + { 0x4461, 0x85 }, + { 0x4462, 0x85 }, + { 0x4463, 0x86 }, + { 0x4464, 0x90 }, + { 0x4465, 0x8E }, + { 0x4466, 0x8E }, + { 0x4467, 0x8E }, + { 0x4468, 0x9B }, + { 0x4469, 0x9C }, + { 0x446A, 0x9A }, + { 0x446B, 0x9A }, + { 0x446C, 0x91 }, + { 0x446D, 0x97 }, + { 0x446E, 0x95 }, + { 0x446F, 0x95 }, + { 0x4470, 0x87 }, + { 0x4471, 0x8A }, + { 0x4472, 0x8A }, + { 0x4473, 0x89 }, + { 0x4474, 0x81 }, + { 0x4475, 0x83 }, + { 0x4476, 0x83 }, + { 0x4477, 0x83 }, + { 0x4478, 0x7F }, + { 0x4479, 0x80 }, + { 0x447A, 0x80 }, + { 0x447B, 0x80 }, + { 0x447C, 0x80 }, + { 0x447D, 0x80 }, + { 0x447E, 0x80 }, + { 0x447F, 0x7F }, + { 0x4480, 0x81 }, + { 0x4481, 0x81 }, + { 0x4482, 0x81 }, + { 0x4483, 0x81 }, + { 0x4484, 0x85 }, + { 0x4485, 0x85 }, + { 0x4486, 0x85 }, + { 0x4487, 0x85 }, + { 0x4488, 0x8E }, + { 0x4489, 0x8D }, + { 0x448A, 0x8D }, + { 0x448B, 0x8E }, + { 0x448C, 0x9D }, + { 0x448D, 0x9C }, + { 0x448E, 0x9C }, + { 0x448F, 0x9C }, + { 0x4490, 0x94 }, + { 0x4491, 0x9B }, + { 0x4492, 0x9A }, + { 0x4493, 0x97 }, + { 0x4494, 0x8A }, + { 0x4495, 0x8E }, + { 0x4496, 0x8E }, + { 0x4497, 0x8C }, + { 0x4498, 0x84 }, + { 0x4499, 0x86 }, + { 0x449A, 0x86 }, + { 0x449B, 0x84 }, + { 0x449C, 0x81 }, + { 0x449D, 0x83 }, + { 0x449E, 0x83 }, + { 0x449F, 0x81 }, + { 0x44A0, 0x81 }, + { 0x44A1, 0x82 }, + { 0x44A2, 0x82 }, + { 0x44A3, 0x81 }, + { 0x44A4, 0x83 }, + { 0x44A5, 0x83 }, + { 0x44A6, 0x83 }, + { 0x44A7, 0x83 }, + { 0x44A8, 0x88 }, + { 0x44A9, 0x88 }, + { 0x44AA, 0x88 }, + { 0x44AB, 0x88 }, + { 0x44AC, 0x91 }, + { 0x44AD, 0x91 }, + { 0x44AE, 0x91 }, + { 0x44AF, 0x92 }, + { 0x44B0, 0xA0 }, + { 0x44B1, 0xA0 }, + { 0x44B2, 0xA0 }, + { 0x44B3, 0xA0 }, + { 0x44B4, 0x9E }, + { 0x44B5, 0xA9 }, + { 0x44B6, 0xA8 }, + { 0x44B7, 0xA3 }, + { 0x44B8, 0x90 }, + { 0x44B9, 0x95 }, + { 0x44BA, 0x95 }, + { 0x44BB, 0x92 }, + { 0x44BC, 0x8A }, + { 0x44BD, 0x8E }, + { 0x44BE, 0x8E }, + { 0x44BF, 0x8B }, + { 0x44C0, 0x84 }, + { 0x44C1, 0x86 }, + { 0x44C2, 0x86 }, + { 0x44C3, 0x84 }, + { 0x44C4, 0x84 }, + { 0x44C5, 0x85 }, + { 0x44C6, 0x85 }, + { 0x44C7, 0x84 }, + { 0x44C8, 0x86 }, + { 0x44C9, 0x87 }, + { 0x44CA, 0x87 }, + { 0x44CB, 0x86 }, + { 0x44CC, 0x8D }, + { 0x44CD, 0x8E }, + { 0x44CE, 0x8E }, + { 0x44CF, 0x8D }, + { 0x44D0, 0x98 }, + { 0x44D1, 0x98 }, + { 0x44D2, 0x99 }, + { 0x44D3, 0x9A }, + { 0x44D4, 0xA9 }, + { 0x44D5, 0xAA }, + { 0x44D6, 0xAA }, + { 0x44D7, 0xAD }, + { 0x4500, 0x9F }, + { 0x4501, 0xA8 }, + { 0x4502, 0xA5 }, + { 0x4503, 0xAF }, + { 0x4504, 0x8F }, + { 0x4505, 0x96 }, + { 0x4506, 0x92 }, + { 0x4507, 0x94 }, + { 0x4508, 0x89 }, + { 0x4509, 0x8D }, + { 0x450A, 0x8A }, + { 0x450B, 0x8E }, + { 0x450C, 0x84 }, + { 0x450D, 0x85 }, + { 0x450E, 0x84 }, + { 0x450F, 0x87 }, + { 0x4510, 0x84 }, + { 0x4511, 0x85 }, + { 0x4512, 0x84 }, + { 0x4513, 0x86 }, + { 0x4514, 0x87 }, + { 0x4515, 0x86 }, + { 0x4516, 0x86 }, + { 0x4517, 0x88 }, + { 0x4518, 0x8F }, + { 0x4519, 0x8D }, + { 0x451A, 0x8D }, + { 0x451B, 0x8F }, + { 0x451C, 0x9A }, + { 0x451D, 0x9A }, + { 0x451E, 0x98 }, + { 0x451F, 0x9A }, + { 0x4520, 0xAF }, + { 0x4521, 0xAF }, + { 0x4522, 0xB2 }, + { 0x4523, 0xB1 }, + { 0x4524, 0x95 }, + { 0x4525, 0x9B }, + { 0x4526, 0x97 }, + { 0x4527, 0x9C }, + { 0x4528, 0x8A }, + { 0x4529, 0x8E }, + { 0x452A, 0x8D }, + { 0x452B, 0x90 }, + { 0x452C, 0x84 }, + { 0x452D, 0x86 }, + { 0x452E, 0x85 }, + { 0x452F, 0x87 }, + { 0x4530, 0x81 }, + { 0x4531, 0x82 }, + { 0x4532, 0x82 }, + { 0x4533, 0x83 }, + { 0x4534, 0x81 }, + { 0x4535, 0x81 }, + { 0x4536, 0x81 }, + { 0x4537, 0x82 }, + { 0x4538, 0x84 }, + { 0x4539, 0x83 }, + { 0x453A, 0x83 }, + { 0x453B, 0x84 }, + { 0x453C, 0x8A }, + { 0x453D, 0x88 }, + { 0x453E, 0x88 }, + { 0x453F, 0x89 }, + { 0x4540, 0x94 }, + { 0x4541, 0x92 }, + { 0x4542, 0x91 }, + { 0x4543, 0x92 }, + { 0x4544, 0xA1 }, + { 0x4545, 0xA0 }, + { 0x4546, 0x9C }, + { 0x4547, 0x9D }, + { 0x4548, 0x8F }, + { 0x4549, 0x96 }, + { 0x454A, 0x95 }, + { 0x454B, 0x92 }, + { 0x454C, 0x87 }, + { 0x454D, 0x8A }, + { 0x454E, 0x89 }, + { 0x454F, 0x8A }, + { 0x4550, 0x81 }, + { 0x4551, 0x83 }, + { 0x4552, 0x82 }, + { 0x4553, 0x83 }, + { 0x4554, 0x7F }, + { 0x4555, 0x80 }, + { 0x4556, 0x80 }, + { 0x4557, 0x81 }, + { 0x4558, 0x7F }, + { 0x4559, 0x80 }, + { 0x455A, 0x7F }, + { 0x455B, 0x80 }, + { 0x455C, 0x81 }, + { 0x455D, 0x81 }, + { 0x455E, 0x81 }, + { 0x455F, 0x81 }, + { 0x4560, 0x86 }, + { 0x4561, 0x85 }, + { 0x4562, 0x85 }, + { 0x4563, 0x85 }, + { 0x4564, 0x8F }, + { 0x4565, 0x8D }, + { 0x4566, 0x8D }, + { 0x4567, 0x8D }, + { 0x4568, 0x99 }, + { 0x4569, 0x9A }, + { 0x456A, 0x97 }, + { 0x456B, 0x99 }, + { 0x456C, 0x90 }, + { 0x456D, 0x95 }, + { 0x456E, 0x93 }, + { 0x456F, 0x92 }, + { 0x4570, 0x87 }, + { 0x4571, 0x8A }, + { 0x4572, 0x88 }, + { 0x4573, 0x87 }, + { 0x4574, 0x81 }, + { 0x4575, 0x83 }, + { 0x4576, 0x82 }, + { 0x4577, 0x82 }, + { 0x4578, 0x7F }, + { 0x4579, 0x80 }, + { 0x457A, 0x80 }, + { 0x457B, 0x80 }, + { 0x457C, 0x80 }, + { 0x457D, 0x80 }, + { 0x457E, 0x80 }, + { 0x457F, 0x80 }, + { 0x4580, 0x81 }, + { 0x4581, 0x81 }, + { 0x4582, 0x81 }, + { 0x4583, 0x81 }, + { 0x4584, 0x85 }, + { 0x4585, 0x85 }, + { 0x4586, 0x84 }, + { 0x4587, 0x85 }, + { 0x4588, 0x8E }, + { 0x4589, 0x8D }, + { 0x458A, 0x8C }, + { 0x458B, 0x8D }, + { 0x458C, 0x9B }, + { 0x458D, 0x9B }, + { 0x458E, 0x9A }, + { 0x458F, 0x98 }, + { 0x4590, 0x94 }, + { 0x4591, 0x9A }, + { 0x4592, 0x94 }, + { 0x4593, 0x90 }, + { 0x4594, 0x8A }, + { 0x4595, 0x8D }, + { 0x4596, 0x8C }, + { 0x4597, 0x89 }, + { 0x4598, 0x84 }, + { 0x4599, 0x86 }, + { 0x459A, 0x85 }, + { 0x459B, 0x83 }, + { 0x459C, 0x82 }, + { 0x459D, 0x83 }, + { 0x459E, 0x82 }, + { 0x459F, 0x80 }, + { 0x45A0, 0x81 }, + { 0x45A1, 0x82 }, + { 0x45A2, 0x81 }, + { 0x45A3, 0x80 }, + { 0x45A4, 0x83 }, + { 0x45A5, 0x83 }, + { 0x45A6, 0x83 }, + { 0x45A7, 0x83 }, + { 0x45A8, 0x88 }, + { 0x45A9, 0x87 }, + { 0x45AA, 0x87 }, + { 0x45AB, 0x88 }, + { 0x45AC, 0x91 }, + { 0x45AD, 0x90 }, + { 0x45AE, 0x90 }, + { 0x45AF, 0x91 }, + { 0x45B0, 0x9F }, + { 0x45B1, 0x9F }, + { 0x45B2, 0x9E }, + { 0x45B3, 0x9F }, + { 0x45B4, 0x9F }, + { 0x45B5, 0xA8 }, + { 0x45B6, 0xA6 }, + { 0x45B7, 0xA7 }, + { 0x45B8, 0x8D }, + { 0x45B9, 0x95 }, + { 0x45BA, 0x90 }, + { 0x45BB, 0x8A }, + { 0x45BC, 0x89 }, + { 0x45BD, 0x8D }, + { 0x45BE, 0x88 }, + { 0x45BF, 0x86 }, + { 0x45C0, 0x84 }, + { 0x45C1, 0x86 }, + { 0x45C2, 0x85 }, + { 0x45C3, 0x82 }, + { 0x45C4, 0x84 }, + { 0x45C5, 0x85 }, + { 0x45C6, 0x85 }, + { 0x45C7, 0x83 }, + { 0x45C8, 0x86 }, + { 0x45C9, 0x86 }, + { 0x45CA, 0x86 }, + { 0x45CB, 0x85 }, + { 0x45CC, 0x8E }, + { 0x45CD, 0x8D }, + { 0x45CE, 0x8D }, + { 0x45CF, 0x8C }, + { 0x45D0, 0x99 }, + { 0x45D1, 0x98 }, + { 0x45D2, 0x98 }, + { 0x45D3, 0x98 }, + { 0x45D4, 0xA6 }, + { 0x45D5, 0xA9 }, + { 0x45D6, 0xA7 }, + { 0x45D7, 0xAC }, +}; diff -Naur --no-dereference a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig --- a/drivers/media/i2c/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/i2c/Kconfig 2024-07-07 20:37:34.644306549 -0400 @@ -181,6 +181,18 @@ To compile this driver as a module, choose M here: the module will be called imx355. +config VIDEO_IMX390 + tristate "Sony IMX390 sensor support" + depends on I2C && VIDEO_DEV + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + help + This is a Video4Linux2 sensor driver for the Sony + IMX390 camera. + + To compile this driver as a module, choose M here: the + module will be called imx390. + config VIDEO_IMX412 tristate "Sony IMX412 sensor support" depends on OF_GPIO @@ -312,6 +324,18 @@ This is a Video4Linux2 sensor driver for the OmniVision OV13B10 camera. +config VIDEO_OV2312 + tristate "OmniVision OV2312 sensor support" + depends on I2C && VIDEO_DEV + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + help + This is a Video4Linux2 sensor driver for the OmniVision + OV2312 camera. + + To compile this driver as a module, choose M here: the + module will be called ov2312. + config VIDEO_OV2640 tristate "OmniVision OV2640 sensor support" help @@ -558,6 +582,19 @@ To compile this driver as a module, choose M here: the module's name is ov9734. +config VIDEO_OX05B1S + tristate "OmniVision OX05B1S sensor support" + depends on OF_GPIO + depends on I2C && VIDEO_DEV + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + help + This is a Video4Linux2 sensor driver for the OmniVision + OX05B1S camera. + + To compile this driver as a module, choose M here: the + module will be called OX05B1S. + config VIDEO_RDACM20 tristate "IMI RDACM20 camera support" select VIDEO_MAX9271_LIB diff -Naur --no-dereference a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile --- a/drivers/media/i2c/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/i2c/Makefile 2024-07-07 20:37:34.648306569 -0400 @@ -51,6 +51,7 @@ obj-$(CONFIG_VIDEO_IMX334) += imx334.o obj-$(CONFIG_VIDEO_IMX335) += imx335.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o +obj-$(CONFIG_VIDEO_IMX390) += imx390.o obj-$(CONFIG_VIDEO_IMX412) += imx412.o obj-$(CONFIG_VIDEO_IMX415) += imx415.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o @@ -77,6 +78,7 @@ obj-$(CONFIG_VIDEO_OV08X40) += ov08x40.o obj-$(CONFIG_VIDEO_OV13858) += ov13858.o obj-$(CONFIG_VIDEO_OV13B10) += ov13b10.o +obj-$(CONFIG_VIDEO_OV2312) += ov2312.o obj-$(CONFIG_VIDEO_OV2640) += ov2640.o obj-$(CONFIG_VIDEO_OV2659) += ov2659.o obj-$(CONFIG_VIDEO_OV2680) += ov2680.o @@ -104,6 +106,7 @@ obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o obj-$(CONFIG_VIDEO_OV9734) += ov9734.o +obj-$(CONFIG_VIDEO_OX05B1S) += ox05b1s.o obj-$(CONFIG_VIDEO_RDACM20) += rdacm20.o obj-$(CONFIG_VIDEO_RDACM21) += rdacm21.o obj-$(CONFIG_VIDEO_RJ54N1) += rj54n1cb0c.o diff -Naur --no-dereference a/drivers/media/i2c/ov2312.c b/drivers/media/i2c/ov2312.c --- a/drivers/media/i2c/ov2312.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/i2c/ov2312.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,781 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Omnivision OV2312 RGB-IR Image Sensor driver + * + * Copyright (c) 2022 Jai Luthra + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ov2312.h" + +struct ov2312 { + struct device *dev; + + struct clk *clk; + unsigned long clk_rate; + + struct i2c_client *client; + struct regmap *regmap; + struct gpio_desc *reset_gpio; + + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_mbus_framefmt format; + + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *again; + struct v4l2_ctrl *dgain; + struct v4l2_ctrl *h_flip; + struct v4l2_ctrl *v_flip; + + u32 fps; + + struct mutex lock; /* For streaming status */ + bool streaming; +}; + +static inline struct ov2312 *to_ov2312(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ov2312, sd); +} + +static int ov2312_read(struct ov2312 *ov2312, u16 addr, u32 *val, size_t nbytes) +{ + int ret; + __le32 val_le = 0; + + ret = regmap_bulk_read(ov2312->regmap, addr, &val_le, nbytes); + if (ret < 0) { + dev_err(ov2312->dev, "%s: failed to read reg 0x%04x: %d\n", + __func__, addr, ret); + return ret; + } + + *val = le32_to_cpu(val_le); + return 0; +} + +static int ov2312_write(struct ov2312 *ov2312, u16 addr, u32 val, size_t nbytes) +{ + int ret; + __le32 val_le = cpu_to_le32(val); + + ret = regmap_bulk_write(ov2312->regmap, addr, &val_le, nbytes); + if (ret < 0) + dev_err(ov2312->dev, "%s: failed to write reg 0x%04x: %d\n", + __func__, addr, ret); + return ret; +} + +static int ov2312_write_table(struct ov2312 *ov2312, + const struct reg_sequence *regs, + unsigned int nr_regs) +{ + int ret, i; + + for (i = 0; i < nr_regs; i++) { + ret = regmap_write(ov2312->regmap, regs[i].reg, regs[i].def); + if (ret < 0) { + dev_err(ov2312->dev, + "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n", + __func__, i, regs[i].reg, regs[i].def, ret); + return ret; + } + } + return 0; +} + +static void ov2312_init_formats(struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *format; + int i; + + for (i = 0; i < 2; ++i) { + format = v4l2_subdev_state_get_stream_format(state, 0, i); + format->code = ov2312_mbus_formats[0]; + format->width = ov2312_framesizes[0].width; + format->height = ov2312_framesizes[0].height; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_DEFAULT; + } +} + +static int ov2312_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct ov2312 *ov2312 = to_ov2312(sd); + struct v4l2_mbus_framefmt *format; + const struct v4l2_area *fsize; + u32 code; + int ret = 0; + + if (fmt->pad != 0) + return -EINVAL; + + if (fmt->stream != 0) + return -EINVAL; + + /* Sensor only supports a single format. */ + code = ov2312_mbus_formats[0]; + + /* Find the nearest supported frame size. */ + fsize = v4l2_find_nearest_size(ov2312_framesizes, + ARRAY_SIZE(ov2312_framesizes), width, + height, fmt->format.width, + fmt->format.height); + + v4l2_subdev_lock_state(state); + + /* Update the stored format and return it. */ + format = v4l2_subdev_state_get_stream_format(state, fmt->pad, fmt->stream); + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && ov2312->streaming) { + ret = -EBUSY; + goto done; + } + + format->code = code; + format->width = fsize->width; + format->height = fsize->height; + + fmt->format = *format; + +done: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int _ov2312_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route routes[] = { + { + .source_pad = 0, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + { + .source_pad = 0, + .source_stream = 1, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + }; + + struct v4l2_subdev_krouting routing = { + .num_routes = ARRAY_SIZE(routes), + .routes = routes, + }; + + int ret; + + ret = v4l2_subdev_set_routing(sd, state, &routing); + if (ret < 0) + return ret; + + ov2312_init_formats(state); + + return 0; +} + +static int ov2312_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *fmt; + u32 bpp; + int ret = 0; + unsigned int i; + + if (pad != 0) + return -EINVAL; + + state = v4l2_subdev_lock_and_get_active_state(sd); + + fmt = v4l2_subdev_state_get_stream_format(state, 0, 0); + if (!fmt) { + ret = -EPIPE; + goto out; + } + + memset(fd, 0, sizeof(*fd)); + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; + + /* pixel stream - 2 virtual channels */ + + bpp = 10; + + for (i = 0; i < 2; ++i) { + fd->entry[fd->num_entries].stream = i; + + fd->entry[fd->num_entries].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->entry[fd->num_entries].length = fmt->width * fmt->height * bpp / 8; + fd->entry[fd->num_entries].pixelcode = fmt->code; + fd->entry[fd->num_entries].bus.csi2.vc = i; + fd->entry[fd->num_entries].bus.csi2.dt = 0x2b; /* RAW10 */ + + fd->num_entries++; + } + +out: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int ov2312_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + int ret; + + if (routing->num_routes == 0 || routing->num_routes > 2) + return -EINVAL; + + v4l2_subdev_lock_state(state); + + ret = _ov2312_set_routing(sd, state); + + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int ov2312_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + int ret; + + ret = _ov2312_set_routing(sd, state); + + return ret; +} + +static int ov2312_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(ov2312_mbus_formats)) + return -EINVAL; + + code->code = ov2312_mbus_formats[code->index]; + + return 0; +} + +static int ov2312_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ov2312_mbus_formats); ++i) { + if (ov2312_mbus_formats[i] == fse->code) + break; + } + + if (i == ARRAY_SIZE(ov2312_mbus_formats)) + return -EINVAL; + + if (fse->index >= ARRAY_SIZE(ov2312_framesizes)) + return -EINVAL; + + fse->min_width = ov2312_framesizes[fse->index].width; + fse->max_width = fse->min_width; + fse->max_height = ov2312_framesizes[fse->index].height; + fse->min_height = fse->max_height; + + return 0; +} + +static int ov2312_get_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct ov2312 *ov2312 = to_ov2312(sd); + + fi->interval.numerator = 1; + fi->interval.denominator = ov2312->fps / 2; + + return 0; +} + +static int ov2312_set_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct ov2312 *ov2312 = to_ov2312(sd); + + dev_dbg(ov2312->dev, "%s: Set framerate %dfps\n", __func__, + fi->interval.denominator / fi->interval.numerator); + if ((fi->interval.denominator / fi->interval.numerator) != ov2312->fps) { + dev_err(ov2312->dev, "%s: Framerate can only be %dfps\n", + __func__, ov2312->fps); + return -EINVAL; + } + return 0; +} + +static int ov2312_detect(struct ov2312 *ov2312) +{ + int ret; + u32 id; + + ret = ov2312_read(ov2312, OV2312_SC_CHIP_ID_HI, &id, 2); + if (ret < 0) + return ret; + + id = cpu_to_be16(id); + + if (id != OV2312_CHIP_ID) { + dev_err(ov2312->dev, + "%s: unknown chip ID 0x%04x\n", __func__, id); + return -ENODEV; + } + + dev_dbg(ov2312->dev, "%s: detected chip ID 0x%04x\n", __func__, id); + return 0; +} + +static int ov2312_set_AB_mode(struct ov2312 *ov2312) +{ + int i, ret; + u32 exposure = ov2312->exposure->val; + u32 again = ov2312->again->val; + u32 dgain = ov2312->dgain->val; + struct reg_sequence ov2312_groupB[] = { + {0x3208, 0x00},/* Group B (RGB Dominant VC1) */ + {OV2312_AEC_PK_EXPO_HI, (exposure >> 8) & 0xff}, + {OV2312_AEC_PK_EXPO_LO, exposure & 0xff}, + {OV2312_AEC_PK_AGAIN_HI, (again >> 4) & 0xff}, + {OV2312_AEC_PK_AGAIN_LO, (again & 0x0f) << 4}, + {OV2312_AEC_PK_DGAIN_HI, (dgain >> 8) & 0xff}, + {OV2312_AEC_PK_DGAIN_LO, dgain & 0xff}, + {0x3920, 0x00}, + {0x4813, 0x00},/* VC=0. This register takes effect from next frame */ + {0x3208, 0x10}, + {0x320D, 0x00},/* Auto mode switch between group0 and group1 ;setting to switch */ + {0x320D, 0x31}, + {0x3208, 0xA0}, + }; + + for (i = 0; i < ARRAY_SIZE(ov2312_groupB); i++) { + ret = regmap_write(ov2312->regmap, ov2312_groupB[i].reg, ov2312_groupB[i].def); + if (ret < 0) { + dev_err(ov2312->dev, + "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n", + __func__, i, ov2312_groupB[i].reg, ov2312_groupB[i].def, ret); + return ret; + } + } + + msleep(33); + return 0; +} + +static int ov2312_set_orientation(struct ov2312 *ov2312) +{ + bool v_flip = ov2312->v_flip->val; + bool h_flip = ov2312->h_flip->val; + u32 reg = (v_flip ? 0x4400 : 0) | (h_flip ? 0x0004 : 0); + + return ov2312_write(ov2312, OV2312_TIMING_VFLIP, be16_to_cpu(reg), 2); +} + +static int ov2312_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2312 *ov2312 = container_of(ctrl->handler, + struct ov2312, ctrls); + int ret; + + dev_dbg(ov2312->dev, "%s: %s, value: %d\n", __func__, + ctrl->name, ctrl->val); + + /* + * If the device is not powered up by the host driver do + * not apply any controls to H/W at this time. Instead + * the controls will be restored right after power-up. + */ + if (pm_runtime_suspended(ov2312->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + case V4L2_CID_ANALOGUE_GAIN: + case V4L2_CID_DIGITAL_GAIN: + ret = ov2312_set_AB_mode(ov2312); + break; + + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + ret = ov2312_set_orientation(ov2312); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static int ov2312_power_on(struct ov2312 *ov2312) +{ + int ret; + + ret = clk_prepare_enable(ov2312->clk); + if (ret < 0) + return ret; + + if (ov2312->reset_gpio) { + gpiod_set_value_cansleep(ov2312->reset_gpio, 0); + usleep_range(100, 1000); + gpiod_set_value_cansleep(ov2312->reset_gpio, 1); + msleep(30); + } + return 0; +} + +static int ov2312_power_off(struct ov2312 *ov2312) +{ + if (ov2312->reset_gpio) { + gpiod_set_value_cansleep(ov2312->reset_gpio, 0); + usleep_range(1, 10); + } + + clk_disable_unprepare(ov2312->clk); + + return 0; +} + +static int ov2312_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2312 *ov2312 = to_ov2312(sd); + + return ov2312_power_on(ov2312); +} + +static int ov2312_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2312 *ov2312 = to_ov2312(sd); + + return ov2312_power_off(ov2312); +} + +static int ov2312_start_stream(struct ov2312 *ov2312) +{ + int ret; + + ret = ov2312_write_table(ov2312, ov2312_1600x1300_60fps_AB, + ARRAY_SIZE(ov2312_1600x1300_60fps_AB)); + if (ret < 0) + return ret; + + /* Update controls on wake up */ + ret = ov2312_set_orientation(ov2312); + if (ret < 0) + return ret; + + ret = ov2312_set_AB_mode(ov2312); + if (ret < 0) + return ret; + + msleep(100); + + /* Set active */ + ret = ov2312_write(ov2312, OV2312_SYS_MODE_SEL, 1, 1); + if (ret < 0) + return ret; + + /* No communication is possible for a while after exiting standby */ + msleep(20); + return 0; +} + +static int ov2312_stop_stream(struct ov2312 *ov2312) +{ + int ret; + + /* Set standby */ + ret = ov2312_write(ov2312, OV2312_SYS_MODE_SEL, 0, 1); + if (ret < 0) + return ret; + + /* No communication is possible for a while after entering standby */ + usleep_range(10000, 20000); + return 0; +} + +static int ov2312_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov2312 *ov2312 = to_ov2312(sd); + int ret; + + mutex_lock(&ov2312->lock); + if (ov2312->streaming == enable) { + mutex_unlock(&ov2312->lock); + return 0; + } + + if (enable) { + ret = pm_runtime_resume_and_get(ov2312->dev); + if (ret < 0) + goto err_unlock; + + ret = ov2312_start_stream(ov2312); + if (ret < 0) + goto err_runtime_put; + } else { + ret = ov2312_stop_stream(ov2312); + if (ret < 0) + goto err_runtime_put; + pm_runtime_put(ov2312->dev); + } + + ov2312->streaming = enable; + mutex_unlock(&ov2312->lock); + return 0; + +err_runtime_put: + pm_runtime_put(ov2312->dev); + +err_unlock: + mutex_unlock(&ov2312->lock); + dev_err(ov2312->dev, + "%s: failed to setup streaming %d\n", __func__, ret); + return ret; +} + +static const struct v4l2_subdev_video_ops ov2312_subdev_video_ops = { + .s_stream = ov2312_set_stream, + .g_frame_interval = ov2312_get_frame_interval, + .s_frame_interval = ov2312_set_frame_interval, +}; + +static const struct v4l2_subdev_pad_ops ov2312_subdev_pad_ops = { + .init_cfg = ov2312_init_cfg, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ov2312_set_fmt, + .enum_mbus_code = ov2312_enum_mbus_code, + .enum_frame_size = ov2312_enum_frame_sizes, + .set_routing = ov2312_set_routing, + .get_frame_desc = ov2312_get_frame_desc, +}; + +static const struct v4l2_subdev_ops ov2312_subdev_ops = { + .video = &ov2312_subdev_video_ops, + .pad = &ov2312_subdev_pad_ops, +}; + +static const struct v4l2_ctrl_ops ov2312_ctrl_ops = { + .s_ctrl = ov2312_set_ctrl, +}; + +static const struct dev_pm_ops ov2312_pm_ops = { + SET_RUNTIME_PM_OPS(ov2312_suspend, ov2312_resume, NULL) +}; + +static int ov2312_probe(struct i2c_client *client) +{ + struct ov2312 *ov2312; + struct v4l2_subdev *sd; + struct v4l2_ctrl_handler *ctrl_hdr; + int ret; + + /* Allocate internal struct */ + ov2312 = devm_kzalloc(&client->dev, sizeof(*ov2312), GFP_KERNEL); + if (!ov2312) + return -ENOMEM; + + ov2312->dev = &client->dev; + ov2312->client = client; + + /* Initialize I2C Regmap */ + ov2312->regmap = devm_regmap_init_i2c(client, &ov2312_regmap_config); + if (IS_ERR(ov2312->regmap)) + return PTR_ERR(ov2312->regmap); + + /* Initialize Shutdown GPIO */ + ov2312->reset_gpio = devm_gpiod_get_optional(ov2312->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov2312->reset_gpio)) + return PTR_ERR(ov2312->reset_gpio); + + ov2312->clk = devm_clk_get(ov2312->dev, "xvclk"); + if (IS_ERR(ov2312->clk)) + return PTR_ERR(ov2312->clk); + + ov2312->clk_rate = clk_get_rate(ov2312->clk); + dev_info(ov2312->dev, "xvclk rate: %lu Hz\n", ov2312->clk_rate); + + if (ov2312->clk_rate < 6000000 || ov2312->clk_rate > 27000000) + return -EINVAL; + + /* Power on */ + ret = ov2312_power_on(ov2312); + if (ret < 0) + return ret; + + /* Detect sensor */ + ret = ov2312_detect(ov2312); + if (ret < 0) + return ret; + + /* Initialize the subdev and its controls. */ + sd = &ov2312->sd; + v4l2_i2c_subdev_init(sd, client, &ov2312_subdev_ops); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_STREAMS; + + /* Initialize the media entity. */ + ov2312->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &ov2312->pad); + if (ret < 0) { + dev_err(ov2312->dev, + "%s: media entity init failed %d\n", __func__, ret); + return ret; + } + + ov2312->fps = OV2312_FRAMERATE_DEFAULT; + mutex_init(&ov2312->lock); + + /* Initialize controls */ + ctrl_hdr = &ov2312->ctrls; + ret = v4l2_ctrl_handler_init(ctrl_hdr, 5); + if (ret < 0) { + dev_err(ov2312->dev, + "%s: ctrl handler init failed: %d\n", __func__, ret); + goto err_media_cleanup; + } + + ov2312->ctrls.lock = &ov2312->lock; + + /* Add new controls */ + ov2312->exposure = v4l2_ctrl_new_std(ctrl_hdr, &ov2312_ctrl_ops, + V4L2_CID_EXPOSURE, 1, + OV2312_EXPOSURE_MAX, + 1, OV2312_EXPOSURE_DEFAULT); + + ov2312->again = v4l2_ctrl_new_std(ctrl_hdr, &ov2312_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 0, + OV2312_AGAIN_MAX, 1, + OV2312_AGAIN_DEFAULT); + + ov2312->dgain = v4l2_ctrl_new_std(ctrl_hdr, &ov2312_ctrl_ops, + V4L2_CID_DIGITAL_GAIN, 0, + OV2312_DGAIN_MAX, 1, + OV2312_DGAIN_DEFAULT); + + ov2312->h_flip = v4l2_ctrl_new_std(ctrl_hdr, &ov2312_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + ov2312->v_flip = v4l2_ctrl_new_std(ctrl_hdr, &ov2312_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + ov2312->sd.ctrl_handler = ctrl_hdr; + if (ov2312->ctrls.error) { + ret = ov2312->ctrls.error; + dev_err(ov2312->dev, + "%s: failed to add the ctrls: %d\n", __func__, ret); + goto err_ctrl_free; + } + + /* PM Runtime */ + pm_runtime_enable(ov2312->dev); + pm_runtime_set_suspended(ov2312->dev); + + ret = v4l2_subdev_init_finalize(sd); + if (ret < 0) + goto err_pm_disable; + + /* Finally, register the subdev. */ + ret = v4l2_async_register_subdev(sd); + if (ret < 0) { + dev_err(ov2312->dev, + "%s: v4l2 subdev register failed %d\n", __func__, ret); + goto err_subdev_cleanup; + } + + dev_info(ov2312->dev, "ov2312 probed\n"); + return 0; + +err_subdev_cleanup: + v4l2_subdev_cleanup(&ov2312->sd); + +err_pm_disable: + pm_runtime_disable(ov2312->dev); + +err_ctrl_free: + v4l2_ctrl_handler_free(ctrl_hdr); + mutex_destroy(&ov2312->lock); + +err_media_cleanup: + media_entity_cleanup(&ov2312->sd.entity); + + return ret; +} + +static void ov2312_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2312 *ov2312 = to_ov2312(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_ctrl_handler_free(&ov2312->ctrls); + v4l2_subdev_cleanup(&ov2312->sd); + media_entity_cleanup(&sd->entity); + mutex_destroy(&ov2312->lock); + + pm_runtime_disable(ov2312->dev); +} + +static const struct i2c_device_id ov2312_id[] = { + { "ov2312", 0 }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i2c, ov2312_id); + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ov2312_of_match[] = { + { .compatible = "ovti,ov2312", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ov2312_of_match); +#endif + +static struct i2c_driver ov2312_i2c_driver = { + .driver = { + .name = "ov2312", + .pm = &ov2312_pm_ops, + .of_match_table = of_match_ptr(ov2312_of_match), + }, + .probe = ov2312_probe, + .remove = ov2312_remove, + .id_table = ov2312_id, +}; + +module_i2c_driver(ov2312_i2c_driver); + +MODULE_AUTHOR("Jai Luthra "); +MODULE_DESCRIPTION("OV2312 RGB-IR Image Sensor driver"); +MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/drivers/media/i2c/ov2312.h b/drivers/media/i2c/ov2312.h --- a/drivers/media/i2c/ov2312.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/i2c/ov2312.h 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,267 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Omnivision OV2312 RGB-IR Image Sensor driver + * + * Copyright (c) 2022 Jai Luthra + */ + +#include +#include + +#define OV2312_CHIP_ID 0x2311 +#define OV2312_FRAMERATE_DEFAULT 60 + +#define OV2312_OUT_WIDTH 1600 +#define OV2312_OUT_HEIGHT 1300 +#define OV2312_VTS 0x0588 + +#define OV2312_SYS_MODE_SEL 0x0100 +#define OV2312_SC_CHIP_ID_HI 0x300a +#define OV2312_SC_CHIP_ID_LO 0x300b +#define OV2312_AEC_PK_EXPO_HI 0x3501 +#define OV2312_AEC_PK_EXPO_LO 0x3502 +#define OV2312_AEC_PK_AGAIN_HI 0x3508 +#define OV2312_AEC_PK_AGAIN_LO 0x3509 +#define OV2312_AEC_PK_DGAIN_HI 0x350a +#define OV2312_AEC_PK_DGAIN_LO 0x350b +#define OV2312_TIMING_VFLIP 0x3820 +#define OV2312_TIMING_HFLIP 0x3821 + +/* Exposure control */ +#define OV2312_EXPOSURE_MAX (OV2312_VTS - 12) +#define OV2312_EXPOSURE_DEFAULT 0x057c +#define OV2312_IR_EXPOSURE 0x0090 +#define OV2312_IR_STROBE OV2312_IR_EXPOSURE +#define OV2312_IR_STROBE_START (OV2312_VTS - OV2312_IR_EXPOSURE - 7) + +/* Analog gain control */ +#define OV2312_AGAIN_MAX 0x1FF +#define OV2312_AGAIN_DEFAULT 0x010 + +/* Digital gain control */ +#define OV2312_DGAIN_MAX 0x0FFF +#define OV2312_DGAIN_DEFAULT 0x0100 + +static const struct v4l2_area ov2312_framesizes[] = { + { + .width = OV2312_OUT_WIDTH, + .height = OV2312_OUT_HEIGHT, + }, +}; + +static const u32 ov2312_mbus_formats[] = { + MEDIA_BUS_FMT_SBGGI10_1X10, +}; + +static const struct regmap_config ov2312_regmap_config = { + .reg_bits = 16, + .val_bits = 8, +}; + +static const struct reg_sequence ov2312_1600x1300_60fps_AB[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x010c, 0x02}, + {0x010b, 0x01}, + {0x0300, 0x01}, + {0x0302, 0x32}, + {0x0303, 0x00}, + {0x0304, 0x03}, + {0x0305, 0x02}, + {0x0306, 0x01}, + {0x030d, 0x5a}, + {0x030e, 0x04}, + {0x3001, 0x02}, + {0x3004, 0x00}, + {0x3005, 0x00}, + {0x3006, 0x0a}, + {0x3011, 0x0d}, + {0x3014, 0x04}, + {0x301c, 0xf0}, + {0x3020, 0x20}, + {0x302c, 0x00}, + {0x302d, 0x00}, + {0x302e, 0x00}, + {0x302f, 0x03}, + {0x3030, 0x10}, + {0x303f, 0x03}, + {0x3103, 0x00}, + {0x3106, 0x08}, + {0x31ff, 0x01}, + {0x3501, 0x05}, + {0x3502, 0x7c}, + {0x3506, 0x00}, + {0x3507, 0x00}, + {0x3620, 0x67}, + {0x3633, 0x78}, + {0x3662, 0x65}, + {0x3664, 0xb0}, + {0x3666, 0x70}, + {0x3670, 0x68}, + {0x3674, 0x10}, + {0x3675, 0x00}, + {0x367e, 0x90}, + {0x3680, 0x84}, + {0x36a2, 0x04}, + {0x36a3, 0x80}, + {0x36b0, 0x00}, + {0x3700, 0x35}, + {0x3704, 0x39}, + {0x370a, 0x50}, + {0x3712, 0x00}, + {0x3713, 0x02}, + {0x3778, 0x00}, + {0x379b, 0x01}, + {0x379c, 0x10}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x00}, + {0x3804, 0x06}, + {0x3805, 0x4f}, + {0x3806, 0x05}, + {0x3807, 0x23}, + {0x3808, 0x06}, + {0x3809, 0x40}, + {0x380a, 0x05}, + {0x380b, 0x14}, + {0x380c, 0x03}, + {0x380d, 0xa8}, + {0x380e, (OV2312_VTS >> 8) & 0xff}, + {0x380f, OV2312_VTS & 0xff}, + {0x3810, 0x00}, + {0x3811, 0x08}, + {0x3812, 0x00}, + {0x3813, 0x08}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3816, 0x00}, + {0x3817, 0x01}, + {0x3818, 0x00}, + {0x3819, 0x05}, + {0x382b, 0x5a}, + {0x382c, 0x0a}, + {0x382d, 0xf8}, + {0x3881, 0x44}, + {0x3882, 0x02}, + {0x3883, 0x8c}, + {0x3885, 0x07}, + {0x389d, 0x03}, + {0x38a6, 0x00}, + {0x38a7, 0x01}, + {0x38b3, 0x07}, + {0x38b1, 0x00}, + {0x38e5, 0x02}, + {0x38e7, 0x00}, + {0x38e8, 0x00}, + {0x3910, 0xff}, + {0x3911, 0xff}, + {0x3912, 0x08}, + {0x3913, 0x00}, + {0x3914, 0x00}, + {0x3915, 0x00}, + {0x391c, 0x00}, + {0x3920, 0xff}, + {0x3921, 0x80}, + {0x3922, 0x00}, + {0x3923, 0x00}, + {0x3924, 0x05}, + {0x3925, 0x00}, + {0x3926, 0x00}, + {0x3927, 0x00}, + {0x3928, 0x1a}, + {0x392d, 0x03}, + {0x392e, 0xa8}, + {0x392f, 0x08}, + {0x4001, 0x00}, + {0x4003, 0x40}, + {0x4008, 0x04}, + {0x4009, 0x1b}, + {0x400c, 0x04}, + {0x400d, 0x1b}, + {0x4010, 0xf4}, + {0x4011, 0x00}, + {0x4016, 0x00}, + {0x4017, 0x04}, + {0x4042, 0x11}, + {0x4043, 0x70}, + {0x4045, 0x00}, + {0x4409, 0x5f}, + {0x4509, 0x00}, + {0x450b, 0x00}, + {0x4600, 0x00}, + {0x4601, 0x80}, + {0x4708, 0x09}, + {0x470c, 0x81}, + {0x4710, 0x06}, + {0x4711, 0x00}, + {0x4800, 0x00}, + {0x481f, 0x30}, + {0x4837, 0x14}, + {0x4f00, 0x00}, + {0x4f07, 0x00}, + {0x4f08, 0x03}, + {0x4f09, 0x08}, + {0x4f0c, 0x05}, + {0x4f0d, 0xb4}, + {0x4f10, 0x00}, + {0x4f11, 0x00}, + {0x4f12, 0x07}, + {0x4f13, 0xe2}, + {0x5000, 0x9f}, + {0x5001, 0x20}, + {0x5026, 0x00}, + {0x5c00, 0x00}, + {0x5c01, 0x2c}, + {0x5c02, 0x00}, + {0x5c03, 0x7f}, + {0x5e00, 0x00}, + {0x5e01, 0x41}, + {0x38b1, 0x02}, + {0x0100, 0x01}, + {0x3006, 0x08},/* Strobe control */ + {0x3004, 0x02}, + {0x3007, 0x02}, + {0x301c, 0x20}, + {0x3020, 0x20}, + {0x3025, 0x02}, + {0x382c, 0x0a}, + {0x382d, 0xf8}, + {0x3920, 0xff}, + {0x3921, 0x00}, + {0x3923, 0x00}, + {0x3924, 0x00}, + {0x3925, 0x00}, + {0x3926, 0x00}, + {0x3927, 0x00}, + {0x3928, 0x80}, + {0x392b, 0x00}, + {0x392c, 0x00}, + {0x392d, 0x03}, + {0x392e, 0xa8}, + {0x392f, 0x0b}, + {0x38b3, 0x07}, + {0x3885, 0x07}, + {0x382b, 0x3a}, + {0x3670, 0x68}, + {0x301C, 0xF0},/* AB mode - Group auto switch example setting */ + {0x3209, 0x01},/* Stay in Group A for 1 Frame */ + {0x320A, 0x01},/* Stay in Group B for 1 Frame */ + {0x320B, 0x00}, + {0x320C, 0x00}, + {0x3208, 0x01},/* Group A (IR Dominant VC0) */ + {OV2312_AEC_PK_EXPO_HI, (OV2312_IR_EXPOSURE >> 8) & 0xff}, + {OV2312_AEC_PK_EXPO_LO, OV2312_IR_EXPOSURE & 0xff}, + {OV2312_AEC_PK_AGAIN_HI, 0x01}, + {OV2312_AEC_PK_AGAIN_LO, 0x00}, + {OV2312_AEC_PK_DGAIN_HI, 0x01}, + {OV2312_AEC_PK_DGAIN_LO, 0x00}, + {0x3920, 0xff},/* IR Strobe duty cycle */ + {0x3927, (OV2312_IR_STROBE >> 8) & 0xff}, + {0x3928, OV2312_IR_STROBE & 0xff}, + {0x3929, (OV2312_IR_STROBE_START >> 8) & 0xff}, + {0x392a, OV2312_IR_STROBE_START & 0xff}, + {0x4813, 0x01},/* VC=1. This register takes effect from next frame */ + {0x3208, 0x11}, + +}; diff -Naur --no-dereference a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c --- a/drivers/media/i2c/ov5640.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/i2c/ov5640.c 2024-07-07 20:37:34.648306569 -0400 @@ -178,8 +178,8 @@ 248000000, 192000000, 192000000, 192000000, 96000000, }; -/* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */ -#define OV5640_DEFAULT_LINK_FREQ 13 +/* Link freq for default mode: UYVY 640x480, 16 bpp, 2 data lanes. */ +#define OV5640_DEFAULT_LINK_FREQ 19 enum ov5640_format_mux { OV5640_FMT_MUX_YUV422 = 0, @@ -3943,7 +3943,7 @@ if (ret) goto err_pm_runtime; - pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_set_autosuspend_delay(dev, -1); pm_runtime_use_autosuspend(dev); pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); diff -Naur --no-dereference a/drivers/media/i2c/ox05b1s.c b/drivers/media/i2c/ox05b1s.c --- a/drivers/media/i2c/ox05b1s.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/i2c/ox05b1s.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,1146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * OmniVision OX05B1S RGB-IR Image Sensor driver + * + * Copyright (c) 2023-2024 Abhishek Sharma + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define OX05B_CHIP_ID 0x0558 +#define OX05B_FRAMERATE_DEFAULT 60 + +#define OX05B_OUT_WIDTH 2592 +#define OX05B_OUT_HEIGHT 1944 + +#define OX05B_SYS_MODE_SEL 0x0100 +#define OX05B_SC_CHIP_ID_HI 0x300a +#define OX05B_AEC_PK_EXPO_HI 0x3501 +#define OX05B_AEC_PK_EXPO_LO 0x3502 +#define OX05B_AEC_PK_AGAIN_HI 0x3508 +#define OX05B_AEC_PK_AGAIN_LO 0x3509 +#define OX05B_AEC_PK_DGAIN_HI 0x350a +#define OX05B_AEC_PK_DGAIN_LO 0x350b +#define OX05B_DEFAULT_LINK_FREQ 480000000 + +/* + * Exposure control + * Set max value as 0x850 (frame length = 2128) - 30 = 0x0832 for 16.66 ms exposure + * Set default value to be 1000 (0x03E8). + */ +#define OX05B_EXPOSURE_MAX 0x0832 +#define OX05B_EXPOSURE_DEFAULT 0x03E8 + +/* Analog gain control */ +#define OX05B_AGAIN_MAX 0x0F80 +#define OX05B_AGAIN_DEFAULT 0x010 + +/* Digital gain control */ +#define OX05B_DGAIN_MAX 0x0FFF +#define OX05B_DGAIN_DEFAULT 0x0100 + +static const struct v4l2_area ox05b_framesizes[] = { + { + .width = OX05B_OUT_WIDTH, + .height = OX05B_OUT_HEIGHT, + }, +}; + +static const u32 ox05b_mbus_formats[] = { + MEDIA_BUS_FMT_SBGGI10_1X10, +}; + +static const struct regmap_config ox05b_regmap_config = { + .reg_bits = 16, + .val_bits = 8, +}; + +static const s64 ox05b_link_freq_menu[] = { + OX05B_DEFAULT_LINK_FREQ, +}; + +static const struct reg_sequence ox05b_linear_2592x1944[] = { + {0x0107, 0x01}, {0x0104, 0x00}, {0x0301, 0x1a}, {0x0304, 0x01}, + {0x0305, 0xe0}, {0x0306, 0x04}, {0x0307, 0x01}, {0x0321, 0x03}, + {0x0324, 0x01}, {0x0325, 0x80}, {0x0341, 0x03}, {0x0344, 0x01}, + {0x0345, 0xb0}, {0x0347, 0x07}, {0x034b, 0x06}, {0x0360, 0x80}, + {0x040b, 0x5c}, {0x040c, 0xcd}, {0x2805, 0xff}, {0x2806, 0x0f}, + {0x3000, 0x00}, {0x3001, 0x00}, {0x3002, 0x10}, {0x3004, 0x00}, + {0x3009, 0x2e}, {0x3010, 0x41}, {0x3015, 0xf0}, {0x3016, 0xf0}, + {0x3017, 0xf0}, {0x3018, 0xf0}, {0x301a, 0x78}, {0x301b, 0xb4}, + {0x301f, 0xe9}, {0x3024, 0x80}, {0x302b, 0x00}, {0x3039, 0x00}, + {0x3044, 0x70}, {0x3101, 0x32}, {0x3182, 0x10}, {0x3187, 0xff}, + {0x320a, 0x00}, {0x320b, 0x00}, {0x320c, 0x00}, {0x320d, 0x00}, + {0x320e, 0x00}, {0x320f, 0x00}, {0x3211, 0x61}, {0x3212, 0x00}, + {0x3215, 0xcc}, {0x3218, 0x06}, {0x3251, 0x00}, {0x3252, 0xe4}, + {0x3253, 0x00}, {0x3304, 0x11}, {0x3305, 0x00}, {0x3306, 0x01}, + {0x3307, 0x00}, {0x3308, 0x02}, {0x3309, 0x00}, {0x330a, 0x02}, + {0x330b, 0x00}, {0x330c, 0x02}, {0x330d, 0x00}, {0x330e, 0x02}, + {0x330f, 0x00}, {0x3310, 0x02}, {0x3311, 0x00}, {0x3312, 0x02}, + {0x3313, 0x00}, {0x3314, 0x02}, {0x3315, 0x00}, {0x3316, 0x02}, + {0x3317, 0x11}, {0x3400, 0x0c}, {0x3421, 0x00}, {0x3422, 0x00}, + {0x3423, 0x00}, {0x3424, 0x00}, {0x3425, 0x00}, {0x3426, 0x00}, + {0x3427, 0x00}, {0x3428, 0x00}, {0x3429, 0x00}, {0x342a, 0x00}, + {0x342b, 0x00}, {0x342c, 0x00}, {0x342d, 0x00}, {0x342e, 0x00}, + {0x3500, 0x00}, {0x3501, 0x00}, {0x3502, 0x08}, {0x3503, 0xa8}, + {0x3504, 0x08}, {0x3505, 0x00}, {0x3506, 0x00}, {0x3507, 0x00}, + {0x3508, 0x01}, {0x3509, 0x00}, {0x350a, 0x01}, {0x350b, 0x00}, + {0x350c, 0x00}, {0x351e, 0x00}, {0x351f, 0x00}, {0x3541, 0x00}, + {0x3542, 0x08}, {0x3603, 0x65}, {0x3604, 0x24}, {0x3608, 0x08}, + {0x3610, 0x00}, {0x3612, 0x00}, {0x3619, 0x09}, {0x361a, 0x27}, + {0x3620, 0x40}, {0x3622, 0x15}, {0x3623, 0x0e}, {0x3624, 0x1f}, + {0x3625, 0x1f}, {0x362a, 0x01}, {0x362b, 0x00}, {0x3633, 0x88}, + {0x3634, 0x86}, {0x3636, 0x80}, {0x3638, 0x5b}, {0x363b, 0x22}, + {0x363c, 0x07}, {0x363d, 0x11}, {0x363e, 0x21}, {0x363f, 0x24}, + {0x3640, 0xd3}, {0x3641, 0x00}, {0x3650, 0xe4}, {0x3651, 0x80}, + {0x3652, 0xff}, {0x3653, 0x00}, {0x3654, 0x05}, {0x3655, 0xf8}, + {0x3656, 0x00}, {0x3660, 0x00}, {0x3664, 0x00}, {0x366a, 0x80}, + {0x366b, 0x00}, {0x3670, 0x00}, {0x3674, 0x00}, {0x3684, 0x6d}, + {0x3685, 0x6d}, {0x3686, 0x6d}, {0x3687, 0x6d}, {0x368c, 0x07}, + {0x368d, 0x07}, {0x368e, 0x07}, {0x368f, 0x07}, {0x3690, 0x04}, + {0x3691, 0x04}, {0x3692, 0x04}, {0x3693, 0x04}, {0x3698, 0x00}, + {0x369e, 0x1f}, {0x369f, 0x19}, {0x36a0, 0x05}, {0x36a2, 0x19}, + {0x36a3, 0x05}, {0x36a4, 0x07}, {0x36a5, 0x27}, {0x36a6, 0x00}, + {0x36a7, 0x80}, {0x36e3, 0x09}, {0x3700, 0x07}, {0x3701, 0x1b}, + {0x3702, 0x0a}, {0x3703, 0x21}, {0x3704, 0x19}, {0x3705, 0x07}, + {0x3706, 0x36}, {0x370a, 0x1c}, {0x370b, 0x02}, {0x370c, 0x00}, + {0x370d, 0x6e}, {0x370f, 0x80}, {0x3710, 0x10}, {0x3712, 0x09}, + {0x3714, 0x42}, {0x3715, 0x00}, {0x3716, 0x02}, {0x3717, 0xa2}, + {0x3718, 0x41}, {0x371a, 0x80}, {0x371b, 0x0a}, {0x371c, 0x0a}, + {0x371d, 0x08}, {0x371e, 0x01}, {0x371f, 0x20}, {0x3720, 0x0e}, + {0x3721, 0x22}, {0x3722, 0x0c}, {0x3727, 0x84}, {0x3728, 0x03}, + {0x3729, 0x64}, {0x372a, 0x0c}, {0x372b, 0x14}, {0x372d, 0x50}, + {0x372e, 0x14}, {0x3731, 0x11}, {0x3732, 0x24}, {0x3733, 0x00}, + {0x3734, 0x00}, {0x3735, 0x12}, {0x3736, 0x00}, {0x373b, 0x0b}, + {0x373c, 0x14}, {0x373f, 0x3e}, {0x3740, 0x12}, {0x3741, 0x12}, + {0x3753, 0x80}, {0x3754, 0x01}, {0x3756, 0x11}, {0x375c, 0x0f}, + {0x375d, 0x35}, {0x375e, 0x0f}, {0x375f, 0x37}, {0x3760, 0x0f}, + {0x3761, 0x27}, {0x3762, 0x3f}, {0x3763, 0x5d}, {0x3764, 0x01}, + {0x3765, 0x17}, {0x3766, 0x02}, {0x3768, 0x52}, {0x376a, 0x30}, + {0x376b, 0x02}, {0x376c, 0x08}, {0x376d, 0x2a}, {0x376e, 0x00}, + {0x376f, 0x18}, {0x3770, 0x2c}, {0x3771, 0x0c}, {0x3776, 0xc0}, + {0x3778, 0x00}, {0x3779, 0x80}, {0x377a, 0x00}, {0x377d, 0x14}, + {0x377e, 0x0c}, {0x379f, 0x00}, {0x37a3, 0x40}, {0x37a4, 0x03}, + {0x37a5, 0x10}, {0x37a6, 0x02}, {0x37a7, 0x0e}, {0x37a9, 0x00}, + {0x37aa, 0x08}, {0x37ab, 0x08}, {0x37ac, 0x36}, {0x37ad, 0x40}, + {0x37b0, 0x48}, {0x37d0, 0x00}, {0x37d1, 0x0b}, {0x37d2, 0x0c}, + {0x37d3, 0x10}, {0x37d4, 0x10}, {0x37d5, 0x10}, {0x37d8, 0x0e}, + {0x37d9, 0x0e}, {0x37da, 0x3c}, {0x37db, 0x52}, {0x37dc, 0x50}, + {0x37dd, 0x00}, {0x37de, 0x55}, {0x37df, 0x7d}, {0x37e5, 0x88}, + {0x37e7, 0x68}, {0x37e8, 0x07}, {0x37f0, 0x00}, {0x37f1, 0x0e}, + {0x37f2, 0x35}, {0x37f3, 0x14}, {0x37f4, 0x0c}, {0x37f5, 0x14}, + {0x37f6, 0x0c}, {0x37f7, 0x35}, {0x37f8, 0x35}, {0x37f9, 0x37}, + {0x37fa, 0x37}, {0x37fb, 0x37}, {0x3800, 0x00}, {0x3801, 0x00}, + {0x3802, 0x00}, {0x3803, 0x00}, {0x3804, 0x0a}, {0x3805, 0x2f}, + {0x3806, 0x07}, {0x3807, 0xa7}, {0x3808, 0x0a}, {0x3809, 0x20}, + {0x380a, 0x07}, {0x380b, 0x98}, {0x380c, 0x01}, {0x380d, 0x78}, + {0x380e, 0x08}, {0x380f, 0x50}, {0x3810, 0x00}, {0x3811, 0x05}, + {0x3812, 0x00}, {0x3813, 0x08}, {0x3814, 0x11}, {0x3815, 0x11}, + {0x3820, 0x40}, {0x3821, 0x04}, {0x3822, 0x10}, {0x3823, 0x00}, + {0x3826, 0x00}, {0x3827, 0x00}, {0x382b, 0x03}, {0x382c, 0x0c}, + {0x382d, 0x15}, {0x382e, 0x01}, {0x3830, 0x00}, {0x3838, 0x00}, + {0x383b, 0x00}, {0x3840, 0x00}, {0x384a, 0xa2}, {0x3858, 0x00}, + {0x3859, 0x00}, {0x3860, 0x00}, {0x3861, 0x00}, {0x3866, 0x10}, + {0x3867, 0x07}, {0x3868, 0x01}, {0x3869, 0x01}, {0x386a, 0x01}, + {0x386b, 0x01}, {0x386c, 0x46}, {0x386d, 0x07}, {0x386e, 0xd2}, + {0x3871, 0x01}, {0x3872, 0x01}, {0x3873, 0x01}, {0x3874, 0x01}, + {0x3880, 0x00}, {0x3881, 0x00}, {0x3882, 0x00}, {0x3883, 0x00}, + {0x3884, 0x00}, {0x3885, 0x00}, {0x3886, 0x00}, {0x3887, 0x00}, + {0x3888, 0x00}, {0x3889, 0x00}, {0x3900, 0x13}, {0x3901, 0x19}, + {0x3902, 0x05}, {0x3903, 0x00}, {0x3904, 0x00}, {0x3908, 0x00}, + {0x3909, 0x18}, {0x390a, 0x00}, {0x390b, 0x11}, {0x390c, 0x15}, + {0x390d, 0x84}, {0x390f, 0x88}, {0x3910, 0x00}, {0x3911, 0x00}, + {0x3912, 0x03}, {0x3913, 0x62}, {0x3914, 0x00}, {0x3915, 0x06}, + {0x3916, 0x0c}, {0x3917, 0x81}, {0x3918, 0xc8}, {0x3919, 0x94}, + {0x391a, 0x17}, {0x391b, 0x05}, {0x391c, 0x81}, {0x391d, 0x05}, + {0x391e, 0x81}, {0x391f, 0x05}, {0x3920, 0x81}, {0x3921, 0x14}, + {0x3922, 0x0b}, {0x3929, 0x00}, {0x392a, 0x00}, {0x392b, 0xc8}, + {0x392c, 0x81}, {0x392f, 0x00}, {0x3930, 0x00}, {0x3931, 0x00}, + {0x3932, 0x00}, {0x3933, 0x00}, {0x3934, 0x1b}, {0x3935, 0xc0}, + {0x3936, 0x1c}, {0x3937, 0x21}, {0x3938, 0x0d}, {0x3939, 0x92}, + {0x393a, 0x85}, {0x393b, 0x8a}, {0x393c, 0x06}, {0x393d, 0x8b}, + {0x393e, 0x0f}, {0x393f, 0x14}, {0x3940, 0x0f}, {0x3941, 0x14}, + {0x3945, 0xc0}, {0x3946, 0x05}, {0x3947, 0xc0}, {0x3948, 0x01}, + {0x3949, 0x00}, {0x394a, 0x00}, {0x394b, 0x0b}, {0x394c, 0x0c}, + {0x394d, 0x0b}, {0x394e, 0x09}, {0x3951, 0xc7}, {0x3952, 0x0f}, + {0x3953, 0x0f}, {0x3954, 0x0f}, {0x3955, 0x00}, {0x3956, 0x27}, + {0x3957, 0x27}, {0x3958, 0x27}, {0x3959, 0x01}, {0x395a, 0x02}, + {0x395b, 0x14}, {0x395c, 0x36}, {0x395e, 0xc0}, {0x3964, 0x55}, + {0x3965, 0x55}, {0x3966, 0x88}, {0x3967, 0x88}, {0x3968, 0x66}, + {0x3969, 0x66}, {0x396d, 0x80}, {0x396e, 0xff}, {0x396f, 0x10}, + {0x3970, 0x80}, {0x3971, 0x80}, {0x3972, 0x00}, {0x397a, 0x55}, + {0x397b, 0x10}, {0x397c, 0x10}, {0x397d, 0x10}, {0x397e, 0x10}, + {0x3980, 0xfc}, {0x3981, 0xfc}, {0x3982, 0x66}, {0x3983, 0xfc}, + {0x3984, 0xfc}, {0x3985, 0x66}, {0x3986, 0x00}, {0x3987, 0x00}, + {0x3988, 0x00}, {0x3989, 0x00}, {0x398a, 0x00}, {0x398b, 0x00}, + {0x398c, 0x00}, {0x398d, 0x00}, {0x398e, 0x00}, {0x398f, 0x00}, + {0x3990, 0x00}, {0x3991, 0x00}, {0x3992, 0x00}, {0x3993, 0x00}, + {0x3994, 0x00}, {0x3995, 0x00}, {0x3996, 0x00}, {0x3997, 0x0f}, + {0x3998, 0x0c}, {0x3999, 0x0c}, {0x399a, 0x0c}, {0x399b, 0xf0}, + {0x399c, 0x14}, {0x399d, 0x0d}, {0x399e, 0x00}, {0x399f, 0x0c}, + {0x39a0, 0x0c}, {0x39a1, 0x0c}, {0x39a2, 0x00}, {0x39a3, 0x0f}, + {0x39a4, 0x0c}, {0x39a5, 0x0c}, {0x39a6, 0x0c}, {0x39a7, 0x0c}, + {0x39a8, 0x0f}, {0x39a9, 0xff}, {0x39aa, 0xbf}, {0x39ab, 0x3f}, + {0x39ac, 0x7e}, {0x39ad, 0xff}, {0x39ae, 0x00}, {0x39af, 0x00}, + {0x39b0, 0x00}, {0x39b1, 0x00}, {0x39b2, 0x00}, {0x39b3, 0x00}, + {0x39b4, 0x00}, {0x39b5, 0x00}, {0x39b6, 0x00}, {0x39b7, 0x00}, + {0x39b8, 0x00}, {0x39b9, 0x00}, {0x39ba, 0x00}, {0x39bb, 0x00}, + {0x39bc, 0x00}, {0x39c2, 0x00}, {0x39c3, 0x00}, {0x39c4, 0x00}, + {0x39c5, 0x00}, {0x39c7, 0x00}, {0x39c8, 0x00}, {0x39c9, 0x00}, + {0x39ca, 0x01}, {0x39cb, 0x00}, {0x39cc, 0x85}, {0x39cd, 0x09}, + {0x39cf, 0x04}, {0x39d0, 0x85}, {0x39d1, 0x09}, {0x39d2, 0x04}, + {0x39d4, 0x02}, {0x39d5, 0x0e}, {0x39db, 0x00}, {0x39dc, 0x01}, + {0x39dd, 0x0c}, {0x39e5, 0xff}, {0x39e6, 0xff}, {0x39fa, 0x38}, + {0x39fb, 0x07}, {0x39ff, 0x00}, {0x3a05, 0x00}, {0x3a06, 0x07}, + {0x3a07, 0x0d}, {0x3a08, 0x08}, {0x3a09, 0xb2}, {0x3a0a, 0x0a}, + {0x3a0b, 0x3c}, {0x3a0c, 0x0b}, {0x3a0d, 0xe1}, {0x3a0e, 0x03}, + {0x3a0f, 0x85}, {0x3a10, 0x0b}, {0x3a11, 0xff}, {0x3a12, 0x00}, + {0x3a13, 0x01}, {0x3a14, 0x0c}, {0x3a15, 0x04}, {0x3a17, 0x09}, + {0x3a18, 0x20}, {0x3a19, 0x09}, {0x3a1a, 0x9d}, {0x3a1b, 0x09}, + {0x3a1e, 0x34}, {0x3a1f, 0x09}, {0x3a20, 0x89}, {0x3a21, 0x09}, + {0x3a48, 0xbe}, {0x3a52, 0x00}, {0x3a53, 0x01}, {0x3a54, 0x0c}, + {0x3a55, 0x04}, {0x3a58, 0x0c}, {0x3a59, 0x04}, {0x3a5a, 0x01}, + {0x3a5b, 0x00}, {0x3a5c, 0x01}, {0x3a5d, 0xe8}, {0x3a62, 0x03}, + {0x3a63, 0x86}, {0x3a64, 0x0b}, {0x3a65, 0xbe}, {0x3a6a, 0xdc}, + {0x3a6b, 0x0b}, {0x3a6c, 0x1a}, {0x3a6d, 0x06}, {0x3a6e, 0x01}, + {0x3a6f, 0x04}, {0x3a70, 0xdc}, {0x3a71, 0x0b}, {0x3a83, 0x10}, + {0x3a84, 0x00}, {0x3a85, 0x08}, {0x3a87, 0x00}, {0x3a88, 0x6b}, + {0x3a89, 0x01}, {0x3a8a, 0x53}, {0x3a8f, 0x00}, {0x3a90, 0x00}, + {0x3a91, 0x00}, {0x3a92, 0x00}, {0x3a93, 0x60}, {0x3a94, 0xea}, + {0x3a98, 0x00}, {0x3a99, 0x31}, {0x3a9a, 0x01}, {0x3a9b, 0x04}, + {0x3a9c, 0xdc}, {0x3a9d, 0x0b}, {0x3aa4, 0x0f}, {0x3aad, 0x00}, + {0x3aae, 0x3e}, {0x3aaf, 0x02}, {0x3ab0, 0x77}, {0x3ab2, 0x00}, + {0x3ab3, 0x08}, {0x3ab6, 0x0b}, {0x3ab7, 0xff}, {0x3aba, 0x0b}, + {0x3abb, 0xfa}, {0x3abd, 0x05}, {0x3abe, 0x09}, {0x3abf, 0x1e}, + {0x3ac0, 0x00}, {0x3ac1, 0x63}, {0x3ac2, 0x01}, {0x3ac3, 0x55}, + {0x3ac8, 0x00}, {0x3ac9, 0x2a}, {0x3aca, 0x01}, {0x3acb, 0x36}, + {0x3acc, 0x00}, {0x3acd, 0x6f}, {0x3ad0, 0x00}, {0x3ad1, 0x79}, + {0x3ad2, 0x02}, {0x3ad3, 0x59}, {0x3ad4, 0x06}, {0x3ad5, 0x5a}, + {0x3ad6, 0x08}, {0x3ad7, 0x3a}, {0x3ad8, 0x00}, {0x3ad9, 0x79}, + {0x3ada, 0x02}, {0x3adb, 0x59}, {0x3adc, 0x09}, {0x3add, 0x89}, + {0x3ade, 0x0b}, {0x3adf, 0x69}, {0x3ae0, 0x03}, {0x3ae1, 0xc1}, + {0x3ae2, 0x0b}, {0x3ae3, 0xaf}, {0x3ae4, 0x00}, {0x3ae5, 0x3e}, + {0x3ae6, 0x02}, {0x3ae7, 0x77}, {0x3ae8, 0x00}, {0x3aea, 0x0b}, + {0x3aeb, 0xbe}, {0x3aee, 0x08}, {0x3aef, 0x80}, {0x3af0, 0x09}, + {0x3af1, 0x70}, {0x3af2, 0x08}, {0x3af3, 0x94}, {0x3af4, 0x09}, + {0x3af5, 0x5c}, {0x3af6, 0x03}, {0x3af7, 0x85}, {0x3af8, 0x08}, + {0x3af9, 0x80}, {0x3afa, 0x0b}, {0x3afb, 0xaf}, {0x3afc, 0x01}, + {0x3afd, 0x5a}, {0x3b1e, 0x00}, {0x3b20, 0xa5}, {0x3b21, 0x00}, + {0x3b22, 0x00}, {0x3b23, 0x00}, {0x3b24, 0x05}, {0x3b25, 0x00}, + {0x3b26, 0x00}, {0x3b27, 0x00}, {0x3b28, 0x1a}, {0x3b2f, 0x40}, + {0x3b40, 0x08}, {0x3b41, 0x70}, {0x3b42, 0x05}, {0x3b43, 0xf0}, + {0x3b44, 0x01}, {0x3b45, 0x54}, {0x3b46, 0x01}, {0x3b47, 0x54}, + {0x3b56, 0x08}, {0x3b80, 0x00}, {0x3b81, 0x00}, {0x3b82, 0x64}, + {0x3b83, 0x00}, {0x3b84, 0x00}, {0x3b85, 0x64}, {0x3b9d, 0x61}, + {0x3ba8, 0x38}, {0x3c11, 0x33}, {0x3c12, 0x3d}, {0x3c13, 0x00}, + {0x3c14, 0xbe}, {0x3c15, 0x0b}, {0x3c16, 0xa8}, {0x3c17, 0x03}, + {0x3c18, 0x9c}, {0x3c19, 0x0b}, {0x3c1a, 0x0f}, {0x3c1b, 0x97}, + {0x3c1c, 0x00}, {0x3c1d, 0x3c}, {0x3c1e, 0x02}, {0x3c1f, 0x78}, + {0x3c20, 0x06}, {0x3c21, 0x80}, {0x3c22, 0x08}, {0x3c23, 0x0f}, + {0x3c24, 0x97}, {0x3c25, 0x00}, {0x3c26, 0x3c}, {0x3c27, 0x02}, + {0x3c28, 0xa7}, {0x3c29, 0x09}, {0x3c2a, 0xaf}, {0x3c2b, 0x0b}, + {0x3c2c, 0x38}, {0x3c2d, 0xf9}, {0x3c2e, 0x0b}, {0x3c2f, 0xfd}, + {0x3c30, 0x05}, {0x3c35, 0x8c}, {0x3c3e, 0xc3}, {0x3c43, 0xcb}, + {0x3c44, 0x00}, {0x3c45, 0xff}, {0x3c46, 0x0b}, {0x3c48, 0x3b}, + {0x3c49, 0x40}, {0x3c4a, 0x00}, {0x3c4b, 0x5b}, {0x3c4c, 0x02}, + {0x3c4d, 0x02}, {0x3c4e, 0x00}, {0x3c4f, 0x04}, {0x3c50, 0x0c}, + {0x3c51, 0x00}, {0x3c52, 0x3b}, {0x3c53, 0x3a}, {0x3c54, 0x07}, + {0x3c55, 0x9e}, {0x3c56, 0x07}, {0x3c57, 0x9e}, {0x3c58, 0x07}, + {0x3c59, 0xe8}, {0x3c5a, 0x03}, {0x3c5b, 0x33}, {0x3c5c, 0xa8}, + {0x3c5d, 0x07}, {0x3c5e, 0xd0}, {0x3c5f, 0x07}, {0x3c60, 0x32}, + {0x3c61, 0x00}, {0x3c62, 0xd0}, {0x3c63, 0x07}, {0x3c64, 0x80}, + {0x3c65, 0x80}, {0x3c66, 0x3f}, {0x3c67, 0x01}, {0x3c68, 0x00}, + {0x3c69, 0xd0}, {0x3c6a, 0x07}, {0x3c6b, 0x01}, {0x3c6c, 0x00}, + {0x3c6d, 0xcd}, {0x3c6e, 0x07}, {0x3c6f, 0xd1}, {0x3c70, 0x07}, + {0x3c71, 0x01}, {0x3c72, 0x00}, {0x3c73, 0xc3}, {0x3c74, 0x01}, + {0x3c75, 0x00}, {0x3c76, 0xcd}, {0x3c77, 0x07}, {0x3c78, 0xea}, + {0x3c79, 0x03}, {0x3c7a, 0xcd}, {0x3c7b, 0x07}, {0x3c7c, 0x08}, + {0x3c7d, 0x06}, {0x3c7e, 0x03}, {0x3c85, 0x3a}, {0x3c86, 0x08}, + {0x3c87, 0x69}, {0x3c88, 0x0b}, {0x3c8f, 0xb2}, {0x3c90, 0x08}, + {0x3c91, 0xe1}, {0x3c92, 0x0b}, {0x3c93, 0x06}, {0x3c94, 0x03}, + {0x3c9b, 0x35}, {0x3c9c, 0x08}, {0x3c9d, 0x64}, {0x3c9e, 0x0b}, + {0x3ca5, 0xb7}, {0x3ca6, 0x08}, {0x3ca7, 0xe6}, {0x3ca8, 0x0b}, + {0x3ca9, 0x83}, {0x3caa, 0x3c}, {0x3cab, 0x01}, {0x3cac, 0x00}, + {0x3cad, 0x9e}, {0x3cae, 0x07}, {0x3caf, 0x85}, {0x3cb0, 0x03}, + {0x3cb1, 0xbc}, {0x3cb2, 0x0b}, {0x3cb7, 0x3c}, {0x3cb8, 0x01}, + {0x3cb9, 0x00}, {0x3cba, 0xbc}, {0x3cbb, 0x07}, {0x3cbc, 0xa3}, + {0x3cbd, 0x03}, {0x3cbe, 0x9e}, {0x3cbf, 0x0b}, {0x3cc4, 0x99}, + {0x3cc5, 0xe9}, {0x3cc6, 0x99}, {0x3cc7, 0xe9}, {0x3cc8, 0x33}, + {0x3cc9, 0x03}, {0x3cca, 0x33}, {0x3ccb, 0x03}, {0x3cce, 0x66}, + {0x3ccf, 0x66}, {0x3cd0, 0x00}, {0x3cd1, 0x04}, {0x3cd2, 0xf4}, + {0x3cd3, 0xb7}, {0x3cd4, 0x03}, {0x3cd5, 0x10}, {0x3cd6, 0x06}, + {0x3cd7, 0x30}, {0x3cd8, 0x08}, {0x3cd9, 0x5f}, {0x3cda, 0x0b}, + {0x3cdd, 0x44}, {0x3cde, 0x44}, {0x3cdf, 0x04}, {0x3ce0, 0x00}, + {0x3ce1, 0x00}, {0x3ce3, 0x00}, {0x3ce4, 0x00}, {0x3ce5, 0x00}, + {0x3ce6, 0x00}, {0x3ce7, 0x00}, {0x3ce8, 0x00}, {0x3ce9, 0x00}, + {0x3cea, 0x00}, {0x3ceb, 0x00}, {0x3cec, 0x00}, {0x3ced, 0x00}, + {0x3cee, 0x00}, {0x3cef, 0x85}, {0x3cf0, 0x03}, {0x3cf1, 0xaf}, + {0x3cf2, 0x0b}, {0x3cf3, 0x03}, {0x3cf4, 0x2c}, {0x3cf5, 0x00}, + {0x3cf6, 0x42}, {0x3cf7, 0x00}, {0x3cf8, 0x03}, {0x3cf9, 0x2c}, + {0x3cfa, 0x00}, {0x3cfb, 0x42}, {0x3cfc, 0x00}, {0x3cfd, 0x03}, + {0x3cfe, 0x01}, {0x3d81, 0x00}, {0x3e94, 0x0f}, {0x3e95, 0x5f}, + {0x3e96, 0x02}, {0x3e97, 0x3c}, {0x3e98, 0x00}, {0x3e9f, 0x00}, + {0x3f00, 0x00}, {0x3f05, 0x03}, {0x3f07, 0x01}, {0x3f08, 0x55}, + {0x3f09, 0x25}, {0x3f0a, 0x35}, {0x3f0b, 0x20}, {0x3f11, 0x05}, + {0x3f12, 0x05}, {0x3f40, 0x00}, {0x3f41, 0x03}, {0x3f43, 0x10}, + {0x3f44, 0x02}, {0x3f45, 0xe6}, {0x4000, 0xf9}, {0x4001, 0x2b}, + {0x4008, 0x04}, {0x4009, 0x1b}, {0x400a, 0x03}, {0x400e, 0x10}, + {0x4010, 0x04}, {0x4011, 0xf7}, {0x4032, 0x3e}, {0x4033, 0x02}, + {0x4050, 0x02}, {0x4051, 0x0d}, {0x40f9, 0x00}, {0x4200, 0x00}, + {0x4204, 0x00}, {0x4205, 0x00}, {0x4206, 0x00}, {0x4207, 0x00}, + {0x4208, 0x00}, {0x4244, 0x00}, {0x4300, 0x00}, {0x4301, 0xff}, + {0x4302, 0xf0}, {0x4303, 0x00}, {0x4304, 0xff}, {0x4305, 0xf0}, + {0x4306, 0x00}, {0x4308, 0x00}, {0x430a, 0x90}, {0x430b, 0x11}, + {0x4310, 0x00}, {0x4316, 0x00}, {0x431c, 0x00}, {0x431e, 0x00}, + {0x4410, 0x08}, {0x4433, 0x08}, {0x4434, 0xf8}, {0x4508, 0x80}, + {0x4509, 0x10}, {0x450b, 0x83}, {0x4511, 0x00}, {0x4580, 0x09}, + {0x4587, 0x00}, {0x458c, 0x00}, {0x4640, 0x00}, {0x4641, 0xc1}, + {0x4642, 0x00}, {0x4643, 0x00}, {0x4649, 0x00}, {0x4681, 0x04}, + {0x4682, 0x10}, {0x4683, 0xa0}, {0x4698, 0x07}, {0x4699, 0xf0}, + {0x4710, 0x00}, {0x4802, 0x00}, {0x481b, 0x3c}, {0x4837, 0x10}, + {0x4860, 0x00}, {0x4883, 0x00}, {0x4884, 0x09}, {0x4885, 0x80}, + {0x4886, 0x00}, {0x4888, 0x10}, {0x488b, 0x00}, {0x488c, 0x10}, + {0x4980, 0x03}, {0x4981, 0x06}, {0x4984, 0x00}, {0x4985, 0x00}, + {0x4a14, 0x04}, {0x4b01, 0x44}, {0x4b03, 0x80}, {0x4d06, 0xc8}, + {0x4d09, 0xdf}, {0x4d15, 0x7d}, {0x4d34, 0x7d}, {0x4d3c, 0x7d}, + {0x4f00, 0x7f}, {0x4f01, 0xff}, {0x4f03, 0x00}, {0x4f04, 0x18}, + {0x4f05, 0x13}, {0x5000, 0x6e}, {0x5001, 0x00}, {0x500a, 0x00}, + {0x5080, 0x00}, {0x5081, 0x00}, {0x5082, 0x00}, {0x5083, 0x00}, + {0x5100, 0x00}, {0x5103, 0x00}, {0x5180, 0x70}, {0x5181, 0x70}, + {0x5182, 0x73}, {0x5183, 0xff}, {0x5249, 0x06}, {0x524f, 0x06}, + {0x5281, 0x18}, {0x5282, 0x08}, {0x5283, 0x08}, {0x5284, 0x18}, + {0x5285, 0x18}, {0x5286, 0x08}, {0x5287, 0x08}, {0x5288, 0x18}, + {0x5289, 0x2d}, {0x6000, 0x40}, {0x6001, 0x40}, {0x6002, 0x00}, + {0x6003, 0x00}, {0x6004, 0x00}, {0x6005, 0x00}, {0x6006, 0x00}, + {0x6007, 0x00}, {0x6008, 0x00}, {0x6009, 0x00}, {0x600a, 0x00}, + {0x600b, 0x00}, {0x600c, 0x02}, {0x600d, 0x00}, {0x600e, 0x04}, + {0x600f, 0x00}, {0x6010, 0x06}, {0x6011, 0x00}, {0x6012, 0x00}, + {0x6013, 0x00}, {0x6014, 0x02}, {0x6015, 0x00}, {0x6016, 0x04}, + {0x6017, 0x00}, {0x6018, 0x06}, {0x6019, 0x00}, {0x601a, 0x01}, + {0x601b, 0x00}, {0x601c, 0x01}, {0x601d, 0x00}, {0x601e, 0x01}, + {0x601f, 0x00}, {0x6020, 0x01}, {0x6021, 0x00}, {0x6022, 0x01}, + {0x6023, 0x00}, {0x6024, 0x01}, {0x6025, 0x00}, {0x6026, 0x01}, + {0x6027, 0x00}, {0x6028, 0x01}, {0x6029, 0x00}, {0x3501, 0x08}, + {0x3502, 0x32}, {0x320a, 0x01}, {0x320b, 0x01}, {0x320c, 0x00}, + {0x320d, 0x00}, +}; + +struct ox05b { + struct device *dev; + struct clk *clk; + unsigned long clk_rate; + struct i2c_client *client; + struct regmap *regmap; + struct gpio_desc *pwdn_gpio; + struct v4l2_subdev subdev; + struct media_pad pad; + struct v4l2_mbus_framefmt format; + struct v4l2_ctrl_handler handler; + /* Added for RGB dominant stream */ + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *again; + struct v4l2_ctrl *dgain; + /* Added for IR dominant stream */ + struct v4l2_ctrl *ir_exposure; + struct v4l2_ctrl *ir_again; + struct v4l2_ctrl *ir_dgain; + u32 fps; + struct mutex lock; /* For streaming status */ + bool streaming; + struct v4l2_ctrl *link_freq; +}; + +static inline struct ox05b *to_ox05b(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ox05b, subdev); +} + +static int ox05b_read(struct ox05b *ox05b, u16 addr, u32 *val, size_t nbytes) +{ + int ret; + __le32 val_le = 0; + + ret = regmap_bulk_read(ox05b->regmap, addr, &val_le, nbytes); + if (ret < 0) { + dev_err(ox05b->dev, "%s: failed to read reg 0x%04x: %d\n", + __func__, addr, ret); + return ret; + } + + *val = le32_to_cpu(val_le); + return 0; +} + +static int ox05b_write(struct ox05b *ox05b, u16 addr, u32 val, size_t nbytes) +{ + int ret; + __le32 val_le = cpu_to_le32(val); + + ret = regmap_bulk_write(ox05b->regmap, addr, &val_le, nbytes); + if (ret < 0) { + dev_err(ox05b->dev, "%s: failed to write reg 0x%04x: %d\n", + __func__, addr, ret); + } + return ret; +} + +static int ox05b_write_table(struct ox05b *ox05b, + const struct reg_sequence *regs, + unsigned int nr_regs) +{ + int ret; + + ret = regmap_multi_reg_write(ox05b->regmap, regs, nr_regs); + if (ret < 0) { + dev_err(ox05b->dev, "%s: failed to write reg table (%d)!\n", + __func__, ret); + } + return ret; +} + +static void ox05b_init_formats(struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *format; + int i; + + for (i = 0; i < 2; ++i) { + format = v4l2_subdev_state_get_stream_format(state, 0, i); + format->code = ox05b_mbus_formats[0]; + format->width = ox05b_framesizes[0].width; + format->height = ox05b_framesizes[0].height; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + } +} + +static int ox05b_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct ox05b *ox05b = to_ox05b(sd); + struct v4l2_mbus_framefmt *format; + const struct v4l2_area *fsize; + u32 code; + int ret = 0; + + if (fmt->pad != 0) + return -EINVAL; + + if (fmt->stream != 0) + return -EINVAL; + + /* Sensor only supports a single format. */ + code = ox05b_mbus_formats[0]; + + /* Find the nearest supported frame size. */ + fsize = v4l2_find_nearest_size(ox05b_framesizes, + ARRAY_SIZE(ox05b_framesizes), width, + height, fmt->format.width, + fmt->format.height); + + v4l2_subdev_lock_state(state); + + format = v4l2_subdev_state_get_stream_format(state, fmt->pad, fmt->stream); + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && ox05b->streaming) { + ret = -EBUSY; + goto done; + } + + format->code = code; + format->width = fsize->width; + format->height = fsize->height; + + fmt->format = *format; + +done: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int _ox05b_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route routes[] = { + { + .source_pad = 0, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + { + .source_pad = 0, + .source_stream = 1, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + }; + + struct v4l2_subdev_krouting routing = { + .num_routes = ARRAY_SIZE(routes), + .routes = routes, + }; + + int ret; + + ret = v4l2_subdev_set_routing(sd, state, &routing); + if (ret < 0) + return ret; + + ox05b_init_formats(state); + + return 0; +} + +static int ox05b_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *fmt; + u32 bpp; + int ret = 0; + unsigned int i; + + if (pad != 0) + return -EINVAL; + state = v4l2_subdev_lock_and_get_active_state(sd); + fmt = v4l2_subdev_state_get_stream_format(state, 0, 0); + if (!fmt) { + ret = -EPIPE; + goto out; + } + memset(fd, 0, sizeof(*fd)); + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; + + /* pixel stream - 2 virtual channels*/ + + bpp = 10; + + for (i = 0; i < 2; ++i) { + fd->entry[fd->num_entries].stream = i; + + fd->entry[fd->num_entries].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->entry[fd->num_entries].length = fmt->width * fmt->height * bpp / 8; + fd->entry[fd->num_entries].pixelcode = fmt->code; + fd->entry[fd->num_entries].bus.csi2.vc = i; + fd->entry[fd->num_entries].bus.csi2.dt = 0x2b; /* RAW10 */ + + fd->num_entries++; + } + +out: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int ox05b_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + int ret; + + if (routing->num_routes == 0 || routing->num_routes > 2) + return -EINVAL; + + v4l2_subdev_lock_state(state); + + ret = _ox05b_set_routing(sd, state); + + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int ox05b_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + int ret; + + ret = _ox05b_set_routing(sd, state); + + return ret; +} + +static int ox05b_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(ox05b_mbus_formats)) + return -EINVAL; + + code->code = ox05b_mbus_formats[code->index]; + + return 0; +} + +static int ox05b_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ox05b_mbus_formats); ++i) { + if (ox05b_mbus_formats[i] == fse->code) + break; + } + + if (i == ARRAY_SIZE(ox05b_mbus_formats)) + return -EINVAL; + + if (fse->index >= ARRAY_SIZE(ox05b_framesizes)) + return -EINVAL; + + fse->min_width = ox05b_framesizes[fse->index].width; + fse->max_width = fse->min_width; + fse->max_height = ox05b_framesizes[fse->index].height; + fse->min_height = fse->max_height; + + return 0; +} + +static int ox05b_get_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct ox05b *ox05b = to_ox05b(sd); + + fi->interval.numerator = 1; + fi->interval.denominator = ox05b->fps; + return 0; +} + +static int ox05b_set_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct ox05b *ox05b = to_ox05b(sd); + + dev_dbg(ox05b->dev, "%s: Set framerate %dfps\n", __func__, + fi->interval.denominator / fi->interval.numerator); + if ((fi->interval.denominator / fi->interval.numerator) != ox05b->fps) { + dev_err(ox05b->dev, "%s: Framerate can only be %dfps\n", + __func__, ox05b->fps); + return -EINVAL; + } + return 0; +} + +static int ox05b_detect(struct ox05b *ox05b) +{ + int ret; + u32 id; + + ret = ox05b_read(ox05b, OX05B_SC_CHIP_ID_HI, &id, 2); + if (ret < 0) + return ret; + + if (id != OX05B_CHIP_ID) { + dev_err(ox05b->dev, + "%s: unknown chip ID 0x%04x\n", __func__, id); + return -ENODEV; + } + + dev_info(ox05b->dev, "%s: detected chip ID 0x%04x\n", __func__, id); + return 0; +} + +static int ox05b_set_groupA(struct ox05b *ox05b) +{ + int i, ret; + u32 exposure = ox05b->ir_exposure->val; + u32 again = ox05b->ir_again->val; + u32 dgain = ox05b->ir_dgain->val; + struct reg_sequence ox05b_groupA[] = { + {0x3208, 0x01}, /* Group 1 (IR Dominant VC0) hold start */ + {OX05B_AEC_PK_EXPO_HI, (exposure >> 8) & 0xff}, /* Exposure time Hi */ + {OX05B_AEC_PK_EXPO_LO, exposure & 0xff}, /* Exposure time Low */ + {OX05B_AEC_PK_AGAIN_HI, (again >> 4) & 0xff}, /* Analog gain Hi */ + {OX05B_AEC_PK_AGAIN_LO, (again & 0x0f) << 4}, /* Analog gain Low */ + {OX05B_AEC_PK_DGAIN_HI, (dgain >> 8) & 0xff}, /* Digital gain Hi */ + {OX05B_AEC_PK_DGAIN_LO, dgain & 0xff}, /* Digital gain Lo */ + {0x4813, 0x01}, /* VC=1. This register takes effect from next frame. */ + {0x3208, 0x11}, /* Group 1 (IR Dominant VC0) hold end*/ + }; + + for (i = 0; i < ARRAY_SIZE(ox05b_groupA); i++) { + ret = regmap_write(ox05b->regmap, ox05b_groupA[i].reg, ox05b_groupA[i].def); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n", + __func__, i, ox05b_groupA[i].reg, ox05b_groupA[i].def, ret); + return ret; + } + } + + return 0; +} + +static int ox05b_set_groupB(struct ox05b *ox05b) +{ + int i, ret; + u32 exposure = ox05b->exposure->val; + u32 again = ox05b->again->val; + u32 dgain = ox05b->dgain->val; + struct reg_sequence ox05b_groupB[] = { + {0x3208, 0x00}, /* Group 0 (RGB Dominant VC1) hold start */ + {OX05B_AEC_PK_EXPO_HI, (exposure >> 8) & 0xff}, /* Exposure time Hi */ + {OX05B_AEC_PK_EXPO_LO, exposure & 0xff}, /* Exposure time Low */ + {OX05B_AEC_PK_AGAIN_HI, (again >> 4) & 0xff}, /* Analog gain Hi */ + {OX05B_AEC_PK_AGAIN_LO, (again & 0x0f) << 4}, /* Analog gain Low */ + {OX05B_AEC_PK_DGAIN_HI, (dgain >> 8) & 0xff}, /* Digital gain Hi */ + {OX05B_AEC_PK_DGAIN_LO, dgain & 0xff}, /* Digital gain Lo */ + {0x4813, 0x00}, /* VC=0. This register takes effect from next frame. */ + {0x3208, 0x10}, /* Group 0 (RGB Dominant VC1) hold end*/ + }; + + for (i = 0; i < ARRAY_SIZE(ox05b_groupB); i++) { + ret = regmap_write(ox05b->regmap, ox05b_groupB[i].reg, ox05b_groupB[i].def); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n", + __func__, i, ox05b_groupB[i].reg, ox05b_groupB[i].def, ret); + return ret; + } + } + + return 0; +} + +static int ox05b_set_AB_mode_regs(struct ox05b *ox05b) +{ + int i, ret; + struct reg_sequence ox5b_AB_mode_regs[] = { + {0x3211, 0xF1}, /* AB mode enable */ + {0x3212, 0x21}, /* Enable sync between holds of group 0 and group 1*/ + {0x3208, 0xA0}, /* Always use for repeat launch */ + }; + + for (i = 0; i < ARRAY_SIZE(ox5b_AB_mode_regs); i++) { + ret = regmap_write(ox05b->regmap, ox5b_AB_mode_regs[i].reg, + ox5b_AB_mode_regs[i].def); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n", + __func__, i, ox5b_AB_mode_regs[i].reg, + ox5b_AB_mode_regs[i].def, ret); + return ret; + } + } + + return 0; +} + +static int ox05b_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ox05b *ox05b = container_of(ctrl->handler, struct ox05b, handler); + int ret; + + dev_dbg(ox05b->dev, "%s: %s, value: %d\n", __func__, + ctrl->name, ctrl->val); + + /* + * If the device is not powered up by the host driver do + * not apply any controls to H/W at this time. Instead + * the controls will be restored right after power-up. + */ + if (pm_runtime_suspended(ox05b->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + case V4L2_CID_ANALOGUE_GAIN: + case V4L2_CID_DIGITAL_GAIN: + ret = ox05b_set_groupB(ox05b); + break; + case V4L2_CID_IR_EXPOSURE: + case V4L2_CID_IR_ANALOGUE_GAIN: + case V4L2_CID_IR_DIGITAL_GAIN: + ret = ox05b_set_groupA(ox05b); + break; + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int ox05b_power_on(struct ox05b *ox05b) +{ + int ret; + + ret = clk_prepare_enable(ox05b->clk); + if (ret < 0) + return ret; + + if (ox05b->pwdn_gpio) { + gpiod_set_value_cansleep(ox05b->pwdn_gpio, 1); + usleep_range(100, 1000); + gpiod_set_value_cansleep(ox05b->pwdn_gpio, 0); + msleep(30); + } + return 0; +} + +static int ox05b_power_off(struct ox05b *ox05b) +{ + if (ox05b->pwdn_gpio) { + gpiod_set_value_cansleep(ox05b->pwdn_gpio, 1); + usleep_range(1, 10); + } + + clk_disable_unprepare(ox05b->clk); + + return 0; +} + +static int ox05b_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ox05b *ox05b = to_ox05b(sd); + + return ox05b_power_on(ox05b); +} + +static int ox05b_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ox05b *ox05b = to_ox05b(sd); + + return ox05b_power_off(ox05b); +} + +static int ox05b_start_stream(struct ox05b *ox05b) +{ + int ret; + + ret = ox05b_write_table(ox05b, ox05b_linear_2592x1944, + ARRAY_SIZE(ox05b_linear_2592x1944)); + if (ret < 0) + return ret; + + msleep(20); + + /* set registers for IR frame */ + ret = ox05b_set_groupA(ox05b); + if (ret < 0) + return ret; + + /* set registers for RGB frame */ + ret = ox05b_set_groupB(ox05b); + if (ret < 0) + return ret; + + /* set registers specific to AB mode */ + ret = ox05b_set_AB_mode_regs(ox05b); + + /* Set active */ + ret = ox05b_write(ox05b, OX05B_SYS_MODE_SEL, 0x01, 1); + if (ret < 0) + return ret; + + /* No communication is possible for a while after exiting standby. + * we want the sensor to have sufficient time to process + * the new configurations. The same type of delays have been programmed + * in the OV2312 driver. + * TODO: check if there is a status register to poll for sensor readiness. + */ + msleep(20); + + return 0; +} + +static int ox05b_stop_stream(struct ox05b *ox05b) +{ + int ret; + + /* Set standby */ + ret = ox05b_write(ox05b, OX05B_SYS_MODE_SEL, 0, 1); + if (ret < 0) + return ret; + + /* No communication is possible for a while after entering standby */ + usleep_range(10000, 20000); + return 0; +} + +static int ox05b_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ox05b *ox05b = to_ox05b(sd); + int ret; + + mutex_lock(&ox05b->lock); + if (ox05b->streaming == enable) { + mutex_unlock(&ox05b->lock); + return 0; + } + + if (enable) { + ret = pm_runtime_resume_and_get(ox05b->dev); + if (ret < 0) + goto err_unlock; + + ret = ox05b_start_stream(ox05b); + if (ret < 0) + goto err_runtime_put; + + } else { + ret = ox05b_stop_stream(ox05b); + if (ret < 0) + goto err_runtime_put; + pm_runtime_put(ox05b->dev); + } + + ox05b->streaming = enable; + + mutex_unlock(&ox05b->lock); + return 0; + +err_runtime_put: + pm_runtime_put(ox05b->dev); + +err_unlock: + mutex_unlock(&ox05b->lock); + dev_err(ox05b->dev, + "%s: failed to setup streaming %d\n", __func__, ret); + return ret; +} + +static const struct v4l2_subdev_video_ops ox05b_subdev_video_ops = { + .g_frame_interval = ox05b_get_frame_interval, + .s_frame_interval = ox05b_set_frame_interval, + .s_stream = ox05b_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ox05b_subdev_pad_ops = { + .init_cfg = ox05b_init_cfg, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ox05b_set_fmt, + .enum_mbus_code = ox05b_enum_mbus_code, + .enum_frame_size = ox05b_enum_frame_sizes, + .set_routing = ox05b_set_routing, + .get_frame_desc = ox05b_get_frame_desc, +}; + +static const struct v4l2_subdev_ops ox05b_subdev_ops = { + .video = &ox05b_subdev_video_ops, + .pad = &ox05b_subdev_pad_ops, +}; + +static const struct v4l2_ctrl_ops ox05b_ctrl_ops = { + .s_ctrl = ox05b_set_ctrl, +}; + +static const struct dev_pm_ops ox05b_pm_ops = { + SET_RUNTIME_PM_OPS(ox05b_suspend, ox05b_resume, NULL) +}; + +static int ox05b_probe(struct i2c_client *client) +{ + struct ox05b *ox05b; + struct v4l2_subdev *sd; + struct v4l2_ctrl_handler *ctrl_hdr; + int ret; + /* Allocate internal struct */ + ox05b = devm_kzalloc(&client->dev, sizeof(*ox05b), GFP_KERNEL); + if (!ox05b) + return -ENOMEM; + ox05b->dev = &client->dev; + + /* Initialize I2C Regmap */ + ox05b->regmap = devm_regmap_init_i2c(client, &ox05b_regmap_config); + if (IS_ERR(ox05b->regmap)) + return PTR_ERR(ox05b->regmap); + + /* Initialize Powerdown GPIO */ + ox05b->pwdn_gpio = devm_gpiod_get_optional(ox05b->dev, "pwdn", GPIOD_OUT_LOW); + if (IS_ERR(ox05b->pwdn_gpio)) + return PTR_ERR(ox05b->pwdn_gpio); + + ox05b->clk = devm_clk_get(ox05b->dev, "inck"); + if (IS_ERR(ox05b->clk)) + return PTR_ERR(ox05b->clk); + + ox05b->clk_rate = clk_get_rate(ox05b->clk); + + if (ox05b->clk_rate < 6000000 || ox05b->clk_rate > 27000000) + return -EINVAL; + + /* Power on */ + ret = ox05b_power_on(ox05b); + if (ret < 0) + return ret; + + /* Detect sensor */ + ret = ox05b_detect(ox05b); + if (ret < 0) + return ret; + + /* Initialize the subdev and its controls. */ + sd = &ox05b->subdev; + v4l2_i2c_subdev_init(sd, client, &ox05b_subdev_ops); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS | + V4L2_SUBDEV_FL_STREAMS; + + /* Initialize the media entity. */ + ox05b->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &ox05b->pad); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: media entity init failed %d\n", __func__, ret); + return ret; + } + + ox05b->fps = OX05B_FRAMERATE_DEFAULT; + mutex_init(&ox05b->lock); + /* Initialize controls */ + ctrl_hdr = &ox05b->handler; + ret = v4l2_ctrl_handler_init(ctrl_hdr, 7); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: ctrl handler init failed: %d\n", __func__, ret); + goto err_media_cleanup; + } + + ox05b->handler.lock = &ox05b->lock; + + /* Add new controls */ + ox05b->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(ox05b_link_freq_menu) - 1, 0, + ox05b_link_freq_menu); + if (ox05b->link_freq) + ox05b->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ox05b->exposure = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_EXPOSURE, 0, + OX05B_EXPOSURE_MAX, + 1, OX05B_EXPOSURE_DEFAULT); + + ox05b->again = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 0, + OX05B_AGAIN_MAX, 1, + OX05B_AGAIN_DEFAULT); + ox05b->dgain = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_DIGITAL_GAIN, 0, + OX05B_DGAIN_MAX, 1, + OX05B_DGAIN_DEFAULT); + + /* Added new control for IR frames. */ + ox05b->ir_exposure = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_IR_EXPOSURE, 0, + OX05B_EXPOSURE_MAX, + 1, OX05B_EXPOSURE_DEFAULT); + + ox05b->ir_again = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_IR_ANALOGUE_GAIN, 0, + OX05B_AGAIN_MAX, 1, + OX05B_AGAIN_DEFAULT); + + ox05b->ir_dgain = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_IR_DIGITAL_GAIN, 0, + OX05B_DGAIN_MAX, 1, + OX05B_DGAIN_DEFAULT); + + ox05b->subdev.ctrl_handler = ctrl_hdr; + if (ox05b->handler.error) { + ret = ox05b->handler.error; + dev_err(ox05b->dev, + "%s: failed to add the ctrls: %d\n", __func__, ret); + goto err_ctrl_free; + } + + /* PM Runtime */ + pm_runtime_enable(ox05b->dev); + pm_runtime_set_suspended(ox05b->dev); + + ret = v4l2_subdev_init_finalize(sd); + if (ret < 0) { + dev_err(ox05b->dev, "%s: failed to init subdev: %d\n", __func__, ret); + goto err_pm_disable; + } + + /* Finally, register the subdev. */ + ret = v4l2_async_register_subdev(sd); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: v4l2 subdev register failed %d\n", __func__, ret); + goto err_subdev_cleanup; + } + + dev_info(ox05b->dev, "ox05b1s probed!\n"); + return 0; + +err_subdev_cleanup: + v4l2_subdev_cleanup(&ox05b->subdev); + +err_pm_disable: + pm_runtime_disable(ox05b->dev); + +err_ctrl_free: + v4l2_ctrl_handler_free(ctrl_hdr); + mutex_destroy(&ox05b->lock); + +err_media_cleanup: + media_entity_cleanup(&ox05b->subdev.entity); + + return ret; +} + +static void ox05b_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ox05b *ox05b = to_ox05b(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_ctrl_handler_free(&ox05b->handler); + v4l2_subdev_cleanup(&ox05b->subdev); + media_entity_cleanup(&sd->entity); + mutex_destroy(&ox05b->lock); + + pm_runtime_disable(ox05b->dev); +} + +static const struct of_device_id ox05b_of_match[] = { + { .compatible = "ovti,ox05b" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, ox05b_of_match); + +static struct i2c_driver ox05b_i2c_driver = { + .driver = { + .name = "ox05b", + .of_match_table = ox05b_of_match, + .pm = &ox05b_pm_ops, + }, + .probe = ox05b_probe, + .remove = ox05b_remove, +}; + +module_i2c_driver(ox05b_i2c_driver); + +MODULE_AUTHOR("Abhishek Sharma "); +MODULE_DESCRIPTION("OX05B1S RGB-IR Image Sensor driver"); +MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c --- a/drivers/media/platform/cadence/cdns-csi2rx.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/cadence/cdns-csi2rx.c 2024-07-07 20:37:34.648306569 -0400 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -40,10 +41,14 @@ #define CSI2RX_STREAM_BASE(n) (((n) + 1) * 0x100) #define CSI2RX_STREAM_CTRL_REG(n) (CSI2RX_STREAM_BASE(n) + 0x000) +#define CSI2RX_STREAM_CTRL_SOFT_RST BIT(4) +#define CSI2RX_STREAM_CTRL_STOP BIT(1) #define CSI2RX_STREAM_CTRL_START BIT(0) +#define CSI2RX_STREAM_STATUS_REG(n) (CSI2RX_STREAM_BASE(n) + 0x004) +#define CSI2RX_STREAM_STATUS_RDY BIT(31) + #define CSI2RX_STREAM_DATA_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x008) -#define CSI2RX_STREAM_DATA_CFG_EN_VC_SELECT BIT(31) #define CSI2RX_STREAM_DATA_CFG_VC_SELECT(n) BIT((n) + 16) #define CSI2RX_STREAM_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x00c) @@ -61,6 +66,11 @@ CSI2RX_PAD_MAX, }; +struct csi2rx_fmt { + u32 code; + u8 bpp; +}; + struct csi2rx_priv { struct device *dev; unsigned int count; @@ -80,6 +90,7 @@ struct reset_control *pixel_rst[CSI2RX_STREAMS_MAX]; struct phy *dphy; + u32 vc_select[CSI2RX_STREAMS_MAX]; u8 lanes[CSI2RX_LANES_MAX]; u8 num_lanes; u8 max_lanes; @@ -95,6 +106,63 @@ int source_pad; }; +static const struct csi2rx_fmt formats[] = { + { .code = MEDIA_BUS_FMT_YUYV8_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_YVYU8_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_VYUY8_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_Y8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SRGGI10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SGRIG10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SBGGI10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SGBIG10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SGIRG10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SIGGR10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SGIBG10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SIGGB10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SBGGR12_1X12, .bpp = 12, }, + { .code = MEDIA_BUS_FMT_SGBRG12_1X12, .bpp = 12, }, + { .code = MEDIA_BUS_FMT_SGRBG12_1X12, .bpp = 12, }, + { .code = MEDIA_BUS_FMT_SRGGB12_1X12, .bpp = 12, }, + { .code = MEDIA_BUS_FMT_RGB565_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 24, }, + { .code = MEDIA_BUS_FMT_BGR888_1X24, .bpp = 24, }, +}; + +static const struct csi2rx_fmt *csi2rx_get_fmt_by_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); i++) + if (formats[i].code == code) + return &formats[i]; + + return NULL; +} + +static int csi2rx_get_frame_desc_from_source(struct csi2rx_priv *csi2rx, + struct v4l2_mbus_frame_desc *fd) +{ + struct media_pad *remote_pad; + + remote_pad = media_entity_remote_source_pad_unique(&csi2rx->subdev.entity); + if (!remote_pad) { + dev_err(csi2rx->dev, "No remote pad found for sink\n"); + return -ENODEV; + } + + return v4l2_subdev_call(csi2rx->source_subdev, pad, get_frame_desc, + remote_pad->index, fd); +} + static inline struct csi2rx_priv *v4l2_subdev_to_csi2rx(struct v4l2_subdev *subdev) { @@ -103,19 +171,70 @@ static void csi2rx_reset(struct csi2rx_priv *csi2rx) { + unsigned int i; + + /* Reset module */ writel(CSI2RX_SOFT_RESET_PROTOCOL | CSI2RX_SOFT_RESET_FRONT, csi2rx->base + CSI2RX_SOFT_RESET_REG); + /* Reset individual streams. */ + for (i = 0; i < csi2rx->max_streams; i++) { + writel(CSI2RX_STREAM_CTRL_SOFT_RST, + csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); + } - udelay(10); + usleep_range(10, 20); + /* Clear resets */ writel(0, csi2rx->base + CSI2RX_SOFT_RESET_REG); + for (i = 0; i < csi2rx->max_streams; i++) + writel(0, csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); } static int csi2rx_configure_ext_dphy(struct csi2rx_priv *csi2rx) { + struct v4l2_ctrl_handler *handler = csi2rx->source_subdev->ctrl_handler; union phy_configure_opts opts = { }; + struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy; + struct v4l2_mbus_framefmt *framefmt; + struct v4l2_subdev_state *state; + const struct csi2rx_fmt *fmt; + s64 link_freq; int ret; + if (v4l2_ctrl_find(handler, V4L2_CID_LINK_FREQ)) { + link_freq = v4l2_get_link_freq(handler, 0, 0); + } else { + state = v4l2_subdev_get_locked_active_state(&csi2rx->subdev); + framefmt = v4l2_subdev_state_get_stream_format(state, + CSI2RX_PAD_SINK, + 0); + if (framefmt) { + fmt = csi2rx_get_fmt_by_code(framefmt->code); + } else { + dev_err(csi2rx->dev, + "Did not find active sink format\n"); + return -EINVAL; + } + + link_freq = v4l2_get_link_freq(handler, fmt->bpp, + 2 * csi2rx->num_lanes); + + dev_warn(csi2rx->dev, + "Guessing link frequency using bitdepth of stream 0.\n"); + dev_warn(csi2rx->dev, + "V4L2_CID_LINK_FREQ control is required for multi format sources.\n"); + } + + if (link_freq < 0) { + dev_err(csi2rx->dev, "Unable to calculate link frequency\n"); + return link_freq; + } + + ret = phy_mipi_dphy_get_default_config_for_hsclk(link_freq, + csi2rx->num_lanes, cfg); + if (ret) + return ret; + ret = phy_power_on(csi2rx->dphy); if (ret) return ret; @@ -164,10 +283,6 @@ writel(reg, csi2rx->base + CSI2RX_STATIC_CFG_REG); - ret = v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, true); - if (ret) - goto err_disable_pclk; - /* Enable DPHY clk and data lanes. */ if (csi2rx->dphy) { reg = CSI2RX_DPHY_CL_EN | CSI2RX_DPHY_CL_RST; @@ -177,6 +292,13 @@ } writel(reg, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG); + + ret = csi2rx_configure_ext_dphy(csi2rx); + if (ret) { + dev_err(csi2rx->dev, + "Failed to configure external DPHY: %d\n", ret); + goto err_disable_pclk; + } } /* @@ -199,8 +321,7 @@ writel(CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF, csi2rx->base + CSI2RX_STREAM_CFG_REG(i)); - writel(CSI2RX_STREAM_DATA_CFG_EN_VC_SELECT | - CSI2RX_STREAM_DATA_CFG_VC_SELECT(i), + writel(csi2rx->vc_select[i], csi2rx->base + CSI2RX_STREAM_DATA_CFG_REG(i)); writel(CSI2RX_STREAM_CTRL_START, @@ -213,27 +334,20 @@ reset_control_deassert(csi2rx->sys_rst); - if (csi2rx->dphy) { - ret = csi2rx_configure_ext_dphy(csi2rx); - if (ret) { - dev_err(csi2rx->dev, - "Failed to configure external DPHY: %d\n", ret); - goto err_disable_sysclk; - } - } - clk_disable_unprepare(csi2rx->p_clk); return 0; -err_disable_sysclk: - clk_disable_unprepare(csi2rx->sys_clk); err_disable_pixclk: for (; i > 0; i--) { reset_control_assert(csi2rx->pixel_rst[i - 1]); clk_disable_unprepare(csi2rx->pixel_clk[i - 1]); } + if (csi2rx->dphy) { + writel(0, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG); + phy_power_off(csi2rx->dphy); + } err_disable_pclk: clk_disable_unprepare(csi2rx->p_clk); @@ -243,13 +357,25 @@ static void csi2rx_stop(struct csi2rx_priv *csi2rx) { unsigned int i; + u32 val; + int ret; clk_prepare_enable(csi2rx->p_clk); reset_control_assert(csi2rx->sys_rst); clk_disable_unprepare(csi2rx->sys_clk); for (i = 0; i < csi2rx->max_streams; i++) { - writel(0, csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); + writel(CSI2RX_STREAM_CTRL_STOP, + csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); + + ret = readl_relaxed_poll_timeout(csi2rx->base + + CSI2RX_STREAM_STATUS_REG(i), + val, + !(val & CSI2RX_STREAM_STATUS_RDY), + 10, 10000); + if (ret) + dev_warn(csi2rx->dev, + "Failed to stop streaming on pad%u\n", i); reset_control_assert(csi2rx->pixel_rst[i]); clk_disable_unprepare(csi2rx->pixel_clk[i]); @@ -258,9 +384,6 @@ reset_control_assert(csi2rx->p_rst); clk_disable_unprepare(csi2rx->p_clk); - if (v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, false)) - dev_warn(csi2rx->dev, "Couldn't disable our subdev\n"); - if (csi2rx->dphy) { writel(0, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG); @@ -269,46 +392,354 @@ } } -static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable) +static void csi2rx_update_vc_select(struct csi2rx_priv *csi2rx, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_frame_desc fd = {0}; + struct v4l2_subdev_route *route; + unsigned int i; + int ret; + + for (i = 0; i < CSI2RX_STREAMS_MAX; i++) + csi2rx->vc_select[i] = 0; + + ret = csi2rx_get_frame_desc_from_source(csi2rx, &fd); + if (ret || fd.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { + dev_dbg(csi2rx->dev, + "Failed to get source frame desc, allowing only VC=0\n"); + goto err_no_fd; + } + + /* If source provides per-stream VC info, use it to filter by VC */ + for_each_active_route(&state->routing, route) { + int cdns_stream = route->source_pad - CSI2RX_PAD_SOURCE_STREAM0; + u8 used_vc = 0; + + for (i = 0; i < fd.num_entries; i++) { + if (fd.entry[i].stream == route->sink_stream) { + used_vc = fd.entry[i].bus.csi2.vc; + break; + } + } + csi2rx->vc_select[cdns_stream] |= + CSI2RX_STREAM_DATA_CFG_VC_SELECT(used_vc); + } + +err_no_fd: + for (i = 0; i < CSI2RX_STREAMS_MAX; i++) { + if (!csi2rx->vc_select[i]) { + csi2rx->vc_select[i] = + CSI2RX_STREAM_DATA_CFG_VC_SELECT(0); + } + } +} + +static int csi2rx_enable_streams(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); - int ret = 0; + struct media_pad *remote_pad; + u64 sink_streams; + int ret; + + remote_pad = media_pad_remote_pad_first(&csi2rx->pads[CSI2RX_PAD_SINK]); + if (!remote_pad) { + dev_err(csi2rx->dev, + "Failed to find connected source\n"); + return -ENODEV; + } + + ret = pm_runtime_resume_and_get(csi2rx->dev); + if (ret < 0) + return ret; + + sink_streams = v4l2_subdev_state_xlate_streams(state, pad, + CSI2RX_PAD_SINK, + &streams_mask); mutex_lock(&csi2rx->lock); + /* + * If we're not the first users, there's no need to + * enable the whole controller. + */ + if (!csi2rx->count) { + ret = csi2rx_start(csi2rx); + if (ret) + goto err_stream_start; + } - if (enable) { - /* - * If we're not the first users, there's no need to - * enable the whole controller. - */ - if (!csi2rx->count) { - ret = csi2rx_start(csi2rx); - if (ret) - goto out; - } + /* Start streaming on the source */ + ret = v4l2_subdev_enable_streams(csi2rx->source_subdev, remote_pad->index, + sink_streams); + if (ret) { + dev_err(csi2rx->dev, + "Failed to start streams %#llx on subdev\n", + sink_streams); + goto err_subdev_enable; + } - csi2rx->count++; - } else { - csi2rx->count--; + csi2rx->count++; + mutex_unlock(&csi2rx->lock); - /* - * Let the last user turn off the lights. - */ - if (!csi2rx->count) - csi2rx_stop(csi2rx); + return 0; + +err_subdev_enable: + if (!csi2rx->count) + csi2rx_stop(csi2rx); +err_stream_start: + mutex_unlock(&csi2rx->lock); + pm_runtime_put(csi2rx->dev); + return ret; +} + +static int csi2rx_disable_streams(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); + struct media_pad *remote_pad; + u64 sink_streams; + + sink_streams = v4l2_subdev_state_xlate_streams(state, pad, + CSI2RX_PAD_SINK, + &streams_mask); + + remote_pad = media_pad_remote_pad_first(&csi2rx->pads[CSI2RX_PAD_SINK]); + if (!remote_pad || + v4l2_subdev_disable_streams(csi2rx->source_subdev, + remote_pad->index, sink_streams)) { + dev_err(csi2rx->dev, "Couldn't disable our subdev\n"); } -out: + mutex_lock(&csi2rx->lock); + csi2rx->count--; + /* + * Let the last user turn off the lights. + */ + if (!csi2rx->count) + csi2rx_stop(csi2rx); mutex_unlock(&csi2rx->lock); + + pm_runtime_put(csi2rx->dev); + + return 0; +} + +static int csi2rx_s_stream_fallback(struct v4l2_subdev *sd, int enable) +{ + struct v4l2_subdev_state *state; + struct v4l2_subdev_route *route; + u64 mask[CSI2RX_PAD_MAX] = {0}; + int i, ret; + + /* Find the stream mask on all source pads */ + state = v4l2_subdev_lock_and_get_active_state(sd); + for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) { + for_each_active_route(&state->routing, route) { + if (route->source_pad == i) + mask[i] |= BIT_ULL(route->source_stream); + } + } + v4l2_subdev_unlock_state(state); + + /* Start streaming on each pad */ + for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) { + if (enable) + ret = v4l2_subdev_enable_streams(sd, i, mask[i]); + else + ret = v4l2_subdev_disable_streams(sd, i, mask[i]); + if (ret) + return ret; + } + + return ret; +} + +static int _csi2rx_set_routing(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_krouting *routing) +{ + static const struct v4l2_mbus_framefmt format = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, + }; + int ret; + + if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX) + return -EINVAL; + + ret = v4l2_subdev_routing_validate(subdev, routing, + V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); + if (ret) + return ret; + + ret = v4l2_subdev_set_routing_with_fmt(subdev, state, routing, &format); + if (ret) + return ret; + + return 0; +} + +static int csi2rx_set_routing(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); + int ret; + + if (which == V4L2_SUBDEV_FORMAT_ACTIVE && csi2rx->count) + return -EBUSY; + + ret = _csi2rx_set_routing(subdev, state, routing); + + if (ret) + return ret; + + csi2rx_update_vc_select(csi2rx, state); + + return 0; +} + +static int csi2rx_set_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt; + + /* No transcoding, source and sink formats must match. */ + if (format->pad != CSI2RX_PAD_SINK) + return v4l2_subdev_get_fmt(subdev, state, format); + + if (!csi2rx_get_fmt_by_code(format->format.code)) + format->format.code = formats[0].code; + + format->format.field = V4L2_FIELD_NONE; + + /* Set sink format */ + fmt = v4l2_subdev_state_get_stream_format(state, format->pad, + format->stream); + if (!fmt) + return -EINVAL; + + *fmt = format->format; + + /* Propagate to source format */ + fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad, + format->stream); + if (!fmt) + return -EINVAL; + + *fmt = format->format; + + return 0; +} + +static int csi2rx_init_cfg(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route routes[] = { + { + .sink_pad = CSI2RX_PAD_SINK, + .sink_stream = 0, + .source_pad = CSI2RX_PAD_SOURCE_STREAM0, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + }; + + struct v4l2_subdev_krouting routing = { + .num_routes = ARRAY_SIZE(routes), + .routes = routes, + }; + + return _csi2rx_set_routing(subdev, state, &routing); +} + +static int csi2rx_get_frame_desc(struct v4l2_subdev *subdev, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); + struct v4l2_mbus_frame_desc source_fd = {0}; + struct v4l2_subdev_route *route; + struct v4l2_subdev_state *state; + int ret; + + ret = csi2rx_get_frame_desc_from_source(csi2rx, &source_fd); + if (ret) + return ret; + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; + + state = v4l2_subdev_lock_and_get_active_state(subdev); + + for_each_active_route(&state->routing, route) { + struct v4l2_mbus_frame_desc_entry *source_entry = NULL; + unsigned int i; + + if (route->source_pad != pad) + continue; + + for (i = 0; i < source_fd.num_entries; i++) { + if (source_fd.entry[i].stream == route->sink_stream) { + source_entry = &source_fd.entry[i]; + break; + } + } + + if (!source_entry) { + dev_err(csi2rx->dev, + "Failed to find stream from source frame desc\n"); + ret = -EPIPE; + goto err_missing_stream; + } + + fd->entry[fd->num_entries].stream = route->source_stream; + fd->entry[fd->num_entries].flags = source_entry->flags; + fd->entry[fd->num_entries].length = source_entry->length; + fd->entry[fd->num_entries].pixelcode = source_entry->pixelcode; + fd->entry[fd->num_entries].bus.csi2.vc = + source_entry->bus.csi2.vc; + fd->entry[fd->num_entries].bus.csi2.dt = + source_entry->bus.csi2.dt; + + fd->num_entries++; + } + +err_missing_stream: + v4l2_subdev_unlock_state(state); + return ret; } +static const struct v4l2_subdev_pad_ops csi2rx_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = csi2rx_set_fmt, + .init_cfg = csi2rx_init_cfg, + .get_frame_desc = csi2rx_get_frame_desc, + .set_routing = csi2rx_set_routing, + .enable_streams = csi2rx_enable_streams, + .disable_streams = csi2rx_disable_streams, +}; + static const struct v4l2_subdev_video_ops csi2rx_video_ops = { - .s_stream = csi2rx_s_stream, + .s_stream = csi2rx_s_stream_fallback, }; static const struct v4l2_subdev_ops csi2rx_subdev_ops = { .video = &csi2rx_video_ops, + .pad = &csi2rx_pad_ops, +}; + +static const struct media_entity_operations csi2rx_media_ops = { + .link_validate = v4l2_subdev_link_validate, }; static int csi2rx_async_bound(struct v4l2_async_notifier *notifier, @@ -493,6 +924,29 @@ return ret; } +static int csi2rx_suspend(struct device *dev) +{ + struct csi2rx_priv *csi2rx = dev_get_drvdata(dev); + + mutex_lock(&csi2rx->lock); + if (csi2rx->count) + csi2rx_stop(csi2rx); + mutex_unlock(&csi2rx->lock); + + return 0; +} + +static int csi2rx_resume(struct device *dev) +{ + struct csi2rx_priv *csi2rx = dev_get_drvdata(dev); + + mutex_lock(&csi2rx->lock); + if (csi2rx->count) + csi2rx_start(csi2rx); + mutex_unlock(&csi2rx->lock); + return 0; +} + static int csi2rx_probe(struct platform_device *pdev) { struct csi2rx_priv *csi2rx; @@ -526,15 +980,23 @@ csi2rx->pads[CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) csi2rx->pads[i].flags = MEDIA_PAD_FL_SOURCE; + csi2rx->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_STREAMS; + csi2rx->subdev.entity.ops = &csi2rx_media_ops; ret = media_entity_pads_init(&csi2rx->subdev.entity, CSI2RX_PAD_MAX, csi2rx->pads); if (ret) goto err_cleanup; + ret = v4l2_subdev_init_finalize(&csi2rx->subdev); + if (ret) + goto err_cleanup; + + pm_runtime_enable(csi2rx->dev); ret = v4l2_async_register_subdev(&csi2rx->subdev); if (ret < 0) - goto err_cleanup; + goto err_free_state; dev_info(&pdev->dev, "Probed CSI2RX with %u/%u lanes, %u streams, %s D-PHY\n", @@ -544,9 +1006,13 @@ return 0; +err_free_state: + v4l2_subdev_cleanup(&csi2rx->subdev); + pm_runtime_disable(csi2rx->dev); err_cleanup: v4l2_async_nf_unregister(&csi2rx->notifier); v4l2_async_nf_cleanup(&csi2rx->notifier); + media_entity_cleanup(&csi2rx->subdev.entity); err_free_priv: kfree(csi2rx); return ret; @@ -559,9 +1025,16 @@ v4l2_async_nf_unregister(&csi2rx->notifier); v4l2_async_nf_cleanup(&csi2rx->notifier); v4l2_async_unregister_subdev(&csi2rx->subdev); + v4l2_subdev_cleanup(&csi2rx->subdev); + media_entity_cleanup(&csi2rx->subdev.entity); + pm_runtime_disable(csi2rx->dev); kfree(csi2rx); } +static const struct dev_pm_ops csi2rx_pm_ops = { + SET_RUNTIME_PM_OPS(csi2rx_suspend, csi2rx_resume, NULL) +}; + static const struct of_device_id csi2rx_of_table[] = { { .compatible = "starfive,jh7110-csi2rx" }, { .compatible = "cdns,csi2rx" }, @@ -576,6 +1049,7 @@ .driver = { .name = "cdns-csi2rx", .of_match_table = csi2rx_of_table, + .pm = &csi2rx_pm_ops, }, }; module_platform_driver(csi2rx_driver); diff -Naur --no-dereference a/drivers/media/platform/cadence/Kconfig b/drivers/media/platform/cadence/Kconfig --- a/drivers/media/platform/cadence/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/cadence/Kconfig 2024-07-07 20:37:34.648306569 -0400 @@ -8,6 +8,7 @@ select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE + select GENERIC_PHY_MIPI_DPHY help Support for the Cadence MIPI CSI2 Receiver controller. diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/coda-bit.c b/drivers/media/platform/chips-media/coda/coda-bit.c --- a/drivers/media/platform/chips-media/coda/coda-bit.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/coda-bit.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,2666 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Coda multi-standard codec IP - BIT processor functions + * + * Copyright (C) 2012 Vista Silicon S.L. + * Javier Martin, + * Xavier Duret + * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "coda.h" +#include "imx-vdoa.h" +#define CREATE_TRACE_POINTS +#include "trace.h" + +#define CODA_PARA_BUF_SIZE (10 * 1024) +#define CODA7_PS_BUF_SIZE 0x28000 +#define CODA9_PS_SAVE_SIZE (512 * 1024) + +#define CODA_DEFAULT_GAMMA 4096 +#define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ + +static void coda_free_bitstream_buffer(struct coda_ctx *ctx); + +static inline int coda_is_initialized(struct coda_dev *dev) +{ + return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0; +} + +static inline unsigned long coda_isbusy(struct coda_dev *dev) +{ + return coda_read(dev, CODA_REG_BIT_BUSY); +} + +static int coda_wait_timeout(struct coda_dev *dev) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + while (coda_isbusy(dev)) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + } + return 0; +} + +static void coda_command_async(struct coda_ctx *ctx, int cmd) +{ + struct coda_dev *dev = ctx->dev; + + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541 || + dev->devtype->product == CODA_960) { + /* Restore context related registers to CODA */ + coda_write(dev, ctx->bit_stream_param, + CODA_REG_BIT_BIT_STREAM_PARAM); + coda_write(dev, ctx->frm_dis_flg, + CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + coda_write(dev, ctx->frame_mem_ctrl, + CODA_REG_BIT_FRAME_MEM_CTRL); + coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR); + } + + if (dev->devtype->product == CODA_960) { + coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); + coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); + } + + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + + coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX); + coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); + coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); + + trace_coda_bit_run(ctx, cmd); + + coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); +} + +static int coda_command_sync(struct coda_ctx *ctx, int cmd) +{ + struct coda_dev *dev = ctx->dev; + int ret; + + lockdep_assert_held(&dev->coda_mutex); + + coda_command_async(ctx, cmd); + ret = coda_wait_timeout(dev); + trace_coda_bit_done(ctx); + + return ret; +} + +int coda_hw_reset(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + unsigned long timeout; + unsigned int idx; + int ret; + + lockdep_assert_held(&dev->coda_mutex); + + if (!dev->rstc) + return -ENOENT; + + idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); + + if (dev->devtype->product == CODA_960) { + timeout = jiffies + msecs_to_jiffies(100); + coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); + while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { + if (time_after(jiffies, timeout)) + return -ETIME; + cpu_relax(); + } + } + + ret = reset_control_reset(dev->rstc); + if (ret < 0) + return ret; + + if (dev->devtype->product == CODA_960) + coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); + ret = coda_wait_timeout(dev); + coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX); + + return ret; +} + +static void coda_kfifo_sync_from_device(struct coda_ctx *ctx) +{ + struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; + struct coda_dev *dev = ctx->dev; + u32 rd_ptr; + + rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); + kfifo->out = (kfifo->in & ~kfifo->mask) | + (rd_ptr - ctx->bitstream.paddr); + if (kfifo->out > kfifo->in) + kfifo->out -= kfifo->mask + 1; +} + +static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx) +{ + struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; + struct coda_dev *dev = ctx->dev; + u32 rd_ptr, wr_ptr; + + rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask); + coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); + wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); + coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); +} + +static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) +{ + struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; + struct coda_dev *dev = ctx->dev; + u32 wr_ptr; + + wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); + coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); +} + +static int coda_h264_bitstream_pad(struct coda_ctx *ctx, u32 size) +{ + unsigned char *buf; + u32 n; + + if (size < 6) + size = 6; + + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + coda_h264_filler_nal(size, buf); + n = kfifo_in(&ctx->bitstream_fifo, buf, size); + kfree(buf); + + return (n < size) ? -ENOSPC : 0; +} + +int coda_bitstream_flush(struct coda_ctx *ctx) +{ + int ret; + + if (ctx->inst_type != CODA_INST_DECODER || !ctx->use_bit) + return 0; + + ret = coda_command_sync(ctx, CODA_COMMAND_DEC_BUF_FLUSH); + if (ret < 0) { + v4l2_err(&ctx->dev->v4l2_dev, "failed to flush bitstream\n"); + return ret; + } + + kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, + ctx->bitstream.size); + coda_kfifo_sync_to_device_full(ctx); + + return 0; +} + +static int coda_bitstream_queue(struct coda_ctx *ctx, const u8 *buf, u32 size) +{ + u32 n = kfifo_in(&ctx->bitstream_fifo, buf, size); + + return (n < size) ? -ENOSPC : 0; +} + +static u32 coda_buffer_parse_headers(struct coda_ctx *ctx, + struct vb2_v4l2_buffer *src_buf, + u32 payload) +{ + u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); + u32 size = 0; + + switch (ctx->codec->src_fourcc) { + case V4L2_PIX_FMT_MPEG2: + size = coda_mpeg2_parse_headers(ctx, vaddr, payload); + break; + case V4L2_PIX_FMT_MPEG4: + size = coda_mpeg4_parse_headers(ctx, vaddr, payload); + break; + default: + break; + } + + return size; +} + +static bool coda_bitstream_try_queue(struct coda_ctx *ctx, + struct vb2_v4l2_buffer *src_buf) +{ + unsigned long payload = vb2_get_plane_payload(&src_buf->vb2_buf, 0); + u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); + int ret; + int i; + + if (coda_get_bitstream_payload(ctx) + payload + 512 >= + ctx->bitstream.size) + return false; + + if (!vaddr) { + v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); + return true; + } + + if (ctx->qsequence == 0 && payload < 512) { + /* + * Add padding after the first buffer, if it is too small to be + * fetched by the CODA, by repeating the headers. Without + * repeated headers, or the first frame already queued, decoder + * sequence initialization fails with error code 0x2000 on i.MX6 + * or error code 0x1 on i.MX51. + */ + u32 header_size = coda_buffer_parse_headers(ctx, src_buf, + payload); + + if (header_size) { + coda_dbg(1, ctx, "pad with %u-byte header\n", + header_size); + for (i = payload; i < 512; i += header_size) { + ret = coda_bitstream_queue(ctx, vaddr, + header_size); + if (ret < 0) { + v4l2_err(&ctx->dev->v4l2_dev, + "bitstream buffer overflow\n"); + return false; + } + if (ctx->dev->devtype->product == CODA_960) + break; + } + } else { + coda_dbg(1, ctx, + "could not parse header, sequence initialization might fail\n"); + } + + /* Add padding before the first buffer, if it is too small */ + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) + coda_h264_bitstream_pad(ctx, 512 - payload); + } + + ret = coda_bitstream_queue(ctx, vaddr, payload); + if (ret < 0) { + v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); + return false; + } + + src_buf->sequence = ctx->qsequence++; + + /* Sync read pointer to device */ + if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) + coda_kfifo_sync_to_device_write(ctx); + + /* Set the stream-end flag after the last buffer is queued */ + if (src_buf->flags & V4L2_BUF_FLAG_LAST) + coda_bit_stream_end_flag(ctx); + ctx->hold = false; + + return true; +} + +void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) +{ + struct vb2_v4l2_buffer *src_buf; + struct coda_buffer_meta *meta; + u32 start; + + lockdep_assert_held(&ctx->bitstream_mutex); + + if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) + return; + + while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { + /* + * Only queue two JPEGs into the bitstream buffer to keep + * latency low. We need at least one complete buffer and the + * header of another buffer (for prescan) in the bitstream. + */ + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && + ctx->num_metas > 1) + break; + + if (ctx->num_internal_frames && + ctx->num_metas >= ctx->num_internal_frames) { + meta = list_first_entry(&ctx->buffer_meta_list, + struct coda_buffer_meta, list); + + /* + * If we managed to fill in at least a full reorder + * window of buffers (num_internal_frames is a + * conservative estimate for this) and the bitstream + * prefetcher has at least 2 256 bytes periods beyond + * the first buffer to fetch, we can safely stop queuing + * in order to limit the decoder drain latency. + */ + if (coda_bitstream_can_fetch_past(ctx, meta->end)) + break; + } + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + + /* Drop frames that do not start/end with a SOI/EOI markers */ + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && + !coda_jpeg_check_buffer(ctx, &src_buf->vb2_buf)) { + v4l2_err(&ctx->dev->v4l2_dev, + "dropping invalid JPEG frame %d\n", + ctx->qsequence); + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + if (buffer_list) { + struct v4l2_m2m_buffer *m2m_buf; + + m2m_buf = container_of(src_buf, + struct v4l2_m2m_buffer, + vb); + list_add_tail(&m2m_buf->list, buffer_list); + } else { + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + } + continue; + } + + /* Dump empty buffers */ + if (!vb2_get_plane_payload(&src_buf->vb2_buf, 0)) { + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + continue; + } + + /* Buffer start position */ + start = ctx->bitstream_fifo.kfifo.in; + + if (coda_bitstream_try_queue(ctx, src_buf)) { + /* + * Source buffer is queued in the bitstream ringbuffer; + * queue the timestamp and mark source buffer as done + */ + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + + meta = kmalloc(sizeof(*meta), GFP_KERNEL); + if (meta) { + meta->sequence = src_buf->sequence; + meta->timecode = src_buf->timecode; + meta->timestamp = src_buf->vb2_buf.timestamp; + meta->start = start; + meta->end = ctx->bitstream_fifo.kfifo.in; + meta->last = src_buf->flags & V4L2_BUF_FLAG_LAST; + if (meta->last) + coda_dbg(1, ctx, "marking last meta"); + spin_lock(&ctx->buffer_meta_lock); + list_add_tail(&meta->list, + &ctx->buffer_meta_list); + ctx->num_metas++; + spin_unlock(&ctx->buffer_meta_lock); + + trace_coda_bit_queue(ctx, src_buf, meta); + } + + if (buffer_list) { + struct v4l2_m2m_buffer *m2m_buf; + + m2m_buf = container_of(src_buf, + struct v4l2_m2m_buffer, + vb); + list_add_tail(&m2m_buf->list, buffer_list); + } else { + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } + } else { + break; + } + } +} + +void coda_bit_stream_end_flag(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + + /* If this context is currently running, update the hardware flag */ + if ((dev->devtype->product == CODA_960) && + coda_isbusy(dev) && + (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { + coda_write(dev, ctx->bit_stream_param, + CODA_REG_BIT_BIT_STREAM_PARAM); + } +} + +static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) +{ + struct coda_dev *dev = ctx->dev; + u32 *p = ctx->parabuf.vaddr; + + if (dev->devtype->product == CODA_DX6) + p[index] = value; + else + p[index ^ 1] = value; +} + +static inline int coda_alloc_context_buf(struct coda_ctx *ctx, + struct coda_aux_buf *buf, size_t size, + const char *name) +{ + return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); +} + + +static void coda_free_framebuffers(struct coda_ctx *ctx) +{ + int i; + + for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) + coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i].buf); +} + +static int coda_alloc_framebuffers(struct coda_ctx *ctx, + struct coda_q_data *q_data, u32 fourcc) +{ + struct coda_dev *dev = ctx->dev; + unsigned int ysize, ycbcr_size; + int ret; + int i; + + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || + ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 || + ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 || + ctx->codec->dst_fourcc == V4L2_PIX_FMT_MPEG4) + ysize = round_up(q_data->rect.width, 16) * + round_up(q_data->rect.height, 16); + else + ysize = round_up(q_data->rect.width, 8) * q_data->rect.height; + + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + ycbcr_size = round_up(ysize, 4096) + ysize / 2; + else + ycbcr_size = ysize + ysize / 2; + + /* Allocate frame buffers */ + for (i = 0; i < ctx->num_internal_frames; i++) { + size_t size = ycbcr_size; + char *name; + + /* Add space for mvcol buffers */ + if (dev->devtype->product != CODA_DX6 && + (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || + (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0))) + size += ysize / 4; + name = kasprintf(GFP_KERNEL, "fb%d", i); + if (!name) { + coda_free_framebuffers(ctx); + return -ENOMEM; + } + ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i].buf, + size, name); + kfree(name); + if (ret < 0) { + coda_free_framebuffers(ctx); + return ret; + } + } + + /* Register frame buffers in the parameter buffer */ + for (i = 0; i < ctx->num_internal_frames; i++) { + u32 y, cb, cr, mvcol; + + /* Start addresses of Y, Cb, Cr planes */ + y = ctx->internal_frames[i].buf.paddr; + cb = y + ysize; + cr = y + ysize + ysize/4; + mvcol = y + ysize + ysize/4 + ysize/4; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) { + cb = round_up(cb, 4096); + mvcol = cb + ysize/2; + cr = 0; + /* Packed 20-bit MSB of base addresses */ + /* YYYYYCCC, CCyyyyyc, cccc.... */ + y = (y & 0xfffff000) | cb >> 20; + cb = (cb & 0x000ff000) << 12; + } + coda_parabuf_write(ctx, i * 3 + 0, y); + coda_parabuf_write(ctx, i * 3 + 1, cb); + coda_parabuf_write(ctx, i * 3 + 2, cr); + + if (dev->devtype->product == CODA_DX6) + continue; + + /* mvcol buffer for h.264 and mpeg4 */ + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) + coda_parabuf_write(ctx, 96 + i, mvcol); + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0) + coda_parabuf_write(ctx, 97, mvcol); + } + + return 0; +} + +static void coda_free_context_buffers(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + + coda_free_aux_buf(dev, &ctx->slicebuf); + coda_free_aux_buf(dev, &ctx->psbuf); + if (dev->devtype->product != CODA_DX6) + coda_free_aux_buf(dev, &ctx->workbuf); + coda_free_aux_buf(dev, &ctx->parabuf); +} + +static int coda_alloc_context_buffers(struct coda_ctx *ctx, + struct coda_q_data *q_data) +{ + struct coda_dev *dev = ctx->dev; + size_t size; + int ret; + + if (!ctx->parabuf.vaddr) { + ret = coda_alloc_context_buf(ctx, &ctx->parabuf, + CODA_PARA_BUF_SIZE, "parabuf"); + if (ret < 0) + return ret; + } + + if (dev->devtype->product == CODA_DX6) + return 0; + + if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) { + /* worst case slice size */ + size = (DIV_ROUND_UP(q_data->rect.width, 16) * + DIV_ROUND_UP(q_data->rect.height, 16)) * 3200 / 8 + 512; + ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, + "slicebuf"); + if (ret < 0) + goto err; + } + + if (!ctx->psbuf.vaddr && (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541)) { + ret = coda_alloc_context_buf(ctx, &ctx->psbuf, + CODA7_PS_BUF_SIZE, "psbuf"); + if (ret < 0) + goto err; + } + + if (!ctx->workbuf.vaddr) { + size = dev->devtype->workbuf_size; + if (dev->devtype->product == CODA_960 && + q_data->fourcc == V4L2_PIX_FMT_H264) + size += CODA9_PS_SAVE_SIZE; + ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, + "workbuf"); + if (ret < 0) + goto err; + } + + return 0; + +err: + coda_free_context_buffers(ctx); + return ret; +} + +static int coda_encode_header(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, + int header_code, u8 *header, int *size) +{ + struct vb2_buffer *vb = &buf->vb2_buf; + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data_src; + struct v4l2_rect *r; + size_t bufsize; + int ret; + int i; + + if (dev->devtype->product == CODA_960) + memset(vb2_plane_vaddr(vb, 0), 0, 64); + + coda_write(dev, vb2_dma_contig_plane_dma_addr(vb, 0), + CODA_CMD_ENC_HEADER_BB_START); + bufsize = vb2_plane_size(vb, 0); + if (dev->devtype->product == CODA_960) + bufsize /= 1024; + coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE); + if (dev->devtype->product == CODA_960 && + ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 && + header_code == CODA_HEADER_H264_SPS) { + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + r = &q_data_src->rect; + + if (r->width % 16 || r->height % 16) { + u32 crop_right = round_up(r->width, 16) - r->width; + u32 crop_bottom = round_up(r->height, 16) - r->height; + + coda_write(dev, crop_right, + CODA9_CMD_ENC_HEADER_FRAME_CROP_H); + coda_write(dev, crop_bottom, + CODA9_CMD_ENC_HEADER_FRAME_CROP_V); + header_code |= CODA9_HEADER_FRAME_CROP; + } + } + coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE); + ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); + return ret; + } + + if (dev->devtype->product == CODA_960) { + for (i = 63; i > 0; i--) + if (((char *)vb2_plane_vaddr(vb, 0))[i] != 0) + break; + *size = i + 1; + } else { + *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) - + coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); + } + memcpy(header, vb2_plane_vaddr(vb, 0), *size); + + return 0; +} + +static u32 coda_slice_mode(struct coda_ctx *ctx) +{ + int size, unit; + + switch (ctx->params.slice_mode) { + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: + default: + return 0; + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB: + size = ctx->params.slice_max_mb; + unit = 1; + break; + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES: + size = ctx->params.slice_max_bits; + unit = 0; + break; + } + + return ((size & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET) | + ((unit & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET) | + ((1 & CODA_SLICING_MODE_MASK) << CODA_SLICING_MODE_OFFSET); +} + +static int coda_enc_param_change(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + u32 change_enable = 0; + u32 success; + int ret; + + if (ctx->params.gop_size_changed) { + change_enable |= CODA_PARAM_CHANGE_RC_GOP; + coda_write(dev, ctx->params.gop_size, + CODA_CMD_ENC_PARAM_RC_GOP); + ctx->gopcounter = ctx->params.gop_size - 1; + ctx->params.gop_size_changed = false; + } + if (ctx->params.h264_intra_qp_changed) { + coda_dbg(1, ctx, "parameter change: intra Qp %u\n", + ctx->params.h264_intra_qp); + + if (ctx->params.bitrate) { + change_enable |= CODA_PARAM_CHANGE_RC_INTRA_QP; + coda_write(dev, ctx->params.h264_intra_qp, + CODA_CMD_ENC_PARAM_RC_INTRA_QP); + } + ctx->params.h264_intra_qp_changed = false; + } + if (ctx->params.bitrate_changed) { + coda_dbg(1, ctx, "parameter change: bitrate %u kbit/s\n", + ctx->params.bitrate); + change_enable |= CODA_PARAM_CHANGE_RC_BITRATE; + coda_write(dev, ctx->params.bitrate, + CODA_CMD_ENC_PARAM_RC_BITRATE); + ctx->params.bitrate_changed = false; + } + if (ctx->params.framerate_changed) { + coda_dbg(1, ctx, "parameter change: frame rate %u/%u Hz\n", + ctx->params.framerate & 0xffff, + (ctx->params.framerate >> 16) + 1); + change_enable |= CODA_PARAM_CHANGE_RC_FRAME_RATE; + coda_write(dev, ctx->params.framerate, + CODA_CMD_ENC_PARAM_RC_FRAME_RATE); + ctx->params.framerate_changed = false; + } + if (ctx->params.intra_refresh_changed) { + coda_dbg(1, ctx, "parameter change: intra refresh MBs %u\n", + ctx->params.intra_refresh); + change_enable |= CODA_PARAM_CHANGE_INTRA_MB_NUM; + coda_write(dev, ctx->params.intra_refresh, + CODA_CMD_ENC_PARAM_INTRA_MB_NUM); + ctx->params.intra_refresh_changed = false; + } + if (ctx->params.slice_mode_changed) { + change_enable |= CODA_PARAM_CHANGE_SLICE_MODE; + coda_write(dev, coda_slice_mode(ctx), + CODA_CMD_ENC_PARAM_SLICE_MODE); + ctx->params.slice_mode_changed = false; + } + + if (!change_enable) + return 0; + + coda_write(dev, change_enable, CODA_CMD_ENC_PARAM_CHANGE_ENABLE); + + ret = coda_command_sync(ctx, CODA_COMMAND_RC_CHANGE_PARAMETER); + if (ret < 0) + return ret; + + success = coda_read(dev, CODA_RET_ENC_PARAM_CHANGE_SUCCESS); + if (success != 1) + coda_dbg(1, ctx, "parameter change failed: %u\n", success); + + return 0; +} + +static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) +{ + phys_addr_t ret; + + size = round_up(size, 1024); + if (size > iram->remaining) + return 0; + iram->remaining -= size; + + ret = iram->next_paddr; + iram->next_paddr += size; + + return ret; +} + +static void coda_setup_iram(struct coda_ctx *ctx) +{ + struct coda_iram_info *iram_info = &ctx->iram_info; + struct coda_dev *dev = ctx->dev; + int w64, w128; + int mb_width; + int dbk_bits; + int bit_bits; + int ip_bits; + int me_bits; + + memset(iram_info, 0, sizeof(*iram_info)); + iram_info->next_paddr = dev->iram.paddr; + iram_info->remaining = dev->iram.size; + + if (!dev->iram.vaddr) + return; + + switch (dev->devtype->product) { + case CODA_HX4: + dbk_bits = CODA7_USE_HOST_DBK_ENABLE; + bit_bits = CODA7_USE_HOST_BIT_ENABLE; + ip_bits = CODA7_USE_HOST_IP_ENABLE; + me_bits = CODA7_USE_HOST_ME_ENABLE; + break; + case CODA_7541: + dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; + bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; + ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + me_bits = CODA7_USE_HOST_ME_ENABLE | CODA7_USE_ME_ENABLE; + break; + case CODA_960: + dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; + bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; + ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + me_bits = 0; + break; + default: /* CODA_DX6 */ + return; + } + + if (ctx->inst_type == CODA_INST_ENCODER) { + struct coda_q_data *q_data_src; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + mb_width = DIV_ROUND_UP(q_data_src->rect.width, 16); + w128 = mb_width * 128; + w64 = mb_width * 64; + + /* Prioritize in case IRAM is too small for everything */ + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { + iram_info->search_ram_size = round_up(mb_width * 16 * + 36 + 2048, 1024); + iram_info->search_ram_paddr = coda_iram_alloc(iram_info, + iram_info->search_ram_size); + if (!iram_info->search_ram_paddr) { + pr_err("IRAM is smaller than the search ram size\n"); + goto out; + } + iram_info->axi_sram_use |= me_bits; + } + + /* Only H.264BP and H.263P3 are considered */ + iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64); + iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64); + if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use) + goto out; + iram_info->axi_sram_use |= dbk_bits; + + iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); + if (!iram_info->buf_bit_use) + goto out; + iram_info->axi_sram_use |= bit_bits; + + iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); + if (!iram_info->buf_ip_ac_dc_use) + goto out; + iram_info->axi_sram_use |= ip_bits; + + /* OVL and BTP disabled for encoder */ + } else if (ctx->inst_type == CODA_INST_DECODER) { + struct coda_q_data *q_data_dst; + + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + mb_width = DIV_ROUND_UP(q_data_dst->width, 16); + w128 = mb_width * 128; + + iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128); + iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128); + if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use) + goto out; + iram_info->axi_sram_use |= dbk_bits; + + iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); + if (!iram_info->buf_bit_use) + goto out; + iram_info->axi_sram_use |= bit_bits; + + iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); + if (!iram_info->buf_ip_ac_dc_use) + goto out; + iram_info->axi_sram_use |= ip_bits; + + /* OVL and BTP unused as there is no VC1 support yet */ + } + +out: + if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)) + coda_dbg(1, ctx, "IRAM smaller than needed\n"); + + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { + /* TODO - Enabling these causes picture errors on CODA7541 */ + if (ctx->inst_type == CODA_INST_DECODER) { + /* fw 1.4.50 */ + iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | + CODA7_USE_IP_ENABLE); + } else { + /* fw 13.4.29 */ + iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | + CODA7_USE_HOST_DBK_ENABLE | + CODA7_USE_IP_ENABLE | + CODA7_USE_DBK_ENABLE); + } + } +} + +static u32 coda_supported_firmwares[] = { + CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), + CODA_FIRMWARE_VERNUM(CODA_HX4, 1, 4, 50), + CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), + CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), + CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 9), + CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10), + CODA_FIRMWARE_VERNUM(CODA_960, 3, 1, 1), +}; + +static bool coda_firmware_supported(u32 vernum) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++) + if (vernum == coda_supported_firmwares[i]) + return true; + return false; +} + +int coda_check_firmware(struct coda_dev *dev) +{ + u16 product, major, minor, release; + u32 data; + int ret; + + ret = clk_prepare_enable(dev->clk_per); + if (ret) + goto err_clk_per; + + ret = clk_prepare_enable(dev->clk_ahb); + if (ret) + goto err_clk_ahb; + + coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM); + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX); + coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD); + coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND); + if (coda_wait_timeout(dev)) { + v4l2_err(&dev->v4l2_dev, "firmware get command error\n"); + ret = -EIO; + goto err_run_cmd; + } + + if (dev->devtype->product == CODA_960) { + data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV); + v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n", + data); + } + + /* Check we are compatible with the loaded firmware */ + data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM); + product = CODA_FIRMWARE_PRODUCT(data); + major = CODA_FIRMWARE_MAJOR(data); + minor = CODA_FIRMWARE_MINOR(data); + release = CODA_FIRMWARE_RELEASE(data); + + clk_disable_unprepare(dev->clk_per); + clk_disable_unprepare(dev->clk_ahb); + + if (product != dev->devtype->product) { + v4l2_err(&dev->v4l2_dev, + "Wrong firmware. Hw: %s, Fw: %s, Version: %u.%u.%u\n", + coda_product_name(dev->devtype->product), + coda_product_name(product), major, minor, release); + return -EINVAL; + } + + v4l2_info(&dev->v4l2_dev, "Initialized %s.\n", + coda_product_name(product)); + + if (coda_firmware_supported(data)) { + v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", + major, minor, release); + } else { + v4l2_warn(&dev->v4l2_dev, + "Unsupported firmware version: %u.%u.%u\n", + major, minor, release); + } + + return 0; + +err_run_cmd: + clk_disable_unprepare(dev->clk_ahb); +err_clk_ahb: + clk_disable_unprepare(dev->clk_per); +err_clk_per: + return ret; +} + +static void coda9_set_frame_cache(struct coda_ctx *ctx, u32 fourcc) +{ + u32 cache_size, cache_config; + + if (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) { + /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ + cache_size = 0x20262024; + cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET; + } else { + /* Luma 0x2 page, 4x4 cache, chroma 0x2 page, 4x3 cache size */ + cache_size = 0x02440243; + cache_config = 1 << CODA9_CACHE_PAGEMERGE_OFFSET; + } + coda_write(ctx->dev, cache_size, CODA9_CMD_SET_FRAME_CACHE_SIZE); + if (fourcc == V4L2_PIX_FMT_NV12 || fourcc == V4L2_PIX_FMT_YUYV) { + cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | + 16 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | + 0 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; + } else { + cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | + 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | + 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; + } + coda_write(ctx->dev, cache_config, CODA9_CMD_SET_FRAME_CACHE_CONFIG); +} + +/* + * Encoder context operations + */ + +static int coda_encoder_reqbufs(struct coda_ctx *ctx, + struct v4l2_requestbuffers *rb) +{ + struct coda_q_data *q_data_src; + int ret; + + if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return 0; + + if (rb->count) { + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + } else { + coda_free_context_buffers(ctx); + } + + return 0; +} + +static int coda_start_encoding(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + struct coda_q_data *q_data_src, *q_data_dst; + u32 bitstream_buf, bitstream_size; + struct vb2_v4l2_buffer *buf; + int gamma, ret, value; + u32 dst_fourcc; + int num_fb; + u32 stride; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_fourcc = q_data_dst->fourcc; + + buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + bitstream_buf = vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, 0); + bitstream_size = q_data_dst->sizeimage; + + if (!coda_is_initialized(dev)) { + v4l2_err(v4l2_dev, "coda is not initialized.\n"); + return -EFAULT; + } + + if (dst_fourcc == V4L2_PIX_FMT_JPEG) { + if (!ctx->params.jpeg_qmat_tab[0]) { + ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL); + if (!ctx->params.jpeg_qmat_tab[0]) + return -ENOMEM; + } + if (!ctx->params.jpeg_qmat_tab[1]) { + ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL); + if (!ctx->params.jpeg_qmat_tab[1]) + return -ENOMEM; + } + coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality); + } + + mutex_lock(&dev->coda_mutex); + + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); + coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); + coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); + switch (dev->devtype->product) { + case CODA_DX6: + coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN | + CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); + break; + case CODA_960: + coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); + fallthrough; + case CODA_HX4: + case CODA_7541: + coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | + CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); + break; + } + + ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | + CODA9_FRAME_TILED2LINEAR); + if (q_data_src->fourcc == V4L2_PIX_FMT_NV12) + ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR; + coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); + + if (dev->devtype->product == CODA_DX6) { + /* Configure the coda */ + coda_write(dev, dev->iram.paddr, + CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); + } + + /* Could set rotation here if needed */ + value = 0; + switch (dev->devtype->product) { + case CODA_DX6: + value = (q_data_src->rect.width & CODADX6_PICWIDTH_MASK) + << CODADX6_PICWIDTH_OFFSET; + value |= (q_data_src->rect.height & CODADX6_PICHEIGHT_MASK) + << CODA_PICHEIGHT_OFFSET; + break; + case CODA_HX4: + case CODA_7541: + if (dst_fourcc == V4L2_PIX_FMT_H264) { + value = (round_up(q_data_src->rect.width, 16) & + CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; + value |= (round_up(q_data_src->rect.height, 16) & + CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + break; + } + fallthrough; + case CODA_960: + value = (q_data_src->rect.width & CODA7_PICWIDTH_MASK) + << CODA7_PICWIDTH_OFFSET; + value |= (q_data_src->rect.height & CODA7_PICHEIGHT_MASK) + << CODA_PICHEIGHT_OFFSET; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); + if (dst_fourcc == V4L2_PIX_FMT_JPEG) + ctx->params.framerate = 0; + coda_write(dev, ctx->params.framerate, + CODA_CMD_ENC_SEQ_SRC_F_RATE); + + ctx->params.codec_mode = ctx->codec->mode; + switch (dst_fourcc) { + case V4L2_PIX_FMT_MPEG4: + if (dev->devtype->product == CODA_960) + coda_write(dev, CODA9_STD_MPEG4, + CODA_CMD_ENC_SEQ_COD_STD); + else + coda_write(dev, CODA_STD_MPEG4, + CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); + break; + case V4L2_PIX_FMT_H264: + if (dev->devtype->product == CODA_960) + coda_write(dev, CODA9_STD_H264, + CODA_CMD_ENC_SEQ_COD_STD); + else + coda_write(dev, CODA_STD_H264, + CODA_CMD_ENC_SEQ_COD_STD); + value = ((ctx->params.h264_disable_deblocking_filter_idc & + CODA_264PARAM_DISABLEDEBLK_MASK) << + CODA_264PARAM_DISABLEDEBLK_OFFSET) | + ((ctx->params.h264_slice_alpha_c0_offset_div2 & + CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << + CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | + ((ctx->params.h264_slice_beta_offset_div2 & + CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << + CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET) | + (ctx->params.h264_constrained_intra_pred_flag << + CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET) | + (ctx->params.h264_chroma_qp_index_offset & + CODA_264PARAM_CHROMAQPOFFSET_MASK); + coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); + break; + case V4L2_PIX_FMT_JPEG: + coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_PARA); + coda_write(dev, ctx->params.jpeg_restart_interval, + CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_EN); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET); + + coda_jpeg_write_tables(ctx); + break; + default: + v4l2_err(v4l2_dev, + "dst format (0x%08x) invalid.\n", dst_fourcc); + ret = -EINVAL; + goto out; + } + + /* + * slice mode and GOP size registers are used for thumb size/offset + * in JPEG mode + */ + if (dst_fourcc != V4L2_PIX_FMT_JPEG) { + value = coda_slice_mode(ctx); + coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); + value = ctx->params.gop_size; + coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); + } + + if (ctx->params.bitrate && (ctx->params.frame_rc_enable || + ctx->params.mb_rc_enable)) { + ctx->params.bitrate_changed = false; + ctx->params.h264_intra_qp_changed = false; + + /* Rate control enabled */ + value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) + << CODA_RATECONTROL_BITRATE_OFFSET; + value |= 1 & CODA_RATECONTROL_ENABLE_MASK; + value |= (ctx->params.vbv_delay & + CODA_RATECONTROL_INITIALDELAY_MASK) + << CODA_RATECONTROL_INITIALDELAY_OFFSET; + if (dev->devtype->product == CODA_960) + value |= BIT(31); /* disable autoskip */ + } else { + value = 0; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA); + + coda_write(dev, ctx->params.vbv_size, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); + coda_write(dev, ctx->params.intra_refresh, + CODA_CMD_ENC_SEQ_INTRA_REFRESH); + + coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START); + coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE); + + + value = 0; + if (dev->devtype->product == CODA_960) + gamma = CODA9_DEFAULT_GAMMA; + else + gamma = CODA_DEFAULT_GAMMA; + if (gamma > 0) { + coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET, + CODA_CMD_ENC_SEQ_RC_GAMMA); + } + + if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) { + coda_write(dev, + ctx->params.h264_min_qp << CODA_QPMIN_OFFSET | + ctx->params.h264_max_qp << CODA_QPMAX_OFFSET, + CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX); + } + if (dev->devtype->product == CODA_960) { + if (ctx->params.h264_max_qp) + value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET; + if (CODA_DEFAULT_GAMMA > 0) + value |= 1 << CODA9_OPTION_GAMMA_OFFSET; + } else { + if (CODA_DEFAULT_GAMMA > 0) { + if (dev->devtype->product == CODA_DX6) + value |= 1 << CODADX6_OPTION_GAMMA_OFFSET; + else + value |= 1 << CODA7_OPTION_GAMMA_OFFSET; + } + if (ctx->params.h264_min_qp) + value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET; + if (ctx->params.h264_max_qp) + value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION); + + if (ctx->params.frame_rc_enable && !ctx->params.mb_rc_enable) + value = 1; + else + value = 0; + coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE); + + coda_setup_iram(ctx); + + if (dst_fourcc == V4L2_PIX_FMT_H264) { + switch (dev->devtype->product) { + case CODA_DX6: + value = FMO_SLICE_SAVE_BUF_SIZE << 7; + coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); + break; + case CODA_HX4: + case CODA_7541: + coda_write(dev, ctx->iram_info.search_ram_paddr, + CODA7_CMD_ENC_SEQ_SEARCH_BASE); + coda_write(dev, ctx->iram_info.search_ram_size, + CODA7_CMD_ENC_SEQ_SEARCH_SIZE); + break; + case CODA_960: + coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION); + coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT); + } + } + + ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); + if (ret < 0) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); + goto out; + } + + if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n"); + ret = -EFAULT; + goto out; + } + ctx->initialized = 1; + + if (dst_fourcc != V4L2_PIX_FMT_JPEG) { + if (dev->devtype->product == CODA_960) + ctx->num_internal_frames = 4; + else + ctx->num_internal_frames = 2; + ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); + if (ret < 0) { + v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); + goto out; + } + num_fb = 2; + stride = q_data_src->bytesperline; + } else { + ctx->num_internal_frames = 0; + num_fb = 0; + stride = 0; + } + coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM); + coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE); + + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { + coda_write(dev, q_data_src->bytesperline, + CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); + } + if (dev->devtype->product != CODA_DX6) { + coda_write(dev, ctx->iram_info.buf_bit_use, + CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); + coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, + CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_y_use, + CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_c_use, + CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); + coda_write(dev, ctx->iram_info.buf_ovl_use, + CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); + if (dev->devtype->product == CODA_960) { + coda_write(dev, ctx->iram_info.buf_btp_use, + CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); + + coda9_set_frame_cache(ctx, q_data_src->fourcc); + + /* FIXME */ + coda_write(dev, ctx->internal_frames[2].buf.paddr, + CODA9_CMD_SET_FRAME_SUBSAMP_A); + coda_write(dev, ctx->internal_frames[3].buf.paddr, + CODA9_CMD_SET_FRAME_SUBSAMP_B); + } + } + + ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF); + if (ret < 0) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n"); + goto out; + } + + coda_dbg(1, ctx, "start encoding %dx%d %4.4s->%4.4s @ %d/%d Hz\n", + q_data_src->rect.width, q_data_src->rect.height, + (char *)&ctx->codec->src_fourcc, (char *)&dst_fourcc, + ctx->params.framerate & 0xffff, + (ctx->params.framerate >> 16) + 1); + + /* Save stream headers */ + buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + /* + * Get SPS in the first frame and copy it to an + * intermediate buffer. + */ + ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS, + &ctx->vpu_header[0][0], + &ctx->vpu_header_size[0]); + if (ret < 0) + goto out; + + /* + * If visible width or height are not aligned to macroblock + * size, the crop_right and crop_bottom SPS fields must be set + * to the difference between visible and coded size. This is + * only supported by CODA960 firmware. All others do not allow + * writing frame cropping parameters, so we have to manually + * fix up the SPS RBSP (Sequence Parameter Set Raw Byte + * Sequence Payload) ourselves. + */ + if (ctx->dev->devtype->product != CODA_960 && + ((q_data_src->rect.width % 16) || + (q_data_src->rect.height % 16))) { + ret = coda_h264_sps_fixup(ctx, q_data_src->rect.width, + q_data_src->rect.height, + &ctx->vpu_header[0][0], + &ctx->vpu_header_size[0], + sizeof(ctx->vpu_header[0])); + if (ret < 0) + goto out; + } + + /* + * Get PPS in the first frame and copy it to an + * intermediate buffer. + */ + ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS, + &ctx->vpu_header[1][0], + &ctx->vpu_header_size[1]); + if (ret < 0) + goto out; + + /* + * Length of H.264 headers is variable and thus it might not be + * aligned for the coda to append the encoded frame. In that is + * the case a filler NAL must be added to header 2. + */ + ctx->vpu_header_size[2] = coda_h264_padding( + (ctx->vpu_header_size[0] + + ctx->vpu_header_size[1]), + ctx->vpu_header[2]); + break; + case V4L2_PIX_FMT_MPEG4: + /* + * Get VOS in the first frame and copy it to an + * intermediate buffer + */ + ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS, + &ctx->vpu_header[0][0], + &ctx->vpu_header_size[0]); + if (ret < 0) + goto out; + + ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS, + &ctx->vpu_header[1][0], + &ctx->vpu_header_size[1]); + if (ret < 0) + goto out; + + ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL, + &ctx->vpu_header[2][0], + &ctx->vpu_header_size[2]); + if (ret < 0) + goto out; + break; + default: + /* No more formats need to save headers at the moment */ + break; + } + +out: + mutex_unlock(&dev->coda_mutex); + return ret; +} + +static int coda_prepare_encode(struct coda_ctx *ctx) +{ + struct coda_q_data *q_data_src, *q_data_dst; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct coda_dev *dev = ctx->dev; + int force_ipicture; + int quant_param = 0; + u32 pic_stream_buffer_addr, pic_stream_buffer_size; + u32 rot_mode = 0; + u32 dst_fourcc; + u32 reg; + int ret; + + ret = coda_enc_param_change(ctx); + if (ret < 0) { + v4l2_warn(&ctx->dev->v4l2_dev, "parameter change failed: %d\n", + ret); + } + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_fourcc = q_data_dst->fourcc; + + src_buf->sequence = ctx->osequence; + dst_buf->sequence = ctx->osequence; + ctx->osequence++; + + force_ipicture = ctx->params.force_ipicture; + if (force_ipicture) + ctx->params.force_ipicture = false; + else if (ctx->params.gop_size != 0 && + (src_buf->sequence % ctx->params.gop_size) == 0) + force_ipicture = 1; + + /* + * Workaround coda firmware BUG that only marks the first + * frame as IDR. This is a problem for some decoders that can't + * recover when a frame is lost. + */ + if (!force_ipicture) { + src_buf->flags |= V4L2_BUF_FLAG_PFRAME; + src_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME; + } else { + src_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; + src_buf->flags &= ~V4L2_BUF_FLAG_PFRAME; + } + + if (dev->devtype->product == CODA_960) + coda_set_gdi_regs(ctx); + + /* + * Copy headers in front of the first frame and forced I frames for + * H.264 only. In MPEG4 they are already copied by the CODA. + */ + if (src_buf->sequence == 0 || force_ipicture) { + pic_stream_buffer_addr = + vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0) + + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1] + + ctx->vpu_header_size[2]; + pic_stream_buffer_size = q_data_dst->sizeimage - + ctx->vpu_header_size[0] - + ctx->vpu_header_size[1] - + ctx->vpu_header_size[2]; + memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0), + &ctx->vpu_header[0][0], ctx->vpu_header_size[0]); + memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) + + ctx->vpu_header_size[0], &ctx->vpu_header[1][0], + ctx->vpu_header_size[1]); + memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) + + ctx->vpu_header_size[0] + ctx->vpu_header_size[1], + &ctx->vpu_header[2][0], ctx->vpu_header_size[2]); + } else { + pic_stream_buffer_addr = + vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + pic_stream_buffer_size = q_data_dst->sizeimage; + } + + if (force_ipicture) { + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + quant_param = ctx->params.h264_intra_qp; + break; + case V4L2_PIX_FMT_MPEG4: + quant_param = ctx->params.mpeg4_intra_qp; + break; + case V4L2_PIX_FMT_JPEG: + quant_param = 30; + break; + default: + v4l2_warn(&ctx->dev->v4l2_dev, + "cannot set intra qp, fmt not supported\n"); + break; + } + } else { + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + quant_param = ctx->params.h264_inter_qp; + break; + case V4L2_PIX_FMT_MPEG4: + quant_param = ctx->params.mpeg4_inter_qp; + break; + default: + v4l2_warn(&ctx->dev->v4l2_dev, + "cannot set inter qp, fmt not supported\n"); + break; + } + } + + /* submit */ + if (ctx->params.rot_mode) + rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode; + coda_write(dev, rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); + coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); + + if (dev->devtype->product == CODA_960) { + coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); + coda_write(dev, q_data_src->bytesperline, + CODA9_CMD_ENC_PIC_SRC_STRIDE); + coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC); + + reg = CODA9_CMD_ENC_PIC_SRC_ADDR_Y; + } else { + reg = CODA_CMD_ENC_PIC_SRC_ADDR_Y; + } + coda_write_base(ctx, q_data_src, src_buf, reg); + + coda_write(dev, force_ipicture << 1 & 0x2, + CODA_CMD_ENC_PIC_OPTION); + + coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START); + coda_write(dev, pic_stream_buffer_size / 1024, + CODA_CMD_ENC_PIC_BB_SIZE); + + if (!ctx->streamon_out) { + /* After streamoff on the output side, set stream end flag */ + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + coda_write(dev, ctx->bit_stream_param, + CODA_REG_BIT_BIT_STREAM_PARAM); + } + + if (dev->devtype->product != CODA_DX6) + coda_write(dev, ctx->iram_info.axi_sram_use, + CODA7_REG_BIT_AXI_SRAM_USE); + + trace_coda_enc_pic_run(ctx, src_buf); + + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); + + return 0; +} + +static char coda_frame_type_char(u32 flags) +{ + return (flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : + (flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : + (flags & V4L2_BUF_FLAG_BFRAME) ? 'B' : '?'; +} + +static void coda_finish_encode(struct coda_ctx *ctx) +{ + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct coda_dev *dev = ctx->dev; + u32 wr_ptr, start_ptr; + + if (ctx->aborting) + return; + + /* + * Lock to make sure that an encoder stop command running in parallel + * will either already have marked src_buf as last, or it will wake up + * the capture queue after the buffers are returned. + */ + mutex_lock(&ctx->wakeup_mutex); + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + trace_coda_enc_pic_done(ctx, dst_buf); + + /* Get results from the coda */ + start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); + wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); + + /* Calculate bytesused field */ + if (dst_buf->sequence == 0 || + src_buf->flags & V4L2_BUF_FLAG_KEYFRAME) { + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr + + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1] + + ctx->vpu_header_size[2]); + } else { + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr); + } + + coda_dbg(1, ctx, "frame size = %u\n", wr_ptr - start_ptr); + + coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); + coda_read(dev, CODA_RET_ENC_PIC_FLAG); + + dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | + V4L2_BUF_FLAG_PFRAME | + V4L2_BUF_FLAG_LAST); + if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) + dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; + else + dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; + dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; + + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); + + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); + mutex_unlock(&ctx->wakeup_mutex); + + ctx->gopcounter--; + if (ctx->gopcounter < 0) + ctx->gopcounter = ctx->params.gop_size - 1; + + coda_dbg(1, ctx, "job finished: encoded %c frame (%d)%s\n", + coda_frame_type_char(dst_buf->flags), dst_buf->sequence, + (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); +} + +static void coda_seq_end_work(struct work_struct *work) +{ + struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work); + struct coda_dev *dev = ctx->dev; + + mutex_lock(&ctx->buffer_mutex); + mutex_lock(&dev->coda_mutex); + + if (ctx->initialized == 0) + goto out; + + coda_dbg(1, ctx, "%s: sent command 'SEQ_END' to coda\n", __func__); + if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { + v4l2_err(&dev->v4l2_dev, + "CODA_COMMAND_SEQ_END failed\n"); + } + + /* + * FIXME: Sometimes h.264 encoding fails with 8-byte sequences missing + * from the output stream after the h.264 decoder has run. Resetting the + * hardware after the decoder has finished seems to help. + */ + if (dev->devtype->product == CODA_960) + coda_hw_reset(ctx); + + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + + coda_free_framebuffers(ctx); + + ctx->initialized = 0; + +out: + mutex_unlock(&dev->coda_mutex); + mutex_unlock(&ctx->buffer_mutex); +} + +static void coda_bit_release(struct coda_ctx *ctx) +{ + mutex_lock(&ctx->buffer_mutex); + coda_free_framebuffers(ctx); + coda_free_context_buffers(ctx); + coda_free_bitstream_buffer(ctx); + mutex_unlock(&ctx->buffer_mutex); +} + +const struct coda_context_ops coda_bit_encode_ops = { + .queue_init = coda_encoder_queue_init, + .reqbufs = coda_encoder_reqbufs, + .start_streaming = coda_start_encoding, + .prepare_run = coda_prepare_encode, + .finish_run = coda_finish_encode, + .seq_end_work = coda_seq_end_work, + .release = coda_bit_release, +}; + +/* + * Decoder context operations + */ + +static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx, + struct coda_q_data *q_data) +{ + if (ctx->bitstream.vaddr) + return 0; + + ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2); + ctx->bitstream.vaddr = dma_alloc_wc(ctx->dev->dev, ctx->bitstream.size, + &ctx->bitstream.paddr, GFP_KERNEL); + if (!ctx->bitstream.vaddr) { + v4l2_err(&ctx->dev->v4l2_dev, + "failed to allocate bitstream ringbuffer"); + return -ENOMEM; + } + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + + return 0; +} + +static void coda_free_bitstream_buffer(struct coda_ctx *ctx) +{ + if (ctx->bitstream.vaddr == NULL) + return; + + dma_free_wc(ctx->dev->dev, ctx->bitstream.size, ctx->bitstream.vaddr, + ctx->bitstream.paddr); + ctx->bitstream.vaddr = NULL; + kfifo_init(&ctx->bitstream_fifo, NULL, 0); +} + +static int coda_decoder_reqbufs(struct coda_ctx *ctx, + struct v4l2_requestbuffers *rb) +{ + struct coda_q_data *q_data_src; + int ret; + + if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return 0; + + if (rb->count) { + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + ret = coda_alloc_bitstream_buffer(ctx, q_data_src); + if (ret < 0) { + coda_free_context_buffers(ctx); + return ret; + } + } else { + coda_free_bitstream_buffer(ctx); + coda_free_context_buffers(ctx); + } + + return 0; +} + +static bool coda_reorder_enable(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + int profile; + + if (dev->devtype->product != CODA_HX4 && + dev->devtype->product != CODA_7541 && + dev->devtype->product != CODA_960) + return false; + + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) + return false; + + if (ctx->codec->src_fourcc != V4L2_PIX_FMT_H264) + return true; + + profile = coda_h264_profile(ctx->params.h264_profile_idc); + if (profile < 0) + v4l2_warn(&dev->v4l2_dev, "Unknown H264 Profile: %u\n", + ctx->params.h264_profile_idc); + + /* Baseline profile does not support reordering */ + return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; +} + +static void coda_decoder_drop_used_metas(struct coda_ctx *ctx) +{ + struct coda_buffer_meta *meta, *tmp; + + /* + * All metas that end at or before the RD pointer (fifo out), + * are now consumed by the VPU and should be released. + */ + spin_lock(&ctx->buffer_meta_lock); + list_for_each_entry_safe(meta, tmp, &ctx->buffer_meta_list, list) { + if (ctx->bitstream_fifo.kfifo.out >= meta->end) { + coda_dbg(2, ctx, "releasing meta: seq=%d start=%d end=%d\n", + meta->sequence, meta->start, meta->end); + + list_del(&meta->list); + ctx->num_metas--; + ctx->first_frame_sequence++; + kfree(meta); + } + } + spin_unlock(&ctx->buffer_meta_lock); +} + +static int __coda_decoder_seq_init(struct coda_ctx *ctx) +{ + struct coda_q_data *q_data_src, *q_data_dst; + u32 bitstream_buf, bitstream_size; + struct coda_dev *dev = ctx->dev; + int width, height; + u32 src_fourcc, dst_fourcc; + u32 val; + int ret; + + lockdep_assert_held(&dev->coda_mutex); + + coda_dbg(1, ctx, "Video Data Order Adapter: %s\n", + ctx->use_vdoa ? "Enabled" : "Disabled"); + + /* Start decoding */ + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + bitstream_buf = ctx->bitstream.paddr; + bitstream_size = ctx->bitstream.size; + src_fourcc = q_data_src->fourcc; + dst_fourcc = q_data_dst->fourcc; + + /* Update coda bitstream read and write pointers from kfifo */ + coda_kfifo_sync_to_device_full(ctx); + + ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | + CODA9_FRAME_TILED2LINEAR); + if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV) + ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + ctx->frame_mem_ctrl |= (0x3 << 9) | + ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); + coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); + + ctx->display_idx = -1; + ctx->frm_dis_flg = 0; + coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + + coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); + coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); + val = 0; + if (coda_reorder_enable(ctx)) + val |= CODA_REORDER_ENABLE; + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) + val |= CODA_NO_INT_ENABLE; + coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION); + + ctx->params.codec_mode = ctx->codec->mode; + if (dev->devtype->product == CODA_960 && + src_fourcc == V4L2_PIX_FMT_MPEG4) + ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4; + else + ctx->params.codec_mode_aux = 0; + if (src_fourcc == V4L2_PIX_FMT_MPEG4) { + coda_write(dev, CODA_MP4_CLASS_MPEG4, + CODA_CMD_DEC_SEQ_MP4_ASP_CLASS); + } + if (src_fourcc == V4L2_PIX_FMT_H264) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { + coda_write(dev, ctx->psbuf.paddr, + CODA_CMD_DEC_SEQ_PS_BB_START); + coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), + CODA_CMD_DEC_SEQ_PS_BB_SIZE); + } + if (dev->devtype->product == CODA_960) { + coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN); + coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE); + } + } + if (src_fourcc == V4L2_PIX_FMT_JPEG) + coda_write(dev, 0, CODA_CMD_DEC_SEQ_JPG_THUMB_EN); + if (dev->devtype->product != CODA_960) + coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE); + + ctx->bit_stream_param = CODA_BIT_DEC_SEQ_INIT_ESCAPE; + ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); + ctx->bit_stream_param = 0; + if (ret) { + v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); + return ret; + } + ctx->sequence_offset = ~0U; + ctx->initialized = 1; + ctx->first_frame_sequence = 0; + + /* Update kfifo out pointer from coda bitstream read pointer */ + coda_kfifo_sync_from_device(ctx); + + /* + * After updating the read pointer, we need to check if + * any metas are consumed and should be released. + */ + coda_decoder_drop_used_metas(ctx); + + if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { + v4l2_err(&dev->v4l2_dev, + "CODA_COMMAND_SEQ_INIT failed, error code = 0x%x\n", + coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON)); + return -EAGAIN; + } + + val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE); + if (dev->devtype->product == CODA_DX6) { + width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK; + height = val & CODADX6_PICHEIGHT_MASK; + } else { + width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK; + height = val & CODA7_PICHEIGHT_MASK; + } + + if (width > q_data_dst->bytesperline || height > q_data_dst->height) { + v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", + width, height, q_data_dst->bytesperline, + q_data_dst->height); + return -EINVAL; + } + + width = round_up(width, 16); + height = round_up(height, 16); + + coda_dbg(1, ctx, "start decoding: %dx%d\n", width, height); + + ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED); + /* + * If the VDOA is used, the decoder needs one additional frame, + * because the frames are freed when the next frame is decoded. + * Otherwise there are visible errors in the decoded frames (green + * regions in displayed frames) and a broken order of frames (earlier + * frames are sporadically displayed after later frames). + */ + if (ctx->use_vdoa) + ctx->num_internal_frames += 1; + if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) { + v4l2_err(&dev->v4l2_dev, + "not enough framebuffers to decode (%d < %d)\n", + CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames); + return -EINVAL; + } + + if (src_fourcc == V4L2_PIX_FMT_H264) { + u32 left_right; + u32 top_bottom; + + left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT); + top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM); + + q_data_dst->rect.left = (left_right >> 10) & 0x3ff; + q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff; + q_data_dst->rect.width = width - q_data_dst->rect.left - + (left_right & 0x3ff); + q_data_dst->rect.height = height - q_data_dst->rect.top - + (top_bottom & 0x3ff); + } + + if (dev->devtype->product != CODA_DX6) { + u8 profile, level; + + val = coda_read(dev, CODA7_RET_DEC_SEQ_HEADER_REPORT); + profile = val & 0xff; + level = (val >> 8) & 0x7f; + + if (profile || level) + coda_update_profile_level_ctrls(ctx, profile, level); + } + + return 0; +} + +static void coda_dec_seq_init_work(struct work_struct *work) +{ + struct coda_ctx *ctx = container_of(work, + struct coda_ctx, seq_init_work); + struct coda_dev *dev = ctx->dev; + + mutex_lock(&ctx->buffer_mutex); + mutex_lock(&dev->coda_mutex); + + if (!ctx->initialized) + __coda_decoder_seq_init(ctx); + + mutex_unlock(&dev->coda_mutex); + mutex_unlock(&ctx->buffer_mutex); +} + +static int __coda_start_decoding(struct coda_ctx *ctx) +{ + struct coda_q_data *q_data_src, *q_data_dst; + struct coda_dev *dev = ctx->dev; + u32 src_fourcc, dst_fourcc; + int ret; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + src_fourcc = q_data_src->fourcc; + dst_fourcc = q_data_dst->fourcc; + + if (!ctx->initialized) { + ret = __coda_decoder_seq_init(ctx); + if (ret < 0) + return ret; + } else { + ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | + CODA9_FRAME_TILED2LINEAR); + if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV) + ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + ctx->frame_mem_ctrl |= (0x3 << 9) | + ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); + } + + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); + + ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n"); + return ret; + } + + /* Tell the decoder how many frame buffers we allocated. */ + coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); + coda_write(dev, round_up(q_data_dst->rect.width, 16), + CODA_CMD_SET_FRAME_BUF_STRIDE); + + if (dev->devtype->product != CODA_DX6) { + /* Set secondary AXI IRAM */ + coda_setup_iram(ctx); + + coda_write(dev, ctx->iram_info.buf_bit_use, + CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); + coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, + CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_y_use, + CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_c_use, + CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); + coda_write(dev, ctx->iram_info.buf_ovl_use, + CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); + if (dev->devtype->product == CODA_960) { + coda_write(dev, ctx->iram_info.buf_btp_use, + CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); + + coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); + coda9_set_frame_cache(ctx, dst_fourcc); + } + } + + if (src_fourcc == V4L2_PIX_FMT_H264) { + coda_write(dev, ctx->slicebuf.paddr, + CODA_CMD_SET_FRAME_SLICE_BB_START); + coda_write(dev, ctx->slicebuf.size / 1024, + CODA_CMD_SET_FRAME_SLICE_BB_SIZE); + } + + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { + int max_mb_x = 1920 / 16; + int max_mb_y = 1088 / 16; + int max_mb_num = max_mb_x * max_mb_y; + + coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, + CODA7_CMD_SET_FRAME_MAX_DEC_SIZE); + } else if (dev->devtype->product == CODA_960) { + int max_mb_x = 1920 / 16; + int max_mb_y = 1088 / 16; + int max_mb_num = max_mb_x * max_mb_y; + + coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, + CODA9_CMD_SET_FRAME_MAX_DEC_SIZE); + } + + if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) { + v4l2_err(&ctx->dev->v4l2_dev, + "CODA_COMMAND_SET_FRAME_BUF timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int coda_start_decoding(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + int ret; + + mutex_lock(&dev->coda_mutex); + ret = __coda_start_decoding(ctx); + mutex_unlock(&dev->coda_mutex); + + return ret; +} + +static int coda_prepare_decode(struct coda_ctx *ctx) +{ + struct vb2_v4l2_buffer *dst_buf; + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data_dst; + struct coda_buffer_meta *meta; + u32 rot_mode = 0; + u32 reg_addr, reg_stride; + + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + /* Try to copy source buffer contents into the bitstream ringbuffer */ + mutex_lock(&ctx->bitstream_mutex); + coda_fill_bitstream(ctx, NULL); + mutex_unlock(&ctx->bitstream_mutex); + + if (coda_get_bitstream_payload(ctx) < 512 && + (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { + coda_dbg(1, ctx, "bitstream payload: %d, skipping\n", + coda_get_bitstream_payload(ctx)); + return -EAGAIN; + } + + /* Run coda_start_decoding (again) if not yet initialized */ + if (!ctx->initialized) { + int ret = __coda_start_decoding(ctx); + + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); + return -EAGAIN; + } else { + ctx->initialized = 1; + } + } + + if (dev->devtype->product == CODA_960) + coda_set_gdi_regs(ctx); + + if (ctx->use_vdoa && + ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) { + vdoa_device_run(ctx->vdoa, + vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0), + ctx->internal_frames[ctx->display_idx].buf.paddr); + } else { + if (dev->devtype->product == CODA_960) { + /* + * It was previously assumed that the CODA960 has an + * internal list of 64 buffer entries that contains + * both the registered internal frame buffers as well + * as the rotator buffer output, and that the ROT_INDEX + * register must be set to a value between the last + * internal frame buffers' index and 64. + * At least on firmware version 3.1.1 it turns out that + * setting ROT_INDEX to any value >= 32 causes CODA + * hangups that it can not recover from with the SRC VPU + * reset. + * It does appear to work however, to just set it to a + * fixed value in the [ctx->num_internal_frames, 31] + * range, for example CODA_MAX_FRAMEBUFFERS. + */ + coda_write(dev, CODA_MAX_FRAMEBUFFERS, + CODA9_CMD_DEC_PIC_ROT_INDEX); + + reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y; + reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE; + } else { + reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y; + reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE; + } + coda_write_base(ctx, q_data_dst, dst_buf, reg_addr); + coda_write(dev, q_data_dst->bytesperline, reg_stride); + + rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode; + } + + coda_write(dev, rot_mode, CODA_CMD_DEC_PIC_ROT_MODE); + + switch (dev->devtype->product) { + case CODA_DX6: + /* TBD */ + case CODA_HX4: + case CODA_7541: + coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); + break; + case CODA_960: + /* 'hardcode to use interrupt disable mode'? */ + coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); + break; + } + + coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM); + + coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); + coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); + + if (dev->devtype->product != CODA_DX6) + coda_write(dev, ctx->iram_info.axi_sram_use, + CODA7_REG_BIT_AXI_SRAM_USE); + + spin_lock(&ctx->buffer_meta_lock); + meta = list_first_entry_or_null(&ctx->buffer_meta_list, + struct coda_buffer_meta, list); + + if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) { + + /* If this is the last buffer in the bitstream, add padding */ + if (meta->end == ctx->bitstream_fifo.kfifo.in) { + static unsigned char buf[512]; + unsigned int pad; + + /* Pad to multiple of 256 and then add 256 more */ + pad = ((0 - meta->end) & 0xff) + 256; + + memset(buf, 0xff, sizeof(buf)); + + kfifo_in(&ctx->bitstream_fifo, buf, pad); + } + } + spin_unlock(&ctx->buffer_meta_lock); + + coda_kfifo_sync_to_device_full(ctx); + + /* Clear decode success flag */ + coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS); + + /* Clear error return value */ + coda_write(dev, 0, CODA_RET_DEC_PIC_ERR_MB); + + trace_coda_dec_pic_run(ctx, meta); + + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); + + return 0; +} + +static void coda_finish_decode(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data_src; + struct coda_q_data *q_data_dst; + struct vb2_v4l2_buffer *dst_buf; + struct coda_buffer_meta *meta; + int width, height; + int decoded_idx; + int display_idx; + struct coda_internal_frame *decoded_frame = NULL; + u32 src_fourcc; + int success; + u32 err_mb; + int err_vdoa = 0; + u32 val; + + if (ctx->aborting) + return; + + /* Update kfifo out pointer from coda bitstream read pointer */ + coda_kfifo_sync_from_device(ctx); + + /* + * in stream-end mode, the read pointer can overshoot the write pointer + * by up to 512 bytes + */ + if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { + if (coda_get_bitstream_payload(ctx) >= ctx->bitstream.size - 512) + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + } + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + src_fourcc = q_data_src->fourcc; + + val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS); + if (val != 1) + pr_err("DEC_PIC_SUCCESS = %d\n", val); + + success = val & 0x1; + if (!success) + v4l2_err(&dev->v4l2_dev, "decode failed\n"); + + if (src_fourcc == V4L2_PIX_FMT_H264) { + if (val & (1 << 3)) + v4l2_err(&dev->v4l2_dev, + "insufficient PS buffer space (%d bytes)\n", + ctx->psbuf.size); + if (val & (1 << 2)) + v4l2_err(&dev->v4l2_dev, + "insufficient slice buffer space (%d bytes)\n", + ctx->slicebuf.size); + } + + val = coda_read(dev, CODA_RET_DEC_PIC_SIZE); + width = (val >> 16) & 0xffff; + height = val & 0xffff; + + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + /* frame crop information */ + if (src_fourcc == V4L2_PIX_FMT_H264) { + u32 left_right; + u32 top_bottom; + + left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT); + top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM); + + if (left_right == 0xffffffff && top_bottom == 0xffffffff) { + /* Keep current crop information */ + } else { + struct v4l2_rect *rect = &q_data_dst->rect; + + rect->left = left_right >> 16 & 0xffff; + rect->top = top_bottom >> 16 & 0xffff; + rect->width = width - rect->left - + (left_right & 0xffff); + rect->height = height - rect->top - + (top_bottom & 0xffff); + } + } else { + /* no cropping */ + } + + err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); + if (err_mb > 0) { + if (__ratelimit(&dev->mb_err_rs)) + coda_dbg(1, ctx, "errors in %d macroblocks\n", err_mb); + v4l2_ctrl_s_ctrl(ctx->mb_err_cnt_ctrl, + v4l2_ctrl_g_ctrl(ctx->mb_err_cnt_ctrl) + err_mb); + } + + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { + val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); + if (val == 0) { + /* not enough bitstream data */ + coda_dbg(1, ctx, "prescan failed: %d\n", val); + ctx->hold = true; + return; + } + } + + /* Wait until the VDOA finished writing the previous display frame */ + if (ctx->use_vdoa && + ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) { + err_vdoa = vdoa_wait_for_completion(ctx->vdoa); + } + + ctx->frm_dis_flg = coda_read(dev, + CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + + /* The previous display frame was copied out and can be overwritten */ + if (ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) { + ctx->frm_dis_flg &= ~(1 << ctx->display_idx); + coda_write(dev, ctx->frm_dis_flg, + CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + } + + /* + * The index of the last decoded frame, not necessarily in + * display order, and the index of the next display frame. + * The latter could have been decoded in a previous run. + */ + decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX); + display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX); + + if (decoded_idx == -1) { + /* no frame was decoded, but we might have a display frame */ + if (display_idx >= 0 && display_idx < ctx->num_internal_frames) + ctx->sequence_offset++; + else if (ctx->display_idx < 0) + ctx->hold = true; + } else if (decoded_idx == -2) { + if (ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) + ctx->sequence_offset++; + /* no frame was decoded, we still return remaining buffers */ + } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { + v4l2_err(&dev->v4l2_dev, + "decoded frame index out of range: %d\n", decoded_idx); + } else { + int sequence; + + decoded_frame = &ctx->internal_frames[decoded_idx]; + + val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM); + if (ctx->sequence_offset == -1) + ctx->sequence_offset = val; + + sequence = val + ctx->first_frame_sequence + - ctx->sequence_offset; + spin_lock(&ctx->buffer_meta_lock); + if (!list_empty(&ctx->buffer_meta_list)) { + meta = list_first_entry(&ctx->buffer_meta_list, + struct coda_buffer_meta, list); + list_del(&meta->list); + ctx->num_metas--; + spin_unlock(&ctx->buffer_meta_lock); + /* + * Clamp counters to 16 bits for comparison, as the HW + * counter rolls over at this point for h.264. This + * may be different for other formats, but using 16 bits + * should be enough to detect most errors and saves us + * from doing different things based on the format. + */ + if ((sequence & 0xffff) != (meta->sequence & 0xffff)) { + v4l2_err(&dev->v4l2_dev, + "sequence number mismatch (%d(%d) != %d)\n", + sequence, ctx->sequence_offset, + meta->sequence); + } + decoded_frame->meta = *meta; + kfree(meta); + } else { + spin_unlock(&ctx->buffer_meta_lock); + v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); + memset(&decoded_frame->meta, 0, + sizeof(struct coda_buffer_meta)); + decoded_frame->meta.sequence = sequence; + decoded_frame->meta.last = false; + ctx->sequence_offset++; + } + + trace_coda_dec_pic_done(ctx, &decoded_frame->meta); + + val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; + decoded_frame->type = (val == 0) ? V4L2_BUF_FLAG_KEYFRAME : + (val == 1) ? V4L2_BUF_FLAG_PFRAME : + V4L2_BUF_FLAG_BFRAME; + + decoded_frame->error = err_mb; + } + + if (display_idx == -1) { + /* + * no more frames to be decoded, but there could still + * be rotator output to dequeue + */ + ctx->hold = true; + } else if (display_idx == -3) { + /* possibly prescan failure */ + } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) { + v4l2_err(&dev->v4l2_dev, + "presentation frame index out of range: %d\n", + display_idx); + } + + /* If a frame was copied out, return it */ + if (ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) { + struct coda_internal_frame *ready_frame; + + ready_frame = &ctx->internal_frames[ctx->display_idx]; + + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + dst_buf->sequence = ctx->osequence++; + + dst_buf->field = V4L2_FIELD_NONE; + dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | + V4L2_BUF_FLAG_PFRAME | + V4L2_BUF_FLAG_BFRAME); + dst_buf->flags |= ready_frame->type; + meta = &ready_frame->meta; + if (meta->last && !coda_reorder_enable(ctx)) { + /* + * If this was the last decoded frame, and reordering + * is disabled, this will be the last display frame. + */ + coda_dbg(1, ctx, "last meta, marking as last frame\n"); + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + } else if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG && + display_idx == -1) { + /* + * If there is no designated presentation frame anymore, + * this frame has to be the last one. + */ + coda_dbg(1, ctx, + "no more frames to return, marking as last frame\n"); + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + } + dst_buf->timecode = meta->timecode; + dst_buf->vb2_buf.timestamp = meta->timestamp; + + trace_coda_dec_rot_done(ctx, dst_buf, meta); + + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, + q_data_dst->sizeimage); + + if (ready_frame->error || err_vdoa) + coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); + else + coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); + + if (decoded_frame) { + coda_dbg(1, ctx, "job finished: decoded %c frame %u, returned %c frame %u (%u/%u)%s\n", + coda_frame_type_char(decoded_frame->type), + decoded_frame->meta.sequence, + coda_frame_type_char(dst_buf->flags), + ready_frame->meta.sequence, + dst_buf->sequence, ctx->qsequence, + (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? + " (last)" : ""); + } else { + coda_dbg(1, ctx, "job finished: no frame decoded (%d), returned %c frame %u (%u/%u)%s\n", + decoded_idx, + coda_frame_type_char(dst_buf->flags), + ready_frame->meta.sequence, + dst_buf->sequence, ctx->qsequence, + (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? + " (last)" : ""); + } + } else { + if (decoded_frame) { + coda_dbg(1, ctx, "job finished: decoded %c frame %u, no frame returned (%d)\n", + coda_frame_type_char(decoded_frame->type), + decoded_frame->meta.sequence, + ctx->display_idx); + } else { + coda_dbg(1, ctx, "job finished: no frame decoded (%d) or returned (%d)\n", + decoded_idx, ctx->display_idx); + } + } + + /* The rotator will copy the current display frame next time */ + ctx->display_idx = display_idx; + + /* + * The current decode run might have brought the bitstream fill level + * below the size where we can start the next decode run. As userspace + * might have filled the output queue completely and might thus be + * blocked, we can't rely on the next qbuf to trigger the bitstream + * refill. Check if we have data to refill the bitstream now. + */ + mutex_lock(&ctx->bitstream_mutex); + coda_fill_bitstream(ctx, NULL); + mutex_unlock(&ctx->bitstream_mutex); +} + +static void coda_decode_timeout(struct coda_ctx *ctx) +{ + struct vb2_v4l2_buffer *dst_buf; + + /* + * For now this only handles the case where we would deadlock with + * userspace, i.e. userspace issued DEC_CMD_STOP and waits for EOS, + * but after a failed decode run we would hold the context and wait for + * userspace to queue more buffers. + */ + if (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG)) + return; + + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + dst_buf->sequence = ctx->qsequence - 1; + + coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); +} + +const struct coda_context_ops coda_bit_decode_ops = { + .queue_init = coda_decoder_queue_init, + .reqbufs = coda_decoder_reqbufs, + .start_streaming = coda_start_decoding, + .prepare_run = coda_prepare_decode, + .finish_run = coda_finish_decode, + .run_timeout = coda_decode_timeout, + .seq_init_work = coda_dec_seq_init_work, + .seq_end_work = coda_seq_end_work, + .release = coda_bit_release, +}; + +irqreturn_t coda_irq_handler(int irq, void *data) +{ + struct coda_dev *dev = data; + struct coda_ctx *ctx; + + /* read status register to attend the IRQ */ + coda_read(dev, CODA_REG_BIT_INT_STATUS); + coda_write(dev, 0, CODA_REG_BIT_INT_REASON); + coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, + CODA_REG_BIT_INT_CLEAR); + + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); + if (ctx == NULL) { + v4l2_err(&dev->v4l2_dev, + "Instance released before the end of transaction\n"); + return IRQ_HANDLED; + } + + trace_coda_bit_done(ctx); + + if (ctx->aborting) { + coda_dbg(1, ctx, "task has been aborted\n"); + } + + if (coda_isbusy(ctx->dev)) { + coda_dbg(1, ctx, "coda is still busy!!!!\n"); + return IRQ_NONE; + } + + complete(&ctx->completion); + + return IRQ_HANDLED; +} diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c --- a/drivers/media/platform/chips-media/coda/coda-common.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/coda-common.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,3361 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Coda multi-standard codec IP + * + * Copyright (C) 2012 Vista Silicon S.L. + * Javier Martin, + * Xavier Duret + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "coda.h" +#include "imx-vdoa.h" + +#define CODA_NAME "coda" + +#define CODADX6_MAX_INSTANCES 4 +#define CODA_MAX_FORMATS 5 + +#define CODA_ISRAM_SIZE (2048 * 2) + +#define MIN_W 48 +#define MIN_H 16 + +#define S_ALIGN 1 /* multiple of 2 */ +#define W_ALIGN 1 /* multiple of 2 */ +#define H_ALIGN 1 /* multiple of 2 */ + +#define fh_to_ctx(__fh) container_of(__fh, struct coda_ctx, fh) + +int coda_debug; +module_param(coda_debug, int, 0644); +MODULE_PARM_DESC(coda_debug, "Debug level (0-2)"); + +static int disable_tiling; +module_param(disable_tiling, int, 0644); +MODULE_PARM_DESC(disable_tiling, "Disable tiled frame buffers"); + +static int disable_vdoa; +module_param(disable_vdoa, int, 0644); +MODULE_PARM_DESC(disable_vdoa, "Disable Video Data Order Adapter tiled to raster-scan conversion"); + +static int enable_bwb = 0; +module_param(enable_bwb, int, 0644); +MODULE_PARM_DESC(enable_bwb, "Enable BWB unit for decoding, may crash on certain streams"); + +void coda_write(struct coda_dev *dev, u32 data, u32 reg) +{ + v4l2_dbg(3, coda_debug, &dev->v4l2_dev, + "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); + writel(data, dev->regs_base + reg); +} + +unsigned int coda_read(struct coda_dev *dev, u32 reg) +{ + u32 data; + + data = readl(dev->regs_base + reg); + v4l2_dbg(3, coda_debug, &dev->v4l2_dev, + "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); + return data; +} + +void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, + struct vb2_v4l2_buffer *buf, unsigned int reg_y) +{ + u32 base_y = vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, 0); + u32 base_cb, base_cr; + + switch (q_data->fourcc) { + case V4L2_PIX_FMT_YUYV: + /* Fallthrough: IN -H264-> CODA -NV12 MB-> VDOA -YUYV-> OUT */ + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_YUV420: + default: + base_cb = base_y + q_data->bytesperline * q_data->height; + base_cr = base_cb + q_data->bytesperline * q_data->height / 4; + break; + case V4L2_PIX_FMT_YVU420: + /* Switch Cb and Cr for YVU420 format */ + base_cr = base_y + q_data->bytesperline * q_data->height; + base_cb = base_cr + q_data->bytesperline * q_data->height / 4; + break; + case V4L2_PIX_FMT_YUV422P: + base_cb = base_y + q_data->bytesperline * q_data->height; + base_cr = base_cb + q_data->bytesperline * q_data->height / 2; + } + + coda_write(ctx->dev, base_y, reg_y); + coda_write(ctx->dev, base_cb, reg_y + 4); + coda_write(ctx->dev, base_cr, reg_y + 8); +} + +#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \ + { mode, src_fourcc, dst_fourcc, max_w, max_h } + +/* + * Arrays of codecs supported by each given version of Coda: + * i.MX27 -> codadx6 + * i.MX51 -> codahx4 + * i.MX53 -> coda7 + * i.MX6 -> coda960 + * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants + */ +static const struct coda_codec codadx6_codecs[] = { + CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), + CODA_CODEC(CODADX6_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576), +}; + +static const struct coda_codec codahx4_codecs[] = { + CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), + CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1280, 720), +}; + +static const struct coda_codec coda7_codecs[] = { + CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), + CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), + CODA_CODEC(CODA7_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG, 8192, 8192), + CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MJPG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420, 8192, 8192), +}; + +static const struct coda_codec coda9_codecs[] = { + CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1088), + CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1088), + CODA_CODEC(CODA9_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG, 8192, 8192), + CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA9_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA9_MODE_DECODE_MJPG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420, 8192, 8192), +}; + +struct coda_video_device { + const char *name; + enum coda_inst_type type; + const struct coda_context_ops *ops; + bool direct; + u32 src_formats[CODA_MAX_FORMATS]; + u32 dst_formats[CODA_MAX_FORMATS]; +}; + +static const struct coda_video_device coda_bit_encoder = { + .name = "coda-video-encoder", + .type = CODA_INST_ENCODER, + .ops = &coda_bit_encode_ops, + .src_formats = { + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, + }, + .dst_formats = { + V4L2_PIX_FMT_H264, + V4L2_PIX_FMT_MPEG4, + }, +}; + +static const struct coda_video_device coda_bit_jpeg_encoder = { + .name = "coda-jpeg-encoder", + .type = CODA_INST_ENCODER, + .ops = &coda_bit_encode_ops, + .src_formats = { + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, + V4L2_PIX_FMT_YUV422P, + }, + .dst_formats = { + V4L2_PIX_FMT_JPEG, + }, +}; + +static const struct coda_video_device coda_bit_decoder = { + .name = "coda-video-decoder", + .type = CODA_INST_DECODER, + .ops = &coda_bit_decode_ops, + .src_formats = { + V4L2_PIX_FMT_H264, + V4L2_PIX_FMT_MPEG2, + V4L2_PIX_FMT_MPEG4, + }, + .dst_formats = { + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, + /* + * If V4L2_PIX_FMT_YUYV should be default, + * set_default_params() must be adjusted. + */ + V4L2_PIX_FMT_YUYV, + }, +}; + +static const struct coda_video_device coda_bit_jpeg_decoder = { + .name = "coda-jpeg-decoder", + .type = CODA_INST_DECODER, + .ops = &coda_bit_decode_ops, + .src_formats = { + V4L2_PIX_FMT_JPEG, + }, + .dst_formats = { + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, + V4L2_PIX_FMT_YUV422P, + }, +}; + +static const struct coda_video_device coda9_jpeg_encoder = { + .name = "coda-jpeg-encoder", + .type = CODA_INST_ENCODER, + .ops = &coda9_jpeg_encode_ops, + .direct = true, + .src_formats = { + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, + V4L2_PIX_FMT_YUV422P, + V4L2_PIX_FMT_GREY, + }, + .dst_formats = { + V4L2_PIX_FMT_JPEG, + }, +}; + +static const struct coda_video_device coda9_jpeg_decoder = { + .name = "coda-jpeg-decoder", + .type = CODA_INST_DECODER, + .ops = &coda9_jpeg_decode_ops, + .direct = true, + .src_formats = { + V4L2_PIX_FMT_JPEG, + }, + .dst_formats = { + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, + V4L2_PIX_FMT_YUV422P, + }, +}; + +static const struct coda_video_device *codadx6_video_devices[] = { + &coda_bit_encoder, +}; + +static const struct coda_video_device *codahx4_video_devices[] = { + &coda_bit_encoder, + &coda_bit_decoder, +}; + +static const struct coda_video_device *coda7_video_devices[] = { + &coda_bit_jpeg_encoder, + &coda_bit_jpeg_decoder, + &coda_bit_encoder, + &coda_bit_decoder, +}; + +static const struct coda_video_device *coda9_video_devices[] = { + &coda9_jpeg_encoder, + &coda9_jpeg_decoder, + &coda_bit_encoder, + &coda_bit_decoder, +}; + +/* + * Normalize all supported YUV 4:2:0 formats to the value used in the codec + * tables. + */ +static u32 coda_format_normalize_yuv(u32 fourcc) +{ + switch (fourcc) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUYV: + return V4L2_PIX_FMT_YUV420; + default: + return fourcc; + } +} + +static const struct coda_codec *coda_find_codec(struct coda_dev *dev, + int src_fourcc, int dst_fourcc) +{ + const struct coda_codec *codecs = dev->devtype->codecs; + int num_codecs = dev->devtype->num_codecs; + int k; + + src_fourcc = coda_format_normalize_yuv(src_fourcc); + dst_fourcc = coda_format_normalize_yuv(dst_fourcc); + if (src_fourcc == dst_fourcc) + return NULL; + + for (k = 0; k < num_codecs; k++) { + if (codecs[k].src_fourcc == src_fourcc && + codecs[k].dst_fourcc == dst_fourcc) + break; + } + + if (k == num_codecs) + return NULL; + + return &codecs[k]; +} + +static void coda_get_max_dimensions(struct coda_dev *dev, + const struct coda_codec *codec, + int *max_w, int *max_h) +{ + const struct coda_codec *codecs = dev->devtype->codecs; + int num_codecs = dev->devtype->num_codecs; + unsigned int w, h; + int k; + + if (codec) { + w = codec->max_w; + h = codec->max_h; + } else { + for (k = 0, w = 0, h = 0; k < num_codecs; k++) { + w = max(w, codecs[k].max_w); + h = max(h, codecs[k].max_h); + } + } + + if (max_w) + *max_w = w; + if (max_h) + *max_h = h; +} + +static const struct coda_video_device *to_coda_video_device(struct video_device + *vdev) +{ + struct coda_dev *dev = video_get_drvdata(vdev); + unsigned int i = vdev - dev->vfd; + + if (i >= dev->devtype->num_vdevs) + return NULL; + + return dev->devtype->vdevs[i]; +} + +const char *coda_product_name(int product) +{ + static char buf[9]; + + switch (product) { + case CODA_DX6: + return "CodaDx6"; + case CODA_HX4: + return "CodaHx4"; + case CODA_7541: + return "CODA7541"; + case CODA_960: + return "CODA960"; + default: + snprintf(buf, sizeof(buf), "(0x%04x)", product); + return buf; + } +} + +static struct vdoa_data *coda_get_vdoa_data(void) +{ + struct device_node *vdoa_node; + struct platform_device *vdoa_pdev; + struct vdoa_data *vdoa_data = NULL; + + vdoa_node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-vdoa"); + if (!vdoa_node) + return NULL; + + vdoa_pdev = of_find_device_by_node(vdoa_node); + if (!vdoa_pdev) + goto out; + + vdoa_data = platform_get_drvdata(vdoa_pdev); + if (!vdoa_data) + vdoa_data = ERR_PTR(-EPROBE_DEFER); + + put_device(&vdoa_pdev->dev); +out: + of_node_put(vdoa_node); + + return vdoa_data; +} + +/* + * V4L2 ioctl() operations. + */ +static int coda_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + + strscpy(cap->driver, CODA_NAME, sizeof(cap->driver)); + strscpy(cap->card, coda_product_name(ctx->dev->devtype->product), + sizeof(cap->card)); + strscpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info)); + return 0; +} + +static const u32 coda_formats_420[CODA_MAX_FORMATS] = { + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, +}; + +static int coda_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct video_device *vdev = video_devdata(file); + const struct coda_video_device *cvd = to_coda_video_device(vdev); + struct coda_ctx *ctx = fh_to_ctx(priv); + const u32 *formats; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + formats = cvd->src_formats; + else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + struct coda_q_data *q_data_src; + struct vb2_queue *src_vq; + + formats = cvd->dst_formats; + + /* + * If the source format is already fixed, only allow the same + * chroma subsampling. + */ + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT); + if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && + vb2_is_streaming(src_vq)) { + if (ctx->params.jpeg_chroma_subsampling == + V4L2_JPEG_CHROMA_SUBSAMPLING_420) { + formats = coda_formats_420; + } else if (ctx->params.jpeg_chroma_subsampling == + V4L2_JPEG_CHROMA_SUBSAMPLING_422) { + f->pixelformat = V4L2_PIX_FMT_YUV422P; + return f->index ? -EINVAL : 0; + } + } + } else { + return -EINVAL; + } + + if (f->index >= CODA_MAX_FORMATS || formats[f->index] == 0) + return -EINVAL; + + /* Skip YUYV if the vdoa is not available */ + if (!ctx->vdoa && f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + formats[f->index] == V4L2_PIX_FMT_YUYV) + return -EINVAL; + + f->pixelformat = formats[f->index]; + + return 0; +} + +static int coda_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct coda_q_data *q_data; + struct coda_ctx *ctx = fh_to_ctx(priv); + + q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = q_data->fourcc; + f->fmt.pix.width = q_data->width; + f->fmt.pix.height = q_data->height; + f->fmt.pix.bytesperline = q_data->bytesperline; + + f->fmt.pix.sizeimage = q_data->sizeimage; + f->fmt.pix.colorspace = ctx->colorspace; + f->fmt.pix.xfer_func = ctx->xfer_func; + f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; + f->fmt.pix.quantization = ctx->quantization; + + return 0; +} + +static int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f) +{ + struct coda_q_data *q_data; + const u32 *formats; + int i; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + formats = ctx->cvd->src_formats; + else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + formats = ctx->cvd->dst_formats; + else + return -EINVAL; + + for (i = 0; i < CODA_MAX_FORMATS; i++) { + /* Skip YUYV if the vdoa is not available */ + if (!ctx->vdoa && f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + formats[i] == V4L2_PIX_FMT_YUYV) + continue; + + if (formats[i] == f->fmt.pix.pixelformat) { + f->fmt.pix.pixelformat = formats[i]; + return 0; + } + } + + /* Fall back to currently set pixelformat */ + q_data = get_q_data(ctx, f->type); + f->fmt.pix.pixelformat = q_data->fourcc; + + return 0; +} + +static int coda_try_fmt_vdoa(struct coda_ctx *ctx, struct v4l2_format *f, + bool *use_vdoa) +{ + int err; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (!use_vdoa) + return -EINVAL; + + if (!ctx->vdoa) { + *use_vdoa = false; + return 0; + } + + err = vdoa_context_configure(NULL, round_up(f->fmt.pix.width, 16), + f->fmt.pix.height, f->fmt.pix.pixelformat); + if (err) { + *use_vdoa = false; + return 0; + } + + *use_vdoa = true; + return 0; +} + +static unsigned int coda_estimate_sizeimage(struct coda_ctx *ctx, u32 sizeimage, + u32 width, u32 height) +{ + /* + * This is a rough estimate for sensible compressed buffer + * sizes (between 1 and 16 bits per pixel). This could be + * improved by better format specific worst case estimates. + */ + return round_up(clamp(sizeimage, width * height / 8, + width * height * 2), PAGE_SIZE); +} + +static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, + struct v4l2_format *f) +{ + struct coda_dev *dev = ctx->dev; + unsigned int max_w, max_h; + enum v4l2_field field; + + field = f->fmt.pix.field; + if (field == V4L2_FIELD_ANY) + field = V4L2_FIELD_NONE; + else if (V4L2_FIELD_NONE != field) + return -EINVAL; + + /* V4L2 specification suggests the driver corrects the format struct + * if any of the dimensions is unsupported */ + f->fmt.pix.field = field; + + coda_get_max_dimensions(dev, codec, &max_w, &max_h); + v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w, W_ALIGN, + &f->fmt.pix.height, MIN_H, max_h, H_ALIGN, + S_ALIGN); + + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + /* + * Frame stride must be at least multiple of 8, + * but multiple of 16 for h.264 or JPEG 4:2:x + */ + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height * 3 / 2; + break; + case V4L2_PIX_FMT_YUYV: + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16) * 2; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height; + break; + case V4L2_PIX_FMT_YUV422P: + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height * 2; + break; + case V4L2_PIX_FMT_GREY: + /* keep 16 pixel alignment of 8-bit pixel data */ + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + break; + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_MPEG4: + case V4L2_PIX_FMT_MPEG2: + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = coda_estimate_sizeimage(ctx, + f->fmt.pix.sizeimage, + f->fmt.pix.width, + f->fmt.pix.height); + break; + default: + BUG(); + } + + return 0; +} + +static int coda_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + const struct coda_q_data *q_data_src; + const struct coda_codec *codec; + struct vb2_queue *src_vq; + int hscale = 0; + int vscale = 0; + int ret; + bool use_vdoa; + + ret = coda_try_pixelformat(ctx, f); + if (ret < 0) + return ret; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + + /* + * If the source format is already fixed, only allow the same output + * resolution. When decoding JPEG images, we also have to make sure to + * use the same chroma subsampling. + */ + src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + if (vb2_is_streaming(src_vq)) { + if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && + ctx->dev->devtype->product == CODA_960) { + hscale = coda_jpeg_scale(q_data_src->width, f->fmt.pix.width); + vscale = coda_jpeg_scale(q_data_src->height, f->fmt.pix.height); + } + f->fmt.pix.width = q_data_src->width >> hscale; + f->fmt.pix.height = q_data_src->height >> vscale; + + if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) { + if (ctx->params.jpeg_chroma_subsampling == + V4L2_JPEG_CHROMA_SUBSAMPLING_420 && + f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) + f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12; + else if (ctx->params.jpeg_chroma_subsampling == + V4L2_JPEG_CHROMA_SUBSAMPLING_422) + f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; + } + } + + f->fmt.pix.colorspace = ctx->colorspace; + f->fmt.pix.xfer_func = ctx->xfer_func; + f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; + f->fmt.pix.quantization = ctx->quantization; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + codec = coda_find_codec(ctx->dev, q_data_src->fourcc, + f->fmt.pix.pixelformat); + if (!codec) + return -EINVAL; + + ret = coda_try_fmt(ctx, codec, f); + if (ret < 0) + return ret; + + /* The decoders always write complete macroblocks or MCUs */ + if (ctx->inst_type == CODA_INST_DECODER) { + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16 >> hscale); + f->fmt.pix.height = round_up(f->fmt.pix.height, 16 >> vscale); + if (codec->src_fourcc == V4L2_PIX_FMT_JPEG && + f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) { + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height * 2; + } else { + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height * 3 / 2; + } + + ret = coda_try_fmt_vdoa(ctx, f, &use_vdoa); + if (ret < 0) + return ret; + + if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) { + if (!use_vdoa) + return -EINVAL; + + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16) * 2; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height; + } + } + + return 0; +} + +static void coda_set_default_colorspace(struct v4l2_pix_format *fmt) +{ + enum v4l2_colorspace colorspace; + + if (fmt->pixelformat == V4L2_PIX_FMT_JPEG) + colorspace = V4L2_COLORSPACE_JPEG; + else if (fmt->width <= 720 && fmt->height <= 576) + colorspace = V4L2_COLORSPACE_SMPTE170M; + else + colorspace = V4L2_COLORSPACE_REC709; + + fmt->colorspace = colorspace; + fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; + fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->quantization = V4L2_QUANTIZATION_DEFAULT; +} + +static int coda_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_dev *dev = ctx->dev; + const struct coda_q_data *q_data_dst; + const struct coda_codec *codec; + int ret; + + ret = coda_try_pixelformat(ctx, f); + if (ret < 0) + return ret; + + if (f->fmt.pix.colorspace == V4L2_COLORSPACE_DEFAULT) + coda_set_default_colorspace(&f->fmt.pix); + + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + codec = coda_find_codec(dev, f->fmt.pix.pixelformat, q_data_dst->fourcc); + + return coda_try_fmt(ctx, codec, f); +} + +static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, + struct v4l2_rect *r) +{ + struct coda_q_data *q_data; + struct vb2_queue *vq; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + if (vb2_is_busy(vq)) { + v4l2_err(&ctx->dev->v4l2_dev, "%s: %s queue busy: %d\n", + __func__, v4l2_type_names[f->type], vq->num_buffers); + return -EBUSY; + } + + q_data->fourcc = f->fmt.pix.pixelformat; + q_data->width = f->fmt.pix.width; + q_data->height = f->fmt.pix.height; + q_data->bytesperline = f->fmt.pix.bytesperline; + q_data->sizeimage = f->fmt.pix.sizeimage; + if (r) { + q_data->rect = *r; + } else { + q_data->rect.left = 0; + q_data->rect.top = 0; + q_data->rect.width = f->fmt.pix.width; + q_data->rect.height = f->fmt.pix.height; + } + + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_YUYV: + ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; + break; + case V4L2_PIX_FMT_NV12: + if (!disable_tiling && ctx->use_bit && + ctx->dev->devtype->product == CODA_960) { + ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; + break; + } + fallthrough; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV422P: + ctx->tiled_map_type = GDI_LINEAR_FRAME_MAP; + break; + default: + break; + } + + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP && + !coda_try_fmt_vdoa(ctx, f, &ctx->use_vdoa) && + ctx->use_vdoa) + vdoa_context_configure(ctx->vdoa, + round_up(f->fmt.pix.width, 16), + f->fmt.pix.height, + f->fmt.pix.pixelformat); + else + ctx->use_vdoa = false; + + coda_dbg(1, ctx, "Setting %s format, wxh: %dx%d, fmt: %4.4s %c\n", + v4l2_type_names[f->type], q_data->width, q_data->height, + (char *)&q_data->fourcc, + (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) ? 'L' : 'T'); + + return 0; +} + +static int coda_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_q_data *q_data_src; + const struct coda_codec *codec; + struct v4l2_rect r; + int hscale = 0; + int vscale = 0; + int ret; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + + if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && + ctx->dev->devtype->product == CODA_960) { + hscale = coda_jpeg_scale(q_data_src->width, f->fmt.pix.width); + vscale = coda_jpeg_scale(q_data_src->height, f->fmt.pix.height); + } + + ret = coda_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + r.left = 0; + r.top = 0; + r.width = q_data_src->width >> hscale; + r.height = q_data_src->height >> vscale; + + ret = coda_s_fmt(ctx, f, &r); + if (ret) + return ret; + + if (ctx->inst_type != CODA_INST_ENCODER) + return 0; + + /* Setting the coded format determines the selected codec */ + codec = coda_find_codec(ctx->dev, q_data_src->fourcc, + f->fmt.pix.pixelformat); + if (!codec) { + v4l2_err(&ctx->dev->v4l2_dev, "failed to determine codec\n"); + return -EINVAL; + } + ctx->codec = codec; + + ctx->colorspace = f->fmt.pix.colorspace; + ctx->xfer_func = f->fmt.pix.xfer_func; + ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; + ctx->quantization = f->fmt.pix.quantization; + + return 0; +} + +static int coda_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + const struct coda_codec *codec; + struct v4l2_format f_cap; + struct vb2_queue *dst_vq; + int ret; + + ret = coda_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + + ret = coda_s_fmt(ctx, f, NULL); + if (ret) + return ret; + + ctx->colorspace = f->fmt.pix.colorspace; + ctx->xfer_func = f->fmt.pix.xfer_func; + ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; + ctx->quantization = f->fmt.pix.quantization; + + if (ctx->inst_type != CODA_INST_DECODER) + return 0; + + /* Setting the coded format determines the selected codec */ + codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, + V4L2_PIX_FMT_YUV420); + if (!codec) { + v4l2_err(&ctx->dev->v4l2_dev, "failed to determine codec\n"); + return -EINVAL; + } + ctx->codec = codec; + + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!dst_vq) + return -EINVAL; + + /* + * Setting the capture queue format is not possible while the capture + * queue is still busy. This is not an error, but the user will have to + * make sure themselves that the capture format is set correctly before + * starting the output queue again. + */ + if (vb2_is_busy(dst_vq)) + return 0; + + memset(&f_cap, 0, sizeof(f_cap)); + f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + coda_g_fmt(file, priv, &f_cap); + f_cap.fmt.pix.width = f->fmt.pix.width; + f_cap.fmt.pix.height = f->fmt.pix.height; + + return coda_s_fmt_vid_cap(file, priv, &f_cap); +} + +static int coda_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + int ret; + + ret = v4l2_m2m_reqbufs(file, ctx->fh.m2m_ctx, rb); + if (ret) + return ret; + + /* + * Allow to allocate instance specific per-context buffers, such as + * bitstream ringbuffer, slice buffer, work buffer, etc. if needed. + */ + if (rb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && ctx->ops->reqbufs) + return ctx->ops->reqbufs(ctx, rb); + + return 0; +} + +static int coda_qbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + + if (ctx->inst_type == CODA_INST_DECODER && + buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + buf->flags &= ~V4L2_BUF_FLAG_LAST; + + return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf); +} + +static int coda_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + int ret; + + ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); + + if (ctx->inst_type == CODA_INST_DECODER && + buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + buf->flags &= ~V4L2_BUF_FLAG_LAST; + + return ret; +} + +void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, + enum vb2_buffer_state state) +{ + const struct v4l2_event eos_event = { + .type = V4L2_EVENT_EOS + }; + + if (buf->flags & V4L2_BUF_FLAG_LAST) + v4l2_event_queue_fh(&ctx->fh, &eos_event); + + v4l2_m2m_buf_done(buf, state); +} + +static int coda_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_q_data *q_data; + struct v4l2_rect r, *rsel; + + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; + + r.left = 0; + r.top = 0; + r.width = q_data->width; + r.height = q_data->height; + rsel = &q_data->rect; + + switch (s->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + rsel = &r; + fallthrough; + case V4L2_SEL_TGT_CROP: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || + ctx->inst_type == CODA_INST_DECODER) + return -EINVAL; + break; + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + rsel = &r; + fallthrough; + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + ctx->inst_type == CODA_INST_ENCODER) + return -EINVAL; + break; + default: + return -EINVAL; + } + + s->r = *rsel; + + return 0; +} + +static int coda_s_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_q_data *q_data; + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + if (ctx->inst_type == CODA_INST_ENCODER && + s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; + + s->r.left = 0; + s->r.top = 0; + s->r.width = clamp(s->r.width, 2U, q_data->width); + s->r.height = clamp(s->r.height, 2U, q_data->height); + + if (s->flags & V4L2_SEL_FLAG_LE) { + s->r.width = round_up(s->r.width, 2); + s->r.height = round_up(s->r.height, 2); + } else { + s->r.width = round_down(s->r.width, 2); + s->r.height = round_down(s->r.height, 2); + } + + q_data->rect = s->r; + + coda_dbg(1, ctx, "Setting crop rectangle: %dx%d\n", + s->r.width, s->r.height); + + return 0; + } + fallthrough; + case V4L2_SEL_TGT_NATIVE_SIZE: + case V4L2_SEL_TGT_COMPOSE: + return coda_g_selection(file, fh, s); + default: + /* v4l2-compliance expects this to fail for read-only targets */ + return -EINVAL; + } +} + +static void coda_wake_up_capture_queue(struct coda_ctx *ctx) +{ + struct vb2_queue *dst_vq; + + coda_dbg(1, ctx, "waking up capture queue\n"); + + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_vq->last_buffer_dequeued = true; + wake_up(&dst_vq->done_wq); +} + +static int coda_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *ec) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct vb2_v4l2_buffer *buf; + int ret; + + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); + if (ret < 0) + return ret; + + mutex_lock(&ctx->wakeup_mutex); + buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); + if (buf) { + /* + * If the last output buffer is still on the queue, make sure + * that decoder finish_run will see the last flag and report it + * to userspace. + */ + buf->flags |= V4L2_BUF_FLAG_LAST; + } else { + /* Set the stream-end flag on this context */ + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + + /* + * If the last output buffer has already been taken from the + * queue, wake up the capture queue and signal end of stream + * via the -EPIPE mechanism. + */ + coda_wake_up_capture_queue(ctx); + } + mutex_unlock(&ctx->wakeup_mutex); + + return 0; +} + +static bool coda_mark_last_meta(struct coda_ctx *ctx) +{ + struct coda_buffer_meta *meta; + + coda_dbg(1, ctx, "marking last meta\n"); + + spin_lock(&ctx->buffer_meta_lock); + if (list_empty(&ctx->buffer_meta_list)) { + spin_unlock(&ctx->buffer_meta_lock); + return false; + } + + meta = list_last_entry(&ctx->buffer_meta_list, struct coda_buffer_meta, + list); + meta->last = true; + + spin_unlock(&ctx->buffer_meta_lock); + return true; +} + +static bool coda_mark_last_dst_buf(struct coda_ctx *ctx) +{ + struct vb2_v4l2_buffer *buf; + struct vb2_buffer *dst_vb; + struct vb2_queue *dst_vq; + unsigned long flags; + + coda_dbg(1, ctx, "marking last capture buffer\n"); + + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + spin_lock_irqsave(&dst_vq->done_lock, flags); + if (list_empty(&dst_vq->done_list)) { + spin_unlock_irqrestore(&dst_vq->done_lock, flags); + return false; + } + + dst_vb = list_last_entry(&dst_vq->done_list, struct vb2_buffer, + done_entry); + buf = to_vb2_v4l2_buffer(dst_vb); + buf->flags |= V4L2_BUF_FLAG_LAST; + + spin_unlock_irqrestore(&dst_vq->done_lock, flags); + return true; +} + +static int coda_decoder_cmd(struct file *file, void *fh, + struct v4l2_decoder_cmd *dc) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_dev *dev = ctx->dev; + struct vb2_v4l2_buffer *buf; + struct vb2_queue *dst_vq; + bool stream_end; + bool wakeup; + int ret; + + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); + if (ret < 0) + return ret; + + switch (dc->cmd) { + case V4L2_DEC_CMD_START: + mutex_lock(&dev->coda_mutex); + mutex_lock(&ctx->bitstream_mutex); + coda_bitstream_flush(ctx); + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + vb2_clear_last_buffer_dequeued(dst_vq); + ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; + coda_fill_bitstream(ctx, NULL); + mutex_unlock(&ctx->bitstream_mutex); + mutex_unlock(&dev->coda_mutex); + break; + case V4L2_DEC_CMD_STOP: + stream_end = false; + wakeup = false; + + mutex_lock(&ctx->wakeup_mutex); + + buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); + if (buf) { + coda_dbg(1, ctx, "marking last pending buffer\n"); + + /* Mark last buffer */ + buf->flags |= V4L2_BUF_FLAG_LAST; + + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) == 0) { + coda_dbg(1, ctx, "all remaining buffers queued\n"); + stream_end = true; + } + } else { + if (ctx->use_bit) + if (coda_mark_last_meta(ctx)) + stream_end = true; + else + wakeup = true; + else + if (!coda_mark_last_dst_buf(ctx)) + wakeup = true; + } + + if (stream_end) { + coda_dbg(1, ctx, "all remaining buffers queued\n"); + + /* Set the stream-end flag on this context */ + coda_bit_stream_end_flag(ctx); + ctx->hold = false; + v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); + } + + if (wakeup) { + /* If there is no buffer in flight, wake up */ + coda_wake_up_capture_queue(ctx); + } + + mutex_unlock(&ctx->wakeup_mutex); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int coda_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_q_data *q_data_dst; + const struct coda_codec *codec; + + if (fsize->index) + return -EINVAL; + + if (coda_format_normalize_yuv(fsize->pixel_format) == + V4L2_PIX_FMT_YUV420) { + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + codec = coda_find_codec(ctx->dev, fsize->pixel_format, + q_data_dst->fourcc); + } else { + codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, + fsize->pixel_format); + } + if (!codec) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = MIN_W; + fsize->stepwise.max_width = codec->max_w; + fsize->stepwise.step_width = 1; + fsize->stepwise.min_height = MIN_H; + fsize->stepwise.max_height = codec->max_h; + fsize->stepwise.step_height = 1; + + return 0; +} + +static int coda_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *f) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_q_data *q_data; + const struct coda_codec *codec; + + if (f->index) + return -EINVAL; + + /* Disallow YUYV if the vdoa is not available */ + if (!ctx->vdoa && f->pixel_format == V4L2_PIX_FMT_YUYV) + return -EINVAL; + + if (coda_format_normalize_yuv(f->pixel_format) == V4L2_PIX_FMT_YUV420) { + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + codec = coda_find_codec(ctx->dev, f->pixel_format, + q_data->fourcc); + } else { + codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, + f->pixel_format); + } + if (!codec) + return -EINVAL; + + if (f->width < MIN_W || f->width > codec->max_w || + f->height < MIN_H || f->height > codec->max_h) + return -EINVAL; + + f->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; + f->stepwise.min.numerator = 1; + f->stepwise.min.denominator = 65535; + f->stepwise.max.numerator = 65536; + f->stepwise.max.denominator = 1; + f->stepwise.step.numerator = 1; + f->stepwise.step.denominator = 1; + + return 0; +} + +static int coda_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct v4l2_fract *tpf; + + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + tpf = &a->parm.output.timeperframe; + tpf->denominator = ctx->params.framerate & CODA_FRATE_RES_MASK; + tpf->numerator = 1 + (ctx->params.framerate >> + CODA_FRATE_DIV_OFFSET); + + return 0; +} + +/* + * Approximate timeperframe v4l2_fract with values that can be written + * into the 16-bit CODA_FRATE_DIV and CODA_FRATE_RES fields. + */ +static void coda_approximate_timeperframe(struct v4l2_fract *timeperframe) +{ + struct v4l2_fract s = *timeperframe; + struct v4l2_fract f0; + struct v4l2_fract f1 = { 1, 0 }; + struct v4l2_fract f2 = { 0, 1 }; + unsigned int i, div, s_denominator; + + /* Lower bound is 1/65535 */ + if (s.numerator == 0 || s.denominator / s.numerator > 65535) { + timeperframe->numerator = 1; + timeperframe->denominator = 65535; + return; + } + + /* Upper bound is 65536/1 */ + if (s.denominator == 0 || s.numerator / s.denominator > 65536) { + timeperframe->numerator = 65536; + timeperframe->denominator = 1; + return; + } + + /* Reduce fraction to lowest terms */ + div = gcd(s.numerator, s.denominator); + if (div > 1) { + s.numerator /= div; + s.denominator /= div; + } + + if (s.numerator <= 65536 && s.denominator < 65536) { + *timeperframe = s; + return; + } + + /* Find successive convergents from continued fraction expansion */ + while (f2.numerator <= 65536 && f2.denominator < 65536) { + f0 = f1; + f1 = f2; + + /* Stop when f2 exactly equals timeperframe */ + if (s.numerator == 0) + break; + + i = s.denominator / s.numerator; + + f2.numerator = f0.numerator + i * f1.numerator; + f2.denominator = f0.denominator + i * f2.denominator; + + s_denominator = s.numerator; + s.numerator = s.denominator % s.numerator; + s.denominator = s_denominator; + } + + *timeperframe = f1; +} + +static uint32_t coda_timeperframe_to_frate(struct v4l2_fract *timeperframe) +{ + return ((timeperframe->numerator - 1) << CODA_FRATE_DIV_OFFSET) | + timeperframe->denominator; +} + +static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct v4l2_fract *tpf; + + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + tpf = &a->parm.output.timeperframe; + coda_approximate_timeperframe(tpf); + ctx->params.framerate = coda_timeperframe_to_frate(tpf); + ctx->params.framerate_changed = true; + + return 0; +} + +static int coda_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + if (ctx->inst_type == CODA_INST_DECODER) + return v4l2_event_subscribe(fh, sub, 0, NULL); + else + return -EINVAL; + default: + return v4l2_ctrl_subscribe_event(fh, sub); + } +} + +static const struct v4l2_ioctl_ops coda_ioctl_ops = { + .vidioc_querycap = coda_querycap, + + .vidioc_enum_fmt_vid_cap = coda_enum_fmt, + .vidioc_g_fmt_vid_cap = coda_g_fmt, + .vidioc_try_fmt_vid_cap = coda_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = coda_s_fmt_vid_cap, + + .vidioc_enum_fmt_vid_out = coda_enum_fmt, + .vidioc_g_fmt_vid_out = coda_g_fmt, + .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out, + .vidioc_s_fmt_vid_out = coda_s_fmt_vid_out, + + .vidioc_reqbufs = coda_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + + .vidioc_qbuf = coda_qbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_dqbuf = coda_dqbuf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_g_selection = coda_g_selection, + .vidioc_s_selection = coda_s_selection, + + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = coda_encoder_cmd, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, + .vidioc_decoder_cmd = coda_decoder_cmd, + + .vidioc_g_parm = coda_g_parm, + .vidioc_s_parm = coda_s_parm, + + .vidioc_enum_framesizes = coda_enum_framesizes, + .vidioc_enum_frameintervals = coda_enum_frameintervals, + + .vidioc_subscribe_event = coda_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +/* + * Mem-to-mem operations. + */ + +static void coda_device_run(void *m2m_priv) +{ + struct coda_ctx *ctx = m2m_priv; + struct coda_dev *dev = ctx->dev; + + queue_work(dev->workqueue, &ctx->pic_run_work); +} + +static void coda_pic_run_work(struct work_struct *work) +{ + struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work); + struct coda_dev *dev = ctx->dev; + int ret; + + mutex_lock(&ctx->buffer_mutex); + mutex_lock(&dev->coda_mutex); + + ret = ctx->ops->prepare_run(ctx); + if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) + goto out; + + if (!wait_for_completion_timeout(&ctx->completion, + msecs_to_jiffies(1000))) { + if (ctx->use_bit) { + dev_err(dev->dev, "CODA PIC_RUN timeout\n"); + + ctx->hold = true; + + coda_hw_reset(ctx); + } + + if (ctx->ops->run_timeout) + ctx->ops->run_timeout(ctx); + } else { + ctx->ops->finish_run(ctx); + } + + if ((ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) && + ctx->ops->seq_end_work) + queue_work(dev->workqueue, &ctx->seq_end_work); + +out: + mutex_unlock(&dev->coda_mutex); + mutex_unlock(&ctx->buffer_mutex); + + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); +} + +static int coda_job_ready(void *m2m_priv) +{ + struct coda_ctx *ctx = m2m_priv; + int src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx); + + /* + * For both 'P' and 'key' frame cases 1 picture + * and 1 frame are needed. In the decoder case, + * the compressed frame can be in the bitstream. + */ + if (!src_bufs && ctx->inst_type != CODA_INST_DECODER) { + coda_dbg(1, ctx, "not ready: not enough vid-out buffers.\n"); + return 0; + } + + if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) { + coda_dbg(1, ctx, "not ready: not enough vid-cap buffers.\n"); + return 0; + } + + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { + bool stream_end = ctx->bit_stream_param & + CODA_BIT_STREAM_END_FLAG; + int num_metas = ctx->num_metas; + struct coda_buffer_meta *meta; + unsigned int count; + + count = hweight32(ctx->frm_dis_flg); + if (ctx->use_vdoa && count >= (ctx->num_internal_frames - 1)) { + coda_dbg(1, ctx, + "not ready: all internal buffers in use: %d/%d (0x%x)", + count, ctx->num_internal_frames, + ctx->frm_dis_flg); + return 0; + } + + if (ctx->hold && !src_bufs) { + coda_dbg(1, ctx, + "not ready: on hold for more buffers.\n"); + return 0; + } + + if (!stream_end && (num_metas + src_bufs) < 2) { + coda_dbg(1, ctx, + "not ready: need 2 buffers available (queue:%d + bitstream:%d)\n", + num_metas, src_bufs); + return 0; + } + + meta = list_first_entry(&ctx->buffer_meta_list, + struct coda_buffer_meta, list); + if (!coda_bitstream_can_fetch_past(ctx, meta->end) && + !stream_end) { + coda_dbg(1, ctx, + "not ready: not enough bitstream data to read past %u (%u)\n", + meta->end, ctx->bitstream_fifo.kfifo.in); + return 0; + } + } + + if (ctx->aborting) { + coda_dbg(1, ctx, "not ready: aborting\n"); + return 0; + } + + coda_dbg(2, ctx, "job ready\n"); + + return 1; +} + +static void coda_job_abort(void *priv) +{ + struct coda_ctx *ctx = priv; + + ctx->aborting = 1; + + coda_dbg(1, ctx, "job abort\n"); +} + +static const struct v4l2_m2m_ops coda_m2m_ops = { + .device_run = coda_device_run, + .job_ready = coda_job_ready, + .job_abort = coda_job_abort, +}; + +static void set_default_params(struct coda_ctx *ctx) +{ + unsigned int max_w, max_h, usize, csize; + + ctx->codec = coda_find_codec(ctx->dev, ctx->cvd->src_formats[0], + ctx->cvd->dst_formats[0]); + max_w = min(ctx->codec->max_w, 1920U); + max_h = min(ctx->codec->max_h, 1088U); + usize = max_w * max_h * 3 / 2; + csize = coda_estimate_sizeimage(ctx, usize, max_w, max_h); + + ctx->params.codec_mode = ctx->codec->mode; + if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_JPEG || + ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG) { + ctx->colorspace = V4L2_COLORSPACE_SRGB; + ctx->xfer_func = V4L2_XFER_FUNC_SRGB; + ctx->ycbcr_enc = V4L2_YCBCR_ENC_601; + ctx->quantization = V4L2_QUANTIZATION_FULL_RANGE; + } else { + ctx->colorspace = V4L2_COLORSPACE_REC709; + ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; + ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + ctx->quantization = V4L2_QUANTIZATION_DEFAULT; + } + ctx->params.framerate = 30; + + /* Default formats for output and input queues */ + ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->cvd->src_formats[0]; + ctx->q_data[V4L2_M2M_DST].fourcc = ctx->cvd->dst_formats[0]; + ctx->q_data[V4L2_M2M_SRC].width = max_w; + ctx->q_data[V4L2_M2M_SRC].height = max_h; + ctx->q_data[V4L2_M2M_DST].width = max_w; + ctx->q_data[V4L2_M2M_DST].height = max_h; + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) { + ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w; + ctx->q_data[V4L2_M2M_SRC].sizeimage = usize; + ctx->q_data[V4L2_M2M_DST].bytesperline = 0; + ctx->q_data[V4L2_M2M_DST].sizeimage = csize; + } else { + ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; + ctx->q_data[V4L2_M2M_SRC].sizeimage = csize; + ctx->q_data[V4L2_M2M_DST].bytesperline = max_w; + ctx->q_data[V4L2_M2M_DST].sizeimage = usize; + } + ctx->q_data[V4L2_M2M_SRC].rect.width = max_w; + ctx->q_data[V4L2_M2M_SRC].rect.height = max_h; + ctx->q_data[V4L2_M2M_DST].rect.width = max_w; + ctx->q_data[V4L2_M2M_DST].rect.height = max_h; + + /* + * Since the RBC2AXI logic only supports a single chroma plane, + * macroblock tiling only works for to NV12 pixel format. + */ + ctx->tiled_map_type = GDI_LINEAR_FRAME_MAP; +} + +/* + * Queue operations + */ +static int coda_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(vq); + struct coda_q_data *q_data; + unsigned int size; + + q_data = get_q_data(ctx, vq->type); + size = q_data->sizeimage; + + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + + *nplanes = 1; + sizes[0] = size; + + coda_dbg(1, ctx, "get %d buffer(s) of size %d each.\n", *nbuffers, + size); + + return 0; +} + +static int coda_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct coda_q_data *q_data; + + q_data = get_q_data(ctx, vb->vb2_queue->type); + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + if (vbuf->field == V4L2_FIELD_ANY) + vbuf->field = V4L2_FIELD_NONE; + if (vbuf->field != V4L2_FIELD_NONE) { + v4l2_warn(&ctx->dev->v4l2_dev, + "%s field isn't supported\n", __func__); + return -EINVAL; + } + } + + if (vb2_plane_size(vb, 0) < q_data->sizeimage) { + v4l2_warn(&ctx->dev->v4l2_dev, + "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), + (long)q_data->sizeimage); + return -EINVAL; + } + + return 0; +} + +static void coda_update_menu_ctrl(struct v4l2_ctrl *ctrl, int value) +{ + if (!ctrl) + return; + + v4l2_ctrl_lock(ctrl); + + /* + * Extend the control range if the parsed stream contains a known but + * unsupported value or level. + */ + if (value > ctrl->maximum) { + __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, value, + ctrl->menu_skip_mask & ~(1 << value), + ctrl->default_value); + } else if (value < ctrl->minimum) { + __v4l2_ctrl_modify_range(ctrl, value, ctrl->maximum, + ctrl->menu_skip_mask & ~(1 << value), + ctrl->default_value); + } + + __v4l2_ctrl_s_ctrl(ctrl, value); + + v4l2_ctrl_unlock(ctrl); +} + +void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, + u8 level_idc) +{ + const char * const *profile_names; + const char * const *level_names; + struct v4l2_ctrl *profile_ctrl; + struct v4l2_ctrl *level_ctrl; + const char *codec_name; + u32 profile_cid; + u32 level_cid; + int profile; + int level; + + switch (ctx->codec->src_fourcc) { + case V4L2_PIX_FMT_H264: + codec_name = "H264"; + profile_cid = V4L2_CID_MPEG_VIDEO_H264_PROFILE; + level_cid = V4L2_CID_MPEG_VIDEO_H264_LEVEL; + profile_ctrl = ctx->h264_profile_ctrl; + level_ctrl = ctx->h264_level_ctrl; + profile = coda_h264_profile(profile_idc); + level = coda_h264_level(level_idc); + break; + case V4L2_PIX_FMT_MPEG2: + codec_name = "MPEG-2"; + profile_cid = V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE; + level_cid = V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL; + profile_ctrl = ctx->mpeg2_profile_ctrl; + level_ctrl = ctx->mpeg2_level_ctrl; + profile = coda_mpeg2_profile(profile_idc); + level = coda_mpeg2_level(level_idc); + break; + case V4L2_PIX_FMT_MPEG4: + codec_name = "MPEG-4"; + profile_cid = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE; + level_cid = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL; + profile_ctrl = ctx->mpeg4_profile_ctrl; + level_ctrl = ctx->mpeg4_level_ctrl; + profile = coda_mpeg4_profile(profile_idc); + level = coda_mpeg4_level(level_idc); + break; + default: + return; + } + + profile_names = v4l2_ctrl_get_menu(profile_cid); + level_names = v4l2_ctrl_get_menu(level_cid); + + if (profile < 0) { + v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s profile: %u\n", + codec_name, profile_idc); + } else { + coda_dbg(1, ctx, "Parsed %s profile: %s\n", codec_name, + profile_names[profile]); + coda_update_menu_ctrl(profile_ctrl, profile); + } + + if (level < 0) { + v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s level: %u\n", + codec_name, level_idc); + } else { + coda_dbg(1, ctx, "Parsed %s level: %s\n", codec_name, + level_names[level]); + coda_update_menu_ctrl(level_ctrl, level); + } +} + +static void coda_queue_source_change_event(struct coda_ctx *ctx) +{ + static const struct v4l2_event source_change_event = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + v4l2_event_queue_fh(&ctx->fh, &source_change_event); +} + +static void coda_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_queue *vq = vb->vb2_queue; + struct coda_q_data *q_data; + + q_data = get_q_data(ctx, vb->vb2_queue->type); + + /* + * In the decoder case, immediately try to copy the buffer into the + * bitstream ringbuffer and mark it as ready to be dequeued. + */ + if (ctx->bitstream.size && vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + /* + * For backwards compatibility, queuing an empty buffer marks + * the stream end + */ + if (vb2_get_plane_payload(vb, 0) == 0) + coda_bit_stream_end_flag(ctx); + + if (q_data->fourcc == V4L2_PIX_FMT_H264) { + /* + * Unless already done, try to obtain profile_idc and + * level_idc from the SPS header. This allows to decide + * whether to enable reordering during sequence + * initialization. + */ + if (!ctx->params.h264_profile_idc) { + coda_sps_parse_profile(ctx, vb); + coda_update_profile_level_ctrls(ctx, + ctx->params.h264_profile_idc, + ctx->params.h264_level_idc); + } + } + + mutex_lock(&ctx->bitstream_mutex); + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + if (vb2_is_streaming(vb->vb2_queue)) + /* This set buf->sequence = ctx->qsequence++ */ + coda_fill_bitstream(ctx, NULL); + mutex_unlock(&ctx->bitstream_mutex); + + if (!ctx->initialized) { + /* + * Run sequence initialization in case the queued + * buffer contained headers. + */ + if (vb2_is_streaming(vb->vb2_queue) && + ctx->ops->seq_init_work) { + queue_work(ctx->dev->workqueue, + &ctx->seq_init_work); + flush_work(&ctx->seq_init_work); + } + + if (ctx->initialized) + coda_queue_source_change_event(ctx); + } + } else { + if ((ctx->inst_type == CODA_INST_ENCODER || !ctx->use_bit) && + vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + vbuf->sequence = ctx->qsequence++; + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + } +} + +int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, + size_t size, const char *name, struct dentry *parent) +{ + buf->vaddr = dma_alloc_coherent(dev->dev, size, &buf->paddr, + GFP_KERNEL); + if (!buf->vaddr) { + v4l2_err(&dev->v4l2_dev, + "Failed to allocate %s buffer of size %zu\n", + name, size); + return -ENOMEM; + } + + buf->size = size; + + if (name && parent) { + buf->blob.data = buf->vaddr; + buf->blob.size = size; + buf->dentry = debugfs_create_blob(name, 0444, parent, + &buf->blob); + } + + return 0; +} + +void coda_free_aux_buf(struct coda_dev *dev, + struct coda_aux_buf *buf) +{ + if (buf->vaddr) { + dma_free_coherent(dev->dev, buf->size, buf->vaddr, buf->paddr); + buf->vaddr = NULL; + buf->size = 0; + debugfs_remove(buf->dentry); + buf->dentry = NULL; + } +} + +static int coda_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(q); + struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; + struct coda_q_data *q_data_src, *q_data_dst; + struct v4l2_m2m_buffer *m2m_buf, *tmp; + struct vb2_v4l2_buffer *buf; + struct list_head list; + int ret = 0; + + if (count < 1) + return -EINVAL; + + coda_dbg(1, ctx, "start streaming %s\n", v4l2_type_names[q->type]); + + INIT_LIST_HEAD(&list); + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { + /* copy the buffers that were queued before streamon */ + mutex_lock(&ctx->bitstream_mutex); + coda_fill_bitstream(ctx, &list); + mutex_unlock(&ctx->bitstream_mutex); + + if (ctx->dev->devtype->product != CODA_960 && + coda_get_bitstream_payload(ctx) < 512) { + v4l2_err(v4l2_dev, "start payload < 512\n"); + ret = -EINVAL; + goto err; + } + + if (!ctx->initialized) { + /* Run sequence initialization */ + if (ctx->ops->seq_init_work) { + queue_work(ctx->dev->workqueue, + &ctx->seq_init_work); + flush_work(&ctx->seq_init_work); + } + } + } + + /* + * Check the first input JPEG buffer to determine chroma + * subsampling. + */ + if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) { + buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + coda_jpeg_decode_header(ctx, &buf->vb2_buf); + /* + * We have to start streaming even if the first buffer + * does not contain a valid JPEG image. The error will + * be caught during device run and will be signalled + * via the capture buffer error flag. + */ + + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + q_data_dst->width = round_up(q_data_src->width, 16); + q_data_dst->height = round_up(q_data_src->height, 16); + q_data_dst->bytesperline = q_data_dst->width; + if (ctx->params.jpeg_chroma_subsampling == + V4L2_JPEG_CHROMA_SUBSAMPLING_420) { + q_data_dst->sizeimage = + q_data_dst->bytesperline * + q_data_dst->height * 3 / 2; + if (q_data_dst->fourcc != V4L2_PIX_FMT_YUV420) + q_data_dst->fourcc = V4L2_PIX_FMT_NV12; + } else { + q_data_dst->sizeimage = + q_data_dst->bytesperline * + q_data_dst->height * 2; + q_data_dst->fourcc = V4L2_PIX_FMT_YUV422P; + } + q_data_dst->rect.left = 0; + q_data_dst->rect.top = 0; + q_data_dst->rect.width = q_data_src->width; + q_data_dst->rect.height = q_data_src->height; + } + ctx->streamon_out = 1; + } else { + ctx->streamon_cap = 1; + } + + /* Don't start the coda unless both queues are on */ + if (!(ctx->streamon_out && ctx->streamon_cap)) + goto out; + + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if ((q_data_src->rect.width != q_data_dst->width && + round_up(q_data_src->rect.width, 16) != q_data_dst->width) || + (q_data_src->rect.height != q_data_dst->height && + round_up(q_data_src->rect.height, 16) != q_data_dst->height)) { + v4l2_err(v4l2_dev, "can't convert %dx%d to %dx%d\n", + q_data_src->rect.width, q_data_src->rect.height, + q_data_dst->width, q_data_dst->height); + ret = -EINVAL; + goto err; + } + + /* Allow BIT decoder device_run with no new buffers queued */ + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) + v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); + + ctx->gopcounter = ctx->params.gop_size - 1; + + if (q_data_dst->fourcc == V4L2_PIX_FMT_JPEG) + ctx->params.gop_size = 1; + ctx->gopcounter = ctx->params.gop_size - 1; + /* Only decoders have this control */ + if (ctx->mb_err_cnt_ctrl) + v4l2_ctrl_s_ctrl(ctx->mb_err_cnt_ctrl, 0); + + ret = ctx->ops->start_streaming(ctx); + if (ctx->inst_type == CODA_INST_DECODER) { + if (ret == -EAGAIN) + goto out; + } + if (ret < 0) + goto err; + +out: + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + list_for_each_entry_safe(m2m_buf, tmp, &list, list) { + list_del(&m2m_buf->list); + v4l2_m2m_buf_done(&m2m_buf->vb, VB2_BUF_STATE_DONE); + } + } + return 0; + +err: + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + list_for_each_entry_safe(m2m_buf, tmp, &list, list) { + list_del(&m2m_buf->list); + v4l2_m2m_buf_done(&m2m_buf->vb, VB2_BUF_STATE_QUEUED); + } + while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); + } else { + while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); + } + return ret; +} + +static void coda_stop_streaming(struct vb2_queue *q) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(q); + struct coda_dev *dev = ctx->dev; + struct vb2_v4l2_buffer *buf; + bool stop; + + stop = ctx->streamon_out && ctx->streamon_cap; + + coda_dbg(1, ctx, "stop streaming %s\n", v4l2_type_names[q->type]); + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ctx->streamon_out = 0; + + coda_bit_stream_end_flag(ctx); + + ctx->qsequence = 0; + + while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + } else { + ctx->streamon_cap = 0; + + ctx->osequence = 0; + ctx->sequence_offset = 0; + + while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + } + + if (stop) { + struct coda_buffer_meta *meta; + + if (ctx->ops->seq_end_work) { + queue_work(dev->workqueue, &ctx->seq_end_work); + flush_work(&ctx->seq_end_work); + } + spin_lock(&ctx->buffer_meta_lock); + while (!list_empty(&ctx->buffer_meta_list)) { + meta = list_first_entry(&ctx->buffer_meta_list, + struct coda_buffer_meta, list); + list_del(&meta->list); + kfree(meta); + } + ctx->num_metas = 0; + spin_unlock(&ctx->buffer_meta_lock); + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + ctx->runcounter = 0; + ctx->aborting = 0; + ctx->hold = false; + } + + if (!ctx->streamon_out && !ctx->streamon_cap) + ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; +} + +static const struct vb2_ops coda_qops = { + .queue_setup = coda_queue_setup, + .buf_prepare = coda_buf_prepare, + .buf_queue = coda_buf_queue, + .start_streaming = coda_start_streaming, + .stop_streaming = coda_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int coda_s_ctrl(struct v4l2_ctrl *ctrl) +{ + const char * const *val_names = v4l2_ctrl_get_menu(ctrl->id); + struct coda_ctx *ctx = + container_of(ctrl->handler, struct coda_ctx, ctrls); + + if (val_names) + coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d (\"%s\")\n", + ctrl->id, ctrl->name, ctrl->val, val_names[ctrl->val]); + else + coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n", + ctrl->id, ctrl->name, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + if (ctrl->val) + ctx->params.rot_mode |= CODA_MIR_HOR; + else + ctx->params.rot_mode &= ~CODA_MIR_HOR; + break; + case V4L2_CID_VFLIP: + if (ctrl->val) + ctx->params.rot_mode |= CODA_MIR_VER; + else + ctx->params.rot_mode &= ~CODA_MIR_VER; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + ctx->params.bitrate = ctrl->val / 1000; + ctx->params.bitrate_changed = true; + break; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + ctx->params.gop_size = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: + ctx->params.h264_intra_qp = ctrl->val; + ctx->params.h264_intra_qp_changed = true; + break; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: + ctx->params.h264_inter_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: + ctx->params.h264_min_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: + ctx->params.h264_max_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: + ctx->params.h264_slice_alpha_c0_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: + ctx->params.h264_slice_beta_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + ctx->params.h264_disable_deblocking_filter_idc = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: + ctx->params.h264_constrained_intra_pred_flag = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: + ctx->params.frame_rc_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: + ctx->params.mb_rc_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: + ctx->params.h264_chroma_qp_index_offset = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + /* TODO: switch between baseline and constrained baseline */ + if (ctx->inst_type == CODA_INST_ENCODER) + ctx->params.h264_profile_idc = 66; + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + /* nothing to do, this is set by the encoder */ + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: + ctx->params.mpeg4_intra_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: + ctx->params.mpeg4_inter_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: + case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: + case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: + /* nothing to do, these are fixed */ + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: + ctx->params.slice_mode = ctrl->val; + ctx->params.slice_mode_changed = true; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: + ctx->params.slice_max_mb = ctrl->val; + ctx->params.slice_mode_changed = true; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: + ctx->params.slice_max_bits = ctrl->val * 8; + ctx->params.slice_mode_changed = true; + break; + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: + break; + case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: + ctx->params.intra_refresh = ctrl->val; + ctx->params.intra_refresh_changed = true; + break; + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: + ctx->params.force_ipicture = true; + break; + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + coda_set_jpeg_compression_quality(ctx, ctrl->val); + break; + case V4L2_CID_JPEG_RESTART_INTERVAL: + ctx->params.jpeg_restart_interval = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VBV_DELAY: + ctx->params.vbv_delay = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VBV_SIZE: + ctx->params.vbv_size = min(ctrl->val * 8192, 0x7fffffff); + break; + default: + coda_dbg(1, ctx, "Invalid control, id=%d, val=%d\n", + ctrl->id, ctrl->val); + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops coda_ctrl_ops = { + .s_ctrl = coda_s_ctrl, +}; + +static void coda_encode_ctrls(struct coda_ctx *ctx) +{ + int max_gop_size = (ctx->dev->devtype->product == CODA_DX6) ? 60 : 99; + + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1000, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, max_gop_size, 1, 16); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25); + if (ctx->dev->devtype->product != CODA_960) { + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12); + } + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, -6, 6, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, -6, 6, 1, 0); + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, + 0x0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION, 0, 1, 1, + 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, 0, 1, 1, 1); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, 0, 1, 1, 1); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0); + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE, 0x0, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE); + if (ctx->dev->devtype->product == CODA_HX4 || + ctx->dev->devtype->product == CODA_7541) { + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + V4L2_MPEG_VIDEO_H264_LEVEL_3_1, + ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1)), + V4L2_MPEG_VIDEO_H264_LEVEL_3_1); + } + if (ctx->dev->devtype->product == CODA_960) { + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + V4L2_MPEG_VIDEO_H264_LEVEL_4_2, + ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2)), + V4L2_MPEG_VIDEO_H264_LEVEL_4_0); + } + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2); + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, + V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, 0x0, + V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE); + if (ctx->dev->devtype->product == CODA_HX4 || + ctx->dev->devtype->product == CODA_7541 || + ctx->dev->devtype->product == CODA_960) { + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, + V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, + ~(1 << V4L2_MPEG_VIDEO_MPEG4_LEVEL_5), + V4L2_MPEG_VIDEO_MPEG4_LEVEL_5); + } + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, 0x0, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, + 500); + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE), + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, + 1920 * 1088 / 256, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, 0, 0x7fff, 1, 0); + /* + * The maximum VBV size value is 0x7fffffff bits, + * one bit less than 262144 KiB + */ + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VBV_SIZE, 0, 262144, 1, 0); +} + +static void coda_jpeg_encode_ctrls(struct coda_ctx *ctx) +{ + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, 5, 100, 1, 50); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_JPEG_RESTART_INTERVAL, 0, 100, 1, 0); +} + +static void coda_decode_ctrls(struct coda_ctx *ctx) +{ + u8 max; + + ctx->h264_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); + if (ctx->h264_profile_ctrl) + ctx->h264_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + if (ctx->dev->devtype->product == CODA_HX4 || + ctx->dev->devtype->product == CODA_7541) + max = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; + else if (ctx->dev->devtype->product == CODA_960) + max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1; + else + return; + ctx->h264_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, 0, max); + if (ctx->h264_level_ctrl) + ctx->h264_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctx->mpeg2_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE, + V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH, 0, + V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH); + if (ctx->mpeg2_profile_ctrl) + ctx->mpeg2_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctx->mpeg2_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL, + V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH, 0, + V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH); + if (ctx->mpeg2_level_ctrl) + ctx->mpeg2_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctx->mpeg4_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, + V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY, 0, + V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY); + if (ctx->mpeg4_profile_ctrl) + ctx->mpeg4_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctx->mpeg4_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, + V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, 0, + V4L2_MPEG_VIDEO_MPEG4_LEVEL_5); + if (ctx->mpeg4_level_ctrl) + ctx->mpeg4_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; +} + +static const struct v4l2_ctrl_config coda_mb_err_cnt_ctrl_config = { + .id = V4L2_CID_CODA_MB_ERR_CNT, + .name = "Macroblocks Error Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 0x7fffffff, + .step = 1, +}; + +static int coda_ctrls_setup(struct coda_ctx *ctx) +{ + v4l2_ctrl_handler_init(&ctx->ctrls, 2); + + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + if (ctx->inst_type == CODA_INST_ENCODER) { + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 1, 1, 1, 1); + if (ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG) + coda_jpeg_encode_ctrls(ctx); + else + coda_encode_ctrls(ctx); + } else { + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + 1, 1, 1, 1); + if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_H264) + coda_decode_ctrls(ctx); + + ctx->mb_err_cnt_ctrl = v4l2_ctrl_new_custom(&ctx->ctrls, + &coda_mb_err_cnt_ctrl_config, + NULL); + if (ctx->mb_err_cnt_ctrl) + ctx->mb_err_cnt_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + } + + if (ctx->ctrls.error) { + v4l2_err(&ctx->dev->v4l2_dev, + "control initialization error (%d)", + ctx->ctrls.error); + return -EINVAL; + } + + return v4l2_ctrl_handler_setup(&ctx->ctrls); +} + +static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) +{ + vq->drv_priv = ctx; + vq->ops = &coda_qops; + vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + vq->lock = &ctx->dev->dev_mutex; + /* One way to indicate end-of-stream for coda is to set the + * bytesused == 0. However by default videobuf2 handles bytesused + * equal to 0 as a special case and changes its value to the size + * of the buffer. Set the allow_zero_bytesused flag, so + * that videobuf2 will keep the value of bytesused intact. + */ + vq->allow_zero_bytesused = 1; + /* + * We might be fine with no buffers on some of the queues, but that + * would need to be reflected in job_ready(). Currently we expect all + * queues to have at least one buffer queued. + */ + vq->min_buffers_needed = 1; + vq->dev = ctx->dev->dev; + + return vb2_queue_init(vq); +} + +int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP; + src_vq->mem_ops = &vb2_dma_contig_memops; + + ret = coda_queue_init(priv, src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; + dst_vq->mem_ops = &vb2_dma_contig_memops; + + return coda_queue_init(priv, dst_vq); +} + +int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; + src_vq->mem_ops = &vb2_vmalloc_memops; + + ret = coda_queue_init(priv, src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; + dst_vq->dma_attrs = DMA_ATTR_NO_KERNEL_MAPPING; + dst_vq->mem_ops = &vb2_dma_contig_memops; + + return coda_queue_init(priv, dst_vq); +} + +/* + * File operations + */ + +static int coda_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct coda_dev *dev = video_get_drvdata(vdev); + struct coda_ctx *ctx; + unsigned int max = ~0; + char *name; + int ret; + int idx; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (dev->devtype->product == CODA_DX6) + max = CODADX6_MAX_INSTANCES - 1; + idx = ida_alloc_max(&dev->ida, max, GFP_KERNEL); + if (idx < 0) { + ret = idx; + goto err_coda_max; + } + + name = kasprintf(GFP_KERNEL, "context%d", idx); + if (!name) { + ret = -ENOMEM; + goto err_coda_name_init; + } + + ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); + kfree(name); + + ctx->cvd = to_coda_video_device(vdev); + ctx->inst_type = ctx->cvd->type; + ctx->ops = ctx->cvd->ops; + ctx->use_bit = !ctx->cvd->direct; + init_completion(&ctx->completion); + INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); + if (ctx->ops->seq_init_work) + INIT_WORK(&ctx->seq_init_work, ctx->ops->seq_init_work); + if (ctx->ops->seq_end_work) + INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + ctx->dev = dev; + ctx->idx = idx; + + coda_dbg(1, ctx, "open instance (%p)\n", ctx); + + switch (dev->devtype->product) { + case CODA_960: + /* + * Enabling the BWB when decoding can hang the firmware with + * certain streams. The issue was tracked as ENGR00293425 by + * Freescale. As a workaround, disable BWB for all decoders. + * The enable_bwb module parameter allows to override this. + */ + if (enable_bwb || ctx->inst_type == CODA_INST_ENCODER) + ctx->frame_mem_ctrl = CODA9_FRAME_ENABLE_BWB; + fallthrough; + case CODA_HX4: + case CODA_7541: + ctx->reg_idx = 0; + break; + default: + ctx->reg_idx = idx; + } + if (ctx->dev->vdoa && !disable_vdoa) { + ctx->vdoa = vdoa_context_create(dev->vdoa); + if (!ctx->vdoa) + v4l2_warn(&dev->v4l2_dev, + "Failed to create vdoa context: not using vdoa"); + } + ctx->use_vdoa = false; + + /* Power up and upload firmware if necessary */ + ret = pm_runtime_resume_and_get(dev->dev); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret); + goto err_pm_get; + } + + ret = clk_prepare_enable(dev->clk_per); + if (ret) + goto err_clk_enable; + + ret = clk_prepare_enable(dev->clk_ahb); + if (ret) + goto err_clk_ahb; + + set_default_params(ctx); + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, + ctx->ops->queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + + v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n", + __func__, ret); + goto err_ctx_init; + } + + ret = coda_ctrls_setup(ctx); + if (ret) { + v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n"); + goto err_ctrls_setup; + } + + ctx->fh.ctrl_handler = &ctx->ctrls; + + mutex_init(&ctx->bitstream_mutex); + mutex_init(&ctx->buffer_mutex); + mutex_init(&ctx->wakeup_mutex); + INIT_LIST_HEAD(&ctx->buffer_meta_list); + spin_lock_init(&ctx->buffer_meta_lock); + + return 0; + +err_ctrls_setup: + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); +err_ctx_init: + clk_disable_unprepare(dev->clk_ahb); +err_clk_ahb: + clk_disable_unprepare(dev->clk_per); +err_clk_enable: + pm_runtime_put_sync(dev->dev); +err_pm_get: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); +err_coda_name_init: + ida_free(&dev->ida, ctx->idx); +err_coda_max: + kfree(ctx); + return ret; +} + +static int coda_release(struct file *file) +{ + struct coda_dev *dev = video_drvdata(file); + struct coda_ctx *ctx = fh_to_ctx(file->private_data); + + coda_dbg(1, ctx, "release instance (%p)\n", ctx); + + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) + coda_bit_stream_end_flag(ctx); + + /* If this instance is running, call .job_abort and wait for it to end */ + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + + if (ctx->vdoa) + vdoa_context_destroy(ctx->vdoa); + + /* In case the instance was not running, we still need to call SEQ_END */ + if (ctx->ops->seq_end_work) { + queue_work(dev->workqueue, &ctx->seq_end_work); + flush_work(&ctx->seq_end_work); + } + + if (ctx->dev->devtype->product == CODA_DX6) + coda_free_aux_buf(dev, &ctx->workbuf); + + v4l2_ctrl_handler_free(&ctx->ctrls); + clk_disable_unprepare(dev->clk_ahb); + clk_disable_unprepare(dev->clk_per); + pm_runtime_put_sync(dev->dev); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + ida_free(&dev->ida, ctx->idx); + if (ctx->ops->release) + ctx->ops->release(ctx); + debugfs_remove_recursive(ctx->debugfs_entry); + kfree(ctx); + + return 0; +} + +static const struct v4l2_file_operations coda_fops = { + .owner = THIS_MODULE, + .open = coda_open, + .release = coda_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static int coda_hw_init(struct coda_dev *dev) +{ + u32 data; + u16 *p; + int i, ret; + + ret = clk_prepare_enable(dev->clk_per); + if (ret) + goto err_clk_per; + + ret = clk_prepare_enable(dev->clk_ahb); + if (ret) + goto err_clk_ahb; + + reset_control_reset(dev->rstc); + + /* + * Copy the first CODA_ISRAM_SIZE in the internal SRAM. + * The 16-bit chars in the code buffer are in memory access + * order, re-sort them to CODA order for register download. + * Data in this SRAM survives a reboot. + */ + p = (u16 *)dev->codebuf.vaddr; + if (dev->devtype->product == CODA_DX6) { + for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) { + data = CODA_DOWN_ADDRESS_SET(i) | + CODA_DOWN_DATA_SET(p[i ^ 1]); + coda_write(dev, data, CODA_REG_BIT_CODE_DOWN); + } + } else { + for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) { + data = CODA_DOWN_ADDRESS_SET(i) | + CODA_DOWN_DATA_SET(p[round_down(i, 4) + + 3 - (i % 4)]); + coda_write(dev, data, CODA_REG_BIT_CODE_DOWN); + } + } + + /* Clear registers */ + for (i = 0; i < 64; i++) + coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4); + + /* Tell the BIT where to find everything it needs */ + if (dev->devtype->product == CODA_960 || + dev->devtype->product == CODA_7541 || + dev->devtype->product == CODA_HX4) { + coda_write(dev, dev->tempbuf.paddr, + CODA_REG_BIT_TEMP_BUF_ADDR); + coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); + } else { + coda_write(dev, dev->workbuf.paddr, + CODA_REG_BIT_WORK_BUF_ADDR); + } + coda_write(dev, dev->codebuf.paddr, + CODA_REG_BIT_CODE_BUF_ADDR); + coda_write(dev, 0, CODA_REG_BIT_CODE_RUN); + + /* Set default values */ + switch (dev->devtype->product) { + case CODA_DX6: + coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, + CODA_REG_BIT_STREAM_CTRL); + break; + default: + coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, + CODA_REG_BIT_STREAM_CTRL); + } + if (dev->devtype->product == CODA_960) + coda_write(dev, CODA9_FRAME_ENABLE_BWB, + CODA_REG_BIT_FRAME_MEM_CTRL); + else + coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL); + + if (dev->devtype->product != CODA_DX6) + coda_write(dev, 0, CODA7_REG_BIT_AXI_SRAM_USE); + + coda_write(dev, CODA_INT_INTERRUPT_ENABLE, + CODA_REG_BIT_INT_ENABLE); + + /* Reset VPU and start processor */ + data = coda_read(dev, CODA_REG_BIT_CODE_RESET); + data |= CODA_REG_RESET_ENABLE; + coda_write(dev, data, CODA_REG_BIT_CODE_RESET); + udelay(10); + data &= ~CODA_REG_RESET_ENABLE; + coda_write(dev, data, CODA_REG_BIT_CODE_RESET); + coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); + + clk_disable_unprepare(dev->clk_ahb); + clk_disable_unprepare(dev->clk_per); + + return 0; + +err_clk_ahb: + clk_disable_unprepare(dev->clk_per); +err_clk_per: + return ret; +} + +static int coda_register_device(struct coda_dev *dev, int i) +{ + struct video_device *vfd = &dev->vfd[i]; + const char *name; + int ret; + + if (i >= dev->devtype->num_vdevs) + return -EINVAL; + name = dev->devtype->vdevs[i]->name; + + strscpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name)); + vfd->fops = &coda_fops; + vfd->ioctl_ops = &coda_ioctl_ops; + vfd->release = video_device_release_empty; + vfd->lock = &dev->dev_mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; + video_set_drvdata(vfd, dev); + + /* Not applicable, use the selection API instead */ + v4l2_disable_ioctl(vfd, VIDIOC_CROPCAP); + v4l2_disable_ioctl(vfd, VIDIOC_G_CROP); + v4l2_disable_ioctl(vfd, VIDIOC_S_CROP); + + if (dev->devtype->vdevs[i]->type == CODA_INST_ENCODER) { + v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); + if (dev->devtype->vdevs[i]->dst_formats[0] == V4L2_PIX_FMT_JPEG) { + v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMEINTERVALS); + v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); + v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); + } + } else { + v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMESIZES); + v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMEINTERVALS); + v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); + v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); + } + + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); + if (!ret) + v4l2_info(&dev->v4l2_dev, "%s registered as %s\n", + name, video_device_node_name(vfd)); + return ret; +} + +static void coda_copy_firmware(struct coda_dev *dev, const u8 * const buf, + size_t size) +{ + u32 *src = (u32 *)buf; + + /* Check if the firmware has a 16-byte Freescale header, skip it */ + if (buf[0] == 'M' && buf[1] == 'X') + src += 4; + /* + * Check whether the firmware is in native order or pre-reordered for + * memory access. The first instruction opcode always is 0xe40e. + */ + if (__le16_to_cpup((__le16 *)src) == 0xe40e) { + u32 *dst = dev->codebuf.vaddr; + int i; + + /* Firmware in native order, reorder while copying */ + if (dev->devtype->product == CODA_DX6) { + for (i = 0; i < (size - 16) / 4; i++) + dst[i] = (src[i] << 16) | (src[i] >> 16); + } else { + for (i = 0; i < (size - 16) / 4; i += 2) { + dst[i] = (src[i + 1] << 16) | (src[i + 1] >> 16); + dst[i + 1] = (src[i] << 16) | (src[i] >> 16); + } + } + } else { + /* Copy the already reordered firmware image */ + memcpy(dev->codebuf.vaddr, src, size); + } +} + +static void coda_fw_callback(const struct firmware *fw, void *context); + +static int coda_firmware_request(struct coda_dev *dev) +{ + char *fw; + + if (dev->firmware >= ARRAY_SIZE(dev->devtype->firmware)) + return -EINVAL; + + fw = dev->devtype->firmware[dev->firmware]; + + dev_dbg(dev->dev, "requesting firmware '%s' for %s\n", fw, + coda_product_name(dev->devtype->product)); + + return request_firmware_nowait(THIS_MODULE, true, fw, dev->dev, + GFP_KERNEL, dev, coda_fw_callback); +} + +static void coda_fw_callback(const struct firmware *fw, void *context) +{ + struct coda_dev *dev = context; + int i, ret; + + if (!fw) { + dev->firmware++; + ret = coda_firmware_request(dev); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "firmware request failed\n"); + goto put_pm; + } + return; + } + if (dev->firmware > 0) { + /* + * Since we can't suppress warnings for failed asynchronous + * firmware requests, report that the fallback firmware was + * found. + */ + dev_info(dev->dev, "Using fallback firmware %s\n", + dev->devtype->firmware[dev->firmware]); + } + + /* allocate auxiliary per-device code buffer for the BIT processor */ + ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf", + dev->debugfs_root); + if (ret < 0) + goto put_pm; + + coda_copy_firmware(dev, fw->data, fw->size); + release_firmware(fw); + + ret = coda_hw_init(dev); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "HW initialization failed\n"); + goto put_pm; + } + + ret = coda_check_firmware(dev); + if (ret < 0) + goto put_pm; + + dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); + goto put_pm; + } + + for (i = 0; i < dev->devtype->num_vdevs; i++) { + ret = coda_register_device(dev, i); + if (ret) { + v4l2_err(&dev->v4l2_dev, + "Failed to register %s video device: %d\n", + dev->devtype->vdevs[i]->name, ret); + goto rel_vfd; + } + } + + pm_runtime_put_sync(dev->dev); + return; + +rel_vfd: + while (--i >= 0) + video_unregister_device(&dev->vfd[i]); + v4l2_m2m_release(dev->m2m_dev); +put_pm: + pm_runtime_put_sync(dev->dev); +} + +enum coda_platform { + CODA_IMX27, + CODA_IMX51, + CODA_IMX53, + CODA_IMX6Q, + CODA_IMX6DL, +}; + +static const struct coda_devtype coda_devdata[] = { + [CODA_IMX27] = { + .firmware = { + "vpu_fw_imx27_TO2.bin", + "vpu/vpu_fw_imx27_TO2.bin", + "v4l-codadx6-imx27.bin" + }, + .product = CODA_DX6, + .codecs = codadx6_codecs, + .num_codecs = ARRAY_SIZE(codadx6_codecs), + .vdevs = codadx6_video_devices, + .num_vdevs = ARRAY_SIZE(codadx6_video_devices), + .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024, + .iram_size = 0xb000, + }, + [CODA_IMX51] = { + .firmware = { + "vpu_fw_imx51.bin", + "vpu/vpu_fw_imx51.bin", + "v4l-codahx4-imx51.bin" + }, + .product = CODA_HX4, + .codecs = codahx4_codecs, + .num_codecs = ARRAY_SIZE(codahx4_codecs), + .vdevs = codahx4_video_devices, + .num_vdevs = ARRAY_SIZE(codahx4_video_devices), + .workbuf_size = 128 * 1024, + .tempbuf_size = 304 * 1024, + .iram_size = 0x14000, + }, + [CODA_IMX53] = { + .firmware = { + "vpu_fw_imx53.bin", + "vpu/vpu_fw_imx53.bin", + "v4l-coda7541-imx53.bin" + }, + .product = CODA_7541, + .codecs = coda7_codecs, + .num_codecs = ARRAY_SIZE(coda7_codecs), + .vdevs = coda7_video_devices, + .num_vdevs = ARRAY_SIZE(coda7_video_devices), + .workbuf_size = 128 * 1024, + .tempbuf_size = 304 * 1024, + .iram_size = 0x14000, + }, + [CODA_IMX6Q] = { + .firmware = { + "vpu_fw_imx6q.bin", + "vpu/vpu_fw_imx6q.bin", + "v4l-coda960-imx6q.bin" + }, + .product = CODA_960, + .codecs = coda9_codecs, + .num_codecs = ARRAY_SIZE(coda9_codecs), + .vdevs = coda9_video_devices, + .num_vdevs = ARRAY_SIZE(coda9_video_devices), + .workbuf_size = 80 * 1024, + .tempbuf_size = 204 * 1024, + .iram_size = 0x21000, + }, + [CODA_IMX6DL] = { + .firmware = { + "vpu_fw_imx6d.bin", + "vpu/vpu_fw_imx6d.bin", + "v4l-coda960-imx6dl.bin" + }, + .product = CODA_960, + .codecs = coda9_codecs, + .num_codecs = ARRAY_SIZE(coda9_codecs), + .vdevs = coda9_video_devices, + .num_vdevs = ARRAY_SIZE(coda9_video_devices), + .workbuf_size = 80 * 1024, + .tempbuf_size = 204 * 1024, + .iram_size = 0x1f000, /* leave 4k for suspend code */ + }, +}; + +static const struct of_device_id coda_dt_ids[] = { + { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] }, + { .compatible = "fsl,imx51-vpu", .data = &coda_devdata[CODA_IMX51] }, + { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] }, + { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] }, + { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, coda_dt_ids); + +static int coda_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct gen_pool *pool; + struct coda_dev *dev; + int ret, irq; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->devtype = of_device_get_match_data(&pdev->dev); + + dev->dev = &pdev->dev; + dev->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(dev->clk_per)) { + dev_err(&pdev->dev, "Could not get per clock\n"); + return PTR_ERR(dev->clk_per); + } + + dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(dev->clk_ahb)) { + dev_err(&pdev->dev, "Could not get ahb clock\n"); + return PTR_ERR(dev->clk_ahb); + } + + /* Get memory for physical registers */ + dev->regs_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dev->regs_base)) + return PTR_ERR(dev->regs_base); + + /* IRQ */ + irq = platform_get_irq_byname(pdev, "bit"); + if (irq < 0) + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(&pdev->dev, irq, coda_irq_handler, 0, + CODA_NAME "-video", dev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request irq: %d\n", ret); + return ret; + } + + /* JPEG IRQ */ + if (dev->devtype->product == CODA_960) { + irq = platform_get_irq_byname(pdev, "jpeg"); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + coda9_jpeg_irq_handler, + IRQF_ONESHOT, CODA_NAME "-jpeg", + dev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request jpeg irq\n"); + return ret; + } + } + + dev->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, + NULL); + if (IS_ERR(dev->rstc)) { + ret = PTR_ERR(dev->rstc); + dev_err(&pdev->dev, "failed get reset control: %d\n", ret); + return ret; + } + + /* Get IRAM pool from device tree */ + pool = of_gen_pool_get(np, "iram", 0); + if (!pool) { + dev_err(&pdev->dev, "iram pool not available\n"); + return -ENOMEM; + } + dev->iram_pool = pool; + + /* Get vdoa_data if supported by the platform */ + dev->vdoa = coda_get_vdoa_data(); + if (PTR_ERR(dev->vdoa) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + return ret; + + ratelimit_default_init(&dev->mb_err_rs); + mutex_init(&dev->dev_mutex); + mutex_init(&dev->coda_mutex); + ida_init(&dev->ida); + + dev->debugfs_root = debugfs_create_dir("coda", NULL); + + /* allocate auxiliary per-device buffers for the BIT processor */ + if (dev->devtype->product == CODA_DX6) { + ret = coda_alloc_aux_buf(dev, &dev->workbuf, + dev->devtype->workbuf_size, "workbuf", + dev->debugfs_root); + if (ret < 0) + goto err_v4l2_register; + } + + if (dev->devtype->tempbuf_size) { + ret = coda_alloc_aux_buf(dev, &dev->tempbuf, + dev->devtype->tempbuf_size, "tempbuf", + dev->debugfs_root); + if (ret < 0) + goto err_v4l2_register; + } + + dev->iram.size = dev->devtype->iram_size; + dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size, + &dev->iram.paddr); + if (!dev->iram.vaddr) { + dev_warn(&pdev->dev, "unable to alloc iram\n"); + } else { + memset(dev->iram.vaddr, 0, dev->iram.size); + dev->iram.blob.data = dev->iram.vaddr; + dev->iram.blob.size = dev->iram.size; + dev->iram.dentry = debugfs_create_blob("iram", 0444, + dev->debugfs_root, + &dev->iram.blob); + } + + dev->workqueue = alloc_ordered_workqueue("coda", WQ_MEM_RECLAIM); + if (!dev->workqueue) { + dev_err(&pdev->dev, "unable to alloc workqueue\n"); + ret = -ENOMEM; + goto err_v4l2_register; + } + + platform_set_drvdata(pdev, dev); + + /* + * Start activated so we can directly call coda_hw_init in + * coda_fw_callback regardless of whether CONFIG_PM is + * enabled or whether the device is associated with a PM domain. + */ + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = coda_firmware_request(dev); + if (ret) + goto err_alloc_workqueue; + return 0; + +err_alloc_workqueue: + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + destroy_workqueue(dev->workqueue); +err_v4l2_register: + v4l2_device_unregister(&dev->v4l2_dev); + return ret; +} + +static void coda_remove(struct platform_device *pdev) +{ + struct coda_dev *dev = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < ARRAY_SIZE(dev->vfd); i++) { + if (video_get_drvdata(&dev->vfd[i])) + video_unregister_device(&dev->vfd[i]); + } + if (dev->m2m_dev) + v4l2_m2m_release(dev->m2m_dev); + pm_runtime_disable(&pdev->dev); + v4l2_device_unregister(&dev->v4l2_dev); + destroy_workqueue(dev->workqueue); + if (dev->iram.vaddr) + gen_pool_free(dev->iram_pool, (unsigned long)dev->iram.vaddr, + dev->iram.size); + coda_free_aux_buf(dev, &dev->codebuf); + coda_free_aux_buf(dev, &dev->tempbuf); + coda_free_aux_buf(dev, &dev->workbuf); + debugfs_remove_recursive(dev->debugfs_root); + ida_destroy(&dev->ida); +} + +#ifdef CONFIG_PM +static int coda_runtime_resume(struct device *dev) +{ + struct coda_dev *cdev = dev_get_drvdata(dev); + int ret = 0; + + if (dev->pm_domain && cdev->codebuf.vaddr) { + ret = coda_hw_init(cdev); + if (ret) + v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n"); + } + + return ret; +} +#endif + +static const struct dev_pm_ops coda_pm_ops = { + SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL) +}; + +static struct platform_driver coda_driver = { + .probe = coda_probe, + .remove_new = coda_remove, + .driver = { + .name = CODA_NAME, + .of_match_table = coda_dt_ids, + .pm = &coda_pm_ops, + }, +}; + +module_platform_driver(coda_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Javier Martin "); +MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver"); diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/coda-gdi.c b/drivers/media/platform/chips-media/coda/coda-gdi.c --- a/drivers/media/platform/chips-media/coda/coda-gdi.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/coda-gdi.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Coda multi-standard codec IP + * + * Copyright (C) 2014 Philipp Zabel, Pengutronix + */ + +#include +#include "coda.h" + +#define XY2_INVERT BIT(7) +#define XY2_ZERO BIT(6) +#define XY2_TB_XOR BIT(5) +#define XY2_XYSEL BIT(4) +#define XY2_Y (1 << 4) +#define XY2_X (0 << 4) + +#define XY2(luma_sel, luma_bit, chroma_sel, chroma_bit) \ + (((XY2_##luma_sel) | (luma_bit)) << 8 | \ + (XY2_##chroma_sel) | (chroma_bit)) + +static const u16 xy2ca_zero_map[16] = { + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), +}; + +static const u16 xy2ca_tiled_map[16] = { + XY2(Y, 0, Y, 0), + XY2(Y, 1, Y, 1), + XY2(Y, 2, Y, 2), + XY2(Y, 3, X, 3), + XY2(X, 3, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), +}; + +/* + * RA[15:0], CA[15:8] are hardwired to contain the 24-bit macroblock + * start offset (macroblock size is 16x16 for luma, 16x8 for chroma). + * Bits CA[4:0] are set using XY2CA above. BA[3:0] seems to be unused. + */ + +#define RBC_CA (0 << 4) +#define RBC_BA (1 << 4) +#define RBC_RA (2 << 4) +#define RBC_ZERO (3 << 4) + +#define RBC(luma_sel, luma_bit, chroma_sel, chroma_bit) \ + (((RBC_##luma_sel) | (luma_bit)) << 6 | \ + (RBC_##chroma_sel) | (chroma_bit)) + +static const u16 rbc2axi_tiled_map[32] = { + RBC(ZERO, 0, ZERO, 0), + RBC(ZERO, 0, ZERO, 0), + RBC(ZERO, 0, ZERO, 0), + RBC(CA, 0, CA, 0), + RBC(CA, 1, CA, 1), + RBC(CA, 2, CA, 2), + RBC(CA, 3, CA, 3), + RBC(CA, 4, CA, 8), + RBC(CA, 8, CA, 9), + RBC(CA, 9, CA, 10), + RBC(CA, 10, CA, 11), + RBC(CA, 11, CA, 12), + RBC(CA, 12, CA, 13), + RBC(CA, 13, CA, 14), + RBC(CA, 14, CA, 15), + RBC(CA, 15, RA, 0), + RBC(RA, 0, RA, 1), + RBC(RA, 1, RA, 2), + RBC(RA, 2, RA, 3), + RBC(RA, 3, RA, 4), + RBC(RA, 4, RA, 5), + RBC(RA, 5, RA, 6), + RBC(RA, 6, RA, 7), + RBC(RA, 7, RA, 8), + RBC(RA, 8, RA, 9), + RBC(RA, 9, RA, 10), + RBC(RA, 10, RA, 11), + RBC(RA, 11, RA, 12), + RBC(RA, 12, RA, 13), + RBC(RA, 13, RA, 14), + RBC(RA, 14, RA, 15), + RBC(RA, 15, ZERO, 0), +}; + +void coda_set_gdi_regs(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + const u16 *xy2ca_map; + u32 xy2rbc_config; + int i; + + switch (ctx->tiled_map_type) { + case GDI_LINEAR_FRAME_MAP: + default: + xy2ca_map = xy2ca_zero_map; + xy2rbc_config = 0; + break; + case GDI_TILED_FRAME_MB_RASTER_MAP: + xy2ca_map = xy2ca_tiled_map; + xy2rbc_config = CODA9_XY2RBC_TILED_MAP | + CODA9_XY2RBC_CA_INC_HOR | + (16 - 1) << 12 | (8 - 1) << 4; + break; + } + + for (i = 0; i < 16; i++) + coda_write(dev, xy2ca_map[i], + CODA9_GDI_XY2_CAS_0 + 4 * i); + for (i = 0; i < 4; i++) + coda_write(dev, XY2(ZERO, 0, ZERO, 0), + CODA9_GDI_XY2_BA_0 + 4 * i); + for (i = 0; i < 16; i++) + coda_write(dev, XY2(ZERO, 0, ZERO, 0), + CODA9_GDI_XY2_RAS_0 + 4 * i); + coda_write(dev, xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG); + if (xy2rbc_config) { + for (i = 0; i < 32; i++) + coda_write(dev, rbc2axi_tiled_map[i], + CODA9_GDI_RBC2_AXI_0 + 4 * i); + } +} diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/coda.h b/drivers/media/platform/chips-media/coda/coda.h --- a/drivers/media/platform/chips-media/coda/coda.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/coda.h 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Coda multi-standard codec IP + * + * Copyright (C) 2012 Vista Silicon S.L. + * Javier Martin, + * Xavier Duret + * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix + */ + +#ifndef __CODA_H__ +#define __CODA_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "coda_regs.h" + +#define CODA_MAX_FRAMEBUFFERS 19 +#define FMO_SLICE_SAVE_BUF_SIZE (32) + +/* + * This control allows applications to read the per-stream + * (i.e. per-context) Macroblocks Error Count. This value + * is CODA specific. + */ +#define V4L2_CID_CODA_MB_ERR_CNT (V4L2_CID_USER_CODA_BASE + 0) + +enum { + V4L2_M2M_SRC = 0, + V4L2_M2M_DST = 1, +}; + +enum coda_inst_type { + CODA_INST_ENCODER, + CODA_INST_DECODER, +}; + +enum coda_product { + CODA_DX6 = 0xf001, + CODA_HX4 = 0xf00a, + CODA_7541 = 0xf012, + CODA_960 = 0xf020, +}; + +struct coda_video_device; + +struct coda_devtype { + char *firmware[3]; + enum coda_product product; + const struct coda_codec *codecs; + unsigned int num_codecs; + const struct coda_video_device **vdevs; + unsigned int num_vdevs; + size_t workbuf_size; + size_t tempbuf_size; + size_t iram_size; +}; + +struct coda_aux_buf { + void *vaddr; + dma_addr_t paddr; + u32 size; + struct debugfs_blob_wrapper blob; + struct dentry *dentry; +}; + +struct coda_dev { + struct v4l2_device v4l2_dev; + struct video_device vfd[6]; + struct device *dev; + const struct coda_devtype *devtype; + int firmware; + struct vdoa_data *vdoa; + + void __iomem *regs_base; + struct clk *clk_per; + struct clk *clk_ahb; + struct reset_control *rstc; + + struct coda_aux_buf codebuf; + struct coda_aux_buf tempbuf; + struct coda_aux_buf workbuf; + struct gen_pool *iram_pool; + struct coda_aux_buf iram; + + struct mutex dev_mutex; + struct mutex coda_mutex; + struct workqueue_struct *workqueue; + struct v4l2_m2m_dev *m2m_dev; + struct ida ida; + struct dentry *debugfs_root; + struct ratelimit_state mb_err_rs; +}; + +struct coda_codec { + u32 mode; + u32 src_fourcc; + u32 dst_fourcc; + u32 max_w; + u32 max_h; +}; + +struct coda_huff_tab; + +struct coda_params { + u8 rot_mode; + u8 h264_intra_qp; + u8 h264_inter_qp; + u8 h264_min_qp; + u8 h264_max_qp; + u8 h264_disable_deblocking_filter_idc; + s8 h264_slice_alpha_c0_offset_div2; + s8 h264_slice_beta_offset_div2; + bool h264_constrained_intra_pred_flag; + s8 h264_chroma_qp_index_offset; + u8 h264_profile_idc; + u8 h264_level_idc; + u8 mpeg2_profile_idc; + u8 mpeg2_level_idc; + u8 mpeg4_intra_qp; + u8 mpeg4_inter_qp; + u8 gop_size; + int intra_refresh; + enum v4l2_jpeg_chroma_subsampling jpeg_chroma_subsampling; + u8 jpeg_quality; + u8 jpeg_restart_interval; + u8 *jpeg_qmat_tab[3]; + int jpeg_qmat_index[3]; + int jpeg_huff_dc_index[3]; + int jpeg_huff_ac_index[3]; + u32 *jpeg_huff_data; + struct coda_huff_tab *jpeg_huff_tab; + int codec_mode; + int codec_mode_aux; + enum v4l2_mpeg_video_multi_slice_mode slice_mode; + u32 framerate; + u16 bitrate; + u16 vbv_delay; + u32 vbv_size; + u32 slice_max_bits; + u32 slice_max_mb; + bool force_ipicture; + bool gop_size_changed; + bool bitrate_changed; + bool framerate_changed; + bool h264_intra_qp_changed; + bool intra_refresh_changed; + bool slice_mode_changed; + bool frame_rc_enable; + bool mb_rc_enable; +}; + +struct coda_buffer_meta { + struct list_head list; + u32 sequence; + struct v4l2_timecode timecode; + u64 timestamp; + unsigned int start; + unsigned int end; + bool last; +}; + +/* Per-queue, driver-specific private data */ +struct coda_q_data { + unsigned int width; + unsigned int height; + unsigned int bytesperline; + unsigned int sizeimage; + unsigned int fourcc; + struct v4l2_rect rect; +}; + +struct coda_iram_info { + u32 axi_sram_use; + phys_addr_t buf_bit_use; + phys_addr_t buf_ip_ac_dc_use; + phys_addr_t buf_dbk_y_use; + phys_addr_t buf_dbk_c_use; + phys_addr_t buf_ovl_use; + phys_addr_t buf_btp_use; + phys_addr_t search_ram_paddr; + int search_ram_size; + int remaining; + phys_addr_t next_paddr; +}; + +#define GDI_LINEAR_FRAME_MAP 0 +#define GDI_TILED_FRAME_MB_RASTER_MAP 1 + +struct coda_ctx; + +struct coda_context_ops { + int (*queue_init)(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); + int (*reqbufs)(struct coda_ctx *ctx, struct v4l2_requestbuffers *rb); + int (*start_streaming)(struct coda_ctx *ctx); + int (*prepare_run)(struct coda_ctx *ctx); + void (*finish_run)(struct coda_ctx *ctx); + void (*run_timeout)(struct coda_ctx *ctx); + void (*seq_init_work)(struct work_struct *work); + void (*seq_end_work)(struct work_struct *work); + void (*release)(struct coda_ctx *ctx); +}; + +struct coda_internal_frame { + struct coda_aux_buf buf; + struct coda_buffer_meta meta; + u32 type; + u32 error; +}; + +struct coda_ctx { + struct coda_dev *dev; + struct mutex buffer_mutex; + struct work_struct pic_run_work; + struct work_struct seq_init_work; + struct work_struct seq_end_work; + struct completion completion; + const struct coda_video_device *cvd; + const struct coda_context_ops *ops; + int aborting; + int initialized; + int streamon_out; + int streamon_cap; + u32 qsequence; + u32 osequence; + u32 sequence_offset; + struct coda_q_data q_data[2]; + enum coda_inst_type inst_type; + const struct coda_codec *codec; + enum v4l2_colorspace colorspace; + enum v4l2_xfer_func xfer_func; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_quantization quantization; + struct coda_params params; + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *h264_profile_ctrl; + struct v4l2_ctrl *h264_level_ctrl; + struct v4l2_ctrl *mpeg2_profile_ctrl; + struct v4l2_ctrl *mpeg2_level_ctrl; + struct v4l2_ctrl *mpeg4_profile_ctrl; + struct v4l2_ctrl *mpeg4_level_ctrl; + struct v4l2_ctrl *mb_err_cnt_ctrl; + struct v4l2_fh fh; + int gopcounter; + int runcounter; + int jpeg_ecs_offset; + char vpu_header[3][64]; + int vpu_header_size[3]; + struct kfifo bitstream_fifo; + struct mutex bitstream_mutex; + struct coda_aux_buf bitstream; + bool hold; + struct coda_aux_buf parabuf; + struct coda_aux_buf psbuf; + struct coda_aux_buf slicebuf; + struct coda_internal_frame internal_frames[CODA_MAX_FRAMEBUFFERS]; + struct list_head buffer_meta_list; + spinlock_t buffer_meta_lock; + int num_metas; + unsigned int first_frame_sequence; + struct coda_aux_buf workbuf; + int num_internal_frames; + int idx; + int reg_idx; + struct coda_iram_info iram_info; + int tiled_map_type; + u32 bit_stream_param; + u32 frm_dis_flg; + u32 frame_mem_ctrl; + u32 para_change; + int display_idx; + struct dentry *debugfs_entry; + bool use_bit; + bool use_vdoa; + struct vdoa_ctx *vdoa; + /* + * wakeup mutex used to serialize encoder stop command and finish_run, + * ensures that finish_run always either flags the last returned buffer + * or wakes up the capture queue to signal EOS afterwards. + */ + struct mutex wakeup_mutex; +}; + +extern int coda_debug; + +#define coda_dbg(level, ctx, fmt, arg...) \ + do { \ + if (coda_debug >= (level)) \ + v4l2_dbg((level), coda_debug, &(ctx)->dev->v4l2_dev, \ + "%u: " fmt, (ctx)->idx, ##arg); \ + } while (0) + +void coda_write(struct coda_dev *dev, u32 data, u32 reg); +unsigned int coda_read(struct coda_dev *dev, u32 reg); +void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, + struct vb2_v4l2_buffer *buf, unsigned int reg_y); + +int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, + size_t size, const char *name, struct dentry *parent); +void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf); + +int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); +int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); + +int coda_hw_reset(struct coda_ctx *ctx); + +void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list); + +void coda_set_gdi_regs(struct coda_ctx *ctx); + +static inline struct coda_q_data *get_q_data(struct coda_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &(ctx->q_data[V4L2_M2M_SRC]); + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &(ctx->q_data[V4L2_M2M_DST]); + default: + return NULL; + } +} + +const char *coda_product_name(int product); + +int coda_check_firmware(struct coda_dev *dev); + +static inline unsigned int coda_get_bitstream_payload(struct coda_ctx *ctx) +{ + return kfifo_len(&ctx->bitstream_fifo); +} + +/* + * The bitstream prefetcher needs to read at least 2 256 byte periods past + * the desired bitstream position for all data to reach the decoder. + */ +static inline bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, + unsigned int pos) +{ + return (int)(ctx->bitstream_fifo.kfifo.in - ALIGN(pos, 256)) > 512; +} + +bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, unsigned int pos); +int coda_bitstream_flush(struct coda_ctx *ctx); + +void coda_bit_stream_end_flag(struct coda_ctx *ctx); + +void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, + enum vb2_buffer_state state); + +int coda_h264_filler_nal(int size, char *p); +int coda_h264_padding(int size, char *p); +int coda_h264_profile(int profile_idc); +int coda_h264_level(int level_idc); +int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb); +int coda_h264_sps_fixup(struct coda_ctx *ctx, int width, int height, char *buf, + int *size, int max_size); + +int coda_mpeg2_profile(int profile_idc); +int coda_mpeg2_level(int level_idc); +u32 coda_mpeg2_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size); +int coda_mpeg4_profile(int profile_idc); +int coda_mpeg4_level(int level_idc); +u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size); + +void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, + u8 level_idc); + +static inline int coda_jpeg_scale(int src, int dst) +{ + return (dst <= src / 8) ? 3 : + (dst <= src / 4) ? 2 : + (dst <= src / 2) ? 1 : 0; +} + +bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb); +int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb); +int coda_jpeg_write_tables(struct coda_ctx *ctx); +void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality); + +extern const struct coda_context_ops coda_bit_encode_ops; +extern const struct coda_context_ops coda_bit_decode_ops; +extern const struct coda_context_ops coda9_jpeg_encode_ops; +extern const struct coda_context_ops coda9_jpeg_decode_ops; + +irqreturn_t coda_irq_handler(int irq, void *data); +irqreturn_t coda9_jpeg_irq_handler(int irq, void *data); + +#endif /* __CODA_H__ */ diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/coda-h264.c b/drivers/media/platform/chips-media/coda/coda-h264.c --- a/drivers/media/platform/chips-media/coda/coda-h264.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/coda-h264.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,429 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Coda multi-standard codec IP - H.264 helper functions + * + * Copyright (C) 2012 Vista Silicon S.L. + * Javier Martin, + * Xavier Duret + */ + +#include +#include +#include + +#include "coda.h" + +static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; + +static const u8 *coda_find_nal_header(const u8 *buf, const u8 *end) +{ + u32 val = 0xffffffff; + + do { + val = val << 8 | *buf++; + if (buf >= end) + return NULL; + } while (val != 0x00000001); + + return buf; +} + +int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb) +{ + const u8 *buf = vb2_plane_vaddr(vb, 0); + const u8 *end = buf + vb2_get_plane_payload(vb, 0); + + /* Find SPS header */ + do { + buf = coda_find_nal_header(buf, end); + if (!buf) + return -EINVAL; + } while ((*buf++ & 0x1f) != 0x7); + + ctx->params.h264_profile_idc = buf[0]; + ctx->params.h264_level_idc = buf[2]; + + return 0; +} + +int coda_h264_filler_nal(int size, char *p) +{ + if (size < 6) + return -EINVAL; + + p[0] = 0x00; + p[1] = 0x00; + p[2] = 0x00; + p[3] = 0x01; + p[4] = 0x0c; + memset(p + 5, 0xff, size - 6); + /* Add rbsp stop bit and trailing at the end */ + p[size - 1] = 0x80; + + return 0; +} + +int coda_h264_padding(int size, char *p) +{ + int nal_size; + int diff; + + diff = size - (size & ~0x7); + if (diff == 0) + return 0; + + nal_size = coda_filler_size[diff]; + coda_h264_filler_nal(nal_size, p); + + return nal_size; +} + +int coda_h264_profile(int profile_idc) +{ + switch (profile_idc) { + case 66: return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; + case 77: return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; + case 88: return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED; + case 100: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; + default: return -EINVAL; + } +} + +int coda_h264_level(int level_idc) +{ + switch (level_idc) { + case 10: return V4L2_MPEG_VIDEO_H264_LEVEL_1_0; + case 9: return V4L2_MPEG_VIDEO_H264_LEVEL_1B; + case 11: return V4L2_MPEG_VIDEO_H264_LEVEL_1_1; + case 12: return V4L2_MPEG_VIDEO_H264_LEVEL_1_2; + case 13: return V4L2_MPEG_VIDEO_H264_LEVEL_1_3; + case 20: return V4L2_MPEG_VIDEO_H264_LEVEL_2_0; + case 21: return V4L2_MPEG_VIDEO_H264_LEVEL_2_1; + case 22: return V4L2_MPEG_VIDEO_H264_LEVEL_2_2; + case 30: return V4L2_MPEG_VIDEO_H264_LEVEL_3_0; + case 31: return V4L2_MPEG_VIDEO_H264_LEVEL_3_1; + case 32: return V4L2_MPEG_VIDEO_H264_LEVEL_3_2; + case 40: return V4L2_MPEG_VIDEO_H264_LEVEL_4_0; + case 41: return V4L2_MPEG_VIDEO_H264_LEVEL_4_1; + case 42: return V4L2_MPEG_VIDEO_H264_LEVEL_4_2; + case 50: return V4L2_MPEG_VIDEO_H264_LEVEL_5_0; + case 51: return V4L2_MPEG_VIDEO_H264_LEVEL_5_1; + default: return -EINVAL; + } +} + +struct rbsp { + char *buf; + int size; + int pos; +}; + +static inline int rbsp_read_bit(struct rbsp *rbsp) +{ + int shift = 7 - (rbsp->pos % 8); + int ofs = rbsp->pos++ / 8; + + if (ofs >= rbsp->size) + return -EINVAL; + + return (rbsp->buf[ofs] >> shift) & 1; +} + +static inline int rbsp_write_bit(struct rbsp *rbsp, int bit) +{ + int shift = 7 - (rbsp->pos % 8); + int ofs = rbsp->pos++ / 8; + + if (ofs >= rbsp->size) + return -EINVAL; + + rbsp->buf[ofs] &= ~(1 << shift); + rbsp->buf[ofs] |= bit << shift; + + return 0; +} + +static inline int rbsp_read_bits(struct rbsp *rbsp, int num, int *val) +{ + int i, ret; + int tmp = 0; + + if (num > 32) + return -EINVAL; + + for (i = 0; i < num; i++) { + ret = rbsp_read_bit(rbsp); + if (ret < 0) + return ret; + tmp |= ret << (num - i - 1); + } + + if (val) + *val = tmp; + + return 0; +} + +static int rbsp_write_bits(struct rbsp *rbsp, int num, int value) +{ + int ret; + + while (num--) { + ret = rbsp_write_bit(rbsp, (value >> num) & 1); + if (ret) + return ret; + } + + return 0; +} + +static int rbsp_read_uev(struct rbsp *rbsp, unsigned int *val) +{ + int leading_zero_bits = 0; + unsigned int tmp = 0; + int ret; + + while ((ret = rbsp_read_bit(rbsp)) == 0) + leading_zero_bits++; + if (ret < 0) + return ret; + + if (leading_zero_bits > 0) { + ret = rbsp_read_bits(rbsp, leading_zero_bits, &tmp); + if (ret) + return ret; + } + + if (val) + *val = (1 << leading_zero_bits) - 1 + tmp; + + return 0; +} + +static int rbsp_write_uev(struct rbsp *rbsp, unsigned int value) +{ + int i; + int ret; + int tmp = value + 1; + int leading_zero_bits = fls(tmp) - 1; + + for (i = 0; i < leading_zero_bits; i++) { + ret = rbsp_write_bit(rbsp, 0); + if (ret) + return ret; + } + + return rbsp_write_bits(rbsp, leading_zero_bits + 1, tmp); +} + +static int rbsp_read_sev(struct rbsp *rbsp, int *val) +{ + unsigned int tmp; + int ret; + + ret = rbsp_read_uev(rbsp, &tmp); + if (ret) + return ret; + + if (val) { + if (tmp & 1) + *val = (tmp + 1) / 2; + else + *val = -(tmp / 2); + } + + return 0; +} + +/** + * coda_h264_sps_fixup - fixes frame cropping values in h.264 SPS + * @ctx: encoder context + * @width: visible width + * @height: visible height + * @buf: buffer containing h.264 SPS RBSP, starting with NAL header + * @size: modified RBSP size return value + * @max_size: available size in buf + * + * Rewrites the frame cropping values in an h.264 SPS RBSP correctly for the + * given visible width and height. + */ +int coda_h264_sps_fixup(struct coda_ctx *ctx, int width, int height, char *buf, + int *size, int max_size) +{ + int profile_idc; + unsigned int pic_order_cnt_type; + int pic_width_in_mbs_minus1, pic_height_in_map_units_minus1; + int frame_mbs_only_flag, frame_cropping_flag; + int vui_parameters_present_flag; + unsigned int crop_right, crop_bottom; + struct rbsp sps; + int pos; + int ret; + + if (*size < 8 || *size >= max_size) + return -EINVAL; + + sps.buf = buf + 5; /* Skip NAL header */ + sps.size = *size - 5; + + profile_idc = sps.buf[0]; + /* Skip constraint_set[0-5]_flag, reserved_zero_2bits */ + /* Skip level_idc */ + sps.pos = 24; + + /* seq_parameter_set_id */ + ret = rbsp_read_uev(&sps, NULL); + if (ret) + return ret; + + if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || + profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || + profile_idc == 86 || profile_idc == 118 || profile_idc == 128 || + profile_idc == 138 || profile_idc == 139 || profile_idc == 134 || + profile_idc == 135) { + dev_err(ctx->fh.vdev->dev_parent, + "%s: Handling profile_idc %d not implemented\n", + __func__, profile_idc); + return -EINVAL; + } + + /* log2_max_frame_num_minus4 */ + ret = rbsp_read_uev(&sps, NULL); + if (ret) + return ret; + + ret = rbsp_read_uev(&sps, &pic_order_cnt_type); + if (ret) + return ret; + + if (pic_order_cnt_type == 0) { + /* log2_max_pic_order_cnt_lsb_minus4 */ + ret = rbsp_read_uev(&sps, NULL); + if (ret) + return ret; + } else if (pic_order_cnt_type == 1) { + unsigned int i, num_ref_frames_in_pic_order_cnt_cycle; + + /* delta_pic_order_always_zero_flag */ + ret = rbsp_read_bit(&sps); + if (ret < 0) + return ret; + /* offset_for_non_ref_pic */ + ret = rbsp_read_sev(&sps, NULL); + if (ret) + return ret; + /* offset_for_top_to_bottom_field */ + ret = rbsp_read_sev(&sps, NULL); + if (ret) + return ret; + + ret = rbsp_read_uev(&sps, + &num_ref_frames_in_pic_order_cnt_cycle); + if (ret) + return ret; + for (i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) { + /* offset_for_ref_frame */ + ret = rbsp_read_sev(&sps, NULL); + if (ret) + return ret; + } + } + + /* max_num_ref_frames */ + ret = rbsp_read_uev(&sps, NULL); + if (ret) + return ret; + + /* gaps_in_frame_num_value_allowed_flag */ + ret = rbsp_read_bit(&sps); + if (ret < 0) + return ret; + ret = rbsp_read_uev(&sps, &pic_width_in_mbs_minus1); + if (ret) + return ret; + ret = rbsp_read_uev(&sps, &pic_height_in_map_units_minus1); + if (ret) + return ret; + frame_mbs_only_flag = ret = rbsp_read_bit(&sps); + if (ret < 0) + return ret; + if (!frame_mbs_only_flag) { + /* mb_adaptive_frame_field_flag */ + ret = rbsp_read_bit(&sps); + if (ret < 0) + return ret; + } + /* direct_8x8_inference_flag */ + ret = rbsp_read_bit(&sps); + if (ret < 0) + return ret; + + /* Mark position of the frame cropping flag */ + pos = sps.pos; + frame_cropping_flag = ret = rbsp_read_bit(&sps); + if (ret < 0) + return ret; + if (frame_cropping_flag) { + unsigned int crop_left, crop_top; + + ret = rbsp_read_uev(&sps, &crop_left); + if (ret) + return ret; + ret = rbsp_read_uev(&sps, &crop_right); + if (ret) + return ret; + ret = rbsp_read_uev(&sps, &crop_top); + if (ret) + return ret; + ret = rbsp_read_uev(&sps, &crop_bottom); + if (ret) + return ret; + } + vui_parameters_present_flag = ret = rbsp_read_bit(&sps); + if (ret < 0) + return ret; + if (vui_parameters_present_flag) { + dev_err(ctx->fh.vdev->dev_parent, + "%s: Handling vui_parameters not implemented\n", + __func__); + return -EINVAL; + } + + crop_right = round_up(width, 16) - width; + crop_bottom = round_up(height, 16) - height; + crop_right /= 2; + if (frame_mbs_only_flag) + crop_bottom /= 2; + else + crop_bottom /= 4; + + + sps.size = max_size - 5; + sps.pos = pos; + frame_cropping_flag = 1; + ret = rbsp_write_bit(&sps, frame_cropping_flag); + if (ret) + return ret; + ret = rbsp_write_uev(&sps, 0); /* crop_left */ + if (ret) + return ret; + ret = rbsp_write_uev(&sps, crop_right); + if (ret) + return ret; + ret = rbsp_write_uev(&sps, 0); /* crop_top */ + if (ret) + return ret; + ret = rbsp_write_uev(&sps, crop_bottom); + if (ret) + return ret; + ret = rbsp_write_bit(&sps, 0); /* vui_parameters_present_flag */ + if (ret) + return ret; + ret = rbsp_write_bit(&sps, 1); + if (ret) + return ret; + + *size = 5 + DIV_ROUND_UP(sps.pos, 8); + + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/coda-jpeg.c b/drivers/media/platform/chips-media/coda/coda-jpeg.c --- a/drivers/media/platform/chips-media/coda/coda-jpeg.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/coda-jpeg.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,1547 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Coda multi-standard codec IP - JPEG support functions + * + * Copyright (C) 2014 Philipp Zabel, Pengutronix + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "coda.h" +#include "trace.h" + +#define SOI_MARKER 0xffd8 +#define APP9_MARKER 0xffe9 +#define DRI_MARKER 0xffdd +#define DQT_MARKER 0xffdb +#define DHT_MARKER 0xffc4 +#define SOF_MARKER 0xffc0 +#define SOS_MARKER 0xffda +#define EOI_MARKER 0xffd9 + +enum { + CODA9_JPEG_FORMAT_420, + CODA9_JPEG_FORMAT_422, + CODA9_JPEG_FORMAT_224, + CODA9_JPEG_FORMAT_444, + CODA9_JPEG_FORMAT_400, +}; + +struct coda_huff_tab { + u8 luma_dc[16 + 12]; + u8 chroma_dc[16 + 12]; + u8 luma_ac[16 + 162]; + u8 chroma_ac[16 + 162]; + + /* DC Luma, DC Chroma, AC Luma, AC Chroma */ + s16 min[4 * 16]; + s16 max[4 * 16]; + s8 ptr[4 * 16]; +}; + +#define CODA9_JPEG_ENC_HUFF_DATA_SIZE (256 + 256 + 16 + 16) + +/* + * Typical Huffman tables for 8-bit precision luminance and + * chrominance from JPEG ITU-T.81 (ISO/IEC 10918-1) Annex K.3 + */ + +static const unsigned char luma_dc[16 + 12] = { + /* bits */ + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* values */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, +}; + +static const unsigned char chroma_dc[16 + 12] = { + /* bits */ + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + /* values */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, +}; + +static const unsigned char luma_ac[16 + 162 + 2] = { + /* bits */ + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, + /* values */ + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, /* padded to 32-bit */ +}; + +static const unsigned char chroma_ac[16 + 162 + 2] = { + /* bits */ + 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, + 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, + /* values */ + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, /* padded to 32-bit */ +}; + +/* + * Quantization tables for luminance and chrominance components in + * zig-zag scan order from the Freescale i.MX VPU libraries + */ + +static unsigned char luma_q[64] = { + 0x06, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x05, + 0x05, 0x06, 0x09, 0x06, 0x05, 0x06, 0x09, 0x0b, + 0x08, 0x06, 0x06, 0x08, 0x0b, 0x0c, 0x0a, 0x0a, + 0x0b, 0x0a, 0x0a, 0x0c, 0x10, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x10, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, +}; + +static unsigned char chroma_q[64] = { + 0x07, 0x07, 0x07, 0x0d, 0x0c, 0x0d, 0x18, 0x10, + 0x10, 0x18, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, + 0x0e, 0x0e, 0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, +}; + +static const unsigned char width_align[] = { + [CODA9_JPEG_FORMAT_420] = 16, + [CODA9_JPEG_FORMAT_422] = 16, + [CODA9_JPEG_FORMAT_224] = 8, + [CODA9_JPEG_FORMAT_444] = 8, + [CODA9_JPEG_FORMAT_400] = 8, +}; + +static const unsigned char height_align[] = { + [CODA9_JPEG_FORMAT_420] = 16, + [CODA9_JPEG_FORMAT_422] = 8, + [CODA9_JPEG_FORMAT_224] = 16, + [CODA9_JPEG_FORMAT_444] = 8, + [CODA9_JPEG_FORMAT_400] = 8, +}; + +static int coda9_jpeg_chroma_format(u32 pixfmt) +{ + switch (pixfmt) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_NV12: + return CODA9_JPEG_FORMAT_420; + case V4L2_PIX_FMT_YUV422P: + return CODA9_JPEG_FORMAT_422; + case V4L2_PIX_FMT_YUV444: + return CODA9_JPEG_FORMAT_444; + case V4L2_PIX_FMT_GREY: + return CODA9_JPEG_FORMAT_400; + } + return -EINVAL; +} + +struct coda_memcpy_desc { + int offset; + const void *src; + size_t len; +}; + +static void coda_memcpy_parabuf(void *parabuf, + const struct coda_memcpy_desc *desc) +{ + u32 *dst = parabuf + desc->offset; + const u32 *src = desc->src; + int len = desc->len / 4; + int i; + + for (i = 0; i < len; i += 2) { + dst[i + 1] = swab32(src[i]); + dst[i] = swab32(src[i + 1]); + } +} + +int coda_jpeg_write_tables(struct coda_ctx *ctx) +{ + int i; + static const struct coda_memcpy_desc huff[8] = { + { 0, luma_dc, sizeof(luma_dc) }, + { 32, luma_ac, sizeof(luma_ac) }, + { 216, chroma_dc, sizeof(chroma_dc) }, + { 248, chroma_ac, sizeof(chroma_ac) }, + }; + struct coda_memcpy_desc qmat[3] = { + { 512, ctx->params.jpeg_qmat_tab[0], 64 }, + { 576, ctx->params.jpeg_qmat_tab[1], 64 }, + { 640, ctx->params.jpeg_qmat_tab[1], 64 }, + }; + + /* Write huffman tables to parameter memory */ + for (i = 0; i < ARRAY_SIZE(huff); i++) + coda_memcpy_parabuf(ctx->parabuf.vaddr, huff + i); + + /* Write Q-matrix to parameter memory */ + for (i = 0; i < ARRAY_SIZE(qmat); i++) + coda_memcpy_parabuf(ctx->parabuf.vaddr, qmat + i); + + return 0; +} + +bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb) +{ + void *vaddr = vb2_plane_vaddr(vb, 0); + u16 soi, eoi; + int len, i; + + soi = be16_to_cpup((__be16 *)vaddr); + if (soi != SOI_MARKER) + return false; + + len = vb2_get_plane_payload(vb, 0); + vaddr += len - 2; + for (i = 0; i < 32; i++) { + eoi = be16_to_cpup((__be16 *)(vaddr - i)); + if (eoi == EOI_MARKER) { + if (i > 0) + vb2_set_plane_payload(vb, 0, len - i); + return true; + } + } + + return false; +} + +static int coda9_jpeg_gen_dec_huff_tab(struct coda_ctx *ctx, int tab_num); + +int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb) +{ + struct coda_dev *dev = ctx->dev; + u8 *buf = vb2_plane_vaddr(vb, 0); + size_t len = vb2_get_plane_payload(vb, 0); + struct v4l2_jpeg_scan_header scan_header; + struct v4l2_jpeg_reference quantization_tables[4] = { }; + struct v4l2_jpeg_reference huffman_tables[4] = { }; + struct v4l2_jpeg_header header = { + .scan = &scan_header, + .quantization_tables = quantization_tables, + .huffman_tables = huffman_tables, + }; + struct coda_q_data *q_data_src; + struct coda_huff_tab *huff_tab; + int i, j, ret; + + ret = v4l2_jpeg_parse_header(buf, len, &header); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to parse JPEG header: %pe\n", + ERR_PTR(ret)); + return ret; + } + + ctx->params.jpeg_restart_interval = header.restart_interval; + + /* check frame header */ + if (header.frame.height > ctx->codec->max_h || + header.frame.width > ctx->codec->max_w) { + v4l2_err(&dev->v4l2_dev, "invalid dimensions: %dx%d\n", + header.frame.width, header.frame.height); + return -EINVAL; + } + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + if (header.frame.height != q_data_src->height || + header.frame.width != q_data_src->width) { + v4l2_err(&dev->v4l2_dev, + "dimensions don't match format: %dx%d\n", + header.frame.width, header.frame.height); + return -EINVAL; + } + + if (header.frame.num_components != 3) { + v4l2_err(&dev->v4l2_dev, + "unsupported number of components: %d\n", + header.frame.num_components); + return -EINVAL; + } + + /* install quantization tables */ + if (quantization_tables[3].start) { + v4l2_err(&dev->v4l2_dev, + "only 3 quantization tables supported\n"); + return -EINVAL; + } + for (i = 0; i < 3; i++) { + if (!quantization_tables[i].start) + continue; + if (quantization_tables[i].length != 64) { + v4l2_err(&dev->v4l2_dev, + "only 8-bit quantization tables supported\n"); + continue; + } + if (!ctx->params.jpeg_qmat_tab[i]) { + ctx->params.jpeg_qmat_tab[i] = kmalloc(64, GFP_KERNEL); + if (!ctx->params.jpeg_qmat_tab[i]) + return -ENOMEM; + } + memcpy(ctx->params.jpeg_qmat_tab[i], + quantization_tables[i].start, 64); + } + + /* install Huffman tables */ + for (i = 0; i < 4; i++) { + if (!huffman_tables[i].start) { + v4l2_err(&dev->v4l2_dev, "missing Huffman table\n"); + return -EINVAL; + } + /* AC tables should be between 17 -> 178, DC between 17 -> 28 */ + if (huffman_tables[i].length < 17 || + huffman_tables[i].length > 178 || + ((i & 2) == 0 && huffman_tables[i].length > 28)) { + v4l2_err(&dev->v4l2_dev, + "invalid Huffman table %d length: %zu\n", + i, huffman_tables[i].length); + return -EINVAL; + } + } + huff_tab = ctx->params.jpeg_huff_tab; + if (!huff_tab) { + huff_tab = kzalloc(sizeof(struct coda_huff_tab), GFP_KERNEL); + if (!huff_tab) + return -ENOMEM; + ctx->params.jpeg_huff_tab = huff_tab; + } + + memset(huff_tab, 0, sizeof(*huff_tab)); + memcpy(huff_tab->luma_dc, huffman_tables[0].start, huffman_tables[0].length); + memcpy(huff_tab->chroma_dc, huffman_tables[1].start, huffman_tables[1].length); + memcpy(huff_tab->luma_ac, huffman_tables[2].start, huffman_tables[2].length); + memcpy(huff_tab->chroma_ac, huffman_tables[3].start, huffman_tables[3].length); + + /* check scan header */ + for (i = 0; i < scan_header.num_components; i++) { + struct v4l2_jpeg_scan_component_spec *scan_component; + + scan_component = &scan_header.component[i]; + for (j = 0; j < header.frame.num_components; j++) { + if (header.frame.component[j].component_identifier == + scan_component->component_selector) + break; + } + if (j == header.frame.num_components) + continue; + + ctx->params.jpeg_huff_dc_index[j] = + scan_component->dc_entropy_coding_table_selector; + ctx->params.jpeg_huff_ac_index[j] = + scan_component->ac_entropy_coding_table_selector; + } + + /* Generate Huffman table information */ + for (i = 0; i < 4; i++) + coda9_jpeg_gen_dec_huff_tab(ctx, i); + + /* start of entropy coded segment */ + ctx->jpeg_ecs_offset = header.ecs_offset; + + switch (header.frame.subsampling) { + case V4L2_JPEG_CHROMA_SUBSAMPLING_420: + case V4L2_JPEG_CHROMA_SUBSAMPLING_422: + ctx->params.jpeg_chroma_subsampling = header.frame.subsampling; + break; + default: + v4l2_err(&dev->v4l2_dev, "chroma subsampling not supported: %d", + header.frame.subsampling); + return -EINVAL; + } + + return 0; +} + +static inline void coda9_jpeg_write_huff_values(struct coda_dev *dev, u8 *bits, + int num_values) +{ + s8 *values = (s8 *)(bits + 16); + int huff_length, i; + + for (huff_length = 0, i = 0; i < 16; i++) + huff_length += bits[i]; + for (i = huff_length; i < num_values; i++) + values[i] = -1; + for (i = 0; i < num_values; i++) + coda_write(dev, (s32)values[i], CODA9_REG_JPEG_HUFF_DATA); +} + +static void coda9_jpeg_dec_huff_setup(struct coda_ctx *ctx) +{ + struct coda_huff_tab *huff_tab = ctx->params.jpeg_huff_tab; + struct coda_dev *dev = ctx->dev; + s16 *huff_min = huff_tab->min; + s16 *huff_max = huff_tab->max; + s8 *huff_ptr = huff_tab->ptr; + int i; + + /* MIN Tables */ + coda_write(dev, 0x003, CODA9_REG_JPEG_HUFF_CTRL); + coda_write(dev, 0x000, CODA9_REG_JPEG_HUFF_ADDR); + for (i = 0; i < 4 * 16; i++) + coda_write(dev, (s32)huff_min[i], CODA9_REG_JPEG_HUFF_DATA); + + /* MAX Tables */ + coda_write(dev, 0x403, CODA9_REG_JPEG_HUFF_CTRL); + coda_write(dev, 0x440, CODA9_REG_JPEG_HUFF_ADDR); + for (i = 0; i < 4 * 16; i++) + coda_write(dev, (s32)huff_max[i], CODA9_REG_JPEG_HUFF_DATA); + + /* PTR Tables */ + coda_write(dev, 0x803, CODA9_REG_JPEG_HUFF_CTRL); + coda_write(dev, 0x880, CODA9_REG_JPEG_HUFF_ADDR); + for (i = 0; i < 4 * 16; i++) + coda_write(dev, (s32)huff_ptr[i], CODA9_REG_JPEG_HUFF_DATA); + + /* VAL Tables: DC Luma, DC Chroma, AC Luma, AC Chroma */ + coda_write(dev, 0xc03, CODA9_REG_JPEG_HUFF_CTRL); + coda9_jpeg_write_huff_values(dev, huff_tab->luma_dc, 12); + coda9_jpeg_write_huff_values(dev, huff_tab->chroma_dc, 12); + coda9_jpeg_write_huff_values(dev, huff_tab->luma_ac, 162); + coda9_jpeg_write_huff_values(dev, huff_tab->chroma_ac, 162); + coda_write(dev, 0x000, CODA9_REG_JPEG_HUFF_CTRL); +} + +static inline void coda9_jpeg_write_qmat_tab(struct coda_dev *dev, + u8 *qmat, int index) +{ + int i; + + coda_write(dev, index | 0x3, CODA9_REG_JPEG_QMAT_CTRL); + for (i = 0; i < 64; i++) + coda_write(dev, qmat[i], CODA9_REG_JPEG_QMAT_DATA); + coda_write(dev, 0, CODA9_REG_JPEG_QMAT_CTRL); +} + +static void coda9_jpeg_qmat_setup(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + int *qmat_index = ctx->params.jpeg_qmat_index; + u8 **qmat_tab = ctx->params.jpeg_qmat_tab; + + coda9_jpeg_write_qmat_tab(dev, qmat_tab[qmat_index[0]], 0x00); + coda9_jpeg_write_qmat_tab(dev, qmat_tab[qmat_index[1]], 0x40); + coda9_jpeg_write_qmat_tab(dev, qmat_tab[qmat_index[2]], 0x80); +} + +static void coda9_jpeg_dec_bbc_gbu_setup(struct coda_ctx *ctx, + struct vb2_buffer *buf, u32 ecs_offset) +{ + struct coda_dev *dev = ctx->dev; + int page_ptr, word_ptr, bit_ptr; + u32 bbc_base_addr, end_addr; + int bbc_cur_pos; + int ret, val; + + bbc_base_addr = vb2_dma_contig_plane_dma_addr(buf, 0); + end_addr = bbc_base_addr + vb2_get_plane_payload(buf, 0); + + page_ptr = ecs_offset / 256; + word_ptr = (ecs_offset % 256) / 4; + if (page_ptr & 1) + word_ptr += 64; + bit_ptr = (ecs_offset % 4) * 8; + if (word_ptr & 1) + bit_ptr += 32; + word_ptr &= ~0x1; + + coda_write(dev, end_addr, CODA9_REG_JPEG_BBC_WR_PTR); + coda_write(dev, bbc_base_addr, CODA9_REG_JPEG_BBC_BAS_ADDR); + + /* Leave 3 256-byte page margin to avoid a BBC interrupt */ + coda_write(dev, end_addr + 256 * 3 + 256, CODA9_REG_JPEG_BBC_END_ADDR); + val = DIV_ROUND_UP(vb2_plane_size(buf, 0), 256) + 3; + coda_write(dev, BIT(31) | val, CODA9_REG_JPEG_BBC_STRM_CTRL); + + bbc_cur_pos = page_ptr; + coda_write(dev, bbc_cur_pos, CODA9_REG_JPEG_BBC_CUR_POS); + coda_write(dev, bbc_base_addr + (bbc_cur_pos << 8), + CODA9_REG_JPEG_BBC_EXT_ADDR); + coda_write(dev, (bbc_cur_pos & 1) << 6, CODA9_REG_JPEG_BBC_INT_ADDR); + coda_write(dev, 64, CODA9_REG_JPEG_BBC_DATA_CNT); + coda_write(dev, 0, CODA9_REG_JPEG_BBC_COMMAND); + do { + ret = coda_read(dev, CODA9_REG_JPEG_BBC_BUSY); + } while (ret == 1); + + bbc_cur_pos++; + coda_write(dev, bbc_cur_pos, CODA9_REG_JPEG_BBC_CUR_POS); + coda_write(dev, bbc_base_addr + (bbc_cur_pos << 8), + CODA9_REG_JPEG_BBC_EXT_ADDR); + coda_write(dev, (bbc_cur_pos & 1) << 6, CODA9_REG_JPEG_BBC_INT_ADDR); + coda_write(dev, 64, CODA9_REG_JPEG_BBC_DATA_CNT); + coda_write(dev, 0, CODA9_REG_JPEG_BBC_COMMAND); + do { + ret = coda_read(dev, CODA9_REG_JPEG_BBC_BUSY); + } while (ret == 1); + + bbc_cur_pos++; + coda_write(dev, bbc_cur_pos, CODA9_REG_JPEG_BBC_CUR_POS); + coda_write(dev, 1, CODA9_REG_JPEG_BBC_CTRL); + + coda_write(dev, 0, CODA9_REG_JPEG_GBU_TT_CNT); + coda_write(dev, word_ptr, CODA9_REG_JPEG_GBU_WD_PTR); + coda_write(dev, 0, CODA9_REG_JPEG_GBU_BBSR); + coda_write(dev, 127, CODA9_REG_JPEG_GBU_BBER); + if (page_ptr & 1) { + coda_write(dev, 0, CODA9_REG_JPEG_GBU_BBIR); + coda_write(dev, 0, CODA9_REG_JPEG_GBU_BBHR); + } else { + coda_write(dev, 64, CODA9_REG_JPEG_GBU_BBIR); + coda_write(dev, 64, CODA9_REG_JPEG_GBU_BBHR); + } + coda_write(dev, 4, CODA9_REG_JPEG_GBU_CTRL); + coda_write(dev, bit_ptr, CODA9_REG_JPEG_GBU_FF_RPTR); + coda_write(dev, 3, CODA9_REG_JPEG_GBU_CTRL); +} + +static const int bus_req_num[] = { + [CODA9_JPEG_FORMAT_420] = 2, + [CODA9_JPEG_FORMAT_422] = 3, + [CODA9_JPEG_FORMAT_224] = 3, + [CODA9_JPEG_FORMAT_444] = 4, + [CODA9_JPEG_FORMAT_400] = 4, +}; + +#define MCU_INFO(mcu_block_num, comp_num, comp0_info, comp1_info, comp2_info) \ + (((mcu_block_num) << CODA9_JPEG_MCU_BLOCK_NUM_OFFSET) | \ + ((comp_num) << CODA9_JPEG_COMP_NUM_OFFSET) | \ + ((comp0_info) << CODA9_JPEG_COMP0_INFO_OFFSET) | \ + ((comp1_info) << CODA9_JPEG_COMP1_INFO_OFFSET) | \ + ((comp2_info) << CODA9_JPEG_COMP2_INFO_OFFSET)) + +static const u32 mcu_info[] = { + [CODA9_JPEG_FORMAT_420] = MCU_INFO(6, 3, 10, 5, 5), + [CODA9_JPEG_FORMAT_422] = MCU_INFO(4, 3, 9, 5, 5), + [CODA9_JPEG_FORMAT_224] = MCU_INFO(4, 3, 6, 5, 5), + [CODA9_JPEG_FORMAT_444] = MCU_INFO(3, 3, 5, 5, 5), + [CODA9_JPEG_FORMAT_400] = MCU_INFO(1, 1, 5, 0, 0), +}; + +/* + * Convert Huffman table specifcations to tables of codes and code lengths. + * For reference, see JPEG ITU-T.81 (ISO/IEC 10918-1) [1] + * + * [1] https://www.w3.org/Graphics/JPEG/itu-t81.pdf + */ +static int coda9_jpeg_gen_enc_huff_tab(struct coda_ctx *ctx, int tab_num, + int *ehufsi, int *ehufco) +{ + int i, j, k, lastk, si, code, maxsymbol; + const u8 *bits, *huffval; + struct { + int size[256]; + int code[256]; + } *huff; + static const unsigned char *huff_tabs[4] = { + luma_dc, luma_ac, chroma_dc, chroma_ac, + }; + int ret = -EINVAL; + + huff = kzalloc(sizeof(*huff), GFP_KERNEL); + if (!huff) + return -ENOMEM; + + bits = huff_tabs[tab_num]; + huffval = huff_tabs[tab_num] + 16; + + maxsymbol = tab_num & 1 ? 256 : 16; + + /* Figure C.1 - Generation of table of Huffman code sizes */ + k = 0; + for (i = 1; i <= 16; i++) { + j = bits[i - 1]; + if (k + j > maxsymbol) + goto out; + while (j--) + huff->size[k++] = i; + } + lastk = k; + + /* Figure C.2 - Generation of table of Huffman codes */ + k = 0; + code = 0; + si = huff->size[0]; + while (k < lastk) { + while (huff->size[k] == si) { + huff->code[k++] = code; + code++; + } + if (code >= (1 << si)) + goto out; + code <<= 1; + si++; + } + + /* Figure C.3 - Ordering procedure for encoding procedure code tables */ + for (k = 0; k < lastk; k++) { + i = huffval[k]; + if (i >= maxsymbol || ehufsi[i]) + goto out; + ehufco[i] = huff->code[k]; + ehufsi[i] = huff->size[k]; + } + + ret = 0; +out: + kfree(huff); + return ret; +} + +#define DC_TABLE_INDEX0 0 +#define AC_TABLE_INDEX0 1 +#define DC_TABLE_INDEX1 2 +#define AC_TABLE_INDEX1 3 + +static u8 *coda9_jpeg_get_huff_bits(struct coda_ctx *ctx, int tab_num) +{ + struct coda_huff_tab *huff_tab = ctx->params.jpeg_huff_tab; + + if (!huff_tab) + return NULL; + + switch (tab_num) { + case DC_TABLE_INDEX0: return huff_tab->luma_dc; + case AC_TABLE_INDEX0: return huff_tab->luma_ac; + case DC_TABLE_INDEX1: return huff_tab->chroma_dc; + case AC_TABLE_INDEX1: return huff_tab->chroma_ac; + } + + return NULL; +} + +static int coda9_jpeg_gen_dec_huff_tab(struct coda_ctx *ctx, int tab_num) +{ + int ptr_cnt = 0, huff_code = 0, zero_flag = 0, data_flag = 0; + u8 *huff_bits; + s16 *huff_max; + s16 *huff_min; + s8 *huff_ptr; + int ofs; + int i; + + huff_bits = coda9_jpeg_get_huff_bits(ctx, tab_num); + if (!huff_bits) + return -EINVAL; + + /* DC/AC Luma, DC/AC Chroma -> DC Luma/Chroma, AC Luma/Chroma */ + ofs = ((tab_num & 1) << 1) | ((tab_num >> 1) & 1); + ofs *= 16; + + huff_ptr = ctx->params.jpeg_huff_tab->ptr + ofs; + huff_max = ctx->params.jpeg_huff_tab->max + ofs; + huff_min = ctx->params.jpeg_huff_tab->min + ofs; + + for (i = 0; i < 16; i++) { + if (huff_bits[i]) { + huff_ptr[i] = ptr_cnt; + ptr_cnt += huff_bits[i]; + huff_min[i] = huff_code; + huff_max[i] = huff_code + (huff_bits[i] - 1); + data_flag = 1; + zero_flag = 0; + } else { + huff_ptr[i] = -1; + huff_min[i] = -1; + huff_max[i] = -1; + zero_flag = 1; + } + + if (data_flag == 1) { + if (zero_flag == 1) + huff_code <<= 1; + else + huff_code = (huff_max[i] + 1) << 1; + } + } + + return 0; +} + +static int coda9_jpeg_load_huff_tab(struct coda_ctx *ctx) +{ + struct { + int size[4][256]; + int code[4][256]; + } *huff; + u32 *huff_data; + int i, j; + int ret; + + huff = kzalloc(sizeof(*huff), GFP_KERNEL); + if (!huff) + return -ENOMEM; + + /* Generate all four (luma/chroma DC/AC) code/size lookup tables */ + for (i = 0; i < 4; i++) { + ret = coda9_jpeg_gen_enc_huff_tab(ctx, i, huff->size[i], + huff->code[i]); + if (ret) + goto out; + } + + if (!ctx->params.jpeg_huff_data) { + ctx->params.jpeg_huff_data = + kzalloc(sizeof(u32) * CODA9_JPEG_ENC_HUFF_DATA_SIZE, + GFP_KERNEL); + if (!ctx->params.jpeg_huff_data) { + ret = -ENOMEM; + goto out; + } + } + huff_data = ctx->params.jpeg_huff_data; + + for (j = 0; j < 4; j++) { + /* Store Huffman lookup tables in AC0, AC1, DC0, DC1 order */ + int t = (j == 0) ? AC_TABLE_INDEX0 : + (j == 1) ? AC_TABLE_INDEX1 : + (j == 2) ? DC_TABLE_INDEX0 : + DC_TABLE_INDEX1; + /* DC tables only have 16 entries */ + int len = (j < 2) ? 256 : 16; + + for (i = 0; i < len; i++) { + if (huff->size[t][i] == 0 && huff->code[t][i] == 0) + *(huff_data++) = 0; + else + *(huff_data++) = + ((huff->size[t][i] - 1) << 16) | + huff->code[t][i]; + } + } + + ret = 0; +out: + kfree(huff); + return ret; +} + +static void coda9_jpeg_write_huff_tab(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + u32 *huff_data = ctx->params.jpeg_huff_data; + int i; + + /* Write Huffman size/code lookup tables in AC0, AC1, DC0, DC1 order */ + coda_write(dev, 0x3, CODA9_REG_JPEG_HUFF_CTRL); + for (i = 0; i < CODA9_JPEG_ENC_HUFF_DATA_SIZE; i++) + coda_write(dev, *(huff_data++), CODA9_REG_JPEG_HUFF_DATA); + coda_write(dev, 0x0, CODA9_REG_JPEG_HUFF_CTRL); +} + +static inline void coda9_jpeg_write_qmat_quotients(struct coda_dev *dev, + u8 *qmat, int index) +{ + int i; + + coda_write(dev, index | 0x3, CODA9_REG_JPEG_QMAT_CTRL); + for (i = 0; i < 64; i++) + coda_write(dev, 0x80000 / qmat[i], CODA9_REG_JPEG_QMAT_DATA); + coda_write(dev, index, CODA9_REG_JPEG_QMAT_CTRL); +} + +static void coda9_jpeg_load_qmat_tab(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + u8 *luma_tab; + u8 *chroma_tab; + + luma_tab = ctx->params.jpeg_qmat_tab[0]; + if (!luma_tab) + luma_tab = luma_q; + + chroma_tab = ctx->params.jpeg_qmat_tab[1]; + if (!chroma_tab) + chroma_tab = chroma_q; + + coda9_jpeg_write_qmat_quotients(dev, luma_tab, 0x00); + coda9_jpeg_write_qmat_quotients(dev, chroma_tab, 0x40); + coda9_jpeg_write_qmat_quotients(dev, chroma_tab, 0x80); +} + +struct coda_jpeg_stream { + u8 *curr; + u8 *end; +}; + +static inline int coda_jpeg_put_byte(u8 byte, struct coda_jpeg_stream *stream) +{ + if (stream->curr >= stream->end) + return -EINVAL; + + *stream->curr++ = byte; + + return 0; +} + +static inline int coda_jpeg_put_word(u16 word, struct coda_jpeg_stream *stream) +{ + if (stream->curr + sizeof(__be16) > stream->end) + return -EINVAL; + + put_unaligned_be16(word, stream->curr); + stream->curr += sizeof(__be16); + + return 0; +} + +static int coda_jpeg_put_table(u16 marker, u8 index, const u8 *table, + size_t len, struct coda_jpeg_stream *stream) +{ + int i, ret; + + ret = coda_jpeg_put_word(marker, stream); + if (ret < 0) + return ret; + ret = coda_jpeg_put_word(3 + len, stream); + if (ret < 0) + return ret; + ret = coda_jpeg_put_byte(index, stream); + for (i = 0; i < len && ret == 0; i++) + ret = coda_jpeg_put_byte(table[i], stream); + + return ret; +} + +static int coda_jpeg_define_quantization_table(struct coda_ctx *ctx, u8 index, + struct coda_jpeg_stream *stream) +{ + return coda_jpeg_put_table(DQT_MARKER, index, + ctx->params.jpeg_qmat_tab[index], 64, + stream); +} + +static int coda_jpeg_define_huffman_table(u8 index, const u8 *table, size_t len, + struct coda_jpeg_stream *stream) +{ + return coda_jpeg_put_table(DHT_MARKER, index, table, len, stream); +} + +static int coda9_jpeg_encode_header(struct coda_ctx *ctx, int len, u8 *buf) +{ + struct coda_jpeg_stream stream = { buf, buf + len }; + struct coda_q_data *q_data_src; + int chroma_format, comp_num; + int i, ret, pad; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + chroma_format = coda9_jpeg_chroma_format(q_data_src->fourcc); + if (chroma_format < 0) + return 0; + + /* Start Of Image */ + ret = coda_jpeg_put_word(SOI_MARKER, &stream); + if (ret < 0) + return ret; + + /* Define Restart Interval */ + if (ctx->params.jpeg_restart_interval) { + ret = coda_jpeg_put_word(DRI_MARKER, &stream); + if (ret < 0) + return ret; + ret = coda_jpeg_put_word(4, &stream); + if (ret < 0) + return ret; + ret = coda_jpeg_put_word(ctx->params.jpeg_restart_interval, + &stream); + if (ret < 0) + return ret; + } + + /* Define Quantization Tables */ + ret = coda_jpeg_define_quantization_table(ctx, 0x00, &stream); + if (ret < 0) + return ret; + if (chroma_format != CODA9_JPEG_FORMAT_400) { + ret = coda_jpeg_define_quantization_table(ctx, 0x01, &stream); + if (ret < 0) + return ret; + } + + /* Define Huffman Tables */ + ret = coda_jpeg_define_huffman_table(0x00, luma_dc, 16 + 12, &stream); + if (ret < 0) + return ret; + ret = coda_jpeg_define_huffman_table(0x10, luma_ac, 16 + 162, &stream); + if (ret < 0) + return ret; + if (chroma_format != CODA9_JPEG_FORMAT_400) { + ret = coda_jpeg_define_huffman_table(0x01, chroma_dc, 16 + 12, + &stream); + if (ret < 0) + return ret; + ret = coda_jpeg_define_huffman_table(0x11, chroma_ac, 16 + 162, + &stream); + if (ret < 0) + return ret; + } + + /* Start Of Frame */ + ret = coda_jpeg_put_word(SOF_MARKER, &stream); + if (ret < 0) + return ret; + comp_num = (chroma_format == CODA9_JPEG_FORMAT_400) ? 1 : 3; + ret = coda_jpeg_put_word(8 + comp_num * 3, &stream); + if (ret < 0) + return ret; + ret = coda_jpeg_put_byte(0x08, &stream); + if (ret < 0) + return ret; + ret = coda_jpeg_put_word(q_data_src->height, &stream); + if (ret < 0) + return ret; + ret = coda_jpeg_put_word(q_data_src->width, &stream); + if (ret < 0) + return ret; + ret = coda_jpeg_put_byte(comp_num, &stream); + if (ret < 0) + return ret; + for (i = 0; i < comp_num; i++) { + static unsigned char subsampling[5][3] = { + [CODA9_JPEG_FORMAT_420] = { 0x22, 0x11, 0x11 }, + [CODA9_JPEG_FORMAT_422] = { 0x21, 0x11, 0x11 }, + [CODA9_JPEG_FORMAT_224] = { 0x12, 0x11, 0x11 }, + [CODA9_JPEG_FORMAT_444] = { 0x11, 0x11, 0x11 }, + [CODA9_JPEG_FORMAT_400] = { 0x11 }, + }; + + /* Component identifier, matches SOS */ + ret = coda_jpeg_put_byte(i + 1, &stream); + if (ret < 0) + return ret; + ret = coda_jpeg_put_byte(subsampling[chroma_format][i], + &stream); + if (ret < 0) + return ret; + /* Chroma table index */ + ret = coda_jpeg_put_byte((i == 0) ? 0 : 1, &stream); + if (ret < 0) + return ret; + } + + /* Pad to multiple of 8 bytes */ + pad = (stream.curr - buf) % 8; + if (pad) { + pad = 8 - pad; + while (pad--) { + ret = coda_jpeg_put_byte(0x00, &stream); + if (ret < 0) + return ret; + } + } + + return stream.curr - buf; +} + +/* + * Scale quantization table using nonlinear scaling factor + * u8 qtab[64], scale [50,190] + */ +static void coda_scale_quant_table(u8 *q_tab, int scale) +{ + unsigned int temp; + int i; + + for (i = 0; i < 64; i++) { + temp = DIV_ROUND_CLOSEST((unsigned int)q_tab[i] * scale, 100); + if (temp <= 0) + temp = 1; + if (temp > 255) + temp = 255; + q_tab[i] = (unsigned char)temp; + } +} + +void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality) +{ + unsigned int scale; + + ctx->params.jpeg_quality = quality; + + /* Clip quality setting to [5,100] interval */ + if (quality > 100) + quality = 100; + if (quality < 5) + quality = 5; + + /* + * Non-linear scaling factor: + * [5,50] -> [1000..100], [51,100] -> [98..0] + */ + if (quality < 50) + scale = 5000 / quality; + else + scale = 200 - 2 * quality; + + if (ctx->params.jpeg_qmat_tab[0]) { + memcpy(ctx->params.jpeg_qmat_tab[0], luma_q, 64); + coda_scale_quant_table(ctx->params.jpeg_qmat_tab[0], scale); + } + if (ctx->params.jpeg_qmat_tab[1]) { + memcpy(ctx->params.jpeg_qmat_tab[1], chroma_q, 64); + coda_scale_quant_table(ctx->params.jpeg_qmat_tab[1], scale); + } +} + +/* + * Encoder context operations + */ + +static int coda9_jpeg_start_encoding(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + int ret; + + ret = coda9_jpeg_load_huff_tab(ctx); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "error loading Huffman tables\n"); + return ret; + } + if (!ctx->params.jpeg_qmat_tab[0]) { + ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL); + if (!ctx->params.jpeg_qmat_tab[0]) + return -ENOMEM; + } + if (!ctx->params.jpeg_qmat_tab[1]) { + ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL); + if (!ctx->params.jpeg_qmat_tab[1]) + return -ENOMEM; + } + coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality); + + return 0; +} + +static int coda9_jpeg_prepare_encode(struct coda_ctx *ctx) +{ + struct coda_q_data *q_data_src; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct coda_dev *dev = ctx->dev; + u32 start_addr, end_addr; + u16 aligned_width, aligned_height; + bool chroma_interleave; + int chroma_format; + int header_len; + int ret; + ktime_t timeout; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + + if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == 0) + vb2_set_plane_payload(&src_buf->vb2_buf, 0, + vb2_plane_size(&src_buf->vb2_buf, 0)); + + src_buf->sequence = ctx->osequence; + dst_buf->sequence = ctx->osequence; + ctx->osequence++; + + src_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; + src_buf->flags &= ~V4L2_BUF_FLAG_PFRAME; + + coda_set_gdi_regs(ctx); + + start_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + end_addr = start_addr + vb2_plane_size(&dst_buf->vb2_buf, 0); + + chroma_format = coda9_jpeg_chroma_format(q_data_src->fourcc); + if (chroma_format < 0) + return chroma_format; + + /* Round image dimensions to multiple of MCU size */ + aligned_width = round_up(q_data_src->width, width_align[chroma_format]); + aligned_height = round_up(q_data_src->height, + height_align[chroma_format]); + if (aligned_width != q_data_src->bytesperline) { + v4l2_err(&dev->v4l2_dev, "wrong stride: %d instead of %d\n", + aligned_width, q_data_src->bytesperline); + } + + header_len = + coda9_jpeg_encode_header(ctx, + vb2_plane_size(&dst_buf->vb2_buf, 0), + vb2_plane_vaddr(&dst_buf->vb2_buf, 0)); + if (header_len < 0) + return header_len; + + coda_write(dev, start_addr + header_len, CODA9_REG_JPEG_BBC_BAS_ADDR); + coda_write(dev, end_addr, CODA9_REG_JPEG_BBC_END_ADDR); + coda_write(dev, start_addr + header_len, CODA9_REG_JPEG_BBC_WR_PTR); + coda_write(dev, start_addr + header_len, CODA9_REG_JPEG_BBC_RD_PTR); + coda_write(dev, 0, CODA9_REG_JPEG_BBC_CUR_POS); + /* 64 words per 256-byte page */ + coda_write(dev, 64, CODA9_REG_JPEG_BBC_DATA_CNT); + coda_write(dev, start_addr, CODA9_REG_JPEG_BBC_EXT_ADDR); + coda_write(dev, 0, CODA9_REG_JPEG_BBC_INT_ADDR); + + coda_write(dev, 0, CODA9_REG_JPEG_GBU_BT_PTR); + coda_write(dev, 0, CODA9_REG_JPEG_GBU_WD_PTR); + coda_write(dev, 0, CODA9_REG_JPEG_GBU_BBSR); + coda_write(dev, BIT(31) | ((end_addr - start_addr - header_len) / 256), + CODA9_REG_JPEG_BBC_STRM_CTRL); + coda_write(dev, 0, CODA9_REG_JPEG_GBU_CTRL); + coda_write(dev, 0, CODA9_REG_JPEG_GBU_FF_RPTR); + coda_write(dev, 127, CODA9_REG_JPEG_GBU_BBER); + coda_write(dev, 64, CODA9_REG_JPEG_GBU_BBIR); + coda_write(dev, 64, CODA9_REG_JPEG_GBU_BBHR); + + chroma_interleave = (q_data_src->fourcc == V4L2_PIX_FMT_NV12); + coda_write(dev, CODA9_JPEG_PIC_CTRL_TC_DIRECTION | + CODA9_JPEG_PIC_CTRL_ENCODER_EN, CODA9_REG_JPEG_PIC_CTRL); + coda_write(dev, 0, CODA9_REG_JPEG_SCL_INFO); + coda_write(dev, chroma_interleave, CODA9_REG_JPEG_DPB_CONFIG); + coda_write(dev, ctx->params.jpeg_restart_interval, + CODA9_REG_JPEG_RST_INTVAL); + coda_write(dev, 1, CODA9_REG_JPEG_BBC_CTRL); + + coda_write(dev, bus_req_num[chroma_format], CODA9_REG_JPEG_OP_INFO); + + coda9_jpeg_write_huff_tab(ctx); + coda9_jpeg_load_qmat_tab(ctx); + + if (ctx->params.rot_mode & CODA_ROT_90) { + aligned_width = aligned_height; + aligned_height = q_data_src->bytesperline; + if (chroma_format == CODA9_JPEG_FORMAT_422) + chroma_format = CODA9_JPEG_FORMAT_224; + else if (chroma_format == CODA9_JPEG_FORMAT_224) + chroma_format = CODA9_JPEG_FORMAT_422; + } + /* These need to be multiples of MCU size */ + coda_write(dev, aligned_width << 16 | aligned_height, + CODA9_REG_JPEG_PIC_SIZE); + coda_write(dev, ctx->params.rot_mode ? + (CODA_ROT_MIR_ENABLE | ctx->params.rot_mode) : 0, + CODA9_REG_JPEG_ROT_INFO); + + coda_write(dev, mcu_info[chroma_format], CODA9_REG_JPEG_MCU_INFO); + + coda_write(dev, 1, CODA9_GDI_CONTROL); + timeout = ktime_add_us(ktime_get(), 100000); + do { + ret = coda_read(dev, CODA9_GDI_STATUS); + if (ktime_compare(ktime_get(), timeout) > 0) { + v4l2_err(&dev->v4l2_dev, "timeout waiting for GDI\n"); + return -ETIMEDOUT; + } + } while (!ret); + + coda_write(dev, (chroma_format << 17) | (chroma_interleave << 16) | + q_data_src->bytesperline, CODA9_GDI_INFO_CONTROL); + /* The content of this register seems to be irrelevant: */ + coda_write(dev, aligned_width << 16 | aligned_height, + CODA9_GDI_INFO_PIC_SIZE); + + coda_write_base(ctx, q_data_src, src_buf, CODA9_GDI_INFO_BASE_Y); + + coda_write(dev, 0, CODA9_REG_JPEG_DPB_BASE00); + coda_write(dev, 0, CODA9_GDI_CONTROL); + coda_write(dev, 1, CODA9_GDI_PIC_INIT_HOST); + + coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); + coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); + + trace_coda_jpeg_run(ctx, src_buf); + + coda_write(dev, 1, CODA9_REG_JPEG_PIC_START); + + return 0; +} + +static void coda9_jpeg_finish_encode(struct coda_ctx *ctx) +{ + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct coda_dev *dev = ctx->dev; + u32 wr_ptr, start_ptr; + u32 err_mb; + + if (ctx->aborting) { + coda_write(ctx->dev, 0, CODA9_REG_JPEG_BBC_FLUSH_CMD); + return; + } + + /* + * Lock to make sure that an encoder stop command running in parallel + * will either already have marked src_buf as last, or it will wake up + * the capture queue after the buffers are returned. + */ + mutex_lock(&ctx->wakeup_mutex); + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + trace_coda_jpeg_done(ctx, dst_buf); + + /* + * Set plane payload to the number of bytes written out + * by the JPEG processing unit + */ + start_ptr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + wr_ptr = coda_read(dev, CODA9_REG_JPEG_BBC_WR_PTR); + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr); + + err_mb = coda_read(dev, CODA9_REG_JPEG_PIC_ERRMB); + if (err_mb) + coda_dbg(1, ctx, "ERRMB: 0x%x\n", err_mb); + + coda_write(dev, 0, CODA9_REG_JPEG_BBC_FLUSH_CMD); + + dst_buf->flags &= ~(V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_LAST); + dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; + dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; + + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); + + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + coda_m2m_buf_done(ctx, dst_buf, err_mb ? VB2_BUF_STATE_ERROR : + VB2_BUF_STATE_DONE); + mutex_unlock(&ctx->wakeup_mutex); + + coda_dbg(1, ctx, "job finished: encoded frame (%u)%s\n", + dst_buf->sequence, + (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); + + /* + * Reset JPEG processing unit after each encode run to work + * around hangups when switching context between encoder and + * decoder. + */ + coda_hw_reset(ctx); +} + +static void coda9_jpeg_encode_timeout(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + u32 end_addr, wr_ptr; + + /* Handle missing BBC overflow interrupt via timeout */ + end_addr = coda_read(dev, CODA9_REG_JPEG_BBC_END_ADDR); + wr_ptr = coda_read(dev, CODA9_REG_JPEG_BBC_WR_PTR); + if (wr_ptr >= end_addr - 256) { + v4l2_err(&dev->v4l2_dev, "JPEG too large for capture buffer\n"); + coda9_jpeg_finish_encode(ctx); + return; + } + + coda_hw_reset(ctx); +} + +static void coda9_jpeg_release(struct coda_ctx *ctx) +{ + int i; + + if (ctx->params.jpeg_qmat_tab[0] == luma_q) + ctx->params.jpeg_qmat_tab[0] = NULL; + if (ctx->params.jpeg_qmat_tab[1] == chroma_q) + ctx->params.jpeg_qmat_tab[1] = NULL; + for (i = 0; i < 3; i++) + kfree(ctx->params.jpeg_qmat_tab[i]); + kfree(ctx->params.jpeg_huff_data); + kfree(ctx->params.jpeg_huff_tab); +} + +const struct coda_context_ops coda9_jpeg_encode_ops = { + .queue_init = coda_encoder_queue_init, + .start_streaming = coda9_jpeg_start_encoding, + .prepare_run = coda9_jpeg_prepare_encode, + .finish_run = coda9_jpeg_finish_encode, + .run_timeout = coda9_jpeg_encode_timeout, + .release = coda9_jpeg_release, +}; + +/* + * Decoder context operations + */ + +static int coda9_jpeg_start_decoding(struct coda_ctx *ctx) +{ + ctx->params.jpeg_qmat_index[0] = 0; + ctx->params.jpeg_qmat_index[1] = 1; + ctx->params.jpeg_qmat_index[2] = 1; + ctx->params.jpeg_qmat_tab[0] = luma_q; + ctx->params.jpeg_qmat_tab[1] = chroma_q; + /* nothing more to do here */ + + /* TODO: we could already scan the first header to get the chroma + * format. + */ + + return 0; +} + +static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + int aligned_width, aligned_height; + int chroma_format; + int ret; + u32 val, dst_fourcc; + struct coda_q_data *q_data_src, *q_data_dst; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + int chroma_interleave; + int scl_hor_mode, scl_ver_mode; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_fourcc = q_data_dst->fourcc; + + scl_hor_mode = coda_jpeg_scale(q_data_src->width, q_data_dst->width); + scl_ver_mode = coda_jpeg_scale(q_data_src->height, q_data_dst->height); + + if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == 0) + vb2_set_plane_payload(&src_buf->vb2_buf, 0, + vb2_plane_size(&src_buf->vb2_buf, 0)); + + chroma_format = coda9_jpeg_chroma_format(q_data_dst->fourcc); + if (chroma_format < 0) + return chroma_format; + + ret = coda_jpeg_decode_header(ctx, &src_buf->vb2_buf); + if (ret < 0) { + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); + + return ret; + } + + /* Round image dimensions to multiple of MCU size */ + aligned_width = round_up(q_data_src->width, width_align[chroma_format]); + aligned_height = round_up(q_data_src->height, height_align[chroma_format]); + if (aligned_width != q_data_dst->bytesperline) { + v4l2_err(&dev->v4l2_dev, "stride mismatch: %d != %d\n", + aligned_width, q_data_dst->bytesperline); + } + + coda_set_gdi_regs(ctx); + + val = ctx->params.jpeg_huff_ac_index[0] << 12 | + ctx->params.jpeg_huff_ac_index[1] << 11 | + ctx->params.jpeg_huff_ac_index[2] << 10 | + ctx->params.jpeg_huff_dc_index[0] << 9 | + ctx->params.jpeg_huff_dc_index[1] << 8 | + ctx->params.jpeg_huff_dc_index[2] << 7; + if (ctx->params.jpeg_huff_tab) + val |= CODA9_JPEG_PIC_CTRL_USER_HUFFMAN_EN; + coda_write(dev, val, CODA9_REG_JPEG_PIC_CTRL); + + coda_write(dev, aligned_width << 16 | aligned_height, + CODA9_REG_JPEG_PIC_SIZE); + + chroma_interleave = (dst_fourcc == V4L2_PIX_FMT_NV12); + coda_write(dev, 0, CODA9_REG_JPEG_ROT_INFO); + coda_write(dev, bus_req_num[chroma_format], CODA9_REG_JPEG_OP_INFO); + coda_write(dev, mcu_info[chroma_format], CODA9_REG_JPEG_MCU_INFO); + if (scl_hor_mode || scl_ver_mode) + val = CODA9_JPEG_SCL_ENABLE | (scl_hor_mode << 2) | scl_ver_mode; + else + val = 0; + coda_write(dev, val, CODA9_REG_JPEG_SCL_INFO); + coda_write(dev, chroma_interleave, CODA9_REG_JPEG_DPB_CONFIG); + coda_write(dev, ctx->params.jpeg_restart_interval, + CODA9_REG_JPEG_RST_INTVAL); + + if (ctx->params.jpeg_huff_tab) + coda9_jpeg_dec_huff_setup(ctx); + + coda9_jpeg_qmat_setup(ctx); + + coda9_jpeg_dec_bbc_gbu_setup(ctx, &src_buf->vb2_buf, + ctx->jpeg_ecs_offset); + + coda_write(dev, 0, CODA9_REG_JPEG_RST_INDEX); + coda_write(dev, 0, CODA9_REG_JPEG_RST_COUNT); + + coda_write(dev, 0, CODA9_REG_JPEG_DPCM_DIFF_Y); + coda_write(dev, 0, CODA9_REG_JPEG_DPCM_DIFF_CB); + coda_write(dev, 0, CODA9_REG_JPEG_DPCM_DIFF_CR); + + coda_write(dev, 0, CODA9_REG_JPEG_ROT_INFO); + + coda_write(dev, 1, CODA9_GDI_CONTROL); + do { + ret = coda_read(dev, CODA9_GDI_STATUS); + } while (!ret); + + val = (chroma_format << 17) | (chroma_interleave << 16) | + q_data_dst->bytesperline; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + val |= 3 << 20; + coda_write(dev, val, CODA9_GDI_INFO_CONTROL); + + coda_write(dev, aligned_width << 16 | aligned_height, + CODA9_GDI_INFO_PIC_SIZE); + + coda_write_base(ctx, q_data_dst, dst_buf, CODA9_GDI_INFO_BASE_Y); + + coda_write(dev, 0, CODA9_REG_JPEG_DPB_BASE00); + coda_write(dev, 0, CODA9_GDI_CONTROL); + coda_write(dev, 1, CODA9_GDI_PIC_INIT_HOST); + + trace_coda_jpeg_run(ctx, src_buf); + + coda_write(dev, 1, CODA9_REG_JPEG_PIC_START); + + return 0; +} + +static void coda9_jpeg_finish_decode(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + struct vb2_v4l2_buffer *dst_buf, *src_buf; + struct coda_q_data *q_data_dst; + u32 err_mb; + + err_mb = coda_read(dev, CODA9_REG_JPEG_PIC_ERRMB); + if (err_mb) + v4l2_err(&dev->v4l2_dev, "ERRMB: 0x%x\n", err_mb); + + coda_write(dev, 0, CODA9_REG_JPEG_BBC_FLUSH_CMD); + + /* + * Lock to make sure that a decoder stop command running in parallel + * will either already have marked src_buf as last, or it will wake up + * the capture queue after the buffers are returned. + */ + mutex_lock(&ctx->wakeup_mutex); + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + dst_buf->sequence = ctx->osequence++; + + trace_coda_jpeg_done(ctx, dst_buf); + + dst_buf->flags &= ~(V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_LAST); + dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; + dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; + + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); + + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, q_data_dst->sizeimage); + + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + coda_m2m_buf_done(ctx, dst_buf, err_mb ? VB2_BUF_STATE_ERROR : + VB2_BUF_STATE_DONE); + + mutex_unlock(&ctx->wakeup_mutex); + + coda_dbg(1, ctx, "job finished: decoded frame (%u)%s\n", + dst_buf->sequence, + (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); + + /* + * Reset JPEG processing unit after each decode run to work + * around hangups when switching context between encoder and + * decoder. + */ + coda_hw_reset(ctx); +} + +const struct coda_context_ops coda9_jpeg_decode_ops = { + .queue_init = coda_encoder_queue_init, /* non-bitstream operation */ + .start_streaming = coda9_jpeg_start_decoding, + .prepare_run = coda9_jpeg_prepare_decode, + .finish_run = coda9_jpeg_finish_decode, + .release = coda9_jpeg_release, +}; + +irqreturn_t coda9_jpeg_irq_handler(int irq, void *data) +{ + struct coda_dev *dev = data; + struct coda_ctx *ctx; + int status; + int err_mb; + + status = coda_read(dev, CODA9_REG_JPEG_PIC_STATUS); + if (status == 0) + return IRQ_HANDLED; + coda_write(dev, status, CODA9_REG_JPEG_PIC_STATUS); + + if (status & CODA9_JPEG_STATUS_OVERFLOW) + v4l2_err(&dev->v4l2_dev, "JPEG overflow\n"); + + if (status & CODA9_JPEG_STATUS_BBC_INT) + v4l2_err(&dev->v4l2_dev, "JPEG BBC interrupt\n"); + + if (status & CODA9_JPEG_STATUS_ERROR) { + v4l2_err(&dev->v4l2_dev, "JPEG error\n"); + + err_mb = coda_read(dev, CODA9_REG_JPEG_PIC_ERRMB); + if (err_mb) { + v4l2_err(&dev->v4l2_dev, + "ERRMB: 0x%x: rst idx %d, mcu pos (%d,%d)\n", + err_mb, err_mb >> 24, (err_mb >> 12) & 0xfff, + err_mb & 0xfff); + } + } + + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); + if (!ctx) { + v4l2_err(&dev->v4l2_dev, + "Instance released before the end of transaction\n"); + mutex_unlock(&dev->coda_mutex); + return IRQ_HANDLED; + } + + complete(&ctx->completion); + + return IRQ_HANDLED; +} diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/coda-mpeg2.c b/drivers/media/platform/chips-media/coda/coda-mpeg2.c --- a/drivers/media/platform/chips-media/coda/coda-mpeg2.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/coda-mpeg2.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Coda multi-standard codec IP - MPEG-2 helper functions + * + * Copyright (C) 2019 Pengutronix, Philipp Zabel + */ + +#include +#include +#include "coda.h" + +int coda_mpeg2_profile(int profile_idc) +{ + switch (profile_idc) { + case 5: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE; + case 4: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN; + case 3: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SNR_SCALABLE; + case 2: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SPATIALLY_SCALABLE; + case 1: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH; + default: + return -EINVAL; + } +} + +int coda_mpeg2_level(int level_idc) +{ + switch (level_idc) { + case 10: + return V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW; + case 8: + return V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN; + case 6: + return V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440; + case 4: + return V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH; + default: + return -EINVAL; + } +} + +/* + * Check if the buffer starts with the MPEG-2 sequence header (with or without + * quantization matrix) and extension header, for example: + * + * 00 00 01 b3 2d 01 e0 34 08 8b a3 81 + * 10 11 11 12 12 12 13 13 13 13 14 14 14 14 14 15 + * 15 15 15 15 15 16 16 16 16 16 16 16 17 17 17 17 + * 17 17 17 17 18 18 18 19 18 18 18 19 1a 1a 1a 1a + * 19 1b 1b 1b 1b 1b 1c 1c 1c 1c 1e 1e 1e 1f 1f 21 + * 00 00 01 b5 14 8a 00 01 00 00 + * + * or: + * + * 00 00 01 b3 08 00 40 15 ff ff e0 28 + * 00 00 01 b5 14 8a 00 01 00 00 + * + * Returns the detected header size in bytes or 0. + */ +u32 coda_mpeg2_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size) +{ + static const u8 sequence_header_start[4] = { 0x00, 0x00, 0x01, 0xb3 }; + static const union { + u8 extension_start[4]; + u8 start_code_prefix[3]; + } u = { { 0x00, 0x00, 0x01, 0xb5 } }; + + if (size < 22 || + memcmp(buf, sequence_header_start, 4) != 0) + return 0; + + if ((size == 22 || + (size >= 25 && memcmp(buf + 22, u.start_code_prefix, 3) == 0)) && + memcmp(buf + 12, u.extension_start, 4) == 0) + return 22; + + if ((size == 86 || + (size > 89 && memcmp(buf + 86, u.start_code_prefix, 3) == 0)) && + memcmp(buf + 76, u.extension_start, 4) == 0) + return 86; + + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/coda-mpeg4.c b/drivers/media/platform/chips-media/coda/coda-mpeg4.c --- a/drivers/media/platform/chips-media/coda/coda-mpeg4.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/coda-mpeg4.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Coda multi-standard codec IP - MPEG-4 helper functions + * + * Copyright (C) 2019 Pengutronix, Philipp Zabel + */ + +#include +#include + +#include "coda.h" + +int coda_mpeg4_profile(int profile_idc) +{ + switch (profile_idc) { + case 0: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE; + case 15: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE; + case 2: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE; + case 1: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE; + case 11: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY; + default: + return -EINVAL; + } +} + +int coda_mpeg4_level(int level_idc) +{ + switch (level_idc) { + case 0: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_0; + case 1: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_1; + case 2: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_2; + case 3: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_3; + case 4: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_4; + case 5: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_5; + default: + return -EINVAL; + } +} + +/* + * Check if the buffer starts with the MPEG-4 visual object sequence and visual + * object headers, for example: + * + * 00 00 01 b0 f1 + * 00 00 01 b5 a9 13 00 00 01 00 00 00 01 20 08 + * d4 8d 88 00 f5 04 04 08 14 30 3f + * + * Returns the detected header size in bytes or 0. + */ +u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size) +{ + static const u8 vos_start[4] = { 0x00, 0x00, 0x01, 0xb0 }; + static const union { + u8 vo_start[4]; + u8 start_code_prefix[3]; + } u = { { 0x00, 0x00, 0x01, 0xb5 } }; + + if (size < 30 || + memcmp(buf, vos_start, 4) != 0 || + memcmp(buf + 5, u.vo_start, 4) != 0) + return 0; + + if (size == 30 || + (size >= 33 && memcmp(buf + 30, u.start_code_prefix, 3) == 0)) + return 30; + + if (size == 31 || + (size >= 34 && memcmp(buf + 31, u.start_code_prefix, 3) == 0)) + return 31; + + if (size == 32 || + (size >= 35 && memcmp(buf + 32, u.start_code_prefix, 3) == 0)) + return 32; + + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/coda_regs.h b/drivers/media/platform/chips-media/coda/coda_regs.h --- a/drivers/media/platform/chips-media/coda/coda_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/coda_regs.h 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,563 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * linux/drivers/media/platform/chips-media/coda_regs.h + * + * Copyright (C) 2012 Vista Silicon SL + * Javier Martin + * Xavier Duret + */ + +#ifndef _REGS_CODA_H_ +#define _REGS_CODA_H_ + +/* HW registers */ +#define CODA_REG_BIT_CODE_RUN 0x000 +#define CODA_REG_RUN_ENABLE (1 << 0) +#define CODA_REG_BIT_CODE_DOWN 0x004 +#define CODA_DOWN_ADDRESS_SET(x) (((x) & 0xffff) << 16) +#define CODA_DOWN_DATA_SET(x) ((x) & 0xffff) +#define CODA_REG_BIT_HOST_IN_REQ 0x008 +#define CODA_REG_BIT_INT_CLEAR 0x00c +#define CODA_REG_BIT_INT_CLEAR_SET 0x1 +#define CODA_REG_BIT_INT_STATUS 0x010 +#define CODA_REG_BIT_CODE_RESET 0x014 +#define CODA_REG_RESET_ENABLE (1 << 0) +#define CODA_REG_BIT_CUR_PC 0x018 +#define CODA9_REG_BIT_SW_RESET 0x024 +#define CODA9_SW_RESET_BPU_CORE 0x008 +#define CODA9_SW_RESET_BPU_BUS 0x010 +#define CODA9_SW_RESET_VCE_CORE 0x020 +#define CODA9_SW_RESET_VCE_BUS 0x040 +#define CODA9_SW_RESET_GDI_CORE 0x080 +#define CODA9_SW_RESET_GDI_BUS 0x100 +#define CODA9_REG_BIT_SW_RESET_STATUS 0x034 + +/* Static SW registers */ +#define CODA_REG_BIT_CODE_BUF_ADDR 0x100 +#define CODA_REG_BIT_WORK_BUF_ADDR 0x104 +#define CODA_REG_BIT_PARA_BUF_ADDR 0x108 +#define CODA_REG_BIT_STREAM_CTRL 0x10c +#define CODA7_STREAM_BUF_PIC_RESET (1 << 4) +#define CODADX6_STREAM_BUF_PIC_RESET (1 << 3) +#define CODA7_STREAM_BUF_PIC_FLUSH (1 << 3) +#define CODADX6_STREAM_BUF_PIC_FLUSH (1 << 2) +#define CODA7_STREAM_BUF_DYNALLOC_EN (1 << 5) +#define CODADX6_STREAM_BUF_DYNALLOC_EN (1 << 4) +#define CODADX6_STREAM_CHKDIS_OFFSET (1 << 1) +#define CODA7_STREAM_SEL_64BITS_ENDIAN (1 << 1) +#define CODA_STREAM_ENDIAN_SELECT (1 << 0) +#define CODA_REG_BIT_FRAME_MEM_CTRL 0x110 +#define CODA9_FRAME_ENABLE_BWB (1 << 12) +#define CODA9_FRAME_TILED2LINEAR (1 << 11) +#define CODA_FRAME_CHROMA_INTERLEAVE (1 << 2) +#define CODA_IMAGE_ENDIAN_SELECT (1 << 0) +#define CODA_REG_BIT_BIT_STREAM_PARAM 0x114 +#define CODA_BIT_STREAM_END_FLAG (1 << 2) +#define CODA_BIT_DEC_SEQ_INIT_ESCAPE (1 << 0) +#define CODA_REG_BIT_TEMP_BUF_ADDR 0x118 +#define CODA_REG_BIT_RD_PTR(x) (0x120 + 8 * (x)) +#define CODA_REG_BIT_WR_PTR(x) (0x124 + 8 * (x)) +#define CODA_REG_BIT_FRM_DIS_FLG(x) (0x150 + 4 * (x)) +#define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR 0x140 +#define CODA7_REG_BIT_AXI_SRAM_USE 0x140 +#define CODA9_USE_HOST_BTP_ENABLE (1 << 13) +#define CODA9_USE_HOST_OVL_ENABLE (1 << 12) +#define CODA7_USE_HOST_ME_ENABLE (1 << 11) +#define CODA9_USE_HOST_DBK_ENABLE (3 << 10) +#define CODA7_USE_HOST_OVL_ENABLE (1 << 10) +#define CODA7_USE_HOST_DBK_ENABLE (1 << 9) +#define CODA9_USE_HOST_IP_ENABLE (1 << 9) +#define CODA7_USE_HOST_IP_ENABLE (1 << 8) +#define CODA9_USE_HOST_BIT_ENABLE (1 << 8) +#define CODA7_USE_HOST_BIT_ENABLE (1 << 7) +#define CODA9_USE_BTP_ENABLE (1 << 5) +#define CODA7_USE_ME_ENABLE (1 << 4) +#define CODA9_USE_OVL_ENABLE (1 << 4) +#define CODA7_USE_OVL_ENABLE (1 << 3) +#define CODA9_USE_DBK_ENABLE (3 << 2) +#define CODA7_USE_DBK_ENABLE (1 << 2) +#define CODA7_USE_IP_ENABLE (1 << 1) +#define CODA7_USE_BIT_ENABLE (1 << 0) + +#define CODA_REG_BIT_BUSY 0x160 +#define CODA_REG_BIT_BUSY_FLAG 1 +#define CODA_REG_BIT_RUN_COMMAND 0x164 +#define CODA_COMMAND_SEQ_INIT 1 +#define CODA_COMMAND_SEQ_END 2 +#define CODA_COMMAND_PIC_RUN 3 +#define CODA_COMMAND_SET_FRAME_BUF 4 +#define CODA_COMMAND_ENCODE_HEADER 5 +#define CODA_COMMAND_ENC_PARA_SET 6 +#define CODA_COMMAND_DEC_PARA_SET 7 +#define CODA_COMMAND_DEC_BUF_FLUSH 8 +#define CODA_COMMAND_RC_CHANGE_PARAMETER 9 +#define CODA_COMMAND_FIRMWARE_GET 0xf +#define CODA_REG_BIT_RUN_INDEX 0x168 +#define CODA_INDEX_SET(x) ((x) & 0x3) +#define CODA_REG_BIT_RUN_COD_STD 0x16c +#define CODADX6_MODE_DECODE_MP4 0 +#define CODADX6_MODE_ENCODE_MP4 1 +#define CODADX6_MODE_DECODE_H264 2 +#define CODADX6_MODE_ENCODE_H264 3 +#define CODA7_MODE_DECODE_H264 0 +#define CODA7_MODE_DECODE_VC1 1 +#define CODA7_MODE_DECODE_MP2 2 +#define CODA7_MODE_DECODE_MP4 3 +#define CODA7_MODE_DECODE_DV3 3 +#define CODA7_MODE_DECODE_RV 4 +#define CODA7_MODE_DECODE_MJPG 5 +#define CODA7_MODE_ENCODE_H264 8 +#define CODA7_MODE_ENCODE_MP4 11 +#define CODA7_MODE_ENCODE_MJPG 13 +#define CODA9_MODE_DECODE_H264 0 +#define CODA9_MODE_DECODE_VC1 1 +#define CODA9_MODE_DECODE_MP2 2 +#define CODA9_MODE_DECODE_MP4 3 +#define CODA9_MODE_DECODE_DV3 3 +#define CODA9_MODE_DECODE_RV 4 +#define CODA9_MODE_DECODE_AVS 5 +#define CODA9_MODE_DECODE_MJPG 6 +#define CODA9_MODE_DECODE_VPX 7 +#define CODA9_MODE_ENCODE_H264 8 +#define CODA9_MODE_ENCODE_MP4 11 +#define CODA9_MODE_ENCODE_MJPG 13 +#define CODA_MODE_INVALID 0xffff +#define CODA_REG_BIT_INT_ENABLE 0x170 +#define CODA_INT_INTERRUPT_ENABLE (1 << 3) +#define CODA_REG_BIT_INT_REASON 0x174 +#define CODA7_REG_BIT_RUN_AUX_STD 0x178 +#define CODA_MP4_AUX_MPEG4 0 +#define CODA_MP4_AUX_DIVX3 1 +#define CODA_VPX_AUX_THO 0 +#define CODA_VPX_AUX_VP6 1 +#define CODA_VPX_AUX_VP8 2 +#define CODA_H264_AUX_AVC 0 +#define CODA_H264_AUX_MVC 1 + +/* + * Commands' mailbox: + * registers with offsets in the range 0x180-0x1d0 + * have different meaning depending on the command being + * issued. + */ + +/* Decoder Sequence Initialization */ +#define CODA_CMD_DEC_SEQ_BB_START 0x180 +#define CODA_CMD_DEC_SEQ_BB_SIZE 0x184 +#define CODA_CMD_DEC_SEQ_OPTION 0x188 +#define CODA_NO_INT_ENABLE (1 << 10) +#define CODA_REORDER_ENABLE (1 << 1) +#define CODADX6_QP_REPORT (1 << 0) +#define CODA7_MP4_DEBLK_ENABLE (1 << 0) +#define CODA_CMD_DEC_SEQ_SRC_SIZE 0x18c +#define CODA_CMD_DEC_SEQ_START_BYTE 0x190 +#define CODA_CMD_DEC_SEQ_PS_BB_START 0x194 +#define CODA_CMD_DEC_SEQ_PS_BB_SIZE 0x198 +#define CODA_CMD_DEC_SEQ_JPG_THUMB_EN 0x19c +#define CODA_CMD_DEC_SEQ_MP4_ASP_CLASS 0x19c +#define CODA_MP4_CLASS_MPEG4 0 +#define CODA_CMD_DEC_SEQ_X264_MV_EN 0x19c +#define CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE 0x1a0 + +#define CODA7_RET_DEC_SEQ_ASPECT 0x1b0 +#define CODA9_RET_DEC_SEQ_BITRATE 0x1b4 +#define CODA_RET_DEC_SEQ_SUCCESS 0x1c0 +#define CODA_RET_DEC_SEQ_SRC_FMT 0x1c4 /* SRC_SIZE on CODA7 */ +#define CODA_RET_DEC_SEQ_SRC_SIZE 0x1c4 +#define CODA_RET_DEC_SEQ_SRC_F_RATE 0x1c8 +#define CODA9_RET_DEC_SEQ_ASPECT 0x1c8 +#define CODA_RET_DEC_SEQ_FRAME_NEED 0x1cc +#define CODA_RET_DEC_SEQ_FRAME_DELAY 0x1d0 +#define CODA_RET_DEC_SEQ_INFO 0x1d4 +#define CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT 0x1d8 +#define CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM 0x1dc +#define CODA_RET_DEC_SEQ_NEXT_FRAME_NUM 0x1e0 +#define CODA_RET_DEC_SEQ_ERR_REASON 0x1e0 +#define CODA_RET_DEC_SEQ_FRATE_NR 0x1e4 +#define CODA_RET_DEC_SEQ_FRATE_DR 0x1e8 +#define CODA_RET_DEC_SEQ_JPG_PARA 0x1e4 +#define CODA_RET_DEC_SEQ_JPG_THUMB_IND 0x1e8 +#define CODA7_RET_DEC_SEQ_HEADER_REPORT 0x1ec + +/* Decoder Picture Run */ +#define CODA_CMD_DEC_PIC_ROT_MODE 0x180 +#define CODA_CMD_DEC_PIC_ROT_ADDR_Y 0x184 +#define CODA9_CMD_DEC_PIC_ROT_INDEX 0x184 +#define CODA_CMD_DEC_PIC_ROT_ADDR_CB 0x188 +#define CODA9_CMD_DEC_PIC_ROT_ADDR_Y 0x188 +#define CODA_CMD_DEC_PIC_ROT_ADDR_CR 0x18c +#define CODA9_CMD_DEC_PIC_ROT_ADDR_CB 0x18c +#define CODA_CMD_DEC_PIC_ROT_STRIDE 0x190 +#define CODA9_CMD_DEC_PIC_ROT_ADDR_CR 0x190 +#define CODA9_CMD_DEC_PIC_ROT_STRIDE 0x1b8 + +#define CODA_CMD_DEC_PIC_OPTION 0x194 +#define CODA_PRE_SCAN_EN (1 << 0) +#define CODA_PRE_SCAN_MODE_DECODE (0 << 1) +#define CODA_PRE_SCAN_MODE_RETURN (1 << 1) +#define CODA_IFRAME_SEARCH_EN (1 << 2) +#define CODA_SKIP_FRAME_MODE (0x3 << 3) +#define CODA_CMD_DEC_PIC_SKIP_NUM 0x198 +#define CODA_CMD_DEC_PIC_CHUNK_SIZE 0x19c +#define CODA_CMD_DEC_PIC_BB_START 0x1a0 +#define CODA_CMD_DEC_PIC_START_BYTE 0x1a4 +#define CODA_RET_DEC_PIC_SIZE 0x1bc +#define CODA_RET_DEC_PIC_FRAME_NUM 0x1c0 +#define CODA_RET_DEC_PIC_FRAME_IDX 0x1c4 +#define CODA_RET_DEC_PIC_ERR_MB 0x1c8 +#define CODA_RET_DEC_PIC_TYPE 0x1cc +#define CODA_PIC_TYPE_MASK 0x7 +#define CODA_PIC_TYPE_MASK_VC1 0x3f +#define CODA9_PIC_TYPE_FIRST_MASK (0x7 << 3) +#define CODA9_PIC_TYPE_IDR_MASK (0x3 << 6) +#define CODA7_PIC_TYPE_H264_NPF_MASK (0x3 << 16) +#define CODA7_PIC_TYPE_INTERLACED (1 << 18) +#define CODA_RET_DEC_PIC_POST 0x1d0 +#define CODA_RET_DEC_PIC_MVC_REPORT 0x1d0 +#define CODA_RET_DEC_PIC_OPTION 0x1d4 +#define CODA_RET_DEC_PIC_SUCCESS 0x1d8 +#define CODA_RET_DEC_PIC_CUR_IDX 0x1dc +#define CODA_RET_DEC_PIC_CROP_LEFT_RIGHT 0x1e0 +#define CODA_RET_DEC_PIC_CROP_TOP_BOTTOM 0x1e4 +#define CODA_RET_DEC_PIC_FRAME_NEED 0x1ec + +#define CODA9_RET_DEC_PIC_VP8_PIC_REPORT 0x1e8 +#define CODA9_RET_DEC_PIC_ASPECT 0x1f0 +#define CODA9_RET_DEC_PIC_VP8_SCALE_INFO 0x1f0 +#define CODA9_RET_DEC_PIC_FRATE_NR 0x1f4 +#define CODA9_RET_DEC_PIC_FRATE_DR 0x1f8 + +/* Encoder Sequence Initialization */ +#define CODA_CMD_ENC_SEQ_BB_START 0x180 +#define CODA_CMD_ENC_SEQ_BB_SIZE 0x184 +#define CODA_CMD_ENC_SEQ_OPTION 0x188 +#define CODA7_OPTION_AVCINTRA16X16ONLY_OFFSET 9 +#define CODA9_OPTION_MVC_PREFIX_NAL_OFFSET 9 +#define CODA7_OPTION_GAMMA_OFFSET 8 +#define CODA9_OPTION_MVC_PARASET_REFRESH_OFFSET 8 +#define CODA7_OPTION_RCQPMAX_OFFSET 7 +#define CODA9_OPTION_GAMMA_OFFSET 7 +#define CODADX6_OPTION_GAMMA_OFFSET 7 +#define CODA7_OPTION_RCQPMIN_OFFSET 6 +#define CODA9_OPTION_RCQPMAX_OFFSET 6 +#define CODA_OPTION_LIMITQP_OFFSET 6 +#define CODA_OPTION_RCINTRAQP_OFFSET 5 +#define CODA_OPTION_FMO_OFFSET 4 +#define CODA9_OPTION_MVC_INTERVIEW_OFFSET 4 +#define CODA_OPTION_AVC_AUD_OFFSET 2 +#define CODA_OPTION_SLICEREPORT_OFFSET 1 +#define CODA_CMD_ENC_SEQ_COD_STD 0x18c +#define CODA_STD_MPEG4 0 +#define CODA9_STD_H264 0 +#define CODA_STD_H263 1 +#define CODA_STD_H264 2 +#define CODA9_STD_MPEG4 3 + +#define CODA_CMD_ENC_SEQ_SRC_SIZE 0x190 +#define CODA7_PICWIDTH_OFFSET 16 +#define CODA7_PICWIDTH_MASK 0xffff +#define CODADX6_PICWIDTH_OFFSET 10 +#define CODADX6_PICWIDTH_MASK 0x3ff +#define CODA_PICHEIGHT_OFFSET 0 +#define CODADX6_PICHEIGHT_MASK 0x3ff +#define CODA7_PICHEIGHT_MASK 0xffff +#define CODA_CMD_ENC_SEQ_SRC_F_RATE 0x194 +#define CODA_FRATE_RES_OFFSET 0 +#define CODA_FRATE_RES_MASK 0xffff +#define CODA_FRATE_DIV_OFFSET 16 +#define CODA_FRATE_DIV_MASK 0xffff +#define CODA_CMD_ENC_SEQ_MP4_PARA 0x198 +#define CODA_MP4PARAM_VERID_OFFSET 6 +#define CODA_MP4PARAM_VERID_MASK 0x01 +#define CODA_MP4PARAM_INTRADCVLCTHR_OFFSET 2 +#define CODA_MP4PARAM_INTRADCVLCTHR_MASK 0x07 +#define CODA_MP4PARAM_REVERSIBLEVLCENABLE_OFFSET 1 +#define CODA_MP4PARAM_REVERSIBLEVLCENABLE_MASK 0x01 +#define CODA_MP4PARAM_DATAPARTITIONENABLE_OFFSET 0 +#define CODA_MP4PARAM_DATAPARTITIONENABLE_MASK 0x01 +#define CODA_CMD_ENC_SEQ_263_PARA 0x19c +#define CODA_263PARAM_ANNEXJENABLE_OFFSET 2 +#define CODA_263PARAM_ANNEXJENABLE_MASK 0x01 +#define CODA_263PARAM_ANNEXKENABLE_OFFSET 1 +#define CODA_263PARAM_ANNEXKENABLE_MASK 0x01 +#define CODA_263PARAM_ANNEXTENABLE_OFFSET 0 +#define CODA_263PARAM_ANNEXTENABLE_MASK 0x01 +#define CODA_CMD_ENC_SEQ_264_PARA 0x1a0 +#define CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET 12 +#define CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK 0x0f +#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET 8 +#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK 0x0f +#define CODA_264PARAM_DISABLEDEBLK_OFFSET 6 +#define CODA_264PARAM_DISABLEDEBLK_MASK 0x03 +#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET 5 +#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK 0x01 +#define CODA_264PARAM_CHROMAQPOFFSET_OFFSET 0 +#define CODA_264PARAM_CHROMAQPOFFSET_MASK 0x1f +#define CODA_CMD_ENC_SEQ_SLICE_MODE 0x1a4 +#define CODA_SLICING_SIZE_OFFSET 2 +#define CODA_SLICING_SIZE_MASK 0x3fffffff +#define CODA_SLICING_UNIT_OFFSET 1 +#define CODA_SLICING_UNIT_MASK 0x01 +#define CODA_SLICING_MODE_OFFSET 0 +#define CODA_SLICING_MODE_MASK 0x01 +#define CODA_CMD_ENC_SEQ_GOP_SIZE 0x1a8 +#define CODA_GOP_SIZE_OFFSET 0 +#define CODA_GOP_SIZE_MASK 0x3f +#define CODA_CMD_ENC_SEQ_RC_PARA 0x1ac +#define CODA_RATECONTROL_AUTOSKIP_OFFSET 31 +#define CODA_RATECONTROL_AUTOSKIP_MASK 0x01 +#define CODA_RATECONTROL_INITIALDELAY_OFFSET 16 +#define CODA_RATECONTROL_INITIALDELAY_MASK 0x7fff +#define CODA_RATECONTROL_BITRATE_OFFSET 1 +#define CODA_RATECONTROL_BITRATE_MASK 0x7fff +#define CODA_RATECONTROL_ENABLE_OFFSET 0 +#define CODA_RATECONTROL_ENABLE_MASK 0x01 +#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE 0x1b0 +#define CODA_CMD_ENC_SEQ_INTRA_REFRESH 0x1b4 +#define CODADX6_CMD_ENC_SEQ_FMO 0x1b8 +#define CODA_FMOPARAM_TYPE_OFFSET 4 +#define CODA_FMOPARAM_TYPE_MASK 1 +#define CODA_FMOPARAM_SLICENUM_OFFSET 0 +#define CODA_FMOPARAM_SLICENUM_MASK 0x0f +#define CODADX6_CMD_ENC_SEQ_INTRA_QP 0x1bc +#define CODA7_CMD_ENC_SEQ_SEARCH_BASE 0x1b8 +#define CODA7_CMD_ENC_SEQ_SEARCH_SIZE 0x1bc +#define CODA7_CMD_ENC_SEQ_INTRA_QP 0x1c4 +#define CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX 0x1c8 +#define CODA_QPMIN_OFFSET 8 +#define CODA_QPMIN_MASK 0x3f +#define CODA_QPMAX_OFFSET 0 +#define CODA_QPMAX_MASK 0x3f +#define CODA_CMD_ENC_SEQ_RC_GAMMA 0x1cc +#define CODA_GAMMA_OFFSET 0 +#define CODA_GAMMA_MASK 0xffff +#define CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE 0x1d0 +#define CODA9_CMD_ENC_SEQ_INTRA_WEIGHT 0x1d4 +#define CODA9_CMD_ENC_SEQ_ME_OPTION 0x1d8 +#define CODA_RET_ENC_SEQ_SUCCESS 0x1c0 + +#define CODA_CMD_ENC_SEQ_JPG_PARA 0x198 +#define CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL 0x19C +#define CODA_CMD_ENC_SEQ_JPG_THUMB_EN 0x1a0 +#define CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE 0x1a4 +#define CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET 0x1a8 + +/* Encoder Parameter Change */ +#define CODA_CMD_ENC_PARAM_CHANGE_ENABLE 0x180 +#define CODA_PARAM_CHANGE_RC_GOP BIT(0) +#define CODA_PARAM_CHANGE_RC_INTRA_QP BIT(1) +#define CODA_PARAM_CHANGE_RC_BITRATE BIT(2) +#define CODA_PARAM_CHANGE_RC_FRAME_RATE BIT(3) +#define CODA_PARAM_CHANGE_INTRA_MB_NUM BIT(4) +#define CODA_PARAM_CHANGE_SLICE_MODE BIT(5) +#define CODA_PARAM_CHANGE_HEC_MODE BIT(6) +#define CODA_CMD_ENC_PARAM_RC_GOP 0x184 +#define CODA_CMD_ENC_PARAM_RC_INTRA_QP 0x188 +#define CODA_CMD_ENC_PARAM_RC_BITRATE 0x18c +#define CODA_CMD_ENC_PARAM_RC_FRAME_RATE 0x190 +#define CODA_CMD_ENC_PARAM_INTRA_MB_NUM 0x194 +#define CODA_CMD_ENC_PARAM_SLICE_MODE 0x198 +#define CODA_CMD_ENC_PARAM_HEC_MODE 0x19c +#define CODA_RET_ENC_PARAM_CHANGE_SUCCESS 0x1c0 + +/* Encoder Picture Run */ +#define CODA9_CMD_ENC_PIC_SRC_INDEX 0x180 +#define CODA9_CMD_ENC_PIC_SRC_STRIDE 0x184 +#define CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC 0x1a4 +#define CODA9_CMD_ENC_PIC_SRC_ADDR_Y 0x1a8 +#define CODA9_CMD_ENC_PIC_SRC_ADDR_CB 0x1ac +#define CODA9_CMD_ENC_PIC_SRC_ADDR_CR 0x1b0 +#define CODA_CMD_ENC_PIC_SRC_ADDR_Y 0x180 +#define CODA_CMD_ENC_PIC_SRC_ADDR_CB 0x184 +#define CODA_CMD_ENC_PIC_SRC_ADDR_CR 0x188 +#define CODA_CMD_ENC_PIC_QS 0x18c +#define CODA_CMD_ENC_PIC_ROT_MODE 0x190 +#define CODA_ROT_MIR_ENABLE (1 << 4) +#define CODA_ROT_0 (0x0 << 0) +#define CODA_ROT_90 (0x1 << 0) +#define CODA_ROT_180 (0x2 << 0) +#define CODA_ROT_270 (0x3 << 0) +#define CODA_MIR_NONE (0x0 << 2) +#define CODA_MIR_VER (0x1 << 2) +#define CODA_MIR_HOR (0x2 << 2) +#define CODA_MIR_VER_HOR (0x3 << 2) +#define CODA_CMD_ENC_PIC_OPTION 0x194 +#define CODA_FORCE_IPICTURE BIT(1) +#define CODA_REPORT_MB_INFO BIT(3) +#define CODA_REPORT_MV_INFO BIT(4) +#define CODA_REPORT_SLICE_INFO BIT(5) +#define CODA_CMD_ENC_PIC_BB_START 0x198 +#define CODA_CMD_ENC_PIC_BB_SIZE 0x19c +#define CODA_RET_ENC_FRAME_NUM 0x1c0 +#define CODA_RET_ENC_PIC_TYPE 0x1c4 +#define CODA_RET_ENC_PIC_FRAME_IDX 0x1c8 +#define CODA_RET_ENC_PIC_SLICE_NUM 0x1cc +#define CODA_RET_ENC_PIC_FLAG 0x1d0 +#define CODA_RET_ENC_PIC_SUCCESS 0x1d8 + +/* Set Frame Buffer */ +#define CODA_CMD_SET_FRAME_BUF_NUM 0x180 +#define CODA_CMD_SET_FRAME_BUF_STRIDE 0x184 +#define CODA_CMD_SET_FRAME_SLICE_BB_START 0x188 +#define CODA_CMD_SET_FRAME_SLICE_BB_SIZE 0x18c +#define CODA9_CMD_SET_FRAME_SUBSAMP_A 0x188 +#define CODA9_CMD_SET_FRAME_SUBSAMP_B 0x18c +#define CODA7_CMD_SET_FRAME_AXI_BIT_ADDR 0x190 +#define CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR 0x194 +#define CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR 0x198 +#define CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR 0x19c +#define CODA7_CMD_SET_FRAME_AXI_OVL_ADDR 0x1a0 +#define CODA7_CMD_SET_FRAME_MAX_DEC_SIZE 0x1a4 +#define CODA9_CMD_SET_FRAME_AXI_BTP_ADDR 0x1a4 +#define CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE 0x1a8 +#define CODA9_CMD_SET_FRAME_CACHE_SIZE 0x1a8 +#define CODA9_CMD_SET_FRAME_CACHE_CONFIG 0x1ac +#define CODA9_CACHE_BYPASS_OFFSET 28 +#define CODA9_CACHE_DUALCONF_OFFSET 26 +#define CODA9_CACHE_PAGEMERGE_OFFSET 24 +#define CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET 16 +#define CODA9_CACHE_CB_BUFFER_SIZE_OFFSET 8 +#define CODA9_CACHE_CR_BUFFER_SIZE_OFFSET 0 +#define CODA9_CMD_SET_FRAME_SUBSAMP_A_MVC 0x1b0 +#define CODA9_CMD_SET_FRAME_SUBSAMP_B_MVC 0x1b4 +#define CODA9_CMD_SET_FRAME_DP_BUF_BASE 0x1b0 +#define CODA9_CMD_SET_FRAME_DP_BUF_SIZE 0x1b4 +#define CODA9_CMD_SET_FRAME_MAX_DEC_SIZE 0x1b8 +#define CODA9_CMD_SET_FRAME_DELAY 0x1bc + +/* Encoder Header */ +#define CODA_CMD_ENC_HEADER_CODE 0x180 +#define CODA_GAMMA_OFFSET 0 +#define CODA_HEADER_H264_SPS 0 +#define CODA_HEADER_H264_PPS 1 +#define CODA_HEADER_MP4V_VOL 0 +#define CODA_HEADER_MP4V_VOS 1 +#define CODA_HEADER_MP4V_VIS 2 +#define CODA9_HEADER_FRAME_CROP (1 << 3) +#define CODA_CMD_ENC_HEADER_BB_START 0x184 +#define CODA_CMD_ENC_HEADER_BB_SIZE 0x188 +#define CODA9_CMD_ENC_HEADER_FRAME_CROP_H 0x18c +#define CODA9_CMD_ENC_HEADER_FRAME_CROP_V 0x190 + +/* Get Version */ +#define CODA_CMD_FIRMWARE_VERNUM 0x1c0 +#define CODA_FIRMWARE_PRODUCT(x) (((x) >> 16) & 0xffff) +#define CODA_FIRMWARE_MAJOR(x) (((x) >> 12) & 0x0f) +#define CODA_FIRMWARE_MINOR(x) (((x) >> 8) & 0x0f) +#define CODA_FIRMWARE_RELEASE(x) ((x) & 0xff) +#define CODA_FIRMWARE_VERNUM(product, major, minor, release) \ + ((product) << 16 | ((major) << 12) | \ + ((minor) << 8) | (release)) +#define CODA9_CMD_FIRMWARE_CODE_REV 0x1c4 + +#define CODA9_GDMA_BASE 0x1000 +#define CODA9_GDI_CONTROL (CODA9_GDMA_BASE + 0x034) +#define CODA9_GDI_PIC_INIT_HOST (CODA9_GDMA_BASE + 0x038) +#define CODA9_GDI_STATUS (CODA9_GDMA_BASE + 0x080) +#define CODA9_GDI_WPROT_ERR_CLR (CODA9_GDMA_BASE + 0x0a0) +#define CODA9_GDI_WPROT_RGN_EN (CODA9_GDMA_BASE + 0x0ac) + +#define CODA9_GDI_BUS_CTRL (CODA9_GDMA_BASE + 0x0f0) +#define CODA9_GDI_BUS_STATUS (CODA9_GDMA_BASE + 0x0f4) + +#define CODA9_GDI_INFO_CONTROL (CODA9_GDMA_BASE + 0x400) +#define CODA9_GDI_INFO_PIC_SIZE (CODA9_GDMA_BASE + 0x404) +#define CODA9_GDI_INFO_BASE_Y (CODA9_GDMA_BASE + 0x408) +#define CODA9_GDI_INFO_BASE_CB (CODA9_GDMA_BASE + 0x40c) +#define CODA9_GDI_INFO_BASE_CR (CODA9_GDMA_BASE + 0x410) + +#define CODA9_GDI_XY2_CAS_0 (CODA9_GDMA_BASE + 0x800) +#define CODA9_GDI_XY2_CAS_F (CODA9_GDMA_BASE + 0x83c) + +#define CODA9_GDI_XY2_BA_0 (CODA9_GDMA_BASE + 0x840) +#define CODA9_GDI_XY2_BA_1 (CODA9_GDMA_BASE + 0x844) +#define CODA9_GDI_XY2_BA_2 (CODA9_GDMA_BASE + 0x848) +#define CODA9_GDI_XY2_BA_3 (CODA9_GDMA_BASE + 0x84c) + +#define CODA9_GDI_XY2_RAS_0 (CODA9_GDMA_BASE + 0x850) +#define CODA9_GDI_XY2_RAS_F (CODA9_GDMA_BASE + 0x88c) + +#define CODA9_GDI_XY2_RBC_CONFIG (CODA9_GDMA_BASE + 0x890) +#define CODA9_XY2RBC_SEPARATE_MAP BIT(19) +#define CODA9_XY2RBC_TOP_BOT_SPLIT BIT(18) +#define CODA9_XY2RBC_TILED_MAP BIT(17) +#define CODA9_XY2RBC_CA_INC_HOR BIT(16) +#define CODA9_GDI_RBC2_AXI_0 (CODA9_GDMA_BASE + 0x8a0) +#define CODA9_GDI_RBC2_AXI_1F (CODA9_GDMA_BASE + 0x91c) +#define CODA9_GDI_TILEDBUF_BASE (CODA9_GDMA_BASE + 0x920) + +#define CODA9_JPEG_BASE 0x3000 +#define CODA9_REG_JPEG_PIC_START (CODA9_JPEG_BASE + 0x000) +#define CODA9_REG_JPEG_PIC_STATUS (CODA9_JPEG_BASE + 0x004) +#define CODA9_JPEG_STATUS_OVERFLOW BIT(3) +#define CODA9_JPEG_STATUS_BBC_INT BIT(2) +#define CODA9_JPEG_STATUS_ERROR BIT(1) +#define CODA9_JPEG_STATUS_DONE BIT(0) +#define CODA9_REG_JPEG_PIC_ERRMB (CODA9_JPEG_BASE + 0x008) +#define CODA9_JPEG_ERRMB_RESTART_IDX_MASK (0xf << 24) +#define CODA9_JPEG_ERRMB_MCU_POS_X_MASK (0xfff << 12) +#define CODA9_JPEG_ERRMB_MCU_POS_Y_MASK 0xfff +#define CODA9_REG_JPEG_PIC_CTRL (CODA9_JPEG_BASE + 0x010) +#define CODA9_JPEG_PIC_CTRL_USER_HUFFMAN_EN BIT(6) +#define CODA9_JPEG_PIC_CTRL_TC_DIRECTION BIT(4) +#define CODA9_JPEG_PIC_CTRL_ENCODER_EN BIT(3) +#define CODA9_REG_JPEG_PIC_SIZE (CODA9_JPEG_BASE + 0x014) +#define CODA9_REG_JPEG_MCU_INFO (CODA9_JPEG_BASE + 0x018) +#define CODA9_JPEG_MCU_BLOCK_NUM_OFFSET 16 +#define CODA9_JPEG_COMP_NUM_OFFSET 12 +#define CODA9_JPEG_COMP0_INFO_OFFSET 8 +#define CODA9_JPEG_COMP1_INFO_OFFSET 4 +#define CODA9_JPEG_COMP2_INFO_OFFSET 0 +#define CODA9_REG_JPEG_ROT_INFO (CODA9_JPEG_BASE + 0x01c) +#define CODA9_JPEG_ROT_MIR_ENABLE BIT(4) +#define CODA9_JPEG_ROT_MIR_MODE_MASK 0xf +#define CODA9_REG_JPEG_SCL_INFO (CODA9_JPEG_BASE + 0x020) +#define CODA9_JPEG_SCL_ENABLE BIT(4) +#define CODA9_JPEG_SCL_HOR_MODE_MASK (0x3 << 2) +#define CODA9_JPEG_SCL_VER_MODE_MASK (0x3 << 0) +#define CODA9_REG_JPEG_IF_INFO (CODA9_JPEG_BASE + 0x024) +#define CODA9_JPEG_SENS_IF_CLR BIT(1) +#define CODA9_JPEG_DISP_IF_CLR BIT(0) +#define CODA9_REG_JPEG_OP_INFO (CODA9_JPEG_BASE + 0x02c) +#define CODA9_JPEG_BUS_REQ_NUM_OFFSET 0 +#define CODA9_JPEG_BUS_REQ_NUM_MASK 0x7 +#define CODA9_REG_JPEG_DPB_CONFIG (CODA9_JPEG_BASE + 0x030) +#define CODA9_REG_JPEG_DPB_BASE00 (CODA9_JPEG_BASE + 0x040) +#define CODA9_REG_JPEG_HUFF_CTRL (CODA9_JPEG_BASE + 0x080) +#define CODA9_REG_JPEG_HUFF_ADDR (CODA9_JPEG_BASE + 0x084) +#define CODA9_REG_JPEG_HUFF_DATA (CODA9_JPEG_BASE + 0x088) +#define CODA9_REG_JPEG_QMAT_CTRL (CODA9_JPEG_BASE + 0x090) +#define CODA9_REG_JPEG_QMAT_ADDR (CODA9_JPEG_BASE + 0x094) +#define CODA9_REG_JPEG_QMAT_DATA (CODA9_JPEG_BASE + 0x098) +#define CODA9_REG_JPEG_RST_INTVAL (CODA9_JPEG_BASE + 0x0b0) +#define CODA9_REG_JPEG_RST_INDEX (CODA9_JPEG_BASE + 0x0b4) +#define CODA9_REG_JPEG_RST_COUNT (CODA9_JPEG_BASE + 0x0b8) +#define CODA9_REG_JPEG_DPCM_DIFF_Y (CODA9_JPEG_BASE + 0x0f0) +#define CODA9_REG_JPEG_DPCM_DIFF_CB (CODA9_JPEG_BASE + 0x0f4) +#define CODA9_REG_JPEG_DPCM_DIFF_CR (CODA9_JPEG_BASE + 0x0f8) +#define CODA9_REG_JPEG_GBU_CTRL (CODA9_JPEG_BASE + 0x100) +#define CODA9_REG_JPEG_GBU_BT_PTR (CODA9_JPEG_BASE + 0x110) +#define CODA9_REG_JPEG_GBU_WD_PTR (CODA9_JPEG_BASE + 0x114) +#define CODA9_REG_JPEG_GBU_TT_CNT (CODA9_JPEG_BASE + 0x118) +#define CODA9_REG_JPEG_GBU_BBSR (CODA9_JPEG_BASE + 0x140) +#define CODA9_REG_JPEG_GBU_BBER (CODA9_JPEG_BASE + 0x144) +#define CODA9_REG_JPEG_GBU_BBIR (CODA9_JPEG_BASE + 0x148) +#define CODA9_REG_JPEG_GBU_BBHR (CODA9_JPEG_BASE + 0x14c) +#define CODA9_REG_JPEG_GBU_BCNT (CODA9_JPEG_BASE + 0x158) +#define CODA9_REG_JPEG_GBU_FF_RPTR (CODA9_JPEG_BASE + 0x160) +#define CODA9_REG_JPEG_GBU_FF_WPTR (CODA9_JPEG_BASE + 0x164) +#define CODA9_REG_JPEG_BBC_END_ADDR (CODA9_JPEG_BASE + 0x208) +#define CODA9_REG_JPEG_BBC_WR_PTR (CODA9_JPEG_BASE + 0x20c) +#define CODA9_REG_JPEG_BBC_RD_PTR (CODA9_JPEG_BASE + 0x210) +#define CODA9_REG_JPEG_BBC_EXT_ADDR (CODA9_JPEG_BASE + 0x214) +#define CODA9_REG_JPEG_BBC_INT_ADDR (CODA9_JPEG_BASE + 0x218) +#define CODA9_REG_JPEG_BBC_DATA_CNT (CODA9_JPEG_BASE + 0x21c) +#define CODA9_REG_JPEG_BBC_COMMAND (CODA9_JPEG_BASE + 0x220) +#define CODA9_REG_JPEG_BBC_BUSY (CODA9_JPEG_BASE + 0x224) +#define CODA9_REG_JPEG_BBC_CTRL (CODA9_JPEG_BASE + 0x228) +#define CODA9_REG_JPEG_BBC_CUR_POS (CODA9_JPEG_BASE + 0x22c) +#define CODA9_REG_JPEG_BBC_BAS_ADDR (CODA9_JPEG_BASE + 0x230) +#define CODA9_REG_JPEG_BBC_STRM_CTRL (CODA9_JPEG_BASE + 0x234) +#define CODA9_REG_JPEG_BBC_FLUSH_CMD (CODA9_JPEG_BASE + 0x238) + +#endif diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/imx-vdoa.c b/drivers/media/platform/chips-media/coda/imx-vdoa.c --- a/drivers/media/platform/chips-media/coda/imx-vdoa.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/imx-vdoa.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * i.MX6 Video Data Order Adapter (VDOA) + * + * Copyright (C) 2014 Philipp Zabel + * Copyright (C) 2016 Pengutronix, Michael Tretter + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imx-vdoa.h" + +#define VDOA_NAME "imx-vdoa" + +#define VDOAC 0x00 +#define VDOASRR 0x04 +#define VDOAIE 0x08 +#define VDOAIST 0x0c +#define VDOAFP 0x10 +#define VDOAIEBA00 0x14 +#define VDOAIEBA01 0x18 +#define VDOAIEBA02 0x1c +#define VDOAIEBA10 0x20 +#define VDOAIEBA11 0x24 +#define VDOAIEBA12 0x28 +#define VDOASL 0x2c +#define VDOAIUBO 0x30 +#define VDOAVEBA0 0x34 +#define VDOAVEBA1 0x38 +#define VDOAVEBA2 0x3c +#define VDOAVUBO 0x40 +#define VDOASR 0x44 + +#define VDOAC_ISEL BIT(6) +#define VDOAC_PFS BIT(5) +#define VDOAC_SO BIT(4) +#define VDOAC_SYNC BIT(3) +#define VDOAC_NF BIT(2) +#define VDOAC_BNDM_MASK 0x3 +#define VDOAC_BAND_HEIGHT_8 0x0 +#define VDOAC_BAND_HEIGHT_16 0x1 +#define VDOAC_BAND_HEIGHT_32 0x2 + +#define VDOASRR_START BIT(1) +#define VDOASRR_SWRST BIT(0) + +#define VDOAIE_EITERR BIT(1) +#define VDOAIE_EIEOT BIT(0) + +#define VDOAIST_TERR BIT(1) +#define VDOAIST_EOT BIT(0) + +#define VDOAFP_FH_MASK (0x1fff << 16) +#define VDOAFP_FW_MASK (0x3fff) + +#define VDOASL_VSLY_MASK (0x3fff << 16) +#define VDOASL_ISLY_MASK (0x7fff) + +#define VDOASR_ERRW BIT(4) +#define VDOASR_EOB BIT(3) +#define VDOASR_CURRENT_FRAME (0x3 << 1) +#define VDOASR_CURRENT_BUFFER BIT(1) + +enum { + V4L2_M2M_SRC = 0, + V4L2_M2M_DST = 1, +}; + +struct vdoa_data { + struct vdoa_ctx *curr_ctx; + struct device *dev; + struct clk *vdoa_clk; + void __iomem *regs; +}; + +struct vdoa_q_data { + unsigned int width; + unsigned int height; + unsigned int bytesperline; + unsigned int sizeimage; + u32 pixelformat; +}; + +struct vdoa_ctx { + struct vdoa_data *vdoa; + struct completion completion; + struct vdoa_q_data q_data[2]; + unsigned int submitted_job; + unsigned int completed_job; +}; + +static irqreturn_t vdoa_irq_handler(int irq, void *data) +{ + struct vdoa_data *vdoa = data; + struct vdoa_ctx *curr_ctx; + u32 val; + + /* Disable interrupts */ + writel(0, vdoa->regs + VDOAIE); + + curr_ctx = vdoa->curr_ctx; + if (!curr_ctx) { + dev_warn(vdoa->dev, + "Instance released before the end of transaction\n"); + return IRQ_HANDLED; + } + + val = readl(vdoa->regs + VDOAIST); + writel(val, vdoa->regs + VDOAIST); + if (val & VDOAIST_TERR) { + val = readl(vdoa->regs + VDOASR) & VDOASR_ERRW; + dev_err(vdoa->dev, "AXI %s error\n", val ? "write" : "read"); + } else if (!(val & VDOAIST_EOT)) { + dev_warn(vdoa->dev, "Spurious interrupt\n"); + } + curr_ctx->completed_job++; + complete(&curr_ctx->completion); + + return IRQ_HANDLED; +} + +int vdoa_wait_for_completion(struct vdoa_ctx *ctx) +{ + struct vdoa_data *vdoa = ctx->vdoa; + + if (ctx->submitted_job == ctx->completed_job) + return 0; + + if (!wait_for_completion_timeout(&ctx->completion, + msecs_to_jiffies(300))) { + dev_err(vdoa->dev, + "Timeout waiting for transfer result\n"); + return -ETIMEDOUT; + } + + return 0; +} +EXPORT_SYMBOL(vdoa_wait_for_completion); + +void vdoa_device_run(struct vdoa_ctx *ctx, dma_addr_t dst, dma_addr_t src) +{ + struct vdoa_q_data *src_q_data, *dst_q_data; + struct vdoa_data *vdoa = ctx->vdoa; + u32 val; + + if (vdoa->curr_ctx) + vdoa_wait_for_completion(vdoa->curr_ctx); + + vdoa->curr_ctx = ctx; + + reinit_completion(&ctx->completion); + ctx->submitted_job++; + + src_q_data = &ctx->q_data[V4L2_M2M_SRC]; + dst_q_data = &ctx->q_data[V4L2_M2M_DST]; + + /* Progressive, no sync, 1 frame per run */ + if (dst_q_data->pixelformat == V4L2_PIX_FMT_YUYV) + val = VDOAC_PFS; + else + val = 0; + writel(val, vdoa->regs + VDOAC); + + writel(dst_q_data->height << 16 | dst_q_data->width, + vdoa->regs + VDOAFP); + + val = dst; + writel(val, vdoa->regs + VDOAIEBA00); + + writel(src_q_data->bytesperline << 16 | dst_q_data->bytesperline, + vdoa->regs + VDOASL); + + if (dst_q_data->pixelformat == V4L2_PIX_FMT_NV12 || + dst_q_data->pixelformat == V4L2_PIX_FMT_NV21) + val = dst_q_data->bytesperline * dst_q_data->height; + else + val = 0; + writel(val, vdoa->regs + VDOAIUBO); + + val = src; + writel(val, vdoa->regs + VDOAVEBA0); + val = round_up(src_q_data->bytesperline * src_q_data->height, 4096); + writel(val, vdoa->regs + VDOAVUBO); + + /* Enable interrupts and start transfer */ + writel(VDOAIE_EITERR | VDOAIE_EIEOT, vdoa->regs + VDOAIE); + writel(VDOASRR_START, vdoa->regs + VDOASRR); +} +EXPORT_SYMBOL(vdoa_device_run); + +struct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa) +{ + struct vdoa_ctx *ctx; + int err; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; + + err = clk_prepare_enable(vdoa->vdoa_clk); + if (err) { + kfree(ctx); + return NULL; + } + + init_completion(&ctx->completion); + ctx->vdoa = vdoa; + + return ctx; +} +EXPORT_SYMBOL(vdoa_context_create); + +void vdoa_context_destroy(struct vdoa_ctx *ctx) +{ + struct vdoa_data *vdoa = ctx->vdoa; + + if (vdoa->curr_ctx == ctx) { + vdoa_wait_for_completion(vdoa->curr_ctx); + vdoa->curr_ctx = NULL; + } + + clk_disable_unprepare(vdoa->vdoa_clk); + kfree(ctx); +} +EXPORT_SYMBOL(vdoa_context_destroy); + +int vdoa_context_configure(struct vdoa_ctx *ctx, + unsigned int width, unsigned int height, + u32 pixelformat) +{ + struct vdoa_q_data *src_q_data; + struct vdoa_q_data *dst_q_data; + + if (width < 16 || width > 8192 || width % 16 != 0 || + height < 16 || height > 4096 || height % 16 != 0) + return -EINVAL; + + if (pixelformat != V4L2_PIX_FMT_YUYV && + pixelformat != V4L2_PIX_FMT_NV12) + return -EINVAL; + + /* If no context is passed, only check if the format is valid */ + if (!ctx) + return 0; + + src_q_data = &ctx->q_data[V4L2_M2M_SRC]; + dst_q_data = &ctx->q_data[V4L2_M2M_DST]; + + src_q_data->width = width; + src_q_data->height = height; + src_q_data->bytesperline = width; + src_q_data->sizeimage = + round_up(src_q_data->bytesperline * height, 4096) + + src_q_data->bytesperline * height / 2; + + dst_q_data->width = width; + dst_q_data->height = height; + dst_q_data->pixelformat = pixelformat; + switch (pixelformat) { + case V4L2_PIX_FMT_YUYV: + dst_q_data->bytesperline = width * 2; + dst_q_data->sizeimage = dst_q_data->bytesperline * height; + break; + case V4L2_PIX_FMT_NV12: + default: + dst_q_data->bytesperline = width; + dst_q_data->sizeimage = + dst_q_data->bytesperline * height * 3 / 2; + break; + } + + return 0; +} +EXPORT_SYMBOL(vdoa_context_configure); + +static int vdoa_probe(struct platform_device *pdev) +{ + struct vdoa_data *vdoa; + int ret; + + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "DMA enable failed\n"); + return ret; + } + + vdoa = devm_kzalloc(&pdev->dev, sizeof(*vdoa), GFP_KERNEL); + if (!vdoa) + return -ENOMEM; + + vdoa->dev = &pdev->dev; + + vdoa->vdoa_clk = devm_clk_get(vdoa->dev, NULL); + if (IS_ERR(vdoa->vdoa_clk)) { + dev_err(vdoa->dev, "Failed to get clock\n"); + return PTR_ERR(vdoa->vdoa_clk); + } + + vdoa->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(vdoa->regs)) + return PTR_ERR(vdoa->regs); + + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; + ret = devm_request_threaded_irq(&pdev->dev, ret, NULL, + vdoa_irq_handler, IRQF_ONESHOT, + "vdoa", vdoa); + if (ret < 0) { + dev_err(vdoa->dev, "Failed to get irq\n"); + return ret; + } + + platform_set_drvdata(pdev, vdoa); + + return 0; +} + +static const struct of_device_id vdoa_dt_ids[] = { + { .compatible = "fsl,imx6q-vdoa" }, + {} +}; +MODULE_DEVICE_TABLE(of, vdoa_dt_ids); + +static struct platform_driver vdoa_driver = { + .probe = vdoa_probe, + .driver = { + .name = VDOA_NAME, + .of_match_table = vdoa_dt_ids, + }, +}; + +module_platform_driver(vdoa_driver); + +MODULE_DESCRIPTION("Video Data Order Adapter"); +MODULE_AUTHOR("Philipp Zabel "); +MODULE_ALIAS("platform:imx-vdoa"); +MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/imx-vdoa.h b/drivers/media/platform/chips-media/coda/imx-vdoa.h --- a/drivers/media/platform/chips-media/coda/imx-vdoa.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/imx-vdoa.h 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2016 Pengutronix + */ + +#ifndef IMX_VDOA_H +#define IMX_VDOA_H + +struct vdoa_data; +struct vdoa_ctx; + +#if (defined CONFIG_VIDEO_IMX_VDOA || defined CONFIG_VIDEO_IMX_VDOA_MODULE) + +struct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa); +int vdoa_context_configure(struct vdoa_ctx *ctx, + unsigned int width, unsigned int height, + u32 pixelformat); +void vdoa_context_destroy(struct vdoa_ctx *ctx); + +void vdoa_device_run(struct vdoa_ctx *ctx, dma_addr_t dst, dma_addr_t src); +int vdoa_wait_for_completion(struct vdoa_ctx *ctx); + +#else + +static inline struct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa) +{ + return NULL; +} + +static inline int vdoa_context_configure(struct vdoa_ctx *ctx, + unsigned int width, + unsigned int height, + u32 pixelformat) +{ + return 0; +} + +static inline void vdoa_context_destroy(struct vdoa_ctx *ctx) { }; + +static inline void vdoa_device_run(struct vdoa_ctx *ctx, + dma_addr_t dst, dma_addr_t src) { }; + +static inline int vdoa_wait_for_completion(struct vdoa_ctx *ctx) +{ + return 0; +}; + +#endif + +#endif /* IMX_VDOA_H */ diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/Kconfig b/drivers/media/platform/chips-media/coda/Kconfig --- a/drivers/media/platform/chips-media/coda/Kconfig 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/Kconfig 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config VIDEO_CODA + tristate "Chips&Media Coda multi-standard codec IP" + depends on V4L_MEM2MEM_DRIVERS + depends on VIDEO_DEV && OF && (ARCH_MXC || COMPILE_TEST) + select SRAM + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_VMALLOC + select V4L2_JPEG_HELPER + select V4L2_MEM2MEM_DEV + select GENERIC_ALLOCATOR + help + Coda is a range of video codec IPs that supports + H.264, MPEG-4, and other video formats. + +config VIDEO_IMX_VDOA + def_tristate VIDEO_CODA if SOC_IMX6Q || COMPILE_TEST diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/Makefile b/drivers/media/platform/chips-media/coda/Makefile --- a/drivers/media/platform/chips-media/coda/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/Makefile 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only + +coda-vpu-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg2.o coda-mpeg4.o coda-jpeg.o + +obj-$(CONFIG_VIDEO_CODA) += coda-vpu.o +obj-$(CONFIG_VIDEO_IMX_VDOA) += imx-vdoa.o diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda/trace.h b/drivers/media/platform/chips-media/coda/trace.h --- a/drivers/media/platform/chips-media/coda/trace.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/coda/trace.h 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM coda + +#if !defined(__CODA_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) +#define __CODA_TRACE_H__ + +#include +#include + +#include "coda.h" + +TRACE_EVENT(coda_bit_run, + TP_PROTO(struct coda_ctx *ctx, int cmd), + + TP_ARGS(ctx, cmd), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, ctx) + __field(int, cmd) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->ctx = ctx->idx; + __entry->cmd = cmd; + ), + + TP_printk("minor = %d, ctx = %d, cmd = %d", + __entry->minor, __entry->ctx, __entry->cmd) +); + +TRACE_EVENT(coda_bit_done, + TP_PROTO(struct coda_ctx *ctx), + + TP_ARGS(ctx), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, ctx) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->ctx = ctx->idx; + ), + + TP_printk("minor = %d, ctx = %d", __entry->minor, __entry->ctx) +); + +DECLARE_EVENT_CLASS(coda_buf_class, + TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf), + + TP_ARGS(ctx, buf), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, index) + __field(int, ctx) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->index = buf->vb2_buf.index; + __entry->ctx = ctx->idx; + ), + + TP_printk("minor = %d, index = %d, ctx = %d", + __entry->minor, __entry->index, __entry->ctx) +); + +DEFINE_EVENT(coda_buf_class, coda_enc_pic_run, + TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf), + TP_ARGS(ctx, buf) +); + +DEFINE_EVENT(coda_buf_class, coda_enc_pic_done, + TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf), + TP_ARGS(ctx, buf) +); + +DECLARE_EVENT_CLASS(coda_buf_meta_class, + TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, + struct coda_buffer_meta *meta), + + TP_ARGS(ctx, buf, meta), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, index) + __field(int, start) + __field(int, end) + __field(int, ctx) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->index = buf->vb2_buf.index; + __entry->start = meta->start & ctx->bitstream_fifo.kfifo.mask; + __entry->end = meta->end & ctx->bitstream_fifo.kfifo.mask; + __entry->ctx = ctx->idx; + ), + + TP_printk("minor = %d, index = %d, start = 0x%x, end = 0x%x, ctx = %d", + __entry->minor, __entry->index, __entry->start, __entry->end, + __entry->ctx) +); + +DEFINE_EVENT(coda_buf_meta_class, coda_bit_queue, + TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, + struct coda_buffer_meta *meta), + TP_ARGS(ctx, buf, meta) +); + +DECLARE_EVENT_CLASS(coda_meta_class, + TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), + + TP_ARGS(ctx, meta), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, start) + __field(int, end) + __field(int, ctx) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->start = meta ? (meta->start & + ctx->bitstream_fifo.kfifo.mask) : 0; + __entry->end = meta ? (meta->end & + ctx->bitstream_fifo.kfifo.mask) : 0; + __entry->ctx = ctx->idx; + ), + + TP_printk("minor = %d, start = 0x%x, end = 0x%x, ctx = %d", + __entry->minor, __entry->start, __entry->end, __entry->ctx) +); + +DEFINE_EVENT(coda_meta_class, coda_dec_pic_run, + TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), + TP_ARGS(ctx, meta) +); + +DEFINE_EVENT(coda_meta_class, coda_dec_pic_done, + TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), + TP_ARGS(ctx, meta) +); + +DEFINE_EVENT(coda_buf_meta_class, coda_dec_rot_done, + TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, + struct coda_buffer_meta *meta), + TP_ARGS(ctx, buf, meta) +); + +DEFINE_EVENT(coda_buf_class, coda_jpeg_run, + TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf), + TP_ARGS(ctx, buf) +); + +DEFINE_EVENT(coda_buf_class, coda_jpeg_done, + TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf), + TP_ARGS(ctx, buf) +); + +#endif /* __CODA_TRACE_H__ */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../drivers/media/platform/chips-media/coda +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +/* This part must be outside protection */ +#include diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda-bit.c b/drivers/media/platform/chips-media/coda-bit.c --- a/drivers/media/platform/chips-media/coda-bit.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/coda-bit.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,2666 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Coda multi-standard codec IP - BIT processor functions - * - * Copyright (C) 2012 Vista Silicon S.L. - * Javier Martin, - * Xavier Duret - * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "coda.h" -#include "imx-vdoa.h" -#define CREATE_TRACE_POINTS -#include "trace.h" - -#define CODA_PARA_BUF_SIZE (10 * 1024) -#define CODA7_PS_BUF_SIZE 0x28000 -#define CODA9_PS_SAVE_SIZE (512 * 1024) - -#define CODA_DEFAULT_GAMMA 4096 -#define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ - -static void coda_free_bitstream_buffer(struct coda_ctx *ctx); - -static inline int coda_is_initialized(struct coda_dev *dev) -{ - return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0; -} - -static inline unsigned long coda_isbusy(struct coda_dev *dev) -{ - return coda_read(dev, CODA_REG_BIT_BUSY); -} - -static int coda_wait_timeout(struct coda_dev *dev) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(1000); - - while (coda_isbusy(dev)) { - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - } - return 0; -} - -static void coda_command_async(struct coda_ctx *ctx, int cmd) -{ - struct coda_dev *dev = ctx->dev; - - if (dev->devtype->product == CODA_HX4 || - dev->devtype->product == CODA_7541 || - dev->devtype->product == CODA_960) { - /* Restore context related registers to CODA */ - coda_write(dev, ctx->bit_stream_param, - CODA_REG_BIT_BIT_STREAM_PARAM); - coda_write(dev, ctx->frm_dis_flg, - CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - coda_write(dev, ctx->frame_mem_ctrl, - CODA_REG_BIT_FRAME_MEM_CTRL); - coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR); - } - - if (dev->devtype->product == CODA_960) { - coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); - coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); - } - - coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); - - coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX); - coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); - coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); - - trace_coda_bit_run(ctx, cmd); - - coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); -} - -static int coda_command_sync(struct coda_ctx *ctx, int cmd) -{ - struct coda_dev *dev = ctx->dev; - int ret; - - lockdep_assert_held(&dev->coda_mutex); - - coda_command_async(ctx, cmd); - ret = coda_wait_timeout(dev); - trace_coda_bit_done(ctx); - - return ret; -} - -int coda_hw_reset(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - unsigned long timeout; - unsigned int idx; - int ret; - - lockdep_assert_held(&dev->coda_mutex); - - if (!dev->rstc) - return -ENOENT; - - idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); - - if (dev->devtype->product == CODA_960) { - timeout = jiffies + msecs_to_jiffies(100); - coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); - while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { - if (time_after(jiffies, timeout)) - return -ETIME; - cpu_relax(); - } - } - - ret = reset_control_reset(dev->rstc); - if (ret < 0) - return ret; - - if (dev->devtype->product == CODA_960) - coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); - coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); - coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); - ret = coda_wait_timeout(dev); - coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX); - - return ret; -} - -static void coda_kfifo_sync_from_device(struct coda_ctx *ctx) -{ - struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; - struct coda_dev *dev = ctx->dev; - u32 rd_ptr; - - rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); - kfifo->out = (kfifo->in & ~kfifo->mask) | - (rd_ptr - ctx->bitstream.paddr); - if (kfifo->out > kfifo->in) - kfifo->out -= kfifo->mask + 1; -} - -static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx) -{ - struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; - struct coda_dev *dev = ctx->dev; - u32 rd_ptr, wr_ptr; - - rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask); - coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); - wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); - coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); -} - -static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) -{ - struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; - struct coda_dev *dev = ctx->dev; - u32 wr_ptr; - - wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); - coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); -} - -static int coda_h264_bitstream_pad(struct coda_ctx *ctx, u32 size) -{ - unsigned char *buf; - u32 n; - - if (size < 6) - size = 6; - - buf = kmalloc(size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - coda_h264_filler_nal(size, buf); - n = kfifo_in(&ctx->bitstream_fifo, buf, size); - kfree(buf); - - return (n < size) ? -ENOSPC : 0; -} - -int coda_bitstream_flush(struct coda_ctx *ctx) -{ - int ret; - - if (ctx->inst_type != CODA_INST_DECODER || !ctx->use_bit) - return 0; - - ret = coda_command_sync(ctx, CODA_COMMAND_DEC_BUF_FLUSH); - if (ret < 0) { - v4l2_err(&ctx->dev->v4l2_dev, "failed to flush bitstream\n"); - return ret; - } - - kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, - ctx->bitstream.size); - coda_kfifo_sync_to_device_full(ctx); - - return 0; -} - -static int coda_bitstream_queue(struct coda_ctx *ctx, const u8 *buf, u32 size) -{ - u32 n = kfifo_in(&ctx->bitstream_fifo, buf, size); - - return (n < size) ? -ENOSPC : 0; -} - -static u32 coda_buffer_parse_headers(struct coda_ctx *ctx, - struct vb2_v4l2_buffer *src_buf, - u32 payload) -{ - u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); - u32 size = 0; - - switch (ctx->codec->src_fourcc) { - case V4L2_PIX_FMT_MPEG2: - size = coda_mpeg2_parse_headers(ctx, vaddr, payload); - break; - case V4L2_PIX_FMT_MPEG4: - size = coda_mpeg4_parse_headers(ctx, vaddr, payload); - break; - default: - break; - } - - return size; -} - -static bool coda_bitstream_try_queue(struct coda_ctx *ctx, - struct vb2_v4l2_buffer *src_buf) -{ - unsigned long payload = vb2_get_plane_payload(&src_buf->vb2_buf, 0); - u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); - int ret; - int i; - - if (coda_get_bitstream_payload(ctx) + payload + 512 >= - ctx->bitstream.size) - return false; - - if (!vaddr) { - v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); - return true; - } - - if (ctx->qsequence == 0 && payload < 512) { - /* - * Add padding after the first buffer, if it is too small to be - * fetched by the CODA, by repeating the headers. Without - * repeated headers, or the first frame already queued, decoder - * sequence initialization fails with error code 0x2000 on i.MX6 - * or error code 0x1 on i.MX51. - */ - u32 header_size = coda_buffer_parse_headers(ctx, src_buf, - payload); - - if (header_size) { - coda_dbg(1, ctx, "pad with %u-byte header\n", - header_size); - for (i = payload; i < 512; i += header_size) { - ret = coda_bitstream_queue(ctx, vaddr, - header_size); - if (ret < 0) { - v4l2_err(&ctx->dev->v4l2_dev, - "bitstream buffer overflow\n"); - return false; - } - if (ctx->dev->devtype->product == CODA_960) - break; - } - } else { - coda_dbg(1, ctx, - "could not parse header, sequence initialization might fail\n"); - } - - /* Add padding before the first buffer, if it is too small */ - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) - coda_h264_bitstream_pad(ctx, 512 - payload); - } - - ret = coda_bitstream_queue(ctx, vaddr, payload); - if (ret < 0) { - v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); - return false; - } - - src_buf->sequence = ctx->qsequence++; - - /* Sync read pointer to device */ - if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) - coda_kfifo_sync_to_device_write(ctx); - - /* Set the stream-end flag after the last buffer is queued */ - if (src_buf->flags & V4L2_BUF_FLAG_LAST) - coda_bit_stream_end_flag(ctx); - ctx->hold = false; - - return true; -} - -void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) -{ - struct vb2_v4l2_buffer *src_buf; - struct coda_buffer_meta *meta; - u32 start; - - lockdep_assert_held(&ctx->bitstream_mutex); - - if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) - return; - - while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { - /* - * Only queue two JPEGs into the bitstream buffer to keep - * latency low. We need at least one complete buffer and the - * header of another buffer (for prescan) in the bitstream. - */ - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && - ctx->num_metas > 1) - break; - - if (ctx->num_internal_frames && - ctx->num_metas >= ctx->num_internal_frames) { - meta = list_first_entry(&ctx->buffer_meta_list, - struct coda_buffer_meta, list); - - /* - * If we managed to fill in at least a full reorder - * window of buffers (num_internal_frames is a - * conservative estimate for this) and the bitstream - * prefetcher has at least 2 256 bytes periods beyond - * the first buffer to fetch, we can safely stop queuing - * in order to limit the decoder drain latency. - */ - if (coda_bitstream_can_fetch_past(ctx, meta->end)) - break; - } - - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - - /* Drop frames that do not start/end with a SOI/EOI markers */ - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && - !coda_jpeg_check_buffer(ctx, &src_buf->vb2_buf)) { - v4l2_err(&ctx->dev->v4l2_dev, - "dropping invalid JPEG frame %d\n", - ctx->qsequence); - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - if (buffer_list) { - struct v4l2_m2m_buffer *m2m_buf; - - m2m_buf = container_of(src_buf, - struct v4l2_m2m_buffer, - vb); - list_add_tail(&m2m_buf->list, buffer_list); - } else { - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); - } - continue; - } - - /* Dump empty buffers */ - if (!vb2_get_plane_payload(&src_buf->vb2_buf, 0)) { - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - continue; - } - - /* Buffer start position */ - start = ctx->bitstream_fifo.kfifo.in; - - if (coda_bitstream_try_queue(ctx, src_buf)) { - /* - * Source buffer is queued in the bitstream ringbuffer; - * queue the timestamp and mark source buffer as done - */ - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - - meta = kmalloc(sizeof(*meta), GFP_KERNEL); - if (meta) { - meta->sequence = src_buf->sequence; - meta->timecode = src_buf->timecode; - meta->timestamp = src_buf->vb2_buf.timestamp; - meta->start = start; - meta->end = ctx->bitstream_fifo.kfifo.in; - meta->last = src_buf->flags & V4L2_BUF_FLAG_LAST; - if (meta->last) - coda_dbg(1, ctx, "marking last meta"); - spin_lock(&ctx->buffer_meta_lock); - list_add_tail(&meta->list, - &ctx->buffer_meta_list); - ctx->num_metas++; - spin_unlock(&ctx->buffer_meta_lock); - - trace_coda_bit_queue(ctx, src_buf, meta); - } - - if (buffer_list) { - struct v4l2_m2m_buffer *m2m_buf; - - m2m_buf = container_of(src_buf, - struct v4l2_m2m_buffer, - vb); - list_add_tail(&m2m_buf->list, buffer_list); - } else { - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - } - } else { - break; - } - } -} - -void coda_bit_stream_end_flag(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - - /* If this context is currently running, update the hardware flag */ - if ((dev->devtype->product == CODA_960) && - coda_isbusy(dev) && - (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { - coda_write(dev, ctx->bit_stream_param, - CODA_REG_BIT_BIT_STREAM_PARAM); - } -} - -static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) -{ - struct coda_dev *dev = ctx->dev; - u32 *p = ctx->parabuf.vaddr; - - if (dev->devtype->product == CODA_DX6) - p[index] = value; - else - p[index ^ 1] = value; -} - -static inline int coda_alloc_context_buf(struct coda_ctx *ctx, - struct coda_aux_buf *buf, size_t size, - const char *name) -{ - return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); -} - - -static void coda_free_framebuffers(struct coda_ctx *ctx) -{ - int i; - - for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) - coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i].buf); -} - -static int coda_alloc_framebuffers(struct coda_ctx *ctx, - struct coda_q_data *q_data, u32 fourcc) -{ - struct coda_dev *dev = ctx->dev; - unsigned int ysize, ycbcr_size; - int ret; - int i; - - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || - ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 || - ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 || - ctx->codec->dst_fourcc == V4L2_PIX_FMT_MPEG4) - ysize = round_up(q_data->rect.width, 16) * - round_up(q_data->rect.height, 16); - else - ysize = round_up(q_data->rect.width, 8) * q_data->rect.height; - - if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) - ycbcr_size = round_up(ysize, 4096) + ysize / 2; - else - ycbcr_size = ysize + ysize / 2; - - /* Allocate frame buffers */ - for (i = 0; i < ctx->num_internal_frames; i++) { - size_t size = ycbcr_size; - char *name; - - /* Add space for mvcol buffers */ - if (dev->devtype->product != CODA_DX6 && - (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || - (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0))) - size += ysize / 4; - name = kasprintf(GFP_KERNEL, "fb%d", i); - if (!name) { - coda_free_framebuffers(ctx); - return -ENOMEM; - } - ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i].buf, - size, name); - kfree(name); - if (ret < 0) { - coda_free_framebuffers(ctx); - return ret; - } - } - - /* Register frame buffers in the parameter buffer */ - for (i = 0; i < ctx->num_internal_frames; i++) { - u32 y, cb, cr, mvcol; - - /* Start addresses of Y, Cb, Cr planes */ - y = ctx->internal_frames[i].buf.paddr; - cb = y + ysize; - cr = y + ysize + ysize/4; - mvcol = y + ysize + ysize/4 + ysize/4; - if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) { - cb = round_up(cb, 4096); - mvcol = cb + ysize/2; - cr = 0; - /* Packed 20-bit MSB of base addresses */ - /* YYYYYCCC, CCyyyyyc, cccc.... */ - y = (y & 0xfffff000) | cb >> 20; - cb = (cb & 0x000ff000) << 12; - } - coda_parabuf_write(ctx, i * 3 + 0, y); - coda_parabuf_write(ctx, i * 3 + 1, cb); - coda_parabuf_write(ctx, i * 3 + 2, cr); - - if (dev->devtype->product == CODA_DX6) - continue; - - /* mvcol buffer for h.264 and mpeg4 */ - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) - coda_parabuf_write(ctx, 96 + i, mvcol); - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0) - coda_parabuf_write(ctx, 97, mvcol); - } - - return 0; -} - -static void coda_free_context_buffers(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - - coda_free_aux_buf(dev, &ctx->slicebuf); - coda_free_aux_buf(dev, &ctx->psbuf); - if (dev->devtype->product != CODA_DX6) - coda_free_aux_buf(dev, &ctx->workbuf); - coda_free_aux_buf(dev, &ctx->parabuf); -} - -static int coda_alloc_context_buffers(struct coda_ctx *ctx, - struct coda_q_data *q_data) -{ - struct coda_dev *dev = ctx->dev; - size_t size; - int ret; - - if (!ctx->parabuf.vaddr) { - ret = coda_alloc_context_buf(ctx, &ctx->parabuf, - CODA_PARA_BUF_SIZE, "parabuf"); - if (ret < 0) - return ret; - } - - if (dev->devtype->product == CODA_DX6) - return 0; - - if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) { - /* worst case slice size */ - size = (DIV_ROUND_UP(q_data->rect.width, 16) * - DIV_ROUND_UP(q_data->rect.height, 16)) * 3200 / 8 + 512; - ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, - "slicebuf"); - if (ret < 0) - goto err; - } - - if (!ctx->psbuf.vaddr && (dev->devtype->product == CODA_HX4 || - dev->devtype->product == CODA_7541)) { - ret = coda_alloc_context_buf(ctx, &ctx->psbuf, - CODA7_PS_BUF_SIZE, "psbuf"); - if (ret < 0) - goto err; - } - - if (!ctx->workbuf.vaddr) { - size = dev->devtype->workbuf_size; - if (dev->devtype->product == CODA_960 && - q_data->fourcc == V4L2_PIX_FMT_H264) - size += CODA9_PS_SAVE_SIZE; - ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, - "workbuf"); - if (ret < 0) - goto err; - } - - return 0; - -err: - coda_free_context_buffers(ctx); - return ret; -} - -static int coda_encode_header(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, - int header_code, u8 *header, int *size) -{ - struct vb2_buffer *vb = &buf->vb2_buf; - struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data_src; - struct v4l2_rect *r; - size_t bufsize; - int ret; - int i; - - if (dev->devtype->product == CODA_960) - memset(vb2_plane_vaddr(vb, 0), 0, 64); - - coda_write(dev, vb2_dma_contig_plane_dma_addr(vb, 0), - CODA_CMD_ENC_HEADER_BB_START); - bufsize = vb2_plane_size(vb, 0); - if (dev->devtype->product == CODA_960) - bufsize /= 1024; - coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE); - if (dev->devtype->product == CODA_960 && - ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 && - header_code == CODA_HEADER_H264_SPS) { - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - r = &q_data_src->rect; - - if (r->width % 16 || r->height % 16) { - u32 crop_right = round_up(r->width, 16) - r->width; - u32 crop_bottom = round_up(r->height, 16) - r->height; - - coda_write(dev, crop_right, - CODA9_CMD_ENC_HEADER_FRAME_CROP_H); - coda_write(dev, crop_bottom, - CODA9_CMD_ENC_HEADER_FRAME_CROP_V); - header_code |= CODA9_HEADER_FRAME_CROP; - } - } - coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE); - ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); - return ret; - } - - if (dev->devtype->product == CODA_960) { - for (i = 63; i > 0; i--) - if (((char *)vb2_plane_vaddr(vb, 0))[i] != 0) - break; - *size = i + 1; - } else { - *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) - - coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); - } - memcpy(header, vb2_plane_vaddr(vb, 0), *size); - - return 0; -} - -static u32 coda_slice_mode(struct coda_ctx *ctx) -{ - int size, unit; - - switch (ctx->params.slice_mode) { - case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: - default: - return 0; - case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB: - size = ctx->params.slice_max_mb; - unit = 1; - break; - case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES: - size = ctx->params.slice_max_bits; - unit = 0; - break; - } - - return ((size & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET) | - ((unit & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET) | - ((1 & CODA_SLICING_MODE_MASK) << CODA_SLICING_MODE_OFFSET); -} - -static int coda_enc_param_change(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - u32 change_enable = 0; - u32 success; - int ret; - - if (ctx->params.gop_size_changed) { - change_enable |= CODA_PARAM_CHANGE_RC_GOP; - coda_write(dev, ctx->params.gop_size, - CODA_CMD_ENC_PARAM_RC_GOP); - ctx->gopcounter = ctx->params.gop_size - 1; - ctx->params.gop_size_changed = false; - } - if (ctx->params.h264_intra_qp_changed) { - coda_dbg(1, ctx, "parameter change: intra Qp %u\n", - ctx->params.h264_intra_qp); - - if (ctx->params.bitrate) { - change_enable |= CODA_PARAM_CHANGE_RC_INTRA_QP; - coda_write(dev, ctx->params.h264_intra_qp, - CODA_CMD_ENC_PARAM_RC_INTRA_QP); - } - ctx->params.h264_intra_qp_changed = false; - } - if (ctx->params.bitrate_changed) { - coda_dbg(1, ctx, "parameter change: bitrate %u kbit/s\n", - ctx->params.bitrate); - change_enable |= CODA_PARAM_CHANGE_RC_BITRATE; - coda_write(dev, ctx->params.bitrate, - CODA_CMD_ENC_PARAM_RC_BITRATE); - ctx->params.bitrate_changed = false; - } - if (ctx->params.framerate_changed) { - coda_dbg(1, ctx, "parameter change: frame rate %u/%u Hz\n", - ctx->params.framerate & 0xffff, - (ctx->params.framerate >> 16) + 1); - change_enable |= CODA_PARAM_CHANGE_RC_FRAME_RATE; - coda_write(dev, ctx->params.framerate, - CODA_CMD_ENC_PARAM_RC_FRAME_RATE); - ctx->params.framerate_changed = false; - } - if (ctx->params.intra_refresh_changed) { - coda_dbg(1, ctx, "parameter change: intra refresh MBs %u\n", - ctx->params.intra_refresh); - change_enable |= CODA_PARAM_CHANGE_INTRA_MB_NUM; - coda_write(dev, ctx->params.intra_refresh, - CODA_CMD_ENC_PARAM_INTRA_MB_NUM); - ctx->params.intra_refresh_changed = false; - } - if (ctx->params.slice_mode_changed) { - change_enable |= CODA_PARAM_CHANGE_SLICE_MODE; - coda_write(dev, coda_slice_mode(ctx), - CODA_CMD_ENC_PARAM_SLICE_MODE); - ctx->params.slice_mode_changed = false; - } - - if (!change_enable) - return 0; - - coda_write(dev, change_enable, CODA_CMD_ENC_PARAM_CHANGE_ENABLE); - - ret = coda_command_sync(ctx, CODA_COMMAND_RC_CHANGE_PARAMETER); - if (ret < 0) - return ret; - - success = coda_read(dev, CODA_RET_ENC_PARAM_CHANGE_SUCCESS); - if (success != 1) - coda_dbg(1, ctx, "parameter change failed: %u\n", success); - - return 0; -} - -static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) -{ - phys_addr_t ret; - - size = round_up(size, 1024); - if (size > iram->remaining) - return 0; - iram->remaining -= size; - - ret = iram->next_paddr; - iram->next_paddr += size; - - return ret; -} - -static void coda_setup_iram(struct coda_ctx *ctx) -{ - struct coda_iram_info *iram_info = &ctx->iram_info; - struct coda_dev *dev = ctx->dev; - int w64, w128; - int mb_width; - int dbk_bits; - int bit_bits; - int ip_bits; - int me_bits; - - memset(iram_info, 0, sizeof(*iram_info)); - iram_info->next_paddr = dev->iram.paddr; - iram_info->remaining = dev->iram.size; - - if (!dev->iram.vaddr) - return; - - switch (dev->devtype->product) { - case CODA_HX4: - dbk_bits = CODA7_USE_HOST_DBK_ENABLE; - bit_bits = CODA7_USE_HOST_BIT_ENABLE; - ip_bits = CODA7_USE_HOST_IP_ENABLE; - me_bits = CODA7_USE_HOST_ME_ENABLE; - break; - case CODA_7541: - dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; - bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; - ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; - me_bits = CODA7_USE_HOST_ME_ENABLE | CODA7_USE_ME_ENABLE; - break; - case CODA_960: - dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; - bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; - ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; - me_bits = 0; - break; - default: /* CODA_DX6 */ - return; - } - - if (ctx->inst_type == CODA_INST_ENCODER) { - struct coda_q_data *q_data_src; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - mb_width = DIV_ROUND_UP(q_data_src->rect.width, 16); - w128 = mb_width * 128; - w64 = mb_width * 64; - - /* Prioritize in case IRAM is too small for everything */ - if (dev->devtype->product == CODA_HX4 || - dev->devtype->product == CODA_7541) { - iram_info->search_ram_size = round_up(mb_width * 16 * - 36 + 2048, 1024); - iram_info->search_ram_paddr = coda_iram_alloc(iram_info, - iram_info->search_ram_size); - if (!iram_info->search_ram_paddr) { - pr_err("IRAM is smaller than the search ram size\n"); - goto out; - } - iram_info->axi_sram_use |= me_bits; - } - - /* Only H.264BP and H.263P3 are considered */ - iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64); - iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64); - if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use) - goto out; - iram_info->axi_sram_use |= dbk_bits; - - iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); - if (!iram_info->buf_bit_use) - goto out; - iram_info->axi_sram_use |= bit_bits; - - iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); - if (!iram_info->buf_ip_ac_dc_use) - goto out; - iram_info->axi_sram_use |= ip_bits; - - /* OVL and BTP disabled for encoder */ - } else if (ctx->inst_type == CODA_INST_DECODER) { - struct coda_q_data *q_data_dst; - - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - mb_width = DIV_ROUND_UP(q_data_dst->width, 16); - w128 = mb_width * 128; - - iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128); - iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128); - if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use) - goto out; - iram_info->axi_sram_use |= dbk_bits; - - iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); - if (!iram_info->buf_bit_use) - goto out; - iram_info->axi_sram_use |= bit_bits; - - iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); - if (!iram_info->buf_ip_ac_dc_use) - goto out; - iram_info->axi_sram_use |= ip_bits; - - /* OVL and BTP unused as there is no VC1 support yet */ - } - -out: - if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)) - coda_dbg(1, ctx, "IRAM smaller than needed\n"); - - if (dev->devtype->product == CODA_HX4 || - dev->devtype->product == CODA_7541) { - /* TODO - Enabling these causes picture errors on CODA7541 */ - if (ctx->inst_type == CODA_INST_DECODER) { - /* fw 1.4.50 */ - iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | - CODA7_USE_IP_ENABLE); - } else { - /* fw 13.4.29 */ - iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | - CODA7_USE_HOST_DBK_ENABLE | - CODA7_USE_IP_ENABLE | - CODA7_USE_DBK_ENABLE); - } - } -} - -static u32 coda_supported_firmwares[] = { - CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), - CODA_FIRMWARE_VERNUM(CODA_HX4, 1, 4, 50), - CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), - CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), - CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 9), - CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10), - CODA_FIRMWARE_VERNUM(CODA_960, 3, 1, 1), -}; - -static bool coda_firmware_supported(u32 vernum) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++) - if (vernum == coda_supported_firmwares[i]) - return true; - return false; -} - -int coda_check_firmware(struct coda_dev *dev) -{ - u16 product, major, minor, release; - u32 data; - int ret; - - ret = clk_prepare_enable(dev->clk_per); - if (ret) - goto err_clk_per; - - ret = clk_prepare_enable(dev->clk_ahb); - if (ret) - goto err_clk_ahb; - - coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM); - coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); - coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX); - coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD); - coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND); - if (coda_wait_timeout(dev)) { - v4l2_err(&dev->v4l2_dev, "firmware get command error\n"); - ret = -EIO; - goto err_run_cmd; - } - - if (dev->devtype->product == CODA_960) { - data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV); - v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n", - data); - } - - /* Check we are compatible with the loaded firmware */ - data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM); - product = CODA_FIRMWARE_PRODUCT(data); - major = CODA_FIRMWARE_MAJOR(data); - minor = CODA_FIRMWARE_MINOR(data); - release = CODA_FIRMWARE_RELEASE(data); - - clk_disable_unprepare(dev->clk_per); - clk_disable_unprepare(dev->clk_ahb); - - if (product != dev->devtype->product) { - v4l2_err(&dev->v4l2_dev, - "Wrong firmware. Hw: %s, Fw: %s, Version: %u.%u.%u\n", - coda_product_name(dev->devtype->product), - coda_product_name(product), major, minor, release); - return -EINVAL; - } - - v4l2_info(&dev->v4l2_dev, "Initialized %s.\n", - coda_product_name(product)); - - if (coda_firmware_supported(data)) { - v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", - major, minor, release); - } else { - v4l2_warn(&dev->v4l2_dev, - "Unsupported firmware version: %u.%u.%u\n", - major, minor, release); - } - - return 0; - -err_run_cmd: - clk_disable_unprepare(dev->clk_ahb); -err_clk_ahb: - clk_disable_unprepare(dev->clk_per); -err_clk_per: - return ret; -} - -static void coda9_set_frame_cache(struct coda_ctx *ctx, u32 fourcc) -{ - u32 cache_size, cache_config; - - if (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) { - /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ - cache_size = 0x20262024; - cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET; - } else { - /* Luma 0x2 page, 4x4 cache, chroma 0x2 page, 4x3 cache size */ - cache_size = 0x02440243; - cache_config = 1 << CODA9_CACHE_PAGEMERGE_OFFSET; - } - coda_write(ctx->dev, cache_size, CODA9_CMD_SET_FRAME_CACHE_SIZE); - if (fourcc == V4L2_PIX_FMT_NV12 || fourcc == V4L2_PIX_FMT_YUYV) { - cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | - 16 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | - 0 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; - } else { - cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | - 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | - 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; - } - coda_write(ctx->dev, cache_config, CODA9_CMD_SET_FRAME_CACHE_CONFIG); -} - -/* - * Encoder context operations - */ - -static int coda_encoder_reqbufs(struct coda_ctx *ctx, - struct v4l2_requestbuffers *rb) -{ - struct coda_q_data *q_data_src; - int ret; - - if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return 0; - - if (rb->count) { - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - ret = coda_alloc_context_buffers(ctx, q_data_src); - if (ret < 0) - return ret; - } else { - coda_free_context_buffers(ctx); - } - - return 0; -} - -static int coda_start_encoding(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - struct v4l2_device *v4l2_dev = &dev->v4l2_dev; - struct coda_q_data *q_data_src, *q_data_dst; - u32 bitstream_buf, bitstream_size; - struct vb2_v4l2_buffer *buf; - int gamma, ret, value; - u32 dst_fourcc; - int num_fb; - u32 stride; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_fourcc = q_data_dst->fourcc; - - buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - bitstream_buf = vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, 0); - bitstream_size = q_data_dst->sizeimage; - - if (!coda_is_initialized(dev)) { - v4l2_err(v4l2_dev, "coda is not initialized.\n"); - return -EFAULT; - } - - if (dst_fourcc == V4L2_PIX_FMT_JPEG) { - if (!ctx->params.jpeg_qmat_tab[0]) { - ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL); - if (!ctx->params.jpeg_qmat_tab[0]) - return -ENOMEM; - } - if (!ctx->params.jpeg_qmat_tab[1]) { - ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL); - if (!ctx->params.jpeg_qmat_tab[1]) - return -ENOMEM; - } - coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality); - } - - mutex_lock(&dev->coda_mutex); - - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); - coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); - coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); - switch (dev->devtype->product) { - case CODA_DX6: - coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN | - CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); - break; - case CODA_960: - coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); - fallthrough; - case CODA_HX4: - case CODA_7541: - coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | - CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); - break; - } - - ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | - CODA9_FRAME_TILED2LINEAR); - if (q_data_src->fourcc == V4L2_PIX_FMT_NV12) - ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; - if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) - ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR; - coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); - - if (dev->devtype->product == CODA_DX6) { - /* Configure the coda */ - coda_write(dev, dev->iram.paddr, - CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); - } - - /* Could set rotation here if needed */ - value = 0; - switch (dev->devtype->product) { - case CODA_DX6: - value = (q_data_src->rect.width & CODADX6_PICWIDTH_MASK) - << CODADX6_PICWIDTH_OFFSET; - value |= (q_data_src->rect.height & CODADX6_PICHEIGHT_MASK) - << CODA_PICHEIGHT_OFFSET; - break; - case CODA_HX4: - case CODA_7541: - if (dst_fourcc == V4L2_PIX_FMT_H264) { - value = (round_up(q_data_src->rect.width, 16) & - CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; - value |= (round_up(q_data_src->rect.height, 16) & - CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; - break; - } - fallthrough; - case CODA_960: - value = (q_data_src->rect.width & CODA7_PICWIDTH_MASK) - << CODA7_PICWIDTH_OFFSET; - value |= (q_data_src->rect.height & CODA7_PICHEIGHT_MASK) - << CODA_PICHEIGHT_OFFSET; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); - if (dst_fourcc == V4L2_PIX_FMT_JPEG) - ctx->params.framerate = 0; - coda_write(dev, ctx->params.framerate, - CODA_CMD_ENC_SEQ_SRC_F_RATE); - - ctx->params.codec_mode = ctx->codec->mode; - switch (dst_fourcc) { - case V4L2_PIX_FMT_MPEG4: - if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_STD_MPEG4, - CODA_CMD_ENC_SEQ_COD_STD); - else - coda_write(dev, CODA_STD_MPEG4, - CODA_CMD_ENC_SEQ_COD_STD); - coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); - break; - case V4L2_PIX_FMT_H264: - if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_STD_H264, - CODA_CMD_ENC_SEQ_COD_STD); - else - coda_write(dev, CODA_STD_H264, - CODA_CMD_ENC_SEQ_COD_STD); - value = ((ctx->params.h264_disable_deblocking_filter_idc & - CODA_264PARAM_DISABLEDEBLK_MASK) << - CODA_264PARAM_DISABLEDEBLK_OFFSET) | - ((ctx->params.h264_slice_alpha_c0_offset_div2 & - CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << - CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | - ((ctx->params.h264_slice_beta_offset_div2 & - CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << - CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET) | - (ctx->params.h264_constrained_intra_pred_flag << - CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET) | - (ctx->params.h264_chroma_qp_index_offset & - CODA_264PARAM_CHROMAQPOFFSET_MASK); - coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); - break; - case V4L2_PIX_FMT_JPEG: - coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_PARA); - coda_write(dev, ctx->params.jpeg_restart_interval, - CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL); - coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_EN); - coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE); - coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET); - - coda_jpeg_write_tables(ctx); - break; - default: - v4l2_err(v4l2_dev, - "dst format (0x%08x) invalid.\n", dst_fourcc); - ret = -EINVAL; - goto out; - } - - /* - * slice mode and GOP size registers are used for thumb size/offset - * in JPEG mode - */ - if (dst_fourcc != V4L2_PIX_FMT_JPEG) { - value = coda_slice_mode(ctx); - coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); - value = ctx->params.gop_size; - coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); - } - - if (ctx->params.bitrate && (ctx->params.frame_rc_enable || - ctx->params.mb_rc_enable)) { - ctx->params.bitrate_changed = false; - ctx->params.h264_intra_qp_changed = false; - - /* Rate control enabled */ - value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) - << CODA_RATECONTROL_BITRATE_OFFSET; - value |= 1 & CODA_RATECONTROL_ENABLE_MASK; - value |= (ctx->params.vbv_delay & - CODA_RATECONTROL_INITIALDELAY_MASK) - << CODA_RATECONTROL_INITIALDELAY_OFFSET; - if (dev->devtype->product == CODA_960) - value |= BIT(31); /* disable autoskip */ - } else { - value = 0; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA); - - coda_write(dev, ctx->params.vbv_size, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); - coda_write(dev, ctx->params.intra_refresh, - CODA_CMD_ENC_SEQ_INTRA_REFRESH); - - coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START); - coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE); - - - value = 0; - if (dev->devtype->product == CODA_960) - gamma = CODA9_DEFAULT_GAMMA; - else - gamma = CODA_DEFAULT_GAMMA; - if (gamma > 0) { - coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET, - CODA_CMD_ENC_SEQ_RC_GAMMA); - } - - if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) { - coda_write(dev, - ctx->params.h264_min_qp << CODA_QPMIN_OFFSET | - ctx->params.h264_max_qp << CODA_QPMAX_OFFSET, - CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX); - } - if (dev->devtype->product == CODA_960) { - if (ctx->params.h264_max_qp) - value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET; - if (CODA_DEFAULT_GAMMA > 0) - value |= 1 << CODA9_OPTION_GAMMA_OFFSET; - } else { - if (CODA_DEFAULT_GAMMA > 0) { - if (dev->devtype->product == CODA_DX6) - value |= 1 << CODADX6_OPTION_GAMMA_OFFSET; - else - value |= 1 << CODA7_OPTION_GAMMA_OFFSET; - } - if (ctx->params.h264_min_qp) - value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET; - if (ctx->params.h264_max_qp) - value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION); - - if (ctx->params.frame_rc_enable && !ctx->params.mb_rc_enable) - value = 1; - else - value = 0; - coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE); - - coda_setup_iram(ctx); - - if (dst_fourcc == V4L2_PIX_FMT_H264) { - switch (dev->devtype->product) { - case CODA_DX6: - value = FMO_SLICE_SAVE_BUF_SIZE << 7; - coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); - break; - case CODA_HX4: - case CODA_7541: - coda_write(dev, ctx->iram_info.search_ram_paddr, - CODA7_CMD_ENC_SEQ_SEARCH_BASE); - coda_write(dev, ctx->iram_info.search_ram_size, - CODA7_CMD_ENC_SEQ_SEARCH_SIZE); - break; - case CODA_960: - coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION); - coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT); - } - } - - ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); - if (ret < 0) { - v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); - goto out; - } - - if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) { - v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n"); - ret = -EFAULT; - goto out; - } - ctx->initialized = 1; - - if (dst_fourcc != V4L2_PIX_FMT_JPEG) { - if (dev->devtype->product == CODA_960) - ctx->num_internal_frames = 4; - else - ctx->num_internal_frames = 2; - ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); - if (ret < 0) { - v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); - goto out; - } - num_fb = 2; - stride = q_data_src->bytesperline; - } else { - ctx->num_internal_frames = 0; - num_fb = 0; - stride = 0; - } - coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM); - coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE); - - if (dev->devtype->product == CODA_HX4 || - dev->devtype->product == CODA_7541) { - coda_write(dev, q_data_src->bytesperline, - CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); - } - if (dev->devtype->product != CODA_DX6) { - coda_write(dev, ctx->iram_info.buf_bit_use, - CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); - coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, - CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_y_use, - CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_c_use, - CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); - coda_write(dev, ctx->iram_info.buf_ovl_use, - CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); - if (dev->devtype->product == CODA_960) { - coda_write(dev, ctx->iram_info.buf_btp_use, - CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); - - coda9_set_frame_cache(ctx, q_data_src->fourcc); - - /* FIXME */ - coda_write(dev, ctx->internal_frames[2].buf.paddr, - CODA9_CMD_SET_FRAME_SUBSAMP_A); - coda_write(dev, ctx->internal_frames[3].buf.paddr, - CODA9_CMD_SET_FRAME_SUBSAMP_B); - } - } - - ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF); - if (ret < 0) { - v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n"); - goto out; - } - - coda_dbg(1, ctx, "start encoding %dx%d %4.4s->%4.4s @ %d/%d Hz\n", - q_data_src->rect.width, q_data_src->rect.height, - (char *)&ctx->codec->src_fourcc, (char *)&dst_fourcc, - ctx->params.framerate & 0xffff, - (ctx->params.framerate >> 16) + 1); - - /* Save stream headers */ - buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - switch (dst_fourcc) { - case V4L2_PIX_FMT_H264: - /* - * Get SPS in the first frame and copy it to an - * intermediate buffer. - */ - ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS, - &ctx->vpu_header[0][0], - &ctx->vpu_header_size[0]); - if (ret < 0) - goto out; - - /* - * If visible width or height are not aligned to macroblock - * size, the crop_right and crop_bottom SPS fields must be set - * to the difference between visible and coded size. This is - * only supported by CODA960 firmware. All others do not allow - * writing frame cropping parameters, so we have to manually - * fix up the SPS RBSP (Sequence Parameter Set Raw Byte - * Sequence Payload) ourselves. - */ - if (ctx->dev->devtype->product != CODA_960 && - ((q_data_src->rect.width % 16) || - (q_data_src->rect.height % 16))) { - ret = coda_h264_sps_fixup(ctx, q_data_src->rect.width, - q_data_src->rect.height, - &ctx->vpu_header[0][0], - &ctx->vpu_header_size[0], - sizeof(ctx->vpu_header[0])); - if (ret < 0) - goto out; - } - - /* - * Get PPS in the first frame and copy it to an - * intermediate buffer. - */ - ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS, - &ctx->vpu_header[1][0], - &ctx->vpu_header_size[1]); - if (ret < 0) - goto out; - - /* - * Length of H.264 headers is variable and thus it might not be - * aligned for the coda to append the encoded frame. In that is - * the case a filler NAL must be added to header 2. - */ - ctx->vpu_header_size[2] = coda_h264_padding( - (ctx->vpu_header_size[0] + - ctx->vpu_header_size[1]), - ctx->vpu_header[2]); - break; - case V4L2_PIX_FMT_MPEG4: - /* - * Get VOS in the first frame and copy it to an - * intermediate buffer - */ - ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS, - &ctx->vpu_header[0][0], - &ctx->vpu_header_size[0]); - if (ret < 0) - goto out; - - ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS, - &ctx->vpu_header[1][0], - &ctx->vpu_header_size[1]); - if (ret < 0) - goto out; - - ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL, - &ctx->vpu_header[2][0], - &ctx->vpu_header_size[2]); - if (ret < 0) - goto out; - break; - default: - /* No more formats need to save headers at the moment */ - break; - } - -out: - mutex_unlock(&dev->coda_mutex); - return ret; -} - -static int coda_prepare_encode(struct coda_ctx *ctx) -{ - struct coda_q_data *q_data_src, *q_data_dst; - struct vb2_v4l2_buffer *src_buf, *dst_buf; - struct coda_dev *dev = ctx->dev; - int force_ipicture; - int quant_param = 0; - u32 pic_stream_buffer_addr, pic_stream_buffer_size; - u32 rot_mode = 0; - u32 dst_fourcc; - u32 reg; - int ret; - - ret = coda_enc_param_change(ctx); - if (ret < 0) { - v4l2_warn(&ctx->dev->v4l2_dev, "parameter change failed: %d\n", - ret); - } - - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_fourcc = q_data_dst->fourcc; - - src_buf->sequence = ctx->osequence; - dst_buf->sequence = ctx->osequence; - ctx->osequence++; - - force_ipicture = ctx->params.force_ipicture; - if (force_ipicture) - ctx->params.force_ipicture = false; - else if (ctx->params.gop_size != 0 && - (src_buf->sequence % ctx->params.gop_size) == 0) - force_ipicture = 1; - - /* - * Workaround coda firmware BUG that only marks the first - * frame as IDR. This is a problem for some decoders that can't - * recover when a frame is lost. - */ - if (!force_ipicture) { - src_buf->flags |= V4L2_BUF_FLAG_PFRAME; - src_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME; - } else { - src_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; - src_buf->flags &= ~V4L2_BUF_FLAG_PFRAME; - } - - if (dev->devtype->product == CODA_960) - coda_set_gdi_regs(ctx); - - /* - * Copy headers in front of the first frame and forced I frames for - * H.264 only. In MPEG4 they are already copied by the CODA. - */ - if (src_buf->sequence == 0 || force_ipicture) { - pic_stream_buffer_addr = - vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0) + - ctx->vpu_header_size[0] + - ctx->vpu_header_size[1] + - ctx->vpu_header_size[2]; - pic_stream_buffer_size = q_data_dst->sizeimage - - ctx->vpu_header_size[0] - - ctx->vpu_header_size[1] - - ctx->vpu_header_size[2]; - memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0), - &ctx->vpu_header[0][0], ctx->vpu_header_size[0]); - memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) - + ctx->vpu_header_size[0], &ctx->vpu_header[1][0], - ctx->vpu_header_size[1]); - memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) - + ctx->vpu_header_size[0] + ctx->vpu_header_size[1], - &ctx->vpu_header[2][0], ctx->vpu_header_size[2]); - } else { - pic_stream_buffer_addr = - vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); - pic_stream_buffer_size = q_data_dst->sizeimage; - } - - if (force_ipicture) { - switch (dst_fourcc) { - case V4L2_PIX_FMT_H264: - quant_param = ctx->params.h264_intra_qp; - break; - case V4L2_PIX_FMT_MPEG4: - quant_param = ctx->params.mpeg4_intra_qp; - break; - case V4L2_PIX_FMT_JPEG: - quant_param = 30; - break; - default: - v4l2_warn(&ctx->dev->v4l2_dev, - "cannot set intra qp, fmt not supported\n"); - break; - } - } else { - switch (dst_fourcc) { - case V4L2_PIX_FMT_H264: - quant_param = ctx->params.h264_inter_qp; - break; - case V4L2_PIX_FMT_MPEG4: - quant_param = ctx->params.mpeg4_inter_qp; - break; - default: - v4l2_warn(&ctx->dev->v4l2_dev, - "cannot set inter qp, fmt not supported\n"); - break; - } - } - - /* submit */ - if (ctx->params.rot_mode) - rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode; - coda_write(dev, rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); - coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); - - if (dev->devtype->product == CODA_960) { - coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); - coda_write(dev, q_data_src->bytesperline, - CODA9_CMD_ENC_PIC_SRC_STRIDE); - coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC); - - reg = CODA9_CMD_ENC_PIC_SRC_ADDR_Y; - } else { - reg = CODA_CMD_ENC_PIC_SRC_ADDR_Y; - } - coda_write_base(ctx, q_data_src, src_buf, reg); - - coda_write(dev, force_ipicture << 1 & 0x2, - CODA_CMD_ENC_PIC_OPTION); - - coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START); - coda_write(dev, pic_stream_buffer_size / 1024, - CODA_CMD_ENC_PIC_BB_SIZE); - - if (!ctx->streamon_out) { - /* After streamoff on the output side, set stream end flag */ - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - coda_write(dev, ctx->bit_stream_param, - CODA_REG_BIT_BIT_STREAM_PARAM); - } - - if (dev->devtype->product != CODA_DX6) - coda_write(dev, ctx->iram_info.axi_sram_use, - CODA7_REG_BIT_AXI_SRAM_USE); - - trace_coda_enc_pic_run(ctx, src_buf); - - coda_command_async(ctx, CODA_COMMAND_PIC_RUN); - - return 0; -} - -static char coda_frame_type_char(u32 flags) -{ - return (flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : - (flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : - (flags & V4L2_BUF_FLAG_BFRAME) ? 'B' : '?'; -} - -static void coda_finish_encode(struct coda_ctx *ctx) -{ - struct vb2_v4l2_buffer *src_buf, *dst_buf; - struct coda_dev *dev = ctx->dev; - u32 wr_ptr, start_ptr; - - if (ctx->aborting) - return; - - /* - * Lock to make sure that an encoder stop command running in parallel - * will either already have marked src_buf as last, or it will wake up - * the capture queue after the buffers are returned. - */ - mutex_lock(&ctx->wakeup_mutex); - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - - trace_coda_enc_pic_done(ctx, dst_buf); - - /* Get results from the coda */ - start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); - wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); - - /* Calculate bytesused field */ - if (dst_buf->sequence == 0 || - src_buf->flags & V4L2_BUF_FLAG_KEYFRAME) { - vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr + - ctx->vpu_header_size[0] + - ctx->vpu_header_size[1] + - ctx->vpu_header_size[2]); - } else { - vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr); - } - - coda_dbg(1, ctx, "frame size = %u\n", wr_ptr - start_ptr); - - coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); - coda_read(dev, CODA_RET_ENC_PIC_FLAG); - - dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | - V4L2_BUF_FLAG_PFRAME | - V4L2_BUF_FLAG_LAST); - if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) - dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; - else - dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; - dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; - - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); - - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); - mutex_unlock(&ctx->wakeup_mutex); - - ctx->gopcounter--; - if (ctx->gopcounter < 0) - ctx->gopcounter = ctx->params.gop_size - 1; - - coda_dbg(1, ctx, "job finished: encoded %c frame (%d)%s\n", - coda_frame_type_char(dst_buf->flags), dst_buf->sequence, - (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); -} - -static void coda_seq_end_work(struct work_struct *work) -{ - struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work); - struct coda_dev *dev = ctx->dev; - - mutex_lock(&ctx->buffer_mutex); - mutex_lock(&dev->coda_mutex); - - if (ctx->initialized == 0) - goto out; - - coda_dbg(1, ctx, "%s: sent command 'SEQ_END' to coda\n", __func__); - if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { - v4l2_err(&dev->v4l2_dev, - "CODA_COMMAND_SEQ_END failed\n"); - } - - /* - * FIXME: Sometimes h.264 encoding fails with 8-byte sequences missing - * from the output stream after the h.264 decoder has run. Resetting the - * hardware after the decoder has finished seems to help. - */ - if (dev->devtype->product == CODA_960) - coda_hw_reset(ctx); - - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); - - coda_free_framebuffers(ctx); - - ctx->initialized = 0; - -out: - mutex_unlock(&dev->coda_mutex); - mutex_unlock(&ctx->buffer_mutex); -} - -static void coda_bit_release(struct coda_ctx *ctx) -{ - mutex_lock(&ctx->buffer_mutex); - coda_free_framebuffers(ctx); - coda_free_context_buffers(ctx); - coda_free_bitstream_buffer(ctx); - mutex_unlock(&ctx->buffer_mutex); -} - -const struct coda_context_ops coda_bit_encode_ops = { - .queue_init = coda_encoder_queue_init, - .reqbufs = coda_encoder_reqbufs, - .start_streaming = coda_start_encoding, - .prepare_run = coda_prepare_encode, - .finish_run = coda_finish_encode, - .seq_end_work = coda_seq_end_work, - .release = coda_bit_release, -}; - -/* - * Decoder context operations - */ - -static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx, - struct coda_q_data *q_data) -{ - if (ctx->bitstream.vaddr) - return 0; - - ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2); - ctx->bitstream.vaddr = dma_alloc_wc(ctx->dev->dev, ctx->bitstream.size, - &ctx->bitstream.paddr, GFP_KERNEL); - if (!ctx->bitstream.vaddr) { - v4l2_err(&ctx->dev->v4l2_dev, - "failed to allocate bitstream ringbuffer"); - return -ENOMEM; - } - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); - - return 0; -} - -static void coda_free_bitstream_buffer(struct coda_ctx *ctx) -{ - if (ctx->bitstream.vaddr == NULL) - return; - - dma_free_wc(ctx->dev->dev, ctx->bitstream.size, ctx->bitstream.vaddr, - ctx->bitstream.paddr); - ctx->bitstream.vaddr = NULL; - kfifo_init(&ctx->bitstream_fifo, NULL, 0); -} - -static int coda_decoder_reqbufs(struct coda_ctx *ctx, - struct v4l2_requestbuffers *rb) -{ - struct coda_q_data *q_data_src; - int ret; - - if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return 0; - - if (rb->count) { - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - ret = coda_alloc_context_buffers(ctx, q_data_src); - if (ret < 0) - return ret; - ret = coda_alloc_bitstream_buffer(ctx, q_data_src); - if (ret < 0) { - coda_free_context_buffers(ctx); - return ret; - } - } else { - coda_free_bitstream_buffer(ctx); - coda_free_context_buffers(ctx); - } - - return 0; -} - -static bool coda_reorder_enable(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - int profile; - - if (dev->devtype->product != CODA_HX4 && - dev->devtype->product != CODA_7541 && - dev->devtype->product != CODA_960) - return false; - - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) - return false; - - if (ctx->codec->src_fourcc != V4L2_PIX_FMT_H264) - return true; - - profile = coda_h264_profile(ctx->params.h264_profile_idc); - if (profile < 0) - v4l2_warn(&dev->v4l2_dev, "Unknown H264 Profile: %u\n", - ctx->params.h264_profile_idc); - - /* Baseline profile does not support reordering */ - return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; -} - -static void coda_decoder_drop_used_metas(struct coda_ctx *ctx) -{ - struct coda_buffer_meta *meta, *tmp; - - /* - * All metas that end at or before the RD pointer (fifo out), - * are now consumed by the VPU and should be released. - */ - spin_lock(&ctx->buffer_meta_lock); - list_for_each_entry_safe(meta, tmp, &ctx->buffer_meta_list, list) { - if (ctx->bitstream_fifo.kfifo.out >= meta->end) { - coda_dbg(2, ctx, "releasing meta: seq=%d start=%d end=%d\n", - meta->sequence, meta->start, meta->end); - - list_del(&meta->list); - ctx->num_metas--; - ctx->first_frame_sequence++; - kfree(meta); - } - } - spin_unlock(&ctx->buffer_meta_lock); -} - -static int __coda_decoder_seq_init(struct coda_ctx *ctx) -{ - struct coda_q_data *q_data_src, *q_data_dst; - u32 bitstream_buf, bitstream_size; - struct coda_dev *dev = ctx->dev; - int width, height; - u32 src_fourcc, dst_fourcc; - u32 val; - int ret; - - lockdep_assert_held(&dev->coda_mutex); - - coda_dbg(1, ctx, "Video Data Order Adapter: %s\n", - ctx->use_vdoa ? "Enabled" : "Disabled"); - - /* Start decoding */ - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - bitstream_buf = ctx->bitstream.paddr; - bitstream_size = ctx->bitstream.size; - src_fourcc = q_data_src->fourcc; - dst_fourcc = q_data_dst->fourcc; - - /* Update coda bitstream read and write pointers from kfifo */ - coda_kfifo_sync_to_device_full(ctx); - - ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | - CODA9_FRAME_TILED2LINEAR); - if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV) - ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; - if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) - ctx->frame_mem_ctrl |= (0x3 << 9) | - ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); - coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); - - ctx->display_idx = -1; - ctx->frm_dis_flg = 0; - coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - - coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); - coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); - val = 0; - if (coda_reorder_enable(ctx)) - val |= CODA_REORDER_ENABLE; - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) - val |= CODA_NO_INT_ENABLE; - coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION); - - ctx->params.codec_mode = ctx->codec->mode; - if (dev->devtype->product == CODA_960 && - src_fourcc == V4L2_PIX_FMT_MPEG4) - ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4; - else - ctx->params.codec_mode_aux = 0; - if (src_fourcc == V4L2_PIX_FMT_MPEG4) { - coda_write(dev, CODA_MP4_CLASS_MPEG4, - CODA_CMD_DEC_SEQ_MP4_ASP_CLASS); - } - if (src_fourcc == V4L2_PIX_FMT_H264) { - if (dev->devtype->product == CODA_HX4 || - dev->devtype->product == CODA_7541) { - coda_write(dev, ctx->psbuf.paddr, - CODA_CMD_DEC_SEQ_PS_BB_START); - coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), - CODA_CMD_DEC_SEQ_PS_BB_SIZE); - } - if (dev->devtype->product == CODA_960) { - coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN); - coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE); - } - } - if (src_fourcc == V4L2_PIX_FMT_JPEG) - coda_write(dev, 0, CODA_CMD_DEC_SEQ_JPG_THUMB_EN); - if (dev->devtype->product != CODA_960) - coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE); - - ctx->bit_stream_param = CODA_BIT_DEC_SEQ_INIT_ESCAPE; - ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); - ctx->bit_stream_param = 0; - if (ret) { - v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); - return ret; - } - ctx->sequence_offset = ~0U; - ctx->initialized = 1; - ctx->first_frame_sequence = 0; - - /* Update kfifo out pointer from coda bitstream read pointer */ - coda_kfifo_sync_from_device(ctx); - - /* - * After updating the read pointer, we need to check if - * any metas are consumed and should be released. - */ - coda_decoder_drop_used_metas(ctx); - - if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { - v4l2_err(&dev->v4l2_dev, - "CODA_COMMAND_SEQ_INIT failed, error code = 0x%x\n", - coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON)); - return -EAGAIN; - } - - val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE); - if (dev->devtype->product == CODA_DX6) { - width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK; - height = val & CODADX6_PICHEIGHT_MASK; - } else { - width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK; - height = val & CODA7_PICHEIGHT_MASK; - } - - if (width > q_data_dst->bytesperline || height > q_data_dst->height) { - v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", - width, height, q_data_dst->bytesperline, - q_data_dst->height); - return -EINVAL; - } - - width = round_up(width, 16); - height = round_up(height, 16); - - coda_dbg(1, ctx, "start decoding: %dx%d\n", width, height); - - ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED); - /* - * If the VDOA is used, the decoder needs one additional frame, - * because the frames are freed when the next frame is decoded. - * Otherwise there are visible errors in the decoded frames (green - * regions in displayed frames) and a broken order of frames (earlier - * frames are sporadically displayed after later frames). - */ - if (ctx->use_vdoa) - ctx->num_internal_frames += 1; - if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) { - v4l2_err(&dev->v4l2_dev, - "not enough framebuffers to decode (%d < %d)\n", - CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames); - return -EINVAL; - } - - if (src_fourcc == V4L2_PIX_FMT_H264) { - u32 left_right; - u32 top_bottom; - - left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT); - top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM); - - q_data_dst->rect.left = (left_right >> 10) & 0x3ff; - q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff; - q_data_dst->rect.width = width - q_data_dst->rect.left - - (left_right & 0x3ff); - q_data_dst->rect.height = height - q_data_dst->rect.top - - (top_bottom & 0x3ff); - } - - if (dev->devtype->product != CODA_DX6) { - u8 profile, level; - - val = coda_read(dev, CODA7_RET_DEC_SEQ_HEADER_REPORT); - profile = val & 0xff; - level = (val >> 8) & 0x7f; - - if (profile || level) - coda_update_profile_level_ctrls(ctx, profile, level); - } - - return 0; -} - -static void coda_dec_seq_init_work(struct work_struct *work) -{ - struct coda_ctx *ctx = container_of(work, - struct coda_ctx, seq_init_work); - struct coda_dev *dev = ctx->dev; - - mutex_lock(&ctx->buffer_mutex); - mutex_lock(&dev->coda_mutex); - - if (!ctx->initialized) - __coda_decoder_seq_init(ctx); - - mutex_unlock(&dev->coda_mutex); - mutex_unlock(&ctx->buffer_mutex); -} - -static int __coda_start_decoding(struct coda_ctx *ctx) -{ - struct coda_q_data *q_data_src, *q_data_dst; - struct coda_dev *dev = ctx->dev; - u32 src_fourcc, dst_fourcc; - int ret; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - src_fourcc = q_data_src->fourcc; - dst_fourcc = q_data_dst->fourcc; - - if (!ctx->initialized) { - ret = __coda_decoder_seq_init(ctx); - if (ret < 0) - return ret; - } else { - ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | - CODA9_FRAME_TILED2LINEAR); - if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV) - ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; - if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) - ctx->frame_mem_ctrl |= (0x3 << 9) | - ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); - } - - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); - - ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n"); - return ret; - } - - /* Tell the decoder how many frame buffers we allocated. */ - coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); - coda_write(dev, round_up(q_data_dst->rect.width, 16), - CODA_CMD_SET_FRAME_BUF_STRIDE); - - if (dev->devtype->product != CODA_DX6) { - /* Set secondary AXI IRAM */ - coda_setup_iram(ctx); - - coda_write(dev, ctx->iram_info.buf_bit_use, - CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); - coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, - CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_y_use, - CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_c_use, - CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); - coda_write(dev, ctx->iram_info.buf_ovl_use, - CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); - if (dev->devtype->product == CODA_960) { - coda_write(dev, ctx->iram_info.buf_btp_use, - CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); - - coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); - coda9_set_frame_cache(ctx, dst_fourcc); - } - } - - if (src_fourcc == V4L2_PIX_FMT_H264) { - coda_write(dev, ctx->slicebuf.paddr, - CODA_CMD_SET_FRAME_SLICE_BB_START); - coda_write(dev, ctx->slicebuf.size / 1024, - CODA_CMD_SET_FRAME_SLICE_BB_SIZE); - } - - if (dev->devtype->product == CODA_HX4 || - dev->devtype->product == CODA_7541) { - int max_mb_x = 1920 / 16; - int max_mb_y = 1088 / 16; - int max_mb_num = max_mb_x * max_mb_y; - - coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, - CODA7_CMD_SET_FRAME_MAX_DEC_SIZE); - } else if (dev->devtype->product == CODA_960) { - int max_mb_x = 1920 / 16; - int max_mb_y = 1088 / 16; - int max_mb_num = max_mb_x * max_mb_y; - - coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, - CODA9_CMD_SET_FRAME_MAX_DEC_SIZE); - } - - if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) { - v4l2_err(&ctx->dev->v4l2_dev, - "CODA_COMMAND_SET_FRAME_BUF timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int coda_start_decoding(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - int ret; - - mutex_lock(&dev->coda_mutex); - ret = __coda_start_decoding(ctx); - mutex_unlock(&dev->coda_mutex); - - return ret; -} - -static int coda_prepare_decode(struct coda_ctx *ctx) -{ - struct vb2_v4l2_buffer *dst_buf; - struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data_dst; - struct coda_buffer_meta *meta; - u32 rot_mode = 0; - u32 reg_addr, reg_stride; - - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - - /* Try to copy source buffer contents into the bitstream ringbuffer */ - mutex_lock(&ctx->bitstream_mutex); - coda_fill_bitstream(ctx, NULL); - mutex_unlock(&ctx->bitstream_mutex); - - if (coda_get_bitstream_payload(ctx) < 512 && - (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { - coda_dbg(1, ctx, "bitstream payload: %d, skipping\n", - coda_get_bitstream_payload(ctx)); - return -EAGAIN; - } - - /* Run coda_start_decoding (again) if not yet initialized */ - if (!ctx->initialized) { - int ret = __coda_start_decoding(ctx); - - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); - return -EAGAIN; - } else { - ctx->initialized = 1; - } - } - - if (dev->devtype->product == CODA_960) - coda_set_gdi_regs(ctx); - - if (ctx->use_vdoa && - ctx->display_idx >= 0 && - ctx->display_idx < ctx->num_internal_frames) { - vdoa_device_run(ctx->vdoa, - vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0), - ctx->internal_frames[ctx->display_idx].buf.paddr); - } else { - if (dev->devtype->product == CODA_960) { - /* - * It was previously assumed that the CODA960 has an - * internal list of 64 buffer entries that contains - * both the registered internal frame buffers as well - * as the rotator buffer output, and that the ROT_INDEX - * register must be set to a value between the last - * internal frame buffers' index and 64. - * At least on firmware version 3.1.1 it turns out that - * setting ROT_INDEX to any value >= 32 causes CODA - * hangups that it can not recover from with the SRC VPU - * reset. - * It does appear to work however, to just set it to a - * fixed value in the [ctx->num_internal_frames, 31] - * range, for example CODA_MAX_FRAMEBUFFERS. - */ - coda_write(dev, CODA_MAX_FRAMEBUFFERS, - CODA9_CMD_DEC_PIC_ROT_INDEX); - - reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y; - reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE; - } else { - reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y; - reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE; - } - coda_write_base(ctx, q_data_dst, dst_buf, reg_addr); - coda_write(dev, q_data_dst->bytesperline, reg_stride); - - rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode; - } - - coda_write(dev, rot_mode, CODA_CMD_DEC_PIC_ROT_MODE); - - switch (dev->devtype->product) { - case CODA_DX6: - /* TBD */ - case CODA_HX4: - case CODA_7541: - coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); - break; - case CODA_960: - /* 'hardcode to use interrupt disable mode'? */ - coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); - break; - } - - coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM); - - coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); - coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); - - if (dev->devtype->product != CODA_DX6) - coda_write(dev, ctx->iram_info.axi_sram_use, - CODA7_REG_BIT_AXI_SRAM_USE); - - spin_lock(&ctx->buffer_meta_lock); - meta = list_first_entry_or_null(&ctx->buffer_meta_list, - struct coda_buffer_meta, list); - - if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) { - - /* If this is the last buffer in the bitstream, add padding */ - if (meta->end == ctx->bitstream_fifo.kfifo.in) { - static unsigned char buf[512]; - unsigned int pad; - - /* Pad to multiple of 256 and then add 256 more */ - pad = ((0 - meta->end) & 0xff) + 256; - - memset(buf, 0xff, sizeof(buf)); - - kfifo_in(&ctx->bitstream_fifo, buf, pad); - } - } - spin_unlock(&ctx->buffer_meta_lock); - - coda_kfifo_sync_to_device_full(ctx); - - /* Clear decode success flag */ - coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS); - - /* Clear error return value */ - coda_write(dev, 0, CODA_RET_DEC_PIC_ERR_MB); - - trace_coda_dec_pic_run(ctx, meta); - - coda_command_async(ctx, CODA_COMMAND_PIC_RUN); - - return 0; -} - -static void coda_finish_decode(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data_src; - struct coda_q_data *q_data_dst; - struct vb2_v4l2_buffer *dst_buf; - struct coda_buffer_meta *meta; - int width, height; - int decoded_idx; - int display_idx; - struct coda_internal_frame *decoded_frame = NULL; - u32 src_fourcc; - int success; - u32 err_mb; - int err_vdoa = 0; - u32 val; - - if (ctx->aborting) - return; - - /* Update kfifo out pointer from coda bitstream read pointer */ - coda_kfifo_sync_from_device(ctx); - - /* - * in stream-end mode, the read pointer can overshoot the write pointer - * by up to 512 bytes - */ - if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { - if (coda_get_bitstream_payload(ctx) >= ctx->bitstream.size - 512) - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); - } - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - src_fourcc = q_data_src->fourcc; - - val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS); - if (val != 1) - pr_err("DEC_PIC_SUCCESS = %d\n", val); - - success = val & 0x1; - if (!success) - v4l2_err(&dev->v4l2_dev, "decode failed\n"); - - if (src_fourcc == V4L2_PIX_FMT_H264) { - if (val & (1 << 3)) - v4l2_err(&dev->v4l2_dev, - "insufficient PS buffer space (%d bytes)\n", - ctx->psbuf.size); - if (val & (1 << 2)) - v4l2_err(&dev->v4l2_dev, - "insufficient slice buffer space (%d bytes)\n", - ctx->slicebuf.size); - } - - val = coda_read(dev, CODA_RET_DEC_PIC_SIZE); - width = (val >> 16) & 0xffff; - height = val & 0xffff; - - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - - /* frame crop information */ - if (src_fourcc == V4L2_PIX_FMT_H264) { - u32 left_right; - u32 top_bottom; - - left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT); - top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM); - - if (left_right == 0xffffffff && top_bottom == 0xffffffff) { - /* Keep current crop information */ - } else { - struct v4l2_rect *rect = &q_data_dst->rect; - - rect->left = left_right >> 16 & 0xffff; - rect->top = top_bottom >> 16 & 0xffff; - rect->width = width - rect->left - - (left_right & 0xffff); - rect->height = height - rect->top - - (top_bottom & 0xffff); - } - } else { - /* no cropping */ - } - - err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); - if (err_mb > 0) { - if (__ratelimit(&dev->mb_err_rs)) - coda_dbg(1, ctx, "errors in %d macroblocks\n", err_mb); - v4l2_ctrl_s_ctrl(ctx->mb_err_cnt_ctrl, - v4l2_ctrl_g_ctrl(ctx->mb_err_cnt_ctrl) + err_mb); - } - - if (dev->devtype->product == CODA_HX4 || - dev->devtype->product == CODA_7541) { - val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); - if (val == 0) { - /* not enough bitstream data */ - coda_dbg(1, ctx, "prescan failed: %d\n", val); - ctx->hold = true; - return; - } - } - - /* Wait until the VDOA finished writing the previous display frame */ - if (ctx->use_vdoa && - ctx->display_idx >= 0 && - ctx->display_idx < ctx->num_internal_frames) { - err_vdoa = vdoa_wait_for_completion(ctx->vdoa); - } - - ctx->frm_dis_flg = coda_read(dev, - CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - - /* The previous display frame was copied out and can be overwritten */ - if (ctx->display_idx >= 0 && - ctx->display_idx < ctx->num_internal_frames) { - ctx->frm_dis_flg &= ~(1 << ctx->display_idx); - coda_write(dev, ctx->frm_dis_flg, - CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - } - - /* - * The index of the last decoded frame, not necessarily in - * display order, and the index of the next display frame. - * The latter could have been decoded in a previous run. - */ - decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX); - display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX); - - if (decoded_idx == -1) { - /* no frame was decoded, but we might have a display frame */ - if (display_idx >= 0 && display_idx < ctx->num_internal_frames) - ctx->sequence_offset++; - else if (ctx->display_idx < 0) - ctx->hold = true; - } else if (decoded_idx == -2) { - if (ctx->display_idx >= 0 && - ctx->display_idx < ctx->num_internal_frames) - ctx->sequence_offset++; - /* no frame was decoded, we still return remaining buffers */ - } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { - v4l2_err(&dev->v4l2_dev, - "decoded frame index out of range: %d\n", decoded_idx); - } else { - int sequence; - - decoded_frame = &ctx->internal_frames[decoded_idx]; - - val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM); - if (ctx->sequence_offset == -1) - ctx->sequence_offset = val; - - sequence = val + ctx->first_frame_sequence - - ctx->sequence_offset; - spin_lock(&ctx->buffer_meta_lock); - if (!list_empty(&ctx->buffer_meta_list)) { - meta = list_first_entry(&ctx->buffer_meta_list, - struct coda_buffer_meta, list); - list_del(&meta->list); - ctx->num_metas--; - spin_unlock(&ctx->buffer_meta_lock); - /* - * Clamp counters to 16 bits for comparison, as the HW - * counter rolls over at this point for h.264. This - * may be different for other formats, but using 16 bits - * should be enough to detect most errors and saves us - * from doing different things based on the format. - */ - if ((sequence & 0xffff) != (meta->sequence & 0xffff)) { - v4l2_err(&dev->v4l2_dev, - "sequence number mismatch (%d(%d) != %d)\n", - sequence, ctx->sequence_offset, - meta->sequence); - } - decoded_frame->meta = *meta; - kfree(meta); - } else { - spin_unlock(&ctx->buffer_meta_lock); - v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); - memset(&decoded_frame->meta, 0, - sizeof(struct coda_buffer_meta)); - decoded_frame->meta.sequence = sequence; - decoded_frame->meta.last = false; - ctx->sequence_offset++; - } - - trace_coda_dec_pic_done(ctx, &decoded_frame->meta); - - val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; - decoded_frame->type = (val == 0) ? V4L2_BUF_FLAG_KEYFRAME : - (val == 1) ? V4L2_BUF_FLAG_PFRAME : - V4L2_BUF_FLAG_BFRAME; - - decoded_frame->error = err_mb; - } - - if (display_idx == -1) { - /* - * no more frames to be decoded, but there could still - * be rotator output to dequeue - */ - ctx->hold = true; - } else if (display_idx == -3) { - /* possibly prescan failure */ - } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) { - v4l2_err(&dev->v4l2_dev, - "presentation frame index out of range: %d\n", - display_idx); - } - - /* If a frame was copied out, return it */ - if (ctx->display_idx >= 0 && - ctx->display_idx < ctx->num_internal_frames) { - struct coda_internal_frame *ready_frame; - - ready_frame = &ctx->internal_frames[ctx->display_idx]; - - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - dst_buf->sequence = ctx->osequence++; - - dst_buf->field = V4L2_FIELD_NONE; - dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | - V4L2_BUF_FLAG_PFRAME | - V4L2_BUF_FLAG_BFRAME); - dst_buf->flags |= ready_frame->type; - meta = &ready_frame->meta; - if (meta->last && !coda_reorder_enable(ctx)) { - /* - * If this was the last decoded frame, and reordering - * is disabled, this will be the last display frame. - */ - coda_dbg(1, ctx, "last meta, marking as last frame\n"); - dst_buf->flags |= V4L2_BUF_FLAG_LAST; - } else if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG && - display_idx == -1) { - /* - * If there is no designated presentation frame anymore, - * this frame has to be the last one. - */ - coda_dbg(1, ctx, - "no more frames to return, marking as last frame\n"); - dst_buf->flags |= V4L2_BUF_FLAG_LAST; - } - dst_buf->timecode = meta->timecode; - dst_buf->vb2_buf.timestamp = meta->timestamp; - - trace_coda_dec_rot_done(ctx, dst_buf, meta); - - vb2_set_plane_payload(&dst_buf->vb2_buf, 0, - q_data_dst->sizeimage); - - if (ready_frame->error || err_vdoa) - coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); - else - coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); - - if (decoded_frame) { - coda_dbg(1, ctx, "job finished: decoded %c frame %u, returned %c frame %u (%u/%u)%s\n", - coda_frame_type_char(decoded_frame->type), - decoded_frame->meta.sequence, - coda_frame_type_char(dst_buf->flags), - ready_frame->meta.sequence, - dst_buf->sequence, ctx->qsequence, - (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? - " (last)" : ""); - } else { - coda_dbg(1, ctx, "job finished: no frame decoded (%d), returned %c frame %u (%u/%u)%s\n", - decoded_idx, - coda_frame_type_char(dst_buf->flags), - ready_frame->meta.sequence, - dst_buf->sequence, ctx->qsequence, - (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? - " (last)" : ""); - } - } else { - if (decoded_frame) { - coda_dbg(1, ctx, "job finished: decoded %c frame %u, no frame returned (%d)\n", - coda_frame_type_char(decoded_frame->type), - decoded_frame->meta.sequence, - ctx->display_idx); - } else { - coda_dbg(1, ctx, "job finished: no frame decoded (%d) or returned (%d)\n", - decoded_idx, ctx->display_idx); - } - } - - /* The rotator will copy the current display frame next time */ - ctx->display_idx = display_idx; - - /* - * The current decode run might have brought the bitstream fill level - * below the size where we can start the next decode run. As userspace - * might have filled the output queue completely and might thus be - * blocked, we can't rely on the next qbuf to trigger the bitstream - * refill. Check if we have data to refill the bitstream now. - */ - mutex_lock(&ctx->bitstream_mutex); - coda_fill_bitstream(ctx, NULL); - mutex_unlock(&ctx->bitstream_mutex); -} - -static void coda_decode_timeout(struct coda_ctx *ctx) -{ - struct vb2_v4l2_buffer *dst_buf; - - /* - * For now this only handles the case where we would deadlock with - * userspace, i.e. userspace issued DEC_CMD_STOP and waits for EOS, - * but after a failed decode run we would hold the context and wait for - * userspace to queue more buffers. - */ - if (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG)) - return; - - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - dst_buf->sequence = ctx->qsequence - 1; - - coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); -} - -const struct coda_context_ops coda_bit_decode_ops = { - .queue_init = coda_decoder_queue_init, - .reqbufs = coda_decoder_reqbufs, - .start_streaming = coda_start_decoding, - .prepare_run = coda_prepare_decode, - .finish_run = coda_finish_decode, - .run_timeout = coda_decode_timeout, - .seq_init_work = coda_dec_seq_init_work, - .seq_end_work = coda_seq_end_work, - .release = coda_bit_release, -}; - -irqreturn_t coda_irq_handler(int irq, void *data) -{ - struct coda_dev *dev = data; - struct coda_ctx *ctx; - - /* read status register to attend the IRQ */ - coda_read(dev, CODA_REG_BIT_INT_STATUS); - coda_write(dev, 0, CODA_REG_BIT_INT_REASON); - coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, - CODA_REG_BIT_INT_CLEAR); - - ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); - if (ctx == NULL) { - v4l2_err(&dev->v4l2_dev, - "Instance released before the end of transaction\n"); - return IRQ_HANDLED; - } - - trace_coda_bit_done(ctx); - - if (ctx->aborting) { - coda_dbg(1, ctx, "task has been aborted\n"); - } - - if (coda_isbusy(ctx->dev)) { - coda_dbg(1, ctx, "coda is still busy!!!!\n"); - return IRQ_NONE; - } - - complete(&ctx->completion); - - return IRQ_HANDLED; -} diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda-common.c b/drivers/media/platform/chips-media/coda-common.c --- a/drivers/media/platform/chips-media/coda-common.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/coda-common.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,3361 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Coda multi-standard codec IP - * - * Copyright (C) 2012 Vista Silicon S.L. - * Javier Martin, - * Xavier Duret - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "coda.h" -#include "imx-vdoa.h" - -#define CODA_NAME "coda" - -#define CODADX6_MAX_INSTANCES 4 -#define CODA_MAX_FORMATS 5 - -#define CODA_ISRAM_SIZE (2048 * 2) - -#define MIN_W 48 -#define MIN_H 16 - -#define S_ALIGN 1 /* multiple of 2 */ -#define W_ALIGN 1 /* multiple of 2 */ -#define H_ALIGN 1 /* multiple of 2 */ - -#define fh_to_ctx(__fh) container_of(__fh, struct coda_ctx, fh) - -int coda_debug; -module_param(coda_debug, int, 0644); -MODULE_PARM_DESC(coda_debug, "Debug level (0-2)"); - -static int disable_tiling; -module_param(disable_tiling, int, 0644); -MODULE_PARM_DESC(disable_tiling, "Disable tiled frame buffers"); - -static int disable_vdoa; -module_param(disable_vdoa, int, 0644); -MODULE_PARM_DESC(disable_vdoa, "Disable Video Data Order Adapter tiled to raster-scan conversion"); - -static int enable_bwb = 0; -module_param(enable_bwb, int, 0644); -MODULE_PARM_DESC(enable_bwb, "Enable BWB unit for decoding, may crash on certain streams"); - -void coda_write(struct coda_dev *dev, u32 data, u32 reg) -{ - v4l2_dbg(3, coda_debug, &dev->v4l2_dev, - "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); - writel(data, dev->regs_base + reg); -} - -unsigned int coda_read(struct coda_dev *dev, u32 reg) -{ - u32 data; - - data = readl(dev->regs_base + reg); - v4l2_dbg(3, coda_debug, &dev->v4l2_dev, - "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); - return data; -} - -void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, - struct vb2_v4l2_buffer *buf, unsigned int reg_y) -{ - u32 base_y = vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, 0); - u32 base_cb, base_cr; - - switch (q_data->fourcc) { - case V4L2_PIX_FMT_YUYV: - /* Fallthrough: IN -H264-> CODA -NV12 MB-> VDOA -YUYV-> OUT */ - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_YUV420: - default: - base_cb = base_y + q_data->bytesperline * q_data->height; - base_cr = base_cb + q_data->bytesperline * q_data->height / 4; - break; - case V4L2_PIX_FMT_YVU420: - /* Switch Cb and Cr for YVU420 format */ - base_cr = base_y + q_data->bytesperline * q_data->height; - base_cb = base_cr + q_data->bytesperline * q_data->height / 4; - break; - case V4L2_PIX_FMT_YUV422P: - base_cb = base_y + q_data->bytesperline * q_data->height; - base_cr = base_cb + q_data->bytesperline * q_data->height / 2; - } - - coda_write(ctx->dev, base_y, reg_y); - coda_write(ctx->dev, base_cb, reg_y + 4); - coda_write(ctx->dev, base_cr, reg_y + 8); -} - -#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \ - { mode, src_fourcc, dst_fourcc, max_w, max_h } - -/* - * Arrays of codecs supported by each given version of Coda: - * i.MX27 -> codadx6 - * i.MX51 -> codahx4 - * i.MX53 -> coda7 - * i.MX6 -> coda960 - * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants - */ -static const struct coda_codec codadx6_codecs[] = { - CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), - CODA_CODEC(CODADX6_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576), -}; - -static const struct coda_codec codahx4_codecs[] = { - CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), - CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), - CODA_CODEC(CODA7_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), - CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1280, 720), -}; - -static const struct coda_codec coda7_codecs[] = { - CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), - CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), - CODA_CODEC(CODA7_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG, 8192, 8192), - CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), - CODA_CODEC(CODA7_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), - CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), - CODA_CODEC(CODA7_MODE_DECODE_MJPG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420, 8192, 8192), -}; - -static const struct coda_codec coda9_codecs[] = { - CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1088), - CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1088), - CODA_CODEC(CODA9_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG, 8192, 8192), - CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), - CODA_CODEC(CODA9_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), - CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), - CODA_CODEC(CODA9_MODE_DECODE_MJPG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420, 8192, 8192), -}; - -struct coda_video_device { - const char *name; - enum coda_inst_type type; - const struct coda_context_ops *ops; - bool direct; - u32 src_formats[CODA_MAX_FORMATS]; - u32 dst_formats[CODA_MAX_FORMATS]; -}; - -static const struct coda_video_device coda_bit_encoder = { - .name = "coda-video-encoder", - .type = CODA_INST_ENCODER, - .ops = &coda_bit_encode_ops, - .src_formats = { - V4L2_PIX_FMT_NV12, - V4L2_PIX_FMT_YUV420, - V4L2_PIX_FMT_YVU420, - }, - .dst_formats = { - V4L2_PIX_FMT_H264, - V4L2_PIX_FMT_MPEG4, - }, -}; - -static const struct coda_video_device coda_bit_jpeg_encoder = { - .name = "coda-jpeg-encoder", - .type = CODA_INST_ENCODER, - .ops = &coda_bit_encode_ops, - .src_formats = { - V4L2_PIX_FMT_NV12, - V4L2_PIX_FMT_YUV420, - V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_YUV422P, - }, - .dst_formats = { - V4L2_PIX_FMT_JPEG, - }, -}; - -static const struct coda_video_device coda_bit_decoder = { - .name = "coda-video-decoder", - .type = CODA_INST_DECODER, - .ops = &coda_bit_decode_ops, - .src_formats = { - V4L2_PIX_FMT_H264, - V4L2_PIX_FMT_MPEG2, - V4L2_PIX_FMT_MPEG4, - }, - .dst_formats = { - V4L2_PIX_FMT_NV12, - V4L2_PIX_FMT_YUV420, - V4L2_PIX_FMT_YVU420, - /* - * If V4L2_PIX_FMT_YUYV should be default, - * set_default_params() must be adjusted. - */ - V4L2_PIX_FMT_YUYV, - }, -}; - -static const struct coda_video_device coda_bit_jpeg_decoder = { - .name = "coda-jpeg-decoder", - .type = CODA_INST_DECODER, - .ops = &coda_bit_decode_ops, - .src_formats = { - V4L2_PIX_FMT_JPEG, - }, - .dst_formats = { - V4L2_PIX_FMT_NV12, - V4L2_PIX_FMT_YUV420, - V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_YUV422P, - }, -}; - -static const struct coda_video_device coda9_jpeg_encoder = { - .name = "coda-jpeg-encoder", - .type = CODA_INST_ENCODER, - .ops = &coda9_jpeg_encode_ops, - .direct = true, - .src_formats = { - V4L2_PIX_FMT_NV12, - V4L2_PIX_FMT_YUV420, - V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_YUV422P, - V4L2_PIX_FMT_GREY, - }, - .dst_formats = { - V4L2_PIX_FMT_JPEG, - }, -}; - -static const struct coda_video_device coda9_jpeg_decoder = { - .name = "coda-jpeg-decoder", - .type = CODA_INST_DECODER, - .ops = &coda9_jpeg_decode_ops, - .direct = true, - .src_formats = { - V4L2_PIX_FMT_JPEG, - }, - .dst_formats = { - V4L2_PIX_FMT_NV12, - V4L2_PIX_FMT_YUV420, - V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_YUV422P, - }, -}; - -static const struct coda_video_device *codadx6_video_devices[] = { - &coda_bit_encoder, -}; - -static const struct coda_video_device *codahx4_video_devices[] = { - &coda_bit_encoder, - &coda_bit_decoder, -}; - -static const struct coda_video_device *coda7_video_devices[] = { - &coda_bit_jpeg_encoder, - &coda_bit_jpeg_decoder, - &coda_bit_encoder, - &coda_bit_decoder, -}; - -static const struct coda_video_device *coda9_video_devices[] = { - &coda9_jpeg_encoder, - &coda9_jpeg_decoder, - &coda_bit_encoder, - &coda_bit_decoder, -}; - -/* - * Normalize all supported YUV 4:2:0 formats to the value used in the codec - * tables. - */ -static u32 coda_format_normalize_yuv(u32 fourcc) -{ - switch (fourcc) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_YUV422P: - case V4L2_PIX_FMT_YUYV: - return V4L2_PIX_FMT_YUV420; - default: - return fourcc; - } -} - -static const struct coda_codec *coda_find_codec(struct coda_dev *dev, - int src_fourcc, int dst_fourcc) -{ - const struct coda_codec *codecs = dev->devtype->codecs; - int num_codecs = dev->devtype->num_codecs; - int k; - - src_fourcc = coda_format_normalize_yuv(src_fourcc); - dst_fourcc = coda_format_normalize_yuv(dst_fourcc); - if (src_fourcc == dst_fourcc) - return NULL; - - for (k = 0; k < num_codecs; k++) { - if (codecs[k].src_fourcc == src_fourcc && - codecs[k].dst_fourcc == dst_fourcc) - break; - } - - if (k == num_codecs) - return NULL; - - return &codecs[k]; -} - -static void coda_get_max_dimensions(struct coda_dev *dev, - const struct coda_codec *codec, - int *max_w, int *max_h) -{ - const struct coda_codec *codecs = dev->devtype->codecs; - int num_codecs = dev->devtype->num_codecs; - unsigned int w, h; - int k; - - if (codec) { - w = codec->max_w; - h = codec->max_h; - } else { - for (k = 0, w = 0, h = 0; k < num_codecs; k++) { - w = max(w, codecs[k].max_w); - h = max(h, codecs[k].max_h); - } - } - - if (max_w) - *max_w = w; - if (max_h) - *max_h = h; -} - -static const struct coda_video_device *to_coda_video_device(struct video_device - *vdev) -{ - struct coda_dev *dev = video_get_drvdata(vdev); - unsigned int i = vdev - dev->vfd; - - if (i >= dev->devtype->num_vdevs) - return NULL; - - return dev->devtype->vdevs[i]; -} - -const char *coda_product_name(int product) -{ - static char buf[9]; - - switch (product) { - case CODA_DX6: - return "CodaDx6"; - case CODA_HX4: - return "CodaHx4"; - case CODA_7541: - return "CODA7541"; - case CODA_960: - return "CODA960"; - default: - snprintf(buf, sizeof(buf), "(0x%04x)", product); - return buf; - } -} - -static struct vdoa_data *coda_get_vdoa_data(void) -{ - struct device_node *vdoa_node; - struct platform_device *vdoa_pdev; - struct vdoa_data *vdoa_data = NULL; - - vdoa_node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-vdoa"); - if (!vdoa_node) - return NULL; - - vdoa_pdev = of_find_device_by_node(vdoa_node); - if (!vdoa_pdev) - goto out; - - vdoa_data = platform_get_drvdata(vdoa_pdev); - if (!vdoa_data) - vdoa_data = ERR_PTR(-EPROBE_DEFER); - - put_device(&vdoa_pdev->dev); -out: - of_node_put(vdoa_node); - - return vdoa_data; -} - -/* - * V4L2 ioctl() operations. - */ -static int coda_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - - strscpy(cap->driver, CODA_NAME, sizeof(cap->driver)); - strscpy(cap->card, coda_product_name(ctx->dev->devtype->product), - sizeof(cap->card)); - strscpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info)); - return 0; -} - -static const u32 coda_formats_420[CODA_MAX_FORMATS] = { - V4L2_PIX_FMT_NV12, - V4L2_PIX_FMT_YUV420, - V4L2_PIX_FMT_YVU420, -}; - -static int coda_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct video_device *vdev = video_devdata(file); - const struct coda_video_device *cvd = to_coda_video_device(vdev); - struct coda_ctx *ctx = fh_to_ctx(priv); - const u32 *formats; - - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - formats = cvd->src_formats; - else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - struct coda_q_data *q_data_src; - struct vb2_queue *src_vq; - - formats = cvd->dst_formats; - - /* - * If the source format is already fixed, only allow the same - * chroma subsampling. - */ - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_OUTPUT); - if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && - vb2_is_streaming(src_vq)) { - if (ctx->params.jpeg_chroma_subsampling == - V4L2_JPEG_CHROMA_SUBSAMPLING_420) { - formats = coda_formats_420; - } else if (ctx->params.jpeg_chroma_subsampling == - V4L2_JPEG_CHROMA_SUBSAMPLING_422) { - f->pixelformat = V4L2_PIX_FMT_YUV422P; - return f->index ? -EINVAL : 0; - } - } - } else { - return -EINVAL; - } - - if (f->index >= CODA_MAX_FORMATS || formats[f->index] == 0) - return -EINVAL; - - /* Skip YUYV if the vdoa is not available */ - if (!ctx->vdoa && f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && - formats[f->index] == V4L2_PIX_FMT_YUYV) - return -EINVAL; - - f->pixelformat = formats[f->index]; - - return 0; -} - -static int coda_g_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct coda_q_data *q_data; - struct coda_ctx *ctx = fh_to_ctx(priv); - - q_data = get_q_data(ctx, f->type); - if (!q_data) - return -EINVAL; - - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.pixelformat = q_data->fourcc; - f->fmt.pix.width = q_data->width; - f->fmt.pix.height = q_data->height; - f->fmt.pix.bytesperline = q_data->bytesperline; - - f->fmt.pix.sizeimage = q_data->sizeimage; - f->fmt.pix.colorspace = ctx->colorspace; - f->fmt.pix.xfer_func = ctx->xfer_func; - f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; - f->fmt.pix.quantization = ctx->quantization; - - return 0; -} - -static int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f) -{ - struct coda_q_data *q_data; - const u32 *formats; - int i; - - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - formats = ctx->cvd->src_formats; - else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - formats = ctx->cvd->dst_formats; - else - return -EINVAL; - - for (i = 0; i < CODA_MAX_FORMATS; i++) { - /* Skip YUYV if the vdoa is not available */ - if (!ctx->vdoa && f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && - formats[i] == V4L2_PIX_FMT_YUYV) - continue; - - if (formats[i] == f->fmt.pix.pixelformat) { - f->fmt.pix.pixelformat = formats[i]; - return 0; - } - } - - /* Fall back to currently set pixelformat */ - q_data = get_q_data(ctx, f->type); - f->fmt.pix.pixelformat = q_data->fourcc; - - return 0; -} - -static int coda_try_fmt_vdoa(struct coda_ctx *ctx, struct v4l2_format *f, - bool *use_vdoa) -{ - int err; - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (!use_vdoa) - return -EINVAL; - - if (!ctx->vdoa) { - *use_vdoa = false; - return 0; - } - - err = vdoa_context_configure(NULL, round_up(f->fmt.pix.width, 16), - f->fmt.pix.height, f->fmt.pix.pixelformat); - if (err) { - *use_vdoa = false; - return 0; - } - - *use_vdoa = true; - return 0; -} - -static unsigned int coda_estimate_sizeimage(struct coda_ctx *ctx, u32 sizeimage, - u32 width, u32 height) -{ - /* - * This is a rough estimate for sensible compressed buffer - * sizes (between 1 and 16 bits per pixel). This could be - * improved by better format specific worst case estimates. - */ - return round_up(clamp(sizeimage, width * height / 8, - width * height * 2), PAGE_SIZE); -} - -static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, - struct v4l2_format *f) -{ - struct coda_dev *dev = ctx->dev; - unsigned int max_w, max_h; - enum v4l2_field field; - - field = f->fmt.pix.field; - if (field == V4L2_FIELD_ANY) - field = V4L2_FIELD_NONE; - else if (V4L2_FIELD_NONE != field) - return -EINVAL; - - /* V4L2 specification suggests the driver corrects the format struct - * if any of the dimensions is unsupported */ - f->fmt.pix.field = field; - - coda_get_max_dimensions(dev, codec, &max_w, &max_h); - v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w, W_ALIGN, - &f->fmt.pix.height, MIN_H, max_h, H_ALIGN, - S_ALIGN); - - switch (f->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - /* - * Frame stride must be at least multiple of 8, - * but multiple of 16 for h.264 or JPEG 4:2:x - */ - f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * - f->fmt.pix.height * 3 / 2; - break; - case V4L2_PIX_FMT_YUYV: - f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16) * 2; - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * - f->fmt.pix.height; - break; - case V4L2_PIX_FMT_YUV422P: - f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * - f->fmt.pix.height * 2; - break; - case V4L2_PIX_FMT_GREY: - /* keep 16 pixel alignment of 8-bit pixel data */ - f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; - break; - case V4L2_PIX_FMT_JPEG: - case V4L2_PIX_FMT_H264: - case V4L2_PIX_FMT_MPEG4: - case V4L2_PIX_FMT_MPEG2: - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = coda_estimate_sizeimage(ctx, - f->fmt.pix.sizeimage, - f->fmt.pix.width, - f->fmt.pix.height); - break; - default: - BUG(); - } - - return 0; -} - -static int coda_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - const struct coda_q_data *q_data_src; - const struct coda_codec *codec; - struct vb2_queue *src_vq; - int hscale = 0; - int vscale = 0; - int ret; - bool use_vdoa; - - ret = coda_try_pixelformat(ctx, f); - if (ret < 0) - return ret; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - - /* - * If the source format is already fixed, only allow the same output - * resolution. When decoding JPEG images, we also have to make sure to - * use the same chroma subsampling. - */ - src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - if (vb2_is_streaming(src_vq)) { - if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && - ctx->dev->devtype->product == CODA_960) { - hscale = coda_jpeg_scale(q_data_src->width, f->fmt.pix.width); - vscale = coda_jpeg_scale(q_data_src->height, f->fmt.pix.height); - } - f->fmt.pix.width = q_data_src->width >> hscale; - f->fmt.pix.height = q_data_src->height >> vscale; - - if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) { - if (ctx->params.jpeg_chroma_subsampling == - V4L2_JPEG_CHROMA_SUBSAMPLING_420 && - f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) - f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12; - else if (ctx->params.jpeg_chroma_subsampling == - V4L2_JPEG_CHROMA_SUBSAMPLING_422) - f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; - } - } - - f->fmt.pix.colorspace = ctx->colorspace; - f->fmt.pix.xfer_func = ctx->xfer_func; - f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; - f->fmt.pix.quantization = ctx->quantization; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - codec = coda_find_codec(ctx->dev, q_data_src->fourcc, - f->fmt.pix.pixelformat); - if (!codec) - return -EINVAL; - - ret = coda_try_fmt(ctx, codec, f); - if (ret < 0) - return ret; - - /* The decoders always write complete macroblocks or MCUs */ - if (ctx->inst_type == CODA_INST_DECODER) { - f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16 >> hscale); - f->fmt.pix.height = round_up(f->fmt.pix.height, 16 >> vscale); - if (codec->src_fourcc == V4L2_PIX_FMT_JPEG && - f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) { - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * - f->fmt.pix.height * 2; - } else { - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * - f->fmt.pix.height * 3 / 2; - } - - ret = coda_try_fmt_vdoa(ctx, f, &use_vdoa); - if (ret < 0) - return ret; - - if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) { - if (!use_vdoa) - return -EINVAL; - - f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16) * 2; - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * - f->fmt.pix.height; - } - } - - return 0; -} - -static void coda_set_default_colorspace(struct v4l2_pix_format *fmt) -{ - enum v4l2_colorspace colorspace; - - if (fmt->pixelformat == V4L2_PIX_FMT_JPEG) - colorspace = V4L2_COLORSPACE_JPEG; - else if (fmt->width <= 720 && fmt->height <= 576) - colorspace = V4L2_COLORSPACE_SMPTE170M; - else - colorspace = V4L2_COLORSPACE_REC709; - - fmt->colorspace = colorspace; - fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; - fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - fmt->quantization = V4L2_QUANTIZATION_DEFAULT; -} - -static int coda_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - struct coda_dev *dev = ctx->dev; - const struct coda_q_data *q_data_dst; - const struct coda_codec *codec; - int ret; - - ret = coda_try_pixelformat(ctx, f); - if (ret < 0) - return ret; - - if (f->fmt.pix.colorspace == V4L2_COLORSPACE_DEFAULT) - coda_set_default_colorspace(&f->fmt.pix); - - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - codec = coda_find_codec(dev, f->fmt.pix.pixelformat, q_data_dst->fourcc); - - return coda_try_fmt(ctx, codec, f); -} - -static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, - struct v4l2_rect *r) -{ - struct coda_q_data *q_data; - struct vb2_queue *vq; - - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - - q_data = get_q_data(ctx, f->type); - if (!q_data) - return -EINVAL; - - if (vb2_is_busy(vq)) { - v4l2_err(&ctx->dev->v4l2_dev, "%s: %s queue busy: %d\n", - __func__, v4l2_type_names[f->type], vq->num_buffers); - return -EBUSY; - } - - q_data->fourcc = f->fmt.pix.pixelformat; - q_data->width = f->fmt.pix.width; - q_data->height = f->fmt.pix.height; - q_data->bytesperline = f->fmt.pix.bytesperline; - q_data->sizeimage = f->fmt.pix.sizeimage; - if (r) { - q_data->rect = *r; - } else { - q_data->rect.left = 0; - q_data->rect.top = 0; - q_data->rect.width = f->fmt.pix.width; - q_data->rect.height = f->fmt.pix.height; - } - - switch (f->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_YUYV: - ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; - break; - case V4L2_PIX_FMT_NV12: - if (!disable_tiling && ctx->use_bit && - ctx->dev->devtype->product == CODA_960) { - ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; - break; - } - fallthrough; - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_YUV422P: - ctx->tiled_map_type = GDI_LINEAR_FRAME_MAP; - break; - default: - break; - } - - if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP && - !coda_try_fmt_vdoa(ctx, f, &ctx->use_vdoa) && - ctx->use_vdoa) - vdoa_context_configure(ctx->vdoa, - round_up(f->fmt.pix.width, 16), - f->fmt.pix.height, - f->fmt.pix.pixelformat); - else - ctx->use_vdoa = false; - - coda_dbg(1, ctx, "Setting %s format, wxh: %dx%d, fmt: %4.4s %c\n", - v4l2_type_names[f->type], q_data->width, q_data->height, - (char *)&q_data->fourcc, - (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) ? 'L' : 'T'); - - return 0; -} - -static int coda_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - struct coda_q_data *q_data_src; - const struct coda_codec *codec; - struct v4l2_rect r; - int hscale = 0; - int vscale = 0; - int ret; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - - if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && - ctx->dev->devtype->product == CODA_960) { - hscale = coda_jpeg_scale(q_data_src->width, f->fmt.pix.width); - vscale = coda_jpeg_scale(q_data_src->height, f->fmt.pix.height); - } - - ret = coda_try_fmt_vid_cap(file, priv, f); - if (ret) - return ret; - - r.left = 0; - r.top = 0; - r.width = q_data_src->width >> hscale; - r.height = q_data_src->height >> vscale; - - ret = coda_s_fmt(ctx, f, &r); - if (ret) - return ret; - - if (ctx->inst_type != CODA_INST_ENCODER) - return 0; - - /* Setting the coded format determines the selected codec */ - codec = coda_find_codec(ctx->dev, q_data_src->fourcc, - f->fmt.pix.pixelformat); - if (!codec) { - v4l2_err(&ctx->dev->v4l2_dev, "failed to determine codec\n"); - return -EINVAL; - } - ctx->codec = codec; - - ctx->colorspace = f->fmt.pix.colorspace; - ctx->xfer_func = f->fmt.pix.xfer_func; - ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; - ctx->quantization = f->fmt.pix.quantization; - - return 0; -} - -static int coda_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - const struct coda_codec *codec; - struct v4l2_format f_cap; - struct vb2_queue *dst_vq; - int ret; - - ret = coda_try_fmt_vid_out(file, priv, f); - if (ret) - return ret; - - ret = coda_s_fmt(ctx, f, NULL); - if (ret) - return ret; - - ctx->colorspace = f->fmt.pix.colorspace; - ctx->xfer_func = f->fmt.pix.xfer_func; - ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; - ctx->quantization = f->fmt.pix.quantization; - - if (ctx->inst_type != CODA_INST_DECODER) - return 0; - - /* Setting the coded format determines the selected codec */ - codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, - V4L2_PIX_FMT_YUV420); - if (!codec) { - v4l2_err(&ctx->dev->v4l2_dev, "failed to determine codec\n"); - return -EINVAL; - } - ctx->codec = codec; - - dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - if (!dst_vq) - return -EINVAL; - - /* - * Setting the capture queue format is not possible while the capture - * queue is still busy. This is not an error, but the user will have to - * make sure themselves that the capture format is set correctly before - * starting the output queue again. - */ - if (vb2_is_busy(dst_vq)) - return 0; - - memset(&f_cap, 0, sizeof(f_cap)); - f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - coda_g_fmt(file, priv, &f_cap); - f_cap.fmt.pix.width = f->fmt.pix.width; - f_cap.fmt.pix.height = f->fmt.pix.height; - - return coda_s_fmt_vid_cap(file, priv, &f_cap); -} - -static int coda_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - int ret; - - ret = v4l2_m2m_reqbufs(file, ctx->fh.m2m_ctx, rb); - if (ret) - return ret; - - /* - * Allow to allocate instance specific per-context buffers, such as - * bitstream ringbuffer, slice buffer, work buffer, etc. if needed. - */ - if (rb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && ctx->ops->reqbufs) - return ctx->ops->reqbufs(ctx, rb); - - return 0; -} - -static int coda_qbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - - if (ctx->inst_type == CODA_INST_DECODER && - buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - buf->flags &= ~V4L2_BUF_FLAG_LAST; - - return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf); -} - -static int coda_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - int ret; - - ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); - - if (ctx->inst_type == CODA_INST_DECODER && - buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - buf->flags &= ~V4L2_BUF_FLAG_LAST; - - return ret; -} - -void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, - enum vb2_buffer_state state) -{ - const struct v4l2_event eos_event = { - .type = V4L2_EVENT_EOS - }; - - if (buf->flags & V4L2_BUF_FLAG_LAST) - v4l2_event_queue_fh(&ctx->fh, &eos_event); - - v4l2_m2m_buf_done(buf, state); -} - -static int coda_g_selection(struct file *file, void *fh, - struct v4l2_selection *s) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - struct coda_q_data *q_data; - struct v4l2_rect r, *rsel; - - q_data = get_q_data(ctx, s->type); - if (!q_data) - return -EINVAL; - - r.left = 0; - r.top = 0; - r.width = q_data->width; - r.height = q_data->height; - rsel = &q_data->rect; - - switch (s->target) { - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - rsel = &r; - fallthrough; - case V4L2_SEL_TGT_CROP: - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || - ctx->inst_type == CODA_INST_DECODER) - return -EINVAL; - break; - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - case V4L2_SEL_TGT_COMPOSE_PADDED: - rsel = &r; - fallthrough; - case V4L2_SEL_TGT_COMPOSE: - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - ctx->inst_type == CODA_INST_ENCODER) - return -EINVAL; - break; - default: - return -EINVAL; - } - - s->r = *rsel; - - return 0; -} - -static int coda_s_selection(struct file *file, void *fh, - struct v4l2_selection *s) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - struct coda_q_data *q_data; - - switch (s->target) { - case V4L2_SEL_TGT_CROP: - if (ctx->inst_type == CODA_INST_ENCODER && - s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - q_data = get_q_data(ctx, s->type); - if (!q_data) - return -EINVAL; - - s->r.left = 0; - s->r.top = 0; - s->r.width = clamp(s->r.width, 2U, q_data->width); - s->r.height = clamp(s->r.height, 2U, q_data->height); - - if (s->flags & V4L2_SEL_FLAG_LE) { - s->r.width = round_up(s->r.width, 2); - s->r.height = round_up(s->r.height, 2); - } else { - s->r.width = round_down(s->r.width, 2); - s->r.height = round_down(s->r.height, 2); - } - - q_data->rect = s->r; - - coda_dbg(1, ctx, "Setting crop rectangle: %dx%d\n", - s->r.width, s->r.height); - - return 0; - } - fallthrough; - case V4L2_SEL_TGT_NATIVE_SIZE: - case V4L2_SEL_TGT_COMPOSE: - return coda_g_selection(file, fh, s); - default: - /* v4l2-compliance expects this to fail for read-only targets */ - return -EINVAL; - } -} - -static void coda_wake_up_capture_queue(struct coda_ctx *ctx) -{ - struct vb2_queue *dst_vq; - - coda_dbg(1, ctx, "waking up capture queue\n"); - - dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_vq->last_buffer_dequeued = true; - wake_up(&dst_vq->done_wq); -} - -static int coda_encoder_cmd(struct file *file, void *fh, - struct v4l2_encoder_cmd *ec) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - struct vb2_v4l2_buffer *buf; - int ret; - - ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); - if (ret < 0) - return ret; - - mutex_lock(&ctx->wakeup_mutex); - buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); - if (buf) { - /* - * If the last output buffer is still on the queue, make sure - * that decoder finish_run will see the last flag and report it - * to userspace. - */ - buf->flags |= V4L2_BUF_FLAG_LAST; - } else { - /* Set the stream-end flag on this context */ - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - - /* - * If the last output buffer has already been taken from the - * queue, wake up the capture queue and signal end of stream - * via the -EPIPE mechanism. - */ - coda_wake_up_capture_queue(ctx); - } - mutex_unlock(&ctx->wakeup_mutex); - - return 0; -} - -static bool coda_mark_last_meta(struct coda_ctx *ctx) -{ - struct coda_buffer_meta *meta; - - coda_dbg(1, ctx, "marking last meta\n"); - - spin_lock(&ctx->buffer_meta_lock); - if (list_empty(&ctx->buffer_meta_list)) { - spin_unlock(&ctx->buffer_meta_lock); - return false; - } - - meta = list_last_entry(&ctx->buffer_meta_list, struct coda_buffer_meta, - list); - meta->last = true; - - spin_unlock(&ctx->buffer_meta_lock); - return true; -} - -static bool coda_mark_last_dst_buf(struct coda_ctx *ctx) -{ - struct vb2_v4l2_buffer *buf; - struct vb2_buffer *dst_vb; - struct vb2_queue *dst_vq; - unsigned long flags; - - coda_dbg(1, ctx, "marking last capture buffer\n"); - - dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - spin_lock_irqsave(&dst_vq->done_lock, flags); - if (list_empty(&dst_vq->done_list)) { - spin_unlock_irqrestore(&dst_vq->done_lock, flags); - return false; - } - - dst_vb = list_last_entry(&dst_vq->done_list, struct vb2_buffer, - done_entry); - buf = to_vb2_v4l2_buffer(dst_vb); - buf->flags |= V4L2_BUF_FLAG_LAST; - - spin_unlock_irqrestore(&dst_vq->done_lock, flags); - return true; -} - -static int coda_decoder_cmd(struct file *file, void *fh, - struct v4l2_decoder_cmd *dc) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - struct coda_dev *dev = ctx->dev; - struct vb2_v4l2_buffer *buf; - struct vb2_queue *dst_vq; - bool stream_end; - bool wakeup; - int ret; - - ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); - if (ret < 0) - return ret; - - switch (dc->cmd) { - case V4L2_DEC_CMD_START: - mutex_lock(&dev->coda_mutex); - mutex_lock(&ctx->bitstream_mutex); - coda_bitstream_flush(ctx); - dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE); - vb2_clear_last_buffer_dequeued(dst_vq); - ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; - coda_fill_bitstream(ctx, NULL); - mutex_unlock(&ctx->bitstream_mutex); - mutex_unlock(&dev->coda_mutex); - break; - case V4L2_DEC_CMD_STOP: - stream_end = false; - wakeup = false; - - mutex_lock(&ctx->wakeup_mutex); - - buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); - if (buf) { - coda_dbg(1, ctx, "marking last pending buffer\n"); - - /* Mark last buffer */ - buf->flags |= V4L2_BUF_FLAG_LAST; - - if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) == 0) { - coda_dbg(1, ctx, "all remaining buffers queued\n"); - stream_end = true; - } - } else { - if (ctx->use_bit) - if (coda_mark_last_meta(ctx)) - stream_end = true; - else - wakeup = true; - else - if (!coda_mark_last_dst_buf(ctx)) - wakeup = true; - } - - if (stream_end) { - coda_dbg(1, ctx, "all remaining buffers queued\n"); - - /* Set the stream-end flag on this context */ - coda_bit_stream_end_flag(ctx); - ctx->hold = false; - v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); - } - - if (wakeup) { - /* If there is no buffer in flight, wake up */ - coda_wake_up_capture_queue(ctx); - } - - mutex_unlock(&ctx->wakeup_mutex); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int coda_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - struct coda_q_data *q_data_dst; - const struct coda_codec *codec; - - if (fsize->index) - return -EINVAL; - - if (coda_format_normalize_yuv(fsize->pixel_format) == - V4L2_PIX_FMT_YUV420) { - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - codec = coda_find_codec(ctx->dev, fsize->pixel_format, - q_data_dst->fourcc); - } else { - codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, - fsize->pixel_format); - } - if (!codec) - return -EINVAL; - - fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; - fsize->stepwise.min_width = MIN_W; - fsize->stepwise.max_width = codec->max_w; - fsize->stepwise.step_width = 1; - fsize->stepwise.min_height = MIN_H; - fsize->stepwise.max_height = codec->max_h; - fsize->stepwise.step_height = 1; - - return 0; -} - -static int coda_enum_frameintervals(struct file *file, void *fh, - struct v4l2_frmivalenum *f) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - struct coda_q_data *q_data; - const struct coda_codec *codec; - - if (f->index) - return -EINVAL; - - /* Disallow YUYV if the vdoa is not available */ - if (!ctx->vdoa && f->pixel_format == V4L2_PIX_FMT_YUYV) - return -EINVAL; - - if (coda_format_normalize_yuv(f->pixel_format) == V4L2_PIX_FMT_YUV420) { - q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - codec = coda_find_codec(ctx->dev, f->pixel_format, - q_data->fourcc); - } else { - codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, - f->pixel_format); - } - if (!codec) - return -EINVAL; - - if (f->width < MIN_W || f->width > codec->max_w || - f->height < MIN_H || f->height > codec->max_h) - return -EINVAL; - - f->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; - f->stepwise.min.numerator = 1; - f->stepwise.min.denominator = 65535; - f->stepwise.max.numerator = 65536; - f->stepwise.max.denominator = 1; - f->stepwise.step.numerator = 1; - f->stepwise.step.denominator = 1; - - return 0; -} - -static int coda_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - struct v4l2_fract *tpf; - - if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; - tpf = &a->parm.output.timeperframe; - tpf->denominator = ctx->params.framerate & CODA_FRATE_RES_MASK; - tpf->numerator = 1 + (ctx->params.framerate >> - CODA_FRATE_DIV_OFFSET); - - return 0; -} - -/* - * Approximate timeperframe v4l2_fract with values that can be written - * into the 16-bit CODA_FRATE_DIV and CODA_FRATE_RES fields. - */ -static void coda_approximate_timeperframe(struct v4l2_fract *timeperframe) -{ - struct v4l2_fract s = *timeperframe; - struct v4l2_fract f0; - struct v4l2_fract f1 = { 1, 0 }; - struct v4l2_fract f2 = { 0, 1 }; - unsigned int i, div, s_denominator; - - /* Lower bound is 1/65535 */ - if (s.numerator == 0 || s.denominator / s.numerator > 65535) { - timeperframe->numerator = 1; - timeperframe->denominator = 65535; - return; - } - - /* Upper bound is 65536/1 */ - if (s.denominator == 0 || s.numerator / s.denominator > 65536) { - timeperframe->numerator = 65536; - timeperframe->denominator = 1; - return; - } - - /* Reduce fraction to lowest terms */ - div = gcd(s.numerator, s.denominator); - if (div > 1) { - s.numerator /= div; - s.denominator /= div; - } - - if (s.numerator <= 65536 && s.denominator < 65536) { - *timeperframe = s; - return; - } - - /* Find successive convergents from continued fraction expansion */ - while (f2.numerator <= 65536 && f2.denominator < 65536) { - f0 = f1; - f1 = f2; - - /* Stop when f2 exactly equals timeperframe */ - if (s.numerator == 0) - break; - - i = s.denominator / s.numerator; - - f2.numerator = f0.numerator + i * f1.numerator; - f2.denominator = f0.denominator + i * f2.denominator; - - s_denominator = s.numerator; - s.numerator = s.denominator % s.numerator; - s.denominator = s_denominator; - } - - *timeperframe = f1; -} - -static uint32_t coda_timeperframe_to_frate(struct v4l2_fract *timeperframe) -{ - return ((timeperframe->numerator - 1) << CODA_FRATE_DIV_OFFSET) | - timeperframe->denominator; -} - -static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - struct v4l2_fract *tpf; - - if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; - tpf = &a->parm.output.timeperframe; - coda_approximate_timeperframe(tpf); - ctx->params.framerate = coda_timeperframe_to_frate(tpf); - ctx->params.framerate_changed = true; - - return 0; -} - -static int coda_subscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - - switch (sub->type) { - case V4L2_EVENT_EOS: - return v4l2_event_subscribe(fh, sub, 0, NULL); - case V4L2_EVENT_SOURCE_CHANGE: - if (ctx->inst_type == CODA_INST_DECODER) - return v4l2_event_subscribe(fh, sub, 0, NULL); - else - return -EINVAL; - default: - return v4l2_ctrl_subscribe_event(fh, sub); - } -} - -static const struct v4l2_ioctl_ops coda_ioctl_ops = { - .vidioc_querycap = coda_querycap, - - .vidioc_enum_fmt_vid_cap = coda_enum_fmt, - .vidioc_g_fmt_vid_cap = coda_g_fmt, - .vidioc_try_fmt_vid_cap = coda_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = coda_s_fmt_vid_cap, - - .vidioc_enum_fmt_vid_out = coda_enum_fmt, - .vidioc_g_fmt_vid_out = coda_g_fmt, - .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out, - .vidioc_s_fmt_vid_out = coda_s_fmt_vid_out, - - .vidioc_reqbufs = coda_reqbufs, - .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, - - .vidioc_qbuf = coda_qbuf, - .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - .vidioc_dqbuf = coda_dqbuf, - .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, - .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, - - .vidioc_streamon = v4l2_m2m_ioctl_streamon, - .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, - - .vidioc_g_selection = coda_g_selection, - .vidioc_s_selection = coda_s_selection, - - .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, - .vidioc_encoder_cmd = coda_encoder_cmd, - .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, - .vidioc_decoder_cmd = coda_decoder_cmd, - - .vidioc_g_parm = coda_g_parm, - .vidioc_s_parm = coda_s_parm, - - .vidioc_enum_framesizes = coda_enum_framesizes, - .vidioc_enum_frameintervals = coda_enum_frameintervals, - - .vidioc_subscribe_event = coda_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -/* - * Mem-to-mem operations. - */ - -static void coda_device_run(void *m2m_priv) -{ - struct coda_ctx *ctx = m2m_priv; - struct coda_dev *dev = ctx->dev; - - queue_work(dev->workqueue, &ctx->pic_run_work); -} - -static void coda_pic_run_work(struct work_struct *work) -{ - struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work); - struct coda_dev *dev = ctx->dev; - int ret; - - mutex_lock(&ctx->buffer_mutex); - mutex_lock(&dev->coda_mutex); - - ret = ctx->ops->prepare_run(ctx); - if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) - goto out; - - if (!wait_for_completion_timeout(&ctx->completion, - msecs_to_jiffies(1000))) { - if (ctx->use_bit) { - dev_err(dev->dev, "CODA PIC_RUN timeout\n"); - - ctx->hold = true; - - coda_hw_reset(ctx); - } - - if (ctx->ops->run_timeout) - ctx->ops->run_timeout(ctx); - } else { - ctx->ops->finish_run(ctx); - } - - if ((ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) && - ctx->ops->seq_end_work) - queue_work(dev->workqueue, &ctx->seq_end_work); - -out: - mutex_unlock(&dev->coda_mutex); - mutex_unlock(&ctx->buffer_mutex); - - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); -} - -static int coda_job_ready(void *m2m_priv) -{ - struct coda_ctx *ctx = m2m_priv; - int src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx); - - /* - * For both 'P' and 'key' frame cases 1 picture - * and 1 frame are needed. In the decoder case, - * the compressed frame can be in the bitstream. - */ - if (!src_bufs && ctx->inst_type != CODA_INST_DECODER) { - coda_dbg(1, ctx, "not ready: not enough vid-out buffers.\n"); - return 0; - } - - if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) { - coda_dbg(1, ctx, "not ready: not enough vid-cap buffers.\n"); - return 0; - } - - if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { - bool stream_end = ctx->bit_stream_param & - CODA_BIT_STREAM_END_FLAG; - int num_metas = ctx->num_metas; - struct coda_buffer_meta *meta; - unsigned int count; - - count = hweight32(ctx->frm_dis_flg); - if (ctx->use_vdoa && count >= (ctx->num_internal_frames - 1)) { - coda_dbg(1, ctx, - "not ready: all internal buffers in use: %d/%d (0x%x)", - count, ctx->num_internal_frames, - ctx->frm_dis_flg); - return 0; - } - - if (ctx->hold && !src_bufs) { - coda_dbg(1, ctx, - "not ready: on hold for more buffers.\n"); - return 0; - } - - if (!stream_end && (num_metas + src_bufs) < 2) { - coda_dbg(1, ctx, - "not ready: need 2 buffers available (queue:%d + bitstream:%d)\n", - num_metas, src_bufs); - return 0; - } - - meta = list_first_entry(&ctx->buffer_meta_list, - struct coda_buffer_meta, list); - if (!coda_bitstream_can_fetch_past(ctx, meta->end) && - !stream_end) { - coda_dbg(1, ctx, - "not ready: not enough bitstream data to read past %u (%u)\n", - meta->end, ctx->bitstream_fifo.kfifo.in); - return 0; - } - } - - if (ctx->aborting) { - coda_dbg(1, ctx, "not ready: aborting\n"); - return 0; - } - - coda_dbg(2, ctx, "job ready\n"); - - return 1; -} - -static void coda_job_abort(void *priv) -{ - struct coda_ctx *ctx = priv; - - ctx->aborting = 1; - - coda_dbg(1, ctx, "job abort\n"); -} - -static const struct v4l2_m2m_ops coda_m2m_ops = { - .device_run = coda_device_run, - .job_ready = coda_job_ready, - .job_abort = coda_job_abort, -}; - -static void set_default_params(struct coda_ctx *ctx) -{ - unsigned int max_w, max_h, usize, csize; - - ctx->codec = coda_find_codec(ctx->dev, ctx->cvd->src_formats[0], - ctx->cvd->dst_formats[0]); - max_w = min(ctx->codec->max_w, 1920U); - max_h = min(ctx->codec->max_h, 1088U); - usize = max_w * max_h * 3 / 2; - csize = coda_estimate_sizeimage(ctx, usize, max_w, max_h); - - ctx->params.codec_mode = ctx->codec->mode; - if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_JPEG || - ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG) { - ctx->colorspace = V4L2_COLORSPACE_SRGB; - ctx->xfer_func = V4L2_XFER_FUNC_SRGB; - ctx->ycbcr_enc = V4L2_YCBCR_ENC_601; - ctx->quantization = V4L2_QUANTIZATION_FULL_RANGE; - } else { - ctx->colorspace = V4L2_COLORSPACE_REC709; - ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; - ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - ctx->quantization = V4L2_QUANTIZATION_DEFAULT; - } - ctx->params.framerate = 30; - - /* Default formats for output and input queues */ - ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->cvd->src_formats[0]; - ctx->q_data[V4L2_M2M_DST].fourcc = ctx->cvd->dst_formats[0]; - ctx->q_data[V4L2_M2M_SRC].width = max_w; - ctx->q_data[V4L2_M2M_SRC].height = max_h; - ctx->q_data[V4L2_M2M_DST].width = max_w; - ctx->q_data[V4L2_M2M_DST].height = max_h; - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) { - ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w; - ctx->q_data[V4L2_M2M_SRC].sizeimage = usize; - ctx->q_data[V4L2_M2M_DST].bytesperline = 0; - ctx->q_data[V4L2_M2M_DST].sizeimage = csize; - } else { - ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; - ctx->q_data[V4L2_M2M_SRC].sizeimage = csize; - ctx->q_data[V4L2_M2M_DST].bytesperline = max_w; - ctx->q_data[V4L2_M2M_DST].sizeimage = usize; - } - ctx->q_data[V4L2_M2M_SRC].rect.width = max_w; - ctx->q_data[V4L2_M2M_SRC].rect.height = max_h; - ctx->q_data[V4L2_M2M_DST].rect.width = max_w; - ctx->q_data[V4L2_M2M_DST].rect.height = max_h; - - /* - * Since the RBC2AXI logic only supports a single chroma plane, - * macroblock tiling only works for to NV12 pixel format. - */ - ctx->tiled_map_type = GDI_LINEAR_FRAME_MAP; -} - -/* - * Queue operations - */ -static int coda_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], struct device *alloc_devs[]) -{ - struct coda_ctx *ctx = vb2_get_drv_priv(vq); - struct coda_q_data *q_data; - unsigned int size; - - q_data = get_q_data(ctx, vq->type); - size = q_data->sizeimage; - - if (*nplanes) - return sizes[0] < size ? -EINVAL : 0; - - *nplanes = 1; - sizes[0] = size; - - coda_dbg(1, ctx, "get %d buffer(s) of size %d each.\n", *nbuffers, - size); - - return 0; -} - -static int coda_buf_prepare(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct coda_q_data *q_data; - - q_data = get_q_data(ctx, vb->vb2_queue->type); - if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { - if (vbuf->field == V4L2_FIELD_ANY) - vbuf->field = V4L2_FIELD_NONE; - if (vbuf->field != V4L2_FIELD_NONE) { - v4l2_warn(&ctx->dev->v4l2_dev, - "%s field isn't supported\n", __func__); - return -EINVAL; - } - } - - if (vb2_plane_size(vb, 0) < q_data->sizeimage) { - v4l2_warn(&ctx->dev->v4l2_dev, - "%s data will not fit into plane (%lu < %lu)\n", - __func__, vb2_plane_size(vb, 0), - (long)q_data->sizeimage); - return -EINVAL; - } - - return 0; -} - -static void coda_update_menu_ctrl(struct v4l2_ctrl *ctrl, int value) -{ - if (!ctrl) - return; - - v4l2_ctrl_lock(ctrl); - - /* - * Extend the control range if the parsed stream contains a known but - * unsupported value or level. - */ - if (value > ctrl->maximum) { - __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, value, - ctrl->menu_skip_mask & ~(1 << value), - ctrl->default_value); - } else if (value < ctrl->minimum) { - __v4l2_ctrl_modify_range(ctrl, value, ctrl->maximum, - ctrl->menu_skip_mask & ~(1 << value), - ctrl->default_value); - } - - __v4l2_ctrl_s_ctrl(ctrl, value); - - v4l2_ctrl_unlock(ctrl); -} - -void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, - u8 level_idc) -{ - const char * const *profile_names; - const char * const *level_names; - struct v4l2_ctrl *profile_ctrl; - struct v4l2_ctrl *level_ctrl; - const char *codec_name; - u32 profile_cid; - u32 level_cid; - int profile; - int level; - - switch (ctx->codec->src_fourcc) { - case V4L2_PIX_FMT_H264: - codec_name = "H264"; - profile_cid = V4L2_CID_MPEG_VIDEO_H264_PROFILE; - level_cid = V4L2_CID_MPEG_VIDEO_H264_LEVEL; - profile_ctrl = ctx->h264_profile_ctrl; - level_ctrl = ctx->h264_level_ctrl; - profile = coda_h264_profile(profile_idc); - level = coda_h264_level(level_idc); - break; - case V4L2_PIX_FMT_MPEG2: - codec_name = "MPEG-2"; - profile_cid = V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE; - level_cid = V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL; - profile_ctrl = ctx->mpeg2_profile_ctrl; - level_ctrl = ctx->mpeg2_level_ctrl; - profile = coda_mpeg2_profile(profile_idc); - level = coda_mpeg2_level(level_idc); - break; - case V4L2_PIX_FMT_MPEG4: - codec_name = "MPEG-4"; - profile_cid = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE; - level_cid = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL; - profile_ctrl = ctx->mpeg4_profile_ctrl; - level_ctrl = ctx->mpeg4_level_ctrl; - profile = coda_mpeg4_profile(profile_idc); - level = coda_mpeg4_level(level_idc); - break; - default: - return; - } - - profile_names = v4l2_ctrl_get_menu(profile_cid); - level_names = v4l2_ctrl_get_menu(level_cid); - - if (profile < 0) { - v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s profile: %u\n", - codec_name, profile_idc); - } else { - coda_dbg(1, ctx, "Parsed %s profile: %s\n", codec_name, - profile_names[profile]); - coda_update_menu_ctrl(profile_ctrl, profile); - } - - if (level < 0) { - v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s level: %u\n", - codec_name, level_idc); - } else { - coda_dbg(1, ctx, "Parsed %s level: %s\n", codec_name, - level_names[level]); - coda_update_menu_ctrl(level_ctrl, level); - } -} - -static void coda_queue_source_change_event(struct coda_ctx *ctx) -{ - static const struct v4l2_event source_change_event = { - .type = V4L2_EVENT_SOURCE_CHANGE, - .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, - }; - - v4l2_event_queue_fh(&ctx->fh, &source_change_event); -} - -static void coda_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_queue *vq = vb->vb2_queue; - struct coda_q_data *q_data; - - q_data = get_q_data(ctx, vb->vb2_queue->type); - - /* - * In the decoder case, immediately try to copy the buffer into the - * bitstream ringbuffer and mark it as ready to be dequeued. - */ - if (ctx->bitstream.size && vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - /* - * For backwards compatibility, queuing an empty buffer marks - * the stream end - */ - if (vb2_get_plane_payload(vb, 0) == 0) - coda_bit_stream_end_flag(ctx); - - if (q_data->fourcc == V4L2_PIX_FMT_H264) { - /* - * Unless already done, try to obtain profile_idc and - * level_idc from the SPS header. This allows to decide - * whether to enable reordering during sequence - * initialization. - */ - if (!ctx->params.h264_profile_idc) { - coda_sps_parse_profile(ctx, vb); - coda_update_profile_level_ctrls(ctx, - ctx->params.h264_profile_idc, - ctx->params.h264_level_idc); - } - } - - mutex_lock(&ctx->bitstream_mutex); - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); - if (vb2_is_streaming(vb->vb2_queue)) - /* This set buf->sequence = ctx->qsequence++ */ - coda_fill_bitstream(ctx, NULL); - mutex_unlock(&ctx->bitstream_mutex); - - if (!ctx->initialized) { - /* - * Run sequence initialization in case the queued - * buffer contained headers. - */ - if (vb2_is_streaming(vb->vb2_queue) && - ctx->ops->seq_init_work) { - queue_work(ctx->dev->workqueue, - &ctx->seq_init_work); - flush_work(&ctx->seq_init_work); - } - - if (ctx->initialized) - coda_queue_source_change_event(ctx); - } - } else { - if ((ctx->inst_type == CODA_INST_ENCODER || !ctx->use_bit) && - vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - vbuf->sequence = ctx->qsequence++; - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); - } -} - -int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, - size_t size, const char *name, struct dentry *parent) -{ - buf->vaddr = dma_alloc_coherent(dev->dev, size, &buf->paddr, - GFP_KERNEL); - if (!buf->vaddr) { - v4l2_err(&dev->v4l2_dev, - "Failed to allocate %s buffer of size %zu\n", - name, size); - return -ENOMEM; - } - - buf->size = size; - - if (name && parent) { - buf->blob.data = buf->vaddr; - buf->blob.size = size; - buf->dentry = debugfs_create_blob(name, 0444, parent, - &buf->blob); - } - - return 0; -} - -void coda_free_aux_buf(struct coda_dev *dev, - struct coda_aux_buf *buf) -{ - if (buf->vaddr) { - dma_free_coherent(dev->dev, buf->size, buf->vaddr, buf->paddr); - buf->vaddr = NULL; - buf->size = 0; - debugfs_remove(buf->dentry); - buf->dentry = NULL; - } -} - -static int coda_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct coda_ctx *ctx = vb2_get_drv_priv(q); - struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; - struct coda_q_data *q_data_src, *q_data_dst; - struct v4l2_m2m_buffer *m2m_buf, *tmp; - struct vb2_v4l2_buffer *buf; - struct list_head list; - int ret = 0; - - if (count < 1) - return -EINVAL; - - coda_dbg(1, ctx, "start streaming %s\n", v4l2_type_names[q->type]); - - INIT_LIST_HEAD(&list); - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { - /* copy the buffers that were queued before streamon */ - mutex_lock(&ctx->bitstream_mutex); - coda_fill_bitstream(ctx, &list); - mutex_unlock(&ctx->bitstream_mutex); - - if (ctx->dev->devtype->product != CODA_960 && - coda_get_bitstream_payload(ctx) < 512) { - v4l2_err(v4l2_dev, "start payload < 512\n"); - ret = -EINVAL; - goto err; - } - - if (!ctx->initialized) { - /* Run sequence initialization */ - if (ctx->ops->seq_init_work) { - queue_work(ctx->dev->workqueue, - &ctx->seq_init_work); - flush_work(&ctx->seq_init_work); - } - } - } - - /* - * Check the first input JPEG buffer to determine chroma - * subsampling. - */ - if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) { - buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - coda_jpeg_decode_header(ctx, &buf->vb2_buf); - /* - * We have to start streaming even if the first buffer - * does not contain a valid JPEG image. The error will - * be caught during device run and will be signalled - * via the capture buffer error flag. - */ - - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - q_data_dst->width = round_up(q_data_src->width, 16); - q_data_dst->height = round_up(q_data_src->height, 16); - q_data_dst->bytesperline = q_data_dst->width; - if (ctx->params.jpeg_chroma_subsampling == - V4L2_JPEG_CHROMA_SUBSAMPLING_420) { - q_data_dst->sizeimage = - q_data_dst->bytesperline * - q_data_dst->height * 3 / 2; - if (q_data_dst->fourcc != V4L2_PIX_FMT_YUV420) - q_data_dst->fourcc = V4L2_PIX_FMT_NV12; - } else { - q_data_dst->sizeimage = - q_data_dst->bytesperline * - q_data_dst->height * 2; - q_data_dst->fourcc = V4L2_PIX_FMT_YUV422P; - } - q_data_dst->rect.left = 0; - q_data_dst->rect.top = 0; - q_data_dst->rect.width = q_data_src->width; - q_data_dst->rect.height = q_data_src->height; - } - ctx->streamon_out = 1; - } else { - ctx->streamon_cap = 1; - } - - /* Don't start the coda unless both queues are on */ - if (!(ctx->streamon_out && ctx->streamon_cap)) - goto out; - - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - if ((q_data_src->rect.width != q_data_dst->width && - round_up(q_data_src->rect.width, 16) != q_data_dst->width) || - (q_data_src->rect.height != q_data_dst->height && - round_up(q_data_src->rect.height, 16) != q_data_dst->height)) { - v4l2_err(v4l2_dev, "can't convert %dx%d to %dx%d\n", - q_data_src->rect.width, q_data_src->rect.height, - q_data_dst->width, q_data_dst->height); - ret = -EINVAL; - goto err; - } - - /* Allow BIT decoder device_run with no new buffers queued */ - if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) - v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); - - ctx->gopcounter = ctx->params.gop_size - 1; - - if (q_data_dst->fourcc == V4L2_PIX_FMT_JPEG) - ctx->params.gop_size = 1; - ctx->gopcounter = ctx->params.gop_size - 1; - /* Only decoders have this control */ - if (ctx->mb_err_cnt_ctrl) - v4l2_ctrl_s_ctrl(ctx->mb_err_cnt_ctrl, 0); - - ret = ctx->ops->start_streaming(ctx); - if (ctx->inst_type == CODA_INST_DECODER) { - if (ret == -EAGAIN) - goto out; - } - if (ret < 0) - goto err; - -out: - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - list_for_each_entry_safe(m2m_buf, tmp, &list, list) { - list_del(&m2m_buf->list); - v4l2_m2m_buf_done(&m2m_buf->vb, VB2_BUF_STATE_DONE); - } - } - return 0; - -err: - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - list_for_each_entry_safe(m2m_buf, tmp, &list, list) { - list_del(&m2m_buf->list); - v4l2_m2m_buf_done(&m2m_buf->vb, VB2_BUF_STATE_QUEUED); - } - while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) - v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); - } else { - while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) - v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); - } - return ret; -} - -static void coda_stop_streaming(struct vb2_queue *q) -{ - struct coda_ctx *ctx = vb2_get_drv_priv(q); - struct coda_dev *dev = ctx->dev; - struct vb2_v4l2_buffer *buf; - bool stop; - - stop = ctx->streamon_out && ctx->streamon_cap; - - coda_dbg(1, ctx, "stop streaming %s\n", v4l2_type_names[q->type]); - - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - ctx->streamon_out = 0; - - coda_bit_stream_end_flag(ctx); - - ctx->qsequence = 0; - - while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) - v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); - } else { - ctx->streamon_cap = 0; - - ctx->osequence = 0; - ctx->sequence_offset = 0; - - while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) - v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); - } - - if (stop) { - struct coda_buffer_meta *meta; - - if (ctx->ops->seq_end_work) { - queue_work(dev->workqueue, &ctx->seq_end_work); - flush_work(&ctx->seq_end_work); - } - spin_lock(&ctx->buffer_meta_lock); - while (!list_empty(&ctx->buffer_meta_list)) { - meta = list_first_entry(&ctx->buffer_meta_list, - struct coda_buffer_meta, list); - list_del(&meta->list); - kfree(meta); - } - ctx->num_metas = 0; - spin_unlock(&ctx->buffer_meta_lock); - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); - ctx->runcounter = 0; - ctx->aborting = 0; - ctx->hold = false; - } - - if (!ctx->streamon_out && !ctx->streamon_cap) - ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; -} - -static const struct vb2_ops coda_qops = { - .queue_setup = coda_queue_setup, - .buf_prepare = coda_buf_prepare, - .buf_queue = coda_buf_queue, - .start_streaming = coda_start_streaming, - .stop_streaming = coda_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -static int coda_s_ctrl(struct v4l2_ctrl *ctrl) -{ - const char * const *val_names = v4l2_ctrl_get_menu(ctrl->id); - struct coda_ctx *ctx = - container_of(ctrl->handler, struct coda_ctx, ctrls); - - if (val_names) - coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d (\"%s\")\n", - ctrl->id, ctrl->name, ctrl->val, val_names[ctrl->val]); - else - coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n", - ctrl->id, ctrl->name, ctrl->val); - - switch (ctrl->id) { - case V4L2_CID_HFLIP: - if (ctrl->val) - ctx->params.rot_mode |= CODA_MIR_HOR; - else - ctx->params.rot_mode &= ~CODA_MIR_HOR; - break; - case V4L2_CID_VFLIP: - if (ctrl->val) - ctx->params.rot_mode |= CODA_MIR_VER; - else - ctx->params.rot_mode &= ~CODA_MIR_VER; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - ctx->params.bitrate = ctrl->val / 1000; - ctx->params.bitrate_changed = true; - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - ctx->params.gop_size = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: - ctx->params.h264_intra_qp = ctrl->val; - ctx->params.h264_intra_qp_changed = true; - break; - case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: - ctx->params.h264_inter_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: - ctx->params.h264_min_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: - ctx->params.h264_max_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: - ctx->params.h264_slice_alpha_c0_offset_div2 = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: - ctx->params.h264_slice_beta_offset_div2 = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: - ctx->params.h264_disable_deblocking_filter_idc = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: - ctx->params.h264_constrained_intra_pred_flag = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: - ctx->params.frame_rc_enable = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: - ctx->params.mb_rc_enable = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: - ctx->params.h264_chroma_qp_index_offset = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_PROFILE: - /* TODO: switch between baseline and constrained baseline */ - if (ctx->inst_type == CODA_INST_ENCODER) - ctx->params.h264_profile_idc = 66; - break; - case V4L2_CID_MPEG_VIDEO_H264_LEVEL: - /* nothing to do, this is set by the encoder */ - break; - case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: - ctx->params.mpeg4_intra_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: - ctx->params.mpeg4_inter_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: - case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: - case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: - case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: - /* nothing to do, these are fixed */ - break; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: - ctx->params.slice_mode = ctrl->val; - ctx->params.slice_mode_changed = true; - break; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: - ctx->params.slice_max_mb = ctrl->val; - ctx->params.slice_mode_changed = true; - break; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: - ctx->params.slice_max_bits = ctrl->val * 8; - ctx->params.slice_mode_changed = true; - break; - case V4L2_CID_MPEG_VIDEO_HEADER_MODE: - break; - case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: - ctx->params.intra_refresh = ctrl->val; - ctx->params.intra_refresh_changed = true; - break; - case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: - ctx->params.force_ipicture = true; - break; - case V4L2_CID_JPEG_COMPRESSION_QUALITY: - coda_set_jpeg_compression_quality(ctx, ctrl->val); - break; - case V4L2_CID_JPEG_RESTART_INTERVAL: - ctx->params.jpeg_restart_interval = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VBV_DELAY: - ctx->params.vbv_delay = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VBV_SIZE: - ctx->params.vbv_size = min(ctrl->val * 8192, 0x7fffffff); - break; - default: - coda_dbg(1, ctx, "Invalid control, id=%d, val=%d\n", - ctrl->id, ctrl->val); - return -EINVAL; - } - - return 0; -} - -static const struct v4l2_ctrl_ops coda_ctrl_ops = { - .s_ctrl = coda_s_ctrl, -}; - -static void coda_encode_ctrls(struct coda_ctx *ctx) -{ - int max_gop_size = (ctx->dev->devtype->product == CODA_DX6) ? 60 : 99; - - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1000, 0); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, max_gop_size, 1, 16); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25); - if (ctx->dev->devtype->product != CODA_960) { - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12); - } - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, -6, 6, 1, 0); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, -6, 6, 1, 0); - v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, - V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, - 0x0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION, 0, 1, 1, - 0); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, 0, 1, 1, 1); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, 0, 1, 1, 1); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0); - v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_PROFILE, - V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE, 0x0, - V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE); - if (ctx->dev->devtype->product == CODA_HX4 || - ctx->dev->devtype->product == CODA_7541) { - v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_LEVEL, - V4L2_MPEG_VIDEO_H264_LEVEL_3_1, - ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1)), - V4L2_MPEG_VIDEO_H264_LEVEL_3_1); - } - if (ctx->dev->devtype->product == CODA_960) { - v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_LEVEL, - V4L2_MPEG_VIDEO_H264_LEVEL_4_2, - ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2)), - V4L2_MPEG_VIDEO_H264_LEVEL_4_0); - } - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2); - v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, - V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, 0x0, - V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE); - if (ctx->dev->devtype->product == CODA_HX4 || - ctx->dev->devtype->product == CODA_7541 || - ctx->dev->devtype->product == CODA_960) { - v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, - V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, - ~(1 << V4L2_MPEG_VIDEO_MPEG4_LEVEL_5), - V4L2_MPEG_VIDEO_MPEG4_LEVEL_5); - } - v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, - V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, 0x0, - V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, - 500); - v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_HEADER_MODE, - V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, - (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE), - V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, - 1920 * 1088 / 256, 1, 0); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_VBV_DELAY, 0, 0x7fff, 1, 0); - /* - * The maximum VBV size value is 0x7fffffff bits, - * one bit less than 262144 KiB - */ - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_VBV_SIZE, 0, 262144, 1, 0); -} - -static void coda_jpeg_encode_ctrls(struct coda_ctx *ctx) -{ - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_JPEG_COMPRESSION_QUALITY, 5, 100, 1, 50); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_JPEG_RESTART_INTERVAL, 0, 100, 1, 0); -} - -static void coda_decode_ctrls(struct coda_ctx *ctx) -{ - u8 max; - - ctx->h264_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, - &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, - ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | - (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | - (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); - if (ctx->h264_profile_ctrl) - ctx->h264_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; - - if (ctx->dev->devtype->product == CODA_HX4 || - ctx->dev->devtype->product == CODA_7541) - max = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; - else if (ctx->dev->devtype->product == CODA_960) - max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1; - else - return; - ctx->h264_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, - &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, 0, max); - if (ctx->h264_level_ctrl) - ctx->h264_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; - - ctx->mpeg2_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, - &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE, - V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH, 0, - V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH); - if (ctx->mpeg2_profile_ctrl) - ctx->mpeg2_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; - - ctx->mpeg2_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, - &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL, - V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH, 0, - V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH); - if (ctx->mpeg2_level_ctrl) - ctx->mpeg2_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; - - ctx->mpeg4_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, - &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, - V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY, 0, - V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY); - if (ctx->mpeg4_profile_ctrl) - ctx->mpeg4_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; - - ctx->mpeg4_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, - &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, - V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, 0, - V4L2_MPEG_VIDEO_MPEG4_LEVEL_5); - if (ctx->mpeg4_level_ctrl) - ctx->mpeg4_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; -} - -static const struct v4l2_ctrl_config coda_mb_err_cnt_ctrl_config = { - .id = V4L2_CID_CODA_MB_ERR_CNT, - .name = "Macroblocks Error Count", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 0x7fffffff, - .step = 1, -}; - -static int coda_ctrls_setup(struct coda_ctx *ctx) -{ - v4l2_ctrl_handler_init(&ctx->ctrls, 2); - - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - if (ctx->inst_type == CODA_INST_ENCODER) { - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, - 1, 1, 1, 1); - if (ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG) - coda_jpeg_encode_ctrls(ctx); - else - coda_encode_ctrls(ctx); - } else { - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, - 1, 1, 1, 1); - if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_H264) - coda_decode_ctrls(ctx); - - ctx->mb_err_cnt_ctrl = v4l2_ctrl_new_custom(&ctx->ctrls, - &coda_mb_err_cnt_ctrl_config, - NULL); - if (ctx->mb_err_cnt_ctrl) - ctx->mb_err_cnt_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; - } - - if (ctx->ctrls.error) { - v4l2_err(&ctx->dev->v4l2_dev, - "control initialization error (%d)", - ctx->ctrls.error); - return -EINVAL; - } - - return v4l2_ctrl_handler_setup(&ctx->ctrls); -} - -static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) -{ - vq->drv_priv = ctx; - vq->ops = &coda_qops; - vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - vq->lock = &ctx->dev->dev_mutex; - /* One way to indicate end-of-stream for coda is to set the - * bytesused == 0. However by default videobuf2 handles bytesused - * equal to 0 as a special case and changes its value to the size - * of the buffer. Set the allow_zero_bytesused flag, so - * that videobuf2 will keep the value of bytesused intact. - */ - vq->allow_zero_bytesused = 1; - /* - * We might be fine with no buffers on some of the queues, but that - * would need to be reflected in job_ready(). Currently we expect all - * queues to have at least one buffer queued. - */ - vq->min_buffers_needed = 1; - vq->dev = ctx->dev->dev; - - return vb2_queue_init(vq); -} - -int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) -{ - int ret; - - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_DMABUF | VB2_MMAP; - src_vq->mem_ops = &vb2_dma_contig_memops; - - ret = coda_queue_init(priv, src_vq); - if (ret) - return ret; - - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; - dst_vq->mem_ops = &vb2_dma_contig_memops; - - return coda_queue_init(priv, dst_vq); -} - -int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) -{ - int ret; - - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; - src_vq->mem_ops = &vb2_vmalloc_memops; - - ret = coda_queue_init(priv, src_vq); - if (ret) - return ret; - - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; - dst_vq->dma_attrs = DMA_ATTR_NO_KERNEL_MAPPING; - dst_vq->mem_ops = &vb2_dma_contig_memops; - - return coda_queue_init(priv, dst_vq); -} - -/* - * File operations - */ - -static int coda_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct coda_dev *dev = video_get_drvdata(vdev); - struct coda_ctx *ctx; - unsigned int max = ~0; - char *name; - int ret; - int idx; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - if (dev->devtype->product == CODA_DX6) - max = CODADX6_MAX_INSTANCES - 1; - idx = ida_alloc_max(&dev->ida, max, GFP_KERNEL); - if (idx < 0) { - ret = idx; - goto err_coda_max; - } - - name = kasprintf(GFP_KERNEL, "context%d", idx); - if (!name) { - ret = -ENOMEM; - goto err_coda_name_init; - } - - ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); - kfree(name); - - ctx->cvd = to_coda_video_device(vdev); - ctx->inst_type = ctx->cvd->type; - ctx->ops = ctx->cvd->ops; - ctx->use_bit = !ctx->cvd->direct; - init_completion(&ctx->completion); - INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); - if (ctx->ops->seq_init_work) - INIT_WORK(&ctx->seq_init_work, ctx->ops->seq_init_work); - if (ctx->ops->seq_end_work) - INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); - v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); - ctx->dev = dev; - ctx->idx = idx; - - coda_dbg(1, ctx, "open instance (%p)\n", ctx); - - switch (dev->devtype->product) { - case CODA_960: - /* - * Enabling the BWB when decoding can hang the firmware with - * certain streams. The issue was tracked as ENGR00293425 by - * Freescale. As a workaround, disable BWB for all decoders. - * The enable_bwb module parameter allows to override this. - */ - if (enable_bwb || ctx->inst_type == CODA_INST_ENCODER) - ctx->frame_mem_ctrl = CODA9_FRAME_ENABLE_BWB; - fallthrough; - case CODA_HX4: - case CODA_7541: - ctx->reg_idx = 0; - break; - default: - ctx->reg_idx = idx; - } - if (ctx->dev->vdoa && !disable_vdoa) { - ctx->vdoa = vdoa_context_create(dev->vdoa); - if (!ctx->vdoa) - v4l2_warn(&dev->v4l2_dev, - "Failed to create vdoa context: not using vdoa"); - } - ctx->use_vdoa = false; - - /* Power up and upload firmware if necessary */ - ret = pm_runtime_resume_and_get(dev->dev); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret); - goto err_pm_get; - } - - ret = clk_prepare_enable(dev->clk_per); - if (ret) - goto err_clk_enable; - - ret = clk_prepare_enable(dev->clk_ahb); - if (ret) - goto err_clk_ahb; - - set_default_params(ctx); - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, - ctx->ops->queue_init); - if (IS_ERR(ctx->fh.m2m_ctx)) { - ret = PTR_ERR(ctx->fh.m2m_ctx); - - v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n", - __func__, ret); - goto err_ctx_init; - } - - ret = coda_ctrls_setup(ctx); - if (ret) { - v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n"); - goto err_ctrls_setup; - } - - ctx->fh.ctrl_handler = &ctx->ctrls; - - mutex_init(&ctx->bitstream_mutex); - mutex_init(&ctx->buffer_mutex); - mutex_init(&ctx->wakeup_mutex); - INIT_LIST_HEAD(&ctx->buffer_meta_list); - spin_lock_init(&ctx->buffer_meta_lock); - - return 0; - -err_ctrls_setup: - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); -err_ctx_init: - clk_disable_unprepare(dev->clk_ahb); -err_clk_ahb: - clk_disable_unprepare(dev->clk_per); -err_clk_enable: - pm_runtime_put_sync(dev->dev); -err_pm_get: - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); -err_coda_name_init: - ida_free(&dev->ida, ctx->idx); -err_coda_max: - kfree(ctx); - return ret; -} - -static int coda_release(struct file *file) -{ - struct coda_dev *dev = video_drvdata(file); - struct coda_ctx *ctx = fh_to_ctx(file->private_data); - - coda_dbg(1, ctx, "release instance (%p)\n", ctx); - - if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) - coda_bit_stream_end_flag(ctx); - - /* If this instance is running, call .job_abort and wait for it to end */ - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - - if (ctx->vdoa) - vdoa_context_destroy(ctx->vdoa); - - /* In case the instance was not running, we still need to call SEQ_END */ - if (ctx->ops->seq_end_work) { - queue_work(dev->workqueue, &ctx->seq_end_work); - flush_work(&ctx->seq_end_work); - } - - if (ctx->dev->devtype->product == CODA_DX6) - coda_free_aux_buf(dev, &ctx->workbuf); - - v4l2_ctrl_handler_free(&ctx->ctrls); - clk_disable_unprepare(dev->clk_ahb); - clk_disable_unprepare(dev->clk_per); - pm_runtime_put_sync(dev->dev); - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - ida_free(&dev->ida, ctx->idx); - if (ctx->ops->release) - ctx->ops->release(ctx); - debugfs_remove_recursive(ctx->debugfs_entry); - kfree(ctx); - - return 0; -} - -static const struct v4l2_file_operations coda_fops = { - .owner = THIS_MODULE, - .open = coda_open, - .release = coda_release, - .poll = v4l2_m2m_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = v4l2_m2m_fop_mmap, -}; - -static int coda_hw_init(struct coda_dev *dev) -{ - u32 data; - u16 *p; - int i, ret; - - ret = clk_prepare_enable(dev->clk_per); - if (ret) - goto err_clk_per; - - ret = clk_prepare_enable(dev->clk_ahb); - if (ret) - goto err_clk_ahb; - - reset_control_reset(dev->rstc); - - /* - * Copy the first CODA_ISRAM_SIZE in the internal SRAM. - * The 16-bit chars in the code buffer are in memory access - * order, re-sort them to CODA order for register download. - * Data in this SRAM survives a reboot. - */ - p = (u16 *)dev->codebuf.vaddr; - if (dev->devtype->product == CODA_DX6) { - for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) { - data = CODA_DOWN_ADDRESS_SET(i) | - CODA_DOWN_DATA_SET(p[i ^ 1]); - coda_write(dev, data, CODA_REG_BIT_CODE_DOWN); - } - } else { - for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) { - data = CODA_DOWN_ADDRESS_SET(i) | - CODA_DOWN_DATA_SET(p[round_down(i, 4) + - 3 - (i % 4)]); - coda_write(dev, data, CODA_REG_BIT_CODE_DOWN); - } - } - - /* Clear registers */ - for (i = 0; i < 64; i++) - coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4); - - /* Tell the BIT where to find everything it needs */ - if (dev->devtype->product == CODA_960 || - dev->devtype->product == CODA_7541 || - dev->devtype->product == CODA_HX4) { - coda_write(dev, dev->tempbuf.paddr, - CODA_REG_BIT_TEMP_BUF_ADDR); - coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); - } else { - coda_write(dev, dev->workbuf.paddr, - CODA_REG_BIT_WORK_BUF_ADDR); - } - coda_write(dev, dev->codebuf.paddr, - CODA_REG_BIT_CODE_BUF_ADDR); - coda_write(dev, 0, CODA_REG_BIT_CODE_RUN); - - /* Set default values */ - switch (dev->devtype->product) { - case CODA_DX6: - coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, - CODA_REG_BIT_STREAM_CTRL); - break; - default: - coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, - CODA_REG_BIT_STREAM_CTRL); - } - if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_FRAME_ENABLE_BWB, - CODA_REG_BIT_FRAME_MEM_CTRL); - else - coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL); - - if (dev->devtype->product != CODA_DX6) - coda_write(dev, 0, CODA7_REG_BIT_AXI_SRAM_USE); - - coda_write(dev, CODA_INT_INTERRUPT_ENABLE, - CODA_REG_BIT_INT_ENABLE); - - /* Reset VPU and start processor */ - data = coda_read(dev, CODA_REG_BIT_CODE_RESET); - data |= CODA_REG_RESET_ENABLE; - coda_write(dev, data, CODA_REG_BIT_CODE_RESET); - udelay(10); - data &= ~CODA_REG_RESET_ENABLE; - coda_write(dev, data, CODA_REG_BIT_CODE_RESET); - coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); - - clk_disable_unprepare(dev->clk_ahb); - clk_disable_unprepare(dev->clk_per); - - return 0; - -err_clk_ahb: - clk_disable_unprepare(dev->clk_per); -err_clk_per: - return ret; -} - -static int coda_register_device(struct coda_dev *dev, int i) -{ - struct video_device *vfd = &dev->vfd[i]; - const char *name; - int ret; - - if (i >= dev->devtype->num_vdevs) - return -EINVAL; - name = dev->devtype->vdevs[i]->name; - - strscpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name)); - vfd->fops = &coda_fops; - vfd->ioctl_ops = &coda_ioctl_ops; - vfd->release = video_device_release_empty; - vfd->lock = &dev->dev_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->vfl_dir = VFL_DIR_M2M; - vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; - video_set_drvdata(vfd, dev); - - /* Not applicable, use the selection API instead */ - v4l2_disable_ioctl(vfd, VIDIOC_CROPCAP); - v4l2_disable_ioctl(vfd, VIDIOC_G_CROP); - v4l2_disable_ioctl(vfd, VIDIOC_S_CROP); - - if (dev->devtype->vdevs[i]->type == CODA_INST_ENCODER) { - v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); - if (dev->devtype->vdevs[i]->dst_formats[0] == V4L2_PIX_FMT_JPEG) { - v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMEINTERVALS); - v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); - v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); - } - } else { - v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMESIZES); - v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMEINTERVALS); - v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); - v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); - } - - ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); - if (!ret) - v4l2_info(&dev->v4l2_dev, "%s registered as %s\n", - name, video_device_node_name(vfd)); - return ret; -} - -static void coda_copy_firmware(struct coda_dev *dev, const u8 * const buf, - size_t size) -{ - u32 *src = (u32 *)buf; - - /* Check if the firmware has a 16-byte Freescale header, skip it */ - if (buf[0] == 'M' && buf[1] == 'X') - src += 4; - /* - * Check whether the firmware is in native order or pre-reordered for - * memory access. The first instruction opcode always is 0xe40e. - */ - if (__le16_to_cpup((__le16 *)src) == 0xe40e) { - u32 *dst = dev->codebuf.vaddr; - int i; - - /* Firmware in native order, reorder while copying */ - if (dev->devtype->product == CODA_DX6) { - for (i = 0; i < (size - 16) / 4; i++) - dst[i] = (src[i] << 16) | (src[i] >> 16); - } else { - for (i = 0; i < (size - 16) / 4; i += 2) { - dst[i] = (src[i + 1] << 16) | (src[i + 1] >> 16); - dst[i + 1] = (src[i] << 16) | (src[i] >> 16); - } - } - } else { - /* Copy the already reordered firmware image */ - memcpy(dev->codebuf.vaddr, src, size); - } -} - -static void coda_fw_callback(const struct firmware *fw, void *context); - -static int coda_firmware_request(struct coda_dev *dev) -{ - char *fw; - - if (dev->firmware >= ARRAY_SIZE(dev->devtype->firmware)) - return -EINVAL; - - fw = dev->devtype->firmware[dev->firmware]; - - dev_dbg(dev->dev, "requesting firmware '%s' for %s\n", fw, - coda_product_name(dev->devtype->product)); - - return request_firmware_nowait(THIS_MODULE, true, fw, dev->dev, - GFP_KERNEL, dev, coda_fw_callback); -} - -static void coda_fw_callback(const struct firmware *fw, void *context) -{ - struct coda_dev *dev = context; - int i, ret; - - if (!fw) { - dev->firmware++; - ret = coda_firmware_request(dev); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "firmware request failed\n"); - goto put_pm; - } - return; - } - if (dev->firmware > 0) { - /* - * Since we can't suppress warnings for failed asynchronous - * firmware requests, report that the fallback firmware was - * found. - */ - dev_info(dev->dev, "Using fallback firmware %s\n", - dev->devtype->firmware[dev->firmware]); - } - - /* allocate auxiliary per-device code buffer for the BIT processor */ - ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf", - dev->debugfs_root); - if (ret < 0) - goto put_pm; - - coda_copy_firmware(dev, fw->data, fw->size); - release_firmware(fw); - - ret = coda_hw_init(dev); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "HW initialization failed\n"); - goto put_pm; - } - - ret = coda_check_firmware(dev); - if (ret < 0) - goto put_pm; - - dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops); - if (IS_ERR(dev->m2m_dev)) { - v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); - goto put_pm; - } - - for (i = 0; i < dev->devtype->num_vdevs; i++) { - ret = coda_register_device(dev, i); - if (ret) { - v4l2_err(&dev->v4l2_dev, - "Failed to register %s video device: %d\n", - dev->devtype->vdevs[i]->name, ret); - goto rel_vfd; - } - } - - pm_runtime_put_sync(dev->dev); - return; - -rel_vfd: - while (--i >= 0) - video_unregister_device(&dev->vfd[i]); - v4l2_m2m_release(dev->m2m_dev); -put_pm: - pm_runtime_put_sync(dev->dev); -} - -enum coda_platform { - CODA_IMX27, - CODA_IMX51, - CODA_IMX53, - CODA_IMX6Q, - CODA_IMX6DL, -}; - -static const struct coda_devtype coda_devdata[] = { - [CODA_IMX27] = { - .firmware = { - "vpu_fw_imx27_TO2.bin", - "vpu/vpu_fw_imx27_TO2.bin", - "v4l-codadx6-imx27.bin" - }, - .product = CODA_DX6, - .codecs = codadx6_codecs, - .num_codecs = ARRAY_SIZE(codadx6_codecs), - .vdevs = codadx6_video_devices, - .num_vdevs = ARRAY_SIZE(codadx6_video_devices), - .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024, - .iram_size = 0xb000, - }, - [CODA_IMX51] = { - .firmware = { - "vpu_fw_imx51.bin", - "vpu/vpu_fw_imx51.bin", - "v4l-codahx4-imx51.bin" - }, - .product = CODA_HX4, - .codecs = codahx4_codecs, - .num_codecs = ARRAY_SIZE(codahx4_codecs), - .vdevs = codahx4_video_devices, - .num_vdevs = ARRAY_SIZE(codahx4_video_devices), - .workbuf_size = 128 * 1024, - .tempbuf_size = 304 * 1024, - .iram_size = 0x14000, - }, - [CODA_IMX53] = { - .firmware = { - "vpu_fw_imx53.bin", - "vpu/vpu_fw_imx53.bin", - "v4l-coda7541-imx53.bin" - }, - .product = CODA_7541, - .codecs = coda7_codecs, - .num_codecs = ARRAY_SIZE(coda7_codecs), - .vdevs = coda7_video_devices, - .num_vdevs = ARRAY_SIZE(coda7_video_devices), - .workbuf_size = 128 * 1024, - .tempbuf_size = 304 * 1024, - .iram_size = 0x14000, - }, - [CODA_IMX6Q] = { - .firmware = { - "vpu_fw_imx6q.bin", - "vpu/vpu_fw_imx6q.bin", - "v4l-coda960-imx6q.bin" - }, - .product = CODA_960, - .codecs = coda9_codecs, - .num_codecs = ARRAY_SIZE(coda9_codecs), - .vdevs = coda9_video_devices, - .num_vdevs = ARRAY_SIZE(coda9_video_devices), - .workbuf_size = 80 * 1024, - .tempbuf_size = 204 * 1024, - .iram_size = 0x21000, - }, - [CODA_IMX6DL] = { - .firmware = { - "vpu_fw_imx6d.bin", - "vpu/vpu_fw_imx6d.bin", - "v4l-coda960-imx6dl.bin" - }, - .product = CODA_960, - .codecs = coda9_codecs, - .num_codecs = ARRAY_SIZE(coda9_codecs), - .vdevs = coda9_video_devices, - .num_vdevs = ARRAY_SIZE(coda9_video_devices), - .workbuf_size = 80 * 1024, - .tempbuf_size = 204 * 1024, - .iram_size = 0x1f000, /* leave 4k for suspend code */ - }, -}; - -static const struct of_device_id coda_dt_ids[] = { - { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] }, - { .compatible = "fsl,imx51-vpu", .data = &coda_devdata[CODA_IMX51] }, - { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] }, - { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] }, - { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, coda_dt_ids); - -static int coda_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct gen_pool *pool; - struct coda_dev *dev; - int ret, irq; - - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - dev->devtype = of_device_get_match_data(&pdev->dev); - - dev->dev = &pdev->dev; - dev->clk_per = devm_clk_get(&pdev->dev, "per"); - if (IS_ERR(dev->clk_per)) { - dev_err(&pdev->dev, "Could not get per clock\n"); - return PTR_ERR(dev->clk_per); - } - - dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); - if (IS_ERR(dev->clk_ahb)) { - dev_err(&pdev->dev, "Could not get ahb clock\n"); - return PTR_ERR(dev->clk_ahb); - } - - /* Get memory for physical registers */ - dev->regs_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(dev->regs_base)) - return PTR_ERR(dev->regs_base); - - /* IRQ */ - irq = platform_get_irq_byname(pdev, "bit"); - if (irq < 0) - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - ret = devm_request_irq(&pdev->dev, irq, coda_irq_handler, 0, - CODA_NAME "-video", dev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to request irq: %d\n", ret); - return ret; - } - - /* JPEG IRQ */ - if (dev->devtype->product == CODA_960) { - irq = platform_get_irq_byname(pdev, "jpeg"); - if (irq < 0) - return irq; - - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, - coda9_jpeg_irq_handler, - IRQF_ONESHOT, CODA_NAME "-jpeg", - dev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to request jpeg irq\n"); - return ret; - } - } - - dev->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, - NULL); - if (IS_ERR(dev->rstc)) { - ret = PTR_ERR(dev->rstc); - dev_err(&pdev->dev, "failed get reset control: %d\n", ret); - return ret; - } - - /* Get IRAM pool from device tree */ - pool = of_gen_pool_get(np, "iram", 0); - if (!pool) { - dev_err(&pdev->dev, "iram pool not available\n"); - return -ENOMEM; - } - dev->iram_pool = pool; - - /* Get vdoa_data if supported by the platform */ - dev->vdoa = coda_get_vdoa_data(); - if (PTR_ERR(dev->vdoa) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); - if (ret) - return ret; - - ratelimit_default_init(&dev->mb_err_rs); - mutex_init(&dev->dev_mutex); - mutex_init(&dev->coda_mutex); - ida_init(&dev->ida); - - dev->debugfs_root = debugfs_create_dir("coda", NULL); - - /* allocate auxiliary per-device buffers for the BIT processor */ - if (dev->devtype->product == CODA_DX6) { - ret = coda_alloc_aux_buf(dev, &dev->workbuf, - dev->devtype->workbuf_size, "workbuf", - dev->debugfs_root); - if (ret < 0) - goto err_v4l2_register; - } - - if (dev->devtype->tempbuf_size) { - ret = coda_alloc_aux_buf(dev, &dev->tempbuf, - dev->devtype->tempbuf_size, "tempbuf", - dev->debugfs_root); - if (ret < 0) - goto err_v4l2_register; - } - - dev->iram.size = dev->devtype->iram_size; - dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size, - &dev->iram.paddr); - if (!dev->iram.vaddr) { - dev_warn(&pdev->dev, "unable to alloc iram\n"); - } else { - memset(dev->iram.vaddr, 0, dev->iram.size); - dev->iram.blob.data = dev->iram.vaddr; - dev->iram.blob.size = dev->iram.size; - dev->iram.dentry = debugfs_create_blob("iram", 0444, - dev->debugfs_root, - &dev->iram.blob); - } - - dev->workqueue = alloc_ordered_workqueue("coda", WQ_MEM_RECLAIM); - if (!dev->workqueue) { - dev_err(&pdev->dev, "unable to alloc workqueue\n"); - ret = -ENOMEM; - goto err_v4l2_register; - } - - platform_set_drvdata(pdev, dev); - - /* - * Start activated so we can directly call coda_hw_init in - * coda_fw_callback regardless of whether CONFIG_PM is - * enabled or whether the device is associated with a PM domain. - */ - pm_runtime_get_noresume(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - - ret = coda_firmware_request(dev); - if (ret) - goto err_alloc_workqueue; - return 0; - -err_alloc_workqueue: - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); - destroy_workqueue(dev->workqueue); -err_v4l2_register: - v4l2_device_unregister(&dev->v4l2_dev); - return ret; -} - -static void coda_remove(struct platform_device *pdev) -{ - struct coda_dev *dev = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < ARRAY_SIZE(dev->vfd); i++) { - if (video_get_drvdata(&dev->vfd[i])) - video_unregister_device(&dev->vfd[i]); - } - if (dev->m2m_dev) - v4l2_m2m_release(dev->m2m_dev); - pm_runtime_disable(&pdev->dev); - v4l2_device_unregister(&dev->v4l2_dev); - destroy_workqueue(dev->workqueue); - if (dev->iram.vaddr) - gen_pool_free(dev->iram_pool, (unsigned long)dev->iram.vaddr, - dev->iram.size); - coda_free_aux_buf(dev, &dev->codebuf); - coda_free_aux_buf(dev, &dev->tempbuf); - coda_free_aux_buf(dev, &dev->workbuf); - debugfs_remove_recursive(dev->debugfs_root); - ida_destroy(&dev->ida); -} - -#ifdef CONFIG_PM -static int coda_runtime_resume(struct device *dev) -{ - struct coda_dev *cdev = dev_get_drvdata(dev); - int ret = 0; - - if (dev->pm_domain && cdev->codebuf.vaddr) { - ret = coda_hw_init(cdev); - if (ret) - v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n"); - } - - return ret; -} -#endif - -static const struct dev_pm_ops coda_pm_ops = { - SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL) -}; - -static struct platform_driver coda_driver = { - .probe = coda_probe, - .remove_new = coda_remove, - .driver = { - .name = CODA_NAME, - .of_match_table = coda_dt_ids, - .pm = &coda_pm_ops, - }, -}; - -module_platform_driver(coda_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Javier Martin "); -MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver"); diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda-gdi.c b/drivers/media/platform/chips-media/coda-gdi.c --- a/drivers/media/platform/chips-media/coda-gdi.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/coda-gdi.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,146 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Coda multi-standard codec IP - * - * Copyright (C) 2014 Philipp Zabel, Pengutronix - */ - -#include -#include "coda.h" - -#define XY2_INVERT BIT(7) -#define XY2_ZERO BIT(6) -#define XY2_TB_XOR BIT(5) -#define XY2_XYSEL BIT(4) -#define XY2_Y (1 << 4) -#define XY2_X (0 << 4) - -#define XY2(luma_sel, luma_bit, chroma_sel, chroma_bit) \ - (((XY2_##luma_sel) | (luma_bit)) << 8 | \ - (XY2_##chroma_sel) | (chroma_bit)) - -static const u16 xy2ca_zero_map[16] = { - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), -}; - -static const u16 xy2ca_tiled_map[16] = { - XY2(Y, 0, Y, 0), - XY2(Y, 1, Y, 1), - XY2(Y, 2, Y, 2), - XY2(Y, 3, X, 3), - XY2(X, 3, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), - XY2(ZERO, 0, ZERO, 0), -}; - -/* - * RA[15:0], CA[15:8] are hardwired to contain the 24-bit macroblock - * start offset (macroblock size is 16x16 for luma, 16x8 for chroma). - * Bits CA[4:0] are set using XY2CA above. BA[3:0] seems to be unused. - */ - -#define RBC_CA (0 << 4) -#define RBC_BA (1 << 4) -#define RBC_RA (2 << 4) -#define RBC_ZERO (3 << 4) - -#define RBC(luma_sel, luma_bit, chroma_sel, chroma_bit) \ - (((RBC_##luma_sel) | (luma_bit)) << 6 | \ - (RBC_##chroma_sel) | (chroma_bit)) - -static const u16 rbc2axi_tiled_map[32] = { - RBC(ZERO, 0, ZERO, 0), - RBC(ZERO, 0, ZERO, 0), - RBC(ZERO, 0, ZERO, 0), - RBC(CA, 0, CA, 0), - RBC(CA, 1, CA, 1), - RBC(CA, 2, CA, 2), - RBC(CA, 3, CA, 3), - RBC(CA, 4, CA, 8), - RBC(CA, 8, CA, 9), - RBC(CA, 9, CA, 10), - RBC(CA, 10, CA, 11), - RBC(CA, 11, CA, 12), - RBC(CA, 12, CA, 13), - RBC(CA, 13, CA, 14), - RBC(CA, 14, CA, 15), - RBC(CA, 15, RA, 0), - RBC(RA, 0, RA, 1), - RBC(RA, 1, RA, 2), - RBC(RA, 2, RA, 3), - RBC(RA, 3, RA, 4), - RBC(RA, 4, RA, 5), - RBC(RA, 5, RA, 6), - RBC(RA, 6, RA, 7), - RBC(RA, 7, RA, 8), - RBC(RA, 8, RA, 9), - RBC(RA, 9, RA, 10), - RBC(RA, 10, RA, 11), - RBC(RA, 11, RA, 12), - RBC(RA, 12, RA, 13), - RBC(RA, 13, RA, 14), - RBC(RA, 14, RA, 15), - RBC(RA, 15, ZERO, 0), -}; - -void coda_set_gdi_regs(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - const u16 *xy2ca_map; - u32 xy2rbc_config; - int i; - - switch (ctx->tiled_map_type) { - case GDI_LINEAR_FRAME_MAP: - default: - xy2ca_map = xy2ca_zero_map; - xy2rbc_config = 0; - break; - case GDI_TILED_FRAME_MB_RASTER_MAP: - xy2ca_map = xy2ca_tiled_map; - xy2rbc_config = CODA9_XY2RBC_TILED_MAP | - CODA9_XY2RBC_CA_INC_HOR | - (16 - 1) << 12 | (8 - 1) << 4; - break; - } - - for (i = 0; i < 16; i++) - coda_write(dev, xy2ca_map[i], - CODA9_GDI_XY2_CAS_0 + 4 * i); - for (i = 0; i < 4; i++) - coda_write(dev, XY2(ZERO, 0, ZERO, 0), - CODA9_GDI_XY2_BA_0 + 4 * i); - for (i = 0; i < 16; i++) - coda_write(dev, XY2(ZERO, 0, ZERO, 0), - CODA9_GDI_XY2_RAS_0 + 4 * i); - coda_write(dev, xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG); - if (xy2rbc_config) { - for (i = 0; i < 32; i++) - coda_write(dev, rbc2axi_tiled_map[i], - CODA9_GDI_RBC2_AXI_0 + 4 * i); - } -} diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda.h b/drivers/media/platform/chips-media/coda.h --- a/drivers/media/platform/chips-media/coda.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/coda.h 1969-12-31 19:00:00.000000000 -0500 @@ -1,403 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Coda multi-standard codec IP - * - * Copyright (C) 2012 Vista Silicon S.L. - * Javier Martin, - * Xavier Duret - * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix - */ - -#ifndef __CODA_H__ -#define __CODA_H__ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "coda_regs.h" - -#define CODA_MAX_FRAMEBUFFERS 19 -#define FMO_SLICE_SAVE_BUF_SIZE (32) - -/* - * This control allows applications to read the per-stream - * (i.e. per-context) Macroblocks Error Count. This value - * is CODA specific. - */ -#define V4L2_CID_CODA_MB_ERR_CNT (V4L2_CID_USER_CODA_BASE + 0) - -enum { - V4L2_M2M_SRC = 0, - V4L2_M2M_DST = 1, -}; - -enum coda_inst_type { - CODA_INST_ENCODER, - CODA_INST_DECODER, -}; - -enum coda_product { - CODA_DX6 = 0xf001, - CODA_HX4 = 0xf00a, - CODA_7541 = 0xf012, - CODA_960 = 0xf020, -}; - -struct coda_video_device; - -struct coda_devtype { - char *firmware[3]; - enum coda_product product; - const struct coda_codec *codecs; - unsigned int num_codecs; - const struct coda_video_device **vdevs; - unsigned int num_vdevs; - size_t workbuf_size; - size_t tempbuf_size; - size_t iram_size; -}; - -struct coda_aux_buf { - void *vaddr; - dma_addr_t paddr; - u32 size; - struct debugfs_blob_wrapper blob; - struct dentry *dentry; -}; - -struct coda_dev { - struct v4l2_device v4l2_dev; - struct video_device vfd[6]; - struct device *dev; - const struct coda_devtype *devtype; - int firmware; - struct vdoa_data *vdoa; - - void __iomem *regs_base; - struct clk *clk_per; - struct clk *clk_ahb; - struct reset_control *rstc; - - struct coda_aux_buf codebuf; - struct coda_aux_buf tempbuf; - struct coda_aux_buf workbuf; - struct gen_pool *iram_pool; - struct coda_aux_buf iram; - - struct mutex dev_mutex; - struct mutex coda_mutex; - struct workqueue_struct *workqueue; - struct v4l2_m2m_dev *m2m_dev; - struct ida ida; - struct dentry *debugfs_root; - struct ratelimit_state mb_err_rs; -}; - -struct coda_codec { - u32 mode; - u32 src_fourcc; - u32 dst_fourcc; - u32 max_w; - u32 max_h; -}; - -struct coda_huff_tab; - -struct coda_params { - u8 rot_mode; - u8 h264_intra_qp; - u8 h264_inter_qp; - u8 h264_min_qp; - u8 h264_max_qp; - u8 h264_disable_deblocking_filter_idc; - s8 h264_slice_alpha_c0_offset_div2; - s8 h264_slice_beta_offset_div2; - bool h264_constrained_intra_pred_flag; - s8 h264_chroma_qp_index_offset; - u8 h264_profile_idc; - u8 h264_level_idc; - u8 mpeg2_profile_idc; - u8 mpeg2_level_idc; - u8 mpeg4_intra_qp; - u8 mpeg4_inter_qp; - u8 gop_size; - int intra_refresh; - enum v4l2_jpeg_chroma_subsampling jpeg_chroma_subsampling; - u8 jpeg_quality; - u8 jpeg_restart_interval; - u8 *jpeg_qmat_tab[3]; - int jpeg_qmat_index[3]; - int jpeg_huff_dc_index[3]; - int jpeg_huff_ac_index[3]; - u32 *jpeg_huff_data; - struct coda_huff_tab *jpeg_huff_tab; - int codec_mode; - int codec_mode_aux; - enum v4l2_mpeg_video_multi_slice_mode slice_mode; - u32 framerate; - u16 bitrate; - u16 vbv_delay; - u32 vbv_size; - u32 slice_max_bits; - u32 slice_max_mb; - bool force_ipicture; - bool gop_size_changed; - bool bitrate_changed; - bool framerate_changed; - bool h264_intra_qp_changed; - bool intra_refresh_changed; - bool slice_mode_changed; - bool frame_rc_enable; - bool mb_rc_enable; -}; - -struct coda_buffer_meta { - struct list_head list; - u32 sequence; - struct v4l2_timecode timecode; - u64 timestamp; - unsigned int start; - unsigned int end; - bool last; -}; - -/* Per-queue, driver-specific private data */ -struct coda_q_data { - unsigned int width; - unsigned int height; - unsigned int bytesperline; - unsigned int sizeimage; - unsigned int fourcc; - struct v4l2_rect rect; -}; - -struct coda_iram_info { - u32 axi_sram_use; - phys_addr_t buf_bit_use; - phys_addr_t buf_ip_ac_dc_use; - phys_addr_t buf_dbk_y_use; - phys_addr_t buf_dbk_c_use; - phys_addr_t buf_ovl_use; - phys_addr_t buf_btp_use; - phys_addr_t search_ram_paddr; - int search_ram_size; - int remaining; - phys_addr_t next_paddr; -}; - -#define GDI_LINEAR_FRAME_MAP 0 -#define GDI_TILED_FRAME_MB_RASTER_MAP 1 - -struct coda_ctx; - -struct coda_context_ops { - int (*queue_init)(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq); - int (*reqbufs)(struct coda_ctx *ctx, struct v4l2_requestbuffers *rb); - int (*start_streaming)(struct coda_ctx *ctx); - int (*prepare_run)(struct coda_ctx *ctx); - void (*finish_run)(struct coda_ctx *ctx); - void (*run_timeout)(struct coda_ctx *ctx); - void (*seq_init_work)(struct work_struct *work); - void (*seq_end_work)(struct work_struct *work); - void (*release)(struct coda_ctx *ctx); -}; - -struct coda_internal_frame { - struct coda_aux_buf buf; - struct coda_buffer_meta meta; - u32 type; - u32 error; -}; - -struct coda_ctx { - struct coda_dev *dev; - struct mutex buffer_mutex; - struct work_struct pic_run_work; - struct work_struct seq_init_work; - struct work_struct seq_end_work; - struct completion completion; - const struct coda_video_device *cvd; - const struct coda_context_ops *ops; - int aborting; - int initialized; - int streamon_out; - int streamon_cap; - u32 qsequence; - u32 osequence; - u32 sequence_offset; - struct coda_q_data q_data[2]; - enum coda_inst_type inst_type; - const struct coda_codec *codec; - enum v4l2_colorspace colorspace; - enum v4l2_xfer_func xfer_func; - enum v4l2_ycbcr_encoding ycbcr_enc; - enum v4l2_quantization quantization; - struct coda_params params; - struct v4l2_ctrl_handler ctrls; - struct v4l2_ctrl *h264_profile_ctrl; - struct v4l2_ctrl *h264_level_ctrl; - struct v4l2_ctrl *mpeg2_profile_ctrl; - struct v4l2_ctrl *mpeg2_level_ctrl; - struct v4l2_ctrl *mpeg4_profile_ctrl; - struct v4l2_ctrl *mpeg4_level_ctrl; - struct v4l2_ctrl *mb_err_cnt_ctrl; - struct v4l2_fh fh; - int gopcounter; - int runcounter; - int jpeg_ecs_offset; - char vpu_header[3][64]; - int vpu_header_size[3]; - struct kfifo bitstream_fifo; - struct mutex bitstream_mutex; - struct coda_aux_buf bitstream; - bool hold; - struct coda_aux_buf parabuf; - struct coda_aux_buf psbuf; - struct coda_aux_buf slicebuf; - struct coda_internal_frame internal_frames[CODA_MAX_FRAMEBUFFERS]; - struct list_head buffer_meta_list; - spinlock_t buffer_meta_lock; - int num_metas; - unsigned int first_frame_sequence; - struct coda_aux_buf workbuf; - int num_internal_frames; - int idx; - int reg_idx; - struct coda_iram_info iram_info; - int tiled_map_type; - u32 bit_stream_param; - u32 frm_dis_flg; - u32 frame_mem_ctrl; - u32 para_change; - int display_idx; - struct dentry *debugfs_entry; - bool use_bit; - bool use_vdoa; - struct vdoa_ctx *vdoa; - /* - * wakeup mutex used to serialize encoder stop command and finish_run, - * ensures that finish_run always either flags the last returned buffer - * or wakes up the capture queue to signal EOS afterwards. - */ - struct mutex wakeup_mutex; -}; - -extern int coda_debug; - -#define coda_dbg(level, ctx, fmt, arg...) \ - do { \ - if (coda_debug >= (level)) \ - v4l2_dbg((level), coda_debug, &(ctx)->dev->v4l2_dev, \ - "%u: " fmt, (ctx)->idx, ##arg); \ - } while (0) - -void coda_write(struct coda_dev *dev, u32 data, u32 reg); -unsigned int coda_read(struct coda_dev *dev, u32 reg); -void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, - struct vb2_v4l2_buffer *buf, unsigned int reg_y); - -int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, - size_t size, const char *name, struct dentry *parent); -void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf); - -int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq); -int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq); - -int coda_hw_reset(struct coda_ctx *ctx); - -void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list); - -void coda_set_gdi_regs(struct coda_ctx *ctx); - -static inline struct coda_q_data *get_q_data(struct coda_ctx *ctx, - enum v4l2_buf_type type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return &(ctx->q_data[V4L2_M2M_SRC]); - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &(ctx->q_data[V4L2_M2M_DST]); - default: - return NULL; - } -} - -const char *coda_product_name(int product); - -int coda_check_firmware(struct coda_dev *dev); - -static inline unsigned int coda_get_bitstream_payload(struct coda_ctx *ctx) -{ - return kfifo_len(&ctx->bitstream_fifo); -} - -/* - * The bitstream prefetcher needs to read at least 2 256 byte periods past - * the desired bitstream position for all data to reach the decoder. - */ -static inline bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, - unsigned int pos) -{ - return (int)(ctx->bitstream_fifo.kfifo.in - ALIGN(pos, 256)) > 512; -} - -bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, unsigned int pos); -int coda_bitstream_flush(struct coda_ctx *ctx); - -void coda_bit_stream_end_flag(struct coda_ctx *ctx); - -void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, - enum vb2_buffer_state state); - -int coda_h264_filler_nal(int size, char *p); -int coda_h264_padding(int size, char *p); -int coda_h264_profile(int profile_idc); -int coda_h264_level(int level_idc); -int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb); -int coda_h264_sps_fixup(struct coda_ctx *ctx, int width, int height, char *buf, - int *size, int max_size); - -int coda_mpeg2_profile(int profile_idc); -int coda_mpeg2_level(int level_idc); -u32 coda_mpeg2_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size); -int coda_mpeg4_profile(int profile_idc); -int coda_mpeg4_level(int level_idc); -u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size); - -void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, - u8 level_idc); - -static inline int coda_jpeg_scale(int src, int dst) -{ - return (dst <= src / 8) ? 3 : - (dst <= src / 4) ? 2 : - (dst <= src / 2) ? 1 : 0; -} - -bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb); -int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb); -int coda_jpeg_write_tables(struct coda_ctx *ctx); -void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality); - -extern const struct coda_context_ops coda_bit_encode_ops; -extern const struct coda_context_ops coda_bit_decode_ops; -extern const struct coda_context_ops coda9_jpeg_encode_ops; -extern const struct coda_context_ops coda9_jpeg_decode_ops; - -irqreturn_t coda_irq_handler(int irq, void *data); -irqreturn_t coda9_jpeg_irq_handler(int irq, void *data); - -#endif /* __CODA_H__ */ diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda-h264.c b/drivers/media/platform/chips-media/coda-h264.c --- a/drivers/media/platform/chips-media/coda-h264.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/coda-h264.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,429 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Coda multi-standard codec IP - H.264 helper functions - * - * Copyright (C) 2012 Vista Silicon S.L. - * Javier Martin, - * Xavier Duret - */ - -#include -#include -#include - -#include "coda.h" - -static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; - -static const u8 *coda_find_nal_header(const u8 *buf, const u8 *end) -{ - u32 val = 0xffffffff; - - do { - val = val << 8 | *buf++; - if (buf >= end) - return NULL; - } while (val != 0x00000001); - - return buf; -} - -int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb) -{ - const u8 *buf = vb2_plane_vaddr(vb, 0); - const u8 *end = buf + vb2_get_plane_payload(vb, 0); - - /* Find SPS header */ - do { - buf = coda_find_nal_header(buf, end); - if (!buf) - return -EINVAL; - } while ((*buf++ & 0x1f) != 0x7); - - ctx->params.h264_profile_idc = buf[0]; - ctx->params.h264_level_idc = buf[2]; - - return 0; -} - -int coda_h264_filler_nal(int size, char *p) -{ - if (size < 6) - return -EINVAL; - - p[0] = 0x00; - p[1] = 0x00; - p[2] = 0x00; - p[3] = 0x01; - p[4] = 0x0c; - memset(p + 5, 0xff, size - 6); - /* Add rbsp stop bit and trailing at the end */ - p[size - 1] = 0x80; - - return 0; -} - -int coda_h264_padding(int size, char *p) -{ - int nal_size; - int diff; - - diff = size - (size & ~0x7); - if (diff == 0) - return 0; - - nal_size = coda_filler_size[diff]; - coda_h264_filler_nal(nal_size, p); - - return nal_size; -} - -int coda_h264_profile(int profile_idc) -{ - switch (profile_idc) { - case 66: return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; - case 77: return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; - case 88: return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED; - case 100: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; - default: return -EINVAL; - } -} - -int coda_h264_level(int level_idc) -{ - switch (level_idc) { - case 10: return V4L2_MPEG_VIDEO_H264_LEVEL_1_0; - case 9: return V4L2_MPEG_VIDEO_H264_LEVEL_1B; - case 11: return V4L2_MPEG_VIDEO_H264_LEVEL_1_1; - case 12: return V4L2_MPEG_VIDEO_H264_LEVEL_1_2; - case 13: return V4L2_MPEG_VIDEO_H264_LEVEL_1_3; - case 20: return V4L2_MPEG_VIDEO_H264_LEVEL_2_0; - case 21: return V4L2_MPEG_VIDEO_H264_LEVEL_2_1; - case 22: return V4L2_MPEG_VIDEO_H264_LEVEL_2_2; - case 30: return V4L2_MPEG_VIDEO_H264_LEVEL_3_0; - case 31: return V4L2_MPEG_VIDEO_H264_LEVEL_3_1; - case 32: return V4L2_MPEG_VIDEO_H264_LEVEL_3_2; - case 40: return V4L2_MPEG_VIDEO_H264_LEVEL_4_0; - case 41: return V4L2_MPEG_VIDEO_H264_LEVEL_4_1; - case 42: return V4L2_MPEG_VIDEO_H264_LEVEL_4_2; - case 50: return V4L2_MPEG_VIDEO_H264_LEVEL_5_0; - case 51: return V4L2_MPEG_VIDEO_H264_LEVEL_5_1; - default: return -EINVAL; - } -} - -struct rbsp { - char *buf; - int size; - int pos; -}; - -static inline int rbsp_read_bit(struct rbsp *rbsp) -{ - int shift = 7 - (rbsp->pos % 8); - int ofs = rbsp->pos++ / 8; - - if (ofs >= rbsp->size) - return -EINVAL; - - return (rbsp->buf[ofs] >> shift) & 1; -} - -static inline int rbsp_write_bit(struct rbsp *rbsp, int bit) -{ - int shift = 7 - (rbsp->pos % 8); - int ofs = rbsp->pos++ / 8; - - if (ofs >= rbsp->size) - return -EINVAL; - - rbsp->buf[ofs] &= ~(1 << shift); - rbsp->buf[ofs] |= bit << shift; - - return 0; -} - -static inline int rbsp_read_bits(struct rbsp *rbsp, int num, int *val) -{ - int i, ret; - int tmp = 0; - - if (num > 32) - return -EINVAL; - - for (i = 0; i < num; i++) { - ret = rbsp_read_bit(rbsp); - if (ret < 0) - return ret; - tmp |= ret << (num - i - 1); - } - - if (val) - *val = tmp; - - return 0; -} - -static int rbsp_write_bits(struct rbsp *rbsp, int num, int value) -{ - int ret; - - while (num--) { - ret = rbsp_write_bit(rbsp, (value >> num) & 1); - if (ret) - return ret; - } - - return 0; -} - -static int rbsp_read_uev(struct rbsp *rbsp, unsigned int *val) -{ - int leading_zero_bits = 0; - unsigned int tmp = 0; - int ret; - - while ((ret = rbsp_read_bit(rbsp)) == 0) - leading_zero_bits++; - if (ret < 0) - return ret; - - if (leading_zero_bits > 0) { - ret = rbsp_read_bits(rbsp, leading_zero_bits, &tmp); - if (ret) - return ret; - } - - if (val) - *val = (1 << leading_zero_bits) - 1 + tmp; - - return 0; -} - -static int rbsp_write_uev(struct rbsp *rbsp, unsigned int value) -{ - int i; - int ret; - int tmp = value + 1; - int leading_zero_bits = fls(tmp) - 1; - - for (i = 0; i < leading_zero_bits; i++) { - ret = rbsp_write_bit(rbsp, 0); - if (ret) - return ret; - } - - return rbsp_write_bits(rbsp, leading_zero_bits + 1, tmp); -} - -static int rbsp_read_sev(struct rbsp *rbsp, int *val) -{ - unsigned int tmp; - int ret; - - ret = rbsp_read_uev(rbsp, &tmp); - if (ret) - return ret; - - if (val) { - if (tmp & 1) - *val = (tmp + 1) / 2; - else - *val = -(tmp / 2); - } - - return 0; -} - -/** - * coda_h264_sps_fixup - fixes frame cropping values in h.264 SPS - * @ctx: encoder context - * @width: visible width - * @height: visible height - * @buf: buffer containing h.264 SPS RBSP, starting with NAL header - * @size: modified RBSP size return value - * @max_size: available size in buf - * - * Rewrites the frame cropping values in an h.264 SPS RBSP correctly for the - * given visible width and height. - */ -int coda_h264_sps_fixup(struct coda_ctx *ctx, int width, int height, char *buf, - int *size, int max_size) -{ - int profile_idc; - unsigned int pic_order_cnt_type; - int pic_width_in_mbs_minus1, pic_height_in_map_units_minus1; - int frame_mbs_only_flag, frame_cropping_flag; - int vui_parameters_present_flag; - unsigned int crop_right, crop_bottom; - struct rbsp sps; - int pos; - int ret; - - if (*size < 8 || *size >= max_size) - return -EINVAL; - - sps.buf = buf + 5; /* Skip NAL header */ - sps.size = *size - 5; - - profile_idc = sps.buf[0]; - /* Skip constraint_set[0-5]_flag, reserved_zero_2bits */ - /* Skip level_idc */ - sps.pos = 24; - - /* seq_parameter_set_id */ - ret = rbsp_read_uev(&sps, NULL); - if (ret) - return ret; - - if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || - profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || - profile_idc == 86 || profile_idc == 118 || profile_idc == 128 || - profile_idc == 138 || profile_idc == 139 || profile_idc == 134 || - profile_idc == 135) { - dev_err(ctx->fh.vdev->dev_parent, - "%s: Handling profile_idc %d not implemented\n", - __func__, profile_idc); - return -EINVAL; - } - - /* log2_max_frame_num_minus4 */ - ret = rbsp_read_uev(&sps, NULL); - if (ret) - return ret; - - ret = rbsp_read_uev(&sps, &pic_order_cnt_type); - if (ret) - return ret; - - if (pic_order_cnt_type == 0) { - /* log2_max_pic_order_cnt_lsb_minus4 */ - ret = rbsp_read_uev(&sps, NULL); - if (ret) - return ret; - } else if (pic_order_cnt_type == 1) { - unsigned int i, num_ref_frames_in_pic_order_cnt_cycle; - - /* delta_pic_order_always_zero_flag */ - ret = rbsp_read_bit(&sps); - if (ret < 0) - return ret; - /* offset_for_non_ref_pic */ - ret = rbsp_read_sev(&sps, NULL); - if (ret) - return ret; - /* offset_for_top_to_bottom_field */ - ret = rbsp_read_sev(&sps, NULL); - if (ret) - return ret; - - ret = rbsp_read_uev(&sps, - &num_ref_frames_in_pic_order_cnt_cycle); - if (ret) - return ret; - for (i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) { - /* offset_for_ref_frame */ - ret = rbsp_read_sev(&sps, NULL); - if (ret) - return ret; - } - } - - /* max_num_ref_frames */ - ret = rbsp_read_uev(&sps, NULL); - if (ret) - return ret; - - /* gaps_in_frame_num_value_allowed_flag */ - ret = rbsp_read_bit(&sps); - if (ret < 0) - return ret; - ret = rbsp_read_uev(&sps, &pic_width_in_mbs_minus1); - if (ret) - return ret; - ret = rbsp_read_uev(&sps, &pic_height_in_map_units_minus1); - if (ret) - return ret; - frame_mbs_only_flag = ret = rbsp_read_bit(&sps); - if (ret < 0) - return ret; - if (!frame_mbs_only_flag) { - /* mb_adaptive_frame_field_flag */ - ret = rbsp_read_bit(&sps); - if (ret < 0) - return ret; - } - /* direct_8x8_inference_flag */ - ret = rbsp_read_bit(&sps); - if (ret < 0) - return ret; - - /* Mark position of the frame cropping flag */ - pos = sps.pos; - frame_cropping_flag = ret = rbsp_read_bit(&sps); - if (ret < 0) - return ret; - if (frame_cropping_flag) { - unsigned int crop_left, crop_top; - - ret = rbsp_read_uev(&sps, &crop_left); - if (ret) - return ret; - ret = rbsp_read_uev(&sps, &crop_right); - if (ret) - return ret; - ret = rbsp_read_uev(&sps, &crop_top); - if (ret) - return ret; - ret = rbsp_read_uev(&sps, &crop_bottom); - if (ret) - return ret; - } - vui_parameters_present_flag = ret = rbsp_read_bit(&sps); - if (ret < 0) - return ret; - if (vui_parameters_present_flag) { - dev_err(ctx->fh.vdev->dev_parent, - "%s: Handling vui_parameters not implemented\n", - __func__); - return -EINVAL; - } - - crop_right = round_up(width, 16) - width; - crop_bottom = round_up(height, 16) - height; - crop_right /= 2; - if (frame_mbs_only_flag) - crop_bottom /= 2; - else - crop_bottom /= 4; - - - sps.size = max_size - 5; - sps.pos = pos; - frame_cropping_flag = 1; - ret = rbsp_write_bit(&sps, frame_cropping_flag); - if (ret) - return ret; - ret = rbsp_write_uev(&sps, 0); /* crop_left */ - if (ret) - return ret; - ret = rbsp_write_uev(&sps, crop_right); - if (ret) - return ret; - ret = rbsp_write_uev(&sps, 0); /* crop_top */ - if (ret) - return ret; - ret = rbsp_write_uev(&sps, crop_bottom); - if (ret) - return ret; - ret = rbsp_write_bit(&sps, 0); /* vui_parameters_present_flag */ - if (ret) - return ret; - ret = rbsp_write_bit(&sps, 1); - if (ret) - return ret; - - *size = 5 + DIV_ROUND_UP(sps.pos, 8); - - return 0; -} diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda-jpeg.c b/drivers/media/platform/chips-media/coda-jpeg.c --- a/drivers/media/platform/chips-media/coda-jpeg.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/coda-jpeg.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,1547 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Coda multi-standard codec IP - JPEG support functions - * - * Copyright (C) 2014 Philipp Zabel, Pengutronix - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "coda.h" -#include "trace.h" - -#define SOI_MARKER 0xffd8 -#define APP9_MARKER 0xffe9 -#define DRI_MARKER 0xffdd -#define DQT_MARKER 0xffdb -#define DHT_MARKER 0xffc4 -#define SOF_MARKER 0xffc0 -#define SOS_MARKER 0xffda -#define EOI_MARKER 0xffd9 - -enum { - CODA9_JPEG_FORMAT_420, - CODA9_JPEG_FORMAT_422, - CODA9_JPEG_FORMAT_224, - CODA9_JPEG_FORMAT_444, - CODA9_JPEG_FORMAT_400, -}; - -struct coda_huff_tab { - u8 luma_dc[16 + 12]; - u8 chroma_dc[16 + 12]; - u8 luma_ac[16 + 162]; - u8 chroma_ac[16 + 162]; - - /* DC Luma, DC Chroma, AC Luma, AC Chroma */ - s16 min[4 * 16]; - s16 max[4 * 16]; - s8 ptr[4 * 16]; -}; - -#define CODA9_JPEG_ENC_HUFF_DATA_SIZE (256 + 256 + 16 + 16) - -/* - * Typical Huffman tables for 8-bit precision luminance and - * chrominance from JPEG ITU-T.81 (ISO/IEC 10918-1) Annex K.3 - */ - -static const unsigned char luma_dc[16 + 12] = { - /* bits */ - 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* values */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, -}; - -static const unsigned char chroma_dc[16 + 12] = { - /* bits */ - 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - /* values */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, -}; - -static const unsigned char luma_ac[16 + 162 + 2] = { - /* bits */ - 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, - 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, - /* values */ - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, - 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, - 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, - 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, - 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, - 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, - 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, /* padded to 32-bit */ -}; - -static const unsigned char chroma_ac[16 + 162 + 2] = { - /* bits */ - 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, - 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, - /* values */ - 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, - 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, - 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, - 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, - 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, - 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, - 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, - 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, - 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, - 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, - 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, - 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, /* padded to 32-bit */ -}; - -/* - * Quantization tables for luminance and chrominance components in - * zig-zag scan order from the Freescale i.MX VPU libraries - */ - -static unsigned char luma_q[64] = { - 0x06, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x05, - 0x05, 0x06, 0x09, 0x06, 0x05, 0x06, 0x09, 0x0b, - 0x08, 0x06, 0x06, 0x08, 0x0b, 0x0c, 0x0a, 0x0a, - 0x0b, 0x0a, 0x0a, 0x0c, 0x10, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x10, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, -}; - -static unsigned char chroma_q[64] = { - 0x07, 0x07, 0x07, 0x0d, 0x0c, 0x0d, 0x18, 0x10, - 0x10, 0x18, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, - 0x0e, 0x0e, 0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, -}; - -static const unsigned char width_align[] = { - [CODA9_JPEG_FORMAT_420] = 16, - [CODA9_JPEG_FORMAT_422] = 16, - [CODA9_JPEG_FORMAT_224] = 8, - [CODA9_JPEG_FORMAT_444] = 8, - [CODA9_JPEG_FORMAT_400] = 8, -}; - -static const unsigned char height_align[] = { - [CODA9_JPEG_FORMAT_420] = 16, - [CODA9_JPEG_FORMAT_422] = 8, - [CODA9_JPEG_FORMAT_224] = 16, - [CODA9_JPEG_FORMAT_444] = 8, - [CODA9_JPEG_FORMAT_400] = 8, -}; - -static int coda9_jpeg_chroma_format(u32 pixfmt) -{ - switch (pixfmt) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_NV12: - return CODA9_JPEG_FORMAT_420; - case V4L2_PIX_FMT_YUV422P: - return CODA9_JPEG_FORMAT_422; - case V4L2_PIX_FMT_YUV444: - return CODA9_JPEG_FORMAT_444; - case V4L2_PIX_FMT_GREY: - return CODA9_JPEG_FORMAT_400; - } - return -EINVAL; -} - -struct coda_memcpy_desc { - int offset; - const void *src; - size_t len; -}; - -static void coda_memcpy_parabuf(void *parabuf, - const struct coda_memcpy_desc *desc) -{ - u32 *dst = parabuf + desc->offset; - const u32 *src = desc->src; - int len = desc->len / 4; - int i; - - for (i = 0; i < len; i += 2) { - dst[i + 1] = swab32(src[i]); - dst[i] = swab32(src[i + 1]); - } -} - -int coda_jpeg_write_tables(struct coda_ctx *ctx) -{ - int i; - static const struct coda_memcpy_desc huff[8] = { - { 0, luma_dc, sizeof(luma_dc) }, - { 32, luma_ac, sizeof(luma_ac) }, - { 216, chroma_dc, sizeof(chroma_dc) }, - { 248, chroma_ac, sizeof(chroma_ac) }, - }; - struct coda_memcpy_desc qmat[3] = { - { 512, ctx->params.jpeg_qmat_tab[0], 64 }, - { 576, ctx->params.jpeg_qmat_tab[1], 64 }, - { 640, ctx->params.jpeg_qmat_tab[1], 64 }, - }; - - /* Write huffman tables to parameter memory */ - for (i = 0; i < ARRAY_SIZE(huff); i++) - coda_memcpy_parabuf(ctx->parabuf.vaddr, huff + i); - - /* Write Q-matrix to parameter memory */ - for (i = 0; i < ARRAY_SIZE(qmat); i++) - coda_memcpy_parabuf(ctx->parabuf.vaddr, qmat + i); - - return 0; -} - -bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb) -{ - void *vaddr = vb2_plane_vaddr(vb, 0); - u16 soi, eoi; - int len, i; - - soi = be16_to_cpup((__be16 *)vaddr); - if (soi != SOI_MARKER) - return false; - - len = vb2_get_plane_payload(vb, 0); - vaddr += len - 2; - for (i = 0; i < 32; i++) { - eoi = be16_to_cpup((__be16 *)(vaddr - i)); - if (eoi == EOI_MARKER) { - if (i > 0) - vb2_set_plane_payload(vb, 0, len - i); - return true; - } - } - - return false; -} - -static int coda9_jpeg_gen_dec_huff_tab(struct coda_ctx *ctx, int tab_num); - -int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb) -{ - struct coda_dev *dev = ctx->dev; - u8 *buf = vb2_plane_vaddr(vb, 0); - size_t len = vb2_get_plane_payload(vb, 0); - struct v4l2_jpeg_scan_header scan_header; - struct v4l2_jpeg_reference quantization_tables[4] = { }; - struct v4l2_jpeg_reference huffman_tables[4] = { }; - struct v4l2_jpeg_header header = { - .scan = &scan_header, - .quantization_tables = quantization_tables, - .huffman_tables = huffman_tables, - }; - struct coda_q_data *q_data_src; - struct coda_huff_tab *huff_tab; - int i, j, ret; - - ret = v4l2_jpeg_parse_header(buf, len, &header); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to parse JPEG header: %pe\n", - ERR_PTR(ret)); - return ret; - } - - ctx->params.jpeg_restart_interval = header.restart_interval; - - /* check frame header */ - if (header.frame.height > ctx->codec->max_h || - header.frame.width > ctx->codec->max_w) { - v4l2_err(&dev->v4l2_dev, "invalid dimensions: %dx%d\n", - header.frame.width, header.frame.height); - return -EINVAL; - } - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - if (header.frame.height != q_data_src->height || - header.frame.width != q_data_src->width) { - v4l2_err(&dev->v4l2_dev, - "dimensions don't match format: %dx%d\n", - header.frame.width, header.frame.height); - return -EINVAL; - } - - if (header.frame.num_components != 3) { - v4l2_err(&dev->v4l2_dev, - "unsupported number of components: %d\n", - header.frame.num_components); - return -EINVAL; - } - - /* install quantization tables */ - if (quantization_tables[3].start) { - v4l2_err(&dev->v4l2_dev, - "only 3 quantization tables supported\n"); - return -EINVAL; - } - for (i = 0; i < 3; i++) { - if (!quantization_tables[i].start) - continue; - if (quantization_tables[i].length != 64) { - v4l2_err(&dev->v4l2_dev, - "only 8-bit quantization tables supported\n"); - continue; - } - if (!ctx->params.jpeg_qmat_tab[i]) { - ctx->params.jpeg_qmat_tab[i] = kmalloc(64, GFP_KERNEL); - if (!ctx->params.jpeg_qmat_tab[i]) - return -ENOMEM; - } - memcpy(ctx->params.jpeg_qmat_tab[i], - quantization_tables[i].start, 64); - } - - /* install Huffman tables */ - for (i = 0; i < 4; i++) { - if (!huffman_tables[i].start) { - v4l2_err(&dev->v4l2_dev, "missing Huffman table\n"); - return -EINVAL; - } - /* AC tables should be between 17 -> 178, DC between 17 -> 28 */ - if (huffman_tables[i].length < 17 || - huffman_tables[i].length > 178 || - ((i & 2) == 0 && huffman_tables[i].length > 28)) { - v4l2_err(&dev->v4l2_dev, - "invalid Huffman table %d length: %zu\n", - i, huffman_tables[i].length); - return -EINVAL; - } - } - huff_tab = ctx->params.jpeg_huff_tab; - if (!huff_tab) { - huff_tab = kzalloc(sizeof(struct coda_huff_tab), GFP_KERNEL); - if (!huff_tab) - return -ENOMEM; - ctx->params.jpeg_huff_tab = huff_tab; - } - - memset(huff_tab, 0, sizeof(*huff_tab)); - memcpy(huff_tab->luma_dc, huffman_tables[0].start, huffman_tables[0].length); - memcpy(huff_tab->chroma_dc, huffman_tables[1].start, huffman_tables[1].length); - memcpy(huff_tab->luma_ac, huffman_tables[2].start, huffman_tables[2].length); - memcpy(huff_tab->chroma_ac, huffman_tables[3].start, huffman_tables[3].length); - - /* check scan header */ - for (i = 0; i < scan_header.num_components; i++) { - struct v4l2_jpeg_scan_component_spec *scan_component; - - scan_component = &scan_header.component[i]; - for (j = 0; j < header.frame.num_components; j++) { - if (header.frame.component[j].component_identifier == - scan_component->component_selector) - break; - } - if (j == header.frame.num_components) - continue; - - ctx->params.jpeg_huff_dc_index[j] = - scan_component->dc_entropy_coding_table_selector; - ctx->params.jpeg_huff_ac_index[j] = - scan_component->ac_entropy_coding_table_selector; - } - - /* Generate Huffman table information */ - for (i = 0; i < 4; i++) - coda9_jpeg_gen_dec_huff_tab(ctx, i); - - /* start of entropy coded segment */ - ctx->jpeg_ecs_offset = header.ecs_offset; - - switch (header.frame.subsampling) { - case V4L2_JPEG_CHROMA_SUBSAMPLING_420: - case V4L2_JPEG_CHROMA_SUBSAMPLING_422: - ctx->params.jpeg_chroma_subsampling = header.frame.subsampling; - break; - default: - v4l2_err(&dev->v4l2_dev, "chroma subsampling not supported: %d", - header.frame.subsampling); - return -EINVAL; - } - - return 0; -} - -static inline void coda9_jpeg_write_huff_values(struct coda_dev *dev, u8 *bits, - int num_values) -{ - s8 *values = (s8 *)(bits + 16); - int huff_length, i; - - for (huff_length = 0, i = 0; i < 16; i++) - huff_length += bits[i]; - for (i = huff_length; i < num_values; i++) - values[i] = -1; - for (i = 0; i < num_values; i++) - coda_write(dev, (s32)values[i], CODA9_REG_JPEG_HUFF_DATA); -} - -static void coda9_jpeg_dec_huff_setup(struct coda_ctx *ctx) -{ - struct coda_huff_tab *huff_tab = ctx->params.jpeg_huff_tab; - struct coda_dev *dev = ctx->dev; - s16 *huff_min = huff_tab->min; - s16 *huff_max = huff_tab->max; - s8 *huff_ptr = huff_tab->ptr; - int i; - - /* MIN Tables */ - coda_write(dev, 0x003, CODA9_REG_JPEG_HUFF_CTRL); - coda_write(dev, 0x000, CODA9_REG_JPEG_HUFF_ADDR); - for (i = 0; i < 4 * 16; i++) - coda_write(dev, (s32)huff_min[i], CODA9_REG_JPEG_HUFF_DATA); - - /* MAX Tables */ - coda_write(dev, 0x403, CODA9_REG_JPEG_HUFF_CTRL); - coda_write(dev, 0x440, CODA9_REG_JPEG_HUFF_ADDR); - for (i = 0; i < 4 * 16; i++) - coda_write(dev, (s32)huff_max[i], CODA9_REG_JPEG_HUFF_DATA); - - /* PTR Tables */ - coda_write(dev, 0x803, CODA9_REG_JPEG_HUFF_CTRL); - coda_write(dev, 0x880, CODA9_REG_JPEG_HUFF_ADDR); - for (i = 0; i < 4 * 16; i++) - coda_write(dev, (s32)huff_ptr[i], CODA9_REG_JPEG_HUFF_DATA); - - /* VAL Tables: DC Luma, DC Chroma, AC Luma, AC Chroma */ - coda_write(dev, 0xc03, CODA9_REG_JPEG_HUFF_CTRL); - coda9_jpeg_write_huff_values(dev, huff_tab->luma_dc, 12); - coda9_jpeg_write_huff_values(dev, huff_tab->chroma_dc, 12); - coda9_jpeg_write_huff_values(dev, huff_tab->luma_ac, 162); - coda9_jpeg_write_huff_values(dev, huff_tab->chroma_ac, 162); - coda_write(dev, 0x000, CODA9_REG_JPEG_HUFF_CTRL); -} - -static inline void coda9_jpeg_write_qmat_tab(struct coda_dev *dev, - u8 *qmat, int index) -{ - int i; - - coda_write(dev, index | 0x3, CODA9_REG_JPEG_QMAT_CTRL); - for (i = 0; i < 64; i++) - coda_write(dev, qmat[i], CODA9_REG_JPEG_QMAT_DATA); - coda_write(dev, 0, CODA9_REG_JPEG_QMAT_CTRL); -} - -static void coda9_jpeg_qmat_setup(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - int *qmat_index = ctx->params.jpeg_qmat_index; - u8 **qmat_tab = ctx->params.jpeg_qmat_tab; - - coda9_jpeg_write_qmat_tab(dev, qmat_tab[qmat_index[0]], 0x00); - coda9_jpeg_write_qmat_tab(dev, qmat_tab[qmat_index[1]], 0x40); - coda9_jpeg_write_qmat_tab(dev, qmat_tab[qmat_index[2]], 0x80); -} - -static void coda9_jpeg_dec_bbc_gbu_setup(struct coda_ctx *ctx, - struct vb2_buffer *buf, u32 ecs_offset) -{ - struct coda_dev *dev = ctx->dev; - int page_ptr, word_ptr, bit_ptr; - u32 bbc_base_addr, end_addr; - int bbc_cur_pos; - int ret, val; - - bbc_base_addr = vb2_dma_contig_plane_dma_addr(buf, 0); - end_addr = bbc_base_addr + vb2_get_plane_payload(buf, 0); - - page_ptr = ecs_offset / 256; - word_ptr = (ecs_offset % 256) / 4; - if (page_ptr & 1) - word_ptr += 64; - bit_ptr = (ecs_offset % 4) * 8; - if (word_ptr & 1) - bit_ptr += 32; - word_ptr &= ~0x1; - - coda_write(dev, end_addr, CODA9_REG_JPEG_BBC_WR_PTR); - coda_write(dev, bbc_base_addr, CODA9_REG_JPEG_BBC_BAS_ADDR); - - /* Leave 3 256-byte page margin to avoid a BBC interrupt */ - coda_write(dev, end_addr + 256 * 3 + 256, CODA9_REG_JPEG_BBC_END_ADDR); - val = DIV_ROUND_UP(vb2_plane_size(buf, 0), 256) + 3; - coda_write(dev, BIT(31) | val, CODA9_REG_JPEG_BBC_STRM_CTRL); - - bbc_cur_pos = page_ptr; - coda_write(dev, bbc_cur_pos, CODA9_REG_JPEG_BBC_CUR_POS); - coda_write(dev, bbc_base_addr + (bbc_cur_pos << 8), - CODA9_REG_JPEG_BBC_EXT_ADDR); - coda_write(dev, (bbc_cur_pos & 1) << 6, CODA9_REG_JPEG_BBC_INT_ADDR); - coda_write(dev, 64, CODA9_REG_JPEG_BBC_DATA_CNT); - coda_write(dev, 0, CODA9_REG_JPEG_BBC_COMMAND); - do { - ret = coda_read(dev, CODA9_REG_JPEG_BBC_BUSY); - } while (ret == 1); - - bbc_cur_pos++; - coda_write(dev, bbc_cur_pos, CODA9_REG_JPEG_BBC_CUR_POS); - coda_write(dev, bbc_base_addr + (bbc_cur_pos << 8), - CODA9_REG_JPEG_BBC_EXT_ADDR); - coda_write(dev, (bbc_cur_pos & 1) << 6, CODA9_REG_JPEG_BBC_INT_ADDR); - coda_write(dev, 64, CODA9_REG_JPEG_BBC_DATA_CNT); - coda_write(dev, 0, CODA9_REG_JPEG_BBC_COMMAND); - do { - ret = coda_read(dev, CODA9_REG_JPEG_BBC_BUSY); - } while (ret == 1); - - bbc_cur_pos++; - coda_write(dev, bbc_cur_pos, CODA9_REG_JPEG_BBC_CUR_POS); - coda_write(dev, 1, CODA9_REG_JPEG_BBC_CTRL); - - coda_write(dev, 0, CODA9_REG_JPEG_GBU_TT_CNT); - coda_write(dev, word_ptr, CODA9_REG_JPEG_GBU_WD_PTR); - coda_write(dev, 0, CODA9_REG_JPEG_GBU_BBSR); - coda_write(dev, 127, CODA9_REG_JPEG_GBU_BBER); - if (page_ptr & 1) { - coda_write(dev, 0, CODA9_REG_JPEG_GBU_BBIR); - coda_write(dev, 0, CODA9_REG_JPEG_GBU_BBHR); - } else { - coda_write(dev, 64, CODA9_REG_JPEG_GBU_BBIR); - coda_write(dev, 64, CODA9_REG_JPEG_GBU_BBHR); - } - coda_write(dev, 4, CODA9_REG_JPEG_GBU_CTRL); - coda_write(dev, bit_ptr, CODA9_REG_JPEG_GBU_FF_RPTR); - coda_write(dev, 3, CODA9_REG_JPEG_GBU_CTRL); -} - -static const int bus_req_num[] = { - [CODA9_JPEG_FORMAT_420] = 2, - [CODA9_JPEG_FORMAT_422] = 3, - [CODA9_JPEG_FORMAT_224] = 3, - [CODA9_JPEG_FORMAT_444] = 4, - [CODA9_JPEG_FORMAT_400] = 4, -}; - -#define MCU_INFO(mcu_block_num, comp_num, comp0_info, comp1_info, comp2_info) \ - (((mcu_block_num) << CODA9_JPEG_MCU_BLOCK_NUM_OFFSET) | \ - ((comp_num) << CODA9_JPEG_COMP_NUM_OFFSET) | \ - ((comp0_info) << CODA9_JPEG_COMP0_INFO_OFFSET) | \ - ((comp1_info) << CODA9_JPEG_COMP1_INFO_OFFSET) | \ - ((comp2_info) << CODA9_JPEG_COMP2_INFO_OFFSET)) - -static const u32 mcu_info[] = { - [CODA9_JPEG_FORMAT_420] = MCU_INFO(6, 3, 10, 5, 5), - [CODA9_JPEG_FORMAT_422] = MCU_INFO(4, 3, 9, 5, 5), - [CODA9_JPEG_FORMAT_224] = MCU_INFO(4, 3, 6, 5, 5), - [CODA9_JPEG_FORMAT_444] = MCU_INFO(3, 3, 5, 5, 5), - [CODA9_JPEG_FORMAT_400] = MCU_INFO(1, 1, 5, 0, 0), -}; - -/* - * Convert Huffman table specifcations to tables of codes and code lengths. - * For reference, see JPEG ITU-T.81 (ISO/IEC 10918-1) [1] - * - * [1] https://www.w3.org/Graphics/JPEG/itu-t81.pdf - */ -static int coda9_jpeg_gen_enc_huff_tab(struct coda_ctx *ctx, int tab_num, - int *ehufsi, int *ehufco) -{ - int i, j, k, lastk, si, code, maxsymbol; - const u8 *bits, *huffval; - struct { - int size[256]; - int code[256]; - } *huff; - static const unsigned char *huff_tabs[4] = { - luma_dc, luma_ac, chroma_dc, chroma_ac, - }; - int ret = -EINVAL; - - huff = kzalloc(sizeof(*huff), GFP_KERNEL); - if (!huff) - return -ENOMEM; - - bits = huff_tabs[tab_num]; - huffval = huff_tabs[tab_num] + 16; - - maxsymbol = tab_num & 1 ? 256 : 16; - - /* Figure C.1 - Generation of table of Huffman code sizes */ - k = 0; - for (i = 1; i <= 16; i++) { - j = bits[i - 1]; - if (k + j > maxsymbol) - goto out; - while (j--) - huff->size[k++] = i; - } - lastk = k; - - /* Figure C.2 - Generation of table of Huffman codes */ - k = 0; - code = 0; - si = huff->size[0]; - while (k < lastk) { - while (huff->size[k] == si) { - huff->code[k++] = code; - code++; - } - if (code >= (1 << si)) - goto out; - code <<= 1; - si++; - } - - /* Figure C.3 - Ordering procedure for encoding procedure code tables */ - for (k = 0; k < lastk; k++) { - i = huffval[k]; - if (i >= maxsymbol || ehufsi[i]) - goto out; - ehufco[i] = huff->code[k]; - ehufsi[i] = huff->size[k]; - } - - ret = 0; -out: - kfree(huff); - return ret; -} - -#define DC_TABLE_INDEX0 0 -#define AC_TABLE_INDEX0 1 -#define DC_TABLE_INDEX1 2 -#define AC_TABLE_INDEX1 3 - -static u8 *coda9_jpeg_get_huff_bits(struct coda_ctx *ctx, int tab_num) -{ - struct coda_huff_tab *huff_tab = ctx->params.jpeg_huff_tab; - - if (!huff_tab) - return NULL; - - switch (tab_num) { - case DC_TABLE_INDEX0: return huff_tab->luma_dc; - case AC_TABLE_INDEX0: return huff_tab->luma_ac; - case DC_TABLE_INDEX1: return huff_tab->chroma_dc; - case AC_TABLE_INDEX1: return huff_tab->chroma_ac; - } - - return NULL; -} - -static int coda9_jpeg_gen_dec_huff_tab(struct coda_ctx *ctx, int tab_num) -{ - int ptr_cnt = 0, huff_code = 0, zero_flag = 0, data_flag = 0; - u8 *huff_bits; - s16 *huff_max; - s16 *huff_min; - s8 *huff_ptr; - int ofs; - int i; - - huff_bits = coda9_jpeg_get_huff_bits(ctx, tab_num); - if (!huff_bits) - return -EINVAL; - - /* DC/AC Luma, DC/AC Chroma -> DC Luma/Chroma, AC Luma/Chroma */ - ofs = ((tab_num & 1) << 1) | ((tab_num >> 1) & 1); - ofs *= 16; - - huff_ptr = ctx->params.jpeg_huff_tab->ptr + ofs; - huff_max = ctx->params.jpeg_huff_tab->max + ofs; - huff_min = ctx->params.jpeg_huff_tab->min + ofs; - - for (i = 0; i < 16; i++) { - if (huff_bits[i]) { - huff_ptr[i] = ptr_cnt; - ptr_cnt += huff_bits[i]; - huff_min[i] = huff_code; - huff_max[i] = huff_code + (huff_bits[i] - 1); - data_flag = 1; - zero_flag = 0; - } else { - huff_ptr[i] = -1; - huff_min[i] = -1; - huff_max[i] = -1; - zero_flag = 1; - } - - if (data_flag == 1) { - if (zero_flag == 1) - huff_code <<= 1; - else - huff_code = (huff_max[i] + 1) << 1; - } - } - - return 0; -} - -static int coda9_jpeg_load_huff_tab(struct coda_ctx *ctx) -{ - struct { - int size[4][256]; - int code[4][256]; - } *huff; - u32 *huff_data; - int i, j; - int ret; - - huff = kzalloc(sizeof(*huff), GFP_KERNEL); - if (!huff) - return -ENOMEM; - - /* Generate all four (luma/chroma DC/AC) code/size lookup tables */ - for (i = 0; i < 4; i++) { - ret = coda9_jpeg_gen_enc_huff_tab(ctx, i, huff->size[i], - huff->code[i]); - if (ret) - goto out; - } - - if (!ctx->params.jpeg_huff_data) { - ctx->params.jpeg_huff_data = - kzalloc(sizeof(u32) * CODA9_JPEG_ENC_HUFF_DATA_SIZE, - GFP_KERNEL); - if (!ctx->params.jpeg_huff_data) { - ret = -ENOMEM; - goto out; - } - } - huff_data = ctx->params.jpeg_huff_data; - - for (j = 0; j < 4; j++) { - /* Store Huffman lookup tables in AC0, AC1, DC0, DC1 order */ - int t = (j == 0) ? AC_TABLE_INDEX0 : - (j == 1) ? AC_TABLE_INDEX1 : - (j == 2) ? DC_TABLE_INDEX0 : - DC_TABLE_INDEX1; - /* DC tables only have 16 entries */ - int len = (j < 2) ? 256 : 16; - - for (i = 0; i < len; i++) { - if (huff->size[t][i] == 0 && huff->code[t][i] == 0) - *(huff_data++) = 0; - else - *(huff_data++) = - ((huff->size[t][i] - 1) << 16) | - huff->code[t][i]; - } - } - - ret = 0; -out: - kfree(huff); - return ret; -} - -static void coda9_jpeg_write_huff_tab(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - u32 *huff_data = ctx->params.jpeg_huff_data; - int i; - - /* Write Huffman size/code lookup tables in AC0, AC1, DC0, DC1 order */ - coda_write(dev, 0x3, CODA9_REG_JPEG_HUFF_CTRL); - for (i = 0; i < CODA9_JPEG_ENC_HUFF_DATA_SIZE; i++) - coda_write(dev, *(huff_data++), CODA9_REG_JPEG_HUFF_DATA); - coda_write(dev, 0x0, CODA9_REG_JPEG_HUFF_CTRL); -} - -static inline void coda9_jpeg_write_qmat_quotients(struct coda_dev *dev, - u8 *qmat, int index) -{ - int i; - - coda_write(dev, index | 0x3, CODA9_REG_JPEG_QMAT_CTRL); - for (i = 0; i < 64; i++) - coda_write(dev, 0x80000 / qmat[i], CODA9_REG_JPEG_QMAT_DATA); - coda_write(dev, index, CODA9_REG_JPEG_QMAT_CTRL); -} - -static void coda9_jpeg_load_qmat_tab(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - u8 *luma_tab; - u8 *chroma_tab; - - luma_tab = ctx->params.jpeg_qmat_tab[0]; - if (!luma_tab) - luma_tab = luma_q; - - chroma_tab = ctx->params.jpeg_qmat_tab[1]; - if (!chroma_tab) - chroma_tab = chroma_q; - - coda9_jpeg_write_qmat_quotients(dev, luma_tab, 0x00); - coda9_jpeg_write_qmat_quotients(dev, chroma_tab, 0x40); - coda9_jpeg_write_qmat_quotients(dev, chroma_tab, 0x80); -} - -struct coda_jpeg_stream { - u8 *curr; - u8 *end; -}; - -static inline int coda_jpeg_put_byte(u8 byte, struct coda_jpeg_stream *stream) -{ - if (stream->curr >= stream->end) - return -EINVAL; - - *stream->curr++ = byte; - - return 0; -} - -static inline int coda_jpeg_put_word(u16 word, struct coda_jpeg_stream *stream) -{ - if (stream->curr + sizeof(__be16) > stream->end) - return -EINVAL; - - put_unaligned_be16(word, stream->curr); - stream->curr += sizeof(__be16); - - return 0; -} - -static int coda_jpeg_put_table(u16 marker, u8 index, const u8 *table, - size_t len, struct coda_jpeg_stream *stream) -{ - int i, ret; - - ret = coda_jpeg_put_word(marker, stream); - if (ret < 0) - return ret; - ret = coda_jpeg_put_word(3 + len, stream); - if (ret < 0) - return ret; - ret = coda_jpeg_put_byte(index, stream); - for (i = 0; i < len && ret == 0; i++) - ret = coda_jpeg_put_byte(table[i], stream); - - return ret; -} - -static int coda_jpeg_define_quantization_table(struct coda_ctx *ctx, u8 index, - struct coda_jpeg_stream *stream) -{ - return coda_jpeg_put_table(DQT_MARKER, index, - ctx->params.jpeg_qmat_tab[index], 64, - stream); -} - -static int coda_jpeg_define_huffman_table(u8 index, const u8 *table, size_t len, - struct coda_jpeg_stream *stream) -{ - return coda_jpeg_put_table(DHT_MARKER, index, table, len, stream); -} - -static int coda9_jpeg_encode_header(struct coda_ctx *ctx, int len, u8 *buf) -{ - struct coda_jpeg_stream stream = { buf, buf + len }; - struct coda_q_data *q_data_src; - int chroma_format, comp_num; - int i, ret, pad; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - chroma_format = coda9_jpeg_chroma_format(q_data_src->fourcc); - if (chroma_format < 0) - return 0; - - /* Start Of Image */ - ret = coda_jpeg_put_word(SOI_MARKER, &stream); - if (ret < 0) - return ret; - - /* Define Restart Interval */ - if (ctx->params.jpeg_restart_interval) { - ret = coda_jpeg_put_word(DRI_MARKER, &stream); - if (ret < 0) - return ret; - ret = coda_jpeg_put_word(4, &stream); - if (ret < 0) - return ret; - ret = coda_jpeg_put_word(ctx->params.jpeg_restart_interval, - &stream); - if (ret < 0) - return ret; - } - - /* Define Quantization Tables */ - ret = coda_jpeg_define_quantization_table(ctx, 0x00, &stream); - if (ret < 0) - return ret; - if (chroma_format != CODA9_JPEG_FORMAT_400) { - ret = coda_jpeg_define_quantization_table(ctx, 0x01, &stream); - if (ret < 0) - return ret; - } - - /* Define Huffman Tables */ - ret = coda_jpeg_define_huffman_table(0x00, luma_dc, 16 + 12, &stream); - if (ret < 0) - return ret; - ret = coda_jpeg_define_huffman_table(0x10, luma_ac, 16 + 162, &stream); - if (ret < 0) - return ret; - if (chroma_format != CODA9_JPEG_FORMAT_400) { - ret = coda_jpeg_define_huffman_table(0x01, chroma_dc, 16 + 12, - &stream); - if (ret < 0) - return ret; - ret = coda_jpeg_define_huffman_table(0x11, chroma_ac, 16 + 162, - &stream); - if (ret < 0) - return ret; - } - - /* Start Of Frame */ - ret = coda_jpeg_put_word(SOF_MARKER, &stream); - if (ret < 0) - return ret; - comp_num = (chroma_format == CODA9_JPEG_FORMAT_400) ? 1 : 3; - ret = coda_jpeg_put_word(8 + comp_num * 3, &stream); - if (ret < 0) - return ret; - ret = coda_jpeg_put_byte(0x08, &stream); - if (ret < 0) - return ret; - ret = coda_jpeg_put_word(q_data_src->height, &stream); - if (ret < 0) - return ret; - ret = coda_jpeg_put_word(q_data_src->width, &stream); - if (ret < 0) - return ret; - ret = coda_jpeg_put_byte(comp_num, &stream); - if (ret < 0) - return ret; - for (i = 0; i < comp_num; i++) { - static unsigned char subsampling[5][3] = { - [CODA9_JPEG_FORMAT_420] = { 0x22, 0x11, 0x11 }, - [CODA9_JPEG_FORMAT_422] = { 0x21, 0x11, 0x11 }, - [CODA9_JPEG_FORMAT_224] = { 0x12, 0x11, 0x11 }, - [CODA9_JPEG_FORMAT_444] = { 0x11, 0x11, 0x11 }, - [CODA9_JPEG_FORMAT_400] = { 0x11 }, - }; - - /* Component identifier, matches SOS */ - ret = coda_jpeg_put_byte(i + 1, &stream); - if (ret < 0) - return ret; - ret = coda_jpeg_put_byte(subsampling[chroma_format][i], - &stream); - if (ret < 0) - return ret; - /* Chroma table index */ - ret = coda_jpeg_put_byte((i == 0) ? 0 : 1, &stream); - if (ret < 0) - return ret; - } - - /* Pad to multiple of 8 bytes */ - pad = (stream.curr - buf) % 8; - if (pad) { - pad = 8 - pad; - while (pad--) { - ret = coda_jpeg_put_byte(0x00, &stream); - if (ret < 0) - return ret; - } - } - - return stream.curr - buf; -} - -/* - * Scale quantization table using nonlinear scaling factor - * u8 qtab[64], scale [50,190] - */ -static void coda_scale_quant_table(u8 *q_tab, int scale) -{ - unsigned int temp; - int i; - - for (i = 0; i < 64; i++) { - temp = DIV_ROUND_CLOSEST((unsigned int)q_tab[i] * scale, 100); - if (temp <= 0) - temp = 1; - if (temp > 255) - temp = 255; - q_tab[i] = (unsigned char)temp; - } -} - -void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality) -{ - unsigned int scale; - - ctx->params.jpeg_quality = quality; - - /* Clip quality setting to [5,100] interval */ - if (quality > 100) - quality = 100; - if (quality < 5) - quality = 5; - - /* - * Non-linear scaling factor: - * [5,50] -> [1000..100], [51,100] -> [98..0] - */ - if (quality < 50) - scale = 5000 / quality; - else - scale = 200 - 2 * quality; - - if (ctx->params.jpeg_qmat_tab[0]) { - memcpy(ctx->params.jpeg_qmat_tab[0], luma_q, 64); - coda_scale_quant_table(ctx->params.jpeg_qmat_tab[0], scale); - } - if (ctx->params.jpeg_qmat_tab[1]) { - memcpy(ctx->params.jpeg_qmat_tab[1], chroma_q, 64); - coda_scale_quant_table(ctx->params.jpeg_qmat_tab[1], scale); - } -} - -/* - * Encoder context operations - */ - -static int coda9_jpeg_start_encoding(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - int ret; - - ret = coda9_jpeg_load_huff_tab(ctx); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "error loading Huffman tables\n"); - return ret; - } - if (!ctx->params.jpeg_qmat_tab[0]) { - ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL); - if (!ctx->params.jpeg_qmat_tab[0]) - return -ENOMEM; - } - if (!ctx->params.jpeg_qmat_tab[1]) { - ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL); - if (!ctx->params.jpeg_qmat_tab[1]) - return -ENOMEM; - } - coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality); - - return 0; -} - -static int coda9_jpeg_prepare_encode(struct coda_ctx *ctx) -{ - struct coda_q_data *q_data_src; - struct vb2_v4l2_buffer *src_buf, *dst_buf; - struct coda_dev *dev = ctx->dev; - u32 start_addr, end_addr; - u16 aligned_width, aligned_height; - bool chroma_interleave; - int chroma_format; - int header_len; - int ret; - ktime_t timeout; - - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - - if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == 0) - vb2_set_plane_payload(&src_buf->vb2_buf, 0, - vb2_plane_size(&src_buf->vb2_buf, 0)); - - src_buf->sequence = ctx->osequence; - dst_buf->sequence = ctx->osequence; - ctx->osequence++; - - src_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; - src_buf->flags &= ~V4L2_BUF_FLAG_PFRAME; - - coda_set_gdi_regs(ctx); - - start_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); - end_addr = start_addr + vb2_plane_size(&dst_buf->vb2_buf, 0); - - chroma_format = coda9_jpeg_chroma_format(q_data_src->fourcc); - if (chroma_format < 0) - return chroma_format; - - /* Round image dimensions to multiple of MCU size */ - aligned_width = round_up(q_data_src->width, width_align[chroma_format]); - aligned_height = round_up(q_data_src->height, - height_align[chroma_format]); - if (aligned_width != q_data_src->bytesperline) { - v4l2_err(&dev->v4l2_dev, "wrong stride: %d instead of %d\n", - aligned_width, q_data_src->bytesperline); - } - - header_len = - coda9_jpeg_encode_header(ctx, - vb2_plane_size(&dst_buf->vb2_buf, 0), - vb2_plane_vaddr(&dst_buf->vb2_buf, 0)); - if (header_len < 0) - return header_len; - - coda_write(dev, start_addr + header_len, CODA9_REG_JPEG_BBC_BAS_ADDR); - coda_write(dev, end_addr, CODA9_REG_JPEG_BBC_END_ADDR); - coda_write(dev, start_addr + header_len, CODA9_REG_JPEG_BBC_WR_PTR); - coda_write(dev, start_addr + header_len, CODA9_REG_JPEG_BBC_RD_PTR); - coda_write(dev, 0, CODA9_REG_JPEG_BBC_CUR_POS); - /* 64 words per 256-byte page */ - coda_write(dev, 64, CODA9_REG_JPEG_BBC_DATA_CNT); - coda_write(dev, start_addr, CODA9_REG_JPEG_BBC_EXT_ADDR); - coda_write(dev, 0, CODA9_REG_JPEG_BBC_INT_ADDR); - - coda_write(dev, 0, CODA9_REG_JPEG_GBU_BT_PTR); - coda_write(dev, 0, CODA9_REG_JPEG_GBU_WD_PTR); - coda_write(dev, 0, CODA9_REG_JPEG_GBU_BBSR); - coda_write(dev, BIT(31) | ((end_addr - start_addr - header_len) / 256), - CODA9_REG_JPEG_BBC_STRM_CTRL); - coda_write(dev, 0, CODA9_REG_JPEG_GBU_CTRL); - coda_write(dev, 0, CODA9_REG_JPEG_GBU_FF_RPTR); - coda_write(dev, 127, CODA9_REG_JPEG_GBU_BBER); - coda_write(dev, 64, CODA9_REG_JPEG_GBU_BBIR); - coda_write(dev, 64, CODA9_REG_JPEG_GBU_BBHR); - - chroma_interleave = (q_data_src->fourcc == V4L2_PIX_FMT_NV12); - coda_write(dev, CODA9_JPEG_PIC_CTRL_TC_DIRECTION | - CODA9_JPEG_PIC_CTRL_ENCODER_EN, CODA9_REG_JPEG_PIC_CTRL); - coda_write(dev, 0, CODA9_REG_JPEG_SCL_INFO); - coda_write(dev, chroma_interleave, CODA9_REG_JPEG_DPB_CONFIG); - coda_write(dev, ctx->params.jpeg_restart_interval, - CODA9_REG_JPEG_RST_INTVAL); - coda_write(dev, 1, CODA9_REG_JPEG_BBC_CTRL); - - coda_write(dev, bus_req_num[chroma_format], CODA9_REG_JPEG_OP_INFO); - - coda9_jpeg_write_huff_tab(ctx); - coda9_jpeg_load_qmat_tab(ctx); - - if (ctx->params.rot_mode & CODA_ROT_90) { - aligned_width = aligned_height; - aligned_height = q_data_src->bytesperline; - if (chroma_format == CODA9_JPEG_FORMAT_422) - chroma_format = CODA9_JPEG_FORMAT_224; - else if (chroma_format == CODA9_JPEG_FORMAT_224) - chroma_format = CODA9_JPEG_FORMAT_422; - } - /* These need to be multiples of MCU size */ - coda_write(dev, aligned_width << 16 | aligned_height, - CODA9_REG_JPEG_PIC_SIZE); - coda_write(dev, ctx->params.rot_mode ? - (CODA_ROT_MIR_ENABLE | ctx->params.rot_mode) : 0, - CODA9_REG_JPEG_ROT_INFO); - - coda_write(dev, mcu_info[chroma_format], CODA9_REG_JPEG_MCU_INFO); - - coda_write(dev, 1, CODA9_GDI_CONTROL); - timeout = ktime_add_us(ktime_get(), 100000); - do { - ret = coda_read(dev, CODA9_GDI_STATUS); - if (ktime_compare(ktime_get(), timeout) > 0) { - v4l2_err(&dev->v4l2_dev, "timeout waiting for GDI\n"); - return -ETIMEDOUT; - } - } while (!ret); - - coda_write(dev, (chroma_format << 17) | (chroma_interleave << 16) | - q_data_src->bytesperline, CODA9_GDI_INFO_CONTROL); - /* The content of this register seems to be irrelevant: */ - coda_write(dev, aligned_width << 16 | aligned_height, - CODA9_GDI_INFO_PIC_SIZE); - - coda_write_base(ctx, q_data_src, src_buf, CODA9_GDI_INFO_BASE_Y); - - coda_write(dev, 0, CODA9_REG_JPEG_DPB_BASE00); - coda_write(dev, 0, CODA9_GDI_CONTROL); - coda_write(dev, 1, CODA9_GDI_PIC_INIT_HOST); - - coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); - coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); - - trace_coda_jpeg_run(ctx, src_buf); - - coda_write(dev, 1, CODA9_REG_JPEG_PIC_START); - - return 0; -} - -static void coda9_jpeg_finish_encode(struct coda_ctx *ctx) -{ - struct vb2_v4l2_buffer *src_buf, *dst_buf; - struct coda_dev *dev = ctx->dev; - u32 wr_ptr, start_ptr; - u32 err_mb; - - if (ctx->aborting) { - coda_write(ctx->dev, 0, CODA9_REG_JPEG_BBC_FLUSH_CMD); - return; - } - - /* - * Lock to make sure that an encoder stop command running in parallel - * will either already have marked src_buf as last, or it will wake up - * the capture queue after the buffers are returned. - */ - mutex_lock(&ctx->wakeup_mutex); - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - - trace_coda_jpeg_done(ctx, dst_buf); - - /* - * Set plane payload to the number of bytes written out - * by the JPEG processing unit - */ - start_ptr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); - wr_ptr = coda_read(dev, CODA9_REG_JPEG_BBC_WR_PTR); - vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr); - - err_mb = coda_read(dev, CODA9_REG_JPEG_PIC_ERRMB); - if (err_mb) - coda_dbg(1, ctx, "ERRMB: 0x%x\n", err_mb); - - coda_write(dev, 0, CODA9_REG_JPEG_BBC_FLUSH_CMD); - - dst_buf->flags &= ~(V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_LAST); - dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; - dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; - - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); - - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - coda_m2m_buf_done(ctx, dst_buf, err_mb ? VB2_BUF_STATE_ERROR : - VB2_BUF_STATE_DONE); - mutex_unlock(&ctx->wakeup_mutex); - - coda_dbg(1, ctx, "job finished: encoded frame (%u)%s\n", - dst_buf->sequence, - (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); - - /* - * Reset JPEG processing unit after each encode run to work - * around hangups when switching context between encoder and - * decoder. - */ - coda_hw_reset(ctx); -} - -static void coda9_jpeg_encode_timeout(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - u32 end_addr, wr_ptr; - - /* Handle missing BBC overflow interrupt via timeout */ - end_addr = coda_read(dev, CODA9_REG_JPEG_BBC_END_ADDR); - wr_ptr = coda_read(dev, CODA9_REG_JPEG_BBC_WR_PTR); - if (wr_ptr >= end_addr - 256) { - v4l2_err(&dev->v4l2_dev, "JPEG too large for capture buffer\n"); - coda9_jpeg_finish_encode(ctx); - return; - } - - coda_hw_reset(ctx); -} - -static void coda9_jpeg_release(struct coda_ctx *ctx) -{ - int i; - - if (ctx->params.jpeg_qmat_tab[0] == luma_q) - ctx->params.jpeg_qmat_tab[0] = NULL; - if (ctx->params.jpeg_qmat_tab[1] == chroma_q) - ctx->params.jpeg_qmat_tab[1] = NULL; - for (i = 0; i < 3; i++) - kfree(ctx->params.jpeg_qmat_tab[i]); - kfree(ctx->params.jpeg_huff_data); - kfree(ctx->params.jpeg_huff_tab); -} - -const struct coda_context_ops coda9_jpeg_encode_ops = { - .queue_init = coda_encoder_queue_init, - .start_streaming = coda9_jpeg_start_encoding, - .prepare_run = coda9_jpeg_prepare_encode, - .finish_run = coda9_jpeg_finish_encode, - .run_timeout = coda9_jpeg_encode_timeout, - .release = coda9_jpeg_release, -}; - -/* - * Decoder context operations - */ - -static int coda9_jpeg_start_decoding(struct coda_ctx *ctx) -{ - ctx->params.jpeg_qmat_index[0] = 0; - ctx->params.jpeg_qmat_index[1] = 1; - ctx->params.jpeg_qmat_index[2] = 1; - ctx->params.jpeg_qmat_tab[0] = luma_q; - ctx->params.jpeg_qmat_tab[1] = chroma_q; - /* nothing more to do here */ - - /* TODO: we could already scan the first header to get the chroma - * format. - */ - - return 0; -} - -static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - int aligned_width, aligned_height; - int chroma_format; - int ret; - u32 val, dst_fourcc; - struct coda_q_data *q_data_src, *q_data_dst; - struct vb2_v4l2_buffer *src_buf, *dst_buf; - int chroma_interleave; - int scl_hor_mode, scl_ver_mode; - - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_fourcc = q_data_dst->fourcc; - - scl_hor_mode = coda_jpeg_scale(q_data_src->width, q_data_dst->width); - scl_ver_mode = coda_jpeg_scale(q_data_src->height, q_data_dst->height); - - if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == 0) - vb2_set_plane_payload(&src_buf->vb2_buf, 0, - vb2_plane_size(&src_buf->vb2_buf, 0)); - - chroma_format = coda9_jpeg_chroma_format(q_data_dst->fourcc); - if (chroma_format < 0) - return chroma_format; - - ret = coda_jpeg_decode_header(ctx, &src_buf->vb2_buf); - if (ret < 0) { - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); - - return ret; - } - - /* Round image dimensions to multiple of MCU size */ - aligned_width = round_up(q_data_src->width, width_align[chroma_format]); - aligned_height = round_up(q_data_src->height, height_align[chroma_format]); - if (aligned_width != q_data_dst->bytesperline) { - v4l2_err(&dev->v4l2_dev, "stride mismatch: %d != %d\n", - aligned_width, q_data_dst->bytesperline); - } - - coda_set_gdi_regs(ctx); - - val = ctx->params.jpeg_huff_ac_index[0] << 12 | - ctx->params.jpeg_huff_ac_index[1] << 11 | - ctx->params.jpeg_huff_ac_index[2] << 10 | - ctx->params.jpeg_huff_dc_index[0] << 9 | - ctx->params.jpeg_huff_dc_index[1] << 8 | - ctx->params.jpeg_huff_dc_index[2] << 7; - if (ctx->params.jpeg_huff_tab) - val |= CODA9_JPEG_PIC_CTRL_USER_HUFFMAN_EN; - coda_write(dev, val, CODA9_REG_JPEG_PIC_CTRL); - - coda_write(dev, aligned_width << 16 | aligned_height, - CODA9_REG_JPEG_PIC_SIZE); - - chroma_interleave = (dst_fourcc == V4L2_PIX_FMT_NV12); - coda_write(dev, 0, CODA9_REG_JPEG_ROT_INFO); - coda_write(dev, bus_req_num[chroma_format], CODA9_REG_JPEG_OP_INFO); - coda_write(dev, mcu_info[chroma_format], CODA9_REG_JPEG_MCU_INFO); - if (scl_hor_mode || scl_ver_mode) - val = CODA9_JPEG_SCL_ENABLE | (scl_hor_mode << 2) | scl_ver_mode; - else - val = 0; - coda_write(dev, val, CODA9_REG_JPEG_SCL_INFO); - coda_write(dev, chroma_interleave, CODA9_REG_JPEG_DPB_CONFIG); - coda_write(dev, ctx->params.jpeg_restart_interval, - CODA9_REG_JPEG_RST_INTVAL); - - if (ctx->params.jpeg_huff_tab) - coda9_jpeg_dec_huff_setup(ctx); - - coda9_jpeg_qmat_setup(ctx); - - coda9_jpeg_dec_bbc_gbu_setup(ctx, &src_buf->vb2_buf, - ctx->jpeg_ecs_offset); - - coda_write(dev, 0, CODA9_REG_JPEG_RST_INDEX); - coda_write(dev, 0, CODA9_REG_JPEG_RST_COUNT); - - coda_write(dev, 0, CODA9_REG_JPEG_DPCM_DIFF_Y); - coda_write(dev, 0, CODA9_REG_JPEG_DPCM_DIFF_CB); - coda_write(dev, 0, CODA9_REG_JPEG_DPCM_DIFF_CR); - - coda_write(dev, 0, CODA9_REG_JPEG_ROT_INFO); - - coda_write(dev, 1, CODA9_GDI_CONTROL); - do { - ret = coda_read(dev, CODA9_GDI_STATUS); - } while (!ret); - - val = (chroma_format << 17) | (chroma_interleave << 16) | - q_data_dst->bytesperline; - if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) - val |= 3 << 20; - coda_write(dev, val, CODA9_GDI_INFO_CONTROL); - - coda_write(dev, aligned_width << 16 | aligned_height, - CODA9_GDI_INFO_PIC_SIZE); - - coda_write_base(ctx, q_data_dst, dst_buf, CODA9_GDI_INFO_BASE_Y); - - coda_write(dev, 0, CODA9_REG_JPEG_DPB_BASE00); - coda_write(dev, 0, CODA9_GDI_CONTROL); - coda_write(dev, 1, CODA9_GDI_PIC_INIT_HOST); - - trace_coda_jpeg_run(ctx, src_buf); - - coda_write(dev, 1, CODA9_REG_JPEG_PIC_START); - - return 0; -} - -static void coda9_jpeg_finish_decode(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - struct vb2_v4l2_buffer *dst_buf, *src_buf; - struct coda_q_data *q_data_dst; - u32 err_mb; - - err_mb = coda_read(dev, CODA9_REG_JPEG_PIC_ERRMB); - if (err_mb) - v4l2_err(&dev->v4l2_dev, "ERRMB: 0x%x\n", err_mb); - - coda_write(dev, 0, CODA9_REG_JPEG_BBC_FLUSH_CMD); - - /* - * Lock to make sure that a decoder stop command running in parallel - * will either already have marked src_buf as last, or it will wake up - * the capture queue after the buffers are returned. - */ - mutex_lock(&ctx->wakeup_mutex); - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - dst_buf->sequence = ctx->osequence++; - - trace_coda_jpeg_done(ctx, dst_buf); - - dst_buf->flags &= ~(V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_LAST); - dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; - dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; - - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); - - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - vb2_set_plane_payload(&dst_buf->vb2_buf, 0, q_data_dst->sizeimage); - - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - coda_m2m_buf_done(ctx, dst_buf, err_mb ? VB2_BUF_STATE_ERROR : - VB2_BUF_STATE_DONE); - - mutex_unlock(&ctx->wakeup_mutex); - - coda_dbg(1, ctx, "job finished: decoded frame (%u)%s\n", - dst_buf->sequence, - (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); - - /* - * Reset JPEG processing unit after each decode run to work - * around hangups when switching context between encoder and - * decoder. - */ - coda_hw_reset(ctx); -} - -const struct coda_context_ops coda9_jpeg_decode_ops = { - .queue_init = coda_encoder_queue_init, /* non-bitstream operation */ - .start_streaming = coda9_jpeg_start_decoding, - .prepare_run = coda9_jpeg_prepare_decode, - .finish_run = coda9_jpeg_finish_decode, - .release = coda9_jpeg_release, -}; - -irqreturn_t coda9_jpeg_irq_handler(int irq, void *data) -{ - struct coda_dev *dev = data; - struct coda_ctx *ctx; - int status; - int err_mb; - - status = coda_read(dev, CODA9_REG_JPEG_PIC_STATUS); - if (status == 0) - return IRQ_HANDLED; - coda_write(dev, status, CODA9_REG_JPEG_PIC_STATUS); - - if (status & CODA9_JPEG_STATUS_OVERFLOW) - v4l2_err(&dev->v4l2_dev, "JPEG overflow\n"); - - if (status & CODA9_JPEG_STATUS_BBC_INT) - v4l2_err(&dev->v4l2_dev, "JPEG BBC interrupt\n"); - - if (status & CODA9_JPEG_STATUS_ERROR) { - v4l2_err(&dev->v4l2_dev, "JPEG error\n"); - - err_mb = coda_read(dev, CODA9_REG_JPEG_PIC_ERRMB); - if (err_mb) { - v4l2_err(&dev->v4l2_dev, - "ERRMB: 0x%x: rst idx %d, mcu pos (%d,%d)\n", - err_mb, err_mb >> 24, (err_mb >> 12) & 0xfff, - err_mb & 0xfff); - } - } - - ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); - if (!ctx) { - v4l2_err(&dev->v4l2_dev, - "Instance released before the end of transaction\n"); - mutex_unlock(&dev->coda_mutex); - return IRQ_HANDLED; - } - - complete(&ctx->completion); - - return IRQ_HANDLED; -} diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda-mpeg2.c b/drivers/media/platform/chips-media/coda-mpeg2.c --- a/drivers/media/platform/chips-media/coda-mpeg2.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/coda-mpeg2.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Coda multi-standard codec IP - MPEG-2 helper functions - * - * Copyright (C) 2019 Pengutronix, Philipp Zabel - */ - -#include -#include -#include "coda.h" - -int coda_mpeg2_profile(int profile_idc) -{ - switch (profile_idc) { - case 5: - return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE; - case 4: - return V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN; - case 3: - return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SNR_SCALABLE; - case 2: - return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SPATIALLY_SCALABLE; - case 1: - return V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH; - default: - return -EINVAL; - } -} - -int coda_mpeg2_level(int level_idc) -{ - switch (level_idc) { - case 10: - return V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW; - case 8: - return V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN; - case 6: - return V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440; - case 4: - return V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH; - default: - return -EINVAL; - } -} - -/* - * Check if the buffer starts with the MPEG-2 sequence header (with or without - * quantization matrix) and extension header, for example: - * - * 00 00 01 b3 2d 01 e0 34 08 8b a3 81 - * 10 11 11 12 12 12 13 13 13 13 14 14 14 14 14 15 - * 15 15 15 15 15 16 16 16 16 16 16 16 17 17 17 17 - * 17 17 17 17 18 18 18 19 18 18 18 19 1a 1a 1a 1a - * 19 1b 1b 1b 1b 1b 1c 1c 1c 1c 1e 1e 1e 1f 1f 21 - * 00 00 01 b5 14 8a 00 01 00 00 - * - * or: - * - * 00 00 01 b3 08 00 40 15 ff ff e0 28 - * 00 00 01 b5 14 8a 00 01 00 00 - * - * Returns the detected header size in bytes or 0. - */ -u32 coda_mpeg2_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size) -{ - static const u8 sequence_header_start[4] = { 0x00, 0x00, 0x01, 0xb3 }; - static const union { - u8 extension_start[4]; - u8 start_code_prefix[3]; - } u = { { 0x00, 0x00, 0x01, 0xb5 } }; - - if (size < 22 || - memcmp(buf, sequence_header_start, 4) != 0) - return 0; - - if ((size == 22 || - (size >= 25 && memcmp(buf + 22, u.start_code_prefix, 3) == 0)) && - memcmp(buf + 12, u.extension_start, 4) == 0) - return 22; - - if ((size == 86 || - (size > 89 && memcmp(buf + 86, u.start_code_prefix, 3) == 0)) && - memcmp(buf + 76, u.extension_start, 4) == 0) - return 86; - - return 0; -} diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda-mpeg4.c b/drivers/media/platform/chips-media/coda-mpeg4.c --- a/drivers/media/platform/chips-media/coda-mpeg4.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/coda-mpeg4.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Coda multi-standard codec IP - MPEG-4 helper functions - * - * Copyright (C) 2019 Pengutronix, Philipp Zabel - */ - -#include -#include - -#include "coda.h" - -int coda_mpeg4_profile(int profile_idc) -{ - switch (profile_idc) { - case 0: - return V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE; - case 15: - return V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE; - case 2: - return V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE; - case 1: - return V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE; - case 11: - return V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY; - default: - return -EINVAL; - } -} - -int coda_mpeg4_level(int level_idc) -{ - switch (level_idc) { - case 0: - return V4L2_MPEG_VIDEO_MPEG4_LEVEL_0; - case 1: - return V4L2_MPEG_VIDEO_MPEG4_LEVEL_1; - case 2: - return V4L2_MPEG_VIDEO_MPEG4_LEVEL_2; - case 3: - return V4L2_MPEG_VIDEO_MPEG4_LEVEL_3; - case 4: - return V4L2_MPEG_VIDEO_MPEG4_LEVEL_4; - case 5: - return V4L2_MPEG_VIDEO_MPEG4_LEVEL_5; - default: - return -EINVAL; - } -} - -/* - * Check if the buffer starts with the MPEG-4 visual object sequence and visual - * object headers, for example: - * - * 00 00 01 b0 f1 - * 00 00 01 b5 a9 13 00 00 01 00 00 00 01 20 08 - * d4 8d 88 00 f5 04 04 08 14 30 3f - * - * Returns the detected header size in bytes or 0. - */ -u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size) -{ - static const u8 vos_start[4] = { 0x00, 0x00, 0x01, 0xb0 }; - static const union { - u8 vo_start[4]; - u8 start_code_prefix[3]; - } u = { { 0x00, 0x00, 0x01, 0xb5 } }; - - if (size < 30 || - memcmp(buf, vos_start, 4) != 0 || - memcmp(buf + 5, u.vo_start, 4) != 0) - return 0; - - if (size == 30 || - (size >= 33 && memcmp(buf + 30, u.start_code_prefix, 3) == 0)) - return 30; - - if (size == 31 || - (size >= 34 && memcmp(buf + 31, u.start_code_prefix, 3) == 0)) - return 31; - - if (size == 32 || - (size >= 35 && memcmp(buf + 32, u.start_code_prefix, 3) == 0)) - return 32; - - return 0; -} diff -Naur --no-dereference a/drivers/media/platform/chips-media/coda_regs.h b/drivers/media/platform/chips-media/coda_regs.h --- a/drivers/media/platform/chips-media/coda_regs.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/coda_regs.h 1969-12-31 19:00:00.000000000 -0500 @@ -1,563 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * linux/drivers/media/platform/chips-media/coda_regs.h - * - * Copyright (C) 2012 Vista Silicon SL - * Javier Martin - * Xavier Duret - */ - -#ifndef _REGS_CODA_H_ -#define _REGS_CODA_H_ - -/* HW registers */ -#define CODA_REG_BIT_CODE_RUN 0x000 -#define CODA_REG_RUN_ENABLE (1 << 0) -#define CODA_REG_BIT_CODE_DOWN 0x004 -#define CODA_DOWN_ADDRESS_SET(x) (((x) & 0xffff) << 16) -#define CODA_DOWN_DATA_SET(x) ((x) & 0xffff) -#define CODA_REG_BIT_HOST_IN_REQ 0x008 -#define CODA_REG_BIT_INT_CLEAR 0x00c -#define CODA_REG_BIT_INT_CLEAR_SET 0x1 -#define CODA_REG_BIT_INT_STATUS 0x010 -#define CODA_REG_BIT_CODE_RESET 0x014 -#define CODA_REG_RESET_ENABLE (1 << 0) -#define CODA_REG_BIT_CUR_PC 0x018 -#define CODA9_REG_BIT_SW_RESET 0x024 -#define CODA9_SW_RESET_BPU_CORE 0x008 -#define CODA9_SW_RESET_BPU_BUS 0x010 -#define CODA9_SW_RESET_VCE_CORE 0x020 -#define CODA9_SW_RESET_VCE_BUS 0x040 -#define CODA9_SW_RESET_GDI_CORE 0x080 -#define CODA9_SW_RESET_GDI_BUS 0x100 -#define CODA9_REG_BIT_SW_RESET_STATUS 0x034 - -/* Static SW registers */ -#define CODA_REG_BIT_CODE_BUF_ADDR 0x100 -#define CODA_REG_BIT_WORK_BUF_ADDR 0x104 -#define CODA_REG_BIT_PARA_BUF_ADDR 0x108 -#define CODA_REG_BIT_STREAM_CTRL 0x10c -#define CODA7_STREAM_BUF_PIC_RESET (1 << 4) -#define CODADX6_STREAM_BUF_PIC_RESET (1 << 3) -#define CODA7_STREAM_BUF_PIC_FLUSH (1 << 3) -#define CODADX6_STREAM_BUF_PIC_FLUSH (1 << 2) -#define CODA7_STREAM_BUF_DYNALLOC_EN (1 << 5) -#define CODADX6_STREAM_BUF_DYNALLOC_EN (1 << 4) -#define CODADX6_STREAM_CHKDIS_OFFSET (1 << 1) -#define CODA7_STREAM_SEL_64BITS_ENDIAN (1 << 1) -#define CODA_STREAM_ENDIAN_SELECT (1 << 0) -#define CODA_REG_BIT_FRAME_MEM_CTRL 0x110 -#define CODA9_FRAME_ENABLE_BWB (1 << 12) -#define CODA9_FRAME_TILED2LINEAR (1 << 11) -#define CODA_FRAME_CHROMA_INTERLEAVE (1 << 2) -#define CODA_IMAGE_ENDIAN_SELECT (1 << 0) -#define CODA_REG_BIT_BIT_STREAM_PARAM 0x114 -#define CODA_BIT_STREAM_END_FLAG (1 << 2) -#define CODA_BIT_DEC_SEQ_INIT_ESCAPE (1 << 0) -#define CODA_REG_BIT_TEMP_BUF_ADDR 0x118 -#define CODA_REG_BIT_RD_PTR(x) (0x120 + 8 * (x)) -#define CODA_REG_BIT_WR_PTR(x) (0x124 + 8 * (x)) -#define CODA_REG_BIT_FRM_DIS_FLG(x) (0x150 + 4 * (x)) -#define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR 0x140 -#define CODA7_REG_BIT_AXI_SRAM_USE 0x140 -#define CODA9_USE_HOST_BTP_ENABLE (1 << 13) -#define CODA9_USE_HOST_OVL_ENABLE (1 << 12) -#define CODA7_USE_HOST_ME_ENABLE (1 << 11) -#define CODA9_USE_HOST_DBK_ENABLE (3 << 10) -#define CODA7_USE_HOST_OVL_ENABLE (1 << 10) -#define CODA7_USE_HOST_DBK_ENABLE (1 << 9) -#define CODA9_USE_HOST_IP_ENABLE (1 << 9) -#define CODA7_USE_HOST_IP_ENABLE (1 << 8) -#define CODA9_USE_HOST_BIT_ENABLE (1 << 8) -#define CODA7_USE_HOST_BIT_ENABLE (1 << 7) -#define CODA9_USE_BTP_ENABLE (1 << 5) -#define CODA7_USE_ME_ENABLE (1 << 4) -#define CODA9_USE_OVL_ENABLE (1 << 4) -#define CODA7_USE_OVL_ENABLE (1 << 3) -#define CODA9_USE_DBK_ENABLE (3 << 2) -#define CODA7_USE_DBK_ENABLE (1 << 2) -#define CODA7_USE_IP_ENABLE (1 << 1) -#define CODA7_USE_BIT_ENABLE (1 << 0) - -#define CODA_REG_BIT_BUSY 0x160 -#define CODA_REG_BIT_BUSY_FLAG 1 -#define CODA_REG_BIT_RUN_COMMAND 0x164 -#define CODA_COMMAND_SEQ_INIT 1 -#define CODA_COMMAND_SEQ_END 2 -#define CODA_COMMAND_PIC_RUN 3 -#define CODA_COMMAND_SET_FRAME_BUF 4 -#define CODA_COMMAND_ENCODE_HEADER 5 -#define CODA_COMMAND_ENC_PARA_SET 6 -#define CODA_COMMAND_DEC_PARA_SET 7 -#define CODA_COMMAND_DEC_BUF_FLUSH 8 -#define CODA_COMMAND_RC_CHANGE_PARAMETER 9 -#define CODA_COMMAND_FIRMWARE_GET 0xf -#define CODA_REG_BIT_RUN_INDEX 0x168 -#define CODA_INDEX_SET(x) ((x) & 0x3) -#define CODA_REG_BIT_RUN_COD_STD 0x16c -#define CODADX6_MODE_DECODE_MP4 0 -#define CODADX6_MODE_ENCODE_MP4 1 -#define CODADX6_MODE_DECODE_H264 2 -#define CODADX6_MODE_ENCODE_H264 3 -#define CODA7_MODE_DECODE_H264 0 -#define CODA7_MODE_DECODE_VC1 1 -#define CODA7_MODE_DECODE_MP2 2 -#define CODA7_MODE_DECODE_MP4 3 -#define CODA7_MODE_DECODE_DV3 3 -#define CODA7_MODE_DECODE_RV 4 -#define CODA7_MODE_DECODE_MJPG 5 -#define CODA7_MODE_ENCODE_H264 8 -#define CODA7_MODE_ENCODE_MP4 11 -#define CODA7_MODE_ENCODE_MJPG 13 -#define CODA9_MODE_DECODE_H264 0 -#define CODA9_MODE_DECODE_VC1 1 -#define CODA9_MODE_DECODE_MP2 2 -#define CODA9_MODE_DECODE_MP4 3 -#define CODA9_MODE_DECODE_DV3 3 -#define CODA9_MODE_DECODE_RV 4 -#define CODA9_MODE_DECODE_AVS 5 -#define CODA9_MODE_DECODE_MJPG 6 -#define CODA9_MODE_DECODE_VPX 7 -#define CODA9_MODE_ENCODE_H264 8 -#define CODA9_MODE_ENCODE_MP4 11 -#define CODA9_MODE_ENCODE_MJPG 13 -#define CODA_MODE_INVALID 0xffff -#define CODA_REG_BIT_INT_ENABLE 0x170 -#define CODA_INT_INTERRUPT_ENABLE (1 << 3) -#define CODA_REG_BIT_INT_REASON 0x174 -#define CODA7_REG_BIT_RUN_AUX_STD 0x178 -#define CODA_MP4_AUX_MPEG4 0 -#define CODA_MP4_AUX_DIVX3 1 -#define CODA_VPX_AUX_THO 0 -#define CODA_VPX_AUX_VP6 1 -#define CODA_VPX_AUX_VP8 2 -#define CODA_H264_AUX_AVC 0 -#define CODA_H264_AUX_MVC 1 - -/* - * Commands' mailbox: - * registers with offsets in the range 0x180-0x1d0 - * have different meaning depending on the command being - * issued. - */ - -/* Decoder Sequence Initialization */ -#define CODA_CMD_DEC_SEQ_BB_START 0x180 -#define CODA_CMD_DEC_SEQ_BB_SIZE 0x184 -#define CODA_CMD_DEC_SEQ_OPTION 0x188 -#define CODA_NO_INT_ENABLE (1 << 10) -#define CODA_REORDER_ENABLE (1 << 1) -#define CODADX6_QP_REPORT (1 << 0) -#define CODA7_MP4_DEBLK_ENABLE (1 << 0) -#define CODA_CMD_DEC_SEQ_SRC_SIZE 0x18c -#define CODA_CMD_DEC_SEQ_START_BYTE 0x190 -#define CODA_CMD_DEC_SEQ_PS_BB_START 0x194 -#define CODA_CMD_DEC_SEQ_PS_BB_SIZE 0x198 -#define CODA_CMD_DEC_SEQ_JPG_THUMB_EN 0x19c -#define CODA_CMD_DEC_SEQ_MP4_ASP_CLASS 0x19c -#define CODA_MP4_CLASS_MPEG4 0 -#define CODA_CMD_DEC_SEQ_X264_MV_EN 0x19c -#define CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE 0x1a0 - -#define CODA7_RET_DEC_SEQ_ASPECT 0x1b0 -#define CODA9_RET_DEC_SEQ_BITRATE 0x1b4 -#define CODA_RET_DEC_SEQ_SUCCESS 0x1c0 -#define CODA_RET_DEC_SEQ_SRC_FMT 0x1c4 /* SRC_SIZE on CODA7 */ -#define CODA_RET_DEC_SEQ_SRC_SIZE 0x1c4 -#define CODA_RET_DEC_SEQ_SRC_F_RATE 0x1c8 -#define CODA9_RET_DEC_SEQ_ASPECT 0x1c8 -#define CODA_RET_DEC_SEQ_FRAME_NEED 0x1cc -#define CODA_RET_DEC_SEQ_FRAME_DELAY 0x1d0 -#define CODA_RET_DEC_SEQ_INFO 0x1d4 -#define CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT 0x1d8 -#define CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM 0x1dc -#define CODA_RET_DEC_SEQ_NEXT_FRAME_NUM 0x1e0 -#define CODA_RET_DEC_SEQ_ERR_REASON 0x1e0 -#define CODA_RET_DEC_SEQ_FRATE_NR 0x1e4 -#define CODA_RET_DEC_SEQ_FRATE_DR 0x1e8 -#define CODA_RET_DEC_SEQ_JPG_PARA 0x1e4 -#define CODA_RET_DEC_SEQ_JPG_THUMB_IND 0x1e8 -#define CODA7_RET_DEC_SEQ_HEADER_REPORT 0x1ec - -/* Decoder Picture Run */ -#define CODA_CMD_DEC_PIC_ROT_MODE 0x180 -#define CODA_CMD_DEC_PIC_ROT_ADDR_Y 0x184 -#define CODA9_CMD_DEC_PIC_ROT_INDEX 0x184 -#define CODA_CMD_DEC_PIC_ROT_ADDR_CB 0x188 -#define CODA9_CMD_DEC_PIC_ROT_ADDR_Y 0x188 -#define CODA_CMD_DEC_PIC_ROT_ADDR_CR 0x18c -#define CODA9_CMD_DEC_PIC_ROT_ADDR_CB 0x18c -#define CODA_CMD_DEC_PIC_ROT_STRIDE 0x190 -#define CODA9_CMD_DEC_PIC_ROT_ADDR_CR 0x190 -#define CODA9_CMD_DEC_PIC_ROT_STRIDE 0x1b8 - -#define CODA_CMD_DEC_PIC_OPTION 0x194 -#define CODA_PRE_SCAN_EN (1 << 0) -#define CODA_PRE_SCAN_MODE_DECODE (0 << 1) -#define CODA_PRE_SCAN_MODE_RETURN (1 << 1) -#define CODA_IFRAME_SEARCH_EN (1 << 2) -#define CODA_SKIP_FRAME_MODE (0x3 << 3) -#define CODA_CMD_DEC_PIC_SKIP_NUM 0x198 -#define CODA_CMD_DEC_PIC_CHUNK_SIZE 0x19c -#define CODA_CMD_DEC_PIC_BB_START 0x1a0 -#define CODA_CMD_DEC_PIC_START_BYTE 0x1a4 -#define CODA_RET_DEC_PIC_SIZE 0x1bc -#define CODA_RET_DEC_PIC_FRAME_NUM 0x1c0 -#define CODA_RET_DEC_PIC_FRAME_IDX 0x1c4 -#define CODA_RET_DEC_PIC_ERR_MB 0x1c8 -#define CODA_RET_DEC_PIC_TYPE 0x1cc -#define CODA_PIC_TYPE_MASK 0x7 -#define CODA_PIC_TYPE_MASK_VC1 0x3f -#define CODA9_PIC_TYPE_FIRST_MASK (0x7 << 3) -#define CODA9_PIC_TYPE_IDR_MASK (0x3 << 6) -#define CODA7_PIC_TYPE_H264_NPF_MASK (0x3 << 16) -#define CODA7_PIC_TYPE_INTERLACED (1 << 18) -#define CODA_RET_DEC_PIC_POST 0x1d0 -#define CODA_RET_DEC_PIC_MVC_REPORT 0x1d0 -#define CODA_RET_DEC_PIC_OPTION 0x1d4 -#define CODA_RET_DEC_PIC_SUCCESS 0x1d8 -#define CODA_RET_DEC_PIC_CUR_IDX 0x1dc -#define CODA_RET_DEC_PIC_CROP_LEFT_RIGHT 0x1e0 -#define CODA_RET_DEC_PIC_CROP_TOP_BOTTOM 0x1e4 -#define CODA_RET_DEC_PIC_FRAME_NEED 0x1ec - -#define CODA9_RET_DEC_PIC_VP8_PIC_REPORT 0x1e8 -#define CODA9_RET_DEC_PIC_ASPECT 0x1f0 -#define CODA9_RET_DEC_PIC_VP8_SCALE_INFO 0x1f0 -#define CODA9_RET_DEC_PIC_FRATE_NR 0x1f4 -#define CODA9_RET_DEC_PIC_FRATE_DR 0x1f8 - -/* Encoder Sequence Initialization */ -#define CODA_CMD_ENC_SEQ_BB_START 0x180 -#define CODA_CMD_ENC_SEQ_BB_SIZE 0x184 -#define CODA_CMD_ENC_SEQ_OPTION 0x188 -#define CODA7_OPTION_AVCINTRA16X16ONLY_OFFSET 9 -#define CODA9_OPTION_MVC_PREFIX_NAL_OFFSET 9 -#define CODA7_OPTION_GAMMA_OFFSET 8 -#define CODA9_OPTION_MVC_PARASET_REFRESH_OFFSET 8 -#define CODA7_OPTION_RCQPMAX_OFFSET 7 -#define CODA9_OPTION_GAMMA_OFFSET 7 -#define CODADX6_OPTION_GAMMA_OFFSET 7 -#define CODA7_OPTION_RCQPMIN_OFFSET 6 -#define CODA9_OPTION_RCQPMAX_OFFSET 6 -#define CODA_OPTION_LIMITQP_OFFSET 6 -#define CODA_OPTION_RCINTRAQP_OFFSET 5 -#define CODA_OPTION_FMO_OFFSET 4 -#define CODA9_OPTION_MVC_INTERVIEW_OFFSET 4 -#define CODA_OPTION_AVC_AUD_OFFSET 2 -#define CODA_OPTION_SLICEREPORT_OFFSET 1 -#define CODA_CMD_ENC_SEQ_COD_STD 0x18c -#define CODA_STD_MPEG4 0 -#define CODA9_STD_H264 0 -#define CODA_STD_H263 1 -#define CODA_STD_H264 2 -#define CODA9_STD_MPEG4 3 - -#define CODA_CMD_ENC_SEQ_SRC_SIZE 0x190 -#define CODA7_PICWIDTH_OFFSET 16 -#define CODA7_PICWIDTH_MASK 0xffff -#define CODADX6_PICWIDTH_OFFSET 10 -#define CODADX6_PICWIDTH_MASK 0x3ff -#define CODA_PICHEIGHT_OFFSET 0 -#define CODADX6_PICHEIGHT_MASK 0x3ff -#define CODA7_PICHEIGHT_MASK 0xffff -#define CODA_CMD_ENC_SEQ_SRC_F_RATE 0x194 -#define CODA_FRATE_RES_OFFSET 0 -#define CODA_FRATE_RES_MASK 0xffff -#define CODA_FRATE_DIV_OFFSET 16 -#define CODA_FRATE_DIV_MASK 0xffff -#define CODA_CMD_ENC_SEQ_MP4_PARA 0x198 -#define CODA_MP4PARAM_VERID_OFFSET 6 -#define CODA_MP4PARAM_VERID_MASK 0x01 -#define CODA_MP4PARAM_INTRADCVLCTHR_OFFSET 2 -#define CODA_MP4PARAM_INTRADCVLCTHR_MASK 0x07 -#define CODA_MP4PARAM_REVERSIBLEVLCENABLE_OFFSET 1 -#define CODA_MP4PARAM_REVERSIBLEVLCENABLE_MASK 0x01 -#define CODA_MP4PARAM_DATAPARTITIONENABLE_OFFSET 0 -#define CODA_MP4PARAM_DATAPARTITIONENABLE_MASK 0x01 -#define CODA_CMD_ENC_SEQ_263_PARA 0x19c -#define CODA_263PARAM_ANNEXJENABLE_OFFSET 2 -#define CODA_263PARAM_ANNEXJENABLE_MASK 0x01 -#define CODA_263PARAM_ANNEXKENABLE_OFFSET 1 -#define CODA_263PARAM_ANNEXKENABLE_MASK 0x01 -#define CODA_263PARAM_ANNEXTENABLE_OFFSET 0 -#define CODA_263PARAM_ANNEXTENABLE_MASK 0x01 -#define CODA_CMD_ENC_SEQ_264_PARA 0x1a0 -#define CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET 12 -#define CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK 0x0f -#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET 8 -#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK 0x0f -#define CODA_264PARAM_DISABLEDEBLK_OFFSET 6 -#define CODA_264PARAM_DISABLEDEBLK_MASK 0x03 -#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET 5 -#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK 0x01 -#define CODA_264PARAM_CHROMAQPOFFSET_OFFSET 0 -#define CODA_264PARAM_CHROMAQPOFFSET_MASK 0x1f -#define CODA_CMD_ENC_SEQ_SLICE_MODE 0x1a4 -#define CODA_SLICING_SIZE_OFFSET 2 -#define CODA_SLICING_SIZE_MASK 0x3fffffff -#define CODA_SLICING_UNIT_OFFSET 1 -#define CODA_SLICING_UNIT_MASK 0x01 -#define CODA_SLICING_MODE_OFFSET 0 -#define CODA_SLICING_MODE_MASK 0x01 -#define CODA_CMD_ENC_SEQ_GOP_SIZE 0x1a8 -#define CODA_GOP_SIZE_OFFSET 0 -#define CODA_GOP_SIZE_MASK 0x3f -#define CODA_CMD_ENC_SEQ_RC_PARA 0x1ac -#define CODA_RATECONTROL_AUTOSKIP_OFFSET 31 -#define CODA_RATECONTROL_AUTOSKIP_MASK 0x01 -#define CODA_RATECONTROL_INITIALDELAY_OFFSET 16 -#define CODA_RATECONTROL_INITIALDELAY_MASK 0x7fff -#define CODA_RATECONTROL_BITRATE_OFFSET 1 -#define CODA_RATECONTROL_BITRATE_MASK 0x7fff -#define CODA_RATECONTROL_ENABLE_OFFSET 0 -#define CODA_RATECONTROL_ENABLE_MASK 0x01 -#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE 0x1b0 -#define CODA_CMD_ENC_SEQ_INTRA_REFRESH 0x1b4 -#define CODADX6_CMD_ENC_SEQ_FMO 0x1b8 -#define CODA_FMOPARAM_TYPE_OFFSET 4 -#define CODA_FMOPARAM_TYPE_MASK 1 -#define CODA_FMOPARAM_SLICENUM_OFFSET 0 -#define CODA_FMOPARAM_SLICENUM_MASK 0x0f -#define CODADX6_CMD_ENC_SEQ_INTRA_QP 0x1bc -#define CODA7_CMD_ENC_SEQ_SEARCH_BASE 0x1b8 -#define CODA7_CMD_ENC_SEQ_SEARCH_SIZE 0x1bc -#define CODA7_CMD_ENC_SEQ_INTRA_QP 0x1c4 -#define CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX 0x1c8 -#define CODA_QPMIN_OFFSET 8 -#define CODA_QPMIN_MASK 0x3f -#define CODA_QPMAX_OFFSET 0 -#define CODA_QPMAX_MASK 0x3f -#define CODA_CMD_ENC_SEQ_RC_GAMMA 0x1cc -#define CODA_GAMMA_OFFSET 0 -#define CODA_GAMMA_MASK 0xffff -#define CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE 0x1d0 -#define CODA9_CMD_ENC_SEQ_INTRA_WEIGHT 0x1d4 -#define CODA9_CMD_ENC_SEQ_ME_OPTION 0x1d8 -#define CODA_RET_ENC_SEQ_SUCCESS 0x1c0 - -#define CODA_CMD_ENC_SEQ_JPG_PARA 0x198 -#define CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL 0x19C -#define CODA_CMD_ENC_SEQ_JPG_THUMB_EN 0x1a0 -#define CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE 0x1a4 -#define CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET 0x1a8 - -/* Encoder Parameter Change */ -#define CODA_CMD_ENC_PARAM_CHANGE_ENABLE 0x180 -#define CODA_PARAM_CHANGE_RC_GOP BIT(0) -#define CODA_PARAM_CHANGE_RC_INTRA_QP BIT(1) -#define CODA_PARAM_CHANGE_RC_BITRATE BIT(2) -#define CODA_PARAM_CHANGE_RC_FRAME_RATE BIT(3) -#define CODA_PARAM_CHANGE_INTRA_MB_NUM BIT(4) -#define CODA_PARAM_CHANGE_SLICE_MODE BIT(5) -#define CODA_PARAM_CHANGE_HEC_MODE BIT(6) -#define CODA_CMD_ENC_PARAM_RC_GOP 0x184 -#define CODA_CMD_ENC_PARAM_RC_INTRA_QP 0x188 -#define CODA_CMD_ENC_PARAM_RC_BITRATE 0x18c -#define CODA_CMD_ENC_PARAM_RC_FRAME_RATE 0x190 -#define CODA_CMD_ENC_PARAM_INTRA_MB_NUM 0x194 -#define CODA_CMD_ENC_PARAM_SLICE_MODE 0x198 -#define CODA_CMD_ENC_PARAM_HEC_MODE 0x19c -#define CODA_RET_ENC_PARAM_CHANGE_SUCCESS 0x1c0 - -/* Encoder Picture Run */ -#define CODA9_CMD_ENC_PIC_SRC_INDEX 0x180 -#define CODA9_CMD_ENC_PIC_SRC_STRIDE 0x184 -#define CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC 0x1a4 -#define CODA9_CMD_ENC_PIC_SRC_ADDR_Y 0x1a8 -#define CODA9_CMD_ENC_PIC_SRC_ADDR_CB 0x1ac -#define CODA9_CMD_ENC_PIC_SRC_ADDR_CR 0x1b0 -#define CODA_CMD_ENC_PIC_SRC_ADDR_Y 0x180 -#define CODA_CMD_ENC_PIC_SRC_ADDR_CB 0x184 -#define CODA_CMD_ENC_PIC_SRC_ADDR_CR 0x188 -#define CODA_CMD_ENC_PIC_QS 0x18c -#define CODA_CMD_ENC_PIC_ROT_MODE 0x190 -#define CODA_ROT_MIR_ENABLE (1 << 4) -#define CODA_ROT_0 (0x0 << 0) -#define CODA_ROT_90 (0x1 << 0) -#define CODA_ROT_180 (0x2 << 0) -#define CODA_ROT_270 (0x3 << 0) -#define CODA_MIR_NONE (0x0 << 2) -#define CODA_MIR_VER (0x1 << 2) -#define CODA_MIR_HOR (0x2 << 2) -#define CODA_MIR_VER_HOR (0x3 << 2) -#define CODA_CMD_ENC_PIC_OPTION 0x194 -#define CODA_FORCE_IPICTURE BIT(1) -#define CODA_REPORT_MB_INFO BIT(3) -#define CODA_REPORT_MV_INFO BIT(4) -#define CODA_REPORT_SLICE_INFO BIT(5) -#define CODA_CMD_ENC_PIC_BB_START 0x198 -#define CODA_CMD_ENC_PIC_BB_SIZE 0x19c -#define CODA_RET_ENC_FRAME_NUM 0x1c0 -#define CODA_RET_ENC_PIC_TYPE 0x1c4 -#define CODA_RET_ENC_PIC_FRAME_IDX 0x1c8 -#define CODA_RET_ENC_PIC_SLICE_NUM 0x1cc -#define CODA_RET_ENC_PIC_FLAG 0x1d0 -#define CODA_RET_ENC_PIC_SUCCESS 0x1d8 - -/* Set Frame Buffer */ -#define CODA_CMD_SET_FRAME_BUF_NUM 0x180 -#define CODA_CMD_SET_FRAME_BUF_STRIDE 0x184 -#define CODA_CMD_SET_FRAME_SLICE_BB_START 0x188 -#define CODA_CMD_SET_FRAME_SLICE_BB_SIZE 0x18c -#define CODA9_CMD_SET_FRAME_SUBSAMP_A 0x188 -#define CODA9_CMD_SET_FRAME_SUBSAMP_B 0x18c -#define CODA7_CMD_SET_FRAME_AXI_BIT_ADDR 0x190 -#define CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR 0x194 -#define CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR 0x198 -#define CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR 0x19c -#define CODA7_CMD_SET_FRAME_AXI_OVL_ADDR 0x1a0 -#define CODA7_CMD_SET_FRAME_MAX_DEC_SIZE 0x1a4 -#define CODA9_CMD_SET_FRAME_AXI_BTP_ADDR 0x1a4 -#define CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE 0x1a8 -#define CODA9_CMD_SET_FRAME_CACHE_SIZE 0x1a8 -#define CODA9_CMD_SET_FRAME_CACHE_CONFIG 0x1ac -#define CODA9_CACHE_BYPASS_OFFSET 28 -#define CODA9_CACHE_DUALCONF_OFFSET 26 -#define CODA9_CACHE_PAGEMERGE_OFFSET 24 -#define CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET 16 -#define CODA9_CACHE_CB_BUFFER_SIZE_OFFSET 8 -#define CODA9_CACHE_CR_BUFFER_SIZE_OFFSET 0 -#define CODA9_CMD_SET_FRAME_SUBSAMP_A_MVC 0x1b0 -#define CODA9_CMD_SET_FRAME_SUBSAMP_B_MVC 0x1b4 -#define CODA9_CMD_SET_FRAME_DP_BUF_BASE 0x1b0 -#define CODA9_CMD_SET_FRAME_DP_BUF_SIZE 0x1b4 -#define CODA9_CMD_SET_FRAME_MAX_DEC_SIZE 0x1b8 -#define CODA9_CMD_SET_FRAME_DELAY 0x1bc - -/* Encoder Header */ -#define CODA_CMD_ENC_HEADER_CODE 0x180 -#define CODA_GAMMA_OFFSET 0 -#define CODA_HEADER_H264_SPS 0 -#define CODA_HEADER_H264_PPS 1 -#define CODA_HEADER_MP4V_VOL 0 -#define CODA_HEADER_MP4V_VOS 1 -#define CODA_HEADER_MP4V_VIS 2 -#define CODA9_HEADER_FRAME_CROP (1 << 3) -#define CODA_CMD_ENC_HEADER_BB_START 0x184 -#define CODA_CMD_ENC_HEADER_BB_SIZE 0x188 -#define CODA9_CMD_ENC_HEADER_FRAME_CROP_H 0x18c -#define CODA9_CMD_ENC_HEADER_FRAME_CROP_V 0x190 - -/* Get Version */ -#define CODA_CMD_FIRMWARE_VERNUM 0x1c0 -#define CODA_FIRMWARE_PRODUCT(x) (((x) >> 16) & 0xffff) -#define CODA_FIRMWARE_MAJOR(x) (((x) >> 12) & 0x0f) -#define CODA_FIRMWARE_MINOR(x) (((x) >> 8) & 0x0f) -#define CODA_FIRMWARE_RELEASE(x) ((x) & 0xff) -#define CODA_FIRMWARE_VERNUM(product, major, minor, release) \ - ((product) << 16 | ((major) << 12) | \ - ((minor) << 8) | (release)) -#define CODA9_CMD_FIRMWARE_CODE_REV 0x1c4 - -#define CODA9_GDMA_BASE 0x1000 -#define CODA9_GDI_CONTROL (CODA9_GDMA_BASE + 0x034) -#define CODA9_GDI_PIC_INIT_HOST (CODA9_GDMA_BASE + 0x038) -#define CODA9_GDI_STATUS (CODA9_GDMA_BASE + 0x080) -#define CODA9_GDI_WPROT_ERR_CLR (CODA9_GDMA_BASE + 0x0a0) -#define CODA9_GDI_WPROT_RGN_EN (CODA9_GDMA_BASE + 0x0ac) - -#define CODA9_GDI_BUS_CTRL (CODA9_GDMA_BASE + 0x0f0) -#define CODA9_GDI_BUS_STATUS (CODA9_GDMA_BASE + 0x0f4) - -#define CODA9_GDI_INFO_CONTROL (CODA9_GDMA_BASE + 0x400) -#define CODA9_GDI_INFO_PIC_SIZE (CODA9_GDMA_BASE + 0x404) -#define CODA9_GDI_INFO_BASE_Y (CODA9_GDMA_BASE + 0x408) -#define CODA9_GDI_INFO_BASE_CB (CODA9_GDMA_BASE + 0x40c) -#define CODA9_GDI_INFO_BASE_CR (CODA9_GDMA_BASE + 0x410) - -#define CODA9_GDI_XY2_CAS_0 (CODA9_GDMA_BASE + 0x800) -#define CODA9_GDI_XY2_CAS_F (CODA9_GDMA_BASE + 0x83c) - -#define CODA9_GDI_XY2_BA_0 (CODA9_GDMA_BASE + 0x840) -#define CODA9_GDI_XY2_BA_1 (CODA9_GDMA_BASE + 0x844) -#define CODA9_GDI_XY2_BA_2 (CODA9_GDMA_BASE + 0x848) -#define CODA9_GDI_XY2_BA_3 (CODA9_GDMA_BASE + 0x84c) - -#define CODA9_GDI_XY2_RAS_0 (CODA9_GDMA_BASE + 0x850) -#define CODA9_GDI_XY2_RAS_F (CODA9_GDMA_BASE + 0x88c) - -#define CODA9_GDI_XY2_RBC_CONFIG (CODA9_GDMA_BASE + 0x890) -#define CODA9_XY2RBC_SEPARATE_MAP BIT(19) -#define CODA9_XY2RBC_TOP_BOT_SPLIT BIT(18) -#define CODA9_XY2RBC_TILED_MAP BIT(17) -#define CODA9_XY2RBC_CA_INC_HOR BIT(16) -#define CODA9_GDI_RBC2_AXI_0 (CODA9_GDMA_BASE + 0x8a0) -#define CODA9_GDI_RBC2_AXI_1F (CODA9_GDMA_BASE + 0x91c) -#define CODA9_GDI_TILEDBUF_BASE (CODA9_GDMA_BASE + 0x920) - -#define CODA9_JPEG_BASE 0x3000 -#define CODA9_REG_JPEG_PIC_START (CODA9_JPEG_BASE + 0x000) -#define CODA9_REG_JPEG_PIC_STATUS (CODA9_JPEG_BASE + 0x004) -#define CODA9_JPEG_STATUS_OVERFLOW BIT(3) -#define CODA9_JPEG_STATUS_BBC_INT BIT(2) -#define CODA9_JPEG_STATUS_ERROR BIT(1) -#define CODA9_JPEG_STATUS_DONE BIT(0) -#define CODA9_REG_JPEG_PIC_ERRMB (CODA9_JPEG_BASE + 0x008) -#define CODA9_JPEG_ERRMB_RESTART_IDX_MASK (0xf << 24) -#define CODA9_JPEG_ERRMB_MCU_POS_X_MASK (0xfff << 12) -#define CODA9_JPEG_ERRMB_MCU_POS_Y_MASK 0xfff -#define CODA9_REG_JPEG_PIC_CTRL (CODA9_JPEG_BASE + 0x010) -#define CODA9_JPEG_PIC_CTRL_USER_HUFFMAN_EN BIT(6) -#define CODA9_JPEG_PIC_CTRL_TC_DIRECTION BIT(4) -#define CODA9_JPEG_PIC_CTRL_ENCODER_EN BIT(3) -#define CODA9_REG_JPEG_PIC_SIZE (CODA9_JPEG_BASE + 0x014) -#define CODA9_REG_JPEG_MCU_INFO (CODA9_JPEG_BASE + 0x018) -#define CODA9_JPEG_MCU_BLOCK_NUM_OFFSET 16 -#define CODA9_JPEG_COMP_NUM_OFFSET 12 -#define CODA9_JPEG_COMP0_INFO_OFFSET 8 -#define CODA9_JPEG_COMP1_INFO_OFFSET 4 -#define CODA9_JPEG_COMP2_INFO_OFFSET 0 -#define CODA9_REG_JPEG_ROT_INFO (CODA9_JPEG_BASE + 0x01c) -#define CODA9_JPEG_ROT_MIR_ENABLE BIT(4) -#define CODA9_JPEG_ROT_MIR_MODE_MASK 0xf -#define CODA9_REG_JPEG_SCL_INFO (CODA9_JPEG_BASE + 0x020) -#define CODA9_JPEG_SCL_ENABLE BIT(4) -#define CODA9_JPEG_SCL_HOR_MODE_MASK (0x3 << 2) -#define CODA9_JPEG_SCL_VER_MODE_MASK (0x3 << 0) -#define CODA9_REG_JPEG_IF_INFO (CODA9_JPEG_BASE + 0x024) -#define CODA9_JPEG_SENS_IF_CLR BIT(1) -#define CODA9_JPEG_DISP_IF_CLR BIT(0) -#define CODA9_REG_JPEG_OP_INFO (CODA9_JPEG_BASE + 0x02c) -#define CODA9_JPEG_BUS_REQ_NUM_OFFSET 0 -#define CODA9_JPEG_BUS_REQ_NUM_MASK 0x7 -#define CODA9_REG_JPEG_DPB_CONFIG (CODA9_JPEG_BASE + 0x030) -#define CODA9_REG_JPEG_DPB_BASE00 (CODA9_JPEG_BASE + 0x040) -#define CODA9_REG_JPEG_HUFF_CTRL (CODA9_JPEG_BASE + 0x080) -#define CODA9_REG_JPEG_HUFF_ADDR (CODA9_JPEG_BASE + 0x084) -#define CODA9_REG_JPEG_HUFF_DATA (CODA9_JPEG_BASE + 0x088) -#define CODA9_REG_JPEG_QMAT_CTRL (CODA9_JPEG_BASE + 0x090) -#define CODA9_REG_JPEG_QMAT_ADDR (CODA9_JPEG_BASE + 0x094) -#define CODA9_REG_JPEG_QMAT_DATA (CODA9_JPEG_BASE + 0x098) -#define CODA9_REG_JPEG_RST_INTVAL (CODA9_JPEG_BASE + 0x0b0) -#define CODA9_REG_JPEG_RST_INDEX (CODA9_JPEG_BASE + 0x0b4) -#define CODA9_REG_JPEG_RST_COUNT (CODA9_JPEG_BASE + 0x0b8) -#define CODA9_REG_JPEG_DPCM_DIFF_Y (CODA9_JPEG_BASE + 0x0f0) -#define CODA9_REG_JPEG_DPCM_DIFF_CB (CODA9_JPEG_BASE + 0x0f4) -#define CODA9_REG_JPEG_DPCM_DIFF_CR (CODA9_JPEG_BASE + 0x0f8) -#define CODA9_REG_JPEG_GBU_CTRL (CODA9_JPEG_BASE + 0x100) -#define CODA9_REG_JPEG_GBU_BT_PTR (CODA9_JPEG_BASE + 0x110) -#define CODA9_REG_JPEG_GBU_WD_PTR (CODA9_JPEG_BASE + 0x114) -#define CODA9_REG_JPEG_GBU_TT_CNT (CODA9_JPEG_BASE + 0x118) -#define CODA9_REG_JPEG_GBU_BBSR (CODA9_JPEG_BASE + 0x140) -#define CODA9_REG_JPEG_GBU_BBER (CODA9_JPEG_BASE + 0x144) -#define CODA9_REG_JPEG_GBU_BBIR (CODA9_JPEG_BASE + 0x148) -#define CODA9_REG_JPEG_GBU_BBHR (CODA9_JPEG_BASE + 0x14c) -#define CODA9_REG_JPEG_GBU_BCNT (CODA9_JPEG_BASE + 0x158) -#define CODA9_REG_JPEG_GBU_FF_RPTR (CODA9_JPEG_BASE + 0x160) -#define CODA9_REG_JPEG_GBU_FF_WPTR (CODA9_JPEG_BASE + 0x164) -#define CODA9_REG_JPEG_BBC_END_ADDR (CODA9_JPEG_BASE + 0x208) -#define CODA9_REG_JPEG_BBC_WR_PTR (CODA9_JPEG_BASE + 0x20c) -#define CODA9_REG_JPEG_BBC_RD_PTR (CODA9_JPEG_BASE + 0x210) -#define CODA9_REG_JPEG_BBC_EXT_ADDR (CODA9_JPEG_BASE + 0x214) -#define CODA9_REG_JPEG_BBC_INT_ADDR (CODA9_JPEG_BASE + 0x218) -#define CODA9_REG_JPEG_BBC_DATA_CNT (CODA9_JPEG_BASE + 0x21c) -#define CODA9_REG_JPEG_BBC_COMMAND (CODA9_JPEG_BASE + 0x220) -#define CODA9_REG_JPEG_BBC_BUSY (CODA9_JPEG_BASE + 0x224) -#define CODA9_REG_JPEG_BBC_CTRL (CODA9_JPEG_BASE + 0x228) -#define CODA9_REG_JPEG_BBC_CUR_POS (CODA9_JPEG_BASE + 0x22c) -#define CODA9_REG_JPEG_BBC_BAS_ADDR (CODA9_JPEG_BASE + 0x230) -#define CODA9_REG_JPEG_BBC_STRM_CTRL (CODA9_JPEG_BASE + 0x234) -#define CODA9_REG_JPEG_BBC_FLUSH_CMD (CODA9_JPEG_BASE + 0x238) - -#endif diff -Naur --no-dereference a/drivers/media/platform/chips-media/imx-vdoa.c b/drivers/media/platform/chips-media/imx-vdoa.c --- a/drivers/media/platform/chips-media/imx-vdoa.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/imx-vdoa.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,346 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * i.MX6 Video Data Order Adapter (VDOA) - * - * Copyright (C) 2014 Philipp Zabel - * Copyright (C) 2016 Pengutronix, Michael Tretter - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "imx-vdoa.h" - -#define VDOA_NAME "imx-vdoa" - -#define VDOAC 0x00 -#define VDOASRR 0x04 -#define VDOAIE 0x08 -#define VDOAIST 0x0c -#define VDOAFP 0x10 -#define VDOAIEBA00 0x14 -#define VDOAIEBA01 0x18 -#define VDOAIEBA02 0x1c -#define VDOAIEBA10 0x20 -#define VDOAIEBA11 0x24 -#define VDOAIEBA12 0x28 -#define VDOASL 0x2c -#define VDOAIUBO 0x30 -#define VDOAVEBA0 0x34 -#define VDOAVEBA1 0x38 -#define VDOAVEBA2 0x3c -#define VDOAVUBO 0x40 -#define VDOASR 0x44 - -#define VDOAC_ISEL BIT(6) -#define VDOAC_PFS BIT(5) -#define VDOAC_SO BIT(4) -#define VDOAC_SYNC BIT(3) -#define VDOAC_NF BIT(2) -#define VDOAC_BNDM_MASK 0x3 -#define VDOAC_BAND_HEIGHT_8 0x0 -#define VDOAC_BAND_HEIGHT_16 0x1 -#define VDOAC_BAND_HEIGHT_32 0x2 - -#define VDOASRR_START BIT(1) -#define VDOASRR_SWRST BIT(0) - -#define VDOAIE_EITERR BIT(1) -#define VDOAIE_EIEOT BIT(0) - -#define VDOAIST_TERR BIT(1) -#define VDOAIST_EOT BIT(0) - -#define VDOAFP_FH_MASK (0x1fff << 16) -#define VDOAFP_FW_MASK (0x3fff) - -#define VDOASL_VSLY_MASK (0x3fff << 16) -#define VDOASL_ISLY_MASK (0x7fff) - -#define VDOASR_ERRW BIT(4) -#define VDOASR_EOB BIT(3) -#define VDOASR_CURRENT_FRAME (0x3 << 1) -#define VDOASR_CURRENT_BUFFER BIT(1) - -enum { - V4L2_M2M_SRC = 0, - V4L2_M2M_DST = 1, -}; - -struct vdoa_data { - struct vdoa_ctx *curr_ctx; - struct device *dev; - struct clk *vdoa_clk; - void __iomem *regs; -}; - -struct vdoa_q_data { - unsigned int width; - unsigned int height; - unsigned int bytesperline; - unsigned int sizeimage; - u32 pixelformat; -}; - -struct vdoa_ctx { - struct vdoa_data *vdoa; - struct completion completion; - struct vdoa_q_data q_data[2]; - unsigned int submitted_job; - unsigned int completed_job; -}; - -static irqreturn_t vdoa_irq_handler(int irq, void *data) -{ - struct vdoa_data *vdoa = data; - struct vdoa_ctx *curr_ctx; - u32 val; - - /* Disable interrupts */ - writel(0, vdoa->regs + VDOAIE); - - curr_ctx = vdoa->curr_ctx; - if (!curr_ctx) { - dev_warn(vdoa->dev, - "Instance released before the end of transaction\n"); - return IRQ_HANDLED; - } - - val = readl(vdoa->regs + VDOAIST); - writel(val, vdoa->regs + VDOAIST); - if (val & VDOAIST_TERR) { - val = readl(vdoa->regs + VDOASR) & VDOASR_ERRW; - dev_err(vdoa->dev, "AXI %s error\n", val ? "write" : "read"); - } else if (!(val & VDOAIST_EOT)) { - dev_warn(vdoa->dev, "Spurious interrupt\n"); - } - curr_ctx->completed_job++; - complete(&curr_ctx->completion); - - return IRQ_HANDLED; -} - -int vdoa_wait_for_completion(struct vdoa_ctx *ctx) -{ - struct vdoa_data *vdoa = ctx->vdoa; - - if (ctx->submitted_job == ctx->completed_job) - return 0; - - if (!wait_for_completion_timeout(&ctx->completion, - msecs_to_jiffies(300))) { - dev_err(vdoa->dev, - "Timeout waiting for transfer result\n"); - return -ETIMEDOUT; - } - - return 0; -} -EXPORT_SYMBOL(vdoa_wait_for_completion); - -void vdoa_device_run(struct vdoa_ctx *ctx, dma_addr_t dst, dma_addr_t src) -{ - struct vdoa_q_data *src_q_data, *dst_q_data; - struct vdoa_data *vdoa = ctx->vdoa; - u32 val; - - if (vdoa->curr_ctx) - vdoa_wait_for_completion(vdoa->curr_ctx); - - vdoa->curr_ctx = ctx; - - reinit_completion(&ctx->completion); - ctx->submitted_job++; - - src_q_data = &ctx->q_data[V4L2_M2M_SRC]; - dst_q_data = &ctx->q_data[V4L2_M2M_DST]; - - /* Progressive, no sync, 1 frame per run */ - if (dst_q_data->pixelformat == V4L2_PIX_FMT_YUYV) - val = VDOAC_PFS; - else - val = 0; - writel(val, vdoa->regs + VDOAC); - - writel(dst_q_data->height << 16 | dst_q_data->width, - vdoa->regs + VDOAFP); - - val = dst; - writel(val, vdoa->regs + VDOAIEBA00); - - writel(src_q_data->bytesperline << 16 | dst_q_data->bytesperline, - vdoa->regs + VDOASL); - - if (dst_q_data->pixelformat == V4L2_PIX_FMT_NV12 || - dst_q_data->pixelformat == V4L2_PIX_FMT_NV21) - val = dst_q_data->bytesperline * dst_q_data->height; - else - val = 0; - writel(val, vdoa->regs + VDOAIUBO); - - val = src; - writel(val, vdoa->regs + VDOAVEBA0); - val = round_up(src_q_data->bytesperline * src_q_data->height, 4096); - writel(val, vdoa->regs + VDOAVUBO); - - /* Enable interrupts and start transfer */ - writel(VDOAIE_EITERR | VDOAIE_EIEOT, vdoa->regs + VDOAIE); - writel(VDOASRR_START, vdoa->regs + VDOASRR); -} -EXPORT_SYMBOL(vdoa_device_run); - -struct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa) -{ - struct vdoa_ctx *ctx; - int err; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return NULL; - - err = clk_prepare_enable(vdoa->vdoa_clk); - if (err) { - kfree(ctx); - return NULL; - } - - init_completion(&ctx->completion); - ctx->vdoa = vdoa; - - return ctx; -} -EXPORT_SYMBOL(vdoa_context_create); - -void vdoa_context_destroy(struct vdoa_ctx *ctx) -{ - struct vdoa_data *vdoa = ctx->vdoa; - - if (vdoa->curr_ctx == ctx) { - vdoa_wait_for_completion(vdoa->curr_ctx); - vdoa->curr_ctx = NULL; - } - - clk_disable_unprepare(vdoa->vdoa_clk); - kfree(ctx); -} -EXPORT_SYMBOL(vdoa_context_destroy); - -int vdoa_context_configure(struct vdoa_ctx *ctx, - unsigned int width, unsigned int height, - u32 pixelformat) -{ - struct vdoa_q_data *src_q_data; - struct vdoa_q_data *dst_q_data; - - if (width < 16 || width > 8192 || width % 16 != 0 || - height < 16 || height > 4096 || height % 16 != 0) - return -EINVAL; - - if (pixelformat != V4L2_PIX_FMT_YUYV && - pixelformat != V4L2_PIX_FMT_NV12) - return -EINVAL; - - /* If no context is passed, only check if the format is valid */ - if (!ctx) - return 0; - - src_q_data = &ctx->q_data[V4L2_M2M_SRC]; - dst_q_data = &ctx->q_data[V4L2_M2M_DST]; - - src_q_data->width = width; - src_q_data->height = height; - src_q_data->bytesperline = width; - src_q_data->sizeimage = - round_up(src_q_data->bytesperline * height, 4096) + - src_q_data->bytesperline * height / 2; - - dst_q_data->width = width; - dst_q_data->height = height; - dst_q_data->pixelformat = pixelformat; - switch (pixelformat) { - case V4L2_PIX_FMT_YUYV: - dst_q_data->bytesperline = width * 2; - dst_q_data->sizeimage = dst_q_data->bytesperline * height; - break; - case V4L2_PIX_FMT_NV12: - default: - dst_q_data->bytesperline = width; - dst_q_data->sizeimage = - dst_q_data->bytesperline * height * 3 / 2; - break; - } - - return 0; -} -EXPORT_SYMBOL(vdoa_context_configure); - -static int vdoa_probe(struct platform_device *pdev) -{ - struct vdoa_data *vdoa; - int ret; - - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(&pdev->dev, "DMA enable failed\n"); - return ret; - } - - vdoa = devm_kzalloc(&pdev->dev, sizeof(*vdoa), GFP_KERNEL); - if (!vdoa) - return -ENOMEM; - - vdoa->dev = &pdev->dev; - - vdoa->vdoa_clk = devm_clk_get(vdoa->dev, NULL); - if (IS_ERR(vdoa->vdoa_clk)) { - dev_err(vdoa->dev, "Failed to get clock\n"); - return PTR_ERR(vdoa->vdoa_clk); - } - - vdoa->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(vdoa->regs)) - return PTR_ERR(vdoa->regs); - - ret = platform_get_irq(pdev, 0); - if (ret < 0) - return ret; - ret = devm_request_threaded_irq(&pdev->dev, ret, NULL, - vdoa_irq_handler, IRQF_ONESHOT, - "vdoa", vdoa); - if (ret < 0) { - dev_err(vdoa->dev, "Failed to get irq\n"); - return ret; - } - - platform_set_drvdata(pdev, vdoa); - - return 0; -} - -static const struct of_device_id vdoa_dt_ids[] = { - { .compatible = "fsl,imx6q-vdoa" }, - {} -}; -MODULE_DEVICE_TABLE(of, vdoa_dt_ids); - -static struct platform_driver vdoa_driver = { - .probe = vdoa_probe, - .driver = { - .name = VDOA_NAME, - .of_match_table = vdoa_dt_ids, - }, -}; - -module_platform_driver(vdoa_driver); - -MODULE_DESCRIPTION("Video Data Order Adapter"); -MODULE_AUTHOR("Philipp Zabel "); -MODULE_ALIAS("platform:imx-vdoa"); -MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/drivers/media/platform/chips-media/imx-vdoa.h b/drivers/media/platform/chips-media/imx-vdoa.h --- a/drivers/media/platform/chips-media/imx-vdoa.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/imx-vdoa.h 1969-12-31 19:00:00.000000000 -0500 @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2016 Pengutronix - */ - -#ifndef IMX_VDOA_H -#define IMX_VDOA_H - -struct vdoa_data; -struct vdoa_ctx; - -#if (defined CONFIG_VIDEO_IMX_VDOA || defined CONFIG_VIDEO_IMX_VDOA_MODULE) - -struct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa); -int vdoa_context_configure(struct vdoa_ctx *ctx, - unsigned int width, unsigned int height, - u32 pixelformat); -void vdoa_context_destroy(struct vdoa_ctx *ctx); - -void vdoa_device_run(struct vdoa_ctx *ctx, dma_addr_t dst, dma_addr_t src); -int vdoa_wait_for_completion(struct vdoa_ctx *ctx); - -#else - -static inline struct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa) -{ - return NULL; -} - -static inline int vdoa_context_configure(struct vdoa_ctx *ctx, - unsigned int width, - unsigned int height, - u32 pixelformat) -{ - return 0; -} - -static inline void vdoa_context_destroy(struct vdoa_ctx *ctx) { }; - -static inline void vdoa_device_run(struct vdoa_ctx *ctx, - dma_addr_t dst, dma_addr_t src) { }; - -static inline int vdoa_wait_for_completion(struct vdoa_ctx *ctx) -{ - return 0; -}; - -#endif - -#endif /* IMX_VDOA_H */ diff -Naur --no-dereference a/drivers/media/platform/chips-media/Kconfig b/drivers/media/platform/chips-media/Kconfig --- a/drivers/media/platform/chips-media/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/Kconfig 2024-07-07 20:37:34.648306569 -0400 @@ -2,19 +2,5 @@ comment "Chips&Media media platform drivers" -config VIDEO_CODA - tristate "Chips&Media Coda multi-standard codec IP" - depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && OF && (ARCH_MXC || COMPILE_TEST) - select SRAM - select VIDEOBUF2_DMA_CONTIG - select VIDEOBUF2_VMALLOC - select V4L2_JPEG_HELPER - select V4L2_MEM2MEM_DEV - select GENERIC_ALLOCATOR - help - Coda is a range of video codec IPs that supports - H.264, MPEG-4, and other video formats. - -config VIDEO_IMX_VDOA - def_tristate VIDEO_CODA if SOC_IMX6Q || COMPILE_TEST +source "drivers/media/platform/chips-media/coda/Kconfig" +source "drivers/media/platform/chips-media/wave5/Kconfig" diff -Naur --no-dereference a/drivers/media/platform/chips-media/Makefile b/drivers/media/platform/chips-media/Makefile --- a/drivers/media/platform/chips-media/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/Makefile 2024-07-07 20:37:34.648306569 -0400 @@ -1,6 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -coda-vpu-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg2.o coda-mpeg4.o coda-jpeg.o - -obj-$(CONFIG_VIDEO_CODA) += coda-vpu.o -obj-$(CONFIG_VIDEO_IMX_VDOA) += imx-vdoa.o +obj-y += coda/ +obj-y += wave5/ diff -Naur --no-dereference a/drivers/media/platform/chips-media/trace.h b/drivers/media/platform/chips-media/trace.h --- a/drivers/media/platform/chips-media/trace.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/chips-media/trace.h 1969-12-31 19:00:00.000000000 -0500 @@ -1,175 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM coda - -#if !defined(__CODA_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) -#define __CODA_TRACE_H__ - -#include -#include - -#include "coda.h" - -TRACE_EVENT(coda_bit_run, - TP_PROTO(struct coda_ctx *ctx, int cmd), - - TP_ARGS(ctx, cmd), - - TP_STRUCT__entry( - __field(int, minor) - __field(int, ctx) - __field(int, cmd) - ), - - TP_fast_assign( - __entry->minor = ctx->fh.vdev->minor; - __entry->ctx = ctx->idx; - __entry->cmd = cmd; - ), - - TP_printk("minor = %d, ctx = %d, cmd = %d", - __entry->minor, __entry->ctx, __entry->cmd) -); - -TRACE_EVENT(coda_bit_done, - TP_PROTO(struct coda_ctx *ctx), - - TP_ARGS(ctx), - - TP_STRUCT__entry( - __field(int, minor) - __field(int, ctx) - ), - - TP_fast_assign( - __entry->minor = ctx->fh.vdev->minor; - __entry->ctx = ctx->idx; - ), - - TP_printk("minor = %d, ctx = %d", __entry->minor, __entry->ctx) -); - -DECLARE_EVENT_CLASS(coda_buf_class, - TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf), - - TP_ARGS(ctx, buf), - - TP_STRUCT__entry( - __field(int, minor) - __field(int, index) - __field(int, ctx) - ), - - TP_fast_assign( - __entry->minor = ctx->fh.vdev->minor; - __entry->index = buf->vb2_buf.index; - __entry->ctx = ctx->idx; - ), - - TP_printk("minor = %d, index = %d, ctx = %d", - __entry->minor, __entry->index, __entry->ctx) -); - -DEFINE_EVENT(coda_buf_class, coda_enc_pic_run, - TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf), - TP_ARGS(ctx, buf) -); - -DEFINE_EVENT(coda_buf_class, coda_enc_pic_done, - TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf), - TP_ARGS(ctx, buf) -); - -DECLARE_EVENT_CLASS(coda_buf_meta_class, - TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, - struct coda_buffer_meta *meta), - - TP_ARGS(ctx, buf, meta), - - TP_STRUCT__entry( - __field(int, minor) - __field(int, index) - __field(int, start) - __field(int, end) - __field(int, ctx) - ), - - TP_fast_assign( - __entry->minor = ctx->fh.vdev->minor; - __entry->index = buf->vb2_buf.index; - __entry->start = meta->start & ctx->bitstream_fifo.kfifo.mask; - __entry->end = meta->end & ctx->bitstream_fifo.kfifo.mask; - __entry->ctx = ctx->idx; - ), - - TP_printk("minor = %d, index = %d, start = 0x%x, end = 0x%x, ctx = %d", - __entry->minor, __entry->index, __entry->start, __entry->end, - __entry->ctx) -); - -DEFINE_EVENT(coda_buf_meta_class, coda_bit_queue, - TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, - struct coda_buffer_meta *meta), - TP_ARGS(ctx, buf, meta) -); - -DECLARE_EVENT_CLASS(coda_meta_class, - TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), - - TP_ARGS(ctx, meta), - - TP_STRUCT__entry( - __field(int, minor) - __field(int, start) - __field(int, end) - __field(int, ctx) - ), - - TP_fast_assign( - __entry->minor = ctx->fh.vdev->minor; - __entry->start = meta ? (meta->start & - ctx->bitstream_fifo.kfifo.mask) : 0; - __entry->end = meta ? (meta->end & - ctx->bitstream_fifo.kfifo.mask) : 0; - __entry->ctx = ctx->idx; - ), - - TP_printk("minor = %d, start = 0x%x, end = 0x%x, ctx = %d", - __entry->minor, __entry->start, __entry->end, __entry->ctx) -); - -DEFINE_EVENT(coda_meta_class, coda_dec_pic_run, - TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), - TP_ARGS(ctx, meta) -); - -DEFINE_EVENT(coda_meta_class, coda_dec_pic_done, - TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), - TP_ARGS(ctx, meta) -); - -DEFINE_EVENT(coda_buf_meta_class, coda_dec_rot_done, - TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, - struct coda_buffer_meta *meta), - TP_ARGS(ctx, buf, meta) -); - -DEFINE_EVENT(coda_buf_class, coda_jpeg_run, - TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf), - TP_ARGS(ctx, buf) -); - -DEFINE_EVENT(coda_buf_class, coda_jpeg_done, - TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf), - TP_ARGS(ctx, buf) -); - -#endif /* __CODA_TRACE_H__ */ - -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH ../../drivers/media/platform/chips-media -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE trace - -/* This part must be outside protection */ -#include diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/Kconfig b/drivers/media/platform/chips-media/wave5/Kconfig --- a/drivers/media/platform/chips-media/wave5/Kconfig 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/Kconfig 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0 +config VIDEO_WAVE_VPU + tristate "Chips&Media Wave Codec Driver" + depends on V4L_MEM2MEM_DRIVERS + depends on VIDEO_DEV && OF + depends on ARCH_K3 || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_VMALLOC + select V4L2_MEM2MEM_DEV + select GENERIC_ALLOCATOR + help + Chips&Media stateful encoder and decoder driver. + The driver supports HEVC and H264 formats. + To compile this driver as modules, choose M here: the + modules will be called wave5. diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/Makefile b/drivers/media/platform/chips-media/wave5/Makefile --- a/drivers/media/platform/chips-media/wave5/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/Makefile 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_VIDEO_WAVE_VPU) += wave5.o +wave5-objs += wave5-hw.o \ + wave5-vpuapi.o \ + wave5-vdi.o \ + wave5-vpu-dec.o \ + wave5-vpu.o \ + wave5-vpu-enc.o \ + wave5-helper.o diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5.h b/drivers/media/platform/chips-media/wave5/wave5.h --- a/drivers/media/platform/chips-media/wave5/wave5.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - wave5 backend definitions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef __WAVE5_FUNCTION_H__ +#define __WAVE5_FUNCTION_H__ + +#define WAVE5_SUBSAMPLED_ONE_SIZE(_w, _h) (ALIGN((_w) / 4, 16) * ALIGN((_h) / 4, 8)) +#define WAVE5_SUBSAMPLED_ONE_SIZE_AVC(_w, _h) (ALIGN((_w) / 4, 32) * ALIGN((_h) / 4, 4)) + +/* + * Bitstream buffer option: Explicit End + * When set to 1 the VPU assumes that the bitstream has at least one frame and + * will read until the end of the bitstream buffer. + * When set to 0 the VPU will not read the last few bytes. + * This option can be set anytime but cannot be cleared during processing. + * It can be set to force finish decoding even though there is not enough + * bitstream data for a full frame. + */ +#define BSOPTION_ENABLE_EXPLICIT_END BIT(0) +#define BSOPTION_HIGHLIGHT_STREAM_END BIT(1) + +/* + * Currently the driver only supports hardware with little endian but for source + * picture format, the bitstream and the report parameter the hardware works + * with the opposite endianness, thus hard-code big endian for the register + * writes + */ +#define PIC_SRC_ENDIANNESS_BIG_ENDIAN 0xf +#define BITSTREAM_ENDIANNESS_BIG_ENDIAN 0xf +#define REPORT_PARAM_ENDIANNESS_BIG_ENDIAN 0xf + +#define WTL_RIGHT_JUSTIFIED 0 +#define WTL_LEFT_JUSTIFIED 1 +#define WTL_PIXEL_8BIT 0 +#define WTL_PIXEL_16BIT 1 +#define WTL_PIXEL_32BIT 2 + +/* Mirror & rotation modes of the PRP (pre-processing) module */ +#define NONE_ROTATE 0x0 +#define ROT_CLOCKWISE_90 0x3 +#define ROT_CLOCKWISE_180 0x5 +#define ROT_CLOCKWISE_270 0x7 +#define MIR_HOR_FLIP 0x11 +#define MIR_VER_FLIP 0x9 +#define MIR_HOR_VER_FLIP (MIR_HOR_FLIP | MIR_VER_FLIP) + +bool wave5_vpu_is_init(struct vpu_device *vpu_dev); + +unsigned int wave5_vpu_get_product_id(struct vpu_device *vpu_dev); + +int wave5_vpu_get_version(struct vpu_device *vpu_dev, u32 *revision); + +int wave5_vpu_init(struct device *dev, u8 *fw, size_t size); + +int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code, + size_t size); + +int wave5_vpu_reset(struct device *dev, enum sw_reset_mode reset_mode); + +int wave5_vpu_build_up_dec_param(struct vpu_instance *inst, struct dec_open_param *param); + +int wave5_vpu_dec_set_bitstream_flag(struct vpu_instance *inst, bool eos); + +int wave5_vpu_hw_flush_instance(struct vpu_instance *inst); + +int wave5_vpu_dec_register_framebuffer(struct vpu_instance *inst, + struct frame_buffer *fb_arr, enum tiled_map_type map_type, + unsigned int count); + +int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size); + +int wave5_vpu_dec_init_seq(struct vpu_instance *inst); + +int wave5_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info); + +int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res); + +int wave5_vpu_dec_get_result(struct vpu_instance *inst, struct dec_output_info *result); + +int wave5_vpu_dec_finish_seq(struct vpu_instance *inst, u32 *fail_res); + +int wave5_dec_clr_disp_flag(struct vpu_instance *inst, unsigned int index); + +int wave5_dec_set_disp_flag(struct vpu_instance *inst, unsigned int index); + +int wave5_vpu_clear_interrupt(struct vpu_instance *inst, u32 flags); + +dma_addr_t wave5_dec_get_rd_ptr(struct vpu_instance *inst); + +int wave5_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr); + +/***< WAVE5 encoder >******/ + +int wave5_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst, + struct enc_open_param *open_param); + +int wave5_vpu_enc_init_seq(struct vpu_instance *inst); + +int wave5_vpu_enc_get_seq_info(struct vpu_instance *inst, struct enc_initial_info *info); + +int wave5_vpu_enc_register_framebuffer(struct device *dev, struct vpu_instance *inst, + struct frame_buffer *fb_arr, enum tiled_map_type map_type, + unsigned int count); + +int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res); + +int wave5_vpu_enc_apply_change_param(struct vpu_instance *inst, u32 *fail_res); + +int wave5_vpu_enc_get_result(struct vpu_instance *inst, struct enc_output_info *result); + +int wave5_vpu_enc_finish_seq(struct vpu_instance *inst, u32 *fail_res); + +int wave5_vpu_enc_check_open_param(struct vpu_instance *inst, struct enc_open_param *open_param); + +#endif /* __WAVE5_FUNCTION_H__ */ diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c --- a/drivers/media/platform/chips-media/wave5/wave5-helper.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - decoder interface + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#include "wave5-helper.h" + +#define DEFAULT_BS_SIZE(width, height) ((width) * (height) / 8 * 3) + +const char *state_to_str(enum vpu_instance_state state) +{ + switch (state) { + case VPU_INST_STATE_NONE: + return "NONE"; + case VPU_INST_STATE_OPEN: + return "OPEN"; + case VPU_INST_STATE_INIT_SEQ: + return "INIT_SEQ"; + case VPU_INST_STATE_PIC_RUN: + return "PIC_RUN"; + case VPU_INST_STATE_STOP: + return "STOP"; + default: + return "UNKNOWN"; + } +} + +void wave5_cleanup_instance(struct vpu_instance *inst) +{ + int i; + + if (list_is_singular(&inst->list)) + wave5_vdi_free_sram(inst->dev); + + for (i = 0; i < inst->fbc_buf_count; i++) + wave5_vpu_dec_reset_framebuffer(inst, i); + + wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf); + v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl); + if (inst->v4l2_fh.vdev) { + v4l2_fh_del(&inst->v4l2_fh); + v4l2_fh_exit(&inst->v4l2_fh); + } + list_del_init(&inst->list); + ida_free(&inst->dev->inst_ida, inst->id); + kfree(inst->codec_info); + kfree(inst); +} + +int wave5_vpu_release_device(struct file *filp, + int (*close_func)(struct vpu_instance *inst, u32 *fail_res), + char *name) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data); + int ret = 0; + + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx); + if (inst->state != VPU_INST_STATE_NONE) { + u32 fail_res; + + ret = close_func(inst, &fail_res); + if (fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING) { + dev_err(inst->dev->dev, "%s close failed, device is still running\n", + name); + return -EBUSY; + } + if (ret && ret != -EIO) { + dev_err(inst->dev->dev, "%s close, fail: %d\n", name, ret); + return ret; + } + } + + wave5_cleanup_instance(inst); + + return ret; +} + +int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq, + const struct vb2_ops *ops) +{ + struct vpu_instance *inst = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->ops = ops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->buf_struct_size = sizeof(struct vpu_src_buffer); + src_vq->drv_priv = inst; + src_vq->lock = &inst->dev->dev_lock; + src_vq->dev = inst->dev->v4l2_dev.dev; + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->ops = ops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->buf_struct_size = sizeof(struct vpu_src_buffer); + dst_vq->drv_priv = inst; + dst_vq->lock = &inst->dev->dev_lock; + dst_vq->dev = inst->dev->v4l2_dev.dev; + ret = vb2_queue_init(dst_vq); + if (ret) + return ret; + + return 0; +} + +int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + bool is_decoder = inst->type == VPU_INST_TYPE_DEC; + + dev_dbg(inst->dev->dev, "%s: [%s] type: %u id: %u | flags: %u\n", __func__, + is_decoder ? "decoder" : "encoder", sub->type, sub->id, sub->flags); + + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + if (is_decoder) + return v4l2_src_change_event_subscribe(fh, sub); + return -EINVAL; + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + default: + return -EINVAL; + } +} + +int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + int i; + + f->fmt.pix_mp.width = inst->src_fmt.width; + f->fmt.pix_mp.height = inst->src_fmt.height; + f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat; + f->fmt.pix_mp.field = inst->src_fmt.field; + f->fmt.pix_mp.flags = inst->src_fmt.flags; + f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes; + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { + f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->src_fmt.plane_fmt[i].bytesperline; + f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->src_fmt.plane_fmt[i].sizeimage; + } + + f->fmt.pix_mp.colorspace = inst->colorspace; + f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; + f->fmt.pix_mp.quantization = inst->quantization; + f->fmt.pix_mp.xfer_func = inst->xfer_func; + + return 0; +} + +const struct vpu_format *wave5_find_vpu_fmt(unsigned int v4l2_pix_fmt, + const struct vpu_format fmt_list[MAX_FMTS]) +{ + unsigned int index; + + for (index = 0; index < MAX_FMTS; index++) { + if (fmt_list[index].v4l2_pix_fmt == v4l2_pix_fmt) + return &fmt_list[index]; + } + + return NULL; +} + +const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx, + const struct vpu_format fmt_list[MAX_FMTS]) +{ + if (idx >= MAX_FMTS) + return NULL; + + if (!fmt_list[idx].v4l2_pix_fmt) + return NULL; + + return &fmt_list[idx]; +} + +enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type) +{ + switch (v4l2_pix_fmt) { + case V4L2_PIX_FMT_H264: + return type == VPU_INST_TYPE_DEC ? W_AVC_DEC : W_AVC_ENC; + case V4L2_PIX_FMT_HEVC: + return type == VPU_INST_TYPE_DEC ? W_HEVC_DEC : W_HEVC_ENC; + default: + return STD_UNKNOWN; + } +} + +void wave5_return_bufs(struct vb2_queue *q, u32 state) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct v4l2_ctrl_handler v4l2_ctrl_hdl = inst->v4l2_ctrl_hdl; + struct vb2_v4l2_buffer *vbuf; + + for (;;) { + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + vbuf = v4l2_m2m_src_buf_remove(m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(m2m_ctx); + if (!vbuf) + return; + v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, &v4l2_ctrl_hdl); + v4l2_m2m_buf_done(vbuf, state); + } +} + +void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, + int pix_fmt_type, + unsigned int width, + unsigned int height, + const struct v4l2_frmsize_stepwise *frmsize) +{ + v4l2_apply_frmsize_constraints(&width, &height, frmsize); + + if (pix_fmt_type == VPU_FMT_TYPE_CODEC) { + pix_mp->width = width; + pix_mp->height = height; + pix_mp->num_planes = 1; + pix_mp->plane_fmt[0].bytesperline = 0; + pix_mp->plane_fmt[0].sizeimage = max(DEFAULT_BS_SIZE(width, height), + pix_mp->plane_fmt[0].sizeimage); + } else { + v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, width, height); + } + pix_mp->flags = 0; + pix_mp->field = V4L2_FIELD_NONE; +} diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-helper.h b/drivers/media/platform/chips-media/wave5/wave5-helper.h --- a/drivers/media/platform/chips-media/wave5/wave5-helper.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.h 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - basic types + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef __WAVE_HELPER_H__ +#define __WAVE_HELPER_H__ + +#include "wave5-vpu.h" + +#define FMT_TYPES 2 +#define MAX_FMTS 12 + +const char *state_to_str(enum vpu_instance_state state); +void wave5_cleanup_instance(struct vpu_instance *inst); +int wave5_vpu_release_device(struct file *filp, + int (*close_func)(struct vpu_instance *inst, u32 *fail_res), + char *name); +int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq, + const struct vb2_ops *ops); +int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub); +int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f); +const struct vpu_format *wave5_find_vpu_fmt(unsigned int v4l2_pix_fmt, + const struct vpu_format fmt_list[MAX_FMTS]); +const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx, + const struct vpu_format fmt_list[MAX_FMTS]); +enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type); +void wave5_return_bufs(struct vb2_queue *q, u32 state); +void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, + int pix_fmt_type, + unsigned int width, + unsigned int height, + const struct v4l2_frmsize_stepwise *frmsize); +#endif diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-hw.c b/drivers/media/platform/chips-media/wave5/wave5-hw.c --- a/drivers/media/platform/chips-media/wave5/wave5-hw.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-hw.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,2597 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - wave5 backend logic + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#include +#include +#include "wave5-vpu.h" +#include "wave5.h" +#include "wave5-regdefine.h" + +#define FIO_TIMEOUT 10000000 +#define FIO_CTRL_READY BIT(31) +#define FIO_CTRL_WRITE BIT(16) +#define VPU_BUSY_CHECK_TIMEOUT 10000000 +#define QUEUE_REPORT_MASK 0xffff + +/* Encoder support fields */ +#define FEATURE_HEVC10BIT_ENC BIT(3) +#define FEATURE_AVC10BIT_ENC BIT(11) +#define FEATURE_AVC_ENCODER BIT(1) +#define FEATURE_HEVC_ENCODER BIT(0) + +#define ENC_AVC_INTRA_IDR_PARAM_MASK 0x7ff +#define ENC_AVC_INTRA_PERIOD_SHIFT 6 +#define ENC_AVC_IDR_PERIOD_SHIFT 17 +#define ENC_AVC_FORCED_IDR_HEADER_SHIFT 28 + +#define ENC_HEVC_INTRA_QP_SHIFT 3 +#define ENC_HEVC_FORCED_IDR_HEADER_SHIFT 9 +#define ENC_HEVC_INTRA_PERIOD_SHIFT 16 + +/* Decoder support fields */ +#define FEATURE_AVC_DECODER BIT(3) +#define FEATURE_HEVC_DECODER BIT(2) + +#define FEATURE_BACKBONE BIT(16) +#define FEATURE_VCORE_BACKBONE BIT(22) +#define FEATURE_VCPU_BACKBONE BIT(28) + +#define REMAP_CTRL_MAX_SIZE_BITS ((W5_REMAP_MAX_SIZE >> 12) & 0x1ff) +#define REMAP_CTRL_REGISTER_VALUE(index) ( \ + (BIT(31) | (index << 12) | BIT(11) | REMAP_CTRL_MAX_SIZE_BITS) \ +) + +#define FASTIO_ADDRESS_MASK GENMASK(15, 0) +#define SEQ_PARAM_PROFILE_MASK GENMASK(30, 24) + +static void _wave5_print_reg_err(struct vpu_device *vpu_dev, u32 reg_fail_reason, + const char *func); +#define PRINT_REG_ERR(dev, reason) _wave5_print_reg_err((dev), (reason), __func__) + +static inline const char *cmd_to_str(int cmd, bool is_dec) +{ + switch (cmd) { + case W5_INIT_VPU: + return "W5_INIT_VPU"; + case W5_WAKEUP_VPU: + return "W5_WAKEUP_VPU"; + case W5_SLEEP_VPU: + return "W5_SLEEP_VPU"; + case W5_CREATE_INSTANCE: + return "W5_CREATE_INSTANCE"; + case W5_FLUSH_INSTANCE: + return "W5_FLUSH_INSTANCE"; + case W5_DESTROY_INSTANCE: + return "W5_DESTROY_INSTANCE"; + case W5_INIT_SEQ: + return "W5_INIT_SEQ"; + case W5_SET_FB: + return "W5_SET_FB"; + case W5_DEC_ENC_PIC: + if (is_dec) + return "W5_DEC_PIC"; + return "W5_ENC_PIC"; + case W5_ENC_SET_PARAM: + return "W5_ENC_SET_PARAM"; + case W5_QUERY: + return "W5_QUERY"; + case W5_UPDATE_BS: + return "W5_UPDATE_BS"; + case W5_MAX_VPU_COMD: + return "W5_MAX_VPU_COMD"; + default: + return "UNKNOWN"; + } +} + +static void _wave5_print_reg_err(struct vpu_device *vpu_dev, u32 reg_fail_reason, + const char *func) +{ + struct device *dev = vpu_dev->dev; + u32 reg_val; + + switch (reg_fail_reason) { + case WAVE5_SYSERR_QUEUEING_FAIL: + reg_val = vpu_read_reg(vpu_dev, W5_RET_QUEUE_FAIL_REASON); + dev_dbg(dev, "%s: queueing failure: 0x%x\n", func, reg_val); + break; + case WAVE5_SYSERR_RESULT_NOT_READY: + dev_err(dev, "%s: result not ready: 0x%x\n", func, reg_fail_reason); + break; + case WAVE5_SYSERR_ACCESS_VIOLATION_HW: + dev_err(dev, "%s: access violation: 0x%x\n", func, reg_fail_reason); + break; + case WAVE5_SYSERR_WATCHDOG_TIMEOUT: + dev_err(dev, "%s: watchdog timeout: 0x%x\n", func, reg_fail_reason); + break; + case WAVE5_SYSERR_BUS_ERROR: + dev_err(dev, "%s: bus error: 0x%x\n", func, reg_fail_reason); + break; + case WAVE5_SYSERR_DOUBLE_FAULT: + dev_err(dev, "%s: double fault: 0x%x\n", func, reg_fail_reason); + break; + case WAVE5_SYSERR_VPU_STILL_RUNNING: + dev_err(dev, "%s: still running: 0x%x\n", func, reg_fail_reason); + break; + case WAVE5_SYSERR_VLC_BUF_FULL: + dev_err(dev, "%s: vlc buf full: 0x%x\n", func, reg_fail_reason); + break; + default: + dev_err(dev, "%s: failure:: 0x%x\n", func, reg_fail_reason); + break; + } +} + +static int wave5_wait_fio_readl(struct vpu_device *vpu_dev, u32 addr, u32 val) +{ + u32 ctrl; + int ret; + + ctrl = addr & 0xffff; + wave5_vdi_write_register(vpu_dev, W5_VPU_FIO_CTRL_ADDR, ctrl); + ret = read_poll_timeout(wave5_vdi_read_register, ctrl, ctrl & FIO_CTRL_READY, + 0, FIO_TIMEOUT, false, vpu_dev, W5_VPU_FIO_CTRL_ADDR); + if (ret) + return ret; + + if (wave5_vdi_read_register(vpu_dev, W5_VPU_FIO_DATA) != val) + return -ETIMEDOUT; + + return 0; +} + +static void wave5_fio_writel(struct vpu_device *vpu_dev, unsigned int addr, unsigned int data) +{ + int ret; + unsigned int ctrl; + + wave5_vdi_write_register(vpu_dev, W5_VPU_FIO_DATA, data); + ctrl = FIELD_GET(FASTIO_ADDRESS_MASK, addr); + ctrl |= FIO_CTRL_WRITE; + wave5_vdi_write_register(vpu_dev, W5_VPU_FIO_CTRL_ADDR, ctrl); + ret = read_poll_timeout(wave5_vdi_read_register, ctrl, ctrl & FIO_CTRL_READY, 0, + FIO_TIMEOUT, false, vpu_dev, W5_VPU_FIO_CTRL_ADDR); + if (ret) + dev_dbg_ratelimited(vpu_dev->dev, "FIO write timeout: addr=0x%x data=%x\n", + ctrl, data); +} + +static int wave5_wait_bus_busy(struct vpu_device *vpu_dev, unsigned int addr) +{ + u32 gdi_status_check_value = 0x3f; + + if (vpu_dev->product_code == WAVE521C_CODE || + vpu_dev->product_code == WAVE521_CODE || + vpu_dev->product_code == WAVE521E1_CODE) + gdi_status_check_value = 0x00ff1f3f; + + return wave5_wait_fio_readl(vpu_dev, addr, gdi_status_check_value); +} + +static int wave5_wait_vpu_busy(struct vpu_device *vpu_dev, unsigned int addr) +{ + u32 data; + + return read_poll_timeout(wave5_vdi_read_register, data, data == 0, + 0, VPU_BUSY_CHECK_TIMEOUT, false, vpu_dev, addr); +} + +static int wave5_wait_vcpu_bus_busy(struct vpu_device *vpu_dev, unsigned int addr) +{ + return wave5_wait_fio_readl(vpu_dev, addr, 0); +} + +bool wave5_vpu_is_init(struct vpu_device *vpu_dev) +{ + return vpu_read_reg(vpu_dev, W5_VCPU_CUR_PC) != 0; +} + +static dma_addr_t wave5_read_reg_for_mem_addr(struct vpu_instance *inst, + unsigned int reg_addr) +{ + dma_addr_t addr; + dma_addr_t high_addr = inst->dev->ext_addr; + u32 val; + + val = vpu_read_reg(inst->dev, reg_addr); + addr = ((high_addr << 32) | val); + + return addr; +} + +unsigned int wave5_vpu_get_product_id(struct vpu_device *vpu_dev) +{ + u32 val = vpu_read_reg(vpu_dev, W5_PRODUCT_NUMBER); + + switch (val) { + case WAVE521C_CODE: + return PRODUCT_ID_521; + case WAVE521_CODE: + case WAVE521C_DUAL_CODE: + case WAVE521E1_CODE: + case WAVE511_CODE: + case WAVE517_CODE: + case WAVE537_CODE: + dev_err(vpu_dev->dev, "Unsupported product id (%x)\n", val); + break; + default: + dev_err(vpu_dev->dev, "Invalid product id (%x)\n", val); + break; + } + + return PRODUCT_ID_NONE; +} + +static void wave5_bit_issue_command(struct vpu_device *vpu_dev, struct vpu_instance *inst, u32 cmd) +{ + u32 instance_index; + u32 codec_mode; + + if (inst) { + instance_index = inst->id; + codec_mode = inst->std; + + vpu_write_reg(vpu_dev, W5_CMD_INSTANCE_INFO, (codec_mode << 16) | + (instance_index & 0xffff)); + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); + } + + vpu_write_reg(vpu_dev, W5_COMMAND, cmd); + + if (inst) { + dev_dbg(vpu_dev->dev, "%s: cmd=0x%x (%s)\n", __func__, cmd, + cmd_to_str(cmd, inst->type == VPU_INST_TYPE_DEC)); + } else { + dev_dbg(vpu_dev->dev, "%s: cmd=0x%x\n", __func__, cmd); + } + + vpu_write_reg(vpu_dev, W5_VPU_HOST_INT_REQ, 1); +} + +static int wave5_vpu_firmware_command_queue_error_check(struct vpu_device *dev, u32 *fail_res) +{ + u32 reason = 0; + + /* Check if we were able to add a command into the VCPU QUEUE */ + if (!vpu_read_reg(dev, W5_RET_SUCCESS)) { + reason = vpu_read_reg(dev, W5_RET_FAIL_REASON); + PRINT_REG_ERR(dev, reason); + + /* + * The fail_res argument will be either NULL or 0. + * If the fail_res argument is NULL, then just return -EIO. + * Otherwise, assign the reason to fail_res, so that the + * calling function can use it. + */ + if (fail_res) + *fail_res = reason; + else + return -EIO; + + if (reason == WAVE5_SYSERR_VPU_STILL_RUNNING) + return -EBUSY; + } + return 0; +} + +static int send_firmware_command(struct vpu_instance *inst, u32 cmd, bool check_success, + u32 *queue_status, u32 *fail_result) +{ + int ret; + + wave5_bit_issue_command(inst->dev, inst, cmd); + ret = wave5_wait_vpu_busy(inst->dev, W5_VPU_BUSY_STATUS); + if (ret) { + dev_warn(inst->dev->dev, "%s: command: '%s', timed out\n", __func__, + cmd_to_str(cmd, inst->type == VPU_INST_TYPE_DEC)); + return -ETIMEDOUT; + } + + if (queue_status) + *queue_status = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS); + + /* In some cases we want to send multiple commands before checking + * whether they are queued properly + */ + if (!check_success) + return 0; + + return wave5_vpu_firmware_command_queue_error_check(inst->dev, fail_result); +} + +static int wave5_send_query(struct vpu_device *vpu_dev, struct vpu_instance *inst, + enum query_opt query_opt) +{ + int ret; + + vpu_write_reg(vpu_dev, W5_QUERY_OPTION, query_opt); + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); + wave5_bit_issue_command(vpu_dev, inst, W5_QUERY); + + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS); + if (ret) { + dev_warn(vpu_dev->dev, "command: 'W5_QUERY', timed out opt=0x%x\n", query_opt); + return ret; + } + + return wave5_vpu_firmware_command_queue_error_check(vpu_dev, NULL); +} + +static int setup_wave5_properties(struct device *dev) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + struct vpu_attr *p_attr = &vpu_dev->attr; + u32 reg_val; + u8 *str; + int ret; + u32 hw_config_def0, hw_config_def1, hw_config_feature; + + ret = wave5_send_query(vpu_dev, NULL, GET_VPU_INFO); + if (ret) + return ret; + + reg_val = vpu_read_reg(vpu_dev, W5_RET_PRODUCT_NAME); + str = (u8 *)®_val; + p_attr->product_name[0] = str[3]; + p_attr->product_name[1] = str[2]; + p_attr->product_name[2] = str[1]; + p_attr->product_name[3] = str[0]; + p_attr->product_name[4] = 0; + + p_attr->product_id = wave5_vpu_get_product_id(vpu_dev); + p_attr->product_version = vpu_read_reg(vpu_dev, W5_RET_PRODUCT_VERSION); + p_attr->fw_version = vpu_read_reg(vpu_dev, W5_RET_FW_VERSION); + p_attr->customer_id = vpu_read_reg(vpu_dev, W5_RET_CUSTOMER_ID); + hw_config_def0 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF0); + hw_config_def1 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF1); + hw_config_feature = vpu_read_reg(vpu_dev, W5_RET_CONF_FEATURE); + + p_attr->support_hevc10bit_enc = FIELD_GET(FEATURE_HEVC10BIT_ENC, hw_config_feature); + p_attr->support_avc10bit_enc = FIELD_GET(FEATURE_AVC10BIT_ENC, hw_config_feature); + + p_attr->support_decoders = FIELD_GET(FEATURE_AVC_DECODER, hw_config_def1) << STD_AVC; + p_attr->support_decoders |= FIELD_GET(FEATURE_HEVC_DECODER, hw_config_def1) << STD_HEVC; + p_attr->support_encoders = FIELD_GET(FEATURE_AVC_ENCODER, hw_config_def1) << STD_AVC; + p_attr->support_encoders |= FIELD_GET(FEATURE_HEVC_ENCODER, hw_config_def1) << STD_HEVC; + + p_attr->support_backbone = FIELD_GET(FEATURE_BACKBONE, hw_config_def0); + p_attr->support_vcpu_backbone = FIELD_GET(FEATURE_VCPU_BACKBONE, hw_config_def0); + p_attr->support_vcore_backbone = FIELD_GET(FEATURE_VCORE_BACKBONE, hw_config_def0); + + return 0; +} + +int wave5_vpu_get_version(struct vpu_device *vpu_dev, u32 *revision) +{ + u32 reg_val; + int ret; + + ret = wave5_send_query(vpu_dev, NULL, GET_VPU_INFO); + if (ret) + return ret; + + reg_val = vpu_read_reg(vpu_dev, W5_RET_FW_VERSION); + if (revision) { + *revision = reg_val; + return 0; + } + + return -EINVAL; +} + +static void remap_page(struct vpu_device *vpu_dev, dma_addr_t code_base, u32 index) +{ + vpu_write_reg(vpu_dev, W5_VPU_REMAP_CTRL, REMAP_CTRL_REGISTER_VALUE(index)); + vpu_write_reg(vpu_dev, W5_VPU_REMAP_VADDR, index * W5_REMAP_MAX_SIZE); + vpu_write_reg(vpu_dev, W5_VPU_REMAP_PADDR, code_base + index * W5_REMAP_MAX_SIZE); +} + +int wave5_vpu_init(struct device *dev, u8 *fw, size_t size) +{ + struct vpu_buf *common_vb; + dma_addr_t code_base, temp_base; + u32 code_size, temp_size; + u32 i, reg_val, reason_code; + int ret; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + common_vb = &vpu_dev->common_mem; + + code_base = common_vb->daddr; + /* ALIGN TO 4KB */ + code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff); + if (code_size < size * 2) + return -EINVAL; + + temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET; + temp_size = WAVE5_TEMPBUF_SIZE; + + ret = wave5_vdi_write_memory(vpu_dev, common_vb, 0, fw, size); + if (ret < 0) { + dev_err(vpu_dev->dev, "VPU init, Writing firmware to common buffer, fail: %d\n", + ret); + return ret; + } + + vpu_write_reg(vpu_dev, W5_PO_CONF, 0); + + /* clear registers */ + + for (i = W5_CMD_REG_BASE; i < W5_CMD_REG_END; i += 4) + vpu_write_reg(vpu_dev, i, 0x00); + + remap_page(vpu_dev, code_base, W5_REMAP_INDEX0); + remap_page(vpu_dev, code_base, W5_REMAP_INDEX1); + + vpu_write_reg(vpu_dev, W5_ADDR_CODE_BASE, code_base); + vpu_write_reg(vpu_dev, W5_CODE_SIZE, code_size); + vpu_write_reg(vpu_dev, W5_CODE_PARAM, (WAVE5_UPPER_PROC_AXI_ID << 4) | 0); + vpu_write_reg(vpu_dev, W5_ADDR_TEMP_BASE, temp_base); + vpu_write_reg(vpu_dev, W5_TEMP_SIZE, temp_size); + + /* These register must be reset explicitly */ + vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); + reg_val = (vpu_dev->ext_addr & 0xFFFF); + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, reg_val); + wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); + vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); + + /* Encoder interrupt */ + reg_val = BIT(INT_WAVE5_ENC_SET_PARAM); + reg_val |= BIT(INT_WAVE5_ENC_PIC); + reg_val |= BIT(INT_WAVE5_BSBUF_FULL); + /* Decoder interrupt */ + reg_val |= BIT(INT_WAVE5_INIT_SEQ); + reg_val |= BIT(INT_WAVE5_DEC_PIC); + reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY); + vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val); + + reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); + if (FIELD_GET(FEATURE_BACKBONE, reg_val)) { + reg_val = ((WAVE5_PROC_AXI_ID << 28) | + (WAVE5_PRP_AXI_ID << 24) | + (WAVE5_FBD_Y_AXI_ID << 20) | + (WAVE5_FBC_Y_AXI_ID << 16) | + (WAVE5_FBD_C_AXI_ID << 12) | + (WAVE5_FBC_C_AXI_ID << 8) | + (WAVE5_PRI_AXI_ID << 4) | + WAVE5_SEC_AXI_ID); + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val); + } + + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); + vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU); + vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1); + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS); + if (ret) { + dev_err(vpu_dev->dev, "VPU init(W5_VPU_REMAP_CORE_START) timeout\n"); + return ret; + } + + ret = wave5_vpu_firmware_command_queue_error_check(vpu_dev, &reason_code); + if (ret) + return ret; + + return setup_wave5_properties(dev); +} + +int wave5_vpu_build_up_dec_param(struct vpu_instance *inst, + struct dec_open_param *param) +{ + int ret; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + struct vpu_device *vpu_dev = inst->dev; + + p_dec_info->cycle_per_tick = 256; + if (vpu_dev->sram_buf.size) { + p_dec_info->sec_axi_info.use_bit_enable = 1; + p_dec_info->sec_axi_info.use_ip_enable = 1; + p_dec_info->sec_axi_info.use_lf_row_enable = 1; + } + switch (inst->std) { + case W_HEVC_DEC: + p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_HEVC; + break; + case W_AVC_DEC: + p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_AVC; + break; + default: + return -EINVAL; + } + + p_dec_info->vb_work.size = WAVE521DEC_WORKBUF_SIZE; + ret = wave5_vdi_allocate_dma_memory(inst->dev, &p_dec_info->vb_work); + if (ret) + return ret; + + vpu_write_reg(inst->dev, W5_CMD_DEC_VCORE_INFO, 1); + + wave5_vdi_clear_memory(inst->dev, &p_dec_info->vb_work); + + vpu_write_reg(inst->dev, W5_ADDR_WORK_BASE, p_dec_info->vb_work.daddr); + vpu_write_reg(inst->dev, W5_WORK_SIZE, p_dec_info->vb_work.size); + + vpu_write_reg(inst->dev, W5_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr); + vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size); + + vpu_write_reg(inst->dev, W5_CMD_DEC_BS_START_ADDR, p_dec_info->stream_buf_start_addr); + vpu_write_reg(inst->dev, W5_CMD_DEC_BS_SIZE, p_dec_info->stream_buf_size); + + /* NOTE: SDMA reads MSB first */ + vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, BITSTREAM_ENDIANNESS_BIG_ENDIAN); + /* This register must be reset explicitly */ + vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, inst->dev->ext_addr); + vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1)); + + ret = send_firmware_command(inst, W5_CREATE_INSTANCE, true, NULL, NULL); + if (ret) { + wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_work); + return ret; + } + + p_dec_info->product_code = vpu_read_reg(inst->dev, W5_PRODUCT_NUMBER); + + return 0; +} + +int wave5_vpu_hw_flush_instance(struct vpu_instance *inst) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + u32 instance_queue_count, report_queue_count; + u32 reg_val = 0; + u32 fail_res = 0; + int ret; + + ret = send_firmware_command(inst, W5_FLUSH_INSTANCE, true, ®_val, &fail_res); + if (ret) + return ret; + + instance_queue_count = (reg_val >> 16) & 0xff; + report_queue_count = (reg_val & QUEUE_REPORT_MASK); + if (instance_queue_count != 0 || report_queue_count != 0) { + dev_warn(inst->dev->dev, + "FLUSH_INSTANCE cmd didn't reset the amount of queued commands & reports"); + } + + /* reset our local copy of the counts */ + p_dec_info->instance_queue_count = 0; + p_dec_info->report_queue_count = 0; + + return 0; +} + +static u32 get_bitstream_options(struct dec_info *info) +{ + u32 bs_option = BSOPTION_ENABLE_EXPLICIT_END; + + if (info->stream_endflag) + bs_option |= BSOPTION_HIGHLIGHT_STREAM_END; + return bs_option; +} + +int wave5_vpu_dec_init_seq(struct vpu_instance *inst) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + u32 cmd_option = INIT_SEQ_NORMAL; + u32 reg_val, fail_res; + int ret; + + if (!inst->codec_info) + return -EINVAL; + + vpu_write_reg(inst->dev, W5_BS_RD_PTR, p_dec_info->stream_rd_ptr); + vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr); + + vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info)); + + vpu_write_reg(inst->dev, W5_COMMAND_OPTION, cmd_option); + vpu_write_reg(inst->dev, W5_CMD_DEC_USER_MASK, p_dec_info->user_data_enable); + + ret = send_firmware_command(inst, W5_INIT_SEQ, true, ®_val, &fail_res); + if (ret) + return ret; + + p_dec_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_dec_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + dev_dbg(inst->dev->dev, "%s: init seq sent (queue %u : %u)\n", __func__, + p_dec_info->instance_queue_count, p_dec_info->report_queue_count); + + return 0; +} + +static void wave5_get_dec_seq_result(struct vpu_instance *inst, struct dec_initial_info *info) +{ + u32 reg_val; + u32 profile_compatibility_flag; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + + p_dec_info->stream_rd_ptr = wave5_dec_get_rd_ptr(inst); + info->rd_ptr = p_dec_info->stream_rd_ptr; + + p_dec_info->frame_display_flag = vpu_read_reg(inst->dev, W5_RET_DEC_DISP_IDC); + + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_SIZE); + info->pic_width = ((reg_val >> 16) & 0xffff); + info->pic_height = (reg_val & 0xffff); + info->min_frame_buffer_count = vpu_read_reg(inst->dev, W5_RET_DEC_NUM_REQUIRED_FB); + + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_CROP_LEFT_RIGHT); + info->pic_crop_rect.left = (reg_val >> 16) & 0xffff; + info->pic_crop_rect.right = reg_val & 0xffff; + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_CROP_TOP_BOTTOM); + info->pic_crop_rect.top = (reg_val >> 16) & 0xffff; + info->pic_crop_rect.bottom = reg_val & 0xffff; + + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_COLOR_SAMPLE_INFO); + info->luma_bitdepth = reg_val & 0xf; + info->chroma_bitdepth = (reg_val >> 4) & 0xf; + + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_SEQ_PARAM); + profile_compatibility_flag = (reg_val >> 12) & 0xff; + info->profile = (reg_val >> 24) & 0x1f; + + if (inst->std == W_HEVC_DEC) { + /* guessing profile */ + if (!info->profile) { + if ((profile_compatibility_flag & 0x06) == 0x06) + info->profile = HEVC_PROFILE_MAIN; /* main profile */ + else if (profile_compatibility_flag & 0x04) + info->profile = HEVC_PROFILE_MAIN10; /* main10 profile */ + else if (profile_compatibility_flag & 0x08) + /* main still picture profile */ + info->profile = HEVC_PROFILE_STILLPICTURE; + else + info->profile = HEVC_PROFILE_MAIN; /* for old version HM */ + } + } else if (inst->std == W_AVC_DEC) { + info->profile = FIELD_GET(SEQ_PARAM_PROFILE_MASK, reg_val); + } + + info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE); + info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE); + p_dec_info->vlc_buf_size = info->vlc_buf_size; + p_dec_info->param_buf_size = info->param_buf_size; +} + +int wave5_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info) +{ + int ret; + u32 reg_val; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + + vpu_write_reg(inst->dev, W5_CMD_DEC_ADDR_REPORT_BASE, p_dec_info->user_data_buf_addr); + vpu_write_reg(inst->dev, W5_CMD_DEC_REPORT_SIZE, p_dec_info->user_data_buf_size); + vpu_write_reg(inst->dev, W5_CMD_DEC_REPORT_PARAM, REPORT_PARAM_ENDIANNESS_BIG_ENDIAN); + + /* send QUERY cmd */ + ret = wave5_send_query(inst->dev, inst, GET_RESULT); + if (ret) + return ret; + + reg_val = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS); + + p_dec_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_dec_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + dev_dbg(inst->dev->dev, "%s: init seq complete (queue %u : %u)\n", __func__, + p_dec_info->instance_queue_count, p_dec_info->report_queue_count); + + /* this is not a fatal error, set ret to -EIO but don't return immediately */ + if (vpu_read_reg(inst->dev, W5_RET_DEC_DECODING_SUCCESS) != 1) { + info->seq_init_err_reason = vpu_read_reg(inst->dev, W5_RET_DEC_ERR_INFO); + ret = -EIO; + } + + wave5_get_dec_seq_result(inst, info); + + return ret; +} + +int wave5_vpu_dec_register_framebuffer(struct vpu_instance *inst, struct frame_buffer *fb_arr, + enum tiled_map_type map_type, unsigned int count) +{ + int ret; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + struct dec_initial_info *init_info = &p_dec_info->initial_info; + size_t remain, idx, j, i, cnt_8_chunk, size; + u32 start_no, end_no; + u32 reg_val, cbcr_interleave, nv21, pic_size; + u32 addr_y, addr_cb, addr_cr; + u32 mv_col_size, frame_width, frame_height, fbc_y_tbl_size, fbc_c_tbl_size; + struct vpu_buf vb_buf; + bool justified = WTL_RIGHT_JUSTIFIED; + u32 format_no = WTL_PIXEL_8BIT; + u32 color_format = 0; + u32 pixel_order = 1; + u32 bwb_flag = (map_type == LINEAR_FRAME_MAP) ? 1 : 0; + + cbcr_interleave = inst->cbcr_interleave; + nv21 = inst->nv21; + mv_col_size = 0; + fbc_y_tbl_size = 0; + fbc_c_tbl_size = 0; + + if (map_type >= COMPRESSED_FRAME_MAP) { + cbcr_interleave = 0; + nv21 = 0; + + switch (inst->std) { + case W_HEVC_DEC: + mv_col_size = WAVE5_DEC_HEVC_BUF_SIZE(init_info->pic_width, + init_info->pic_height); + break; + case W_AVC_DEC: + mv_col_size = WAVE5_DEC_AVC_BUF_SIZE(init_info->pic_width, + init_info->pic_height); + break; + default: + return -EINVAL; + } + + if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC) { + size = ALIGN(ALIGN(mv_col_size, 16), BUFFER_MARGIN) + BUFFER_MARGIN; + ret = wave5_vdi_allocate_array(inst->dev, p_dec_info->vb_mv, count, size); + if (ret) + goto free_mv_buffers; + } + + frame_width = init_info->pic_width; + frame_height = init_info->pic_height; + fbc_y_tbl_size = ALIGN(WAVE5_FBC_LUMA_TABLE_SIZE(frame_width, frame_height), 16); + fbc_c_tbl_size = ALIGN(WAVE5_FBC_CHROMA_TABLE_SIZE(frame_width, frame_height), 16); + + size = ALIGN(fbc_y_tbl_size, BUFFER_MARGIN) + BUFFER_MARGIN; + ret = wave5_vdi_allocate_array(inst->dev, p_dec_info->vb_fbc_y_tbl, count, size); + if (ret) + goto free_fbc_y_tbl_buffers; + + size = ALIGN(fbc_c_tbl_size, BUFFER_MARGIN) + BUFFER_MARGIN; + ret = wave5_vdi_allocate_array(inst->dev, p_dec_info->vb_fbc_c_tbl, count, size); + if (ret) + goto free_fbc_c_tbl_buffers; + + pic_size = (init_info->pic_width << 16) | (init_info->pic_height); + + vb_buf.size = (p_dec_info->vlc_buf_size * VLC_BUF_NUM) + + (p_dec_info->param_buf_size * COMMAND_QUEUE_DEPTH); + vb_buf.daddr = 0; + + if (vb_buf.size != p_dec_info->vb_task.size) { + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task); + ret = wave5_vdi_allocate_dma_memory(inst->dev, &vb_buf); + if (ret) + goto free_fbc_c_tbl_buffers; + + p_dec_info->vb_task = vb_buf; + } + + vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF, + p_dec_info->vb_task.daddr); + vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE, vb_buf.size); + } else { + pic_size = (init_info->pic_width << 16) | (init_info->pic_height); + + if (inst->output_format == FORMAT_422) + color_format = 1; + } + vpu_write_reg(inst->dev, W5_PIC_SIZE, pic_size); + + reg_val = (bwb_flag << 28) | + (pixel_order << 23) | + (justified << 22) | + (format_no << 20) | + (color_format << 19) | + (nv21 << 17) | + (cbcr_interleave << 16) | + (fb_arr[0].stride); + vpu_write_reg(inst->dev, W5_COMMON_PIC_INFO, reg_val); + + remain = count; + cnt_8_chunk = DIV_ROUND_UP(count, 8); + idx = 0; + for (j = 0; j < cnt_8_chunk; j++) { + reg_val = (j == cnt_8_chunk - 1) << 4 | ((j == 0) << 3); + vpu_write_reg(inst->dev, W5_SFB_OPTION, reg_val); + start_no = j * 8; + end_no = start_no + ((remain >= 8) ? 8 : remain) - 1; + + vpu_write_reg(inst->dev, W5_SET_FB_NUM, (start_no << 8) | end_no); + + for (i = 0; i < 8 && i < remain; i++) { + addr_y = fb_arr[i + start_no].buf_y; + addr_cb = fb_arr[i + start_no].buf_cb; + addr_cr = fb_arr[i + start_no].buf_cr; + vpu_write_reg(inst->dev, W5_ADDR_LUMA_BASE0 + (i << 4), addr_y); + vpu_write_reg(inst->dev, W5_ADDR_CB_BASE0 + (i << 4), addr_cb); + if (map_type >= COMPRESSED_FRAME_MAP) { + /* luma FBC offset table */ + vpu_write_reg(inst->dev, W5_ADDR_FBC_Y_OFFSET0 + (i << 4), + p_dec_info->vb_fbc_y_tbl[idx].daddr); + /* chroma FBC offset table */ + vpu_write_reg(inst->dev, W5_ADDR_FBC_C_OFFSET0 + (i << 4), + p_dec_info->vb_fbc_c_tbl[idx].daddr); + vpu_write_reg(inst->dev, W5_ADDR_MV_COL0 + (i << 2), + p_dec_info->vb_mv[idx].daddr); + } else { + vpu_write_reg(inst->dev, W5_ADDR_CR_BASE0 + (i << 4), addr_cr); + vpu_write_reg(inst->dev, W5_ADDR_FBC_C_OFFSET0 + (i << 4), 0); + vpu_write_reg(inst->dev, W5_ADDR_MV_COL0 + (i << 2), 0); + } + idx++; + } + remain -= i; + + ret = send_firmware_command(inst, W5_SET_FB, false, NULL, NULL); + if (ret) + goto free_buffers; + } + + reg_val = vpu_read_reg(inst->dev, W5_RET_SUCCESS); + if (!reg_val) { + ret = -EIO; + goto free_buffers; + } + + return 0; + +free_buffers: + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task); +free_fbc_c_tbl_buffers: + for (i = 0; i < count; i++) + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_fbc_c_tbl[i]); +free_fbc_y_tbl_buffers: + for (i = 0; i < count; i++) + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_fbc_y_tbl[i]); +free_mv_buffers: + for (i = 0; i < count; i++) + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_mv[i]); + return ret; +} + +int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res) +{ + u32 reg_val; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + + vpu_write_reg(inst->dev, W5_BS_RD_PTR, p_dec_info->stream_rd_ptr); + vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr); + + vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info)); + + /* secondary AXI */ + reg_val = p_dec_info->sec_axi_info.use_bit_enable | + (p_dec_info->sec_axi_info.use_ip_enable << 9) | + (p_dec_info->sec_axi_info.use_lf_row_enable << 15); + vpu_write_reg(inst->dev, W5_USE_SEC_AXI, reg_val); + + /* set attributes of user buffer */ + vpu_write_reg(inst->dev, W5_CMD_DEC_USER_MASK, p_dec_info->user_data_enable); + + vpu_write_reg(inst->dev, W5_COMMAND_OPTION, DEC_PIC_NORMAL); + vpu_write_reg(inst->dev, W5_CMD_DEC_TEMPORAL_ID_PLUS1, + (p_dec_info->target_spatial_id << 9) | + (p_dec_info->temp_id_select_mode << 8) | p_dec_info->target_temp_id); + vpu_write_reg(inst->dev, W5_CMD_SEQ_CHANGE_ENABLE_FLAG, p_dec_info->seq_change_mask); + /* When reordering is disabled we force the latency of the framebuffers */ + vpu_write_reg(inst->dev, W5_CMD_DEC_FORCE_FB_LATENCY_PLUS1, !p_dec_info->reorder_enable); + + ret = send_firmware_command(inst, W5_DEC_ENC_PIC, true, ®_val, fail_res); + if (ret == -ETIMEDOUT) + return ret; + + p_dec_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_dec_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + dev_dbg(inst->dev->dev, "%s: dec pic sent (queue %u : %u)\n", __func__, + p_dec_info->instance_queue_count, p_dec_info->report_queue_count); + + if (ret) + return ret; + + return 0; +} + +int wave5_vpu_dec_get_result(struct vpu_instance *inst, struct dec_output_info *result) +{ + int ret; + u32 index, nal_unit_type, reg_val, sub_layer_info; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + struct vpu_device *vpu_dev = inst->dev; + + vpu_write_reg(inst->dev, W5_CMD_DEC_ADDR_REPORT_BASE, p_dec_info->user_data_buf_addr); + vpu_write_reg(inst->dev, W5_CMD_DEC_REPORT_SIZE, p_dec_info->user_data_buf_size); + vpu_write_reg(inst->dev, W5_CMD_DEC_REPORT_PARAM, REPORT_PARAM_ENDIANNESS_BIG_ENDIAN); + + /* send QUERY cmd */ + ret = wave5_send_query(vpu_dev, inst, GET_RESULT); + if (ret) + return ret; + + reg_val = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS); + + p_dec_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_dec_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + dev_dbg(inst->dev->dev, "%s: dec pic complete (queue %u : %u)\n", __func__, + p_dec_info->instance_queue_count, p_dec_info->report_queue_count); + + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_TYPE); + + nal_unit_type = (reg_val >> 4) & 0x3f; + + if (inst->std == W_HEVC_DEC) { + if (reg_val & 0x04) + result->pic_type = PIC_TYPE_B; + else if (reg_val & 0x02) + result->pic_type = PIC_TYPE_P; + else if (reg_val & 0x01) + result->pic_type = PIC_TYPE_I; + else + result->pic_type = PIC_TYPE_MAX; + if ((nal_unit_type == 19 || nal_unit_type == 20) && result->pic_type == PIC_TYPE_I) + /* IDR_W_RADL, IDR_N_LP */ + result->pic_type = PIC_TYPE_IDR; + } else if (inst->std == W_AVC_DEC) { + if (reg_val & 0x04) + result->pic_type = PIC_TYPE_B; + else if (reg_val & 0x02) + result->pic_type = PIC_TYPE_P; + else if (reg_val & 0x01) + result->pic_type = PIC_TYPE_I; + else + result->pic_type = PIC_TYPE_MAX; + if (nal_unit_type == 5 && result->pic_type == PIC_TYPE_I) + result->pic_type = PIC_TYPE_IDR; + } + index = vpu_read_reg(inst->dev, W5_RET_DEC_DISPLAY_INDEX); + result->index_frame_display = index; + index = vpu_read_reg(inst->dev, W5_RET_DEC_DECODED_INDEX); + result->index_frame_decoded = index; + result->index_frame_decoded_for_tiled = index; + + sub_layer_info = vpu_read_reg(inst->dev, W5_RET_DEC_SUB_LAYER_INFO); + result->temporal_id = sub_layer_info & 0x7; + + if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC) { + result->decoded_poc = -1; + if (result->index_frame_decoded >= 0 || + result->index_frame_decoded == DECODED_IDX_FLAG_SKIP) + result->decoded_poc = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_POC); + } + + result->sequence_changed = vpu_read_reg(inst->dev, W5_RET_DEC_NOTIFICATION); + reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_SIZE); + result->dec_pic_width = reg_val >> 16; + result->dec_pic_height = reg_val & 0xffff; + + if (result->sequence_changed) { + memcpy((void *)&p_dec_info->new_seq_info, (void *)&p_dec_info->initial_info, + sizeof(struct dec_initial_info)); + wave5_get_dec_seq_result(inst, &p_dec_info->new_seq_info); + } + + result->dec_host_cmd_tick = vpu_read_reg(inst->dev, W5_RET_DEC_HOST_CMD_TICK); + result->dec_decode_end_tick = vpu_read_reg(inst->dev, W5_RET_DEC_DECODING_ENC_TICK); + + if (!p_dec_info->first_cycle_check) { + result->frame_cycle = + (result->dec_decode_end_tick - result->dec_host_cmd_tick) * + p_dec_info->cycle_per_tick; + vpu_dev->last_performance_cycles = result->dec_decode_end_tick; + p_dec_info->first_cycle_check = true; + } else if (result->index_frame_decoded_for_tiled != -1) { + result->frame_cycle = + (result->dec_decode_end_tick - vpu_dev->last_performance_cycles) * + p_dec_info->cycle_per_tick; + vpu_dev->last_performance_cycles = result->dec_decode_end_tick; + if (vpu_dev->last_performance_cycles < result->dec_host_cmd_tick) + result->frame_cycle = + (result->dec_decode_end_tick - result->dec_host_cmd_tick) * + p_dec_info->cycle_per_tick; + } + + /* no remaining command. reset frame cycle. */ + if (p_dec_info->instance_queue_count == 0 && p_dec_info->report_queue_count == 0) + p_dec_info->first_cycle_check = false; + + return 0; +} + +int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size) +{ + struct vpu_buf *common_vb; + dma_addr_t code_base, temp_base; + dma_addr_t old_code_base, temp_size; + u32 code_size, reason_code; + u32 reg_val; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + common_vb = &vpu_dev->common_mem; + + code_base = common_vb->daddr; + /* ALIGN TO 4KB */ + code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff); + if (code_size < size * 2) + return -EINVAL; + temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET; + temp_size = WAVE5_TEMPBUF_SIZE; + + old_code_base = vpu_read_reg(vpu_dev, W5_VPU_REMAP_PADDR); + + if (old_code_base != code_base + W5_REMAP_INDEX1 * W5_REMAP_MAX_SIZE) { + int ret; + + ret = wave5_vdi_write_memory(vpu_dev, common_vb, 0, fw, size); + if (ret < 0) { + dev_err(vpu_dev->dev, + "VPU init, Writing firmware to common buffer, fail: %d\n", ret); + return ret; + } + + vpu_write_reg(vpu_dev, W5_PO_CONF, 0); + + ret = wave5_vpu_reset(dev, SW_RESET_ON_BOOT); + if (ret < 0) { + dev_err(vpu_dev->dev, "VPU init, Resetting the VPU, fail: %d\n", ret); + return ret; + } + + remap_page(vpu_dev, code_base, W5_REMAP_INDEX0); + remap_page(vpu_dev, code_base, W5_REMAP_INDEX1); + + vpu_write_reg(vpu_dev, W5_ADDR_CODE_BASE, code_base); + vpu_write_reg(vpu_dev, W5_CODE_SIZE, code_size); + vpu_write_reg(vpu_dev, W5_CODE_PARAM, (WAVE5_UPPER_PROC_AXI_ID << 4) | 0); + vpu_write_reg(vpu_dev, W5_ADDR_TEMP_BASE, temp_base); + vpu_write_reg(vpu_dev, W5_TEMP_SIZE, temp_size); + + /* These register must be reset explicitly */ + vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); + reg_val = (vpu_dev->ext_addr & 0xFFFF); + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, reg_val); + wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); + vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); + + /* Encoder interrupt */ + reg_val = BIT(INT_WAVE5_ENC_SET_PARAM); + reg_val |= BIT(INT_WAVE5_ENC_PIC); + reg_val |= BIT(INT_WAVE5_BSBUF_FULL); + /* Decoder interrupt */ + reg_val |= BIT(INT_WAVE5_INIT_SEQ); + reg_val |= BIT(INT_WAVE5_DEC_PIC); + reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY); + vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val); + + reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); + if (FIELD_GET(FEATURE_BACKBONE, reg_val)) { + reg_val = ((WAVE5_PROC_AXI_ID << 28) | + (WAVE5_PRP_AXI_ID << 24) | + (WAVE5_FBD_Y_AXI_ID << 20) | + (WAVE5_FBC_Y_AXI_ID << 16) | + (WAVE5_FBD_C_AXI_ID << 12) | + (WAVE5_FBC_C_AXI_ID << 8) | + (WAVE5_PRI_AXI_ID << 4) | + WAVE5_SEC_AXI_ID); + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val); + } + + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); + vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU); + vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1); + + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS); + if (ret) { + dev_err(vpu_dev->dev, "VPU reinit(W5_VPU_REMAP_CORE_START) timeout\n"); + return ret; + } + + ret = wave5_vpu_firmware_command_queue_error_check(vpu_dev, &reason_code); + if (ret) + return ret; + } + + return setup_wave5_properties(dev); +} + +int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code, + size_t size) +{ + u32 reg_val; + struct vpu_buf *common_vb; + dma_addr_t code_base; + u32 code_size, reason_code; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + int ret; + + if (i_sleep_wake) { + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS); + if (ret) + return ret; + + /* + * Declare who has ownership for the host interface access + * 1 = VPU + * 0 = Host processor + */ + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); + vpu_write_reg(vpu_dev, W5_COMMAND, W5_SLEEP_VPU); + /* Send an interrupt named HOST to the VPU */ + vpu_write_reg(vpu_dev, W5_VPU_HOST_INT_REQ, 1); + + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS); + if (ret) + return ret; + + ret = wave5_vpu_firmware_command_queue_error_check(vpu_dev, &reason_code); + if (ret) + return ret; + } else { /* restore */ + common_vb = &vpu_dev->common_mem; + + code_base = common_vb->daddr; + /* ALIGN TO 4KB */ + code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff); + if (code_size < size * 2) { + dev_err(dev, "size too small\n"); + return -EINVAL; + } + + /* Power on without DEBUG mode */ + vpu_write_reg(vpu_dev, W5_PO_CONF, 0); + + remap_page(vpu_dev, code_base, W5_REMAP_INDEX0); + remap_page(vpu_dev, code_base, W5_REMAP_INDEX1); + + vpu_write_reg(vpu_dev, W5_ADDR_CODE_BASE, code_base); + vpu_write_reg(vpu_dev, W5_CODE_SIZE, code_size); + vpu_write_reg(vpu_dev, W5_CODE_PARAM, (WAVE5_UPPER_PROC_AXI_ID << 4) | 0); + + /* These register must be reset explicitly */ + vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); + reg_val = (vpu_dev->ext_addr & 0xFFFF); + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, reg_val); + wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); + vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); + + /* Encoder interrupt */ + reg_val = BIT(INT_WAVE5_ENC_SET_PARAM); + reg_val |= BIT(INT_WAVE5_ENC_PIC); + reg_val |= BIT(INT_WAVE5_BSBUF_FULL); + /* Decoder interrupt */ + reg_val |= BIT(INT_WAVE5_INIT_SEQ); + reg_val |= BIT(INT_WAVE5_DEC_PIC); + reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY); + vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val); + + reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); + if (FIELD_GET(FEATURE_BACKBONE, reg_val)) { + reg_val = ((WAVE5_PROC_AXI_ID << 28) | + (WAVE5_PRP_AXI_ID << 24) | + (WAVE5_FBD_Y_AXI_ID << 20) | + (WAVE5_FBC_Y_AXI_ID << 16) | + (WAVE5_FBD_C_AXI_ID << 12) | + (WAVE5_FBC_C_AXI_ID << 8) | + (WAVE5_PRI_AXI_ID << 4) | + WAVE5_SEC_AXI_ID); + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val); + } + + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); + vpu_write_reg(vpu_dev, W5_COMMAND, W5_WAKEUP_VPU); + /* Start VPU after settings */ + vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1); + + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS); + if (ret) { + dev_err(vpu_dev->dev, "VPU wakeup(W5_VPU_REMAP_CORE_START) timeout\n"); + return ret; + } + + return wave5_vpu_firmware_command_queue_error_check(vpu_dev, &reason_code); + } + + return 0; +} + +int wave5_vpu_reset(struct device *dev, enum sw_reset_mode reset_mode) +{ + u32 val = 0; + int ret = 0; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + struct vpu_attr *p_attr = &vpu_dev->attr; + /* VPU doesn't send response. force to set BUSY flag to 0. */ + vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 0); + + if (reset_mode == SW_RESET_SAFETY) { + ret = wave5_vpu_sleep_wake(dev, true, NULL, 0); + if (ret) + return ret; + } + + val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); + if ((val >> 16) & 0x1) + p_attr->support_backbone = true; + if ((val >> 22) & 0x1) + p_attr->support_vcore_backbone = true; + if ((val >> 28) & 0x1) + p_attr->support_vcpu_backbone = true; + + /* waiting for completion of bus transaction */ + if (p_attr->support_backbone) { + dev_dbg(dev, "%s: backbone supported\n", __func__); + + if (p_attr->support_vcore_backbone) { + if (p_attr->support_vcpu_backbone) { + /* step1 : disable request */ + wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCPU, 0xFF); + + /* step2 : waiting for completion of bus transaction */ + ret = wave5_wait_vcpu_bus_busy(vpu_dev, + W5_BACKBONE_BUS_STATUS_VCPU); + if (ret) { + wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCPU, 0x00); + return ret; + } + } + /* step1 : disable request */ + wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCORE0, 0x7); + + /* step2 : waiting for completion of bus transaction */ + if (wave5_wait_bus_busy(vpu_dev, W5_BACKBONE_BUS_STATUS_VCORE0)) { + wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCORE0, 0x00); + return -EBUSY; + } + } else { + /* step1 : disable request */ + wave5_fio_writel(vpu_dev, W5_COMBINED_BACKBONE_BUS_CTRL, 0x7); + + /* step2 : waiting for completion of bus transaction */ + if (wave5_wait_bus_busy(vpu_dev, W5_COMBINED_BACKBONE_BUS_STATUS)) { + wave5_fio_writel(vpu_dev, W5_COMBINED_BACKBONE_BUS_CTRL, 0x00); + return -EBUSY; + } + } + } else { + dev_dbg(dev, "%s: backbone NOT supported\n", __func__); + /* step1 : disable request */ + wave5_fio_writel(vpu_dev, W5_GDI_BUS_CTRL, 0x100); + + /* step2 : waiting for completion of bus transaction */ + ret = wave5_wait_bus_busy(vpu_dev, W5_GDI_BUS_STATUS); + if (ret) { + wave5_fio_writel(vpu_dev, W5_GDI_BUS_CTRL, 0x00); + return ret; + } + } + + switch (reset_mode) { + case SW_RESET_ON_BOOT: + case SW_RESET_FORCE: + case SW_RESET_SAFETY: + val = W5_RST_BLOCK_ALL; + break; + default: + return -EINVAL; + } + + if (val) { + vpu_write_reg(vpu_dev, W5_VPU_RESET_REQ, val); + + ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_RESET_STATUS); + if (ret) { + vpu_write_reg(vpu_dev, W5_VPU_RESET_REQ, 0); + return ret; + } + vpu_write_reg(vpu_dev, W5_VPU_RESET_REQ, 0); + } + /* step3 : must clear GDI_BUS_CTRL after done SW_RESET */ + if (p_attr->support_backbone) { + if (p_attr->support_vcore_backbone) { + if (p_attr->support_vcpu_backbone) + wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCPU, 0x00); + wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCORE0, 0x00); + } else { + wave5_fio_writel(vpu_dev, W5_COMBINED_BACKBONE_BUS_CTRL, 0x00); + } + } else { + wave5_fio_writel(vpu_dev, W5_GDI_BUS_CTRL, 0x00); + } + if (reset_mode == SW_RESET_SAFETY || reset_mode == SW_RESET_FORCE) + ret = wave5_vpu_sleep_wake(dev, false, NULL, 0); + + return ret; +} + +int wave5_vpu_dec_finish_seq(struct vpu_instance *inst, u32 *fail_res) +{ + return send_firmware_command(inst, W5_DESTROY_INSTANCE, true, NULL, fail_res); +} + +int wave5_vpu_dec_set_bitstream_flag(struct vpu_instance *inst, bool eos) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + + p_dec_info->stream_endflag = eos ? 1 : 0; + vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info)); + vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr); + + return send_firmware_command(inst, W5_UPDATE_BS, true, NULL, NULL); +} + +int wave5_dec_clr_disp_flag(struct vpu_instance *inst, unsigned int index) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + + vpu_write_reg(inst->dev, W5_CMD_DEC_CLR_DISP_IDC, BIT(index)); + vpu_write_reg(inst->dev, W5_CMD_DEC_SET_DISP_IDC, 0); + + ret = wave5_send_query(inst->dev, inst, UPDATE_DISP_FLAG); + if (ret) + return ret; + + p_dec_info->frame_display_flag = vpu_read_reg(inst->dev, W5_RET_DEC_DISP_IDC); + + return 0; +} + +int wave5_dec_set_disp_flag(struct vpu_instance *inst, unsigned int index) +{ + int ret; + + vpu_write_reg(inst->dev, W5_CMD_DEC_CLR_DISP_IDC, 0); + vpu_write_reg(inst->dev, W5_CMD_DEC_SET_DISP_IDC, BIT(index)); + + ret = wave5_send_query(inst->dev, inst, UPDATE_DISP_FLAG); + if (ret) + return ret; + + return 0; +} + +int wave5_vpu_clear_interrupt(struct vpu_instance *inst, u32 flags) +{ + u32 interrupt_reason; + + interrupt_reason = vpu_read_reg(inst->dev, W5_VPU_VINT_REASON_USR); + interrupt_reason &= ~flags; + vpu_write_reg(inst->dev, W5_VPU_VINT_REASON_USR, interrupt_reason); + + return 0; +} + +dma_addr_t wave5_dec_get_rd_ptr(struct vpu_instance *inst) +{ + int ret; + + ret = wave5_send_query(inst->dev, inst, GET_BS_RD_PTR); + if (ret) + return inst->codec_info->dec_info.stream_rd_ptr; + + return wave5_read_reg_for_mem_addr(inst, W5_RET_QUERY_DEC_BS_RD_PTR); +} + +int wave5_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr) +{ + int ret; + + vpu_write_reg(inst->dev, W5_RET_QUERY_DEC_SET_BS_RD_PTR, addr); + + ret = wave5_send_query(inst->dev, inst, SET_BS_RD_PTR); + + return ret; +} + +/************************************************************************/ +/* ENCODER functions */ +/************************************************************************/ + +int wave5_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst, + struct enc_open_param *open_param) +{ + int ret; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + u32 reg_val; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + dma_addr_t buffer_addr; + size_t buffer_size; + + p_enc_info->cycle_per_tick = 256; + if (vpu_dev->sram_buf.size) { + p_enc_info->sec_axi_info.use_enc_rdo_enable = 1; + p_enc_info->sec_axi_info.use_enc_lf_enable = 1; + } + + p_enc_info->vb_work.size = WAVE521ENC_WORKBUF_SIZE; + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &p_enc_info->vb_work); + if (ret) { + memset(&p_enc_info->vb_work, 0, sizeof(p_enc_info->vb_work)); + return ret; + } + + wave5_vdi_clear_memory(vpu_dev, &p_enc_info->vb_work); + + vpu_write_reg(inst->dev, W5_ADDR_WORK_BASE, p_enc_info->vb_work.daddr); + vpu_write_reg(inst->dev, W5_WORK_SIZE, p_enc_info->vb_work.size); + + vpu_write_reg(inst->dev, W5_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr); + vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size); + + reg_val = (open_param->line_buf_int_en << 6) | BITSTREAM_ENDIANNESS_BIG_ENDIAN; + vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, reg_val); + vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, inst->dev->ext_addr); + vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1)); + + /* This register must be reset explicitly */ + vpu_write_reg(inst->dev, W5_CMD_ENC_SRC_OPTIONS, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_VCORE_INFO, 1); + + ret = send_firmware_command(inst, W5_CREATE_INSTANCE, true, NULL, NULL); + if (ret) + goto free_vb_work; + + buffer_addr = open_param->bitstream_buffer; + buffer_size = open_param->bitstream_buffer_size; + p_enc_info->stream_rd_ptr = buffer_addr; + p_enc_info->stream_wr_ptr = buffer_addr; + p_enc_info->line_buf_int_en = open_param->line_buf_int_en; + p_enc_info->stream_buf_start_addr = buffer_addr; + p_enc_info->stream_buf_size = buffer_size; + p_enc_info->stream_buf_end_addr = buffer_addr + buffer_size; + p_enc_info->stride = 0; + p_enc_info->initial_info_obtained = false; + p_enc_info->product_code = vpu_read_reg(inst->dev, W5_PRODUCT_NUMBER); + + return 0; +free_vb_work: + if (wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_work)) + memset(&p_enc_info->vb_work, 0, sizeof(p_enc_info->vb_work)); + return ret; +} + +static void wave5_set_enc_crop_info(u32 codec, struct enc_wave_param *param, int rot_mode, + int src_width, int src_height) +{ + int aligned_width = (codec == W_HEVC_ENC) ? ALIGN(src_width, 32) : ALIGN(src_width, 16); + int aligned_height = (codec == W_HEVC_ENC) ? ALIGN(src_height, 32) : ALIGN(src_height, 16); + int pad_right, pad_bot; + int crop_right, crop_left, crop_top, crop_bot; + int prp_mode = rot_mode >> 1; /* remove prp_enable bit */ + + if (codec == W_HEVC_ENC && + (!rot_mode || prp_mode == 14)) /* prp_mode 14 : hor_mir && ver_mir && rot_180 */ + return; + + pad_right = aligned_width - src_width; + pad_bot = aligned_height - src_height; + + if (param->conf_win_right > 0) + crop_right = param->conf_win_right + pad_right; + else + crop_right = pad_right; + + if (param->conf_win_bot > 0) + crop_bot = param->conf_win_bot + pad_bot; + else + crop_bot = pad_bot; + + crop_top = param->conf_win_top; + crop_left = param->conf_win_left; + + param->conf_win_top = crop_top; + param->conf_win_left = crop_left; + param->conf_win_bot = crop_bot; + param->conf_win_right = crop_right; + + switch (prp_mode) { + case 0: + return; + case 1: + case 15: + param->conf_win_top = crop_right; + param->conf_win_left = crop_top; + param->conf_win_bot = crop_left; + param->conf_win_right = crop_bot; + break; + case 2: + case 12: + param->conf_win_top = crop_bot; + param->conf_win_left = crop_right; + param->conf_win_bot = crop_top; + param->conf_win_right = crop_left; + break; + case 3: + case 13: + param->conf_win_top = crop_left; + param->conf_win_left = crop_bot; + param->conf_win_bot = crop_right; + param->conf_win_right = crop_top; + break; + case 4: + case 10: + param->conf_win_top = crop_bot; + param->conf_win_bot = crop_top; + break; + case 8: + case 6: + param->conf_win_left = crop_right; + param->conf_win_right = crop_left; + break; + case 5: + case 11: + param->conf_win_top = crop_left; + param->conf_win_left = crop_top; + param->conf_win_bot = crop_right; + param->conf_win_right = crop_bot; + break; + case 7: + case 9: + param->conf_win_top = crop_right; + param->conf_win_left = crop_bot; + param->conf_win_bot = crop_left; + param->conf_win_right = crop_top; + break; + default: + WARN(1, "Invalid prp_mode: %d, must be in range of 1 - 15\n", prp_mode); + } +} + +int wave5_vpu_enc_init_seq(struct vpu_instance *inst) +{ + u32 reg_val = 0, rot_mir_mode, fixed_cu_size_mode = 0x7; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + struct enc_open_param *p_open_param = &p_enc_info->open_param; + struct enc_wave_param *p_param = &p_open_param->wave_param; + + /* + * OPT_COMMON: + * the last SET_PARAM command should be called with OPT_COMMON + */ + rot_mir_mode = 0; + if (p_enc_info->rotation_enable) { + switch (p_enc_info->rotation_angle) { + case 0: + rot_mir_mode |= NONE_ROTATE; + break; + case 90: + rot_mir_mode |= ROT_CLOCKWISE_90; + break; + case 180: + rot_mir_mode |= ROT_CLOCKWISE_180; + break; + case 270: + rot_mir_mode |= ROT_CLOCKWISE_270; + break; + } + } + + if (p_enc_info->mirror_enable) { + switch (p_enc_info->mirror_direction) { + case MIRDIR_NONE: + rot_mir_mode |= NONE_ROTATE; + break; + case MIRDIR_VER: + rot_mir_mode |= MIR_VER_FLIP; + break; + case MIRDIR_HOR: + rot_mir_mode |= MIR_HOR_FLIP; + break; + case MIRDIR_HOR_VER: + rot_mir_mode |= MIR_HOR_VER_FLIP; + break; + } + } + + wave5_set_enc_crop_info(inst->std, p_param, rot_mir_mode, p_open_param->pic_width, + p_open_param->pic_height); + + /* SET_PARAM + COMMON */ + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SET_PARAM_OPTION, OPT_COMMON); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SRC_SIZE, p_open_param->pic_height << 16 + | p_open_param->pic_width); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MAP_ENDIAN, VDI_LITTLE_ENDIAN); + + reg_val = p_param->profile | + (p_param->level << 3) | + (p_param->internal_bit_depth << 14); + if (inst->std == W_HEVC_ENC) + reg_val |= (p_param->tier << 12) | + (p_param->tmvp_enable << 23) | + (p_param->sao_enable << 24) | + (p_param->skip_intra_trans << 25) | + (p_param->strong_intra_smooth_enable << 27) | + (p_param->en_still_picture << 30); + else if (inst->std == W_AVC_ENC) + reg_val |= (p_param->constraint_set1_flag << 29); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SPS_PARAM, reg_val); + + reg_val = (p_param->lossless_enable) | + (p_param->const_intra_pred_flag << 1) | + (p_param->lf_cross_slice_boundary_enable << 2) | + (p_param->wpp_enable << 4) | + (p_param->disable_deblk << 5) | + ((p_param->beta_offset_div2 & 0xF) << 6) | + ((p_param->tc_offset_div2 & 0xF) << 10) | + ((p_param->chroma_cb_qp_offset & 0x1F) << 14) | + ((p_param->chroma_cr_qp_offset & 0x1F) << 19) | + (p_param->transform8x8_enable << 29) | + (p_param->entropy_coding_mode << 30); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_PPS_PARAM, reg_val); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_GOP_PARAM, p_param->gop_preset_idx); + + if (inst->std == W_AVC_ENC) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM, p_param->intra_qp | + ((p_param->intra_period & ENC_AVC_INTRA_IDR_PARAM_MASK) << ENC_AVC_INTRA_PERIOD_SHIFT) | + ((p_param->avc_idr_period & ENC_AVC_INTRA_IDR_PARAM_MASK) << ENC_AVC_IDR_PERIOD_SHIFT) | + (p_param->forced_idr_header_enable << ENC_AVC_FORCED_IDR_HEADER_SHIFT)); + else if (inst->std == W_HEVC_ENC) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM, + p_param->decoding_refresh_type | (p_param->intra_qp << ENC_HEVC_INTRA_QP_SHIFT) | + (p_param->forced_idr_header_enable << ENC_HEVC_FORCED_IDR_HEADER_SHIFT) | + (p_param->intra_period << ENC_HEVC_INTRA_PERIOD_SHIFT)); + + reg_val = (p_param->rdo_skip << 2) | + (p_param->lambda_scaling_enable << 3) | + (fixed_cu_size_mode << 5) | + (p_param->intra_nx_n_enable << 8) | + (p_param->max_num_merge << 18); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RDO_PARAM, reg_val); + + if (inst->std == W_AVC_ENC) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_REFRESH, + p_param->intra_mb_refresh_arg << 16 | p_param->intra_mb_refresh_mode); + else if (inst->std == W_HEVC_ENC) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_REFRESH, + p_param->intra_refresh_arg << 16 | p_param->intra_refresh_mode); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_FRAME_RATE, p_open_param->frame_rate_info); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_TARGET_RATE, p_open_param->bit_rate); + + reg_val = p_open_param->rc_enable | + (p_param->hvs_qp_enable << 2) | + (p_param->hvs_qp_scale << 4) | + ((p_param->initial_rc_qp & 0x3F) << 14) | + (p_open_param->vbv_buffer_size << 20); + if (inst->std == W_AVC_ENC) + reg_val |= (p_param->mb_level_rc_enable << 1); + else if (inst->std == W_HEVC_ENC) + reg_val |= (p_param->cu_level_rc_enable << 1); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_PARAM, reg_val); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_WEIGHT_PARAM, + p_param->rc_weight_buf << 8 | p_param->rc_weight_param); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_MIN_MAX_QP, p_param->min_qp_i | + (p_param->max_qp_i << 6) | (p_param->hvs_max_delta_qp << 12)); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_INTER_MIN_MAX_QP, p_param->min_qp_p | + (p_param->max_qp_p << 6) | (p_param->min_qp_b << 12) | + (p_param->max_qp_b << 18)); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_BIT_RATIO_LAYER_0_3, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_BIT_RATIO_LAYER_4_7, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_ROT_PARAM, rot_mir_mode); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_BG_PARAM, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_LAMBDA_ADDR, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CONF_WIN_TOP_BOT, + p_param->conf_win_bot << 16 | p_param->conf_win_top); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CONF_WIN_LEFT_RIGHT, + p_param->conf_win_right << 16 | p_param->conf_win_left); + + if (inst->std == W_AVC_ENC) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INDEPENDENT_SLICE, + p_param->avc_slice_arg << 16 | p_param->avc_slice_mode); + else if (inst->std == W_HEVC_ENC) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INDEPENDENT_SLICE, + p_param->independ_slice_mode_arg << 16 | + p_param->independ_slice_mode); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_USER_SCALING_LIST_ADDR, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_NUM_UNITS_IN_TICK, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_TIME_SCALE, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_NUM_TICKS_POC_DIFF_ONE, 0); + + if (inst->std == W_HEVC_ENC) { + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_PU04, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_PU08, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_PU16, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_PU32, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_CU08, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_CU16, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_CU32, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_DEPENDENT_SLICE, + p_param->depend_slice_mode_arg << 16 | p_param->depend_slice_mode); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_NR_PARAM, 0); + + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_NR_WEIGHT, + p_param->nr_intra_weight_y | + (p_param->nr_intra_weight_cb << 5) | + (p_param->nr_intra_weight_cr << 10) | + (p_param->nr_inter_weight_y << 15) | + (p_param->nr_inter_weight_cb << 20) | + (p_param->nr_inter_weight_cr << 25)); + } + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_VUI_HRD_PARAM, 0); + + return send_firmware_command(inst, W5_ENC_SET_PARAM, true, NULL, NULL); +} + +int wave5_vpu_enc_get_seq_info(struct vpu_instance *inst, struct enc_initial_info *info) +{ + int ret; + u32 reg_val; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + + /* send QUERY cmd */ + ret = wave5_send_query(inst->dev, inst, GET_RESULT); + if (ret) + return ret; + + dev_dbg(inst->dev->dev, "%s: init seq\n", __func__); + + reg_val = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS); + + p_enc_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_enc_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + if (vpu_read_reg(inst->dev, W5_RET_ENC_ENCODING_SUCCESS) != 1) { + info->seq_init_err_reason = vpu_read_reg(inst->dev, W5_RET_ENC_ERR_INFO); + ret = -EIO; + } else { + info->warn_info = vpu_read_reg(inst->dev, W5_RET_ENC_WARN_INFO); + } + + info->min_frame_buffer_count = vpu_read_reg(inst->dev, W5_RET_ENC_NUM_REQUIRED_FB); + info->min_src_frame_count = vpu_read_reg(inst->dev, W5_RET_ENC_MIN_SRC_BUF_NUM); + info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE); + info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE); + p_enc_info->vlc_buf_size = info->vlc_buf_size; + p_enc_info->param_buf_size = info->param_buf_size; + + return ret; +} + +static u32 calculate_luma_stride(u32 width, u32 bit_depth) +{ + return ALIGN(ALIGN(width, 16) * ((bit_depth > 8) ? 5 : 4), 32); +} + +static u32 calculate_chroma_stride(u32 width, u32 bit_depth) +{ + return ALIGN(ALIGN(width / 2, 16) * ((bit_depth > 8) ? 5 : 4), 32); +} + +int wave5_vpu_enc_register_framebuffer(struct device *dev, struct vpu_instance *inst, + struct frame_buffer *fb_arr, enum tiled_map_type map_type, + unsigned int count) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + int ret = 0; + u32 stride; + u32 start_no, end_no; + size_t remain, idx, j, i, cnt_8_chunk; + u32 reg_val = 0, pic_size = 0, mv_col_size, fbc_y_tbl_size, fbc_c_tbl_size; + u32 sub_sampled_size = 0; + u32 luma_stride, chroma_stride; + u32 buf_height = 0, buf_width = 0; + u32 bit_depth; + bool avc_encoding = (inst->std == W_AVC_ENC); + struct vpu_buf vb_mv = {0}; + struct vpu_buf vb_fbc_y_tbl = {0}; + struct vpu_buf vb_fbc_c_tbl = {0}; + struct vpu_buf vb_sub_sam_buf = {0}; + struct vpu_buf vb_task = {0}; + struct enc_open_param *p_open_param; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + + p_open_param = &p_enc_info->open_param; + mv_col_size = 0; + fbc_y_tbl_size = 0; + fbc_c_tbl_size = 0; + stride = p_enc_info->stride; + bit_depth = p_open_param->wave_param.internal_bit_depth; + + if (avc_encoding) { + buf_width = ALIGN(p_open_param->pic_width, 16); + buf_height = ALIGN(p_open_param->pic_height, 16); + + if ((p_enc_info->rotation_angle || p_enc_info->mirror_direction) && + !(p_enc_info->rotation_angle == 180 && + p_enc_info->mirror_direction == MIRDIR_HOR_VER)) { + buf_width = ALIGN(p_open_param->pic_width, 16); + buf_height = ALIGN(p_open_param->pic_height, 16); + } + + if (p_enc_info->rotation_angle == 90 || p_enc_info->rotation_angle == 270) { + buf_width = ALIGN(p_open_param->pic_height, 16); + buf_height = ALIGN(p_open_param->pic_width, 16); + } + } else { + buf_width = ALIGN(p_open_param->pic_width, 8); + buf_height = ALIGN(p_open_param->pic_height, 8); + + if ((p_enc_info->rotation_angle || p_enc_info->mirror_direction) && + !(p_enc_info->rotation_angle == 180 && + p_enc_info->mirror_direction == MIRDIR_HOR_VER)) { + buf_width = ALIGN(p_open_param->pic_width, 32); + buf_height = ALIGN(p_open_param->pic_height, 32); + } + + if (p_enc_info->rotation_angle == 90 || p_enc_info->rotation_angle == 270) { + buf_width = ALIGN(p_open_param->pic_height, 32); + buf_height = ALIGN(p_open_param->pic_width, 32); + } + } + + pic_size = (buf_width << 16) | buf_height; + + if (avc_encoding) { + mv_col_size = WAVE5_ENC_AVC_BUF_SIZE(buf_width, buf_height); + vb_mv.daddr = 0; + vb_mv.size = ALIGN(mv_col_size * count, BUFFER_MARGIN) + BUFFER_MARGIN; + } else { + mv_col_size = WAVE5_ENC_HEVC_BUF_SIZE(buf_width, buf_height); + mv_col_size = ALIGN(mv_col_size, 16); + vb_mv.daddr = 0; + vb_mv.size = ALIGN(mv_col_size * count, BUFFER_MARGIN) + BUFFER_MARGIN; + } + + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_mv); + if (ret) + return ret; + + p_enc_info->vb_mv = vb_mv; + + fbc_y_tbl_size = ALIGN(WAVE5_FBC_LUMA_TABLE_SIZE(buf_width, buf_height), 16); + fbc_c_tbl_size = ALIGN(WAVE5_FBC_CHROMA_TABLE_SIZE(buf_width, buf_height), 16); + + vb_fbc_y_tbl.daddr = 0; + vb_fbc_y_tbl.size = ALIGN(fbc_y_tbl_size * count, BUFFER_MARGIN) + BUFFER_MARGIN; + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_fbc_y_tbl); + if (ret) + goto free_vb_fbc_y_tbl; + + p_enc_info->vb_fbc_y_tbl = vb_fbc_y_tbl; + + vb_fbc_c_tbl.daddr = 0; + vb_fbc_c_tbl.size = ALIGN(fbc_c_tbl_size * count, BUFFER_MARGIN) + BUFFER_MARGIN; + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_fbc_c_tbl); + if (ret) + goto free_vb_fbc_c_tbl; + + p_enc_info->vb_fbc_c_tbl = vb_fbc_c_tbl; + + if (avc_encoding) + sub_sampled_size = WAVE5_SUBSAMPLED_ONE_SIZE_AVC(buf_width, buf_height); + else + sub_sampled_size = WAVE5_SUBSAMPLED_ONE_SIZE(buf_width, buf_height); + vb_sub_sam_buf.size = ALIGN(sub_sampled_size * count, BUFFER_MARGIN) + BUFFER_MARGIN; + vb_sub_sam_buf.daddr = 0; + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_sub_sam_buf); + if (ret) + goto free_vb_sam_buf; + + p_enc_info->vb_sub_sam_buf = vb_sub_sam_buf; + + vb_task.size = (p_enc_info->vlc_buf_size * VLC_BUF_NUM) + + (p_enc_info->param_buf_size * COMMAND_QUEUE_DEPTH); + vb_task.daddr = 0; + if (p_enc_info->vb_task.size == 0) { + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_task); + if (ret) + goto free_vb_task; + + p_enc_info->vb_task = vb_task; + + vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF, + p_enc_info->vb_task.daddr); + vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE, vb_task.size); + } + + /* set sub-sampled buffer base addr */ + vpu_write_reg(inst->dev, W5_ADDR_SUB_SAMPLED_FB_BASE, vb_sub_sam_buf.daddr); + /* set sub-sampled buffer size for one frame */ + vpu_write_reg(inst->dev, W5_SUB_SAMPLED_ONE_FB_SIZE, sub_sampled_size); + + vpu_write_reg(inst->dev, W5_PIC_SIZE, pic_size); + + /* set stride of luma/chroma for compressed buffer */ + if ((p_enc_info->rotation_angle || p_enc_info->mirror_direction) && + !(p_enc_info->rotation_angle == 180 && + p_enc_info->mirror_direction == MIRDIR_HOR_VER)) { + luma_stride = calculate_luma_stride(buf_width, bit_depth); + chroma_stride = calculate_chroma_stride(buf_width / 2, bit_depth); + } else { + luma_stride = calculate_luma_stride(p_open_param->pic_width, bit_depth); + chroma_stride = calculate_chroma_stride(p_open_param->pic_width / 2, bit_depth); + } + + vpu_write_reg(inst->dev, W5_FBC_STRIDE, luma_stride << 16 | chroma_stride); + vpu_write_reg(inst->dev, W5_COMMON_PIC_INFO, stride); + + remain = count; + cnt_8_chunk = DIV_ROUND_UP(count, 8); + idx = 0; + for (j = 0; j < cnt_8_chunk; j++) { + reg_val = (j == cnt_8_chunk - 1) << 4 | ((j == 0) << 3); + vpu_write_reg(inst->dev, W5_SFB_OPTION, reg_val); + start_no = j * 8; + end_no = start_no + ((remain >= 8) ? 8 : remain) - 1; + + vpu_write_reg(inst->dev, W5_SET_FB_NUM, (start_no << 8) | end_no); + + for (i = 0; i < 8 && i < remain; i++) { + vpu_write_reg(inst->dev, W5_ADDR_LUMA_BASE0 + (i << 4), fb_arr[i + + start_no].buf_y); + vpu_write_reg(inst->dev, W5_ADDR_CB_BASE0 + (i << 4), + fb_arr[i + start_no].buf_cb); + /* luma FBC offset table */ + vpu_write_reg(inst->dev, W5_ADDR_FBC_Y_OFFSET0 + (i << 4), + vb_fbc_y_tbl.daddr + idx * fbc_y_tbl_size); + /* chroma FBC offset table */ + vpu_write_reg(inst->dev, W5_ADDR_FBC_C_OFFSET0 + (i << 4), + vb_fbc_c_tbl.daddr + idx * fbc_c_tbl_size); + + vpu_write_reg(inst->dev, W5_ADDR_MV_COL0 + (i << 2), + vb_mv.daddr + idx * mv_col_size); + idx++; + } + remain -= i; + + ret = send_firmware_command(inst, W5_SET_FB, false, NULL, NULL); + if (ret) + goto free_vb_mem; + } + + ret = wave5_vpu_firmware_command_queue_error_check(vpu_dev, NULL); + if (ret) + goto free_vb_mem; + + return ret; + +free_vb_mem: + wave5_vdi_free_dma_memory(vpu_dev, &vb_task); +free_vb_task: + wave5_vdi_free_dma_memory(vpu_dev, &vb_sub_sam_buf); +free_vb_sam_buf: + wave5_vdi_free_dma_memory(vpu_dev, &vb_fbc_c_tbl); +free_vb_fbc_c_tbl: + wave5_vdi_free_dma_memory(vpu_dev, &vb_fbc_y_tbl); +free_vb_fbc_y_tbl: + wave5_vdi_free_dma_memory(vpu_dev, &vb_mv); + return ret; +} + +int wave5_vpu_enc_apply_change_param(struct vpu_instance *inst, u32 *fail_res) +{ + /* SET_PARAM + COMMON */ + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SET_PARAM_OPTION, OPT_CHANGE_PARAM); + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SET_PARAM_ENABLE, inst->change_param_flags); + + if (inst->change_param_flags & W5_ENC_CHANGE_PARAM_RC_TARGET_RATE) + vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_TARGET_RATE, inst->bit_rate); + + return send_firmware_command(inst, W5_ENC_SET_PARAM, true, NULL, fail_res); +} + +int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res) +{ + u32 src_frame_format; + u32 reg_val = 0; + u32 src_stride_c = 0; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + struct frame_buffer *p_src_frame = option->source_frame; + struct enc_open_param *p_open_param = &p_enc_info->open_param; + bool justified = WTL_RIGHT_JUSTIFIED; + u32 format_no = WTL_PIXEL_8BIT; + int ret; + + vpu_write_reg(inst->dev, W5_CMD_ENC_BS_START_ADDR, option->pic_stream_buffer_addr); + vpu_write_reg(inst->dev, W5_CMD_ENC_BS_SIZE, option->pic_stream_buffer_size); + p_enc_info->stream_buf_start_addr = option->pic_stream_buffer_addr; + p_enc_info->stream_buf_size = option->pic_stream_buffer_size; + p_enc_info->stream_buf_end_addr = + option->pic_stream_buffer_addr + option->pic_stream_buffer_size; + + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_AXI_SEL, DEFAULT_SRC_AXI); + /* secondary AXI */ + reg_val = (p_enc_info->sec_axi_info.use_enc_rdo_enable << 11) | + (p_enc_info->sec_axi_info.use_enc_lf_enable << 15); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_USE_SEC_AXI, reg_val); + + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_REPORT_PARAM, 0); + + /* + * CODEOPT_ENC_VCL is used to implicitly encode header/headers to generate bitstream. + * (use ENC_PUT_VIDEO_HEADER for give_command to encode only a header) + */ + if (option->code_option.implicit_header_encode) + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_CODE_OPTION, + CODEOPT_ENC_HEADER_IMPLICIT | CODEOPT_ENC_VCL | + (option->code_option.encode_aud << 5) | + (option->code_option.encode_eos << 6) | + (option->code_option.encode_eob << 7)); + else + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_CODE_OPTION, + option->code_option.implicit_header_encode | + (option->code_option.encode_vcl << 1) | + (option->code_option.encode_vps << 2) | + (option->code_option.encode_sps << 3) | + (option->code_option.encode_pps << 4) | + (option->code_option.encode_aud << 5) | + (option->code_option.encode_eos << 6) | + (option->code_option.encode_eob << 7)); + + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_PIC_PARAM, (option->force_pictype_enable<<20) | + (option->force_pic_type<<21)); + + option->force_pictype_enable = 0; + option->force_pic_type = 0; + + if (option->src_end_flag) + /* no more source images. */ + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_PIC_IDX, 0xFFFFFFFF); + else + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_PIC_IDX, option->src_idx); + + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_ADDR_Y, p_src_frame->buf_y); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_ADDR_U, p_src_frame->buf_cb); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_ADDR_V, p_src_frame->buf_cr); + + switch (p_open_param->src_format) { + case FORMAT_420: + case FORMAT_422: + case FORMAT_YUYV: + case FORMAT_YVYU: + case FORMAT_UYVY: + case FORMAT_VYUY: + justified = WTL_LEFT_JUSTIFIED; + format_no = WTL_PIXEL_8BIT; + src_stride_c = inst->cbcr_interleave ? p_src_frame->stride : + (p_src_frame->stride / 2); + src_stride_c = (p_open_param->src_format == FORMAT_422) ? src_stride_c * 2 : + src_stride_c; + break; + case FORMAT_420_P10_16BIT_MSB: + case FORMAT_422_P10_16BIT_MSB: + case FORMAT_YUYV_P10_16BIT_MSB: + case FORMAT_YVYU_P10_16BIT_MSB: + case FORMAT_UYVY_P10_16BIT_MSB: + case FORMAT_VYUY_P10_16BIT_MSB: + justified = WTL_RIGHT_JUSTIFIED; + format_no = WTL_PIXEL_16BIT; + src_stride_c = inst->cbcr_interleave ? p_src_frame->stride : + (p_src_frame->stride / 2); + src_stride_c = (p_open_param->src_format == + FORMAT_422_P10_16BIT_MSB) ? src_stride_c * 2 : src_stride_c; + break; + case FORMAT_420_P10_16BIT_LSB: + case FORMAT_422_P10_16BIT_LSB: + case FORMAT_YUYV_P10_16BIT_LSB: + case FORMAT_YVYU_P10_16BIT_LSB: + case FORMAT_UYVY_P10_16BIT_LSB: + case FORMAT_VYUY_P10_16BIT_LSB: + justified = WTL_LEFT_JUSTIFIED; + format_no = WTL_PIXEL_16BIT; + src_stride_c = inst->cbcr_interleave ? p_src_frame->stride : + (p_src_frame->stride / 2); + src_stride_c = (p_open_param->src_format == + FORMAT_422_P10_16BIT_LSB) ? src_stride_c * 2 : src_stride_c; + break; + case FORMAT_420_P10_32BIT_MSB: + case FORMAT_422_P10_32BIT_MSB: + case FORMAT_YUYV_P10_32BIT_MSB: + case FORMAT_YVYU_P10_32BIT_MSB: + case FORMAT_UYVY_P10_32BIT_MSB: + case FORMAT_VYUY_P10_32BIT_MSB: + justified = WTL_RIGHT_JUSTIFIED; + format_no = WTL_PIXEL_32BIT; + src_stride_c = inst->cbcr_interleave ? p_src_frame->stride : + ALIGN(p_src_frame->stride / 2, 16) * BIT(inst->cbcr_interleave); + src_stride_c = (p_open_param->src_format == + FORMAT_422_P10_32BIT_MSB) ? src_stride_c * 2 : src_stride_c; + break; + case FORMAT_420_P10_32BIT_LSB: + case FORMAT_422_P10_32BIT_LSB: + case FORMAT_YUYV_P10_32BIT_LSB: + case FORMAT_YVYU_P10_32BIT_LSB: + case FORMAT_UYVY_P10_32BIT_LSB: + case FORMAT_VYUY_P10_32BIT_LSB: + justified = WTL_LEFT_JUSTIFIED; + format_no = WTL_PIXEL_32BIT; + src_stride_c = inst->cbcr_interleave ? p_src_frame->stride : + ALIGN(p_src_frame->stride / 2, 16) * BIT(inst->cbcr_interleave); + src_stride_c = (p_open_param->src_format == + FORMAT_422_P10_32BIT_LSB) ? src_stride_c * 2 : src_stride_c; + break; + default: + return -EINVAL; + } + + src_frame_format = (inst->cbcr_interleave << 1) | (inst->nv21); + switch (p_open_param->packed_format) { + case PACKED_YUYV: + src_frame_format = 4; + break; + case PACKED_YVYU: + src_frame_format = 5; + break; + case PACKED_UYVY: + src_frame_format = 6; + break; + case PACKED_VYUY: + src_frame_format = 7; + break; + default: + break; + } + + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_STRIDE, + (p_src_frame->stride << 16) | src_stride_c); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_FORMAT, src_frame_format | + (format_no << 3) | (justified << 5) | (PIC_SRC_ENDIANNESS_BIG_ENDIAN << 6)); + + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_CUSTOM_MAP_OPTION_ADDR, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_CUSTOM_MAP_OPTION_PARAM, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_LONGTERM_PIC, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_WP_PIXEL_SIGMA_Y, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_WP_PIXEL_SIGMA_C, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_WP_PIXEL_MEAN_Y, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_WP_PIXEL_MEAN_C, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_PREFIX_SEI_INFO, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_PREFIX_SEI_NAL_ADDR, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SUFFIX_SEI_INFO, 0); + vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SUFFIX_SEI_NAL_ADDR, 0); + + ret = send_firmware_command(inst, W5_DEC_ENC_PIC, true, ®_val, fail_res); + if (ret == -ETIMEDOUT) + return ret; + + p_enc_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_enc_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + if (ret) + return ret; + + return 0; +} + +int wave5_vpu_enc_get_result(struct vpu_instance *inst, struct enc_output_info *result) +{ + int ret; + u32 encoding_success; + u32 reg_val; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + struct vpu_device *vpu_dev = inst->dev; + + ret = wave5_send_query(inst->dev, inst, GET_RESULT); + if (ret) + return ret; + + dev_dbg(inst->dev->dev, "%s: enc pic complete\n", __func__); + + reg_val = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS); + + p_enc_info->instance_queue_count = (reg_val >> 16) & 0xff; + p_enc_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK); + + encoding_success = vpu_read_reg(inst->dev, W5_RET_ENC_ENCODING_SUCCESS); + if (!encoding_success) { + result->error_reason = vpu_read_reg(inst->dev, W5_RET_ENC_ERR_INFO); + return -EIO; + } + + result->warn_info = vpu_read_reg(inst->dev, W5_RET_ENC_WARN_INFO); + + reg_val = vpu_read_reg(inst->dev, W5_RET_ENC_PIC_TYPE); + result->pic_type = reg_val & 0xFFFF; + + result->enc_vcl_nut = vpu_read_reg(inst->dev, W5_RET_ENC_VCL_NUT); + /* + * To get the reconstructed frame use the following index on + * inst->frame_buf + */ + result->recon_frame_index = vpu_read_reg(inst->dev, W5_RET_ENC_PIC_IDX); + result->enc_pic_byte = vpu_read_reg(inst->dev, W5_RET_ENC_PIC_BYTE); + result->enc_src_idx = vpu_read_reg(inst->dev, W5_RET_ENC_USED_SRC_IDX); + p_enc_info->stream_wr_ptr = wave5_read_reg_for_mem_addr(inst, W5_RET_ENC_WR_PTR); + p_enc_info->stream_rd_ptr = wave5_read_reg_for_mem_addr(inst, W5_RET_ENC_RD_PTR); + + result->bitstream_buffer = wave5_read_reg_for_mem_addr(inst, W5_RET_ENC_RD_PTR); + result->rd_ptr = p_enc_info->stream_rd_ptr; + result->wr_ptr = p_enc_info->stream_wr_ptr; + + /*result for header only(no vcl) encoding */ + if (result->recon_frame_index == RECON_IDX_FLAG_HEADER_ONLY) + result->bitstream_size = result->enc_pic_byte; + else if (result->recon_frame_index < 0) + result->bitstream_size = 0; + else + result->bitstream_size = result->enc_pic_byte; + + result->enc_host_cmd_tick = vpu_read_reg(inst->dev, W5_RET_ENC_HOST_CMD_TICK); + result->enc_encode_end_tick = vpu_read_reg(inst->dev, W5_RET_ENC_ENCODING_END_TICK); + + if (!p_enc_info->first_cycle_check) { + result->frame_cycle = (result->enc_encode_end_tick - result->enc_host_cmd_tick) * + p_enc_info->cycle_per_tick; + p_enc_info->first_cycle_check = true; + } else { + result->frame_cycle = + (result->enc_encode_end_tick - vpu_dev->last_performance_cycles) * + p_enc_info->cycle_per_tick; + if (vpu_dev->last_performance_cycles < result->enc_host_cmd_tick) + result->frame_cycle = (result->enc_encode_end_tick - + result->enc_host_cmd_tick) * p_enc_info->cycle_per_tick; + } + vpu_dev->last_performance_cycles = result->enc_encode_end_tick; + + return 0; +} + +int wave5_vpu_enc_finish_seq(struct vpu_instance *inst, u32 *fail_res) +{ + return send_firmware_command(inst, W5_DESTROY_INSTANCE, true, NULL, fail_res); +} + +static bool wave5_vpu_enc_check_common_param_valid(struct vpu_instance *inst, + struct enc_open_param *open_param) +{ + bool low_delay = true; + struct enc_wave_param *param = &open_param->wave_param; + struct vpu_device *vpu_dev = inst->dev; + struct device *dev = vpu_dev->dev; + u32 num_ctu_row = (open_param->pic_height + 64 - 1) / 64; + u32 num_ctu_col = (open_param->pic_width + 64 - 1) / 64; + u32 ctu_sz = num_ctu_col * num_ctu_row; + + if (inst->std == W_HEVC_ENC && low_delay && + param->decoding_refresh_type == DEC_REFRESH_TYPE_CRA) { + dev_warn(dev, + "dec_refresh_type(CRA) shouldn't be used together with low delay GOP\n"); + dev_warn(dev, "Suggested configuration parameter: decoding refresh type (IDR)\n"); + param->decoding_refresh_type = 2; + } + + if (param->wpp_enable && param->independ_slice_mode) { + unsigned int num_ctb_in_width = ALIGN(open_param->pic_width, 64) >> 6; + + if (param->independ_slice_mode_arg % num_ctb_in_width) { + dev_err(dev, "independ_slice_mode_arg %u must be a multiple of %u\n", + param->independ_slice_mode_arg, num_ctb_in_width); + return false; + } + } + + /* multi-slice & wpp */ + if (param->wpp_enable && param->depend_slice_mode) { + dev_err(dev, "wpp_enable && depend_slice_mode cannot be used simultaneously\n"); + return false; + } + + if (!param->independ_slice_mode && param->depend_slice_mode) { + dev_err(dev, "depend_slice_mode requires independ_slice_mode\n"); + return false; + } else if (param->independ_slice_mode && + param->depend_slice_mode == DEPEND_SLICE_MODE_RECOMMENDED && + param->independ_slice_mode_arg < param->depend_slice_mode_arg) { + dev_err(dev, "independ_slice_mode_arg: %u must be smaller than %u\n", + param->independ_slice_mode_arg, param->depend_slice_mode_arg); + return false; + } + + if (param->independ_slice_mode && param->independ_slice_mode_arg > 65535) { + dev_err(dev, "independ_slice_mode_arg: %u must be smaller than 65535\n", + param->independ_slice_mode_arg); + return false; + } + + if (param->depend_slice_mode && param->depend_slice_mode_arg > 65535) { + dev_err(dev, "depend_slice_mode_arg: %u must be smaller than 65535\n", + param->depend_slice_mode_arg); + return false; + } + + if (param->conf_win_top % 2) { + dev_err(dev, "conf_win_top: %u, must be a multiple of 2\n", param->conf_win_top); + return false; + } + + if (param->conf_win_bot % 2) { + dev_err(dev, "conf_win_bot: %u, must be a multiple of 2\n", param->conf_win_bot); + return false; + } + + if (param->conf_win_left % 2) { + dev_err(dev, "conf_win_left: %u, must be a multiple of 2\n", param->conf_win_left); + return false; + } + + if (param->conf_win_right % 2) { + dev_err(dev, "conf_win_right: %u, Must be a multiple of 2\n", + param->conf_win_right); + return false; + } + + if (param->lossless_enable && open_param->rc_enable) { + dev_err(dev, "option rate_control cannot be used with lossless_coding\n"); + return false; + } + + if (param->lossless_enable && !param->skip_intra_trans) { + dev_err(dev, "option intra_trans_skip must be enabled with lossless_coding\n"); + return false; + } + + /* intra refresh */ + if (param->intra_refresh_mode && param->intra_refresh_arg == 0) { + dev_err(dev, "Invalid refresh argument, mode: %u, refresh: %u must be > 0\n", + param->intra_refresh_mode, param->intra_refresh_arg); + return false; + } + switch (param->intra_refresh_mode) { + case REFRESH_MODE_CTU_ROWS: + if (param->intra_mb_refresh_arg > num_ctu_row) + goto invalid_refresh_argument; + break; + case REFRESH_MODE_CTU_COLUMNS: + if (param->intra_refresh_arg > num_ctu_col) + goto invalid_refresh_argument; + break; + case REFRESH_MODE_CTU_STEP_SIZE: + if (param->intra_refresh_arg > ctu_sz) + goto invalid_refresh_argument; + break; + case REFRESH_MODE_CTUS: + if (param->intra_refresh_arg > ctu_sz) + goto invalid_refresh_argument; + if (param->lossless_enable) { + dev_err(dev, "mode: %u cannot be used lossless_enable", + param->intra_refresh_mode); + return false; + } + } + return true; + +invalid_refresh_argument: + dev_err(dev, "Invalid refresh argument, mode: %u, refresh: %u > W(%u)xH(%u)\n", + param->intra_refresh_mode, param->intra_refresh_arg, + num_ctu_row, num_ctu_col); + return false; +} + +static bool wave5_vpu_enc_check_param_valid(struct vpu_device *vpu_dev, + struct enc_open_param *open_param) +{ + struct enc_wave_param *param = &open_param->wave_param; + + if (open_param->rc_enable) { + if (param->min_qp_i > param->max_qp_i || param->min_qp_p > param->max_qp_p || + param->min_qp_b > param->max_qp_b) { + dev_err(vpu_dev->dev, "Configuration failed because min_qp is greater than max_qp\n"); + dev_err(vpu_dev->dev, "Suggested configuration parameters: min_qp = max_qp\n"); + return false; + } + + if (open_param->bit_rate <= (int)open_param->frame_rate_info) { + dev_err(vpu_dev->dev, + "enc_bit_rate: %u must be greater than the frame_rate: %u\n", + open_param->bit_rate, (int)open_param->frame_rate_info); + return false; + } + } + + return true; +} + +int wave5_vpu_enc_check_open_param(struct vpu_instance *inst, struct enc_open_param *open_param) +{ + u32 pic_width; + u32 pic_height; + s32 product_id = inst->dev->product; + struct vpu_attr *p_attr = &inst->dev->attr; + struct enc_wave_param *param; + + if (!open_param) + return -EINVAL; + + param = &open_param->wave_param; + pic_width = open_param->pic_width; + pic_height = open_param->pic_height; + + if (inst->id >= MAX_NUM_INSTANCE) { + dev_err(inst->dev->dev, "Too many simultaneous instances: %d (max: %u)\n", + inst->id, MAX_NUM_INSTANCE); + return -EOPNOTSUPP; + } + + if (inst->std != W_HEVC_ENC && + !(inst->std == W_AVC_ENC && product_id == PRODUCT_ID_521)) { + dev_err(inst->dev->dev, "Unsupported encoder-codec & product combination\n"); + return -EOPNOTSUPP; + } + + if (param->internal_bit_depth == 10) { + if (inst->std == W_HEVC_ENC && !p_attr->support_hevc10bit_enc) { + dev_err(inst->dev->dev, + "Flag support_hevc10bit_enc must be set to encode 10bit HEVC\n"); + return -EOPNOTSUPP; + } else if (inst->std == W_AVC_ENC && !p_attr->support_avc10bit_enc) { + dev_err(inst->dev->dev, + "Flag support_avc10bit_enc must be set to encode 10bit AVC\n"); + return -EOPNOTSUPP; + } + } + + if (!open_param->frame_rate_info) { + dev_err(inst->dev->dev, "No frame rate information.\n"); + return -EINVAL; + } + + if (open_param->bit_rate > MAX_BIT_RATE) { + dev_err(inst->dev->dev, "Invalid encoding bit-rate: %u (valid: 0-%u)\n", + open_param->bit_rate, MAX_BIT_RATE); + return -EINVAL; + } + + if (pic_width < W5_MIN_ENC_PIC_WIDTH || pic_width > W5_MAX_ENC_PIC_WIDTH || + pic_height < W5_MIN_ENC_PIC_HEIGHT || pic_height > W5_MAX_ENC_PIC_HEIGHT) { + dev_err(inst->dev->dev, "Invalid encoding dimension: %ux%u\n", + pic_width, pic_height); + return -EINVAL; + } + + if (param->profile) { + if (inst->std == W_HEVC_ENC) { + if ((param->profile != HEVC_PROFILE_MAIN || + (param->profile == HEVC_PROFILE_MAIN && + param->internal_bit_depth > 8)) && + (param->profile != HEVC_PROFILE_MAIN10 || + (param->profile == HEVC_PROFILE_MAIN10 && + param->internal_bit_depth < 10)) && + param->profile != HEVC_PROFILE_STILLPICTURE) { + dev_err(inst->dev->dev, + "Invalid HEVC encoding profile: %u (bit-depth: %u)\n", + param->profile, param->internal_bit_depth); + return -EINVAL; + } + } else if (inst->std == W_AVC_ENC) { + if ((param->internal_bit_depth > 8 && + param->profile != H264_PROFILE_HIGH10)) { + dev_err(inst->dev->dev, + "Invalid AVC encoding profile: %u (bit-depth: %u)\n", + param->profile, param->internal_bit_depth); + return -EINVAL; + } + } + } + + if (param->decoding_refresh_type > DEC_REFRESH_TYPE_IDR) { + dev_err(inst->dev->dev, "Invalid decoding refresh type: %u (valid: 0-2)\n", + param->decoding_refresh_type); + return -EINVAL; + } + + if (param->intra_refresh_mode > REFRESH_MODE_CTUS) { + dev_err(inst->dev->dev, "Invalid intra refresh mode: %d (valid: 0-4)\n", + param->intra_refresh_mode); + return -EINVAL; + } + + if (inst->std == W_HEVC_ENC && param->independ_slice_mode && + param->depend_slice_mode > DEPEND_SLICE_MODE_BOOST) { + dev_err(inst->dev->dev, + "Can't combine slice modes: independent and fast dependent for HEVC\n"); + return -EINVAL; + } + + if (!param->disable_deblk) { + if (param->beta_offset_div2 < -6 || param->beta_offset_div2 > 6) { + dev_err(inst->dev->dev, "Invalid beta offset: %d (valid: -6-6)\n", + param->beta_offset_div2); + return -EINVAL; + } + + if (param->tc_offset_div2 < -6 || param->tc_offset_div2 > 6) { + dev_err(inst->dev->dev, "Invalid tc offset: %d (valid: -6-6)\n", + param->tc_offset_div2); + return -EINVAL; + } + } + + if (param->intra_qp > MAX_INTRA_QP) { + dev_err(inst->dev->dev, + "Invalid intra quantization parameter: %u (valid: 0-%u)\n", + param->intra_qp, MAX_INTRA_QP); + return -EINVAL; + } + + if (open_param->rc_enable) { + if (param->min_qp_i > MAX_INTRA_QP || param->max_qp_i > MAX_INTRA_QP || + param->min_qp_p > MAX_INTRA_QP || param->max_qp_p > MAX_INTRA_QP || + param->min_qp_b > MAX_INTRA_QP || param->max_qp_b > MAX_INTRA_QP) { + dev_err(inst->dev->dev, + "Invalid quantization parameter min/max values: " + "I: %u-%u, P: %u-%u, B: %u-%u (valid for each: 0-%u)\n", + param->min_qp_i, param->max_qp_i, param->min_qp_p, param->max_qp_p, + param->min_qp_b, param->max_qp_b, MAX_INTRA_QP); + return -EINVAL; + } + + if (param->hvs_qp_enable && param->hvs_max_delta_qp > MAX_HVS_MAX_DELTA_QP) { + dev_err(inst->dev->dev, + "Invalid HVS max delta quantization parameter: %u (valid: 0-%u)\n", + param->hvs_max_delta_qp, MAX_HVS_MAX_DELTA_QP); + return -EINVAL; + } + + if (open_param->vbv_buffer_size < MIN_VBV_BUFFER_SIZE || + open_param->vbv_buffer_size > MAX_VBV_BUFFER_SIZE) { + dev_err(inst->dev->dev, "VBV buffer size: %u (valid: %u-%u)\n", + open_param->vbv_buffer_size, MIN_VBV_BUFFER_SIZE, + MAX_VBV_BUFFER_SIZE); + return -EINVAL; + } + } + + if (!wave5_vpu_enc_check_common_param_valid(inst, open_param)) + return -EINVAL; + + if (!wave5_vpu_enc_check_param_valid(inst->dev, open_param)) + return -EINVAL; + + if (param->chroma_cb_qp_offset < -12 || param->chroma_cb_qp_offset > 12) { + dev_err(inst->dev->dev, + "Invalid chroma Cb quantization parameter offset: %d (valid: -12-12)\n", + param->chroma_cb_qp_offset); + return -EINVAL; + } + + if (param->chroma_cr_qp_offset < -12 || param->chroma_cr_qp_offset > 12) { + dev_err(inst->dev->dev, + "Invalid chroma Cr quantization parameter offset: %d (valid: -12-12)\n", + param->chroma_cr_qp_offset); + return -EINVAL; + } + + if (param->intra_refresh_mode == REFRESH_MODE_CTU_STEP_SIZE && !param->intra_refresh_arg) { + dev_err(inst->dev->dev, + "Intra refresh mode CTU step-size requires an argument\n"); + return -EINVAL; + } + + if (inst->std == W_HEVC_ENC) { + if (param->nr_intra_weight_y > MAX_INTRA_WEIGHT || + param->nr_intra_weight_cb > MAX_INTRA_WEIGHT || + param->nr_intra_weight_cr > MAX_INTRA_WEIGHT) { + dev_err(inst->dev->dev, + "Invalid intra weight Y(%u) Cb(%u) Cr(%u) (valid: %u)\n", + param->nr_intra_weight_y, param->nr_intra_weight_cb, + param->nr_intra_weight_cr, MAX_INTRA_WEIGHT); + return -EINVAL; + } + + if (param->nr_inter_weight_y > MAX_INTER_WEIGHT || + param->nr_inter_weight_cb > MAX_INTER_WEIGHT || + param->nr_inter_weight_cr > MAX_INTER_WEIGHT) { + dev_err(inst->dev->dev, + "Invalid inter weight Y(%u) Cb(%u) Cr(%u) (valid: %u)\n", + param->nr_inter_weight_y, param->nr_inter_weight_cb, + param->nr_inter_weight_cr, MAX_INTER_WEIGHT); + return -EINVAL; + } + } + + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-regdefine.h b/drivers/media/platform/chips-media/wave5/wave5-regdefine.h --- a/drivers/media/platform/chips-media/wave5/wave5-regdefine.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-regdefine.h 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,732 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - wave5 register definitions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef __WAVE5_REGISTER_DEFINE_H__ +#define __WAVE5_REGISTER_DEFINE_H__ + +enum W5_VPU_COMMAND { + W5_INIT_VPU = 0x0001, + W5_WAKEUP_VPU = 0x0002, + W5_SLEEP_VPU = 0x0004, + W5_CREATE_INSTANCE = 0x0008, /* queuing command */ + W5_FLUSH_INSTANCE = 0x0010, + W5_DESTROY_INSTANCE = 0x0020, /* queuing command */ + W5_INIT_SEQ = 0x0040, /* queuing command */ + W5_SET_FB = 0x0080, + W5_DEC_ENC_PIC = 0x0100, /* queuing command */ + W5_ENC_SET_PARAM = 0x0200, /* queuing command */ + W5_QUERY = 0x4000, + W5_UPDATE_BS = 0x8000, + W5_MAX_VPU_COMD = 0x10000, +}; + +enum query_opt { + GET_VPU_INFO = 0, + SET_WRITE_PROT = 1, + GET_RESULT = 2, + UPDATE_DISP_FLAG = 3, + GET_BW_REPORT = 4, + GET_BS_RD_PTR = 5, /* for decoder */ + GET_BS_WR_PTR = 6, /* for encoder */ + GET_SRC_BUF_FLAG = 7, /* for encoder */ + SET_BS_RD_PTR = 8, /* for decoder */ + GET_DEBUG_INFO = 0x61, +}; + +#define W5_REG_BASE 0x00000000 +#define W5_CMD_REG_BASE 0x00000100 +#define W5_CMD_REG_END 0x00000200 + +/* + * COMMON + * + * ---- + * + * Power on configuration + * PO_DEBUG_MODE [0] 1 - power on with debug mode + * USE_PO_CONF [3] 1 - use power-on-configuration + */ +#define W5_PO_CONF (W5_REG_BASE + 0x0000) +#define W5_VCPU_CUR_PC (W5_REG_BASE + 0x0004) +#define W5_VCPU_CUR_LR (W5_REG_BASE + 0x0008) +#define W5_VPU_PDBG_STEP_MASK_V (W5_REG_BASE + 0x000C) +#define W5_VPU_PDBG_CTRL (W5_REG_BASE + 0x0010) /* v_cpu debugger ctrl register */ +#define W5_VPU_PDBG_IDX_REG (W5_REG_BASE + 0x0014) /* v_cpu debugger index register */ +#define W5_VPU_PDBG_WDATA_REG (W5_REG_BASE + 0x0018) /* v_cpu debugger write data reg */ +#define W5_VPU_PDBG_RDATA_REG (W5_REG_BASE + 0x001C) /* v_cpu debugger read data reg */ + +#define W5_VPU_FIO_CTRL_ADDR (W5_REG_BASE + 0x0020) +#define W5_VPU_FIO_DATA (W5_REG_BASE + 0x0024) +#define W5_VPU_VINT_REASON_USR (W5_REG_BASE + 0x0030) +#define W5_VPU_VINT_REASON_CLR (W5_REG_BASE + 0x0034) +#define W5_VPU_HOST_INT_REQ (W5_REG_BASE + 0x0038) +#define W5_VPU_VINT_CLEAR (W5_REG_BASE + 0x003C) +#define W5_VPU_HINT_CLEAR (W5_REG_BASE + 0x0040) +#define W5_VPU_VPU_INT_STS (W5_REG_BASE + 0x0044) +#define W5_VPU_VINT_ENABLE (W5_REG_BASE + 0x0048) +#define W5_VPU_VINT_REASON (W5_REG_BASE + 0x004C) +#define W5_VPU_RESET_REQ (W5_REG_BASE + 0x0050) +#define W5_RST_BLOCK_CCLK(_core) BIT((_core)) +#define W5_RST_BLOCK_CCLK_ALL (0xff) +#define W5_RST_BLOCK_BCLK(_core) (0x100 << (_core)) +#define W5_RST_BLOCK_BCLK_ALL (0xff00) +#define W5_RST_BLOCK_ACLK(_core) (0x10000 << (_core)) +#define W5_RST_BLOCK_ACLK_ALL (0xff0000) +#define W5_RST_BLOCK_VCPU_ALL (0x3f000000) +#define W5_RST_BLOCK_ALL (0x3fffffff) +#define W5_VPU_RESET_STATUS (W5_REG_BASE + 0x0054) + +#define W5_VCPU_RESTART (W5_REG_BASE + 0x0058) +#define W5_VPU_CLK_MASK (W5_REG_BASE + 0x005C) + +/* REMAP_CTRL + * PAGE SIZE: [8:0] 0x001 - 4K + * 0x002 - 8K + * 0x004 - 16K + * ... + * 0x100 - 1M + * REGION ATTR1 [10] 0 - normal + * 1 - make bus error for the region + * REGION ATTR2 [11] 0 - normal + * 1 - bypass region + * REMAP INDEX [15:12] - 0 ~ 3 + * ENDIAN [19:16] - NOTE: Currently not supported in this driver + * AXI-ID [23:20] - upper AXI-ID + * BUS_ERROR [29] 0 - bypass + * 1 - make BUS_ERROR for unmapped region + * BYPASS_ALL [30] 1 - bypass all + * ENABLE [31] 1 - update control register[30:16] + */ +#define W5_VPU_REMAP_CTRL (W5_REG_BASE + 0x0060) +#define W5_VPU_REMAP_VADDR (W5_REG_BASE + 0x0064) +#define W5_VPU_REMAP_PADDR (W5_REG_BASE + 0x0068) +#define W5_VPU_REMAP_CORE_START (W5_REG_BASE + 0x006C) +#define W5_VPU_BUSY_STATUS (W5_REG_BASE + 0x0070) +#define W5_VPU_HALT_STATUS (W5_REG_BASE + 0x0074) +#define W5_VPU_VCPU_STATUS (W5_REG_BASE + 0x0078) +#define W5_VPU_RET_PRODUCT_VERSION (W5_REG_BASE + 0x0094) +/* + * assign vpu_config0 = {conf_map_converter_reg, // [31] + * conf_map_converter_sig, // [30] + * 8'd0, // [29:22] + * conf_std_switch_en, // [21] + * conf_bg_detect, // [20] + * conf_3dnr_en, // [19] + * conf_one_axi_en, // [18] + * conf_sec_axi_en, // [17] + * conf_bus_info, // [16] + * conf_afbc_en, // [15] + * conf_afbc_version_id, // [14:12] + * conf_fbc_en, // [11] + * conf_fbc_version_id, // [10:08] + * conf_scaler_en, // [07] + * conf_scaler_version_id, // [06:04] + * conf_bwb_en, // [03] + * 3'd0}; // [02:00] + */ +#define W5_VPU_RET_VPU_CONFIG0 (W5_REG_BASE + 0x0098) +/* + * assign vpu_config1 = {4'd0, // [31:28] + * conf_perf_timer_en, // [27] + * conf_multi_core_en, // [26] + * conf_gcu_en, // [25] + * conf_cu_report, // [24] + * 4'd0, // [23:20] + * conf_vcore_id_3, // [19] + * conf_vcore_id_2, // [18] + * conf_vcore_id_1, // [17] + * conf_vcore_id_0, // [16] + * conf_bwb_opt, // [15] + * 7'd0, // [14:08] + * conf_cod_std_en_reserved_7, // [7] + * conf_cod_std_en_reserved_6, // [6] + * conf_cod_std_en_reserved_5, // [5] + * conf_cod_std_en_reserved_4, // [4] + * conf_cod_std_en_reserved_3, // [3] + * conf_cod_std_en_reserved_2, // [2] + * conf_cod_std_en_vp9, // [1] + * conf_cod_std_en_hevc}; // [0] + * } + */ +#define W5_VPU_RET_VPU_CONFIG1 (W5_REG_BASE + 0x009C) + +#define W5_VPU_DBG_REG0 (W5_REG_BASE + 0x00f0) +#define W5_VPU_DBG_REG1 (W5_REG_BASE + 0x00f4) +#define W5_VPU_DBG_REG2 (W5_REG_BASE + 0x00f8) +#define W5_VPU_DBG_REG3 (W5_REG_BASE + 0x00fc) + +/************************************************************************/ +/* PRODUCT INFORMATION */ +/************************************************************************/ +#define W5_PRODUCT_NAME (W5_REG_BASE + 0x1040) +#define W5_PRODUCT_NUMBER (W5_REG_BASE + 0x1044) + +/************************************************************************/ +/* DECODER/ENCODER COMMON */ +/************************************************************************/ +#define W5_COMMAND (W5_REG_BASE + 0x0100) +#define W5_COMMAND_OPTION (W5_REG_BASE + 0x0104) +#define W5_QUERY_OPTION (W5_REG_BASE + 0x0104) +#define W5_RET_SUCCESS (W5_REG_BASE + 0x0108) +#define W5_RET_FAIL_REASON (W5_REG_BASE + 0x010C) +#define W5_RET_QUEUE_FAIL_REASON (W5_REG_BASE + 0x0110) +#define W5_CMD_INSTANCE_INFO (W5_REG_BASE + 0x0110) + +#define W5_RET_QUEUE_STATUS (W5_REG_BASE + 0x01E0) +#define W5_RET_BS_EMPTY_INST (W5_REG_BASE + 0x01E4) +#define W5_RET_QUEUE_CMD_DONE_INST (W5_REG_BASE + 0x01E8) +#define W5_RET_STAGE0_INSTANCE_INFO (W5_REG_BASE + 0x01EC) +#define W5_RET_STAGE1_INSTANCE_INFO (W5_REG_BASE + 0x01F0) +#define W5_RET_STAGE2_INSTANCE_INFO (W5_REG_BASE + 0x01F4) + +#define W5_RET_SEQ_DONE_INSTANCE_INFO (W5_REG_BASE + 0x01FC) + +#define W5_BS_OPTION (W5_REG_BASE + 0x0120) + +/* return info when QUERY (GET_RESULT) for en/decoder */ +#define W5_RET_VLC_BUF_SIZE (W5_REG_BASE + 0x01B0) +/* return info when QUERY (GET_RESULT) for en/decoder */ +#define W5_RET_PARAM_BUF_SIZE (W5_REG_BASE + 0x01B4) + +/* set when SET_FB for en/decoder */ +#define W5_CMD_SET_FB_ADDR_TASK_BUF (W5_REG_BASE + 0x01D4) +#define W5_CMD_SET_FB_TASK_BUF_SIZE (W5_REG_BASE + 0x01D8) +/************************************************************************/ +/* INIT_VPU - COMMON */ +/************************************************************************/ +/* note: W5_ADDR_CODE_BASE should be aligned to 4KB */ +#define W5_ADDR_CODE_BASE (W5_REG_BASE + 0x0110) +#define W5_CODE_SIZE (W5_REG_BASE + 0x0114) +#define W5_CODE_PARAM (W5_REG_BASE + 0x0118) +#define W5_ADDR_TEMP_BASE (W5_REG_BASE + 0x011C) +#define W5_TEMP_SIZE (W5_REG_BASE + 0x0120) +#define W5_HW_OPTION (W5_REG_BASE + 0x012C) +#define W5_SEC_AXI_PARAM (W5_REG_BASE + 0x0180) + +/************************************************************************/ +/* CREATE_INSTANCE - COMMON */ +/************************************************************************/ +#define W5_ADDR_WORK_BASE (W5_REG_BASE + 0x0114) +#define W5_WORK_SIZE (W5_REG_BASE + 0x0118) +#define W5_CMD_DEC_BS_START_ADDR (W5_REG_BASE + 0x011C) +#define W5_CMD_DEC_BS_SIZE (W5_REG_BASE + 0x0120) +#define W5_CMD_BS_PARAM (W5_REG_BASE + 0x0124) +#define W5_CMD_ADDR_SEC_AXI (W5_REG_BASE + 0x0130) +#define W5_CMD_SEC_AXI_SIZE (W5_REG_BASE + 0x0134) +#define W5_CMD_EXT_ADDR (W5_REG_BASE + 0x0138) +#define W5_CMD_NUM_CQ_DEPTH_M1 (W5_REG_BASE + 0x013C) +#define W5_CMD_ERR_CONCEAL (W5_REG_BASE + 0x0140) + +/************************************************************************/ +/* DECODER - INIT_SEQ */ +/************************************************************************/ +#define W5_BS_RD_PTR (W5_REG_BASE + 0x0118) +#define W5_BS_WR_PTR (W5_REG_BASE + 0x011C) +/************************************************************************/ +/* SET_FRAME_BUF */ +/************************************************************************/ +/* SET_FB_OPTION 0x00 REGISTER FRAMEBUFFERS + * 0x01 UPDATE FRAMEBUFFER, just one framebuffer(linear, fbc and mvcol) + */ +#define W5_SFB_OPTION (W5_REG_BASE + 0x0104) +#define W5_COMMON_PIC_INFO (W5_REG_BASE + 0x0118) +#define W5_PIC_SIZE (W5_REG_BASE + 0x011C) +#define W5_SET_FB_NUM (W5_REG_BASE + 0x0120) +#define W5_EXTRA_PIC_INFO (W5_REG_BASE + 0x0124) + +#define W5_ADDR_LUMA_BASE0 (W5_REG_BASE + 0x0134) +#define W5_ADDR_CB_BASE0 (W5_REG_BASE + 0x0138) +#define W5_ADDR_CR_BASE0 (W5_REG_BASE + 0x013C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET0 (W5_REG_BASE + 0x013C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET0 (W5_REG_BASE + 0x0140) +#define W5_ADDR_LUMA_BASE1 (W5_REG_BASE + 0x0144) +#define W5_ADDR_CB_ADDR1 (W5_REG_BASE + 0x0148) +#define W5_ADDR_CR_ADDR1 (W5_REG_BASE + 0x014C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET1 (W5_REG_BASE + 0x014C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET1 (W5_REG_BASE + 0x0150) +#define W5_ADDR_LUMA_BASE2 (W5_REG_BASE + 0x0154) +#define W5_ADDR_CB_ADDR2 (W5_REG_BASE + 0x0158) +#define W5_ADDR_CR_ADDR2 (W5_REG_BASE + 0x015C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET2 (W5_REG_BASE + 0x015C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET2 (W5_REG_BASE + 0x0160) +#define W5_ADDR_LUMA_BASE3 (W5_REG_BASE + 0x0164) +#define W5_ADDR_CB_ADDR3 (W5_REG_BASE + 0x0168) +#define W5_ADDR_CR_ADDR3 (W5_REG_BASE + 0x016C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET3 (W5_REG_BASE + 0x016C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET3 (W5_REG_BASE + 0x0170) +#define W5_ADDR_LUMA_BASE4 (W5_REG_BASE + 0x0174) +#define W5_ADDR_CB_ADDR4 (W5_REG_BASE + 0x0178) +#define W5_ADDR_CR_ADDR4 (W5_REG_BASE + 0x017C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET4 (W5_REG_BASE + 0x017C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET4 (W5_REG_BASE + 0x0180) +#define W5_ADDR_LUMA_BASE5 (W5_REG_BASE + 0x0184) +#define W5_ADDR_CB_ADDR5 (W5_REG_BASE + 0x0188) +#define W5_ADDR_CR_ADDR5 (W5_REG_BASE + 0x018C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET5 (W5_REG_BASE + 0x018C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET5 (W5_REG_BASE + 0x0190) +#define W5_ADDR_LUMA_BASE6 (W5_REG_BASE + 0x0194) +#define W5_ADDR_CB_ADDR6 (W5_REG_BASE + 0x0198) +#define W5_ADDR_CR_ADDR6 (W5_REG_BASE + 0x019C) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET6 (W5_REG_BASE + 0x019C) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET6 (W5_REG_BASE + 0x01A0) +#define W5_ADDR_LUMA_BASE7 (W5_REG_BASE + 0x01A4) +#define W5_ADDR_CB_ADDR7 (W5_REG_BASE + 0x01A8) +#define W5_ADDR_CR_ADDR7 (W5_REG_BASE + 0x01AC) +/* compression offset table for luma */ +#define W5_ADDR_FBC_Y_OFFSET7 (W5_REG_BASE + 0x01AC) +/* compression offset table for chroma */ +#define W5_ADDR_FBC_C_OFFSET7 (W5_REG_BASE + 0x01B0) +#define W5_ADDR_MV_COL0 (W5_REG_BASE + 0x01B4) +#define W5_ADDR_MV_COL1 (W5_REG_BASE + 0x01B8) +#define W5_ADDR_MV_COL2 (W5_REG_BASE + 0x01BC) +#define W5_ADDR_MV_COL3 (W5_REG_BASE + 0x01C0) +#define W5_ADDR_MV_COL4 (W5_REG_BASE + 0x01C4) +#define W5_ADDR_MV_COL5 (W5_REG_BASE + 0x01C8) +#define W5_ADDR_MV_COL6 (W5_REG_BASE + 0x01CC) +#define W5_ADDR_MV_COL7 (W5_REG_BASE + 0x01D0) + +/* UPDATE_FB */ +/* CMD_SET_FB_STRIDE [15:0] - FBC framebuffer stride + * [31:15] - linear framebuffer stride + */ +#define W5_CMD_SET_FB_STRIDE (W5_REG_BASE + 0x0118) +#define W5_CMD_SET_FB_INDEX (W5_REG_BASE + 0x0120) +#define W5_ADDR_LUMA_BASE (W5_REG_BASE + 0x0134) +#define W5_ADDR_CB_BASE (W5_REG_BASE + 0x0138) +#define W5_ADDR_CR_BASE (W5_REG_BASE + 0x013C) +#define W5_ADDR_MV_COL (W5_REG_BASE + 0x0140) +#define W5_ADDR_FBC_Y_BASE (W5_REG_BASE + 0x0144) +#define W5_ADDR_FBC_C_BASE (W5_REG_BASE + 0x0148) +#define W5_ADDR_FBC_Y_OFFSET (W5_REG_BASE + 0x014C) +#define W5_ADDR_FBC_C_OFFSET (W5_REG_BASE + 0x0150) + +/************************************************************************/ +/* DECODER - DEC_PIC */ +/************************************************************************/ +#define W5_CMD_DEC_VCORE_INFO (W5_REG_BASE + 0x0194) +/* sequence change enable mask register + * CMD_SEQ_CHANGE_ENABLE_FLAG [5] profile_idc + * [16] pic_width/height_in_luma_sample + * [19] sps_max_dec_pic_buffering, max_num_reorder, max_latency_increase + */ +#define W5_CMD_SEQ_CHANGE_ENABLE_FLAG (W5_REG_BASE + 0x0128) +#define W5_CMD_DEC_USER_MASK (W5_REG_BASE + 0x012C) +#define W5_CMD_DEC_TEMPORAL_ID_PLUS1 (W5_REG_BASE + 0x0130) +#define W5_CMD_DEC_FORCE_FB_LATENCY_PLUS1 (W5_REG_BASE + 0x0134) +#define W5_USE_SEC_AXI (W5_REG_BASE + 0x0150) + +/************************************************************************/ +/* DECODER - QUERY : GET_VPU_INFO */ +/************************************************************************/ +#define W5_RET_FW_VERSION (W5_REG_BASE + 0x0118) +#define W5_RET_PRODUCT_NAME (W5_REG_BASE + 0x011C) +#define W5_RET_PRODUCT_VERSION (W5_REG_BASE + 0x0120) +#define W5_RET_STD_DEF0 (W5_REG_BASE + 0x0124) +#define W5_RET_STD_DEF1 (W5_REG_BASE + 0x0128) +#define W5_RET_CONF_FEATURE (W5_REG_BASE + 0x012C) +#define W5_RET_CONF_DATE (W5_REG_BASE + 0x0130) +#define W5_RET_CONF_REVISION (W5_REG_BASE + 0x0134) +#define W5_RET_CONF_TYPE (W5_REG_BASE + 0x0138) +#define W5_RET_PRODUCT_ID (W5_REG_BASE + 0x013C) +#define W5_RET_CUSTOMER_ID (W5_REG_BASE + 0x0140) + +/************************************************************************/ +/* DECODER - QUERY : GET_RESULT */ +/************************************************************************/ +#define W5_CMD_DEC_ADDR_REPORT_BASE (W5_REG_BASE + 0x0114) +#define W5_CMD_DEC_REPORT_SIZE (W5_REG_BASE + 0x0118) +#define W5_CMD_DEC_REPORT_PARAM (W5_REG_BASE + 0x011C) + +#define W5_RET_DEC_BS_RD_PTR (W5_REG_BASE + 0x011C) +#define W5_RET_DEC_SEQ_PARAM (W5_REG_BASE + 0x0120) +#define W5_RET_DEC_COLOR_SAMPLE_INFO (W5_REG_BASE + 0x0124) +#define W5_RET_DEC_ASPECT_RATIO (W5_REG_BASE + 0x0128) +#define W5_RET_DEC_BIT_RATE (W5_REG_BASE + 0x012C) +#define W5_RET_DEC_FRAME_RATE_NR (W5_REG_BASE + 0x0130) +#define W5_RET_DEC_FRAME_RATE_DR (W5_REG_BASE + 0x0134) +#define W5_RET_DEC_NUM_REQUIRED_FB (W5_REG_BASE + 0x0138) +#define W5_RET_DEC_NUM_REORDER_DELAY (W5_REG_BASE + 0x013C) +#define W5_RET_DEC_SUB_LAYER_INFO (W5_REG_BASE + 0x0140) +#define W5_RET_DEC_NOTIFICATION (W5_REG_BASE + 0x0144) +/* + * USER_DATA_FLAGS for HEVC/H264 only. + * Bits: + * [1] - User data buffer full boolean + * [2] - VUI parameter flag + * [4] - Pic_timing SEI flag + * [5] - 1st user_data_registed_itu_t_t35 prefix SEI flag + * [6] - user_data_unregistered prefix SEI flag + * [7] - 1st user_data_registed_itu_t_t35 suffix SEI flag + * [8] - user_data_unregistered suffix SEI flag + * [10]- mastering_display_color_volume prefix SEI flag + * [11]- chroma_resampling_display_color_volume prefix SEI flag + * [12]- knee_function_info SEI flag + * [13]- tone_mapping_info prefix SEI flag + * [14]- film_grain_characteristics_info prefix SEI flag + * [15]- content_light_level_info prefix SEI flag + * [16]- color_remapping_info prefix SEI flag + * [28]- 2nd user_data_registed_itu_t_t35 prefix SEI flag + * [29]- 3rd user_data_registed_itu_t_t35 prefix SEI flag + * [30]- 2nd user_data_registed_itu_t_t35 suffix SEI flag + * [31]- 3rd user_data_registed_itu_t_t35 suffix SEI flag + */ +#define W5_RET_DEC_USERDATA_IDC (W5_REG_BASE + 0x0148) +#define W5_RET_DEC_PIC_SIZE (W5_REG_BASE + 0x014C) +#define W5_RET_DEC_CROP_TOP_BOTTOM (W5_REG_BASE + 0x0150) +#define W5_RET_DEC_CROP_LEFT_RIGHT (W5_REG_BASE + 0x0154) +/* + * #define W5_RET_DEC_AU_START_POS (W5_REG_BASE + 0x0158) + * => Access unit (AU) Bitstream start position + * #define W5_RET_DEC_AU_END_POS (W5_REG_BASE + 0x015C) + * => Access unit (AU) Bitstream end position + */ + +/* + * Decoded picture type: + * reg_val & 0x7 => picture type + * (reg_val >> 4) & 0x3f => VCL NAL unit type + * (reg_val >> 31) & 0x1 => output_flag + * 16 << ((reg_val >> 10) & 0x3) => ctu_size + */ +#define W5_RET_DEC_PIC_TYPE (W5_REG_BASE + 0x0160) +#define W5_RET_DEC_PIC_POC (W5_REG_BASE + 0x0164) +/* + * #define W5_RET_DEC_RECOVERY_POINT (W5_REG_BASE + 0x0168) + * => HEVC recovery point + * reg_val & 0xff => number of signed recovery picture order counts + * (reg_val >> 16) & 0x1 => exact match flag + * (reg_val >> 17) & 0x1 => broken link flag + * (reg_val >> 18) & 0x1 => exist flag + */ +#define W5_RET_DEC_DEBUG_INDEX (W5_REG_BASE + 0x016C) +#define W5_RET_DEC_DECODED_INDEX (W5_REG_BASE + 0x0170) +#define W5_RET_DEC_DISPLAY_INDEX (W5_REG_BASE + 0x0174) +/* + * #define W5_RET_DEC_REALLOC_INDEX (W5_REG_BASE + 0x0178) + * => display picture index in decoded picture buffer + * reg_val & 0xf => display picture index for FBC buffer (by reordering) + */ +#define W5_RET_DEC_DISP_IDC (W5_REG_BASE + 0x017C) +/* + * #define W5_RET_DEC_ERR_CTB_NUM (W5_REG_BASE + 0x0180) + * => Number of error CTUs + * reg_val >> 16 => erroneous CTUs in bitstream + * reg_val & 0xffff => total CTUs in bitstream + * + * #define W5_RET_DEC_PIC_PARAM (W5_REG_BASE + 0x01A0) + * => Bitstream sequence/picture parameter information (AV1 only) + * reg_val & 0x1 => intrabc tool enable + * (reg_val >> 1) & 0x1 => screen content tools enable + */ +#define W5_RET_DEC_HOST_CMD_TICK (W5_REG_BASE + 0x01B8) +/* + * #define W5_RET_DEC_SEEK_START_TICK (W5_REG_BASE + 0x01BC) + * #define W5_RET_DEC_SEEK_END_TICK (W5_REG_BASE + 0x01C0) + * => Start and end ticks for seeking slices of the picture + * #define W5_RET_DEC_PARSING_START_TICK (W5_REG_BASE + 0x01C4) + * #define W5_RET_DEC_PARSING_END_TICK (W5_REG_BASE + 0x01C8) + * => Start and end ticks for parsing slices of the picture + * #define W5_RET_DEC_DECODING_START_TICK (W5_REG_BASE + 0x01CC) + * => Start tick for decoding slices of the picture + */ +#define W5_RET_DEC_DECODING_ENC_TICK (W5_REG_BASE + 0x01D0) +#define W5_RET_DEC_WARN_INFO (W5_REG_BASE + 0x01D4) +#define W5_RET_DEC_ERR_INFO (W5_REG_BASE + 0x01D8) +#define W5_RET_DEC_DECODING_SUCCESS (W5_REG_BASE + 0x01DC) + +/************************************************************************/ +/* DECODER - FLUSH_INSTANCE */ +/************************************************************************/ +#define W5_CMD_FLUSH_INST_OPT (W5_REG_BASE + 0x104) + +/************************************************************************/ +/* DECODER - QUERY : UPDATE_DISP_FLAG */ +/************************************************************************/ +#define W5_CMD_DEC_SET_DISP_IDC (W5_REG_BASE + 0x0118) +#define W5_CMD_DEC_CLR_DISP_IDC (W5_REG_BASE + 0x011C) + +/************************************************************************/ +/* DECODER - QUERY : SET_BS_RD_PTR */ +/************************************************************************/ +#define W5_RET_QUERY_DEC_SET_BS_RD_PTR (W5_REG_BASE + 0x011C) + +/************************************************************************/ +/* DECODER - QUERY : GET_BS_RD_PTR */ +/************************************************************************/ +#define W5_RET_QUERY_DEC_BS_RD_PTR (W5_REG_BASE + 0x011C) + +/************************************************************************/ +/* QUERY : GET_DEBUG_INFO */ +/************************************************************************/ +#define W5_RET_QUERY_DEBUG_PRI_REASON (W5_REG_BASE + 0x114) + +/************************************************************************/ +/* GDI register for debugging */ +/************************************************************************/ +#define W5_GDI_BASE 0x8800 +#define W5_GDI_BUS_CTRL (W5_GDI_BASE + 0x0F0) +#define W5_GDI_BUS_STATUS (W5_GDI_BASE + 0x0F4) + +#define W5_BACKBONE_BASE_VCPU 0xFE00 +#define W5_BACKBONE_BUS_CTRL_VCPU (W5_BACKBONE_BASE_VCPU + 0x010) +#define W5_BACKBONE_BUS_STATUS_VCPU (W5_BACKBONE_BASE_VCPU + 0x014) +#define W5_BACKBONE_PROG_AXI_ID (W5_BACKBONE_BASE_VCPU + 0x00C) + +#define W5_BACKBONE_PROC_EXT_ADDR (W5_BACKBONE_BASE_VCPU + 0x0C0) +#define W5_BACKBONE_AXI_PARAM (W5_BACKBONE_BASE_VCPU + 0x0E0) + +#define W5_BACKBONE_BASE_VCORE0 0x8E00 +#define W5_BACKBONE_BUS_CTRL_VCORE0 (W5_BACKBONE_BASE_VCORE0 + 0x010) +#define W5_BACKBONE_BUS_STATUS_VCORE0 (W5_BACKBONE_BASE_VCORE0 + 0x014) + +#define W5_BACKBONE_BASE_VCORE1 0x9E00 /* for dual-core product */ +#define W5_BACKBONE_BUS_CTRL_VCORE1 (W5_BACKBONE_BASE_VCORE1 + 0x010) +#define W5_BACKBONE_BUS_STATUS_VCORE1 (W5_BACKBONE_BASE_VCORE1 + 0x014) + +#define W5_COMBINED_BACKBONE_BASE 0xFE00 +#define W5_COMBINED_BACKBONE_BUS_CTRL (W5_COMBINED_BACKBONE_BASE + 0x010) +#define W5_COMBINED_BACKBONE_BUS_STATUS (W5_COMBINED_BACKBONE_BASE + 0x014) + +/************************************************************************/ +/* */ +/* for ENCODER */ +/* */ +/************************************************************************/ +#define W5_RET_STAGE3_INSTANCE_INFO (W5_REG_BASE + 0x1F8) +/************************************************************************/ +/* ENCODER - CREATE_INSTANCE */ +/************************************************************************/ +/* 0x114 ~ 0x124 : defined above (CREATE_INSTANCE COMMON) */ +#define W5_CMD_ENC_VCORE_INFO (W5_REG_BASE + 0x0194) +#define W5_CMD_ENC_SRC_OPTIONS (W5_REG_BASE + 0x0128) + +/************************************************************************/ +/* ENCODER - SET_FB */ +/************************************************************************/ +#define W5_FBC_STRIDE (W5_REG_BASE + 0x128) +#define W5_ADDR_SUB_SAMPLED_FB_BASE (W5_REG_BASE + 0x12C) +#define W5_SUB_SAMPLED_ONE_FB_SIZE (W5_REG_BASE + 0x130) + +/************************************************************************/ +/* ENCODER - ENC_SET_PARAM (COMMON & CHANGE_PARAM) */ +/************************************************************************/ +#define W5_CMD_ENC_SEQ_SET_PARAM_OPTION (W5_REG_BASE + 0x104) +#define W5_CMD_ENC_SEQ_SET_PARAM_ENABLE (W5_REG_BASE + 0x118) +#define W5_CMD_ENC_SEQ_SRC_SIZE (W5_REG_BASE + 0x11C) +#define W5_CMD_ENC_SEQ_CUSTOM_MAP_ENDIAN (W5_REG_BASE + 0x120) +#define W5_CMD_ENC_SEQ_SPS_PARAM (W5_REG_BASE + 0x124) +#define W5_CMD_ENC_SEQ_PPS_PARAM (W5_REG_BASE + 0x128) +#define W5_CMD_ENC_SEQ_GOP_PARAM (W5_REG_BASE + 0x12C) +#define W5_CMD_ENC_SEQ_INTRA_PARAM (W5_REG_BASE + 0x130) +#define W5_CMD_ENC_SEQ_CONF_WIN_TOP_BOT (W5_REG_BASE + 0x134) +#define W5_CMD_ENC_SEQ_CONF_WIN_LEFT_RIGHT (W5_REG_BASE + 0x138) +#define W5_CMD_ENC_SEQ_RDO_PARAM (W5_REG_BASE + 0x13C) +#define W5_CMD_ENC_SEQ_INDEPENDENT_SLICE (W5_REG_BASE + 0x140) +#define W5_CMD_ENC_SEQ_DEPENDENT_SLICE (W5_REG_BASE + 0x144) +#define W5_CMD_ENC_SEQ_INTRA_REFRESH (W5_REG_BASE + 0x148) +#define W5_CMD_ENC_SEQ_INPUT_SRC_PARAM (W5_REG_BASE + 0x14C) + +#define W5_CMD_ENC_SEQ_RC_FRAME_RATE (W5_REG_BASE + 0x150) +#define W5_CMD_ENC_SEQ_RC_TARGET_RATE (W5_REG_BASE + 0x154) +#define W5_CMD_ENC_SEQ_RC_PARAM (W5_REG_BASE + 0x158) +#define W5_CMD_ENC_SEQ_RC_MIN_MAX_QP (W5_REG_BASE + 0x15C) +#define W5_CMD_ENC_SEQ_RC_BIT_RATIO_LAYER_0_3 (W5_REG_BASE + 0x160) +#define W5_CMD_ENC_SEQ_RC_BIT_RATIO_LAYER_4_7 (W5_REG_BASE + 0x164) +#define W5_CMD_ENC_SEQ_RC_INTER_MIN_MAX_QP (W5_REG_BASE + 0x168) +#define W5_CMD_ENC_SEQ_RC_WEIGHT_PARAM (W5_REG_BASE + 0x16C) + +#define W5_CMD_ENC_SEQ_ROT_PARAM (W5_REG_BASE + 0x170) +#define W5_CMD_ENC_SEQ_NUM_UNITS_IN_TICK (W5_REG_BASE + 0x174) +#define W5_CMD_ENC_SEQ_TIME_SCALE (W5_REG_BASE + 0x178) +#define W5_CMD_ENC_SEQ_NUM_TICKS_POC_DIFF_ONE (W5_REG_BASE + 0x17C) + +#define W5_CMD_ENC_SEQ_CUSTOM_MD_PU04 (W5_REG_BASE + 0x184) +#define W5_CMD_ENC_SEQ_CUSTOM_MD_PU08 (W5_REG_BASE + 0x188) +#define W5_CMD_ENC_SEQ_CUSTOM_MD_PU16 (W5_REG_BASE + 0x18C) +#define W5_CMD_ENC_SEQ_CUSTOM_MD_PU32 (W5_REG_BASE + 0x190) +#define W5_CMD_ENC_SEQ_CUSTOM_MD_CU08 (W5_REG_BASE + 0x194) +#define W5_CMD_ENC_SEQ_CUSTOM_MD_CU16 (W5_REG_BASE + 0x198) +#define W5_CMD_ENC_SEQ_CUSTOM_MD_CU32 (W5_REG_BASE + 0x19C) +#define W5_CMD_ENC_SEQ_NR_PARAM (W5_REG_BASE + 0x1A0) +#define W5_CMD_ENC_SEQ_NR_WEIGHT (W5_REG_BASE + 0x1A4) +#define W5_CMD_ENC_SEQ_BG_PARAM (W5_REG_BASE + 0x1A8) +#define W5_CMD_ENC_SEQ_CUSTOM_LAMBDA_ADDR (W5_REG_BASE + 0x1AC) +#define W5_CMD_ENC_SEQ_USER_SCALING_LIST_ADDR (W5_REG_BASE + 0x1B0) +#define W5_CMD_ENC_SEQ_VUI_HRD_PARAM (W5_REG_BASE + 0x180) +#define W5_CMD_ENC_SEQ_VUI_RBSP_ADDR (W5_REG_BASE + 0x1B8) +#define W5_CMD_ENC_SEQ_HRD_RBSP_ADDR (W5_REG_BASE + 0x1BC) + +/************************************************************************/ +/* ENCODER - ENC_SET_PARAM (CUSTOM_GOP) */ +/************************************************************************/ +#define W5_CMD_ENC_CUSTOM_GOP_PARAM (W5_REG_BASE + 0x11C) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_0 (W5_REG_BASE + 0x120) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_1 (W5_REG_BASE + 0x124) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_2 (W5_REG_BASE + 0x128) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_3 (W5_REG_BASE + 0x12C) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_4 (W5_REG_BASE + 0x130) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_5 (W5_REG_BASE + 0x134) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_6 (W5_REG_BASE + 0x138) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_7 (W5_REG_BASE + 0x13C) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_8 (W5_REG_BASE + 0x140) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_9 (W5_REG_BASE + 0x144) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_10 (W5_REG_BASE + 0x148) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_11 (W5_REG_BASE + 0x14C) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_12 (W5_REG_BASE + 0x150) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_13 (W5_REG_BASE + 0x154) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_14 (W5_REG_BASE + 0x158) +#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_15 (W5_REG_BASE + 0x15C) + +/************************************************************************/ +/* ENCODER - ENC_PIC */ +/************************************************************************/ +#define W5_CMD_ENC_BS_START_ADDR (W5_REG_BASE + 0x118) +#define W5_CMD_ENC_BS_SIZE (W5_REG_BASE + 0x11C) +#define W5_CMD_ENC_PIC_USE_SEC_AXI (W5_REG_BASE + 0x124) +#define W5_CMD_ENC_PIC_REPORT_PARAM (W5_REG_BASE + 0x128) + +#define W5_CMD_ENC_PIC_CUSTOM_MAP_OPTION_PARAM (W5_REG_BASE + 0x138) +#define W5_CMD_ENC_PIC_CUSTOM_MAP_OPTION_ADDR (W5_REG_BASE + 0x13C) +#define W5_CMD_ENC_PIC_SRC_PIC_IDX (W5_REG_BASE + 0x144) +#define W5_CMD_ENC_PIC_SRC_ADDR_Y (W5_REG_BASE + 0x148) +#define W5_CMD_ENC_PIC_SRC_ADDR_U (W5_REG_BASE + 0x14C) +#define W5_CMD_ENC_PIC_SRC_ADDR_V (W5_REG_BASE + 0x150) +#define W5_CMD_ENC_PIC_SRC_STRIDE (W5_REG_BASE + 0x154) +#define W5_CMD_ENC_PIC_SRC_FORMAT (W5_REG_BASE + 0x158) +#define W5_CMD_ENC_PIC_SRC_AXI_SEL (W5_REG_BASE + 0x160) +#define W5_CMD_ENC_PIC_CODE_OPTION (W5_REG_BASE + 0x164) +#define W5_CMD_ENC_PIC_PIC_PARAM (W5_REG_BASE + 0x168) +#define W5_CMD_ENC_PIC_LONGTERM_PIC (W5_REG_BASE + 0x16C) +#define W5_CMD_ENC_PIC_WP_PIXEL_SIGMA_Y (W5_REG_BASE + 0x170) +#define W5_CMD_ENC_PIC_WP_PIXEL_SIGMA_C (W5_REG_BASE + 0x174) +#define W5_CMD_ENC_PIC_WP_PIXEL_MEAN_Y (W5_REG_BASE + 0x178) +#define W5_CMD_ENC_PIC_WP_PIXEL_MEAN_C (W5_REG_BASE + 0x17C) +#define W5_CMD_ENC_PIC_CF50_Y_OFFSET_TABLE_ADDR (W5_REG_BASE + 0x190) +#define W5_CMD_ENC_PIC_CF50_CB_OFFSET_TABLE_ADDR (W5_REG_BASE + 0x194) +#define W5_CMD_ENC_PIC_CF50_CR_OFFSET_TABLE_ADDR (W5_REG_BASE + 0x198) +#define W5_CMD_ENC_PIC_PREFIX_SEI_NAL_ADDR (W5_REG_BASE + 0x180) +#define W5_CMD_ENC_PIC_PREFIX_SEI_INFO (W5_REG_BASE + 0x184) +#define W5_CMD_ENC_PIC_SUFFIX_SEI_NAL_ADDR (W5_REG_BASE + 0x188) +#define W5_CMD_ENC_PIC_SUFFIX_SEI_INFO (W5_REG_BASE + 0x18c) + +/************************************************************************/ +/* ENCODER - QUERY (GET_RESULT) */ +/************************************************************************/ +#define W5_RET_ENC_NUM_REQUIRED_FB (W5_REG_BASE + 0x11C) +#define W5_RET_ENC_MIN_SRC_BUF_NUM (W5_REG_BASE + 0x120) +#define W5_RET_ENC_PIC_TYPE (W5_REG_BASE + 0x124) +/* + * #define W5_RET_ENC_PIC_POC (W5_REG_BASE + 0x128) + * => picture order count value of current encoded picture + */ +#define W5_RET_ENC_PIC_IDX (W5_REG_BASE + 0x12C) +/* + * #define W5_RET_ENC_PIC_SLICE_NUM (W5_REG_BASE + 0x130) + * reg_val & 0xffff = total independent slice segment number (16 bits) + * (reg_val >> 16) & 0xffff = total dependent slice segment number (16 bits) + * + * #define W5_RET_ENC_PIC_SKIP (W5_REG_BASE + 0x134) + * reg_val & 0xfe = picture skip flag (7 bits) + * + * #define W5_RET_ENC_PIC_NUM_INTRA (W5_REG_BASE + 0x138) + * => number of intra blocks in 8x8 (32 bits) + * + * #define W5_RET_ENC_PIC_NUM_MERGE (W5_REG_BASE + 0x13C) + * => number of merge blocks in 8x8 (32 bits) + * + * #define W5_RET_ENC_PIC_NUM_SKIP (W5_REG_BASE + 0x144) + * => number of skip blocks in 8x8 (32 bits) + * + * #define W5_RET_ENC_PIC_AVG_CTU_QP (W5_REG_BASE + 0x148) + * => Average CTU QP value (32 bits) + */ +#define W5_RET_ENC_PIC_BYTE (W5_REG_BASE + 0x14C) +/* + * #define W5_RET_ENC_GOP_PIC_IDX (W5_REG_BASE + 0x150) + * => picture index in group of pictures + */ +#define W5_RET_ENC_USED_SRC_IDX (W5_REG_BASE + 0x154) +/* + * #define W5_RET_ENC_PIC_NUM (W5_REG_BASE + 0x158) + * => encoded picture number + */ +#define W5_RET_ENC_VCL_NUT (W5_REG_BASE + 0x15C) +/* + * Only for H264: + * #define W5_RET_ENC_PIC_DIST_LOW (W5_REG_BASE + 0x164) + * => lower 32 bits of the sum of squared difference between source Y picture + * and reconstructed Y picture + * #define W5_RET_ENC_PIC_DIST_HIGH (W5_REG_BASE + 0x168) + * => upper 32 bits of the sum of squared difference between source Y picture + * and reconstructed Y picture + */ +#define W5_RET_ENC_PIC_MAX_LATENCY_PICS (W5_REG_BASE + 0x16C) + +#define W5_RET_ENC_HOST_CMD_TICK (W5_REG_BASE + 0x1B8) +/* + * #define W5_RET_ENC_PREPARE_START_TICK (W5_REG_BASE + 0x1BC) + * #define W5_RET_ENC_PREPARE_END_TICK (W5_REG_BASE + 0x1C0) + * => Start and end ticks for preparing slices of the picture + * #define W5_RET_ENC_PROCESSING_START_TICK (W5_REG_BASE + 0x1C4) + * #define W5_RET_ENC_PROCESSING_END_TICK (W5_REG_BASE + 0x1C8) + * => Start and end ticks for processing slices of the picture + * #define W5_RET_ENC_ENCODING_START_TICK (W5_REG_BASE + 0x1CC) + * => Start tick for encoding slices of the picture + */ +#define W5_RET_ENC_ENCODING_END_TICK (W5_REG_BASE + 0x1D0) + +#define W5_RET_ENC_WARN_INFO (W5_REG_BASE + 0x1D4) +#define W5_RET_ENC_ERR_INFO (W5_REG_BASE + 0x1D8) +#define W5_RET_ENC_ENCODING_SUCCESS (W5_REG_BASE + 0x1DC) + +/************************************************************************/ +/* ENCODER - QUERY (GET_BS_WR_PTR) */ +/************************************************************************/ +#define W5_RET_ENC_RD_PTR (W5_REG_BASE + 0x114) +#define W5_RET_ENC_WR_PTR (W5_REG_BASE + 0x118) +#define W5_CMD_ENC_REASON_SEL (W5_REG_BASE + 0x11C) + +/************************************************************************/ +/* ENCODER - QUERY (GET_BW_REPORT) */ +/************************************************************************/ +#define RET_QUERY_BW_PRP_AXI_READ (W5_REG_BASE + 0x118) +#define RET_QUERY_BW_PRP_AXI_WRITE (W5_REG_BASE + 0x11C) +#define RET_QUERY_BW_FBD_Y_AXI_READ (W5_REG_BASE + 0x120) +#define RET_QUERY_BW_FBC_Y_AXI_WRITE (W5_REG_BASE + 0x124) +#define RET_QUERY_BW_FBD_C_AXI_READ (W5_REG_BASE + 0x128) +#define RET_QUERY_BW_FBC_C_AXI_WRITE (W5_REG_BASE + 0x12C) +#define RET_QUERY_BW_PRI_AXI_READ (W5_REG_BASE + 0x130) +#define RET_QUERY_BW_PRI_AXI_WRITE (W5_REG_BASE + 0x134) +#define RET_QUERY_BW_SEC_AXI_READ (W5_REG_BASE + 0x138) +#define RET_QUERY_BW_SEC_AXI_WRITE (W5_REG_BASE + 0x13C) +#define RET_QUERY_BW_PROC_AXI_READ (W5_REG_BASE + 0x140) +#define RET_QUERY_BW_PROC_AXI_WRITE (W5_REG_BASE + 0x144) +#define RET_QUERY_BW_BWB_AXI_WRITE (W5_REG_BASE + 0x148) +#define W5_CMD_BW_OPTION (W5_REG_BASE + 0x14C) + +/************************************************************************/ +/* ENCODER - QUERY (GET_SRC_FLAG) */ +/************************************************************************/ +#define W5_RET_RELEASED_SRC_INSTANCE (W5_REG_BASE + 0x1EC) + +#define W5_ENC_PIC_SUB_FRAME_SYNC_IF (W5_REG_BASE + 0x0300) + +#endif /* __WAVE5_REGISTER_DEFINE_H__ */ diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-vdi.c b/drivers/media/platform/chips-media/wave5/wave5-vdi.c --- a/drivers/media/platform/chips-media/wave5/wave5-vdi.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-vdi.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - low level access functions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#include +#include "wave5-vdi.h" +#include "wave5-vpu.h" +#include "wave5-regdefine.h" +#include + +static int wave5_vdi_allocate_common_memory(struct device *dev) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + if (!vpu_dev->common_mem.vaddr) { + int ret; + + vpu_dev->common_mem.size = SIZE_COMMON; + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vpu_dev->common_mem); + if (ret) { + dev_err(dev, "unable to allocate common buffer\n"); + return ret; + } + } + + dev_dbg(dev, "[VDI] common_mem: daddr=%pad size=%zu vaddr=0x%p\n", + &vpu_dev->common_mem.daddr, vpu_dev->common_mem.size, vpu_dev->common_mem.vaddr); + + return 0; +} + +int wave5_vdi_init(struct device *dev) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + int ret; + + ret = wave5_vdi_allocate_common_memory(dev); + if (ret < 0) { + dev_err(dev, "[VDI] failed to get vpu common buffer from driver\n"); + return ret; + } + + if (!PRODUCT_CODE_W_SERIES(vpu_dev->product_code)) { + WARN_ONCE(1, "unsupported product code: 0x%x\n", vpu_dev->product_code); + return -EOPNOTSUPP; + } + + /* if BIT processor is not running. */ + if (wave5_vdi_read_register(vpu_dev, W5_VCPU_CUR_PC) == 0) { + int i; + + for (i = 0; i < 64; i++) + wave5_vdi_write_register(vpu_dev, (i * 4) + 0x100, 0x0); + } + + dev_dbg(dev, "[VDI] driver initialized successfully\n"); + + return 0; +} + +int wave5_vdi_release(struct device *dev) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + vpu_dev->vdb_register = NULL; + wave5_vdi_free_dma_memory(vpu_dev, &vpu_dev->common_mem); + + return 0; +} + +void wave5_vdi_write_register(struct vpu_device *vpu_dev, u32 addr, u32 data) +{ + writel(data, vpu_dev->vdb_register + addr); +} + +unsigned int wave5_vdi_read_register(struct vpu_device *vpu_dev, u32 addr) +{ + return readl(vpu_dev->vdb_register + addr); +} + +int wave5_vdi_clear_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb) +{ + if (!vb || !vb->vaddr) { + dev_err(vpu_dev->dev, "%s: unable to clear unmapped buffer\n", __func__); + return -EINVAL; + } + + memset(vb->vaddr, 0, vb->size); + return vb->size; +} + +int wave5_vdi_write_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb, size_t offset, + u8 *data, size_t len) +{ + if (!vb || !vb->vaddr) { + dev_err(vpu_dev->dev, "%s: unable to write to unmapped buffer\n", __func__); + return -EINVAL; + } + + if (offset > vb->size || len > vb->size || offset + len > vb->size) { + dev_err(vpu_dev->dev, "%s: buffer too small\n", __func__); + return -ENOSPC; + } + + memcpy(vb->vaddr + offset, data, len); + + return len; +} + +int wave5_vdi_allocate_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb) +{ + void *vaddr; + dma_addr_t daddr; + + if (!vb->size) { + dev_err(vpu_dev->dev, "%s: requested size==0\n", __func__); + return -EINVAL; + } + + vaddr = dma_alloc_coherent(vpu_dev->dev, vb->size, &daddr, GFP_KERNEL); + if (!vaddr) + return -ENOMEM; + vb->vaddr = vaddr; + vb->daddr = daddr; + + return 0; +} + +int wave5_vdi_free_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb) +{ + if (vb->size == 0) + return -EINVAL; + + if (!vb->vaddr) + dev_err(vpu_dev->dev, "%s: requested free of unmapped buffer\n", __func__); + else + dma_free_coherent(vpu_dev->dev, vb->size, vb->vaddr, vb->daddr); + + memset(vb, 0, sizeof(*vb)); + + return 0; +} + +int wave5_vdi_allocate_array(struct vpu_device *vpu_dev, struct vpu_buf *array, unsigned int count, + size_t size) +{ + struct vpu_buf vb_buf; + int i, ret = 0; + + vb_buf.size = size; + + for (i = 0; i < count; i++) { + if (array[i].size == size) + continue; + + if (array[i].size != 0) + wave5_vdi_free_dma_memory(vpu_dev, &array[i]); + + ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_buf); + if (ret) + return -ENOMEM; + array[i] = vb_buf; + } + + for (i = count; i < MAX_REG_FRAME; i++) + wave5_vdi_free_dma_memory(vpu_dev, &array[i]); + + return 0; +} + +void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev) +{ + struct vpu_buf *vb = &vpu_dev->sram_buf; + + if (!vpu_dev->sram_pool || !vpu_dev->sram_size) + return; + + if (!vb->vaddr) { + vb->size = vpu_dev->sram_size; + vb->vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, vb->size, + &vb->daddr); + if (!vb->vaddr) + vb->size = 0; + } + + dev_dbg(vpu_dev->dev, "%s: sram daddr: %pad, size: %zu, vaddr: 0x%p\n", + __func__, &vb->daddr, vb->size, vb->vaddr); +} + +void wave5_vdi_free_sram(struct vpu_device *vpu_dev) +{ + struct vpu_buf *vb = &vpu_dev->sram_buf; + + if (!vb->size || !vb->vaddr) + return; + + if (vb->vaddr) + gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr, + vb->size); + + memset(vb, 0, sizeof(*vb)); +} diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-vdi.h b/drivers/media/platform/chips-media/wave5/wave5-vdi.h --- a/drivers/media/platform/chips-media/wave5/wave5-vdi.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-vdi.h 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - low level access functions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef _VDI_H_ +#define _VDI_H_ + +#include "wave5-vpuconfig.h" +#include +#include +#include + +/************************************************************************/ +/* COMMON REGISTERS */ +/************************************************************************/ +#define VPU_PRODUCT_CODE_REGISTER 0x1044 + +/* system register write */ +#define vpu_write_reg(VPU_INST, ADDR, DATA) wave5_vdi_write_register(VPU_INST, ADDR, DATA) +/* system register read */ +#define vpu_read_reg(CORE, ADDR) wave5_vdi_read_register(CORE, ADDR) + +struct vpu_buf { + size_t size; + dma_addr_t daddr; + void *vaddr; +}; + +int wave5_vdi_init(struct device *dev); +int wave5_vdi_release(struct device *dev); //this function may be called only at system off. + +#endif //#ifndef _VDI_H_ diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c --- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,983 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - helper functions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#include +#include +#include +#include "wave5-vpuapi.h" +#include "wave5-regdefine.h" +#include "wave5.h" + +#define DECODE_ALL_TEMPORAL_LAYERS 0 +#define DECODE_ALL_SPATIAL_LAYERS 0 + +static int wave5_initialize_vpu(struct device *dev, u8 *code, size_t size) +{ + int ret; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + if (wave5_vpu_is_init(vpu_dev)) { + wave5_vpu_re_init(dev, (void *)code, size); + ret = -EBUSY; + goto err_out; + } + + ret = wave5_vpu_reset(dev, SW_RESET_ON_BOOT); + if (ret) + goto err_out; + + ret = wave5_vpu_init(dev, (void *)code, size); + +err_out: + mutex_unlock(&vpu_dev->hw_lock); + return ret; +} + +int wave5_vpu_init_with_bitcode(struct device *dev, u8 *bitcode, size_t size) +{ + if (!bitcode || size == 0) + return -EINVAL; + + return wave5_initialize_vpu(dev, bitcode, size); +} + +int wave5_vpu_flush_instance(struct vpu_instance *inst) +{ + int ret = 0; + int retry = 0; + + ret = mutex_lock_interruptible(&inst->dev->hw_lock); + if (ret) + return ret; + do { + /* + * Repeat the FLUSH command until the firmware reports that the + * VPU isn't running anymore + */ + ret = wave5_vpu_hw_flush_instance(inst); + if (ret < 0 && ret != -EBUSY) { + dev_warn(inst->dev->dev, "Flush of %s instance with id: %d fail: %d\n", + inst->type == VPU_INST_TYPE_DEC ? "DECODER" : "ENCODER", inst->id, + ret); + mutex_unlock(&inst->dev->hw_lock); + return ret; + } + if (ret == -EBUSY && retry++ >= MAX_FIRMWARE_CALL_RETRY) { + dev_warn(inst->dev->dev, "Flush of %s instance with id: %d timed out!\n", + inst->type == VPU_INST_TYPE_DEC ? "DECODER" : "ENCODER", inst->id); + mutex_unlock(&inst->dev->hw_lock); + return -ETIMEDOUT; + } + } while (ret != 0); + mutex_unlock(&inst->dev->hw_lock); + + return ret; +} + +int wave5_vpu_get_version_info(struct device *dev, u32 *revision, unsigned int *product_id) +{ + int ret; + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + if (!wave5_vpu_is_init(vpu_dev)) { + ret = -EINVAL; + goto err_out; + } + + if (product_id) + *product_id = vpu_dev->product; + ret = wave5_vpu_get_version(vpu_dev, revision); + +err_out: + mutex_unlock(&vpu_dev->hw_lock); + return ret; +} + +static int wave5_check_dec_open_param(struct vpu_instance *inst, struct dec_open_param *param) +{ + if (inst->id >= MAX_NUM_INSTANCE) { + dev_err(inst->dev->dev, "Too many simultaneous instances: %d (max: %u)\n", + inst->id, MAX_NUM_INSTANCE); + return -EOPNOTSUPP; + } + + if (param->bitstream_buffer % 8) { + dev_err(inst->dev->dev, + "Bitstream buffer must be aligned to a multiple of 8\n"); + return -EINVAL; + } + + if (param->bitstream_buffer_size % 1024 || + param->bitstream_buffer_size < MIN_BITSTREAM_BUFFER_SIZE) { + dev_err(inst->dev->dev, + "Bitstream buffer size must be aligned to a multiple of 1024 and have a minimum size of %d\n", + MIN_BITSTREAM_BUFFER_SIZE); + return -EINVAL; + } + + return 0; +} + +int wave5_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param *open_param) +{ + struct dec_info *p_dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + dma_addr_t buffer_addr; + size_t buffer_size; + + ret = wave5_check_dec_open_param(inst, open_param); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + if (!wave5_vpu_is_init(vpu_dev)) { + mutex_unlock(&vpu_dev->hw_lock); + return -ENODEV; + } + + p_dec_info = &inst->codec_info->dec_info; + memcpy(&p_dec_info->open_param, open_param, sizeof(struct dec_open_param)); + + buffer_addr = open_param->bitstream_buffer; + buffer_size = open_param->bitstream_buffer_size; + p_dec_info->stream_wr_ptr = buffer_addr; + p_dec_info->stream_rd_ptr = buffer_addr; + p_dec_info->stream_buf_start_addr = buffer_addr; + p_dec_info->stream_buf_size = buffer_size; + p_dec_info->stream_buf_end_addr = buffer_addr + buffer_size; + p_dec_info->reorder_enable = TRUE; + p_dec_info->temp_id_select_mode = TEMPORAL_ID_MODE_ABSOLUTE; + p_dec_info->target_temp_id = DECODE_ALL_TEMPORAL_LAYERS; + p_dec_info->target_spatial_id = DECODE_ALL_SPATIAL_LAYERS; + + ret = wave5_vpu_build_up_dec_param(inst, open_param); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +static int reset_auxiliary_buffers(struct vpu_instance *inst, unsigned int index) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + + if (index >= MAX_REG_FRAME) + return 1; + + if (p_dec_info->vb_mv[index].size == 0 && p_dec_info->vb_fbc_y_tbl[index].size == 0 && + p_dec_info->vb_fbc_c_tbl[index].size == 0) + return 1; + + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_mv[index]); + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_fbc_y_tbl[index]); + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_fbc_c_tbl[index]); + + return 0; +} + +int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + int retry = 0; + struct vpu_device *vpu_dev = inst->dev; + int i; + + *fail_res = 0; + if (!inst->codec_info) + return -EINVAL; + + pm_runtime_resume_and_get(inst->dev->dev); + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) { + pm_runtime_put_sync(inst->dev->dev); + return ret; + } + + do { + ret = wave5_vpu_dec_finish_seq(inst, fail_res); + if (ret < 0 && *fail_res != WAVE5_SYSERR_VPU_STILL_RUNNING) { + dev_warn(inst->dev->dev, "dec_finish_seq timed out\n"); + goto unlock_and_return; + } + + if (*fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING && + retry++ >= MAX_FIRMWARE_CALL_RETRY) { + ret = -ETIMEDOUT; + goto unlock_and_return; + } + } while (ret != 0); + + dev_dbg(inst->dev->dev, "%s: dec_finish_seq complete\n", __func__); + + wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_work); + + for (i = 0 ; i < MAX_REG_FRAME; i++) { + ret = reset_auxiliary_buffers(inst, i); + if (ret) { + ret = 0; + break; + } + } + + wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_task); + +unlock_and_return: + mutex_unlock(&vpu_dev->hw_lock); + pm_runtime_put_sync(inst->dev->dev); + return ret; +} + +int wave5_vpu_dec_issue_seq_init(struct vpu_instance *inst) +{ + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_dec_init_seq(inst); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_complete_seq_init(struct vpu_instance *inst, struct dec_initial_info *info) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_dec_get_seq_info(inst, info); + if (!ret) + p_dec_info->initial_info_obtained = true; + + info->rd_ptr = wave5_dec_get_rd_ptr(inst); + info->wr_ptr = p_dec_info->stream_wr_ptr; + + p_dec_info->initial_info = *info; + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_register_frame_buffer_ex(struct vpu_instance *inst, int num_of_decoding_fbs, + int num_of_display_fbs, int stride, int height) +{ + struct dec_info *p_dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + struct frame_buffer *fb; + + if (num_of_decoding_fbs >= WAVE5_MAX_FBS || num_of_display_fbs >= WAVE5_MAX_FBS) + return -EINVAL; + + p_dec_info = &inst->codec_info->dec_info; + p_dec_info->num_of_decoding_fbs = num_of_decoding_fbs; + p_dec_info->num_of_display_fbs = num_of_display_fbs; + p_dec_info->stride = stride; + + if (!p_dec_info->initial_info_obtained) + return -EINVAL; + + if (stride < p_dec_info->initial_info.pic_width || (stride % 8 != 0) || + height < p_dec_info->initial_info.pic_height) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + fb = inst->frame_buf; + ret = wave5_vpu_dec_register_framebuffer(inst, &fb[p_dec_info->num_of_decoding_fbs], + LINEAR_FRAME_MAP, p_dec_info->num_of_display_fbs); + if (ret) + goto err_out; + + ret = wave5_vpu_dec_register_framebuffer(inst, &fb[0], COMPRESSED_FRAME_MAP, + p_dec_info->num_of_decoding_fbs); + +err_out: + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_get_bitstream_buffer(struct vpu_instance *inst, dma_addr_t *prd_ptr, + dma_addr_t *pwr_ptr, size_t *size) +{ + struct dec_info *p_dec_info; + dma_addr_t rd_ptr; + dma_addr_t wr_ptr; + int room; + struct vpu_device *vpu_dev = inst->dev; + int ret; + + p_dec_info = &inst->codec_info->dec_info; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + rd_ptr = wave5_dec_get_rd_ptr(inst); + mutex_unlock(&vpu_dev->hw_lock); + + wr_ptr = p_dec_info->stream_wr_ptr; + + if (wr_ptr < rd_ptr) + room = rd_ptr - wr_ptr; + else + room = (p_dec_info->stream_buf_end_addr - wr_ptr) + + (rd_ptr - p_dec_info->stream_buf_start_addr); + room--; + + if (prd_ptr) + *prd_ptr = rd_ptr; + if (pwr_ptr) + *pwr_ptr = wr_ptr; + if (size) + *size = room; + + return 0; +} + +int wave5_vpu_dec_update_bitstream_buffer(struct vpu_instance *inst, size_t size) +{ + struct dec_info *p_dec_info; + dma_addr_t wr_ptr; + dma_addr_t rd_ptr; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (!inst->codec_info) + return -EINVAL; + + p_dec_info = &inst->codec_info->dec_info; + wr_ptr = p_dec_info->stream_wr_ptr; + rd_ptr = p_dec_info->stream_rd_ptr; + + if (size > 0) { + if (wr_ptr < rd_ptr && rd_ptr <= wr_ptr + size) + return -EINVAL; + + wr_ptr += size; + + if (wr_ptr > p_dec_info->stream_buf_end_addr) { + u32 room = wr_ptr - p_dec_info->stream_buf_end_addr; + + wr_ptr = p_dec_info->stream_buf_start_addr; + wr_ptr += room; + } else if (wr_ptr == p_dec_info->stream_buf_end_addr) { + wr_ptr = p_dec_info->stream_buf_start_addr; + } + + p_dec_info->stream_wr_ptr = wr_ptr; + p_dec_info->stream_rd_ptr = rd_ptr; + } + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + ret = wave5_vpu_dec_set_bitstream_flag(inst, (size == 0)); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_start_one_frame(struct vpu_instance *inst, u32 *res_fail) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (p_dec_info->stride == 0) /* this means frame buffers have not been registered. */ + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_decode(inst, res_fail); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr, int update_wr_ptr) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_dec_set_rd_ptr(inst, addr); + + p_dec_info->stream_rd_ptr = addr; + if (update_wr_ptr) + p_dec_info->stream_wr_ptr = addr; + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +dma_addr_t wave5_vpu_dec_get_rd_ptr(struct vpu_instance *inst) +{ + int ret; + dma_addr_t rd_ptr; + + ret = mutex_lock_interruptible(&inst->dev->hw_lock); + if (ret) + return ret; + + rd_ptr = wave5_dec_get_rd_ptr(inst); + + mutex_unlock(&inst->dev->hw_lock); + + return rd_ptr; +} + +int wave5_vpu_dec_get_output_info(struct vpu_instance *inst, struct dec_output_info *info) +{ + struct dec_info *p_dec_info; + int ret; + struct vpu_rect rect_info; + u32 val; + u32 decoded_index; + u32 disp_idx; + u32 max_dec_index; + struct vpu_device *vpu_dev = inst->dev; + struct dec_output_info *disp_info; + + if (!info) + return -EINVAL; + + p_dec_info = &inst->codec_info->dec_info; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + memset(info, 0, sizeof(*info)); + + ret = wave5_vpu_dec_get_result(inst, info); + if (ret) { + info->rd_ptr = p_dec_info->stream_rd_ptr; + info->wr_ptr = p_dec_info->stream_wr_ptr; + goto err_out; + } + + decoded_index = info->index_frame_decoded; + + /* calculate display frame region */ + val = 0; + rect_info.left = 0; + rect_info.right = 0; + rect_info.top = 0; + rect_info.bottom = 0; + + if (decoded_index < WAVE5_MAX_FBS) { + if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC) + rect_info = p_dec_info->initial_info.pic_crop_rect; + + if (inst->std == W_HEVC_DEC) + p_dec_info->dec_out_info[decoded_index].decoded_poc = info->decoded_poc; + + p_dec_info->dec_out_info[decoded_index].rc_decoded = rect_info; + } + info->rc_decoded = rect_info; + + disp_idx = info->index_frame_display; + if (info->index_frame_display >= 0 && info->index_frame_display < WAVE5_MAX_FBS) { + disp_info = &p_dec_info->dec_out_info[disp_idx]; + if (info->index_frame_display != info->index_frame_decoded) { + /* + * when index_frame_decoded < 0, and index_frame_display >= 0 + * info->dec_pic_width and info->dec_pic_height are still valid + * but those of p_dec_info->dec_out_info[disp_idx] are invalid in VP9 + */ + info->disp_pic_width = disp_info->dec_pic_width; + info->disp_pic_height = disp_info->dec_pic_height; + } else { + info->disp_pic_width = info->dec_pic_width; + info->disp_pic_height = info->dec_pic_height; + } + + info->rc_display = disp_info->rc_decoded; + + } else { + info->rc_display.left = 0; + info->rc_display.right = 0; + info->rc_display.top = 0; + info->rc_display.bottom = 0; + info->disp_pic_width = 0; + info->disp_pic_height = 0; + } + + p_dec_info->stream_rd_ptr = wave5_dec_get_rd_ptr(inst); + p_dec_info->frame_display_flag = vpu_read_reg(vpu_dev, W5_RET_DEC_DISP_IDC); + + val = p_dec_info->num_of_decoding_fbs; //fb_offset + + max_dec_index = (p_dec_info->num_of_decoding_fbs > p_dec_info->num_of_display_fbs) ? + p_dec_info->num_of_decoding_fbs : p_dec_info->num_of_display_fbs; + + if (info->index_frame_display >= 0 && + info->index_frame_display < (int)max_dec_index) + info->disp_frame = inst->frame_buf[val + info->index_frame_display]; + + info->rd_ptr = p_dec_info->stream_rd_ptr; + info->wr_ptr = p_dec_info->stream_wr_ptr; + info->frame_display_flag = p_dec_info->frame_display_flag; + + info->sequence_no = p_dec_info->initial_info.sequence_no; + if (decoded_index < WAVE5_MAX_FBS) + p_dec_info->dec_out_info[decoded_index] = *info; + + if (disp_idx < WAVE5_MAX_FBS) + info->disp_frame.sequence_no = info->sequence_no; + + if (info->sequence_changed) { + memcpy((void *)&p_dec_info->initial_info, (void *)&p_dec_info->new_seq_info, + sizeof(struct dec_initial_info)); + p_dec_info->initial_info.sequence_no++; + } + +err_out: + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_clr_disp_flag(struct vpu_instance *inst, int index) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (index >= p_dec_info->num_of_display_fbs) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + ret = wave5_dec_clr_disp_flag(inst, index); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_set_disp_flag(struct vpu_instance *inst, int index) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret = 0; + struct vpu_device *vpu_dev = inst->dev; + + if (index >= p_dec_info->num_of_display_fbs) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + ret = wave5_dec_set_disp_flag(inst, index); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_dec_reset_framebuffer(struct vpu_instance *inst, unsigned int index) +{ + if (index >= MAX_REG_FRAME) + return -EINVAL; + + if (inst->frame_vbuf[index].size == 0) + return -EINVAL; + + wave5_vdi_free_dma_memory(inst->dev, &inst->frame_vbuf[index]); + + return 0; +} + +int wave5_vpu_dec_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret = 0; + + switch (cmd) { + case DEC_GET_QUEUE_STATUS: { + struct queue_status_info *queue_info = parameter; + + queue_info->instance_queue_count = p_dec_info->instance_queue_count; + queue_info->report_queue_count = p_dec_info->report_queue_count; + break; + } + case DEC_RESET_FRAMEBUF_INFO: { + int i; + + for (i = 0; i < MAX_REG_FRAME; i++) { + ret = wave5_vpu_dec_reset_framebuffer(inst, i); + if (ret) + break; + } + + for (i = 0; i < MAX_REG_FRAME; i++) { + ret = reset_auxiliary_buffers(inst, i); + if (ret) + break; + } + + wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task); + break; + } + case DEC_GET_SEQ_INFO: { + struct dec_initial_info *seq_info = parameter; + + *seq_info = p_dec_info->initial_info; + break; + } + + default: + return -EINVAL; + } + + return ret; +} + +int wave5_vpu_enc_open(struct vpu_instance *inst, struct enc_open_param *open_param) +{ + struct enc_info *p_enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = wave5_vpu_enc_check_open_param(inst, open_param); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + if (!wave5_vpu_is_init(vpu_dev)) { + mutex_unlock(&vpu_dev->hw_lock); + return -ENODEV; + } + + p_enc_info = &inst->codec_info->enc_info; + p_enc_info->open_param = *open_param; + + ret = wave5_vpu_build_up_enc_param(vpu_dev->dev, inst, open_param); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + int retry = 0; + struct vpu_device *vpu_dev = inst->dev; + + *fail_res = 0; + if (!inst->codec_info) + return -EINVAL; + + pm_runtime_resume_and_get(inst->dev->dev); + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + do { + ret = wave5_vpu_enc_finish_seq(inst, fail_res); + if (ret < 0 && *fail_res != WAVE5_SYSERR_VPU_STILL_RUNNING) { + dev_warn(inst->dev->dev, "enc_finish_seq timed out\n"); + mutex_unlock(&vpu_dev->hw_lock); + return ret; + } + + if (*fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING && + retry++ >= MAX_FIRMWARE_CALL_RETRY) { + mutex_unlock(&vpu_dev->hw_lock); + return -ETIMEDOUT; + } + } while (ret != 0); + + dev_dbg(inst->dev->dev, "%s: enc_finish_seq complete\n", __func__); + + wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_work); + + if (inst->std == W_HEVC_ENC || inst->std == W_AVC_ENC) { + wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_sub_sam_buf); + wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_mv); + wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_fbc_y_tbl); + wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_fbc_c_tbl); + } + + wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_task); + mutex_unlock(&vpu_dev->hw_lock); + + pm_runtime_put_sync(inst->dev->dev); + return 0; +} + +int wave5_vpu_enc_register_frame_buffer(struct vpu_instance *inst, unsigned int num, + unsigned int stride, int height, + enum tiled_map_type map_type) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + unsigned int size_luma, size_chroma; + int i; + + if (p_enc_info->stride) + return -EINVAL; + + if (!p_enc_info->initial_info_obtained) + return -EINVAL; + + if (num < p_enc_info->initial_info.min_frame_buffer_count) + return -EINVAL; + + if (stride == 0 || stride % 8 != 0) + return -EINVAL; + + if (height <= 0) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + p_enc_info->num_frame_buffers = num; + p_enc_info->stride = stride; + + size_luma = stride * height; + size_chroma = ALIGN(stride / 2, 16) * height; + + for (i = 0; i < num; i++) { + if (!inst->frame_buf[i].update_fb_info) + continue; + + inst->frame_buf[i].update_fb_info = false; + inst->frame_buf[i].stride = stride; + inst->frame_buf[i].height = height; + inst->frame_buf[i].map_type = COMPRESSED_FRAME_MAP; + inst->frame_buf[i].buf_y_size = size_luma; + inst->frame_buf[i].buf_cb = inst->frame_buf[i].buf_y + size_luma; + inst->frame_buf[i].buf_cb_size = size_chroma; + inst->frame_buf[i].buf_cr_size = 0; + } + + ret = wave5_vpu_enc_register_framebuffer(inst->dev->dev, inst, &inst->frame_buf[0], + COMPRESSED_FRAME_MAP, + p_enc_info->num_frame_buffers); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +static int wave5_check_enc_param(struct vpu_instance *inst, struct enc_param *param) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + + if (!param) + return -EINVAL; + + if (!param->source_frame) + return -EINVAL; + + if (p_enc_info->open_param.bit_rate == 0 && inst->std == W_HEVC_ENC) { + if (param->pic_stream_buffer_addr % 16 || param->pic_stream_buffer_size == 0) + return -EINVAL; + } + if (param->pic_stream_buffer_addr % 8 || param->pic_stream_buffer_size == 0) + return -EINVAL; + + return 0; +} + +int wave5_vpu_enc_change_param(struct vpu_instance *inst, u32 *fail_res) +{ + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_enc_apply_change_param(inst, fail_res); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_enc_start_one_frame(struct vpu_instance *inst, struct enc_param *param, u32 *fail_res) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + *fail_res = 0; + + if (p_enc_info->stride == 0) /* this means frame buffers have not been registered. */ + return -EINVAL; + + ret = wave5_check_enc_param(inst, param); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + p_enc_info->pts_map[param->src_idx] = param->pts; + + ret = wave5_vpu_encode(inst, param, fail_res); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_enc_get_output_info(struct vpu_instance *inst, struct enc_output_info *info) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_enc_get_result(inst, info); + if (ret) { + info->pts = 0; + goto unlock; + } + + if (info->recon_frame_index >= 0) + info->pts = p_enc_info->pts_map[info->enc_src_idx]; + +unlock: + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_enc_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + + switch (cmd) { + case ENABLE_ROTATION: + p_enc_info->rotation_enable = true; + break; + case ENABLE_MIRRORING: + p_enc_info->mirror_enable = true; + break; + case SET_MIRROR_DIRECTION: { + enum mirror_direction mir_dir; + + mir_dir = *(enum mirror_direction *)parameter; + if (mir_dir != MIRDIR_NONE && mir_dir != MIRDIR_HOR && + mir_dir != MIRDIR_VER && mir_dir != MIRDIR_HOR_VER) + return -EINVAL; + p_enc_info->mirror_direction = mir_dir; + break; + } + case SET_ROTATION_ANGLE: { + int angle; + + angle = *(int *)parameter; + if (angle && angle != 90 && angle != 180 && angle != 270) + return -EINVAL; + if (p_enc_info->initial_info_obtained && (angle == 90 || angle == 270)) + return -EINVAL; + p_enc_info->rotation_angle = angle; + break; + } + case ENC_GET_QUEUE_STATUS: { + struct queue_status_info *queue_info = parameter; + + queue_info->instance_queue_count = p_enc_info->instance_queue_count; + queue_info->report_queue_count = p_enc_info->report_queue_count; + break; + } + default: + return -EINVAL; + } + return 0; +} + +int wave5_vpu_enc_issue_seq_init(struct vpu_instance *inst) +{ + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_enc_init_seq(inst); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave5_vpu_enc_complete_seq_init(struct vpu_instance *inst, struct enc_initial_info *info) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (!info) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave5_vpu_enc_get_seq_info(inst, info); + if (ret) { + p_enc_info->initial_info_obtained = false; + mutex_unlock(&vpu_dev->hw_lock); + return ret; + } + + p_enc_info->initial_info_obtained = true; + p_enc_info->initial_info = *info; + + mutex_unlock(&vpu_dev->hw_lock); + + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h --- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,903 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - helper definitions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef VPUAPI_H_INCLUDED +#define VPUAPI_H_INCLUDED + +#include +#include +#include +#include +#include +#include "wave5-vpuerror.h" +#include "wave5-vpuconfig.h" +#include "wave5-vdi.h" + +enum product_id { + PRODUCT_ID_521, + PRODUCT_ID_511, + PRODUCT_ID_517, + PRODUCT_ID_NONE, +}; + +struct vpu_attr; + +enum vpu_instance_type { + VPU_INST_TYPE_DEC = 0, + VPU_INST_TYPE_ENC = 1 +}; + +enum vpu_instance_state { + VPU_INST_STATE_NONE = 0, + VPU_INST_STATE_OPEN = 1, + VPU_INST_STATE_INIT_SEQ = 2, + VPU_INST_STATE_PIC_RUN = 3, + VPU_INST_STATE_STOP = 4 +}; + +/* Maximum available on hardware. */ +#define WAVE5_MAX_FBS 32 + +#define MAX_REG_FRAME (WAVE5_MAX_FBS * 2) + +#define WAVE5_DEC_HEVC_BUF_SIZE(_w, _h) (DIV_ROUND_UP(_w, 64) * DIV_ROUND_UP(_h, 64) * 256 + 64) +#define WAVE5_DEC_AVC_BUF_SIZE(_w, _h) ((((ALIGN(_w, 256) / 16) * (ALIGN(_h, 16) / 16)) + 16) * 80) + +#define WAVE5_FBC_LUMA_TABLE_SIZE(_w, _h) (ALIGN(_h, 64) * ALIGN(_w, 256) / 32) +#define WAVE5_FBC_CHROMA_TABLE_SIZE(_w, _h) (ALIGN((_h), 64) * ALIGN((_w) / 2, 256) / 32) +#define WAVE5_ENC_AVC_BUF_SIZE(_w, _h) (ALIGN(_w, 64) * ALIGN(_h, 64) / 32) +#define WAVE5_ENC_HEVC_BUF_SIZE(_w, _h) (ALIGN(_w, 64) / 64 * ALIGN(_h, 64) / 64 * 128) + +/* + * common struct and definition + */ +enum cod_std { + STD_AVC = 0, + STD_HEVC = 12, + STD_MAX +}; + +enum wave_std { + W_HEVC_DEC = 0x00, + W_HEVC_ENC = 0x01, + W_AVC_DEC = 0x02, + W_AVC_ENC = 0x03, + STD_UNKNOWN = 0xFF +}; + +enum set_param_option { + OPT_COMMON = 0, /* SET_PARAM command option for encoding sequence */ + OPT_CUSTOM_GOP = 1, /* SET_PARAM command option for setting custom GOP */ + OPT_CUSTOM_HEADER = 2, /* SET_PARAM command option for setting custom VPS/SPS/PPS */ + OPT_VUI = 3, /* SET_PARAM command option for encoding VUI */ + OPT_CHANGE_PARAM = 0x10, +}; + +/************************************************************************/ +/* PROFILE & LEVEL */ +/************************************************************************/ +/* HEVC */ +#define HEVC_PROFILE_MAIN 1 +#define HEVC_PROFILE_MAIN10 2 +#define HEVC_PROFILE_STILLPICTURE 3 +#define HEVC_PROFILE_MAIN10_STILLPICTURE 2 + +/* H.264 profile for encoder*/ +#define H264_PROFILE_BP 1 +#define H264_PROFILE_MP 2 +#define H264_PROFILE_EXTENDED 3 +#define H264_PROFILE_HP 4 +#define H264_PROFILE_HIGH10 5 +#define H264_PROFILE_HIGH422 6 +#define H264_PROFILE_HIGH444 7 + +/************************************************************************/ +/* error codes */ +/************************************************************************/ + +/************************************************************************/ +/* utility macros */ +/************************************************************************/ + +/* Initialize sequence firmware command mode */ +#define INIT_SEQ_NORMAL 1 + +/* Decode firmware command mode */ +#define DEC_PIC_NORMAL 0 + +/* bit_alloc_mode */ +#define BIT_ALLOC_MODE_FIXED_RATIO 2 + +/* bit_rate */ +#define MAX_BIT_RATE 700000000 + +/* decoding_refresh_type */ +#define DEC_REFRESH_TYPE_NON_IRAP 0 +#define DEC_REFRESH_TYPE_CRA 1 +#define DEC_REFRESH_TYPE_IDR 2 + +/* depend_slice_mode */ +#define DEPEND_SLICE_MODE_RECOMMENDED 1 +#define DEPEND_SLICE_MODE_BOOST 2 +#define DEPEND_SLICE_MODE_FAST 3 + +/* hvs_max_delta_qp */ +#define MAX_HVS_MAX_DELTA_QP 51 + +/* intra_refresh_mode */ +#define REFRESH_MODE_CTU_ROWS 1 +#define REFRESH_MODE_CTU_COLUMNS 2 +#define REFRESH_MODE_CTU_STEP_SIZE 3 +#define REFRESH_MODE_CTUS 4 + +/* intra_mb_refresh_mode */ +#define REFRESH_MB_MODE_NONE 0 +#define REFRESH_MB_MODE_CTU_ROWS 1 +#define REFRESH_MB_MODE_CTU_COLUMNS 2 +#define REFRESH_MB_MODE_CTU_STEP_SIZE 3 + +/* intra_qp */ +#define MAX_INTRA_QP 63 + +/* nr_inter_weight_* */ +#define MAX_INTER_WEIGHT 31 + +/* nr_intra_weight_* */ +#define MAX_INTRA_WEIGHT 31 + +/* nr_noise_sigma_* */ +#define MAX_NOISE_SIGMA 255 + +/* bitstream_buffer_size */ +#define MIN_BITSTREAM_BUFFER_SIZE 1024 +#define MIN_BITSTREAM_BUFFER_SIZE_WAVE521 (1024 * 64) + +/* vbv_buffer_size */ +#define MIN_VBV_BUFFER_SIZE 10 +#define MAX_VBV_BUFFER_SIZE 3000 + +#define BUFFER_MARGIN 4096 + +#define MAX_FIRMWARE_CALL_RETRY 10 + +#define VDI_LITTLE_ENDIAN 0x0 + +/* + * Parameters of DEC_SET_SEQ_CHANGE_MASK + */ +#define SEQ_CHANGE_ENABLE_PROFILE BIT(5) +#define SEQ_CHANGE_ENABLE_SIZE BIT(16) +#define SEQ_CHANGE_ENABLE_BITDEPTH BIT(18) +#define SEQ_CHANGE_ENABLE_DPB_COUNT BIT(19) +#define SEQ_CHANGE_ENABLE_ASPECT_RATIO BIT(21) +#define SEQ_CHANGE_ENABLE_VIDEO_SIGNAL BIT(23) +#define SEQ_CHANGE_ENABLE_VUI_TIMING_INFO BIT(29) + +#define SEQ_CHANGE_ENABLE_ALL_HEVC (SEQ_CHANGE_ENABLE_PROFILE | \ + SEQ_CHANGE_ENABLE_SIZE | \ + SEQ_CHANGE_ENABLE_BITDEPTH | \ + SEQ_CHANGE_ENABLE_DPB_COUNT) + +#define SEQ_CHANGE_ENABLE_ALL_AVC (SEQ_CHANGE_ENABLE_SIZE | \ + SEQ_CHANGE_ENABLE_BITDEPTH | \ + SEQ_CHANGE_ENABLE_DPB_COUNT | \ + SEQ_CHANGE_ENABLE_ASPECT_RATIO | \ + SEQ_CHANGE_ENABLE_VIDEO_SIGNAL | \ + SEQ_CHANGE_ENABLE_VUI_TIMING_INFO) + +#define DISPLAY_IDX_FLAG_SEQ_END -1 +#define DISPLAY_IDX_FLAG_NO_FB -3 +#define DECODED_IDX_FLAG_NO_FB -1 +#define DECODED_IDX_FLAG_SKIP -2 + +#define RECON_IDX_FLAG_ENC_END -1 +#define RECON_IDX_FLAG_ENC_DELAY -2 +#define RECON_IDX_FLAG_HEADER_ONLY -3 +#define RECON_IDX_FLAG_CHANGE_PARAM -4 + +enum codec_command { + ENABLE_ROTATION, + ENABLE_MIRRORING, + SET_MIRROR_DIRECTION, + SET_ROTATION_ANGLE, + DEC_GET_QUEUE_STATUS, + ENC_GET_QUEUE_STATUS, + DEC_RESET_FRAMEBUF_INFO, + DEC_GET_SEQ_INFO, +}; + +enum mirror_direction { + MIRDIR_NONE, /* no mirroring */ + MIRDIR_VER, /* vertical mirroring */ + MIRDIR_HOR, /* horizontal mirroring */ + MIRDIR_HOR_VER /* horizontal and vertical mirroring */ +}; + +enum frame_buffer_format { + FORMAT_ERR = -1, + FORMAT_420 = 0, /* 8bit */ + FORMAT_422, /* 8bit */ + FORMAT_224, /* 8bit */ + FORMAT_444, /* 8bit */ + FORMAT_400, /* 8bit */ + + /* little endian perspective */ + /* | addr 0 | addr 1 | */ + FORMAT_420_P10_16BIT_MSB = 5, /* lsb |000000xx|xxxxxxxx | msb */ + FORMAT_420_P10_16BIT_LSB, /* lsb |xxxxxxx |xx000000 | msb */ + FORMAT_420_P10_32BIT_MSB, /* lsb |00xxxxxxxxxxxxxxxxxxxxxxxxxxx| msb */ + FORMAT_420_P10_32BIT_LSB, /* lsb |xxxxxxxxxxxxxxxxxxxxxxxxxxx00| msb */ + + /* 4:2:2 packed format */ + /* little endian perspective */ + /* | addr 0 | addr 1 | */ + FORMAT_422_P10_16BIT_MSB, /* lsb |000000xx |xxxxxxxx | msb */ + FORMAT_422_P10_16BIT_LSB, /* lsb |xxxxxxxx |xx000000 | msb */ + FORMAT_422_P10_32BIT_MSB, /* lsb |00xxxxxxxxxxxxxxxxxxxxxxxxxxx| msb */ + FORMAT_422_P10_32BIT_LSB, /* lsb |xxxxxxxxxxxxxxxxxxxxxxxxxxx00| msb */ + + FORMAT_YUYV, /* 8bit packed format : Y0U0Y1V0 Y2U1Y3V1 ... */ + FORMAT_YUYV_P10_16BIT_MSB, + FORMAT_YUYV_P10_16BIT_LSB, + FORMAT_YUYV_P10_32BIT_MSB, + FORMAT_YUYV_P10_32BIT_LSB, + + FORMAT_YVYU, /* 8bit packed format : Y0V0Y1U0 Y2V1Y3U1 ... */ + FORMAT_YVYU_P10_16BIT_MSB, + FORMAT_YVYU_P10_16BIT_LSB, + FORMAT_YVYU_P10_32BIT_MSB, + FORMAT_YVYU_P10_32BIT_LSB, + + FORMAT_UYVY, /* 8bit packed format : U0Y0V0Y1 U1Y2V1Y3 ... */ + FORMAT_UYVY_P10_16BIT_MSB, + FORMAT_UYVY_P10_16BIT_LSB, + FORMAT_UYVY_P10_32BIT_MSB, + FORMAT_UYVY_P10_32BIT_LSB, + + FORMAT_VYUY, /* 8bit packed format : V0Y0U0Y1 V1Y2U1Y3 ... */ + FORMAT_VYUY_P10_16BIT_MSB, + FORMAT_VYUY_P10_16BIT_LSB, + FORMAT_VYUY_P10_32BIT_MSB, + FORMAT_VYUY_P10_32BIT_LSB, + + FORMAT_MAX, +}; + +enum packed_format_num { + NOT_PACKED = 0, + PACKED_YUYV, + PACKED_YVYU, + PACKED_UYVY, + PACKED_VYUY, +}; + +enum wave5_interrupt_bit { + INT_WAVE5_INIT_VPU = 0, + INT_WAVE5_WAKEUP_VPU = 1, + INT_WAVE5_SLEEP_VPU = 2, + INT_WAVE5_CREATE_INSTANCE = 3, + INT_WAVE5_FLUSH_INSTANCE = 4, + INT_WAVE5_DESTROY_INSTANCE = 5, + INT_WAVE5_INIT_SEQ = 6, + INT_WAVE5_SET_FRAMEBUF = 7, + INT_WAVE5_DEC_PIC = 8, + INT_WAVE5_ENC_PIC = 8, + INT_WAVE5_ENC_SET_PARAM = 9, + INT_WAVE5_DEC_QUERY = 14, + INT_WAVE5_BSBUF_EMPTY = 15, + INT_WAVE5_BSBUF_FULL = 15, +}; + +enum pic_type { + PIC_TYPE_I = 0, + PIC_TYPE_P = 1, + PIC_TYPE_B = 2, + PIC_TYPE_IDR = 5, /* H.264/H.265 IDR (Instantaneous Decoder Refresh) picture */ + PIC_TYPE_MAX /* no meaning */ +}; + +enum sw_reset_mode { + SW_RESET_SAFETY, + SW_RESET_FORCE, + SW_RESET_ON_BOOT +}; + +enum tiled_map_type { + LINEAR_FRAME_MAP = 0, /* linear frame map type */ + COMPRESSED_FRAME_MAP = 17, /* compressed frame map type*/ +}; + +enum temporal_id_mode { + TEMPORAL_ID_MODE_ABSOLUTE, + TEMPORAL_ID_MODE_RELATIVE, +}; + +struct vpu_attr { + u32 product_id; + char product_name[8]; /* product name in ascii code */ + u32 product_version; + u32 fw_version; + u32 customer_id; + u32 support_decoders; /* bitmask */ + u32 support_encoders; /* bitmask */ + u32 support_backbone: 1; + u32 support_avc10bit_enc: 1; + u32 support_hevc10bit_enc: 1; + u32 support_vcore_backbone: 1; + u32 support_vcpu_backbone: 1; +}; + +struct frame_buffer { + dma_addr_t buf_y; + dma_addr_t buf_cb; + dma_addr_t buf_cr; + unsigned int buf_y_size; + unsigned int buf_cb_size; + unsigned int buf_cr_size; + enum tiled_map_type map_type; + unsigned int stride; /* horizontal stride for the given frame buffer */ + unsigned int width; /* width of the given frame buffer */ + unsigned int height; /* height of the given frame buffer */ + size_t size; /* size of the given frame buffer */ + unsigned int sequence_no; + bool update_fb_info; +}; + +struct vpu_rect { + unsigned int left; /* horizontal pixel offset from left edge */ + unsigned int top; /* vertical pixel offset from top edge */ + unsigned int right; /* horizontal pixel offset from right edge */ + unsigned int bottom; /* vertical pixel offset from bottom edge */ +}; + +/* + * decode struct and definition + */ + +struct dec_open_param { + dma_addr_t bitstream_buffer; + size_t bitstream_buffer_size; +}; + +struct dec_initial_info { + u32 pic_width; + u32 pic_height; + struct vpu_rect pic_crop_rect; + u32 min_frame_buffer_count; /* between 1 to 16 */ + + u32 profile; + u32 luma_bitdepth; /* bit-depth of the luma sample */ + u32 chroma_bitdepth; /* bit-depth of the chroma sample */ + u32 seq_init_err_reason; + dma_addr_t rd_ptr; /* read pointer of bitstream buffer */ + dma_addr_t wr_ptr; /* write pointer of bitstream buffer */ + u32 sequence_no; + u32 vlc_buf_size; + u32 param_buf_size; +}; + +struct dec_output_info { + /** + * This is a frame buffer index for the picture to be displayed at the moment + * among frame buffers which are registered using vpu_dec_register_frame_buffer(). + * Frame data that will be displayed is stored in the frame buffer with this index + * When there is no display delay, this index is always the equal to + * index_frame_decoded, however, if displaying is delayed (for display + * reordering in AVC or B-frames in VC1), this index might be different to + * index_frame_decoded. By checking this index, HOST applications can easily figure + * out whether sequence decoding has been finished or not. + * + * -3(0xFFFD) or -2(0xFFFE) : when a display output cannot be given due to picture + * reordering or skip option + * -1(0xFFFF) : when there is no more output for display at the end of sequence + * decoding + */ + s32 index_frame_display; + /** + * This is the frame buffer index of the decoded picture among the frame buffers which were + * registered using vpu_dec_register_frame_buffer(). The currently decoded frame is stored + * into the frame buffer specified by this index. + * + * -2 : indicates that no decoded output is generated because decoder meets EOS + * (end of sequence) or skip + * -1 : indicates that the decoder fails to decode a picture because there is no available + * frame buffer + */ + s32 index_frame_decoded; + s32 index_frame_decoded_for_tiled; + u32 nal_type; + unsigned int pic_type; + struct vpu_rect rc_display; + unsigned int disp_pic_width; + unsigned int disp_pic_height; + struct vpu_rect rc_decoded; + u32 dec_pic_width; + u32 dec_pic_height; + s32 decoded_poc; + int temporal_id; /* temporal ID of the picture */ + dma_addr_t rd_ptr; /* stream buffer read pointer for the current decoder instance */ + dma_addr_t wr_ptr; /* stream buffer write pointer for the current decoder instance */ + struct frame_buffer disp_frame; + u32 frame_display_flag; /* it reports a frame buffer flag to be displayed */ + /** + * this variable reports that sequence has been changed while H.264/AVC stream decoding. + * if it is 1, HOST application can get the new sequence information by calling + * vpu_dec_get_initial_info() or wave5_vpu_dec_issue_seq_init(). + * + * for H.265/HEVC decoder, each bit has a different meaning as follows. + * + * sequence_changed[5] : it indicates that the profile_idc has been changed + * sequence_changed[16] : it indicates that the resolution has been changed + * sequence_changed[19] : it indicates that the required number of frame buffer has + * been changed. + */ + unsigned int frame_cycle; /* reports the number of cycles for processing a frame */ + u32 sequence_no; + + u32 dec_host_cmd_tick; /* tick of DEC_PIC command for the picture */ + u32 dec_decode_end_tick; /* end tick of decoding slices of the picture */ + + u32 sequence_changed; +}; + +struct queue_status_info { + u32 instance_queue_count; + u32 report_queue_count; +}; + +/* + * encode struct and definition + */ + +#define MAX_NUM_TEMPORAL_LAYER 7 +#define MAX_NUM_SPATIAL_LAYER 3 +#define MAX_GOP_NUM 8 + +enum enc_change_param { + // COMMON parameters which can be changed frame by frame. + W5_ENC_CHANGE_PARAM_PPS = (1<<0), + W5_ENC_CHANGE_PARAM_INTRA_PARAM = (1<<1), + W5_ENC_CHANGE_PARAM_RC_FRAME_RATE = (1<<6), + W5_ENC_CHANGE_PARAM_RC_TARGET_RATE = (1<<8), + W5_ENC_CHANGE_PARAM_RC = (1<<9), + W5_ENC_CHANGE_PARAM_RC_MIN_MAX_QP = (1<<10), + W5_ENC_CHANGE_PARAM_RC_BIT_RATIO_LAYER = (1<<11), + W5_ENC_CHANGE_PARAM_RC_INTER_MIN_MAX_QP = (1<<12), + W5_ENC_CHANGE_PARAM_RC_WEIGHT = (1<<13), + W5_ENC_CHANGE_PARAM_INDEPEND_SLICE = (1<<16), + W5_ENC_CHANGE_PARAM_DEPEND_SLICE = (1<<17), + W5_ENC_CHANGE_PARAM_RDO = (1<<18), + W5_ENC_CHANGE_PARAM_NR = (1<<19), + W5_ENC_CHANGE_PARAM_BG = (1<<20), + W5_ENC_CHANGE_PARAM_CUSTOM_MD = (1<<21), + W5_ENC_CHANGE_PARAM_CUSTOM_LAMBDA = (1<<22), + W5_ENC_CHANGE_PARAM_VUI_HRD_PARAM = (1<<23), +}; + +struct custom_gop_pic_param { + u32 pic_type; /* picture type of nth picture in the custom GOP */ + u32 poc_offset; /* POC of nth picture in the custom GOP */ + u32 pic_qp; /* quantization parameter of nth picture in the custom GOP */ + u32 use_multi_ref_p; /* use multiref pic for P picture. valid only if PIC_TYPE is P */ + u32 ref_poc_l0; /* POC of reference L0 of nth picture in the custom GOP */ + u32 ref_poc_l1; /* POC of reference L1 of nth picture in the custom GOP */ + s32 temporal_id; /* temporal ID of nth picture in the custom GOP */ +}; + +struct enc_wave_param { + /* + * profile indicator (HEVC only) + * + * 0 : the firmware determines a profile according to the internal_bit_depth + * 1 : main profile + * 2 : main10 profile + * 3 : main still picture profile + * In the AVC encoder, a profile cannot be set by the host application. + * The firmware decides it based on internal_bit_depth. + * profile = HIGH (bitdepth 8) profile = HIGH10 (bitdepth 10) + */ + u32 profile; + u32 level; /* level indicator (level * 10) */ + u32 internal_bit_depth: 4; /* 8/10 */ + u32 gop_preset_idx: 4; /* 0 - 9 */ + u32 decoding_refresh_type: 2; /* 0=non-IRAP, 1=CRA, 2=IDR */ + u32 intra_qp; /* quantization parameter of intra picture */ + u32 intra_period; /* period of intra picture in GOP size */ + u32 conf_win_top; /* top offset of conformance window */ + u32 conf_win_bot; /* bottom offset of conformance window */ + u32 conf_win_left; /* left offset of conformance window */ + u32 conf_win_right; /* right offset of conformance window */ + u32 intra_refresh_mode: 3; + /* + * Argument for intra_ctu_refresh_mode. + * + * Depending on intra_refresh_mode, it can mean one of the following: + * - intra_ctu_refresh_mode (1) -> number of consecutive CTU rows + * - intra_ctu_refresh_mode (2) -> the number of consecutive CTU columns + * - intra_ctu_refresh_mode (3) -> step size in CTU + * - intra_ctu_refresh_mode (4) -> number of intra ct_us to be encoded in a picture + */ + u32 intra_refresh_arg; + /* + * 0 : custom setting + * 1 : recommended encoder parameters (slow encoding speed, highest picture quality) + * 2 : boost mode (normal encoding speed, moderate picture quality) + * 3 : fast mode (fast encoding speed, low picture quality) + */ + u32 depend_slice_mode : 2; + u32 depend_slice_mode_arg; + u32 independ_slice_mode : 1; /* 0=no-multi-slice, 1=slice-in-ctu-number*/ + u32 independ_slice_mode_arg; + u32 max_num_merge: 2; + s32 beta_offset_div2: 4; /* sets beta_offset_div2 for deblocking filter */ + s32 tc_offset_div2: 4; /* sets tc_offset_div3 for deblocking filter */ + u32 hvs_qp_scale: 4; /* QP scaling factor for CU QP adjust if hvs_qp_scale_enable is 1 */ + u32 hvs_max_delta_qp; /* maximum delta QP for HVS */ + s32 chroma_cb_qp_offset; /* the value of chroma(cb) QP offset */ + s32 chroma_cr_qp_offset; /* the value of chroma(cr) QP offset */ + s32 initial_rc_qp; + u32 nr_intra_weight_y; + u32 nr_intra_weight_cb; /* weight to cb noise level for intra picture (0 ~ 31) */ + u32 nr_intra_weight_cr; /* weight to cr noise level for intra picture (0 ~ 31) */ + u32 nr_inter_weight_y; + u32 nr_inter_weight_cb; /* weight to cb noise level for inter picture (0 ~ 31) */ + u32 nr_inter_weight_cr; /* weight to cr noise level for inter picture (0 ~ 31) */ + u32 min_qp_i; /* minimum QP of I picture for rate control */ + u32 max_qp_i; /* maximum QP of I picture for rate control */ + u32 min_qp_p; /* minimum QP of P picture for rate control */ + u32 max_qp_p; /* maximum QP of P picture for rate control */ + u32 min_qp_b; /* minimum QP of B picture for rate control */ + u32 max_qp_b; /* maximum QP of B picture for rate control */ + u32 avc_idr_period; /* period of IDR picture (0 ~ 1024). 0 - implies an infinite period */ + u32 avc_slice_arg; /* the number of MB for a slice when avc_slice_mode is set with 1 */ + u32 intra_mb_refresh_mode: 2; /* 0=none, 1=row, 2=column, 3=step-size-in-mb */ + /** + * Argument for intra_mb_refresh_mode. + * + * intra_mb_refresh_mode (1) -> number of consecutive MB rows + * intra_mb_refresh_mode (2) ->the number of consecutive MB columns + * intra_mb_refresh_mode (3) -> step size in MB + */ + u32 intra_mb_refresh_arg; + u32 rc_weight_param; + u32 rc_weight_buf; + + /* flags */ + u32 en_still_picture: 1; /* still picture profile */ + u32 tier: 1; /* 0=main, 1=high */ + u32 avc_slice_mode: 1; /* 0=none, 1=slice-in-mb-number */ + u32 entropy_coding_mode: 1; /* 0=CAVLC, 1=CABAC */ + u32 lossless_enable: 1; /* enable lossless encoding */ + u32 const_intra_pred_flag: 1; /* enable constrained intra prediction */ + u32 tmvp_enable: 1; /* enable temporal motion vector prediction */ + u32 wpp_enable: 1; + u32 disable_deblk: 1; /* disable in-loop deblocking filtering */ + u32 lf_cross_slice_boundary_enable: 1; + u32 skip_intra_trans: 1; + u32 sao_enable: 1; /* enable SAO (sample adaptive offset) */ + u32 intra_nx_n_enable: 1; /* enables intra nx_n p_us */ + u32 cu_level_rc_enable: 1; /* enable CU level rate control */ + u32 hvs_qp_enable: 1; /* enable CU QP adjustment for subjective quality enhancement */ + u32 strong_intra_smooth_enable: 1; /* enable strong intra smoothing */ + u32 rdo_skip: 1; /* skip RDO (rate distortion optimization) */ + u32 lambda_scaling_enable: 1; /* enable lambda scaling using custom GOP */ + u32 transform8x8_enable: 1; /* enable 8x8 intra prediction and 8x8 transform */ + u32 mb_level_rc_enable: 1; /* enable MB-level rate control */ + u32 forced_idr_header_enable: 1; /* enable header encoding before IDR frame */ + u32 constraint_set1_flag: 1; /* enable CBP */ + u32 forced_idr_pictype_enable: 1; +}; + +struct enc_open_param { + dma_addr_t bitstream_buffer; + unsigned int bitstream_buffer_size; + u32 pic_width; /* width of a picture to be encoded in unit of sample */ + u32 pic_height; /* height of a picture to be encoded in unit of sample */ + u32 frame_rate_info;/* desired fps */ + u32 vbv_buffer_size; + u32 bit_rate; /* target bitrate in bps */ + struct enc_wave_param wave_param; + enum packed_format_num packed_format; /* <> */ + enum frame_buffer_format src_format; + bool line_buf_int_en; + u32 rc_enable : 1; /* rate control */ +}; + +struct enc_initial_info { + u32 min_frame_buffer_count; /* minimum number of frame buffers */ + u32 min_src_frame_count; /* minimum number of source buffers */ + u32 seq_init_err_reason; + u32 warn_info; + u32 vlc_buf_size; /* size of task buffer */ + u32 param_buf_size; /* size of task buffer */ +}; + +/* + * Flags to encode NAL units explicitly + */ +struct enc_code_opt { + u32 implicit_header_encode: 1; + u32 encode_vcl: 1; + u32 encode_vps: 1; + u32 encode_sps: 1; + u32 encode_pps: 1; + u32 encode_aud: 1; + u32 encode_eos: 1; + u32 encode_eob: 1; + u32 encode_vui: 1; +}; + +struct enc_param { + struct frame_buffer *source_frame; + dma_addr_t pic_stream_buffer_addr; + u64 pic_stream_buffer_size; + u32 src_idx; /* source frame buffer index */ + struct enc_code_opt code_option; + u64 pts; /* presentation timestamp (PTS) of the input source */ + bool src_end_flag; + s32 force_pictype_enable; /* A flag to use a force picture type (WAVE only) */ + s32 force_pic_type; /* A force picture type (I, P, B, IDR). It is valid when forcePicTypeEnable is 1. (WAVE only) */ +}; + +struct enc_output_info { + dma_addr_t bitstream_buffer; + u32 bitstream_size; /* byte size of encoded bitstream */ + u32 pic_type: 2; /* <> */ + s32 recon_frame_index; + dma_addr_t rd_ptr; + dma_addr_t wr_ptr; + u32 enc_pic_byte; /* number of encoded picture bytes */ + s32 enc_src_idx; /* source buffer index of the currently encoded picture */ + u32 enc_vcl_nut; + u32 error_reason; /* error reason of the currently encoded picture */ + u32 warn_info; /* warning information on the currently encoded picture */ + unsigned int frame_cycle; /* param for reporting the cycle number of encoding one frame*/ + u64 pts; + u32 enc_host_cmd_tick; /* tick of ENC_PIC command for the picture */ + u32 enc_encode_end_tick; /* end tick of encoding slices of the picture */ +}; + +enum enc_pic_code_option { + CODEOPT_ENC_HEADER_IMPLICIT = BIT(0), + CODEOPT_ENC_VCL = BIT(1), /* flag to encode VCL nal unit explicitly */ +}; + +enum gop_preset_idx { + PRESET_IDX_CUSTOM_GOP = 0, /* user defined GOP structure */ + PRESET_IDX_ALL_I = 1, /* all intra, gopsize = 1 */ + PRESET_IDX_IPP = 2, /* consecutive P, cyclic gopsize = 1 */ + PRESET_IDX_IBBB = 3, /* consecutive B, cyclic gopsize = 1 */ + PRESET_IDX_IBPBP = 4, /* gopsize = 2 */ + PRESET_IDX_IBBBP = 5, /* gopsize = 4 */ + PRESET_IDX_IPPPP = 6, /* consecutive P, cyclic gopsize = 4 */ + PRESET_IDX_IBBBB = 7, /* consecutive B, cyclic gopsize = 4 */ + PRESET_IDX_RA_IB = 8, /* random access, cyclic gopsize = 8 */ + PRESET_IDX_IPP_SINGLE = 9, /* consecutive P, cyclic gopsize = 1, with single ref */ +}; + +struct sec_axi_info { + u32 use_ip_enable; + u32 use_bit_enable; + u32 use_lf_row_enable: 1; + u32 use_enc_rdo_enable: 1; + u32 use_enc_lf_enable: 1; +}; + +struct dec_info { + struct dec_open_param open_param; + struct dec_initial_info initial_info; + struct dec_initial_info new_seq_info; /* temporal new sequence information */ + dma_addr_t stream_wr_ptr; + dma_addr_t stream_rd_ptr; + u32 frame_display_flag; + dma_addr_t stream_buf_start_addr; + dma_addr_t stream_buf_end_addr; + u32 stream_buf_size; + struct vpu_buf vb_mv[MAX_REG_FRAME]; + struct vpu_buf vb_fbc_y_tbl[MAX_REG_FRAME]; + struct vpu_buf vb_fbc_c_tbl[MAX_REG_FRAME]; + unsigned int num_of_decoding_fbs: 7; + unsigned int num_of_display_fbs: 7; + unsigned int stride; + struct sec_axi_info sec_axi_info; + dma_addr_t user_data_buf_addr; + u32 user_data_enable; + u32 user_data_buf_size; + struct vpu_buf vb_work; + struct vpu_buf vb_task; + struct dec_output_info dec_out_info[WAVE5_MAX_FBS]; + u32 seq_change_mask; + enum temporal_id_mode temp_id_select_mode; + u32 target_temp_id; + u32 target_spatial_id; + u32 instance_queue_count; + u32 report_queue_count; + u32 cycle_per_tick; + u32 product_code; + u32 vlc_buf_size; + u32 param_buf_size; + bool initial_info_obtained; + bool reorder_enable; + bool first_cycle_check; + u32 stream_endflag: 1; +}; + +struct enc_info { + struct enc_open_param open_param; + struct enc_initial_info initial_info; + dma_addr_t stream_rd_ptr; + dma_addr_t stream_wr_ptr; + dma_addr_t stream_buf_start_addr; + dma_addr_t stream_buf_end_addr; + u32 stream_buf_size; + unsigned int num_frame_buffers; + unsigned int stride; + bool rotation_enable; + bool mirror_enable; + enum mirror_direction mirror_direction; + unsigned int rotation_angle; + bool initial_info_obtained; + struct sec_axi_info sec_axi_info; + bool line_buf_int_en; + struct vpu_buf vb_work; + struct vpu_buf vb_mv; /* col_mv buffer */ + struct vpu_buf vb_fbc_y_tbl; /* FBC luma table buffer */ + struct vpu_buf vb_fbc_c_tbl; /* FBC chroma table buffer */ + struct vpu_buf vb_sub_sam_buf; /* sub-sampled buffer for ME */ + struct vpu_buf vb_task; + u64 cur_pts; /* current timestamp in 90_k_hz */ + u64 pts_map[32]; /* PTS mapped with source frame index */ + u32 instance_queue_count; + u32 report_queue_count; + bool first_cycle_check; + u32 cycle_per_tick; + u32 product_code; + u32 vlc_buf_size; + u32 param_buf_size; +}; + +struct vpu_device { + struct device *dev; + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *v4l2_m2m_dec_dev; + struct v4l2_m2m_dev *v4l2_m2m_enc_dev; + struct list_head instances; + struct video_device *video_dev_dec; + struct video_device *video_dev_enc; + struct mutex dev_lock; /* lock for the src, dst v4l2 queues */ + struct mutex hw_lock; /* lock hw configurations */ + int irq; + enum product_id product; + struct vpu_attr attr; + struct vpu_buf common_mem; + u32 last_performance_cycles; + u32 sram_size; + struct gen_pool *sram_pool; + struct vpu_buf sram_buf; + void __iomem *vdb_register; + u32 product_code; + u32 ext_addr; + struct ida inst_ida; + struct clk_bulk_data *clks; + struct hrtimer hrtimer; + struct kthread_work work; + struct kthread_worker *worker; + int vpu_poll_interval; + int num_clks; +}; + +struct vpu_instance; + +struct vpu_instance_ops { + void (*finish_process)(struct vpu_instance *inst); +}; + +struct vpu_instance { + struct list_head list; + struct v4l2_fh v4l2_fh; + struct v4l2_m2m_dev *v4l2_m2m_dev; + struct v4l2_ctrl_handler v4l2_ctrl_hdl; + struct vpu_device *dev; + struct completion irq_done; + + struct v4l2_pix_format_mplane src_fmt; + struct v4l2_pix_format_mplane dst_fmt; + enum v4l2_colorspace colorspace; + enum v4l2_xfer_func xfer_func; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_quantization quantization; + + enum vpu_instance_state state; + enum vpu_instance_type type; + const struct vpu_instance_ops *ops; + spinlock_t state_spinlock; /* This protects the instance state */ + + enum wave_std std; + s32 id; + union { + struct enc_info enc_info; + struct dec_info dec_info; + } *codec_info; + struct frame_buffer frame_buf[MAX_REG_FRAME]; + struct vpu_buf frame_vbuf[MAX_REG_FRAME]; + u32 fbc_buf_count; + u32 queued_src_buf_num; + u32 queued_dst_buf_num; + struct list_head avail_src_bufs; + struct list_head avail_dst_bufs; + struct v4l2_rect conf_win; + u64 timestamp; + enum frame_buffer_format output_format; + bool cbcr_interleave; + bool nv21; + bool eos; + struct vpu_buf bitstream_vbuf; + dma_addr_t last_rd_ptr; + size_t remaining_consumed_bytes; + bool needs_reallocation; + + unsigned int min_src_buf_count; + unsigned int rot_angle; + unsigned int mirror_direction; + unsigned int bit_depth; + unsigned int frame_rate; + unsigned int vbv_buf_size; + unsigned int rc_mode; + unsigned int rc_enable; + unsigned int bit_rate; + unsigned int encode_aud; + unsigned int change_param_flags; + struct enc_wave_param enc_param; +}; + +void wave5_vdi_write_register(struct vpu_device *vpu_dev, u32 addr, u32 data); +u32 wave5_vdi_read_register(struct vpu_device *vpu_dev, u32 addr); +int wave5_vdi_clear_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb); +int wave5_vdi_allocate_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb); +int wave5_vdi_allocate_array(struct vpu_device *vpu_dev, struct vpu_buf *array, unsigned int count, + size_t size); +int wave5_vdi_write_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb, size_t offset, + u8 *data, size_t len); +int wave5_vdi_free_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb); +void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev); +void wave5_vdi_free_sram(struct vpu_device *vpu_dev); + +int wave5_vpu_init_with_bitcode(struct device *dev, u8 *bitcode, size_t size); +int wave5_vpu_flush_instance(struct vpu_instance *inst); +int wave5_vpu_get_version_info(struct device *dev, u32 *revision, unsigned int *product_id); +int wave5_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param *open_param); +int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res); +int wave5_vpu_dec_issue_seq_init(struct vpu_instance *inst); +int wave5_vpu_dec_complete_seq_init(struct vpu_instance *inst, struct dec_initial_info *info); +int wave5_vpu_dec_register_frame_buffer_ex(struct vpu_instance *inst, int num_of_decoding_fbs, + int num_of_display_fbs, int stride, int height); +int wave5_vpu_dec_start_one_frame(struct vpu_instance *inst, u32 *res_fail); +int wave5_vpu_dec_get_output_info(struct vpu_instance *inst, struct dec_output_info *info); +int wave5_vpu_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr, int update_wr_ptr); +dma_addr_t wave5_vpu_dec_get_rd_ptr(struct vpu_instance *inst); +int wave5_vpu_dec_reset_framebuffer(struct vpu_instance *inst, unsigned int index); +int wave5_vpu_dec_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter); +int wave5_vpu_enc_change_param(struct vpu_instance *inst, u32 *fail_res); +int wave5_vpu_dec_get_bitstream_buffer(struct vpu_instance *inst, dma_addr_t *prd_ptr, + dma_addr_t *pwr_ptr, size_t *size); +int wave5_vpu_dec_update_bitstream_buffer(struct vpu_instance *inst, size_t size); +int wave5_vpu_dec_clr_disp_flag(struct vpu_instance *inst, int index); +int wave5_vpu_dec_set_disp_flag(struct vpu_instance *inst, int index); + +int wave5_vpu_enc_open(struct vpu_instance *inst, struct enc_open_param *open_param); +int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res); +int wave5_vpu_enc_issue_seq_init(struct vpu_instance *inst); +int wave5_vpu_enc_complete_seq_init(struct vpu_instance *inst, struct enc_initial_info *info); +int wave5_vpu_enc_register_frame_buffer(struct vpu_instance *inst, unsigned int num, + unsigned int stride, int height, + enum tiled_map_type map_type); +int wave5_vpu_enc_start_one_frame(struct vpu_instance *inst, struct enc_param *param, + u32 *fail_res); +int wave5_vpu_enc_get_output_info(struct vpu_instance *inst, struct enc_output_info *info); +int wave5_vpu_enc_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter); + +#endif diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c --- a/drivers/media/platform/chips-media/wave5/wave5-vpu.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - platform driver + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ +#include +#include +#include +#include +#include +#include +#include +#include "wave5-vpu.h" +#include "wave5-regdefine.h" +#include "wave5-vpuconfig.h" +#include "wave5.h" + +#define VPU_PLATFORM_DEVICE_NAME "vdec" +#define VPU_CLK_NAME "vcodec" + +#define WAVE5_IS_ENC BIT(0) +#define WAVE5_IS_DEC BIT(1) + +struct wave5_match_data { + int flags; + const char *fw_name; +}; + +static int vpu_poll_interval = 5; +module_param(vpu_poll_interval, int, 0644); + +int wave5_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout) +{ + int ret; + + ret = wait_for_completion_timeout(&inst->irq_done, + msecs_to_jiffies(timeout)); + if (!ret) + return -ETIMEDOUT; + + reinit_completion(&inst->irq_done); + + return 0; +} + +static void wave5_vpu_handle_irq(void *dev_id) +{ + u32 seq_done; + u32 cmd_done; + u32 irq_reason; + struct vpu_instance *inst; + struct vpu_device *dev = dev_id; + + irq_reason = wave5_vdi_read_register(dev, W5_VPU_VINT_REASON); + seq_done = wave5_vdi_read_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO); + cmd_done = wave5_vdi_read_register(dev, W5_RET_QUEUE_CMD_DONE_INST); + + wave5_vdi_write_register(dev, W5_VPU_VINT_REASON_CLR, irq_reason); + wave5_vdi_write_register(dev, W5_VPU_VINT_CLEAR, 0x1); + + list_for_each_entry(inst, &dev->instances, list) { + + if (irq_reason & BIT(INT_WAVE5_INIT_SEQ) || + irq_reason & BIT(INT_WAVE5_ENC_SET_PARAM)) { + if (seq_done & BIT(inst->id)) { + seq_done &= ~BIT(inst->id); + wave5_vdi_write_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO, + seq_done); + complete(&inst->irq_done); + } + } + + if (irq_reason & BIT(INT_WAVE5_DEC_PIC) || + irq_reason & BIT(INT_WAVE5_ENC_PIC)) { + if (cmd_done & BIT(inst->id)) { + cmd_done &= ~BIT(inst->id); + wave5_vdi_write_register(dev, W5_RET_QUEUE_CMD_DONE_INST, + cmd_done); + inst->ops->finish_process(inst); + } + } + + wave5_vpu_clear_interrupt(inst, irq_reason); + } +} + +static irqreturn_t wave5_vpu_irq_thread(int irq, void *dev_id) +{ + struct vpu_device *dev = dev_id; + + if (wave5_vdi_read_register(dev, W5_VPU_VPU_INT_STS)) + wave5_vpu_handle_irq(dev); + + return IRQ_HANDLED; +} + +static void wave5_vpu_irq_work_fn(struct kthread_work *work) +{ + struct vpu_device *dev = container_of(work, struct vpu_device, work); + + if (wave5_vdi_read_register(dev, W5_VPU_VPU_INT_STS)) + wave5_vpu_handle_irq(dev); +} + +static enum hrtimer_restart wave5_vpu_timer_callback(struct hrtimer *timer) +{ + struct vpu_device *dev = + container_of(timer, struct vpu_device, hrtimer); + + kthread_queue_work(dev->worker, &dev->work); + hrtimer_forward_now(timer, ns_to_ktime(vpu_poll_interval * NSEC_PER_MSEC)); + + return HRTIMER_RESTART; +} + +static int wave5_vpu_load_firmware(struct device *dev, const char *fw_name, + u32 *revision) +{ + const struct firmware *fw; + int ret; + unsigned int product_id; + + ret = request_firmware(&fw, fw_name, dev); + if (ret) { + dev_err(dev, "request_firmware, fail: %d\n", ret); + return ret; + } + + ret = wave5_vpu_init_with_bitcode(dev, (u8 *)fw->data, fw->size); + if (ret) { + dev_err(dev, "vpu_init_with_bitcode, fail: %d\n", ret); + release_firmware(fw); + return ret; + } + release_firmware(fw); + + ret = wave5_vpu_get_version_info(dev, revision, &product_id); + if (ret) { + dev_err(dev, "vpu_get_version_info fail: %d\n", ret); + return ret; + } + + dev_dbg(dev, "%s: enum product_id: %08x, fw revision: %u\n", + __func__, product_id, *revision); + + return 0; +} + +static int wave5_pm_suspend(struct device *dev) +{ + struct vpu_device *vpu = dev_get_drvdata(dev); + + if (pm_runtime_suspended(dev)) + return 0; + + if (vpu->irq < 0) + hrtimer_cancel(&vpu->hrtimer); + + wave5_vpu_sleep_wake(dev, true, NULL, 0); + clk_bulk_disable_unprepare(vpu->num_clks, vpu->clks); + + return 0; +} + +static int wave5_pm_resume(struct device *dev) +{ + struct vpu_device *vpu = dev_get_drvdata(dev); + int ret = 0; + + wave5_vpu_sleep_wake(dev, false, NULL, 0); + ret = clk_bulk_prepare_enable(vpu->num_clks, vpu->clks); + if (ret) { + dev_err(dev, "Enabling clocks, fail: %d\n", ret); + return ret; + } + + if (vpu->irq < 0 && !hrtimer_active(&vpu->hrtimer)) + hrtimer_start(&vpu->hrtimer, ns_to_ktime(vpu->vpu_poll_interval * NSEC_PER_MSEC), + HRTIMER_MODE_REL_PINNED); + + return ret; +} + +static const struct dev_pm_ops wave5_pm_ops = { + SET_RUNTIME_PM_OPS(wave5_pm_suspend, wave5_pm_resume, NULL) +}; + +static int wave5_vpu_probe(struct platform_device *pdev) +{ + int ret; + struct vpu_device *dev; + const struct wave5_match_data *match_data; + u32 fw_revision; + + match_data = device_get_match_data(&pdev->dev); + if (!match_data) { + dev_err(&pdev->dev, "missing device match data\n"); + return -EINVAL; + } + + /* physical addresses limited to 48 bits */ + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); + if (ret) { + dev_err(&pdev->dev, "Failed to set DMA mask: %d\n", ret); + return ret; + } + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->vdb_register = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dev->vdb_register)) + return PTR_ERR(dev->vdb_register); + ida_init(&dev->inst_ida); + + mutex_init(&dev->dev_lock); + mutex_init(&dev->hw_lock); + dev_set_drvdata(&pdev->dev, dev); + dev->dev = &pdev->dev; + + ret = devm_clk_bulk_get_all(&pdev->dev, &dev->clks); + + /* continue without clock, assume externally managed */ + if (ret < 0) { + dev_warn(&pdev->dev, "Getting clocks, fail: %d\n", ret); + ret = 0; + } + dev->num_clks = ret; + + ret = clk_bulk_prepare_enable(dev->num_clks, dev->clks); + if (ret) { + dev_err(&pdev->dev, "Enabling clocks, fail: %d\n", ret); + return ret; + } + + ret = of_property_read_u32(pdev->dev.of_node, "sram-size", + &dev->sram_size); + if (ret) { + dev_warn(&pdev->dev, "sram-size not found\n"); + dev->sram_size = 0; + } + + dev->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0); + if (!dev->sram_pool) + dev_warn(&pdev->dev, "sram node not found\n"); + + dev->product_code = wave5_vdi_read_register(dev, VPU_PRODUCT_CODE_REGISTER); + ret = wave5_vdi_init(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "wave5_vdi_init, fail: %d\n", ret); + goto err_clk_dis; + } + dev->product = wave5_vpu_get_product_id(dev); + dev->ext_addr = ((dev->common_mem.daddr >> 32) & 0xFFFF); + + dev->irq = platform_get_irq(pdev, 0); + if (dev->irq < 0) { + dev_err(&pdev->dev, "failed to get irq resource, falling back to polling\n"); + hrtimer_init(&dev->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); + dev->hrtimer.function = &wave5_vpu_timer_callback; + dev->worker = kthread_create_worker(0, "vpu_irq_thread"); + if (IS_ERR(dev->worker)) { + dev_err(&pdev->dev, "failed to create vpu irq worker\n"); + ret = PTR_ERR(dev->worker); + goto err_vdi_release; + } + dev->vpu_poll_interval = vpu_poll_interval; + kthread_init_work(&dev->work, wave5_vpu_irq_work_fn); + } else { + ret = devm_request_threaded_irq(&pdev->dev, dev->irq, NULL, + wave5_vpu_irq_thread, IRQF_ONESHOT, "vpu_irq", dev); + if (ret) { + dev_err(&pdev->dev, "Register interrupt handler, fail: %d\n", ret); + goto err_enc_unreg; + } + } + + INIT_LIST_HEAD(&dev->instances); + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) { + dev_err(&pdev->dev, "v4l2_device_register, fail: %d\n", ret); + goto err_vdi_release; + } + + if (match_data->flags & WAVE5_IS_DEC) { + ret = wave5_vpu_dec_register_device(dev); + if (ret) { + dev_err(&pdev->dev, "wave5_vpu_dec_register_device, fail: %d\n", ret); + goto err_v4l2_unregister; + } + } + if (match_data->flags & WAVE5_IS_ENC) { + ret = wave5_vpu_enc_register_device(dev); + if (ret) { + dev_err(&pdev->dev, "wave5_vpu_enc_register_device, fail: %d\n", ret); + goto err_dec_unreg; + } + } + + ret = wave5_vpu_load_firmware(&pdev->dev, match_data->fw_name, &fw_revision); + if (ret) { + dev_err(&pdev->dev, "wave5_vpu_load_firmware, fail: %d\n", ret); + goto err_enc_unreg; + } + + dev_info(&pdev->dev, "Added wave5 driver with caps: %s %s\n", + (match_data->flags & WAVE5_IS_ENC) ? "'ENCODE'" : "", + (match_data->flags & WAVE5_IS_DEC) ? "'DECODE'" : ""); + dev_info(&pdev->dev, "Product Code: 0x%x\n", dev->product_code); + dev_info(&pdev->dev, "Firmware Revision: %u\n", fw_revision); + + pm_runtime_set_autosuspend_delay(&pdev->dev, 5000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + wave5_vpu_sleep_wake(&pdev->dev, true, NULL, 0); + + return 0; + +err_enc_unreg: + if (match_data->flags & WAVE5_IS_ENC) + wave5_vpu_enc_unregister_device(dev); +err_dec_unreg: + if (match_data->flags & WAVE5_IS_DEC) + wave5_vpu_dec_unregister_device(dev); +err_v4l2_unregister: + v4l2_device_unregister(&dev->v4l2_dev); +err_vdi_release: + wave5_vdi_release(&pdev->dev); +err_clk_dis: + clk_bulk_disable_unprepare(dev->num_clks, dev->clks); + + return ret; +} + +static void wave5_vpu_remove(struct platform_device *pdev) +{ + struct vpu_device *dev = dev_get_drvdata(&pdev->dev); + + if (dev->irq < 0) { + kthread_destroy_worker(dev->worker); + hrtimer_cancel(&dev->hrtimer); + } + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + mutex_destroy(&dev->dev_lock); + mutex_destroy(&dev->hw_lock); + clk_bulk_disable_unprepare(dev->num_clks, dev->clks); + wave5_vpu_enc_unregister_device(dev); + wave5_vpu_dec_unregister_device(dev); + v4l2_device_unregister(&dev->v4l2_dev); + wave5_vdi_release(&pdev->dev); + ida_destroy(&dev->inst_ida); +} + +static const struct wave5_match_data ti_wave521c_data = { + .flags = WAVE5_IS_ENC | WAVE5_IS_DEC, + .fw_name = "cnm/wave521c_k3_codec_fw.bin", +}; + +static const struct of_device_id wave5_dt_ids[] = { + { .compatible = "ti,j721s2-wave521c", .data = &ti_wave521c_data }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, wave5_dt_ids); + +static struct platform_driver wave5_vpu_driver = { + .driver = { + .name = VPU_PLATFORM_DEVICE_NAME, + .of_match_table = of_match_ptr(wave5_dt_ids), + .pm = &wave5_pm_ops, + }, + .probe = wave5_vpu_probe, + .remove_new = wave5_vpu_remove, +}; + +module_platform_driver(wave5_vpu_driver); +MODULE_DESCRIPTION("chips&media VPU V4L2 driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h --- a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - product config definitions + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef _VPU_CONFIG_H_ +#define _VPU_CONFIG_H_ + +#define WAVE517_CODE 0x5170 +#define WAVE537_CODE 0x5370 +#define WAVE511_CODE 0x5110 +#define WAVE521_CODE 0x5210 +#define WAVE521C_CODE 0x521c +#define WAVE521C_DUAL_CODE 0x521d // wave521 dual core +#define WAVE521E1_CODE 0x5211 + +#define PRODUCT_CODE_W_SERIES(x) ({ \ + int c = x; \ + ((c) == WAVE517_CODE || (c) == WAVE537_CODE || \ + (c) == WAVE511_CODE || (c) == WAVE521_CODE || \ + (c) == WAVE521E1_CODE || (c) == WAVE521C_CODE || \ + (c) == WAVE521C_DUAL_CODE); \ +}) + +#define WAVE517_WORKBUF_SIZE (2 * 1024 * 1024) +#define WAVE521ENC_WORKBUF_SIZE (128 * 1024) //HEVC 128K, AVC 40K +#define WAVE521DEC_WORKBUF_SIZE (1784 * 1024) + +#define MAX_NUM_INSTANCE 32 + +#define W5_DEF_DEC_PIC_WIDTH 720U +#define W5_DEF_DEC_PIC_HEIGHT 480U +#define W5_MIN_DEC_PIC_8_WIDTH 8U +#define W5_MIN_DEC_PIC_8_HEIGHT 8U +#define W5_MIN_DEC_PIC_32_WIDTH 32U +#define W5_MIN_DEC_PIC_32_HEIGHT 32U +#define W5_MAX_DEC_PIC_WIDTH 8192U +#define W5_MAX_DEC_PIC_HEIGHT 4320U +#define W5_DEC_CODEC_STEP_WIDTH 1U +#define W5_DEC_CODEC_STEP_HEIGHT 1U +#define W5_DEC_RAW_STEP_WIDTH 32U +#define W5_DEC_RAW_STEP_HEIGHT 16U + +#define W5_DEF_ENC_PIC_WIDTH 416U +#define W5_DEF_ENC_PIC_HEIGHT 240U +#define W5_MIN_ENC_PIC_WIDTH 256U +#define W5_MIN_ENC_PIC_HEIGHT 128U +#define W5_MAX_ENC_PIC_WIDTH 8192U +#define W5_MAX_ENC_PIC_HEIGHT 8192U +#define W5_ENC_CODEC_STEP_WIDTH 8U +#define W5_ENC_CODEC_STEP_HEIGHT 8U +#define W5_ENC_RAW_STEP_WIDTH 32U +#define W5_ENC_RAW_STEP_HEIGHT 16U + +// application specific configuration +#define VPU_ENC_TIMEOUT 60000 +#define VPU_DEC_TIMEOUT 60000 + +// for WAVE encoder +#define USE_SRC_PRP_AXI 0 +#define USE_SRC_PRI_AXI 1 +#define DEFAULT_SRC_AXI USE_SRC_PRP_AXI + +/************************************************************************/ +/* VPU COMMON MEMORY */ +/************************************************************************/ +#define VLC_BUF_NUM (2) + +#define COMMAND_QUEUE_DEPTH (2) + +#define W5_REMAP_INDEX0 0 +#define W5_REMAP_INDEX1 1 +#define W5_REMAP_MAX_SIZE (1024 * 1024) + +#define WAVE5_MAX_CODE_BUF_SIZE (2 * 1024 * 1024) +#define WAVE5_TEMPBUF_OFFSET WAVE5_MAX_CODE_BUF_SIZE +#define WAVE5_TEMPBUF_SIZE (1024 * 1024) + +#define SIZE_COMMON (WAVE5_MAX_CODE_BUF_SIZE + WAVE5_TEMPBUF_SIZE) + +//=====4. VPU REPORT MEMORY ======================// + +#define WAVE5_UPPER_PROC_AXI_ID 0x0 + +#define WAVE5_PROC_AXI_ID 0x0 +#define WAVE5_PRP_AXI_ID 0x0 +#define WAVE5_FBD_Y_AXI_ID 0x0 +#define WAVE5_FBC_Y_AXI_ID 0x0 +#define WAVE5_FBD_C_AXI_ID 0x0 +#define WAVE5_FBC_C_AXI_ID 0x0 +#define WAVE5_SEC_AXI_ID 0x0 +#define WAVE5_PRI_AXI_ID 0x0 + +#endif /* _VPU_CONFIG_H_ */ diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c 2024-07-07 20:37:34.648306569 -0400 @@ -0,0 +1,1889 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - decoder interface + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#include +#include "wave5-helper.h" + +#define VPU_DEC_DEV_NAME "C&M Wave5 VPU decoder" +#define VPU_DEC_DRV_NAME "wave5-dec" + +static const struct v4l2_frmsize_stepwise dec_hevc_frmsize = { + .min_width = W5_MIN_DEC_PIC_8_WIDTH, + .max_width = W5_MAX_DEC_PIC_WIDTH, + .step_width = W5_DEC_CODEC_STEP_WIDTH, + .min_height = W5_MIN_DEC_PIC_8_HEIGHT, + .max_height = W5_MAX_DEC_PIC_HEIGHT, + .step_height = W5_DEC_CODEC_STEP_HEIGHT, +}; + +static const struct v4l2_frmsize_stepwise dec_h264_frmsize = { + .min_width = W5_MIN_DEC_PIC_32_WIDTH, + .max_width = W5_MAX_DEC_PIC_WIDTH, + .step_width = W5_DEC_CODEC_STEP_WIDTH, + .min_height = W5_MIN_DEC_PIC_32_HEIGHT, + .max_height = W5_MAX_DEC_PIC_HEIGHT, + .step_height = W5_DEC_CODEC_STEP_HEIGHT, +}; + +static const struct v4l2_frmsize_stepwise dec_raw_frmsize = { + .min_width = W5_MIN_DEC_PIC_8_WIDTH, + .max_width = W5_MAX_DEC_PIC_WIDTH, + .step_width = W5_DEC_RAW_STEP_WIDTH, + .min_height = W5_MIN_DEC_PIC_8_HEIGHT, + .max_height = W5_MAX_DEC_PIC_HEIGHT, + .step_height = W5_DEC_RAW_STEP_HEIGHT, +}; + +static const struct vpu_format dec_fmt_list[FMT_TYPES][MAX_FMTS] = { + [VPU_FMT_TYPE_CODEC] = { + { + .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC, + .v4l2_frmsize = &dec_hevc_frmsize, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_H264, + .v4l2_frmsize = &dec_h264_frmsize, + }, + }, + [VPU_FMT_TYPE_RAW] = { + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420, + .v4l2_frmsize = &dec_raw_frmsize, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12, + .v4l2_frmsize = &dec_raw_frmsize, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21, + .v4l2_frmsize = &dec_raw_frmsize, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P, + .v4l2_frmsize = &dec_raw_frmsize, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16, + .v4l2_frmsize = &dec_raw_frmsize, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61, + .v4l2_frmsize = &dec_raw_frmsize, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M, + .v4l2_frmsize = &dec_raw_frmsize, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M, + .v4l2_frmsize = &dec_raw_frmsize, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M, + .v4l2_frmsize = &dec_raw_frmsize, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M, + .v4l2_frmsize = &dec_raw_frmsize, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M, + .v4l2_frmsize = &dec_raw_frmsize, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M, + .v4l2_frmsize = &dec_raw_frmsize, + }, + } +}; + +static int initialize_sequence(struct vpu_instance *inst); +static bool wave5_is_draining_or_eos(struct vpu_instance *inst); + +/* + * Make sure that the state switch is allowed and add logging for debugging + * purposes + */ +static int switch_state(struct vpu_instance *inst, enum vpu_instance_state state) +{ + switch (state) { + case VPU_INST_STATE_NONE: + break; + case VPU_INST_STATE_OPEN: + if (inst->state != VPU_INST_STATE_NONE) + goto invalid_state_switch; + goto valid_state_switch; + case VPU_INST_STATE_INIT_SEQ: + if (inst->state != VPU_INST_STATE_OPEN && inst->state != VPU_INST_STATE_STOP) + goto invalid_state_switch; + goto valid_state_switch; + case VPU_INST_STATE_PIC_RUN: + if (inst->state != VPU_INST_STATE_INIT_SEQ) + goto invalid_state_switch; + goto valid_state_switch; + case VPU_INST_STATE_STOP: + goto valid_state_switch; + } +invalid_state_switch: + WARN(1, "Invalid state switch from %s to %s.\n", + state_to_str(inst->state), state_to_str(state)); + return -EINVAL; +valid_state_switch: + dev_dbg(inst->dev->dev, "Switch state from %s to %s.\n", + state_to_str(inst->state), state_to_str(state)); + inst->state = state; + return 0; +} + +static int wave5_vpu_dec_set_eos_on_firmware(struct vpu_instance *inst) +{ + int ret; + + ret = wave5_vpu_dec_update_bitstream_buffer(inst, 0); + if (ret) { + /* + * To set the EOS flag, a command is sent to the firmware. + * That command may never return (timeout) or may report an error. + */ + dev_err(inst->dev->dev, + "Setting EOS for the bitstream, fail: %d\n", ret); + return ret; + } + return 0; +} + +static bool wave5_last_src_buffer_consumed(struct v4l2_m2m_ctx *m2m_ctx) +{ + struct vpu_src_buffer *vpu_buf; + + if (!m2m_ctx->last_src_buf) + return false; + + vpu_buf = wave5_to_vpu_src_buf(m2m_ctx->last_src_buf); + return vpu_buf->consumed; +} + +static void wave5_handle_src_buffer(struct vpu_instance *inst, dma_addr_t rd_ptr) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct v4l2_m2m_buffer *buf, *n; + size_t consumed_bytes = 0; + + if (rd_ptr >= inst->last_rd_ptr) { + consumed_bytes = rd_ptr - inst->last_rd_ptr; + } else { + size_t rd_offs = rd_ptr - inst->bitstream_vbuf.daddr; + size_t last_rd_offs = inst->last_rd_ptr - inst->bitstream_vbuf.daddr; + + consumed_bytes = rd_offs + (inst->bitstream_vbuf.size - last_rd_offs); + } + + inst->last_rd_ptr = rd_ptr; + consumed_bytes += inst->remaining_consumed_bytes; + + dev_dbg(inst->dev->dev, "%s: %zu bytes of bitstream was consumed", __func__, + consumed_bytes); + + v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) { + struct vb2_v4l2_buffer *src_buf = &buf->vb; + size_t src_size = vb2_get_plane_payload(&src_buf->vb2_buf, 0); + + if (src_size > consumed_bytes) + break; + + dev_dbg(inst->dev->dev, "%s: removing src buffer %i", + __func__, src_buf->vb2_buf.index); + src_buf = v4l2_m2m_src_buf_remove(m2m_ctx); + inst->timestamp = src_buf->vb2_buf.timestamp; + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + consumed_bytes -= src_size; + + /* Handle the case the last bitstream buffer has been picked */ + if (src_buf == m2m_ctx->last_src_buf) { + int ret; + + m2m_ctx->last_src_buf = NULL; + ret = wave5_vpu_dec_set_eos_on_firmware(inst); + if (ret) + dev_warn(inst->dev->dev, + "Setting EOS for the bitstream, fail: %d\n", ret); + break; + } + } + + inst->remaining_consumed_bytes = consumed_bytes; +} + +static int start_decode(struct vpu_instance *inst, u32 *fail_res) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret = 0; + + ret = wave5_vpu_dec_start_one_frame(inst, fail_res); + if (ret) { + struct vb2_v4l2_buffer *src_buf; + + src_buf = v4l2_m2m_src_buf_remove(m2m_ctx); + if (src_buf) + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + switch_state(inst, VPU_INST_STATE_STOP); + + dev_dbg(inst->dev->dev, "%s: pic run failed / finish job", __func__); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + } + + return ret; +} + +static void flag_last_buffer_done(struct vpu_instance *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_v4l2_buffer *vb; + int i; + + lockdep_assert_held(&inst->state_spinlock); + + vb = v4l2_m2m_dst_buf_remove(m2m_ctx); + if (!vb) { + m2m_ctx->is_draining = true; + m2m_ctx->next_buf_last = true; + return; + } + + for (i = 0; i < vb->vb2_buf.num_planes; i++) + vb2_set_plane_payload(&vb->vb2_buf, i, 0); + vb->field = V4L2_FIELD_NONE; + + v4l2_m2m_last_buffer_done(m2m_ctx, vb); +} + +static void send_eos_event(struct vpu_instance *inst) +{ + static const struct v4l2_event vpu_event_eos = { + .type = V4L2_EVENT_EOS + }; + + lockdep_assert_held(&inst->state_spinlock); + + v4l2_event_queue_fh(&inst->v4l2_fh, &vpu_event_eos); + inst->eos = false; +} + +static int handle_dynamic_resolution_change(struct vpu_instance *inst) +{ + struct v4l2_fh *fh = &inst->v4l2_fh; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + static const struct v4l2_event vpu_event_src_ch = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + struct dec_initial_info *initial_info = &inst->codec_info->dec_info.initial_info; + + lockdep_assert_held(&inst->state_spinlock); + + dev_dbg(inst->dev->dev, "%s: rd_ptr %pad", __func__, &initial_info->rd_ptr); + + dev_dbg(inst->dev->dev, "%s: width: %u height: %u profile: %u | minbuffer: %u\n", + __func__, initial_info->pic_width, initial_info->pic_height, + initial_info->profile, initial_info->min_frame_buffer_count); + + inst->needs_reallocation = true; + inst->fbc_buf_count = initial_info->min_frame_buffer_count + 1; + if (inst->fbc_buf_count != v4l2_m2m_num_dst_bufs_ready(m2m_ctx)) { + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, inst->fbc_buf_count); + } + + if (p_dec_info->initial_info_obtained) { + const struct vpu_format *vpu_fmt; + + inst->conf_win.left = initial_info->pic_crop_rect.left; + inst->conf_win.top = initial_info->pic_crop_rect.top; + inst->conf_win.width = initial_info->pic_width - + initial_info->pic_crop_rect.left - initial_info->pic_crop_rect.right; + inst->conf_win.height = initial_info->pic_height - + initial_info->pic_crop_rect.top - initial_info->pic_crop_rect.bottom; + + vpu_fmt = wave5_find_vpu_fmt(inst->src_fmt.pixelformat, + dec_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) + return -EINVAL; + + wave5_update_pix_fmt(&inst->src_fmt, + VPU_FMT_TYPE_CODEC, + initial_info->pic_width, + initial_info->pic_height, + vpu_fmt->v4l2_frmsize); + + vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, + dec_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + + wave5_update_pix_fmt(&inst->dst_fmt, + VPU_FMT_TYPE_RAW, + initial_info->pic_width, + initial_info->pic_height, + vpu_fmt->v4l2_frmsize); + } + + v4l2_event_queue_fh(fh, &vpu_event_src_ch); + + return 0; +} + +static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct dec_output_info dec_info; + int ret; + struct vb2_v4l2_buffer *dec_buf = NULL; + struct vb2_v4l2_buffer *disp_buf = NULL; + struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx); + struct queue_status_info q_status; + + dev_dbg(inst->dev->dev, "%s: Fetch output info from firmware.", __func__); + + ret = wave5_vpu_dec_get_output_info(inst, &dec_info); + if (ret) { + dev_warn(inst->dev->dev, "%s: could not get output info.", __func__); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + return; + } + + dev_dbg(inst->dev->dev, "%s: rd_ptr %pad wr_ptr %pad", __func__, &dec_info.rd_ptr, + &dec_info.wr_ptr); + wave5_handle_src_buffer(inst, dec_info.rd_ptr); + + dev_dbg(inst->dev->dev, "%s: dec_info dec_idx %i disp_idx %i", __func__, + dec_info.index_frame_decoded, dec_info.index_frame_display); + + if (!vb2_is_streaming(dst_vq)) { + dev_dbg(inst->dev->dev, "%s: capture is not streaming..", __func__); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + return; + } + + /* Remove decoded buffer from the ready queue now that it has been + * decoded. + */ + if (dec_info.index_frame_decoded >= 0) { + struct vb2_buffer *vb = vb2_get_buffer(dst_vq, + dec_info.index_frame_decoded); + if (vb) { + dec_buf = to_vb2_v4l2_buffer(vb); + dec_buf->vb2_buf.timestamp = inst->timestamp; + } else { + dev_warn(inst->dev->dev, "%s: invalid decoded frame index %i", + __func__, dec_info.index_frame_decoded); + } + } + + if (dec_info.index_frame_display >= 0) { + disp_buf = v4l2_m2m_dst_buf_remove_by_idx(m2m_ctx, dec_info.index_frame_display); + if (!disp_buf) + dev_warn(inst->dev->dev, "%s: invalid display frame index %i", + __func__, dec_info.index_frame_display); + } + + /* If there is anything to display, do that now */ + if (disp_buf) { + struct vpu_dst_buffer *dst_vpu_buf = wave5_to_vpu_dst_buf(disp_buf); + + if (inst->dst_fmt.num_planes == 1) { + vb2_set_plane_payload(&disp_buf->vb2_buf, 0, + inst->dst_fmt.plane_fmt[0].sizeimage); + } else if (inst->dst_fmt.num_planes == 2) { + vb2_set_plane_payload(&disp_buf->vb2_buf, 0, + inst->dst_fmt.plane_fmt[0].sizeimage); + vb2_set_plane_payload(&disp_buf->vb2_buf, 1, + inst->dst_fmt.plane_fmt[1].sizeimage); + } else if (inst->dst_fmt.num_planes == 3) { + vb2_set_plane_payload(&disp_buf->vb2_buf, 0, + inst->dst_fmt.plane_fmt[0].sizeimage); + vb2_set_plane_payload(&disp_buf->vb2_buf, 1, + inst->dst_fmt.plane_fmt[1].sizeimage); + vb2_set_plane_payload(&disp_buf->vb2_buf, 2, + inst->dst_fmt.plane_fmt[2].sizeimage); + } + + /* TODO implement interlace support */ + disp_buf->field = V4L2_FIELD_NONE; + dst_vpu_buf->display = true; + v4l2_m2m_buf_done(disp_buf, VB2_BUF_STATE_DONE); + + dev_dbg(inst->dev->dev, "%s: frame_cycle %8u (payload %lu)\n", + __func__, dec_info.frame_cycle, + vb2_get_plane_payload(&disp_buf->vb2_buf, 0)); + } + + if ((dec_info.index_frame_display == DISPLAY_IDX_FLAG_SEQ_END || + dec_info.sequence_changed)) { + unsigned long flags; + + spin_lock_irqsave(&inst->state_spinlock, flags); + if (!v4l2_m2m_has_stopped(m2m_ctx)) { + switch_state(inst, VPU_INST_STATE_STOP); + + if (dec_info.sequence_changed) + handle_dynamic_resolution_change(inst); + else + send_eos_event(inst); + + flag_last_buffer_done(inst); + } + spin_unlock_irqrestore(&inst->state_spinlock, flags); + } + + /* + * During a resolution change and while draining, the firmware may flush + * the reorder queue regardless of having a matching decoding operation + * pending. Only terminate the job if there are no more IRQ coming. + */ + wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status); + if (q_status.report_queue_count == 0 && + (q_status.instance_queue_count == 0 || dec_info.sequence_changed)) { + dev_dbg(inst->dev->dev, "%s: finishing job.\n", __func__); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + } +} + +static int wave5_vpu_dec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + strscpy(cap->driver, VPU_DEC_DRV_NAME, sizeof(cap->driver)); + strscpy(cap->card, VPU_DEC_DRV_NAME, sizeof(cap->card)); + + return 0; +} + +static int wave5_vpu_dec_enum_framesizes(struct file *f, void *fh, struct v4l2_frmsizeenum *fsize) +{ + const struct vpu_format *vpu_fmt; + + if (fsize->index) + return -EINVAL; + + vpu_fmt = wave5_find_vpu_fmt(fsize->pixel_format, dec_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) { + vpu_fmt = wave5_find_vpu_fmt(fsize->pixel_format, dec_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + } + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise = *vpu_fmt->v4l2_frmsize; + + return 0; +} + +static int wave5_vpu_dec_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + const struct vpu_format *vpu_fmt; + + vpu_fmt = wave5_find_vpu_fmt_by_idx(f->index, dec_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + + f->pixelformat = vpu_fmt->v4l2_pix_fmt; + f->flags = 0; + + return 0; +} + +static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + const struct vpu_format *vpu_fmt; + int width, height; + + dev_dbg(inst->dev->dev, + "%s: fourcc: %u width: %u height: %u nm planes: %u colorspace: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.colorspace, f->fmt.pix_mp.field); + + vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, dec_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) { + width = inst->dst_fmt.width; + height = inst->dst_fmt.height; + f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; + } else { + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; + } + + if (p_dec_info->initial_info_obtained) { + width = inst->dst_fmt.width; + height = inst->dst_fmt.height; + } + + wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_RAW, + width, + height, + vpu_fmt->v4l2_frmsize); + f->fmt.pix_mp.colorspace = inst->colorspace; + f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; + f->fmt.pix_mp.quantization = inst->quantization; + f->fmt.pix_mp.xfer_func = inst->xfer_func; + + return 0; +} + +static int wave5_vpu_dec_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + int i, ret; + + dev_dbg(inst->dev->dev, + "%s: fourcc: %u width: %u height: %u num_planes: %u colorspace: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.colorspace, f->fmt.pix_mp.field); + + ret = wave5_vpu_dec_try_fmt_cap(file, fh, f); + if (ret) + return ret; + + inst->dst_fmt.width = f->fmt.pix_mp.width; + inst->dst_fmt.height = f->fmt.pix_mp.height; + inst->dst_fmt.pixelformat = f->fmt.pix_mp.pixelformat; + inst->dst_fmt.field = f->fmt.pix_mp.field; + inst->dst_fmt.flags = f->fmt.pix_mp.flags; + inst->dst_fmt.num_planes = f->fmt.pix_mp.num_planes; + for (i = 0; i < inst->dst_fmt.num_planes; i++) { + inst->dst_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline; + inst->dst_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + + if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12 || + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12M) { + inst->cbcr_interleave = true; + inst->nv21 = false; + inst->output_format = FORMAT_420; + } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21 || + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21M) { + inst->cbcr_interleave = true; + inst->nv21 = true; + inst->output_format = FORMAT_420; + } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV16 || + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV16M) { + inst->cbcr_interleave = true; + inst->nv21 = false; + inst->output_format = FORMAT_422; + } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV61 || + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV61M) { + inst->cbcr_interleave = true; + inst->nv21 = true; + inst->output_format = FORMAT_422; + } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_YUV422P || + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_YUV422M) { + inst->cbcr_interleave = false; + inst->nv21 = false; + inst->output_format = FORMAT_422; + } else { + inst->cbcr_interleave = false; + inst->nv21 = false; + inst->output_format = FORMAT_420; + } + + return 0; +} + +static int wave5_vpu_dec_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + int i; + + f->fmt.pix_mp.width = inst->dst_fmt.width; + f->fmt.pix_mp.height = inst->dst_fmt.height; + f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; + f->fmt.pix_mp.field = inst->dst_fmt.field; + f->fmt.pix_mp.flags = inst->dst_fmt.flags; + f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes; + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { + f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->dst_fmt.plane_fmt[i].bytesperline; + f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->dst_fmt.plane_fmt[i].sizeimage; + } + + f->fmt.pix_mp.colorspace = inst->colorspace; + f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; + f->fmt.pix_mp.quantization = inst->quantization; + f->fmt.pix_mp.xfer_func = inst->xfer_func; + + return 0; +} + +static int wave5_vpu_dec_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + + dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index); + + vpu_fmt = wave5_find_vpu_fmt_by_idx(f->index, dec_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) + return -EINVAL; + + f->pixelformat = vpu_fmt->v4l2_pix_fmt; + f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED; + + return 0; +} + +static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + int width, height; + + dev_dbg(inst->dev->dev, + "%s: fourcc: %u width: %u height: %u num_planes: %u colorspace: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.colorspace, f->fmt.pix_mp.field); + + vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, dec_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) { + width = inst->src_fmt.width; + height = inst->src_fmt.height; + f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat; + } else { + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; + } + + wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_CODEC, + width, + height, + vpu_fmt->v4l2_frmsize); + + return 0; +} + +static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + int i, ret; + + dev_dbg(inst->dev->dev, + "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); + + ret = wave5_vpu_dec_try_fmt_out(file, fh, f); + if (ret) + return ret; + + inst->std = wave5_to_vpu_std(f->fmt.pix_mp.pixelformat, inst->type); + if (inst->std == STD_UNKNOWN) { + dev_warn(inst->dev->dev, "unsupported pixelformat: %.4s\n", + (char *)&f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + + inst->src_fmt.width = f->fmt.pix_mp.width; + inst->src_fmt.height = f->fmt.pix_mp.height; + inst->src_fmt.pixelformat = f->fmt.pix_mp.pixelformat; + inst->src_fmt.field = f->fmt.pix_mp.field; + inst->src_fmt.flags = f->fmt.pix_mp.flags; + inst->src_fmt.num_planes = f->fmt.pix_mp.num_planes; + for (i = 0; i < inst->src_fmt.num_planes; i++) { + inst->src_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline; + inst->src_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + + inst->colorspace = f->fmt.pix_mp.colorspace; + inst->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + inst->quantization = f->fmt.pix_mp.quantization; + inst->xfer_func = f->fmt.pix_mp.xfer_func; + + vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, dec_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + + wave5_update_pix_fmt(&inst->dst_fmt, VPU_FMT_TYPE_RAW, + f->fmt.pix_mp.width, + f->fmt.pix_mp.height, + vpu_fmt->v4l2_frmsize); + + return 0; +} + +static int wave5_vpu_dec_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + + dev_dbg(inst->dev->dev, "%s: type: %u | target: %u\n", __func__, s->type, s->target); + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->dst_fmt.width; + s->r.height = inst->dst_fmt.height; + break; + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + s->r.left = 0; + s->r.top = 0; + if (inst->state > VPU_INST_STATE_OPEN) { + s->r = inst->conf_win; + } else { + s->r.width = inst->src_fmt.width; + s->r.height = inst->src_fmt.height; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wave5_vpu_dec_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (s->target != V4L2_SEL_TGT_COMPOSE) + return -EINVAL; + + dev_dbg(inst->dev->dev, "V4L2_SEL_TGT_COMPOSE w: %u h: %u\n", + s->r.width, s->r.height); + + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->dst_fmt.width; + s->r.height = inst->dst_fmt.height; + + return 0; +} + +static int wave5_vpu_dec_stop(struct vpu_instance *inst) +{ + int ret = 0; + unsigned long flags; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + spin_lock_irqsave(&inst->state_spinlock, flags); + + if (m2m_ctx->is_draining) { + ret = -EBUSY; + goto unlock_and_return; + } + + if (inst->state != VPU_INST_STATE_NONE) { + /* + * Temporarily release the state_spinlock so that subsequent + * calls do not block on a mutex while inside this spinlock. + */ + spin_unlock_irqrestore(&inst->state_spinlock, flags); + ret = wave5_vpu_dec_set_eos_on_firmware(inst); + if (ret) + return ret; + + spin_lock_irqsave(&inst->state_spinlock, flags); + /* + * TODO eliminate this check by using a separate check for + * draining triggered by a resolution change. + */ + if (m2m_ctx->is_draining) { + ret = -EBUSY; + goto unlock_and_return; + } + } + + /* + * Used to remember the EOS state after the streamoff/on transition on + * the capture queue. + */ + inst->eos = true; + + if (m2m_ctx->has_stopped) + goto unlock_and_return; + + m2m_ctx->last_src_buf = v4l2_m2m_last_src_buf(m2m_ctx); + m2m_ctx->is_draining = true; + + /* + * Deferred to device run in case it wasn't in the ring buffer + * yet. In other case, we have to send the EOS signal to the + * firmware so that any pending PIC_RUN ends without new + * bitstream buffer. + */ + if (m2m_ctx->last_src_buf) + goto unlock_and_return; + + if (inst->state == VPU_INST_STATE_NONE) { + send_eos_event(inst); + flag_last_buffer_done(inst); + } + +unlock_and_return: + spin_unlock_irqrestore(&inst->state_spinlock, flags); + return ret; +} + +static int wave5_vpu_dec_start(struct vpu_instance *inst) +{ + int ret = 0; + unsigned long flags; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx); + + spin_lock_irqsave(&inst->state_spinlock, flags); + + if (m2m_ctx->is_draining) { + ret = -EBUSY; + goto unlock_and_return; + } + + if (m2m_ctx->has_stopped) + m2m_ctx->has_stopped = false; + + vb2_clear_last_buffer_dequeued(dst_vq); + inst->eos = false; + +unlock_and_return: + spin_unlock_irqrestore(&inst->state_spinlock, flags); + return ret; +} + +static int wave5_vpu_dec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret; + + dev_dbg(inst->dev->dev, "decoder command: %u\n", dc->cmd); + + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); + if (ret) + return ret; + + switch (dc->cmd) { + case V4L2_DEC_CMD_STOP: + ret = wave5_vpu_dec_stop(inst); + /* Just in case we don't have anything to decode anymore */ + v4l2_m2m_try_schedule(m2m_ctx); + break; + case V4L2_DEC_CMD_START: + ret = wave5_vpu_dec_start(inst); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ioctl_ops wave5_vpu_dec_ioctl_ops = { + .vidioc_querycap = wave5_vpu_dec_querycap, + .vidioc_enum_framesizes = wave5_vpu_dec_enum_framesizes, + + .vidioc_enum_fmt_vid_cap = wave5_vpu_dec_enum_fmt_cap, + .vidioc_s_fmt_vid_cap_mplane = wave5_vpu_dec_s_fmt_cap, + .vidioc_g_fmt_vid_cap_mplane = wave5_vpu_dec_g_fmt_cap, + .vidioc_try_fmt_vid_cap_mplane = wave5_vpu_dec_try_fmt_cap, + + .vidioc_enum_fmt_vid_out = wave5_vpu_dec_enum_fmt_out, + .vidioc_s_fmt_vid_out_mplane = wave5_vpu_dec_s_fmt_out, + .vidioc_g_fmt_vid_out_mplane = wave5_vpu_g_fmt_out, + .vidioc_try_fmt_vid_out_mplane = wave5_vpu_dec_try_fmt_out, + + .vidioc_g_selection = wave5_vpu_dec_g_selection, + .vidioc_s_selection = wave5_vpu_dec_s_selection, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + /* + * Firmware does not support CREATE_BUFS for CAPTURE queue. Since + * there is no immediate use-case for supporting CREATE_BUFS on + * just the OUTPUT queue, disable CREATE_BUFS altogether. + */ + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, + .vidioc_decoder_cmd = wave5_vpu_dec_decoder_cmd, + + .vidioc_subscribe_event = wave5_vpu_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int wave5_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_pix_format_mplane inst_format = + (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt; + unsigned int i; + + dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n", __func__, + *num_buffers, *num_planes, q->type); + + *num_planes = inst_format.num_planes; + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + sizes[0] = inst_format.plane_fmt[0].sizeimage; + dev_dbg(inst->dev->dev, "%s: size[0]: %u\n", __func__, sizes[0]); + } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (*num_buffers < inst->fbc_buf_count) + *num_buffers = inst->fbc_buf_count; + + for (i = 0; i < *num_planes; i++) { + sizes[i] = inst_format.plane_fmt[i].sizeimage; + dev_dbg(inst->dev->dev, "%s: size[%u]: %u\n", __func__, i, sizes[i]); + } + } + + return 0; +} + +static int wave5_prepare_fb(struct vpu_instance *inst) +{ + int linear_num; + int non_linear_num; + int fb_stride = 0, fb_height = 0; + int luma_size, chroma_size; + int ret, i; + struct v4l2_m2m_buffer *buf, *n; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + linear_num = v4l2_m2m_num_dst_bufs_ready(m2m_ctx); + non_linear_num = inst->fbc_buf_count; + + for (i = 0; i < non_linear_num; i++) { + struct frame_buffer *frame = &inst->frame_buf[i]; + struct vpu_buf *vframe = &inst->frame_vbuf[i]; + + fb_stride = inst->dst_fmt.width; + fb_height = ALIGN(inst->dst_fmt.height, 32); + luma_size = fb_stride * fb_height; + + chroma_size = ALIGN(fb_stride / 2, 16) * fb_height; + + if (vframe->size == (luma_size + chroma_size)) + continue; + + if (vframe->size) + wave5_vpu_dec_reset_framebuffer(inst, i); + + vframe->size = luma_size + chroma_size; + ret = wave5_vdi_allocate_dma_memory(inst->dev, vframe); + if (ret) { + dev_dbg(inst->dev->dev, + "%s: Allocating FBC buf of size %zu, fail: %d\n", + __func__, vframe->size, ret); + return ret; + } + + frame->buf_y = vframe->daddr; + frame->buf_cb = vframe->daddr + luma_size; + frame->buf_cr = (dma_addr_t)-1; + frame->size = vframe->size; + frame->width = inst->src_fmt.width; + frame->stride = fb_stride; + frame->map_type = COMPRESSED_FRAME_MAP; + frame->update_fb_info = true; + } + /* In case the count has reduced, clean up leftover framebuffer memory */ + for (i = non_linear_num; i < MAX_REG_FRAME; i++) { + ret = wave5_vpu_dec_reset_framebuffer(inst, i); + if (ret) + break; + } + + for (i = 0; i < linear_num; i++) { + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx); + struct vb2_buffer *vb = vb2_get_buffer(dst_vq, i); + struct frame_buffer *frame = &inst->frame_buf[non_linear_num + i]; + dma_addr_t buf_addr_y = 0, buf_addr_cb = 0, buf_addr_cr = 0; + u32 buf_size = 0; + u32 fb_stride = inst->dst_fmt.width; + u32 luma_size = fb_stride * inst->dst_fmt.height; + u32 chroma_size; + + if (inst->output_format == FORMAT_422) + chroma_size = fb_stride * inst->dst_fmt.height / 2; + else + chroma_size = fb_stride * inst->dst_fmt.height / 4; + + if (inst->dst_fmt.num_planes == 1) { + buf_size = vb2_plane_size(vb, 0); + buf_addr_y = vb2_dma_contig_plane_dma_addr(vb, 0); + buf_addr_cb = buf_addr_y + luma_size; + buf_addr_cr = buf_addr_cb + chroma_size; + } else if (inst->dst_fmt.num_planes == 2) { + buf_size = vb2_plane_size(vb, 0) + + vb2_plane_size(vb, 1); + buf_addr_y = vb2_dma_contig_plane_dma_addr(vb, 0); + buf_addr_cb = vb2_dma_contig_plane_dma_addr(vb, 1); + buf_addr_cr = buf_addr_cb + chroma_size; + } else if (inst->dst_fmt.num_planes == 3) { + buf_size = vb2_plane_size(vb, 0) + + vb2_plane_size(vb, 1) + + vb2_plane_size(vb, 2); + buf_addr_y = vb2_dma_contig_plane_dma_addr(vb, 0); + buf_addr_cb = vb2_dma_contig_plane_dma_addr(vb, 1); + buf_addr_cr = vb2_dma_contig_plane_dma_addr(vb, 2); + } + + frame->buf_y = buf_addr_y; + frame->buf_cb = buf_addr_cb; + frame->buf_cr = buf_addr_cr; + frame->size = buf_size; + frame->width = inst->src_fmt.width; + frame->stride = fb_stride; + frame->map_type = LINEAR_FRAME_MAP; + frame->update_fb_info = true; + } + + ret = wave5_vpu_dec_register_frame_buffer_ex(inst, non_linear_num, linear_num, + fb_stride, inst->dst_fmt.height); + if (ret) { + dev_dbg(inst->dev->dev, "%s: vpu_dec_register_frame_buffer_ex fail: %d", + __func__, ret); + return ret; + } + + /* + * Mark all frame buffers as out of display, to avoid using them before + * the application have them queued. + */ + for (i = 0; i < v4l2_m2m_num_dst_bufs_ready(m2m_ctx); i++) { + ret = wave5_vpu_dec_set_disp_flag(inst, i); + if (ret) { + dev_dbg(inst->dev->dev, + "%s: Setting display flag of buf index: %u, fail: %d\n", + __func__, i, ret); + } + } + + v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) { + struct vb2_v4l2_buffer *vbuf = &buf->vb; + + ret = wave5_vpu_dec_clr_disp_flag(inst, vbuf->vb2_buf.index); + if (ret) + dev_dbg(inst->dev->dev, + "%s: Clearing display flag of buf index: %u, fail: %d\n", + __func__, i, ret); + } + + return 0; +} + +static int write_to_ringbuffer(struct vpu_instance *inst, void *buffer, size_t buffer_size, + struct vpu_buf *ring_buffer, dma_addr_t wr_ptr) +{ + size_t size; + size_t offset = wr_ptr - ring_buffer->daddr; + int ret; + + if (wr_ptr + buffer_size > ring_buffer->daddr + ring_buffer->size) { + size = ring_buffer->daddr + ring_buffer->size - wr_ptr; + ret = wave5_vdi_write_memory(inst->dev, ring_buffer, offset, (u8 *)buffer, size); + if (ret < 0) + return ret; + + ret = wave5_vdi_write_memory(inst->dev, ring_buffer, 0, (u8 *)buffer + size, + buffer_size - size); + if (ret < 0) + return ret; + } else { + ret = wave5_vdi_write_memory(inst->dev, ring_buffer, offset, (u8 *)buffer, + buffer_size); + if (ret < 0) + return ret; + } + + return 0; +} + +static int fill_ringbuffer(struct vpu_instance *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct v4l2_m2m_buffer *buf, *n; + int ret; + + if (m2m_ctx->last_src_buf) { + struct vpu_src_buffer *vpu_buf = wave5_to_vpu_src_buf(m2m_ctx->last_src_buf); + + if (vpu_buf->consumed) { + dev_dbg(inst->dev->dev, "last src buffer already written\n"); + return 0; + } + } + + v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) { + struct vb2_v4l2_buffer *vbuf = &buf->vb; + struct vpu_src_buffer *vpu_buf = wave5_to_vpu_src_buf(vbuf); + struct vpu_buf *ring_buffer = &inst->bitstream_vbuf; + size_t src_size = vb2_get_plane_payload(&vbuf->vb2_buf, 0); + void *src_buf = vb2_plane_vaddr(&vbuf->vb2_buf, 0); + dma_addr_t rd_ptr = 0; + dma_addr_t wr_ptr = 0; + size_t remain_size = 0; + + if (vpu_buf->consumed) { + dev_dbg(inst->dev->dev, "already copied src buf (%u) to the ring buffer\n", + vbuf->vb2_buf.index); + continue; + } + + if (!src_buf) { + dev_dbg(inst->dev->dev, + "%s: Acquiring kernel pointer to src buf (%u), fail\n", + __func__, vbuf->vb2_buf.index); + break; + } + + ret = wave5_vpu_dec_get_bitstream_buffer(inst, &rd_ptr, &wr_ptr, &remain_size); + if (ret) { + /* Unable to acquire the mutex */ + dev_err(inst->dev->dev, "Getting the bitstream buffer, fail: %d\n", + ret); + return ret; + } + + dev_dbg(inst->dev->dev, "%s: rd_ptr %pad wr_ptr %pad", __func__, &rd_ptr, &wr_ptr); + + if (remain_size < src_size) { + dev_dbg(inst->dev->dev, + "%s: remaining size: %zu < source size: %zu for src buf (%u)\n", + __func__, remain_size, src_size, vbuf->vb2_buf.index); + break; + } + + ret = write_to_ringbuffer(inst, src_buf, src_size, ring_buffer, wr_ptr); + if (ret) { + dev_err(inst->dev->dev, "Write src buf (%u) to ring buffer, fail: %d\n", + vbuf->vb2_buf.index, ret); + return ret; + } + + ret = wave5_vpu_dec_update_bitstream_buffer(inst, src_size); + if (ret) { + dev_dbg(inst->dev->dev, + "update_bitstream_buffer fail: %d for src buf (%u)\n", + ret, vbuf->vb2_buf.index); + break; + } + + vpu_buf->consumed = true; + + /* Don't write buffers passed the last one while draining. */ + if (v4l2_m2m_is_last_draining_src_buf(m2m_ctx, vbuf)) { + dev_dbg(inst->dev->dev, "last src buffer written to the ring buffer\n"); + break; + } + } + + return 0; +} + +static void wave5_vpu_dec_buf_queue_src(struct vb2_buffer *vb) +{ + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_src_buffer *vpu_buf = wave5_to_vpu_src_buf(vbuf); + + vpu_buf->consumed = false; + vbuf->sequence = inst->queued_src_buf_num++; + + v4l2_m2m_buf_queue(m2m_ctx, vbuf); +} + +static void wave5_vpu_dec_buf_queue_dst(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + vbuf->sequence = inst->queued_dst_buf_num++; + + if (inst->state == VPU_INST_STATE_PIC_RUN) { + struct vpu_dst_buffer *vpu_buf = wave5_to_vpu_dst_buf(vbuf); + int ret; + + /* + * The buffer is already registered just clear the display flag + * to let the firmware know it can be used. + */ + vpu_buf->display = false; + ret = wave5_vpu_dec_clr_disp_flag(inst, vb->index); + if (ret) { + dev_dbg(inst->dev->dev, + "%s: Clearing the display flag of buffer index: %u, fail: %d\n", + __func__, vb->index, ret); + } + } + + if (vb2_is_streaming(vb->vb2_queue) && v4l2_m2m_dst_buf_is_last(m2m_ctx)) { + unsigned int i; + + for (i = 0; i < vb->num_planes; i++) + vb2_set_plane_payload(vb, i, 0); + + vbuf->field = V4L2_FIELD_NONE; + + send_eos_event(inst); + v4l2_m2m_last_buffer_done(m2m_ctx, vbuf); + } else { + v4l2_m2m_buf_queue(m2m_ctx, vbuf); + } +} + +static void wave5_vpu_dec_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + + dev_dbg(inst->dev->dev, "%s: type: %4u index: %4u size: ([0]=%4lu, [1]=%4lu, [2]=%4lu)\n", + __func__, vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0), + vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2)); + + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + wave5_vpu_dec_buf_queue_src(vb); + else if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + wave5_vpu_dec_buf_queue_dst(vb); +} + +static int wave5_vpu_dec_allocate_ring_buffer(struct vpu_instance *inst) +{ + int ret; + struct vpu_buf *ring_buffer = &inst->bitstream_vbuf; + + ring_buffer->size = ALIGN(inst->src_fmt.plane_fmt[0].sizeimage, 1024) * 4; + ret = wave5_vdi_allocate_dma_memory(inst->dev, ring_buffer); + if (ret) { + dev_dbg(inst->dev->dev, "%s: allocate ring buffer of size %zu fail: %d\n", + __func__, ring_buffer->size, ret); + return ret; + } + + inst->last_rd_ptr = ring_buffer->daddr; + + return 0; +} + +static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret = 0; + + dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); + pm_runtime_resume_and_get(inst->dev->dev); + + v4l2_m2m_update_start_streaming_state(m2m_ctx, q); + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && inst->state == VPU_INST_STATE_NONE) { + struct dec_open_param open_param; + + memset(&open_param, 0, sizeof(struct dec_open_param)); + + ret = wave5_vpu_dec_allocate_ring_buffer(inst); + if (ret) + goto return_buffers; + + open_param.bitstream_buffer = inst->bitstream_vbuf.daddr; + open_param.bitstream_buffer_size = inst->bitstream_vbuf.size; + + ret = wave5_vpu_dec_open(inst, &open_param); + if (ret) { + dev_dbg(inst->dev->dev, "%s: decoder opening, fail: %d\n", + __func__, ret); + goto free_bitstream_vbuf; + } + + ret = switch_state(inst, VPU_INST_STATE_OPEN); + if (ret) + goto free_bitstream_vbuf; + + ret = fill_ringbuffer(inst); + if (ret) + dev_err(inst->dev->dev, "Filling ring buffer failed\n"); + + ret = initialize_sequence(inst); + if (ret) { + unsigned long flags; + + spin_lock_irqsave(&inst->state_spinlock, flags); + if (wave5_is_draining_or_eos(inst) && + wave5_last_src_buffer_consumed(inst->v4l2_fh.m2m_ctx)) { + struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx); + + switch_state(inst, VPU_INST_STATE_STOP); + + if (vb2_is_streaming(dst_vq)) + send_eos_event(inst); + else + handle_dynamic_resolution_change(inst); + + flag_last_buffer_done(inst); + } + spin_unlock_irqrestore(&inst->state_spinlock, flags); + } else { + switch_state(inst, VPU_INST_STATE_INIT_SEQ); + } + } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + struct dec_initial_info *initial_info = + &inst->codec_info->dec_info.initial_info; + + if (inst->state == VPU_INST_STATE_STOP) + ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ); + if (ret) + goto return_buffers; + + if (inst->state == VPU_INST_STATE_INIT_SEQ) { + if (initial_info->luma_bitdepth != 8) { + dev_info(inst->dev->dev, "%s: no support for %d bit depth", + __func__, initial_info->luma_bitdepth); + ret = -EINVAL; + goto return_buffers; + } + } + } + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); + return ret; + +free_bitstream_vbuf: + wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf); +return_buffers: + wave5_return_bufs(q, VB2_BUF_STATE_QUEUED); + pm_runtime_put_autosuspend(inst->dev->dev); + return ret; +} + +static int streamoff_output(struct vb2_queue *q) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_v4l2_buffer *buf; + int ret; + dma_addr_t new_rd_ptr; + + while ((buf = v4l2_m2m_src_buf_remove(m2m_ctx))) { + dev_dbg(inst->dev->dev, "%s: (Multiplanar) buf type %4u | index %4u\n", + __func__, buf->vb2_buf.type, buf->vb2_buf.index); + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + } + + ret = wave5_vpu_flush_instance(inst); + if (ret) + return ret; + + /* Reset the ring buffer information */ + new_rd_ptr = wave5_vpu_dec_get_rd_ptr(inst); + inst->last_rd_ptr = new_rd_ptr; + inst->codec_info->dec_info.stream_rd_ptr = new_rd_ptr; + inst->codec_info->dec_info.stream_wr_ptr = new_rd_ptr; + + if (v4l2_m2m_has_stopped(m2m_ctx)) + send_eos_event(inst); + + /* streamoff on output cancels any draining operation */ + inst->eos = false; + + return 0; +} + +static int streamoff_capture(struct vb2_queue *q) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_v4l2_buffer *buf; + unsigned int i; + int ret = 0; + + for (i = 0; i < v4l2_m2m_num_dst_bufs_ready(m2m_ctx); i++) { + ret = wave5_vpu_dec_set_disp_flag(inst, i); + if (ret) + dev_dbg(inst->dev->dev, + "%s: Setting display flag of buf index: %u, fail: %d\n", + __func__, i, ret); + } + + while ((buf = v4l2_m2m_dst_buf_remove(m2m_ctx))) { + u32 plane; + + dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n", + __func__, buf->vb2_buf.type, buf->vb2_buf.index); + + for (plane = 0; plane < inst->dst_fmt.num_planes; plane++) + vb2_set_plane_payload(&buf->vb2_buf, plane, 0); + + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + } + + if (inst->needs_reallocation) { + wave5_vpu_dec_give_command(inst, DEC_RESET_FRAMEBUF_INFO, NULL); + inst->needs_reallocation = false; + } + + if (v4l2_m2m_has_stopped(m2m_ctx)) { + ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ); + if (ret) + return ret; + } + + return 0; +} + +static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + bool check_cmd = TRUE; + + dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); + pm_runtime_resume_and_get(inst->dev->dev); + + while (check_cmd) { + struct queue_status_info q_status; + struct dec_output_info dec_output_info; + + wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status); + + if (q_status.report_queue_count == 0) + break; + + if (wave5_vpu_wait_interrupt(inst, VPU_DEC_TIMEOUT) < 0) + break; + + if (wave5_vpu_dec_get_output_info(inst, &dec_output_info)) + dev_dbg(inst->dev->dev, "Getting decoding results from fw, fail\n"); + } + + v4l2_m2m_update_stop_streaming_state(m2m_ctx, q); + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + streamoff_output(q); + else + streamoff_capture(q); + + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); +} + +static const struct vb2_ops wave5_vpu_dec_vb2_ops = { + .queue_setup = wave5_vpu_dec_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_queue = wave5_vpu_dec_buf_queue, + .start_streaming = wave5_vpu_dec_start_streaming, + .stop_streaming = wave5_vpu_dec_stop_streaming, +}; + +static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, + struct v4l2_pix_format_mplane *dst_fmt) +{ + src_fmt->pixelformat = dec_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt; + wave5_update_pix_fmt(src_fmt, VPU_FMT_TYPE_CODEC, + W5_DEF_DEC_PIC_WIDTH, + W5_DEF_DEC_PIC_HEIGHT, + &dec_hevc_frmsize); + + dst_fmt->pixelformat = dec_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; + wave5_update_pix_fmt(dst_fmt, VPU_FMT_TYPE_RAW, + W5_DEF_DEC_PIC_WIDTH, + W5_DEF_DEC_PIC_HEIGHT, + &dec_raw_frmsize); +} + +static int wave5_vpu_dec_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + return wave5_vpu_queue_init(priv, src_vq, dst_vq, &wave5_vpu_dec_vb2_ops); +} + +static const struct vpu_instance_ops wave5_vpu_dec_inst_ops = { + .finish_process = wave5_vpu_dec_finish_decode, +}; + +static int initialize_sequence(struct vpu_instance *inst) +{ + struct dec_initial_info initial_info; + int ret = 0; + + memset(&initial_info, 0, sizeof(struct dec_initial_info)); + + ret = wave5_vpu_dec_issue_seq_init(inst); + if (ret) { + dev_dbg(inst->dev->dev, "%s: wave5_vpu_dec_issue_seq_init, fail: %d\n", + __func__, ret); + return ret; + } + + if (wave5_vpu_wait_interrupt(inst, VPU_DEC_TIMEOUT) < 0) + dev_dbg(inst->dev->dev, "%s: failed to call vpu_wait_interrupt()\n", __func__); + + ret = wave5_vpu_dec_complete_seq_init(inst, &initial_info); + if (ret) { + dev_dbg(inst->dev->dev, "%s: vpu_dec_complete_seq_init, fail: %d, reason: %u\n", + __func__, ret, initial_info.seq_init_err_reason); + wave5_handle_src_buffer(inst, initial_info.rd_ptr); + return ret; + } + + handle_dynamic_resolution_change(inst); + + return 0; +} + +static bool wave5_is_draining_or_eos(struct vpu_instance *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + lockdep_assert_held(&inst->state_spinlock); + return m2m_ctx->is_draining || inst->eos; +} + +static void wave5_vpu_dec_device_run(void *priv) +{ + struct vpu_instance *inst = priv; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct queue_status_info q_status; + u32 fail_res = 0; + int ret = 0; + + dev_dbg(inst->dev->dev, "%s: Fill the ring buffer with new bitstream data", __func__); + pm_runtime_resume_and_get(inst->dev->dev); + ret = fill_ringbuffer(inst); + if (ret) { + dev_warn(inst->dev->dev, "Filling ring buffer failed\n"); + goto finish_job_and_return; + } + + switch (inst->state) { + case VPU_INST_STATE_OPEN: + ret = initialize_sequence(inst); + if (ret) { + unsigned long flags; + + spin_lock_irqsave(&inst->state_spinlock, flags); + if (wave5_is_draining_or_eos(inst) && + wave5_last_src_buffer_consumed(m2m_ctx)) { + struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx); + + switch_state(inst, VPU_INST_STATE_STOP); + + if (vb2_is_streaming(dst_vq)) + send_eos_event(inst); + else + handle_dynamic_resolution_change(inst); + + flag_last_buffer_done(inst); + } + spin_unlock_irqrestore(&inst->state_spinlock, flags); + } else { + switch_state(inst, VPU_INST_STATE_INIT_SEQ); + } + + break; + + case VPU_INST_STATE_INIT_SEQ: + /* + * Do this early, preparing the fb can trigger an IRQ before + * we had a chance to switch, which leads to an invalid state + * change. + */ + switch_state(inst, VPU_INST_STATE_PIC_RUN); + + /* + * During DRC, the picture decoding remains pending, so just leave the job + * active until this decode operation completes. + */ + wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status); + + /* + * The sequence must be analyzed first to calculate the proper + * size of the auxiliary buffers. + */ + ret = wave5_prepare_fb(inst); + if (ret) { + dev_warn(inst->dev->dev, "Framebuffer preparation, fail: %d\n", ret); + switch_state(inst, VPU_INST_STATE_STOP); + break; + } + + if (q_status.instance_queue_count) { + dev_dbg(inst->dev->dev, "%s: leave with active job", __func__); + return; + } + + fallthrough; + case VPU_INST_STATE_PIC_RUN: + ret = start_decode(inst, &fail_res); + if (ret) { + dev_err(inst->dev->dev, + "Frame decoding on m2m context (%p), fail: %d (result: %d)\n", + m2m_ctx, ret, fail_res); + break; + } + /* Return so that we leave this job active */ + dev_dbg(inst->dev->dev, "%s: leave with active job", __func__); + return; + default: + WARN(1, "Execution of a job in state %s illegal.\n", state_to_str(inst->state)); + break; + } + +finish_job_and_return: + dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); +} + +static void wave5_vpu_dec_job_abort(void *priv) +{ + struct vpu_instance *inst = priv; + int ret; + + ret = switch_state(inst, VPU_INST_STATE_STOP); + if (ret) + return; + + ret = wave5_vpu_dec_set_eos_on_firmware(inst); + if (ret) + dev_warn(inst->dev->dev, + "Setting EOS for the bitstream, fail: %d\n", ret); +} + +static int wave5_vpu_dec_job_ready(void *priv) +{ + struct vpu_instance *inst = priv; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&inst->state_spinlock, flags); + + switch (inst->state) { + case VPU_INST_STATE_NONE: + dev_dbg(inst->dev->dev, "Decoder must be open to start queueing M2M jobs!\n"); + break; + case VPU_INST_STATE_OPEN: + if (wave5_is_draining_or_eos(inst) || !v4l2_m2m_has_stopped(m2m_ctx) || + v4l2_m2m_num_src_bufs_ready(m2m_ctx) > 0) { + ret = 1; + break; + } + + dev_dbg(inst->dev->dev, + "Decoder must be draining or >= 1 OUTPUT queue buffer must be queued!\n"); + break; + case VPU_INST_STATE_INIT_SEQ: + case VPU_INST_STATE_PIC_RUN: + if (!m2m_ctx->cap_q_ctx.q.streaming) { + dev_dbg(inst->dev->dev, "CAPTURE queue must be streaming to queue jobs!\n"); + break; + } else if (v4l2_m2m_num_dst_bufs_ready(m2m_ctx) < (inst->fbc_buf_count - 1)) { + dev_dbg(inst->dev->dev, + "No capture buffer ready to decode!\n"); + break; + } else if (!wave5_is_draining_or_eos(inst) && + !v4l2_m2m_num_src_bufs_ready(m2m_ctx)) { + dev_dbg(inst->dev->dev, + "No bitstream data to decode!\n"); + break; + } + ret = 1; + break; + case VPU_INST_STATE_STOP: + dev_dbg(inst->dev->dev, "Decoder is stopped, not running.\n"); + break; + } + + spin_unlock_irqrestore(&inst->state_spinlock, flags); + + return ret; +} + +static const struct v4l2_m2m_ops wave5_vpu_dec_m2m_ops = { + .device_run = wave5_vpu_dec_device_run, + .job_abort = wave5_vpu_dec_job_abort, + .job_ready = wave5_vpu_dec_job_ready, +}; + +static int wave5_vpu_open_dec(struct file *filp) +{ + struct video_device *vdev = video_devdata(filp); + struct vpu_device *dev = video_drvdata(filp); + struct vpu_instance *inst = NULL; + struct v4l2_m2m_ctx *m2m_ctx; + int ret = 0; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->dev = dev; + inst->type = VPU_INST_TYPE_DEC; + inst->ops = &wave5_vpu_dec_inst_ops; + + spin_lock_init(&inst->state_spinlock); + + inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); + if (!inst->codec_info) + return -ENOMEM; + + v4l2_fh_init(&inst->v4l2_fh, vdev); + filp->private_data = &inst->v4l2_fh; + v4l2_fh_add(&inst->v4l2_fh); + + INIT_LIST_HEAD(&inst->list); + + inst->v4l2_m2m_dev = inst->dev->v4l2_m2m_dec_dev; + inst->v4l2_fh.m2m_ctx = + v4l2_m2m_ctx_init(inst->v4l2_m2m_dev, inst, wave5_vpu_dec_queue_init); + if (IS_ERR(inst->v4l2_fh.m2m_ctx)) { + ret = PTR_ERR(inst->v4l2_fh.m2m_ctx); + goto cleanup_inst; + } + m2m_ctx = inst->v4l2_fh.m2m_ctx; + + v4l2_m2m_set_src_buffered(m2m_ctx, true); + v4l2_m2m_set_dst_buffered(m2m_ctx, true); + /* + * We use the M2M job queue to ensure synchronization of steps where + * needed, as IOCTLs can occur at anytime and we need to run commands on + * the firmware in a specified order. + * In order to initialize the sequence on the firmware within an M2M + * job, the M2M framework needs to be able to queue jobs before + * the CAPTURE queue has been started, because we need the results of the + * initialization to properly prepare the CAPTURE queue with the correct + * amount of buffers. + * By setting ignore_cap_streaming to true the m2m framework will call + * job_ready as soon as the OUTPUT queue is streaming, instead of + * waiting until both the CAPTURE and OUTPUT queues are streaming. + */ + m2m_ctx->ignore_cap_streaming = true; + + v4l2_ctrl_handler_init(&inst->v4l2_ctrl_hdl, 10); + v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl, NULL, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 1); + + if (inst->v4l2_ctrl_hdl.error) { + ret = -ENODEV; + goto cleanup_inst; + } + + inst->v4l2_fh.ctrl_handler = &inst->v4l2_ctrl_hdl; + v4l2_ctrl_handler_setup(&inst->v4l2_ctrl_hdl); + + wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt); + inst->colorspace = V4L2_COLORSPACE_REC709; + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + inst->quantization = V4L2_QUANTIZATION_DEFAULT; + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT; + + init_completion(&inst->irq_done); + + inst->id = ida_alloc(&inst->dev->inst_ida, GFP_KERNEL); + if (inst->id < 0) { + dev_warn(inst->dev->dev, "Allocating instance ID, fail: %d\n", inst->id); + ret = inst->id; + goto cleanup_inst; + } + + wave5_vdi_allocate_sram(inst->dev); + + ret = mutex_lock_interruptible(&dev->dev_lock); + if (ret) + goto cleanup_inst; + + list_add_tail(&inst->list, &dev->instances); + + mutex_unlock(&dev->dev_lock); + + return 0; + +cleanup_inst: + wave5_cleanup_instance(inst); + return ret; +} + +static int wave5_vpu_dec_release(struct file *filp) +{ + return wave5_vpu_release_device(filp, wave5_vpu_dec_close, "decoder"); +} + +static const struct v4l2_file_operations wave5_vpu_dec_fops = { + .owner = THIS_MODULE, + .open = wave5_vpu_open_dec, + .release = wave5_vpu_dec_release, + .unlocked_ioctl = video_ioctl2, + .poll = v4l2_m2m_fop_poll, + .mmap = v4l2_m2m_fop_mmap, +}; + +int wave5_vpu_dec_register_device(struct vpu_device *dev) +{ + struct video_device *vdev_dec; + int ret; + + vdev_dec = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_dec), GFP_KERNEL); + if (!vdev_dec) + return -ENOMEM; + + dev->v4l2_m2m_dec_dev = v4l2_m2m_init(&wave5_vpu_dec_m2m_ops); + if (IS_ERR(dev->v4l2_m2m_dec_dev)) { + ret = PTR_ERR(dev->v4l2_m2m_dec_dev); + dev_err(dev->dev, "v4l2_m2m_init, fail: %d\n", ret); + return -EINVAL; + } + + dev->video_dev_dec = vdev_dec; + + strscpy(vdev_dec->name, VPU_DEC_DEV_NAME, sizeof(vdev_dec->name)); + vdev_dec->fops = &wave5_vpu_dec_fops; + vdev_dec->ioctl_ops = &wave5_vpu_dec_ioctl_ops; + vdev_dec->release = video_device_release_empty; + vdev_dec->v4l2_dev = &dev->v4l2_dev; + vdev_dec->vfl_dir = VFL_DIR_M2M; + vdev_dec->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + vdev_dec->lock = &dev->dev_lock; + + ret = video_register_device(vdev_dec, VFL_TYPE_VIDEO, -1); + if (ret) + return ret; + + video_set_drvdata(vdev_dec, dev); + + return 0; +} + +void wave5_vpu_dec_unregister_device(struct vpu_device *dev) +{ + video_unregister_device(dev->video_dev_dec); + if (dev->v4l2_m2m_dec_dev) + v4l2_m2m_release(dev->v4l2_m2m_dec_dev); +} diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,1886 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave5 series multi-standard codec IP - encoder interface + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#include +#include "wave5-helper.h" + +#define VPU_ENC_DEV_NAME "C&M Wave5 VPU encoder" +#define VPU_ENC_DRV_NAME "wave5-enc" + +static const struct v4l2_frmsize_stepwise enc_frmsize[FMT_TYPES] = { + [VPU_FMT_TYPE_CODEC] = { + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .step_width = W5_ENC_CODEC_STEP_WIDTH, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .step_height = W5_ENC_CODEC_STEP_HEIGHT, + }, + [VPU_FMT_TYPE_RAW] = { + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .step_width = W5_ENC_RAW_STEP_WIDTH, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .step_height = W5_ENC_RAW_STEP_HEIGHT, + }, +}; + +static const struct vpu_format enc_fmt_list[FMT_TYPES][MAX_FMTS] = { + [VPU_FMT_TYPE_CODEC] = { + { + .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_H264, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC], + }, + }, + [VPU_FMT_TYPE_RAW] = { + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M, + }, + } +}; + +static int switch_state(struct vpu_instance *inst, enum vpu_instance_state state) +{ + switch (state) { + case VPU_INST_STATE_NONE: + goto invalid_state_switch; + case VPU_INST_STATE_OPEN: + if (inst->state != VPU_INST_STATE_NONE) + goto invalid_state_switch; + break; + case VPU_INST_STATE_INIT_SEQ: + if (inst->state != VPU_INST_STATE_OPEN && inst->state != VPU_INST_STATE_STOP) + goto invalid_state_switch; + break; + case VPU_INST_STATE_PIC_RUN: + if (inst->state != VPU_INST_STATE_INIT_SEQ) + goto invalid_state_switch; + break; + case VPU_INST_STATE_STOP: + break; + } + + dev_dbg(inst->dev->dev, "Switch state from %s to %s.\n", + state_to_str(inst->state), state_to_str(state)); + inst->state = state; + return 0; + +invalid_state_switch: + WARN(1, "Invalid state switch from %s to %s.\n", + state_to_str(inst->state), state_to_str(state)); + return -EINVAL; +} + +static int start_encode(struct vpu_instance *inst, u32 *fail_res) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret; + struct vb2_v4l2_buffer *src_buf; + struct vb2_v4l2_buffer *dst_buf; + struct frame_buffer frame_buf; + struct enc_param pic_param; + const struct v4l2_format_info *info; + u32 stride = inst->src_fmt.plane_fmt[0].bytesperline; + u32 luma_size = 0; + u32 chroma_size = 0; + + memset(&pic_param, 0, sizeof(struct enc_param)); + memset(&frame_buf, 0, sizeof(struct frame_buffer)); + + if (inst->change_param_flags) { + struct enc_output_info enc_output_info; + + wave5_vpu_enc_change_param(inst, NULL); + inst->change_param_flags = 0; + if (wave5_vpu_wait_interrupt(inst, VPU_ENC_TIMEOUT) < 0) { + dev_dbg(inst->dev->dev, "%s: wave5_vpu_wait_interrupt failed\n", __func__); + return -EINVAL; + } + + ret = wave5_vpu_enc_get_output_info(inst, &enc_output_info); + if (ret) { + dev_dbg(inst->dev->dev, + "%s: vpu_enc_get_output_info fail: %d reason: %u | info: %u\n", + __func__, ret, enc_output_info.error_reason, enc_output_info.warn_info); + return -EINVAL; + } + + if (enc_output_info.recon_frame_index == RECON_IDX_FLAG_CHANGE_PARAM) + dev_dbg(inst->dev->dev, "%s: the change param done\n", __func__); + else + return -EINVAL; + } + + info = v4l2_format_info(inst->src_fmt.pixelformat); + if (!info) + return -EINVAL; + + if (info->mem_planes == 1) { + luma_size = stride * inst->dst_fmt.height; + chroma_size = luma_size / (info->hdiv * info->vdiv); + } else { + luma_size = inst->src_fmt.plane_fmt[0].sizeimage; + chroma_size = inst->src_fmt.plane_fmt[1].sizeimage; + } + + dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx); + if (!dst_buf) { + dev_dbg(inst->dev->dev, "%s: No destination buffer found\n", __func__); + return -EAGAIN; + } + + pic_param.pic_stream_buffer_addr = + vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + pic_param.pic_stream_buffer_size = + vb2_plane_size(&dst_buf->vb2_buf, 0); + + src_buf = v4l2_m2m_next_src_buf(m2m_ctx); + if (!src_buf) { + dev_dbg(inst->dev->dev, "%s: No source buffer found\n", __func__); + if (m2m_ctx->is_draining) + pic_param.src_end_flag = 1; + else + return -EAGAIN; + } else { + if (inst->src_fmt.num_planes == 1) { + frame_buf.buf_y = + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + frame_buf.buf_cb = frame_buf.buf_y + luma_size; + frame_buf.buf_cr = frame_buf.buf_cb + chroma_size; + } else if (inst->src_fmt.num_planes == 2) { + frame_buf.buf_y = + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + frame_buf.buf_cb = + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 1); + frame_buf.buf_cr = frame_buf.buf_cb + chroma_size; + } else if (inst->src_fmt.num_planes == 3) { + frame_buf.buf_y = + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + frame_buf.buf_cb = + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 1); + frame_buf.buf_cr = + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 2); + } + frame_buf.stride = stride; + pic_param.src_idx = src_buf->vb2_buf.index; + } + + pic_param.source_frame = &frame_buf; + pic_param.code_option.implicit_header_encode = 1; + pic_param.code_option.encode_aud = inst->encode_aud; + if (inst->enc_param.forced_idr_pictype_enable) { + pic_param.force_pic_type = 3; /* IDR Frame */ + pic_param.force_pictype_enable = 1; + inst->enc_param.forced_idr_pictype_enable = 0; + } + ret = wave5_vpu_enc_start_one_frame(inst, &pic_param, fail_res); + if (ret) { + if (*fail_res == WAVE5_SYSERR_QUEUEING_FAIL) + return -EINVAL; + + dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame fail: %d\n", + __func__, ret); + src_buf = v4l2_m2m_src_buf_remove(m2m_ctx); + if (!src_buf) { + dev_dbg(inst->dev->dev, + "%s: Removing src buf failed, the queue is empty\n", + __func__); + return -EINVAL; + } + dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx); + if (!dst_buf) { + dev_dbg(inst->dev->dev, + "%s: Removing dst buf failed, the queue is empty\n", + __func__); + return -EINVAL; + } + switch_state(inst, VPU_INST_STATE_STOP); + dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); + } else { + dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame success\n", + __func__); + /* + * Remove the source buffer from the ready-queue now and finish + * it in the videobuf2 framework once the index is returned by the + * firmware in finish_encode + */ + if (src_buf) + v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, src_buf->vb2_buf.index); + } + + return 0; +} + +static void wave5_vpu_enc_finish_encode(struct vpu_instance *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret; + struct enc_output_info enc_output_info; + struct vb2_v4l2_buffer *src_buf = NULL; + struct vb2_v4l2_buffer *dst_buf = NULL; + + ret = wave5_vpu_enc_get_output_info(inst, &enc_output_info); + if (ret) { + dev_dbg(inst->dev->dev, + "%s: vpu_enc_get_output_info fail: %d reason: %u | info: %u\n", + __func__, ret, enc_output_info.error_reason, enc_output_info.warn_info); + return; + } + + dev_dbg(inst->dev->dev, + "%s: pic_type %i recon_idx %i src_idx %i pic_byte %u pts %llu\n", + __func__, enc_output_info.pic_type, enc_output_info.recon_frame_index, + enc_output_info.enc_src_idx, enc_output_info.enc_pic_byte, enc_output_info.pts); + + /* + * The source buffer will not be found in the ready-queue as it has been + * dropped after sending of the encode firmware command, locate it in + * the videobuf2 queue directly + */ + if (enc_output_info.enc_src_idx >= 0) { + struct vb2_buffer *vb = vb2_get_buffer(v4l2_m2m_get_src_vq(m2m_ctx), + enc_output_info.enc_src_idx); + if (vb->state != VB2_BUF_STATE_ACTIVE) + dev_warn(inst->dev->dev, + "%s: encoded buffer (%d) was not in ready queue %i.", + __func__, enc_output_info.enc_src_idx, vb->state); + else + src_buf = to_vb2_v4l2_buffer(vb); + + if (src_buf) { + inst->timestamp = src_buf->vb2_buf.timestamp; + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } else { + dev_warn(inst->dev->dev, "%s: no source buffer with index: %d found\n", + __func__, enc_output_info.enc_src_idx); + } + } + + dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx); + if (enc_output_info.recon_frame_index == RECON_IDX_FLAG_ENC_END) { + static const struct v4l2_event vpu_event_eos = { + .type = V4L2_EVENT_EOS + }; + + if (!WARN_ON(!dst_buf)) { + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); + dst_buf->field = V4L2_FIELD_NONE; + v4l2_m2m_last_buffer_done(m2m_ctx, dst_buf); + } + + v4l2_event_queue_fh(&inst->v4l2_fh, &vpu_event_eos); + + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + } else { + if (!dst_buf) { + dev_warn(inst->dev->dev, "No bitstream buffer."); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + return; + } + + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, enc_output_info.bitstream_size); + + dst_buf->vb2_buf.timestamp = inst->timestamp; + dst_buf->field = V4L2_FIELD_NONE; + if (enc_output_info.pic_type == PIC_TYPE_I) { + if (inst->std == W_HEVC_ENC && + (enc_output_info.enc_vcl_nut == 19 || + enc_output_info.enc_vcl_nut == 20)) { + dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; + } else if (inst->std == W_AVC_ENC && + enc_output_info.enc_vcl_nut == 5) { + dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; + } else { + dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; + } + } else if (enc_output_info.pic_type == PIC_TYPE_P) { + dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; + } else if (enc_output_info.pic_type == PIC_TYPE_B) { + dst_buf->flags |= V4L2_BUF_FLAG_BFRAME; + } + + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + + dev_dbg(inst->dev->dev, "%s: frame_cycle %8u\n", + __func__, enc_output_info.frame_cycle); + + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); + } +} + +static int wave5_vpu_enc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + strscpy(cap->driver, VPU_ENC_DRV_NAME, sizeof(cap->driver)); + strscpy(cap->card, VPU_ENC_DRV_NAME, sizeof(cap->card)); + + return 0; +} + +static int wave5_vpu_enc_enum_framesizes(struct file *f, void *fh, struct v4l2_frmsizeenum *fsize) +{ + const struct vpu_format *vpu_fmt; + + if (fsize->index) + return -EINVAL; + + vpu_fmt = wave5_find_vpu_fmt(fsize->pixel_format, enc_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) { + vpu_fmt = wave5_find_vpu_fmt(fsize->pixel_format, enc_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + } + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise = enc_frmsize[VPU_FMT_TYPE_CODEC]; + + return 0; +} + +static int wave5_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + + dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index); + + vpu_fmt = wave5_find_vpu_fmt_by_idx(f->index, enc_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) + return -EINVAL; + + f->pixelformat = vpu_fmt->v4l2_pix_fmt; + f->flags = 0; + + return 0; +} + +static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + int width, height; + + dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); + + vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) { + width = inst->dst_fmt.width; + height = inst->dst_fmt.height; + f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; + } else { + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; + } + + wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_CODEC, + width, + height, + vpu_fmt->v4l2_frmsize); + f->fmt.pix_mp.colorspace = inst->colorspace; + f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; + f->fmt.pix_mp.quantization = inst->quantization; + f->fmt.pix_mp.xfer_func = inst->xfer_func; + + return 0; +} + +static int wave5_vpu_enc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + int i, ret; + + dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); + + ret = wave5_vpu_enc_try_fmt_cap(file, fh, f); + if (ret) + return ret; + + inst->std = wave5_to_vpu_std(f->fmt.pix_mp.pixelformat, inst->type); + if (inst->std == STD_UNKNOWN) { + dev_warn(inst->dev->dev, "unsupported pixelformat: %.4s\n", + (char *)&f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + + inst->dst_fmt.width = f->fmt.pix_mp.width; + inst->dst_fmt.height = f->fmt.pix_mp.height; + inst->dst_fmt.pixelformat = f->fmt.pix_mp.pixelformat; + inst->dst_fmt.field = f->fmt.pix_mp.field; + inst->dst_fmt.flags = f->fmt.pix_mp.flags; + inst->dst_fmt.num_planes = f->fmt.pix_mp.num_planes; + for (i = 0; i < inst->dst_fmt.num_planes; i++) { + inst->dst_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline; + inst->dst_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + + return 0; +} + +static int wave5_vpu_enc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + int i; + + f->fmt.pix_mp.width = inst->dst_fmt.width; + f->fmt.pix_mp.height = inst->dst_fmt.height; + f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; + f->fmt.pix_mp.field = inst->dst_fmt.field; + f->fmt.pix_mp.flags = inst->dst_fmt.flags; + f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes; + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { + f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->dst_fmt.plane_fmt[i].bytesperline; + f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->dst_fmt.plane_fmt[i].sizeimage; + } + + f->fmt.pix_mp.colorspace = inst->colorspace; + f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; + f->fmt.pix_mp.quantization = inst->quantization; + f->fmt.pix_mp.xfer_func = inst->xfer_func; + + return 0; +} + +static int wave5_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + + dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index); + + vpu_fmt = wave5_find_vpu_fmt_by_idx(f->index, enc_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + + f->pixelformat = vpu_fmt->v4l2_pix_fmt; + f->flags = 0; + + return 0; +} + +static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + int width, height; + + dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); + + vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) { + width = inst->src_fmt.width; + height = inst->src_fmt.height; + f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat; + } else { + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; + } + + wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_RAW, + width, + height, + vpu_fmt->v4l2_frmsize); + + return 0; +} + +static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + const struct v4l2_format_info *info; + int i, ret; + + dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", + __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); + + ret = wave5_vpu_enc_try_fmt_out(file, fh, f); + if (ret) + return ret; + + inst->src_fmt.width = f->fmt.pix_mp.width; + inst->src_fmt.height = f->fmt.pix_mp.height; + inst->src_fmt.pixelformat = f->fmt.pix_mp.pixelformat; + inst->src_fmt.field = f->fmt.pix_mp.field; + inst->src_fmt.flags = f->fmt.pix_mp.flags; + inst->src_fmt.num_planes = f->fmt.pix_mp.num_planes; + for (i = 0; i < inst->src_fmt.num_planes; i++) { + inst->src_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline; + inst->src_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + + info = v4l2_format_info(inst->src_fmt.pixelformat); + if (!info) + return -EINVAL; + + inst->cbcr_interleave = (info->comp_planes == 2) ? true : false; + + switch (inst->src_fmt.pixelformat) { + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV21M: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV61M: + inst->nv21 = true; + break; + default: + inst->nv21 = false; + } + + inst->colorspace = f->fmt.pix_mp.colorspace; + inst->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + inst->quantization = f->fmt.pix_mp.quantization; + inst->xfer_func = f->fmt.pix_mp.xfer_func; + + vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) + return -EINVAL; + + wave5_update_pix_fmt(&inst->dst_fmt, VPU_FMT_TYPE_CODEC, + f->fmt.pix_mp.width, + f->fmt.pix_mp.height, + vpu_fmt->v4l2_frmsize); + inst->conf_win.width = inst->dst_fmt.width; + inst->conf_win.height = inst->dst_fmt.height; + + return 0; +} + +static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + + dev_dbg(inst->dev->dev, "%s: type: %u | target: %u\n", __func__, s->type, s->target); + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + switch (s->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->dst_fmt.width; + s->r.height = inst->dst_fmt.height; + break; + case V4L2_SEL_TGT_CROP: + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->conf_win.width; + s->r.height = inst->conf_win.height; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + if (s->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + dev_dbg(inst->dev->dev, "%s: V4L2_SEL_TGT_CROP width: %u | height: %u\n", + __func__, s->r.width, s->r.height); + + s->r.left = 0; + s->r.top = 0; + s->r.width = min(s->r.width, inst->dst_fmt.width); + s->r.height = min(s->r.height, inst->dst_fmt.height); + + inst->conf_win = s->r; + + return 0; +} + +static int wave5_vpu_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret; + + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); + if (ret) + return ret; + + if (!wave5_vpu_both_queues_are_streaming(inst)) + return 0; + + switch (ec->cmd) { + case V4L2_ENC_CMD_STOP: + if (m2m_ctx->is_draining) + return -EBUSY; + + if (m2m_ctx->has_stopped) + return 0; + + m2m_ctx->last_src_buf = v4l2_m2m_last_src_buf(m2m_ctx); + m2m_ctx->is_draining = true; + break; + case V4L2_ENC_CMD_START: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wave5_vpu_enc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + + dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, a->type); + + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + a->parm.output.timeperframe.numerator = 1; + a->parm.output.timeperframe.denominator = inst->frame_rate; + + dev_dbg(inst->dev->dev, "%s: numerator: %u | denominator: %u\n", + __func__, a->parm.output.timeperframe.numerator, + a->parm.output.timeperframe.denominator); + + return 0; +} + +static int wave5_vpu_enc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct vpu_instance *inst = wave5_to_vpu_inst(fh); + + dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, a->type); + + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + if (a->parm.output.timeperframe.denominator && a->parm.output.timeperframe.numerator) { + inst->frame_rate = a->parm.output.timeperframe.denominator / + a->parm.output.timeperframe.numerator; + } else { + a->parm.output.timeperframe.numerator = 1; + a->parm.output.timeperframe.denominator = inst->frame_rate; + } + + dev_dbg(inst->dev->dev, "%s: numerator: %u | denominator: %u\n", + __func__, a->parm.output.timeperframe.numerator, + a->parm.output.timeperframe.denominator); + + return 0; +} + +static const struct v4l2_ioctl_ops wave5_vpu_enc_ioctl_ops = { + .vidioc_querycap = wave5_vpu_enc_querycap, + .vidioc_enum_framesizes = wave5_vpu_enc_enum_framesizes, + + .vidioc_enum_fmt_vid_cap = wave5_vpu_enc_enum_fmt_cap, + .vidioc_s_fmt_vid_cap_mplane = wave5_vpu_enc_s_fmt_cap, + .vidioc_g_fmt_vid_cap_mplane = wave5_vpu_enc_g_fmt_cap, + .vidioc_try_fmt_vid_cap_mplane = wave5_vpu_enc_try_fmt_cap, + + .vidioc_enum_fmt_vid_out = wave5_vpu_enc_enum_fmt_out, + .vidioc_s_fmt_vid_out_mplane = wave5_vpu_enc_s_fmt_out, + .vidioc_g_fmt_vid_out_mplane = wave5_vpu_g_fmt_out, + .vidioc_try_fmt_vid_out_mplane = wave5_vpu_enc_try_fmt_out, + + .vidioc_g_selection = wave5_vpu_enc_g_selection, + .vidioc_s_selection = wave5_vpu_enc_s_selection, + + .vidioc_g_parm = wave5_vpu_enc_g_parm, + .vidioc_s_parm = wave5_vpu_enc_s_parm, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = wave5_vpu_enc_encoder_cmd, + + .vidioc_subscribe_event = wave5_vpu_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int wave5_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vpu_instance *inst = wave5_ctrl_to_vpu_inst(ctrl); + + dev_dbg(inst->dev->dev, "%s: name: %s | value: %d\n", __func__, ctrl->name, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_AU_DELIMITER: + inst->encode_aud = ctrl->val; + break; + case V4L2_CID_HFLIP: + inst->mirror_direction |= (ctrl->val << 1); + break; + case V4L2_CID_VFLIP: + inst->mirror_direction |= ctrl->val; + break; + case V4L2_CID_ROTATE: + inst->rot_angle = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VBV_SIZE: + inst->vbv_buf_size = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR: + inst->rc_mode = 0; + break; + case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR: + inst->rc_mode = 1; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + if (inst->state == VPU_INST_STATE_PIC_RUN) + inst->change_param_flags |= W5_ENC_CHANGE_PARAM_RC_TARGET_RATE; + inst->bit_rate = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + inst->enc_param.avc_idr_period = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: + inst->enc_param.independ_slice_mode = ctrl->val; + inst->enc_param.avc_slice_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: + inst->enc_param.independ_slice_mode_arg = ctrl->val; + inst->enc_param.avc_slice_arg = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: + inst->rc_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: + inst->enc_param.mb_level_rc_enable = ctrl->val; + inst->enc_param.cu_level_rc_enable = ctrl->val; + inst->enc_param.hvs_qp_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: + inst->enc_param.profile = HEVC_PROFILE_MAIN; + inst->bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: + inst->enc_param.profile = HEVC_PROFILE_STILLPICTURE; + inst->enc_param.en_still_picture = 1; + inst->bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10: + inst->enc_param.profile = HEVC_PROFILE_MAIN10; + inst->bit_depth = 10; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_LEVEL_1: + inst->enc_param.level = 10 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2: + inst->enc_param.level = 20 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1: + inst->enc_param.level = 21 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3: + inst->enc_param.level = 30 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1: + inst->enc_param.level = 31 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4: + inst->enc_param.level = 40 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1: + inst->enc_param.level = 41 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5: + inst->enc_param.level = 50 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1: + inst->enc_param.level = 51 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2: + inst->enc_param.level = 52 * 3; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: + inst->enc_param.min_qp_i = ctrl->val; + inst->enc_param.min_qp_p = ctrl->val; + inst->enc_param.min_qp_b = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: + inst->enc_param.max_qp_i = ctrl->val; + inst->enc_param.max_qp_p = ctrl->val; + inst->enc_param.max_qp_b = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: + inst->enc_param.intra_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED: + inst->enc_param.disable_deblk = 1; + inst->enc_param.sao_enable = 0; + inst->enc_param.lf_cross_slice_boundary_enable = 0; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED: + inst->enc_param.disable_deblk = 0; + inst->enc_param.sao_enable = 1; + inst->enc_param.lf_cross_slice_boundary_enable = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: + inst->enc_param.disable_deblk = 0; + inst->enc_param.sao_enable = 1; + inst->enc_param.lf_cross_slice_boundary_enable = 0; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: + inst->enc_param.beta_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: + inst->enc_param.tc_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE: + inst->enc_param.decoding_refresh_type = 0; + break; + case V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA: + inst->enc_param.decoding_refresh_type = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR: + inst->enc_param.decoding_refresh_type = 2; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: + inst->enc_param.intra_period = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: + inst->enc_param.lossless_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: + inst->enc_param.const_intra_pred_flag = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: + inst->enc_param.wpp_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: + inst->enc_param.strong_intra_smooth_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: + inst->enc_param.max_num_merge = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: + inst->enc_param.tmvp_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + inst->enc_param.profile = H264_PROFILE_BP; + inst->bit_depth = 8; + if (ctrl->val == V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) + inst->enc_param.constraint_set1_flag = 1; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + inst->enc_param.profile = H264_PROFILE_MP; + inst->bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: + inst->enc_param.profile = H264_PROFILE_EXTENDED; + inst->bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + inst->enc_param.profile = H264_PROFILE_HP; + inst->bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: + inst->enc_param.profile = H264_PROFILE_HIGH10; + inst->bit_depth = 10; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: + inst->enc_param.profile = H264_PROFILE_HIGH422; + inst->bit_depth = 10; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: + inst->enc_param.profile = H264_PROFILE_HIGH444; + inst->bit_depth = 10; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + inst->enc_param.level = 10; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + inst->enc_param.level = 9; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + inst->enc_param.level = 11; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + inst->enc_param.level = 12; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + inst->enc_param.level = 13; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + inst->enc_param.level = 20; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + inst->enc_param.level = 21; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + inst->enc_param.level = 22; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + inst->enc_param.level = 30; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + inst->enc_param.level = 31; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + inst->enc_param.level = 32; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + inst->enc_param.level = 40; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + inst->enc_param.level = 41; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + inst->enc_param.level = 42; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + inst->enc_param.level = 50; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + inst->enc_param.level = 51; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: + inst->enc_param.min_qp_i = ctrl->val; + inst->enc_param.min_qp_p = ctrl->val; + inst->enc_param.min_qp_b = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: + inst->enc_param.max_qp_i = ctrl->val; + inst->enc_param.max_qp_p = ctrl->val; + inst->enc_param.max_qp_b = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: + inst->enc_param.intra_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED: + inst->enc_param.disable_deblk = 1; + inst->enc_param.lf_cross_slice_boundary_enable = 1; + break; + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED: + inst->enc_param.disable_deblk = 0; + inst->enc_param.lf_cross_slice_boundary_enable = 1; + break; + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: + inst->enc_param.disable_deblk = 0; + inst->enc_param.lf_cross_slice_boundary_enable = 0; + break; + default: + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: + inst->enc_param.beta_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: + inst->enc_param.tc_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: + inst->enc_param.transform8x8_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: + inst->enc_param.const_intra_pred_flag = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: + inst->enc_param.chroma_cb_qp_offset = ctrl->val; + inst->enc_param.chroma_cr_qp_offset = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: + inst->enc_param.intra_period = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + inst->enc_param.entropy_coding_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: + inst->enc_param.forced_idr_header_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: + inst->enc_param.forced_idr_pictype_enable = 1; + break; + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops wave5_vpu_enc_ctrl_ops = { + .s_ctrl = wave5_vpu_enc_s_ctrl, +}; + +static int wave5_vpu_enc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_pix_format_mplane inst_format = + (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt; + unsigned int i; + + dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n", __func__, + *num_buffers, *num_planes, q->type); + + if (*num_planes) { + if (inst_format.num_planes != *num_planes) + return -EINVAL; + + for (i = 0; i < *num_planes; i++) { + if (sizes[i] < inst_format.plane_fmt[i].sizeimage) + return -EINVAL; + } + } else { + *num_planes = inst_format.num_planes; + for (i = 0; i < *num_planes; i++) { + sizes[i] = inst_format.plane_fmt[i].sizeimage; + dev_dbg(inst->dev->dev, "%s: size[%u]: %u\n", __func__, i, sizes[i]); + } + } + + dev_dbg(inst->dev->dev, "%s: size: %u\n", __func__, sizes[0]); + + return 0; +} + +static void wave5_vpu_enc_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + dev_dbg(inst->dev->dev, "%s: type: %4u index: %4u size: ([0]=%4lu, [1]=%4lu, [2]=%4lu)\n", + __func__, vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0), + vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2)); + + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + vbuf->sequence = inst->queued_src_buf_num++; + else + vbuf->sequence = inst->queued_dst_buf_num++; + + v4l2_m2m_buf_queue(m2m_ctx, vbuf); +} + +static int wave5_set_enc_openparam(struct enc_open_param *open_param, + struct vpu_instance *inst) +{ + struct enc_wave_param input = inst->enc_param; + const struct v4l2_format_info *info; + u32 num_ctu_row = ALIGN(inst->dst_fmt.height, 64) / 64; + u32 num_mb_row = ALIGN(inst->dst_fmt.height, 16) / 16; + + info = v4l2_format_info(inst->src_fmt.pixelformat); + if (!info) + return -EINVAL; + + if (info->hdiv == 2 && info->vdiv == 1) + open_param->src_format = FORMAT_422; + else + open_param->src_format = FORMAT_420; + + open_param->wave_param.gop_preset_idx = PRESET_IDX_IPP_SINGLE; + open_param->wave_param.hvs_qp_scale = 2; + open_param->wave_param.hvs_max_delta_qp = 10; + open_param->wave_param.skip_intra_trans = 1; + open_param->wave_param.intra_nx_n_enable = 1; + open_param->wave_param.nr_intra_weight_y = 7; + open_param->wave_param.nr_intra_weight_cb = 7; + open_param->wave_param.nr_intra_weight_cr = 7; + open_param->wave_param.nr_inter_weight_y = 4; + open_param->wave_param.nr_inter_weight_cb = 4; + open_param->wave_param.nr_inter_weight_cr = 4; + open_param->wave_param.rdo_skip = 1; + open_param->wave_param.lambda_scaling_enable = 1; + + open_param->line_buf_int_en = true; + open_param->pic_width = inst->conf_win.width; + open_param->pic_height = inst->conf_win.height; + open_param->frame_rate_info = inst->frame_rate; + open_param->rc_enable = inst->rc_enable; + if (inst->rc_enable) { + open_param->wave_param.initial_rc_qp = -1; + open_param->wave_param.rc_weight_param = 16; + open_param->wave_param.rc_weight_buf = 128; + } + open_param->wave_param.mb_level_rc_enable = input.mb_level_rc_enable; + open_param->wave_param.cu_level_rc_enable = input.cu_level_rc_enable; + open_param->wave_param.hvs_qp_enable = input.hvs_qp_enable; + open_param->bit_rate = inst->bit_rate; + open_param->vbv_buffer_size = inst->vbv_buf_size; + if (inst->rc_mode == 0) + open_param->vbv_buffer_size = 3000; + open_param->wave_param.profile = input.profile; + open_param->wave_param.en_still_picture = input.en_still_picture; + open_param->wave_param.level = input.level; + open_param->wave_param.internal_bit_depth = inst->bit_depth; + open_param->wave_param.intra_qp = input.intra_qp; + open_param->wave_param.min_qp_i = input.min_qp_i; + open_param->wave_param.max_qp_i = input.max_qp_i; + open_param->wave_param.min_qp_p = input.min_qp_p; + open_param->wave_param.max_qp_p = input.max_qp_p; + open_param->wave_param.min_qp_b = input.min_qp_b; + open_param->wave_param.max_qp_b = input.max_qp_b; + open_param->wave_param.disable_deblk = input.disable_deblk; + open_param->wave_param.lf_cross_slice_boundary_enable = + input.lf_cross_slice_boundary_enable; + open_param->wave_param.tc_offset_div2 = input.tc_offset_div2; + open_param->wave_param.beta_offset_div2 = input.beta_offset_div2; + open_param->wave_param.decoding_refresh_type = input.decoding_refresh_type; + open_param->wave_param.intra_period = input.intra_period; + if (inst->std == W_HEVC_ENC) { + if (input.intra_period == 0) { + open_param->wave_param.decoding_refresh_type = DEC_REFRESH_TYPE_IDR; + open_param->wave_param.intra_period = input.avc_idr_period; + } + } else if (inst->std == W_AVC_ENC) + open_param->wave_param.constraint_set1_flag = input.constraint_set1_flag; + else + open_param->wave_param.avc_idr_period = input.avc_idr_period; + open_param->wave_param.entropy_coding_mode = input.entropy_coding_mode; + open_param->wave_param.lossless_enable = input.lossless_enable; + open_param->wave_param.const_intra_pred_flag = input.const_intra_pred_flag; + open_param->wave_param.wpp_enable = input.wpp_enable; + open_param->wave_param.strong_intra_smooth_enable = input.strong_intra_smooth_enable; + open_param->wave_param.max_num_merge = input.max_num_merge; + open_param->wave_param.tmvp_enable = input.tmvp_enable; + open_param->wave_param.transform8x8_enable = input.transform8x8_enable; + open_param->wave_param.chroma_cb_qp_offset = input.chroma_cb_qp_offset; + open_param->wave_param.chroma_cr_qp_offset = input.chroma_cr_qp_offset; + open_param->wave_param.independ_slice_mode = input.independ_slice_mode; + open_param->wave_param.independ_slice_mode_arg = input.independ_slice_mode_arg; + open_param->wave_param.avc_slice_mode = input.avc_slice_mode; + open_param->wave_param.avc_slice_arg = input.avc_slice_arg; + open_param->wave_param.intra_mb_refresh_mode = input.intra_mb_refresh_mode; + if (input.intra_mb_refresh_mode != REFRESH_MB_MODE_NONE) { + if (num_mb_row >= input.intra_mb_refresh_arg) + open_param->wave_param.intra_mb_refresh_arg = + num_mb_row / input.intra_mb_refresh_arg; + else + open_param->wave_param.intra_mb_refresh_arg = num_mb_row; + } + open_param->wave_param.intra_refresh_mode = input.intra_refresh_mode; + if (input.intra_refresh_mode != 0) { + if (num_ctu_row >= input.intra_refresh_arg) + open_param->wave_param.intra_refresh_arg = + num_ctu_row / input.intra_refresh_arg; + else + open_param->wave_param.intra_refresh_arg = num_ctu_row; + } + open_param->wave_param.forced_idr_header_enable = input.forced_idr_header_enable; + + return 0; +} + +static int initialize_sequence(struct vpu_instance *inst) +{ + struct enc_initial_info initial_info; + struct v4l2_ctrl *ctrl; + int ret; + + ret = wave5_vpu_enc_issue_seq_init(inst); + if (ret) { + dev_err(inst->dev->dev, "%s: wave5_vpu_enc_issue_seq_init, fail: %d\n", + __func__, ret); + return ret; + } + + if (wave5_vpu_wait_interrupt(inst, VPU_ENC_TIMEOUT) < 0) { + dev_err(inst->dev->dev, "%s: wave5_vpu_wait_interrupt failed\n", __func__); + return -EINVAL; + } + + ret = wave5_vpu_enc_complete_seq_init(inst, &initial_info); + if (ret) + return ret; + + dev_dbg(inst->dev->dev, "%s: min_frame_buffer: %u | min_source_buffer: %u\n", + __func__, initial_info.min_frame_buffer_count, + initial_info.min_src_frame_count); + inst->min_src_buf_count = initial_info.min_src_frame_count + + COMMAND_QUEUE_DEPTH; + + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, inst->min_src_buf_count); + + inst->fbc_buf_count = initial_info.min_frame_buffer_count; + + return 0; +} + +static int prepare_fb(struct vpu_instance *inst) +{ + u32 fb_stride = ALIGN(inst->dst_fmt.width, 32); + u32 fb_height = ALIGN(inst->dst_fmt.height, 32); + int i, ret = 0; + + for (i = 0; i < inst->fbc_buf_count; i++) { + u32 luma_size = fb_stride * fb_height; + u32 chroma_size = ALIGN(fb_stride / 2, 16) * fb_height; + + inst->frame_vbuf[i].size = luma_size + chroma_size; + ret = wave5_vdi_allocate_dma_memory(inst->dev, &inst->frame_vbuf[i]); + if (ret < 0) { + dev_err(inst->dev->dev, "%s: failed to allocate FBC buffer %zu\n", + __func__, inst->frame_vbuf[i].size); + goto free_buffers; + } + + inst->frame_buf[i].buf_y = inst->frame_vbuf[i].daddr; + inst->frame_buf[i].buf_cb = (dma_addr_t)-1; + inst->frame_buf[i].buf_cr = (dma_addr_t)-1; + inst->frame_buf[i].update_fb_info = true; + inst->frame_buf[i].size = inst->frame_vbuf[i].size; + } + + ret = wave5_vpu_enc_register_frame_buffer(inst, inst->fbc_buf_count, fb_stride, + fb_height, COMPRESSED_FRAME_MAP); + if (ret) { + dev_err(inst->dev->dev, + "%s: wave5_vpu_enc_register_frame_buffer, fail: %d\n", + __func__, ret); + goto free_buffers; + } + + return 0; +free_buffers: + for (i = 0; i < inst->fbc_buf_count; i++) + wave5_vpu_dec_reset_framebuffer(inst, i); + return ret; +} + +static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret = 0; + + pm_runtime_resume_and_get(inst->dev->dev); + v4l2_m2m_update_start_streaming_state(m2m_ctx, q); + + if (inst->state == VPU_INST_STATE_NONE && q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + struct enc_open_param open_param; + + memset(&open_param, 0, sizeof(struct enc_open_param)); + + ret = wave5_set_enc_openparam(&open_param, inst); + if (ret) { + dev_dbg(inst->dev->dev, "%s: wave5_set_enc_openparam, fail: %d\n", + __func__, ret); + goto return_buffers; + } + + ret = wave5_vpu_enc_open(inst, &open_param); + if (ret) { + dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_open, fail: %d\n", + __func__, ret); + goto return_buffers; + } + + if (inst->mirror_direction) { + wave5_vpu_enc_give_command(inst, ENABLE_MIRRORING, NULL); + wave5_vpu_enc_give_command(inst, SET_MIRROR_DIRECTION, + &inst->mirror_direction); + } + if (inst->rot_angle) { + wave5_vpu_enc_give_command(inst, ENABLE_ROTATION, NULL); + wave5_vpu_enc_give_command(inst, SET_ROTATION_ANGLE, &inst->rot_angle); + } + + ret = switch_state(inst, VPU_INST_STATE_OPEN); + if (ret) + goto return_buffers; + } + if (inst->state == VPU_INST_STATE_OPEN && m2m_ctx->cap_q_ctx.q.streaming) { + ret = initialize_sequence(inst); + if (ret) { + dev_warn(inst->dev->dev, "Sequence not found: %d\n", ret); + goto return_buffers; + } + ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ); + if (ret) + goto return_buffers; + /* + * The sequence must be analyzed first to calculate the proper + * size of the auxiliary buffers. + */ + ret = prepare_fb(inst); + if (ret) { + dev_warn(inst->dev->dev, "Framebuffer preparation, fail: %d\n", ret); + goto return_buffers; + } + + ret = switch_state(inst, VPU_INST_STATE_PIC_RUN); + } + if (ret) + goto return_buffers; + + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); + return 0; +return_buffers: + wave5_return_bufs(q, VB2_BUF_STATE_QUEUED); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); + return ret; +} + +static void streamoff_output(struct vpu_instance *inst, struct vb2_queue *q) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_v4l2_buffer *buf; + + while ((buf = v4l2_m2m_src_buf_remove(m2m_ctx))) { + dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n", + __func__, buf->vb2_buf.type, buf->vb2_buf.index); + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + } +} + +static void streamoff_capture(struct vpu_instance *inst, struct vb2_queue *q) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + struct vb2_v4l2_buffer *buf; + + while ((buf = v4l2_m2m_dst_buf_remove(m2m_ctx))) { + dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n", + __func__, buf->vb2_buf.type, buf->vb2_buf.index); + vb2_set_plane_payload(&buf->vb2_buf, 0, 0); + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + } + + v4l2_m2m_clear_state(m2m_ctx); +} + +static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + bool check_cmd = true; + + /* + * Note that we don't need m2m_ctx->next_buf_last for this driver, so we + * don't call v4l2_m2m_update_stop_streaming_state(). + */ + + dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); + pm_runtime_resume_and_get(inst->dev->dev); + + if (wave5_vpu_both_queues_are_streaming(inst)) + switch_state(inst, VPU_INST_STATE_STOP); + + while (check_cmd) { + struct queue_status_info q_status; + struct enc_output_info enc_output_info; + + wave5_vpu_enc_give_command(inst, ENC_GET_QUEUE_STATUS, &q_status); + + if (q_status.report_queue_count == 0) + break; + + if (wave5_vpu_wait_interrupt(inst, VPU_ENC_TIMEOUT) < 0) + break; + + if (wave5_vpu_enc_get_output_info(inst, &enc_output_info)) + dev_dbg(inst->dev->dev, "Getting encoding results from fw, fail\n"); + } + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + streamoff_output(inst, q); + else + streamoff_capture(inst, q); + + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); +} + +static const struct vb2_ops wave5_vpu_enc_vb2_ops = { + .queue_setup = wave5_vpu_enc_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_queue = wave5_vpu_enc_buf_queue, + .start_streaming = wave5_vpu_enc_start_streaming, + .stop_streaming = wave5_vpu_enc_stop_streaming, +}; + +static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, + struct v4l2_pix_format_mplane *dst_fmt) +{ + src_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; + wave5_update_pix_fmt(src_fmt, VPU_FMT_TYPE_RAW, + W5_DEF_ENC_PIC_WIDTH, + W5_DEF_ENC_PIC_HEIGHT, + &enc_frmsize[VPU_FMT_TYPE_RAW]); + + dst_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt; + wave5_update_pix_fmt(dst_fmt, VPU_FMT_TYPE_CODEC, + W5_DEF_ENC_PIC_WIDTH, + W5_DEF_ENC_PIC_HEIGHT, + &enc_frmsize[VPU_FMT_TYPE_CODEC]); +} + +static int wave5_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + return wave5_vpu_queue_init(priv, src_vq, dst_vq, &wave5_vpu_enc_vb2_ops); +} + +static const struct vpu_instance_ops wave5_vpu_enc_inst_ops = { + .finish_process = wave5_vpu_enc_finish_encode, +}; + +static void wave5_vpu_enc_device_run(void *priv) +{ + struct vpu_instance *inst = priv; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + u32 fail_res = 0; + int ret = 0; + + pm_runtime_resume_and_get(inst->dev->dev); + switch (inst->state) { + case VPU_INST_STATE_PIC_RUN: + ret = start_encode(inst, &fail_res); + if (ret) { + if (ret == -EINVAL) + dev_err(inst->dev->dev, + "Frame encoding on m2m context (%p), fail: %d (res: %d)\n", + m2m_ctx, ret, fail_res); + else if (ret == -EAGAIN) + dev_dbg(inst->dev->dev, "Missing buffers for encode, try again\n"); + break; + } + dev_dbg(inst->dev->dev, "%s: leave with active job", __func__); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); + return; + default: + WARN(1, "Execution of a job in state %s is invalid.\n", + state_to_str(inst->state)); + break; + } + dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); +} + +static int wave5_vpu_enc_job_ready(void *priv) +{ + struct vpu_instance *inst = priv; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + switch (inst->state) { + case VPU_INST_STATE_NONE: + dev_dbg(inst->dev->dev, "Encoder must be open to start queueing M2M jobs!\n"); + return false; + case VPU_INST_STATE_PIC_RUN: + if (m2m_ctx->is_draining || v4l2_m2m_num_src_bufs_ready(m2m_ctx)) { + dev_dbg(inst->dev->dev, "Encoder ready for a job, state: %s\n", + state_to_str(inst->state)); + return true; + } + fallthrough; + default: + dev_dbg(inst->dev->dev, + "Encoder not ready for a job, state: %s, %s draining, %d src bufs ready\n", + state_to_str(inst->state), m2m_ctx->is_draining ? "is" : "is not", + v4l2_m2m_num_src_bufs_ready(m2m_ctx)); + break; + } + return false; +} + +static const struct v4l2_m2m_ops wave5_vpu_enc_m2m_ops = { + .device_run = wave5_vpu_enc_device_run, + .job_ready = wave5_vpu_enc_job_ready, +}; + +static int wave5_vpu_open_enc(struct file *filp) +{ + struct video_device *vdev = video_devdata(filp); + struct vpu_device *dev = video_drvdata(filp); + struct vpu_instance *inst = NULL; + struct v4l2_ctrl_handler *v4l2_ctrl_hdl; + int ret = 0; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + v4l2_ctrl_hdl = &inst->v4l2_ctrl_hdl; + + inst->dev = dev; + inst->type = VPU_INST_TYPE_ENC; + inst->ops = &wave5_vpu_enc_inst_ops; + + inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); + if (!inst->codec_info) + return -ENOMEM; + + v4l2_fh_init(&inst->v4l2_fh, vdev); + filp->private_data = &inst->v4l2_fh; + v4l2_fh_add(&inst->v4l2_fh); + + INIT_LIST_HEAD(&inst->list); + + inst->v4l2_m2m_dev = inst->dev->v4l2_m2m_enc_dev; + inst->v4l2_fh.m2m_ctx = + v4l2_m2m_ctx_init(inst->v4l2_m2m_dev, inst, wave5_vpu_enc_queue_init); + if (IS_ERR(inst->v4l2_fh.m2m_ctx)) { + ret = PTR_ERR(inst->v4l2_fh.m2m_ctx); + goto cleanup_inst; + } + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, true); + + v4l2_ctrl_handler_init(v4l2_ctrl_hdl, 50); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, 0, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, 0, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + 0, 63, 1, 8); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + 0, 63, 1, 51); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + 0, 63, 1, 30); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2, + -6, 6, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2, + -6, 6, 1, 0); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE, + V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR, 0, + V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD, + 0, 2047, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING, + 0, 1, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1, + 1, 2, 1, 2); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION, + 0, 1, 1, 1); + + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE, 0, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + V4L2_MPEG_VIDEO_H264_LEVEL_5_1, 0, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + 0, 63, 1, 8); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + 0, 63, 1, 51); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + 0, 63, 1, 30); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, + -6, 6, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, + -6, 6, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + -12, 12, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, + 0, 2047, 1, 0); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, 0, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, + 0, 1, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_HFLIP, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_VFLIP, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_ROTATE, + 0, 270, 90, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VBV_SIZE, + 10, 3000, 1, 1000); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE, + 0, 700000000, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + 0, 2047, 1, 0); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB, 0, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + 0, 0xFFFF, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + 0, 0, 0, 0); + + if (v4l2_ctrl_hdl->error) { + ret = -ENODEV; + goto cleanup_inst; + } + + inst->v4l2_fh.ctrl_handler = v4l2_ctrl_hdl; + v4l2_ctrl_handler_setup(v4l2_ctrl_hdl); + + wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt); + inst->conf_win.width = inst->dst_fmt.width; + inst->conf_win.height = inst->dst_fmt.height; + inst->colorspace = V4L2_COLORSPACE_REC709; + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + inst->quantization = V4L2_QUANTIZATION_DEFAULT; + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT; + inst->frame_rate = 30; + + init_completion(&inst->irq_done); + + inst->id = ida_alloc(&inst->dev->inst_ida, GFP_KERNEL); + if (inst->id < 0) { + dev_warn(inst->dev->dev, "Allocating instance ID, fail: %d\n", inst->id); + ret = inst->id; + goto cleanup_inst; + } + + wave5_vdi_allocate_sram(inst->dev); + + ret = mutex_lock_interruptible(&dev->dev_lock); + if (ret) + goto cleanup_inst; + + list_add_tail(&inst->list, &dev->instances); + + mutex_unlock(&dev->dev_lock); + + return 0; + +cleanup_inst: + wave5_cleanup_instance(inst); + return ret; +} + +static int wave5_vpu_enc_release(struct file *filp) +{ + return wave5_vpu_release_device(filp, wave5_vpu_enc_close, "encoder"); +} + +static const struct v4l2_file_operations wave5_vpu_enc_fops = { + .owner = THIS_MODULE, + .open = wave5_vpu_open_enc, + .release = wave5_vpu_enc_release, + .unlocked_ioctl = video_ioctl2, + .poll = v4l2_m2m_fop_poll, + .mmap = v4l2_m2m_fop_mmap, +}; + +int wave5_vpu_enc_register_device(struct vpu_device *dev) +{ + struct video_device *vdev_enc; + int ret; + + vdev_enc = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_enc), GFP_KERNEL); + if (!vdev_enc) + return -ENOMEM; + + dev->v4l2_m2m_enc_dev = v4l2_m2m_init(&wave5_vpu_enc_m2m_ops); + if (IS_ERR(dev->v4l2_m2m_enc_dev)) { + ret = PTR_ERR(dev->v4l2_m2m_enc_dev); + dev_err(dev->dev, "v4l2_m2m_init, fail: %d\n", ret); + return -EINVAL; + } + + dev->video_dev_enc = vdev_enc; + + strscpy(vdev_enc->name, VPU_ENC_DEV_NAME, sizeof(vdev_enc->name)); + vdev_enc->fops = &wave5_vpu_enc_fops; + vdev_enc->ioctl_ops = &wave5_vpu_enc_ioctl_ops; + vdev_enc->release = video_device_release_empty; + vdev_enc->v4l2_dev = &dev->v4l2_dev; + vdev_enc->vfl_dir = VFL_DIR_M2M; + vdev_enc->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + vdev_enc->lock = &dev->dev_lock; + + ret = video_register_device(vdev_enc, VFL_TYPE_VIDEO, -1); + if (ret) + return ret; + + video_set_drvdata(vdev_enc, dev); + + return 0; +} + +void wave5_vpu_enc_unregister_device(struct vpu_device *dev) +{ + video_unregister_device(dev->video_dev_enc); + if (dev->v4l2_m2m_enc_dev) + v4l2_m2m_release(dev->v4l2_m2m_enc_dev); +} diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-vpuerror.h b/drivers/media/platform/chips-media/wave5/wave5-vpuerror.h --- a/drivers/media/platform/chips-media/wave5/wave5-vpuerror.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuerror.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - error values + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ + +#ifndef ERROR_CODE_H_INCLUDED +#define ERROR_CODE_H_INCLUDED + +/* + * WAVE5 + */ + +/************************************************************************/ +/* WAVE5 COMMON SYSTEM ERROR (FAIL_REASON) */ +/************************************************************************/ +#define WAVE5_SYSERR_QUEUEING_FAIL 0x00000001 +#define WAVE5_SYSERR_ACCESS_VIOLATION_HW 0x00000040 +#define WAVE5_SYSERR_BUS_ERROR 0x00000200 +#define WAVE5_SYSERR_DOUBLE_FAULT 0x00000400 +#define WAVE5_SYSERR_RESULT_NOT_READY 0x00000800 +#define WAVE5_SYSERR_VPU_STILL_RUNNING 0x00001000 +#define WAVE5_SYSERR_UNKNOWN_CMD 0x00002000 +#define WAVE5_SYSERR_UNKNOWN_CODEC_STD 0x00004000 +#define WAVE5_SYSERR_UNKNOWN_QUERY_OPTION 0x00008000 +#define WAVE5_SYSERR_VLC_BUF_FULL 0x00010000 +#define WAVE5_SYSERR_WATCHDOG_TIMEOUT 0x00020000 +#define WAVE5_SYSERR_VCPU_TIMEOUT 0x00080000 +#define WAVE5_SYSERR_TEMP_SEC_BUF_OVERFLOW 0x00200000 +#define WAVE5_SYSERR_NEED_MORE_TASK_BUF 0x00400000 +#define WAVE5_SYSERR_PRESCAN_ERR 0x00800000 +#define WAVE5_SYSERR_ENC_GBIN_OVERCONSUME 0x01000000 +#define WAVE5_SYSERR_ENC_MAX_ZERO_DETECT 0x02000000 +#define WAVE5_SYSERR_ENC_LVL_FIRST_ERROR 0x04000000 +#define WAVE5_SYSERR_ENC_EG_RANGE_OVER 0x08000000 +#define WAVE5_SYSERR_ENC_IRB_FRAME_DROP 0x10000000 +#define WAVE5_SYSERR_INPLACE_V 0x20000000 +#define WAVE5_SYSERR_FATAL_VPU_HANGUP 0xf0000000 + +/************************************************************************/ +/* WAVE5 COMMAND QUEUE ERROR (FAIL_REASON) */ +/************************************************************************/ +#define WAVE5_CMDQ_ERR_NOT_QUEABLE_CMD 0x00000001 +#define WAVE5_CMDQ_ERR_SKIP_MODE_ENABLE 0x00000002 +#define WAVE5_CMDQ_ERR_INST_FLUSHING 0x00000003 +#define WAVE5_CMDQ_ERR_INST_INACTIVE 0x00000004 +#define WAVE5_CMDQ_ERR_QUEUE_FAIL 0x00000005 +#define WAVE5_CMDQ_ERR_CMD_BUF_FULL 0x00000006 + +/************************************************************************/ +/* WAVE5 ERROR ON DECODER (ERR_INFO) */ +/************************************************************************/ +// HEVC +#define HEVC_SPSERR_SEQ_PARAMETER_SET_ID 0x00001000 +#define HEVC_SPSERR_CHROMA_FORMAT_IDC 0x00001001 +#define HEVC_SPSERR_PIC_WIDTH_IN_LUMA_SAMPLES 0x00001002 +#define HEVC_SPSERR_PIC_HEIGHT_IN_LUMA_SAMPLES 0x00001003 +#define HEVC_SPSERR_CONF_WIN_LEFT_OFFSET 0x00001004 +#define HEVC_SPSERR_CONF_WIN_RIGHT_OFFSET 0x00001005 +#define HEVC_SPSERR_CONF_WIN_TOP_OFFSET 0x00001006 +#define HEVC_SPSERR_CONF_WIN_BOTTOM_OFFSET 0x00001007 +#define HEVC_SPSERR_BIT_DEPTH_LUMA_MINUS8 0x00001008 +#define HEVC_SPSERR_BIT_DEPTH_CHROMA_MINUS8 0x00001009 +#define HEVC_SPSERR_LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4 0x0000100A +#define HEVC_SPSERR_SPS_MAX_DEC_PIC_BUFFERING 0x0000100B +#define HEVC_SPSERR_SPS_MAX_NUM_REORDER_PICS 0x0000100C +#define HEVC_SPSERR_SPS_MAX_LATENCY_INCREASE 0x0000100D +#define HEVC_SPSERR_LOG2_MIN_LUMA_CODING_BLOCK_SIZE_MINUS3 0x0000100E +#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE 0x0000100F +#define HEVC_SPSERR_LOG2_MIN_TRANSFORM_BLOCK_SIZE_MINUS2 0x00001010 +#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_TRANSFORM_BLOCK_SIZE 0x00001011 +#define HEVC_SPSERR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTER 0x00001012 +#define HEVC_SPSERR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA 0x00001013 +#define HEVC_SPSERR_SCALING_LIST 0x00001014 +#define HEVC_SPSERR_LOG2_DIFF_MIN_PCM_LUMA_CODING_BLOCK_SIZE_MINUS3 0x00001015 +#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE 0x00001016 +#define HEVC_SPSERR_NUM_SHORT_TERM_REF_PIC_SETS 0x00001017 +#define HEVC_SPSERR_NUM_LONG_TERM_REF_PICS_SPS 0x00001018 +#define HEVC_SPSERR_GBU_PARSING_ERROR 0x00001019 +#define HEVC_SPSERR_EXTENSION_FLAG 0x0000101A +#define HEVC_SPSERR_VUI_ERROR 0x0000101B +#define HEVC_SPSERR_ACTIVATE_SPS 0x0000101C +#define HEVC_SPSERR_PROFILE_SPACE 0x0000101D +#define HEVC_PPSERR_PPS_PIC_PARAMETER_SET_ID 0x00002000 +#define HEVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID 0x00002001 +#define HEVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1 0x00002002 +#define HEVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1 0x00002003 +#define HEVC_PPSERR_INIT_QP_MINUS26 0x00002004 +#define HEVC_PPSERR_DIFF_CU_QP_DELTA_DEPTH 0x00002005 +#define HEVC_PPSERR_PPS_CB_QP_OFFSET 0x00002006 +#define HEVC_PPSERR_PPS_CR_QP_OFFSET 0x00002007 +#define HEVC_PPSERR_NUM_TILE_COLUMNS_MINUS1 0x00002008 +#define HEVC_PPSERR_NUM_TILE_ROWS_MINUS1 0x00002009 +#define HEVC_PPSERR_COLUMN_WIDTH_MINUS1 0x0000200A +#define HEVC_PPSERR_ROW_HEIGHT_MINUS1 0x0000200B +#define HEVC_PPSERR_PPS_BETA_OFFSET_DIV2 0x0000200C +#define HEVC_PPSERR_PPS_TC_OFFSET_DIV2 0x0000200D +#define HEVC_PPSERR_SCALING_LIST 0x0000200E +#define HEVC_PPSERR_LOG2_PARALLEL_MERGE_LEVEL_MINUS2 0x0000200F +#define HEVC_PPSERR_NUM_TILE_COLUMNS_RANGE_OUT 0x00002010 +#define HEVC_PPSERR_NUM_TILE_ROWS_RANGE_OUT 0x00002011 +#define HEVC_PPSERR_MORE_RBSP_DATA_ERROR 0x00002012 +#define HEVC_PPSERR_PPS_PIC_PARAMETER_SET_ID_RANGE_OUT 0x00002013 +#define HEVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID_RANGE_OUT 0x00002014 +#define HEVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002015 +#define HEVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002016 +#define HEVC_PPSERR_PPS_CB_QP_OFFSET_RANGE_OUT 0x00002017 +#define HEVC_PPSERR_PPS_CR_QP_OFFSET_RANGE_OUT 0x00002018 +#define HEVC_PPSERR_COLUMN_WIDTH_MINUS1_RANGE_OUT 0x00002019 +#define HEVC_PPSERR_ROW_HEIGHT_MINUS1_RANGE_OUT 0x00002020 +#define HEVC_PPSERR_PPS_BETA_OFFSET_DIV2_RANGE_OUT 0x00002021 +#define HEVC_PPSERR_PPS_TC_OFFSET_DIV2_RANGE_OUT 0x00002022 +#define HEVC_SHERR_SLICE_PIC_PARAMETER_SET_ID 0x00003000 +#define HEVC_SHERR_ACTIVATE_PPS 0x00003001 +#define HEVC_SHERR_ACTIVATE_SPS 0x00003002 +#define HEVC_SHERR_SLICE_TYPE 0x00003003 +#define HEVC_SHERR_FIRST_SLICE_IS_DEPENDENT_SLICE 0x00003004 +#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET_SPS_FLAG 0x00003005 +#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET 0x00003006 +#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET_IDX 0x00003007 +#define HEVC_SHERR_NUM_LONG_TERM_SPS 0x00003008 +#define HEVC_SHERR_NUM_LONG_TERM_PICS 0x00003009 +#define HEVC_SHERR_LT_IDX_SPS_IS_OUT_OF_RANGE 0x0000300A +#define HEVC_SHERR_DELTA_POC_MSB_CYCLE_LT 0x0000300B +#define HEVC_SHERR_NUM_REF_IDX_L0_ACTIVE_MINUS1 0x0000300C +#define HEVC_SHERR_NUM_REF_IDX_L1_ACTIVE_MINUS1 0x0000300D +#define HEVC_SHERR_COLLOCATED_REF_IDX 0x0000300E +#define HEVC_SHERR_PRED_WEIGHT_TABLE 0x0000300F +#define HEVC_SHERR_FIVE_MINUS_MAX_NUM_MERGE_CAND 0x00003010 +#define HEVC_SHERR_SLICE_QP_DELTA 0x00003011 +#define HEVC_SHERR_SLICE_QP_DELTA_IS_OUT_OF_RANGE 0x00003012 +#define HEVC_SHERR_SLICE_CB_QP_OFFSET 0x00003013 +#define HEVC_SHERR_SLICE_CR_QP_OFFSET 0x00003014 +#define HEVC_SHERR_SLICE_BETA_OFFSET_DIV2 0x00003015 +#define HEVC_SHERR_SLICE_TC_OFFSET_DIV2 0x00003016 +#define HEVC_SHERR_NUM_ENTRY_POINT_OFFSETS 0x00003017 +#define HEVC_SHERR_OFFSET_LEN_MINUS1 0x00003018 +#define HEVC_SHERR_SLICE_SEGMENT_HEADER_EXTENSION_LENGTH 0x00003019 +#define HEVC_SHERR_WRONG_POC_IN_STILL_PICTURE_PROFILE 0x0000301A +#define HEVC_SHERR_SLICE_TYPE_ERROR_IN_STILL_PICTURE_PROFILE 0x0000301B +#define HEVC_SHERR_PPS_ID_NOT_EQUAL_PREV_VALUE 0x0000301C +#define HEVC_SPECERR_OVER_PICTURE_WIDTH_SIZE 0x00004000 +#define HEVC_SPECERR_OVER_PICTURE_HEIGHT_SIZE 0x00004001 +#define HEVC_SPECERR_OVER_CHROMA_FORMAT 0x00004002 +#define HEVC_SPECERR_OVER_BIT_DEPTH 0x00004003 +#define HEVC_SPECERR_OVER_BUFFER_OVER_FLOW 0x00004004 +#define HEVC_SPECERR_OVER_WRONG_BUFFER_ACCESS 0x00004005 +#define HEVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND 0x00005000 +#define HEVC_ETCERR_DEC_PIC_VCL_NOT_FOUND 0x00005001 +#define HEVC_ETCERR_NO_VALID_SLICE_IN_AU 0x00005002 +#define HEVC_ETCERR_INPLACE_V 0x0000500F + +// AVC +#define AVC_SPSERR_SEQ_PARAMETER_SET_ID 0x00001000 +#define AVC_SPSERR_CHROMA_FORMAT_IDC 0x00001001 +#define AVC_SPSERR_PIC_WIDTH_IN_LUMA_SAMPLES 0x00001002 +#define AVC_SPSERR_PIC_HEIGHT_IN_LUMA_SAMPLES 0x00001003 +#define AVC_SPSERR_CONF_WIN_LEFT_OFFSET 0x00001004 +#define AVC_SPSERR_CONF_WIN_RIGHT_OFFSET 0x00001005 +#define AVC_SPSERR_CONF_WIN_TOP_OFFSET 0x00001006 +#define AVC_SPSERR_CONF_WIN_BOTTOM_OFFSET 0x00001007 +#define AVC_SPSERR_BIT_DEPTH_LUMA_MINUS8 0x00001008 +#define AVC_SPSERR_BIT_DEPTH_CHROMA_MINUS8 0x00001009 +#define AVC_SPSERR_SPS_MAX_DEC_PIC_BUFFERING 0x0000100B +#define AVC_SPSERR_SPS_MAX_NUM_REORDER_PICS 0x0000100C +#define AVC_SPSERR_SCALING_LIST 0x00001014 +#define AVC_SPSERR_GBU_PARSING_ERROR 0x00001019 +#define AVC_SPSERR_VUI_ERROR 0x0000101B +#define AVC_SPSERR_ACTIVATE_SPS 0x0000101C +#define AVC_PPSERR_PPS_PIC_PARAMETER_SET_ID 0x00002000 +#define AVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID 0x00002001 +#define AVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1 0x00002002 +#define AVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1 0x00002003 +#define AVC_PPSERR_INIT_QP_MINUS26 0x00002004 +#define AVC_PPSERR_PPS_CB_QP_OFFSET 0x00002006 +#define AVC_PPSERR_PPS_CR_QP_OFFSET 0x00002007 +#define AVC_PPSERR_SCALING_LIST 0x0000200E +#define AVC_PPSERR_MORE_RBSP_DATA_ERROR 0x00002012 +#define AVC_PPSERR_PPS_PIC_PARAMETER_SET_ID_RANGE_OUT 0x00002013 +#define AVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID_RANGE_OUT 0x00002014 +#define AVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002015 +#define AVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002016 +#define AVC_PPSERR_PPS_CB_QP_OFFSET_RANGE_OUT 0x00002017 +#define AVC_PPSERR_PPS_CR_QP_OFFSET_RANGE_OUT 0x00002018 +#define AVC_SHERR_SLICE_PIC_PARAMETER_SET_ID 0x00003000 +#define AVC_SHERR_ACTIVATE_PPS 0x00003001 +#define AVC_SHERR_ACTIVATE_SPS 0x00003002 +#define AVC_SHERR_SLICE_TYPE 0x00003003 +#define AVC_SHERR_FIRST_MB_IN_SLICE 0x00003004 +#define AVC_SHERR_RPLM 0x00003006 +#define AVC_SHERR_LT_IDX_SPS_IS_OUT_OF_RANGE 0x0000300A +#define AVC_SHERR_NUM_REF_IDX_L0_ACTIVE_MINUS1 0x0000300C +#define AVC_SHERR_NUM_REF_IDX_L1_ACTIVE_MINUS1 0x0000300D +#define AVC_SHERR_PRED_WEIGHT_TABLE 0x0000300F +#define AVC_SHERR_SLICE_QP_DELTA 0x00003011 +#define AVC_SHERR_SLICE_BETA_OFFSET_DIV2 0x00003015 +#define AVC_SHERR_SLICE_TC_OFFSET_DIV2 0x00003016 +#define AVC_SHERR_DISABLE_DEBLOCK_FILTER_IDC 0x00003017 +#define AVC_SPECERR_OVER_PICTURE_WIDTH_SIZE 0x00004000 +#define AVC_SPECERR_OVER_PICTURE_HEIGHT_SIZE 0x00004001 +#define AVC_SPECERR_OVER_CHROMA_FORMAT 0x00004002 +#define AVC_SPECERR_OVER_BIT_DEPTH 0x00004003 +#define AVC_SPECERR_OVER_BUFFER_OVER_FLOW 0x00004004 +#define AVC_SPECERR_OVER_WRONG_BUFFER_ACCESS 0x00004005 +#define AVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND 0x00005000 +#define AVC_ETCERR_DEC_PIC_VCL_NOT_FOUND 0x00005001 +#define AVC_ETCERR_NO_VALID_SLICE_IN_AU 0x00005002 +#define AVC_ETCERR_ASO 0x00005004 +#define AVC_ETCERR_FMO 0x00005005 +#define AVC_ETCERR_INPLACE_V 0x0000500F + +/************************************************************************/ +/* WAVE5 WARNING ON DECODER (WARN_INFO) */ +/************************************************************************/ +// HEVC +#define HEVC_SPSWARN_MAX_SUB_LAYERS_MINUS1 0x00000001 +#define HEVC_SPSWARN_GENERAL_RESERVED_ZERO_44BITS 0x00000002 +#define HEVC_SPSWARN_RESERVED_ZERO_2BITS 0x00000004 +#define HEVC_SPSWARN_SUB_LAYER_RESERVED_ZERO_44BITS 0x00000008 +#define HEVC_SPSWARN_GENERAL_LEVEL_IDC 0x00000010 +#define HEVC_SPSWARN_SPS_MAX_DEC_PIC_BUFFERING_VALUE_OVER 0x00000020 +#define HEVC_SPSWARN_RBSP_TRAILING_BITS 0x00000040 +#define HEVC_SPSWARN_ST_RPS_UE_ERROR 0x00000080 +#define HEVC_SPSWARN_EXTENSION_FLAG 0x01000000 +#define HEVC_SPSWARN_REPLACED_WITH_PREV_SPS 0x02000000 +#define HEVC_PPSWARN_RBSP_TRAILING_BITS 0x00000100 +#define HEVC_PPSWARN_REPLACED_WITH_PREV_PPS 0x00000200 +#define HEVC_SHWARN_FIRST_SLICE_SEGMENT_IN_PIC_FLAG 0x00001000 +#define HEVC_SHWARN_NO_OUTPUT_OF_PRIOR_PICS_FLAG 0x00002000 +#define HEVC_SHWARN_PIC_OUTPUT_FLAG 0x00004000 +#define HEVC_SHWARN_DUPLICATED_SLICE_SEGMENT 0x00008000 +#define HEVC_ETCWARN_INIT_SEQ_VCL_NOT_FOUND 0x00010000 +#define HEVC_ETCWARN_MISSING_REFERENCE_PICTURE 0x00020000 +#define HEVC_ETCWARN_WRONG_TEMPORAL_ID 0x00040000 +#define HEVC_ETCWARN_ERROR_PICTURE_IS_REFERENCED 0x00080000 +#define HEVC_SPECWARN_OVER_PROFILE 0x00100000 +#define HEVC_SPECWARN_OVER_LEVEL 0x00200000 +#define HEVC_PRESWARN_PARSING_ERR 0x04000000 +#define HEVC_PRESWARN_MVD_OUT_OF_RANGE 0x08000000 +#define HEVC_PRESWARN_CU_QP_DELTA_VAL_OUT_OF_RANGE 0x09000000 +#define HEVC_PRESWARN_COEFF_LEVEL_REMAINING_OUT_OF_RANGE 0x0A000000 +#define HEVC_PRESWARN_PCM_ERR 0x0B000000 +#define HEVC_PRESWARN_OVERCONSUME 0x0C000000 +#define HEVC_PRESWARN_END_OF_SUBSET_ONE_BIT_ERR 0x10000000 +#define HEVC_PRESWARN_END_OF_SLICE_SEGMENT_FLAG 0x20000000 + +// AVC +#define AVC_SPSWARN_RESERVED_ZERO_2BITS 0x00000004 +#define AVC_SPSWARN_GENERAL_LEVEL_IDC 0x00000010 +#define AVC_SPSWARN_RBSP_TRAILING_BITS 0x00000040 +#define AVC_PPSWARN_RBSP_TRAILING_BITS 0x00000100 +#define AVC_SHWARN_NO_OUTPUT_OF_PRIOR_PICS_FLAG 0x00002000 +#define AVC_ETCWARN_INIT_SEQ_VCL_NOT_FOUND 0x00010000 +#define AVC_ETCWARN_MISSING_REFERENCE_PICTURE 0x00020000 +#define AVC_ETCWARN_ERROR_PICTURE_IS_REFERENCED 0x00080000 +#define AVC_SPECWARN_OVER_PROFILE 0x00100000 +#define AVC_SPECWARN_OVER_LEVEL 0x00200000 +#define AVC_PRESWARN_MVD_RANGE_OUT 0x00400000 +#define AVC_PRESWARN_MB_QPD_RANGE_OUT 0x00500000 +#define AVC_PRESWARN_COEFF_RANGE_OUT 0x00600000 +#define AVC_PRESWARN_MV_RANGE_OUT 0x00700000 +#define AVC_PRESWARN_MB_SKIP_RUN_RANGE_OUT 0x00800000 +#define AVC_PRESWARN_MB_TYPE_RANGE_OUT 0x00900000 +#define AVC_PRESWARN_SUB_MB_TYPE_RANGE_OUT 0x00A00000 +#define AVC_PRESWARN_CBP_RANGE_OUT 0x00B00000 +#define AVC_PRESWARN_INTRA_CHROMA_PRED_MODE_RANGE_OUT 0x00C00000 +#define AVC_PRESWARN_REF_IDX_RANGE_OUT 0x00D00000 +#define AVC_PRESWARN_COEFF_TOKEN_RANGE_OUT 0x00E00000 +#define AVC_PRESWARN_TOTAL_ZERO_RANGE_OUT 0x00F00000 +#define AVC_PRESWARN_RUN_BEFORE_RANGE_OUT 0x01000000 +#define AVC_PRESWARN_OVERCONSUME 0x01100000 +#define AVC_PRESWARN_MISSING_SLICE 0x01200000 + +/************************************************************************/ +/* WAVE5 ERROR ON ENCODER (ERR_INFO) */ +/************************************************************************/ + +/************************************************************************/ +/* WAVE5 WARNING ON ENCODER (WARN_INFO) */ +/************************************************************************/ +#define WAVE5_ETCWARN_FORCED_SPLIT_BY_CU8X8 0x000000001 + +/************************************************************************/ +/* WAVE5 debug info (PRI_REASON) */ +/************************************************************************/ +#define WAVE5_DEC_VCORE_VCE_HANGUP 0x0001 +#define WAVE5_DEC_VCORE_UNDETECTED_SYNTAX_ERR 0x0002 +#define WAVE5_DEC_VCORE_MIB_BUSY 0x0003 +#define WAVE5_DEC_VCORE_VLC_BUSY 0x0004 + +#endif /* ERROR_CODE_H_INCLUDED */ diff -Naur --no-dereference a/drivers/media/platform/chips-media/wave5/wave5-vpu.h b/drivers/media/platform/chips-media/wave5/wave5-vpu.h --- a/drivers/media/platform/chips-media/wave5/wave5-vpu.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave5 series multi-standard codec IP - basic types + * + * Copyright (C) 2021-2023 CHIPS&MEDIA INC + */ +#ifndef __VPU_DRV_H__ +#define __VPU_DRV_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "wave5-vpuconfig.h" +#include "wave5-vpuapi.h" + +#define VPU_BUF_SYNC_TO_DEVICE 0 +#define VPU_BUF_SYNC_FROM_DEVICE 1 + +struct vpu_src_buffer { + struct v4l2_m2m_buffer v4l2_m2m_buf; + struct list_head list; + bool consumed; +}; + +struct vpu_dst_buffer { + struct v4l2_m2m_buffer v4l2_m2m_buf; + bool display; +}; + +enum vpu_fmt_type { + VPU_FMT_TYPE_CODEC = 0, + VPU_FMT_TYPE_RAW = 1 +}; + +struct vpu_format { + unsigned int v4l2_pix_fmt; + const struct v4l2_frmsize_stepwise *v4l2_frmsize; +}; + +static inline struct vpu_instance *wave5_to_vpu_inst(struct v4l2_fh *vfh) +{ + return container_of(vfh, struct vpu_instance, v4l2_fh); +} + +static inline struct vpu_instance *wave5_ctrl_to_vpu_inst(struct v4l2_ctrl *vctrl) +{ + return container_of(vctrl->handler, struct vpu_instance, v4l2_ctrl_hdl); +} + +static inline struct vpu_src_buffer *wave5_to_vpu_src_buf(struct vb2_v4l2_buffer *vbuf) +{ + return container_of(vbuf, struct vpu_src_buffer, v4l2_m2m_buf.vb); +} + +static inline struct vpu_dst_buffer *wave5_to_vpu_dst_buf(struct vb2_v4l2_buffer *vbuf) +{ + return container_of(vbuf, struct vpu_dst_buffer, v4l2_m2m_buf.vb); +} + +int wave5_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout); + +int wave5_vpu_dec_register_device(struct vpu_device *dev); +void wave5_vpu_dec_unregister_device(struct vpu_device *dev); +int wave5_vpu_enc_register_device(struct vpu_device *dev); +void wave5_vpu_enc_unregister_device(struct vpu_device *dev); +static inline bool wave5_vpu_both_queues_are_streaming(struct vpu_instance *inst) +{ + struct vb2_queue *vq_cap = + v4l2_m2m_get_vq(inst->v4l2_fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + struct vb2_queue *vq_out = + v4l2_m2m_get_vq(inst->v4l2_fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + + return vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out); +} + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/e5010/e5010-core-regs.h b/drivers/media/platform/imagination/e5010/e5010-core-regs.h --- a/drivers/media/platform/imagination/e5010/e5010-core-regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/e5010/e5010-core-regs.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,585 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Imagination E5010 JPEG Encoder driver. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + * Author: David Huang + * Author: Devarsh Thakkar + */ + +#ifndef _E5010_CORE_REGS_H +#define _E5010_CORE_REGS_H + +#define JASPER_CORE_ID_OFFSET (0x0000) +#define JASPER_CORE_ID_CR_GROUP_ID_MASK (0xFF000000) +#define JASPER_CORE_ID_CR_GROUP_ID_SHIFT (24) +#define JASPER_CORE_ID_CR_CORE_ID_MASK (0x00FF0000) +#define JASPER_CORE_ID_CR_CORE_ID_SHIFT (16) +#define JASPER_CORE_ID_CR_UNIQUE_NUM_MASK (0x0000FFF8) +#define JASPER_CORE_ID_CR_UNIQUE_NUM_SHIFT (3) +#define JASPER_CORE_ID_CR_PELS_PER_CYCLE_MASK (0x00000007) +#define JASPER_CORE_ID_CR_PELS_PER_CYCLE_SHIFT (0) + +#define JASPER_CORE_REV_OFFSET (0x0004) +#define JASPER_CORE_REV_CR_JASPER_DESIGNER_MASK (0xFF000000) +#define JASPER_CORE_REV_CR_JASPER_DESIGNER_SHIFT (24) +#define JASPER_CORE_REV_CR_JASPER_MAJOR_REV_MASK (0x00FF0000) +#define JASPER_CORE_REV_CR_JASPER_MAJOR_REV_SHIFT (16) +#define JASPER_CORE_REV_CR_JASPER_MINOR_REV_MASK (0x0000FF00) +#define JASPER_CORE_REV_CR_JASPER_MINOR_REV_SHIFT (8) +#define JASPER_CORE_REV_CR_JASPER_MAINT_REV_MASK (0x000000FF) +#define JASPER_CORE_REV_CR_JASPER_MAINT_REV_SHIFT (0) + +#define JASPER_INTERRUPT_MASK_OFFSET (0x0008) +#define JASPER_INTERRUPT_MASK_CR_OUTPUT_ADDRESS_ERROR_ENABLE_MASK (0x00000002) +#define JASPER_INTERRUPT_MASK_CR_OUTPUT_ADDRESS_ERROR_ENABLE_SHIFT (1) +#define JASPER_INTERRUPT_MASK_CR_PICTURE_DONE_ENABLE_MASK (0x00000001) +#define JASPER_INTERRUPT_MASK_CR_PICTURE_DONE_ENABLE_SHIFT (0) + +#define JASPER_INTERRUPT_STATUS_OFFSET (0x000C) +#define JASPER_INTERRUPT_STATUS_CR_OUTPUT_ADDRESS_ERROR_IRQ_MASK (0x00000002) +#define JASPER_INTERRUPT_STATUS_CR_OUTPUT_ADDRESS_ERROR_IRQ_SHIFT (1) +#define JASPER_INTERRUPT_STATUS_CR_PICTURE_DONE_IRQ_MASK (0x00000001) +#define JASPER_INTERRUPT_STATUS_CR_PICTURE_DONE_IRQ_SHIFT (0) + +#define JASPER_INTERRUPT_CLEAR_OFFSET (0x0010) +#define JASPER_INTERRUPT_CLEAR_CR_OUTPUT_ERROR_CLEAR_MASK (0x00000002) +#define JASPER_INTERRUPT_CLEAR_CR_OUTPUT_ERROR_CLEAR_SHIFT (1) +#define JASPER_INTERRUPT_CLEAR_CR_PICTURE_DONE_CLEAR_MASK (0x00000001) +#define JASPER_INTERRUPT_CLEAR_CR_PICTURE_DONE_CLEAR_SHIFT (0) + +#define JASPER_CLK_CONTROL_OFFSET (0x0014) +#define JASPER_CLK_CONTROL_CR_JASPER_AUTO_CLKG_ENABLE_MASK (0x00000002) +#define JASPER_CLK_CONTROL_CR_JASPER_AUTO_CLKG_ENABLE_SHIFT (1) +#define JASPER_CLK_CONTROL_CR_JASPER_MAN_CLKG_ENABLE_MASK (0x00000001) +#define JASPER_CLK_CONTROL_CR_JASPER_MAN_CLKG_ENABLE_SHIFT (0) + +#define JASPER_CLK_STATUS_OFFSET (0x0018) +#define JASPER_CLK_STATUS_CR_JASPER_CLKG_STATUS_MASK (0x00000001) +#define JASPER_CLK_STATUS_CR_JASPER_CLKG_STATUS_SHIFT (0) + +#define JASPER_RESET_OFFSET (0x001C) +#define JASPER_RESET_CR_SYS_RESET_MASK (0x00000002) +#define JASPER_RESET_CR_SYS_RESET_SHIFT (1) +#define JASPER_RESET_CR_CORE_RESET_MASK (0x00000001) +#define JASPER_RESET_CR_CORE_RESET_SHIFT (0) + +#define JASPER_CORE_CTRL_OFFSET (0x0020) +#define JASPER_CORE_CTRL_CR_JASPER_ENCODE_START_MASK (0x00000001) +#define JASPER_CORE_CTRL_CR_JASPER_ENCODE_START_SHIFT (0) + +#define JASPER_STATUS_OFFSET (0x0024) +#define JASPER_STATUS_CR_FLUSH_MODE_MASK (0x00000002) +#define JASPER_STATUS_CR_FLUSH_MODE_SHIFT (1) +#define JASPER_STATUS_CR_JASPER_BUSY_MASK (0x00000001) +#define JASPER_STATUS_CR_JASPER_BUSY_SHIFT (0) + +#define JASPER_CRC_CLEAR_OFFSET (0x0028) +#define JASPER_CRC_CLEAR_CR_FRONT_END_CRC_CLEAR_MASK (0x00000001) +#define JASPER_CRC_CLEAR_CR_FRONT_END_CRC_CLEAR_SHIFT (0) +#define JASPER_CRC_CLEAR_CR_DCT_CRC_CLEAR_MASK (0x00000002) +#define JASPER_CRC_CLEAR_CR_DCT_CRC_CLEAR_SHIFT (1) +#define JASPER_CRC_CLEAR_CR_ZZ_CRC_CLEAR_MASK (0x00000004) +#define JASPER_CRC_CLEAR_CR_ZZ_CRC_CLEAR_SHIFT (2) +#define JASPER_CRC_CLEAR_CR_QUANT_CRC_CLEAR_MASK (0x00000008) +#define JASPER_CRC_CLEAR_CR_QUANT_CRC_CLEAR_SHIFT (3) +#define JASPER_CRC_CLEAR_CR_ENTROPY_ENCODER_CRC_CLEAR_MASK (0x00000010) +#define JASPER_CRC_CLEAR_CR_ENTROPY_ENCODER_CRC_CLEAR_SHIFT (4) +#define JASPER_CRC_CLEAR_CR_PACKING_BUFFER_CRC_CLEAR_MASK (0x00000020) +#define JASPER_CRC_CLEAR_CR_PACKING_BUFFER_CRC_CLEAR_SHIFT (5) + +#define JASPER_INPUT_CTRL0_OFFSET (0x002C) +#define JASPER_INPUT_CTRL0_CR_INPUT_CHROMA_ORDER_MASK (0x01000000) +#define JASPER_INPUT_CTRL0_CR_INPUT_CHROMA_ORDER_SHIFT (24) +#define JASPER_INPUT_CTRL0_CR_INPUT_SUBSAMPLING_MASK (0x00030000) +#define JASPER_INPUT_CTRL0_CR_INPUT_SUBSAMPLING_SHIFT (16) +#define JASPER_INPUT_CTRL0_CR_INPUT_SOURCE_MASK (0x00000004) +#define JASPER_INPUT_CTRL0_CR_INPUT_SOURCE_SHIFT (2) + +#define JASPER_INPUT_CTRL1_OFFSET (0x0030) +#define JASPER_INPUT_CTRL1_CR_INPUT_LUMA_STRIDE_MASK (0x1FC00000) +#define JASPER_INPUT_CTRL1_CR_INPUT_LUMA_STRIDE_SHIFT (22) +#define JASPER_INPUT_CTRL1_CR_INPUT_CHROMA_STRIDE_MASK (0x00001FC0) +#define JASPER_INPUT_CTRL1_CR_INPUT_CHROMA_STRIDE_SHIFT (6) + +#define JASPER_MMU_CTRL_OFFSET (0x0034) +#define JASPER_MMU_CTRL_CR_JASPER_TILING_SCHEME_MASK (0x00000002) +#define JASPER_MMU_CTRL_CR_JASPER_TILING_SCHEME_SHIFT (1) +#define JASPER_MMU_CTRL_CR_JASPER_TILING_ENABLE_MASK (0x00000001) +#define JASPER_MMU_CTRL_CR_JASPER_TILING_ENABLE_SHIFT (0) + +#define JASPER_IMAGE_SIZE_OFFSET (0x0038) +#define JASPER_IMAGE_SIZE_CR_IMAGE_VERTICAL_SIZE_MASK (0x1FFF0000) +#define JASPER_IMAGE_SIZE_CR_IMAGE_VERTICAL_SIZE_SHIFT (16) +#define JASPER_IMAGE_SIZE_CR_IMAGE_HORIZONTAL_SIZE_MASK (0x00001FFF) +#define JASPER_IMAGE_SIZE_CR_IMAGE_HORIZONTAL_SIZE_SHIFT (0) + +#define INPUT_LUMA_BASE_OFFSET (0x003C) +#define INPUT_LUMA_BASE_CR_INPUT_LUMA_BASE_MASK (0xFFFFFFC0) +#define INPUT_LUMA_BASE_CR_INPUT_LUMA_BASE_SHIFT (6) + +#define INPUT_CHROMA_BASE_OFFSET (0x0040) +#define INPUT_CHROMA_BASE_CR_INPUT_CHROMA_BASE_MASK (0xFFFFFFC0) +#define INPUT_CHROMA_BASE_CR_INPUT_CHROMA_BASE_SHIFT (6) + +#define JASPER_OUTPUT_BASE_OFFSET (0x0044) +#define JASPER_OUTPUT_BASE_CR_OUTPUT_BASE_MASK (0xFFFFFFFF) +#define JASPER_OUTPUT_BASE_CR_OUTPUT_BASE_SHIFT (0) + +#define JASPER_OUTPUT_SIZE_OFFSET (0x0048) +#define JASPER_OUTPUT_SIZE_CR_OUTPUT_SIZE_MASK (0xFFFFFFFF) +#define JASPER_OUTPUT_SIZE_CR_OUTPUT_SIZE_SHIFT (0) +#define JASPER_OUTPUT_MAX_SIZE_OFFSET (0x004C) +#define JASPER_OUTPUT_MAX_SIZE_CR_OUTPUT_MAX_SIZE_MASK (0xFFFFFFFF) +#define JASPER_OUTPUT_MAX_SIZE_CR_OUTPUT_MAX_SIZE_SHIFT (0) + +#define JASPER_LUMA_QUANTIZATION_TABLE0_OFFSET (0x0050) +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_03_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_03_SHIFT (24) +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_02_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_02_SHIFT (16) +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_01_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_01_SHIFT (8) +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_00_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_00_SHIFT (0) +#define JASPER_LUMA_QUANTIZATION_TABLE1_OFFSET (0x0054) +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_07_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_07_SHIFT (24) +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_06_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_06_SHIFT (16) +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_05_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_05_SHIFT (8) +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_04_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_04_SHIFT (0) +#define JASPER_LUMA_QUANTIZATION_TABLE2_OFFSET (0x0058) +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_13_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_13_SHIFT (24) +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_12_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_12_SHIFT (16) +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_11_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_11_SHIFT (8) +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_10_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_10_SHIFT (0) +#define JASPER_LUMA_QUANTIZATION_TABLE3_OFFSET (0x005C) +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_17_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_17_SHIFT (24) +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_16_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_16_SHIFT (16) +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_15_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_15_SHIFT (8) +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_14_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_14_SHIFT (0) +#define JASPER_LUMA_QUANTIZATION_TABLE4_OFFSET (0x0060) +#define JASPER_LUMA_QUANTIZATION_TABLE4_CR_LUMA_QUANTIZATION_TABLE_21_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE4_CR_LUMA_QUANTIZATION_TABLE_21_SHIFT (8) +#define JASPER_LUMA_QUANTIZATION_TABLE4_CR_LUMA_QUANTIZATION_TABLE_20_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE4_CR_LUMA_QUANTIZATION_TABLE_20_SHIFT (0) + +#define JASPER_LUMA_QUANTIZATION_TABLE5_OFFSET (0x0064) +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_27_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_27_SHIFT (24) +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_26_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_26_SHIFT (16) +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_25_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_25_SHIFT (8) +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_24_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_24_SHIFT (0) + +#define JASPER_LUMA_QUANTIZATION_TABLE6_OFFSET (0x0068) + +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_33_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_33_SHIFT (24) + +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_32_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_32_SHIFT (16) + +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_31_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_31_SHIFT (8) +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_30_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_30_SHIFT (0) + +#define JASPER_LUMA_QUANTIZATION_TABLE7_OFFSET (0x006C) + +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_37_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_37_SHIFT (24) + +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_36_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_36_SHIFT (16) + +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_35_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_35_SHIFT (8) + +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_34_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_34_SHIFT (0) + +#define JASPER_LUMA_QUANTIZATION_TABLE8_OFFSET (0x0070) + +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_43_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_43_SHIFT (24) +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_42_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_42_SHIFT (16) + +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_41_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_41_SHIFT (8) + +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_40_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_40_SHIFT (0) + +#define JASPER_LUMA_QUANTIZATION_TABLE9_OFFSET (0x0074) + +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_47_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_47_SHIFT (24) + +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_46_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_46_SHIFT (16) + +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_45_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_45_SHIFT (8) + +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_44_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_44_SHIFT (0) + +#define JASPER_LUMA_QUANTIZATION_TABLE10_OFFSET (0x0078) + +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_53_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_53_SHIFT (24) + +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_52_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_52_SHIFT (16) + +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_51_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_51_SHIFT (8) + +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_50_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_50_SHIFT (0) + +#define JASPER_LUMA_QUANTIZATION_TABLE11_OFFSET (0x007C) + +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_57_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_57_SHIFT (24) + +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_56_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_56_SHIFT (16) + +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_55_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_55_SHIFT (8) + +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_54_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_54_SHIFT (0) + +#define JASPER_LUMA_QUANTIZATION_TABLE12_OFFSET (0x0080) + +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_63_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_63_SHIFT (24) + +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_62_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_62_SHIFT (16) + +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_61_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_61_SHIFT (8) + +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_60_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_60_SHIFT (0) + +#define JASPER_LUMA_QUANTIZATION_TABLE13_OFFSET (0x0084) + +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_67_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_67_SHIFT (24) + +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_66_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_66_SHIFT (16) + +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_65_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_65_SHIFT (8) + +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_64_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_64_SHIFT (0) + +#define JASPER_LUMA_QUANTIZATION_TABLE14_OFFSET (0x0088) + +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_73_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_73_SHIFT (24) + +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_72_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_72_SHIFT (16) + +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_71_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_71_SHIFT (8) + +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_70_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_70_SHIFT (0) + +#define JASPER_LUMA_QUANTIZATION_TABLE15_OFFSET (0x008C) + +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_77_MASK (0xFF000000) +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_77_SHIFT (24) + +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_76_MASK (0x00FF0000) +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_76_SHIFT (16) + +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_75_MASK (0x0000FF00) +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_75_SHIFT (8) + +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_74_MASK (0x000000FF) +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_74_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE0_OFFSET (0x0090) + +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_03_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_03_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_02_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_02_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_01_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_01_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_00_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_00_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE1_OFFSET (0x0094) + +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_07_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_07_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_06_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_06_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_05_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_05_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_04_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_04_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE2_OFFSET (0x0098) + +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_13_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_13_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_12_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_12_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_11_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_11_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_10_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_10_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE3_OFFSET (0x009C) + +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_17_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_17_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_16_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_16_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_15_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_15_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_14_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_14_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE4_OFFSET (0x00A0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_23_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_23_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_22_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_22_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_21_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_21_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_20_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_20_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE5_OFFSET (0x00A4) + +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_27_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_27_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_26_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_26_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_25_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_25_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_24_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_24_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE6_OFFSET (0x00A8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_33_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_33_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_32_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_32_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_31_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_31_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_30_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_30_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE7_OFFSET (0x00AC) + +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_37_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_37_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_36_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_36_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_35_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_35_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_34_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_34_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE8_OFFSET (0x00B0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_43_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_43_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_42_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_42_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_41_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_41_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_40_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_40_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE9_OFFSET (0x00B4) + +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_47_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_47_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_46_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_46_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_45_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_45_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_44_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_44_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE10_OFFSET (0x00B8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_53_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_53_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_52_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_52_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_51_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_51_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_50_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_50_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE11_OFFSET (0x00BC) + +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_57_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_57_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_56_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_56_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_55_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_55_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_54_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_54_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE12_OFFSET (0x00C0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_63_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_63_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_62_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_62_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_61_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_61_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_60_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_60_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE13_OFFSET (0x00C4) + +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_67_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_67_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_66_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_66_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_65_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_65_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_64_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_64_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE14_OFFSET (0x00C8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_73_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_73_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_72_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_72_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_71_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_71_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_70_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_70_SHIFT (0) + +#define JASPER_CHROMA_QUANTIZATION_TABLE15_OFFSET (0x00CC) + +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_77_MASK (0xFF000000) +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_77_SHIFT (24) + +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_76_MASK (0x00FF0000) +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_76_SHIFT (16) + +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_75_MASK (0x0000FF00) +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_75_SHIFT (8) + +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_74_MASK (0x000000FF) +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_74_SHIFT (0) + +#define JASPER_CRC_CTRL_OFFSET (0x00D0) +#define JASPER_CRC_CTRL_JASPER_CRC_ENABLE_MASK (0x00000001) +#define JASPER_CRC_CTRL_JASPER_CRC_ENABLE_SHIFT (0) + +#define JASPER_FRONT_END_CRC_OFFSET (0x00D4) +#define JASPER_FRONT_END_CRC_CR_JASPER_FRONT_END_CRC_OUT_MASK (0xFFFFFFFF) +#define JASPER_FRONT_END_CRC_CR_JASPER_FRONT_END_CRC_OUT_SHIFT (0) + +#define JASPER_DCT_CRC_OFFSET (0x00D8) +#define JASPER_DCT_CRC_CR_JASPER_DCT_CRC_OUT_MASK (0xFFFFFFFF) +#define JASPER_DCT_CRC_CR_JASPER_DCT_CRC_OUT_SHIFT (0) + +#define JASPER_ZZ_CRC_OFFSET (0x00DC) +#define JASPER_ZZ_CRC_CR_JASPER_ZZ_CRC_OUT_MASK (0xFFFFFFFF) +#define JASPER_ZZ_CRC_CR_JASPER_ZZ_CRC_OUT_SHIFT (0) + +#define JASPER_QUANT_CRC_OFFSET (0x00E0) +#define JASPER_QUANT_CRC_CR_JASPER_QUANT_CRC_OUT_MASK (0xFFFFFFFF) +#define JASPER_QUANT_CRC_CR_JASPER_QUANT_CRC_OUT_SHIFT (0) + +#define JASPER_ENTROPY_ENCODER_CRC_OFFSET (0x00E4) +#define JASPER_ENTROPY_ENCODER_CRC_CR_JASPER_ENTROPY_CRC_OUT_MASK (0xFFFFFFFF) +#define JASPER_ENTROPY_ENCODER_CRC_CR_JASPER_ENTROPY_CRC_OUT_SHIFT (0) + +#define JASPER_PACKING_BUFFER_DATA_CRC_OFFSET (0x00E8) +#define JASPER_PACKING_BUFFER_DATA_CRC_CR_JASPER_PACKING_DATA_CRC_OUT_MASK (0xFFFFFFFF) +#define JASPER_PACKING_BUFFER_DATA_CRC_CR_JASPER_PACKING_DATA_CRC_OUT_SHIFT (0) + +#define JASPER_PACKING_BUFFER_ADDR_CRC_OFFSET (0x00EC) +#define JASPER_PACKING_BUFFER_ADDR_CRC_CR_JASPER_PACKING_ADDR_OUT_CRC_MASK (0xFFFFFFFF) +#define JASPER_PACKING_BUFFER_ADDR_CRC_CR_JASPER_PACKING_ADDR_OUT_CRC_SHIFT (0) + +#define JASPER_CORE_BYTE_SIZE (0x00F0) + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/e5010/e5010-jpeg-enc.c b/drivers/media/platform/imagination/e5010/e5010-jpeg-enc.c --- a/drivers/media/platform/imagination/e5010/e5010-jpeg-enc.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/e5010/e5010-jpeg-enc.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,1641 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Imagination E5010 JPEG Encoder driver. + * + * TODO: Add MMU and memory tiling support + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + * Author: David Huang + * Author: Devarsh Thakkar + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "e5010-jpeg-enc.h" +#include "e5010-jpeg-enc-hw.h" + +/* forward declarations */ +static const struct of_device_id e5010_of_match[]; + +static const struct v4l2_file_operations e5010_fops; + +static const struct v4l2_ioctl_ops e5010_ioctl_ops; + +static const struct vb2_ops e5010_video_ops; + +static const struct v4l2_m2m_ops e5010_m2m_ops; + +static struct e5010_fmt e5010_formats[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .num_planes = 1, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, + .chroma_order = CHROMA_ORDER_CB_CR, + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, + MIN_DIMENSION, MAX_DIMENSION, 8 }, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .num_planes = 2, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, + .chroma_order = CHROMA_ORDER_CB_CR, + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, + MIN_DIMENSION, MAX_DIMENSION, 8 }, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .num_planes = 1, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, + .chroma_order = CHROMA_ORDER_CR_CB, + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, + MIN_DIMENSION, MAX_DIMENSION, 8 }, + }, + { + .fourcc = V4L2_PIX_FMT_NV21M, + .num_planes = 2, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, + .chroma_order = CHROMA_ORDER_CR_CB, + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, + MIN_DIMENSION, MAX_DIMENSION, 8 }, + }, + { + .fourcc = V4L2_PIX_FMT_NV16, + .num_planes = 1, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, + .chroma_order = CHROMA_ORDER_CB_CR, + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, + MIN_DIMENSION, MAX_DIMENSION, 8 }, + }, + { + .fourcc = V4L2_PIX_FMT_NV16M, + .num_planes = 2, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, + .chroma_order = CHROMA_ORDER_CB_CR, + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, + MIN_DIMENSION, MAX_DIMENSION, 8 }, + + }, + { + .fourcc = V4L2_PIX_FMT_NV61, + .num_planes = 1, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, + .chroma_order = CHROMA_ORDER_CR_CB, + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, + MIN_DIMENSION, MAX_DIMENSION, 8 }, + }, + { + .fourcc = V4L2_PIX_FMT_NV61M, + .num_planes = 2, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, + .chroma_order = CHROMA_ORDER_CR_CB, + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, + MIN_DIMENSION, MAX_DIMENSION, 8 }, + }, + { + .fourcc = V4L2_PIX_FMT_JPEG, + .num_planes = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .subsampling = 0, + .chroma_order = 0, + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 16, + MIN_DIMENSION, MAX_DIMENSION, 8 }, + }, +}; + +static unsigned int debug; +module_param(debug, uint, 0644); +MODULE_PARM_DESC(debug, "debug level"); + +#define dprintk(dev, lvl, fmt, arg...) \ + v4l2_dbg(lvl, debug, &(dev)->v4l2_dev, "%s: " fmt, __func__, ## arg) + +static const struct v4l2_event e5010_eos_event = { + .type = V4L2_EVENT_EOS +}; + +static const char *type_name(enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return "Output"; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + return "Capture"; + default: + return "Invalid"; + } +} + +static struct e5010_q_data *get_queue(struct e5010_context *ctx, enum v4l2_buf_type type) +{ + return (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? &ctx->out_queue : &ctx->cap_queue; +} + +static void calculate_qp_tables(struct e5010_context *ctx) +{ + long long luminosity, contrast; + int quality, i; + const u8 *luma_q_table, *chroma_q_table; + + v4l2_jpeg_get_reference_quantization_tables(&luma_q_table, &chroma_q_table); + + quality = 50 - ctx->quality; + + luminosity = LUMINOSITY * quality / 50; + contrast = CONTRAST * quality / 50; + + if (quality > 0) { + luminosity *= INCREASE; + contrast *= INCREASE; + } + + for (i = 0; i < V4L2_JPEG_PIXELS_IN_BLOCK; i++) { + long long delta = chroma_q_table[i] * contrast + luminosity; + int val = (int)(chroma_q_table[i] + delta); + + clamp(val, 1, 255); + ctx->chroma_qp[i] = quality == -50 ? 1 : val; + + delta = luma_q_table[i] * contrast + luminosity; + val = (int)(luma_q_table[i] + delta); + clamp(val, 1, 255); + ctx->luma_qp[i] = quality == -50 ? 1 : val; + } + + ctx->update_qp = true; +} + +static int update_qp_tables(struct e5010_context *ctx) +{ + struct e5010_dev *e5010 = ctx->e5010; + int i, ret = 0; + u32 lvalue, cvalue; + + lvalue = 0; + cvalue = 0; + + for (i = 0; i < QP_TABLE_SIZE; i++) { + lvalue |= ctx->luma_qp[i] << (8 * (i % 4)); + cvalue |= ctx->chroma_qp[i] << (8 * (i % 4)); + if (i % 4 == 3) { + ret |= e5010_hw_set_qpvalue(e5010->core_base, + JASPER_LUMA_QUANTIZATION_TABLE0_OFFSET + + QP_TABLE_FIELD_OFFSET * ((i - 3) / 4), + lvalue); + ret |= e5010_hw_set_qpvalue(e5010->core_base, + JASPER_CHROMA_QUANTIZATION_TABLE0_OFFSET + + QP_TABLE_FIELD_OFFSET * ((i - 3) / 4), + cvalue); + lvalue = 0; + cvalue = 0; + } + } + + return ret; +} + +static int e5010_set_input_subsampling(void __iomem *core_base, int subsampling) +{ + switch (subsampling) { + case V4L2_JPEG_CHROMA_SUBSAMPLING_420: + return e5010_hw_set_input_subsampling(core_base, SUBSAMPLING_420); + case V4L2_JPEG_CHROMA_SUBSAMPLING_422: + return e5010_hw_set_input_subsampling(core_base, SUBSAMPLING_422); + default: + return -EINVAL; + }; +} + +static int e5010_querycap(struct file *file, void *priv, struct v4l2_capability *cap) +{ + strscpy(cap->driver, E5010_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, E5010_MODULE_NAME, sizeof(cap->card)); + + return 0; +} + +static struct e5010_fmt *find_format(struct v4l2_format *f) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(e5010_formats); ++i) { + if (e5010_formats[i].fourcc == f->fmt.pix_mp.pixelformat && + e5010_formats[i].type == f->type) + return &e5010_formats[i]; + } + + return NULL; +} + +static int e5010_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) +{ + int i, index = 0; + struct e5010_fmt *fmt = NULL; + struct e5010_context *ctx = file->private_data; + + if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) { + v4l2_err(&ctx->e5010->v4l2_dev, "ENUMFMT with Invalid type: %d\n", f->type); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(e5010_formats); ++i) { + if (e5010_formats[i].type == f->type) { + if (index == f->index) { + fmt = &e5010_formats[i]; + break; + } + index++; + } + } + + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->fourcc; + return 0; +} + +static int e5010_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct e5010_context *ctx = file->private_data; + struct e5010_q_data *queue; + int i; + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt; + + queue = get_queue(ctx, f->type); + + pix_mp->flags = 0; + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->pixelformat = queue->fmt->fourcc; + pix_mp->width = queue->width_adjusted; + pix_mp->height = queue->height_adjusted; + pix_mp->num_planes = queue->fmt->num_planes; + + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + if (!pix_mp->colorspace) + pix_mp->colorspace = V4L2_COLORSPACE_SRGB; + + for (i = 0; i < queue->fmt->num_planes; i++) { + plane_fmt[i].sizeimage = queue->sizeimage[i]; + plane_fmt[i].bytesperline = queue->bytesperline[i]; + } + + } else { + pix_mp->colorspace = V4L2_COLORSPACE_JPEG; + plane_fmt[0].bytesperline = 0; + plane_fmt[0].sizeimage = queue->sizeimage[0]; + } + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; + pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT; + + return 0; +} + +static int e5010_jpeg_try_fmt(struct v4l2_format *f, struct e5010_context *ctx) +{ + struct e5010_fmt *fmt; + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt; + + fmt = find_format(f); + if (!fmt) { + if (V4L2_TYPE_IS_OUTPUT(f->type)) + pix_mp->pixelformat = V4L2_PIX_FMT_NV12; + else + pix_mp->pixelformat = V4L2_PIX_FMT_JPEG; + fmt = find_format(f); + if (!fmt) + return -EINVAL; + } + + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + if (!pix_mp->colorspace) + pix_mp->colorspace = V4L2_COLORSPACE_JPEG; + if (!pix_mp->ycbcr_enc) + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + if (!pix_mp->quantization) + pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT; + if (!pix_mp->xfer_func) + pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; + + v4l2_apply_frmsize_constraints(&pix_mp->width, + &pix_mp->height, + &fmt->frmsize); + + v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, + pix_mp->width, pix_mp->height); + + } else { + pix_mp->colorspace = V4L2_COLORSPACE_JPEG; + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT; + pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; + v4l2_apply_frmsize_constraints(&pix_mp->width, + &pix_mp->height, + &fmt->frmsize); + plane_fmt[0].sizeimage = pix_mp->width * pix_mp->height * JPEG_MAX_BYTES_PER_PIXEL; + plane_fmt[0].sizeimage += HEADER_SIZE; + plane_fmt[0].bytesperline = 0; + pix_mp->pixelformat = fmt->fourcc; + pix_mp->num_planes = fmt->num_planes; + } + pix_mp->flags = 0; + pix_mp->field = V4L2_FIELD_NONE; + + dprintk(ctx->e5010, 2, + "ctx: 0x%p: format type %s:, wxh: %dx%d (plane0 : %d bytes, plane1 : %d bytes),fmt: %c%c%c%c\n", + ctx, type_name(f->type), pix_mp->width, pix_mp->height, + plane_fmt[0].sizeimage, plane_fmt[1].sizeimage, + (fmt->fourcc & 0xff), + (fmt->fourcc >> 8) & 0xff, + (fmt->fourcc >> 16) & 0xff, + (fmt->fourcc >> 24) & 0xff); + + return 0; +} + +static int e5010_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct e5010_context *ctx = file->private_data; + + return e5010_jpeg_try_fmt(f, ctx); +} + +static int e5010_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct e5010_context *ctx = file->private_data; + struct vb2_queue *vq; + int ret = 0, i = 0; + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt; + struct e5010_q_data *queue; + struct e5010_fmt *fmt; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + if (vb2_is_busy(vq)) { + v4l2_err(&ctx->e5010->v4l2_dev, "queue busy\n"); + return -EBUSY; + } + + ret = e5010_jpeg_try_fmt(f, ctx); + if (ret) + return ret; + + fmt = find_format(f); + queue = get_queue(ctx, f->type); + + queue->fmt = fmt; + queue->width = pix_mp->width; + queue->height = pix_mp->height; + + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + for (i = 0; i < fmt->num_planes; i++) { + queue->bytesperline[i] = plane_fmt[i].bytesperline; + queue->sizeimage[i] = plane_fmt[i].sizeimage; + } + queue->crop.left = 0; + queue->crop.top = 0; + queue->crop.width = queue->width; + queue->crop.height = queue->height; + } else { + queue->sizeimage[0] = plane_fmt[0].sizeimage; + queue->sizeimage[1] = 0; + queue->bytesperline[0] = 0; + queue->bytesperline[1] = 0; + } + + return 0; +} + +static int e5010_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) +{ + struct v4l2_format f; + struct e5010_fmt *fmt; + + if (fsize->index != 0) + return -EINVAL; + + f.fmt.pix_mp.pixelformat = fsize->pixel_format; + if (f.fmt.pix_mp.pixelformat == V4L2_PIX_FMT_JPEG) + f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + else + f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + + fmt = find_format(&f); + if (!fmt) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise = fmt->frmsize; + fsize->reserved[0] = 0; + fsize->reserved[1] = 0; + + return 0; +} + +static int e5010_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct e5010_context *ctx = file->private_data; + struct e5010_q_data *queue; + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + queue = get_queue(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + + switch (s->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = queue->width; + s->r.height = queue->height; + break; + case V4L2_SEL_TGT_CROP: + memcpy(&s->r, &queue->crop, sizeof(s->r)); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int e5010_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct e5010_context *ctx = file->private_data; + struct e5010_q_data *queue; + struct vb2_queue *vq; + struct v4l2_rect base_rect; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, s->type); + if (!vq) + return -EINVAL; + + if (vb2_is_streaming(vq)) + return -EBUSY; + + if (s->target != V4L2_SEL_TGT_CROP || + s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + queue = get_queue(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + base_rect.top = 0; + base_rect.left = 0; + base_rect.width = queue->width; + base_rect.height = queue->height; + + switch (s->flags) { + case 0: + s->r.width = round_closest_down(s->r.width, queue->fmt->frmsize.step_width); + s->r.height = round_closest_down(s->r.height, queue->fmt->frmsize.step_height); + s->r.left = round_closest_down(s->r.left, queue->fmt->frmsize.step_width); + s->r.top = round_closest_down(s->r.top, 2); + + if (s->r.left + s->r.width > queue->width) + s->r.width = round_down(s->r.width + s->r.left - queue->width, + queue->fmt->frmsize.step_width); + if (s->r.top + s->r.height > queue->height) + s->r.top = round_down(s->r.top + s->r.height - queue->height, 2); + break; + case V4L2_SEL_FLAG_GE: + s->r.width = round_up(s->r.width, queue->fmt->frmsize.step_width); + s->r.height = round_up(s->r.height, queue->fmt->frmsize.step_height); + s->r.left = round_up(s->r.left, queue->fmt->frmsize.step_width); + s->r.top = round_up(s->r.top, 2); + break; + case V4L2_SEL_FLAG_LE: + s->r.width = round_down(s->r.width, queue->fmt->frmsize.step_width); + s->r.height = round_down(s->r.height, queue->fmt->frmsize.step_height); + s->r.left = round_down(s->r.left, queue->fmt->frmsize.step_width); + s->r.top = round_down(s->r.top, 2); + break; + case V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE: + if (!IS_ALIGNED(s->r.width, queue->fmt->frmsize.step_width) || + !IS_ALIGNED(s->r.height, queue->fmt->frmsize.step_height) || + !IS_ALIGNED(s->r.left, queue->fmt->frmsize.step_width) || + !IS_ALIGNED(s->r.top, 2)) + return -ERANGE; + break; + default: + return -EINVAL; + } + + if (!v4l2_rect_enclosed(&s->r, &base_rect)) + return -ERANGE; + + memcpy(&queue->crop, &s->r, sizeof(s->r)); + + if (!v4l2_rect_equal(&s->r, &base_rect)) + queue->crop_set = true; + + dprintk(ctx->e5010, 2, "ctx: 0x%p: crop rectangle: w: %d, h : %d, l : %d, t : %d\n", + ctx, queue->crop.width, queue->crop.height, queue->crop.left, queue->crop.top); + + return 0; +} + +static int e5010_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + default: + return -EINVAL; + } + + return 0; +} + +static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + struct e5010_context *ctx = priv; + struct e5010_dev *e5010 = ctx->e5010; + int ret = 0; + + /* src_vq */ + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct e5010_buffer); + src_vq->ops = &e5010_video_ops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &e5010->mutex; + src_vq->dev = e5010->v4l2_dev.dev; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + /* dst_vq */ + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct e5010_buffer); + dst_vq->ops = &e5010_video_ops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &e5010->mutex; + dst_vq->dev = e5010->v4l2_dev.dev; + + ret = vb2_queue_init(dst_vq); + if (ret) { + vb2_queue_release(src_vq); + return ret; + } + + return 0; +} + +static int e5010_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct e5010_context *ctx = + container_of(ctrl->handler, struct e5010_context, ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + ctx->quality = ctrl->val; + calculate_qp_tables(ctx); + dprintk(ctx->e5010, 2, "ctx: 0x%p compression quality set to : %d\n", ctx, + ctx->quality); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops e5010_ctrl_ops = { + .s_ctrl = e5010_s_ctrl, +}; + +static void e5010_encode_ctrls(struct e5010_context *ctx) +{ + v4l2_ctrl_new_std(&ctx->ctrl_handler, &e5010_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 75); +} + +static int e5010_ctrls_setup(struct e5010_context *ctx) +{ + int err; + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1); + + e5010_encode_ctrls(ctx); + + if (ctx->ctrl_handler.error) { + err = ctx->ctrl_handler.error; + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + + return err; + } + + err = v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + if (err) + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + + return err; +} + +static void e5010_jpeg_set_default_params(struct e5010_context *ctx) +{ + struct e5010_q_data *queue; + struct v4l2_format f; + struct e5010_fmt *fmt; + struct v4l2_pix_format_mplane *pix_mp = &f.fmt.pix_mp; + struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt; + int i = 0; + + f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12; + fmt = find_format(&f); + queue = &ctx->out_queue; + queue->fmt = fmt; + queue->width = DEFAULT_WIDTH; + queue->height = DEFAULT_HEIGHT; + pix_mp->width = queue->width; + pix_mp->height = queue->height; + queue->crop.left = 0; + queue->crop.top = 0; + queue->crop.width = queue->width; + queue->crop.height = queue->height; + v4l2_apply_frmsize_constraints(&pix_mp->width, + &pix_mp->height, + &fmt->frmsize); + v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, + pix_mp->width, pix_mp->height); + for (i = 0; i < fmt->num_planes; i++) { + queue->bytesperline[i] = plane_fmt[i].bytesperline; + queue->sizeimage[i] = plane_fmt[i].sizeimage; + } + queue->width_adjusted = pix_mp->width; + queue->height_adjusted = pix_mp->height; + + f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_JPEG; + fmt = find_format(&f); + queue = &ctx->cap_queue; + queue->fmt = fmt; + queue->width = DEFAULT_WIDTH; + queue->height = DEFAULT_HEIGHT; + pix_mp->width = queue->width; + pix_mp->height = queue->height; + v4l2_apply_frmsize_constraints(&pix_mp->width, + &pix_mp->height, + &fmt->frmsize); + queue->sizeimage[0] = pix_mp->width * pix_mp->height * JPEG_MAX_BYTES_PER_PIXEL; + queue->sizeimage[0] += HEADER_SIZE; + queue->sizeimage[1] = 0; + queue->bytesperline[0] = 0; + queue->bytesperline[1] = 0; + queue->width_adjusted = pix_mp->width; + queue->height_adjusted = pix_mp->height; +} + +static int e5010_open(struct file *file) +{ + struct e5010_dev *e5010 = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + struct e5010_context *ctx; + int ret = 0; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (mutex_lock_interruptible(&e5010->mutex)) { + ret = -ERESTARTSYS; + goto free; + } + + v4l2_fh_init(&ctx->fh, vdev); + file->private_data = ctx; + v4l2_fh_add(&ctx->fh); + + ctx->e5010 = e5010; + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(e5010->m2m_dev, ctx, queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + v4l2_err(&e5010->v4l2_dev, "failed to init m2m ctx\n"); + ret = PTR_ERR(ctx->fh.m2m_ctx); + goto exit; + } + + ret = e5010_ctrls_setup(ctx); + if (ret) { + v4l2_err(&e5010->v4l2_dev, "failed to setup e5010 jpeg controls\n"); + goto err_ctrls_setup; + } + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + + e5010_jpeg_set_default_params(ctx); + + dprintk(e5010, 1, "Created instance: 0x%p, m2m_ctx: 0x%p\n", ctx, ctx->fh.m2m_ctx); + + mutex_unlock(&e5010->mutex); + return 0; + +err_ctrls_setup: + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); +exit: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + mutex_unlock(&e5010->mutex); +free: + kfree(ctx); + return ret; +} + +static int e5010_release(struct file *file) +{ + struct e5010_dev *e5010 = video_drvdata(file); + struct e5010_context *ctx = file->private_data; + + dprintk(e5010, 1, "Releasing instance: 0x%p, m2m_ctx: 0x%p\n", ctx, ctx->fh.m2m_ctx); + mutex_lock(&e5010->mutex); + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + mutex_unlock(&e5010->mutex); + + return 0; +} + +static void header_write(struct e5010_context *ctx, u8 *addr, unsigned int *offset, + unsigned int no_bytes, unsigned long bits) +{ + u8 *w_addr = addr + *offset; + int i; + + if ((*offset + no_bytes) > HEADER_SIZE) { + v4l2_warn(&ctx->e5010->v4l2_dev, "%s: %s: %d: Problem writing header. %d > HEADER_SIZE %d\n", + __FILE__, __func__, __LINE__, *offset + no_bytes, HEADER_SIZE); + return; + } + + for (i = no_bytes - 1; i >= 0; i--) + *(w_addr++) = ((u8 *)&bits)[i]; + + *offset += no_bytes; +} + +static void encode_marker_segment(struct e5010_context *ctx, void *addr, unsigned int *offset) +{ + u8 *buffer = (u8 *)addr; + int i; + const u8 *luma_dc_table, *chroma_dc_table, *luma_ac_table, *chroma_ac_table, *zigzag; + + v4l2_jpeg_get_reference_huffman_tables(&luma_dc_table, &luma_ac_table, &chroma_dc_table, + &chroma_ac_table); + v4l2_jpeg_get_zig_zag_scan(&zigzag); + + header_write(ctx, buffer, offset, 2, START_OF_IMAGE); + header_write(ctx, buffer, offset, 2, DQT_MARKER); + header_write(ctx, buffer, offset, 3, LQPQ << 4); + for (i = 0; i < V4L2_JPEG_PIXELS_IN_BLOCK; i++) + header_write(ctx, buffer, offset, 1, ctx->luma_qp[zigzag[i]]); + + header_write(ctx, buffer, offset, 2, DQT_MARKER); + header_write(ctx, buffer, offset, 3, (LQPQ << 4) | 1); + for (i = 0; i < V4L2_JPEG_PIXELS_IN_BLOCK; i++) + header_write(ctx, buffer, offset, 1, ctx->chroma_qp[zigzag[i]]); + + /* Huffman tables */ + header_write(ctx, buffer, offset, 2, DHT_MARKER); + header_write(ctx, buffer, offset, 2, LH_DC); + header_write(ctx, buffer, offset, 1, V4L2_JPEG_LUM_HT | V4L2_JPEG_DC_HT); + for (i = 0 ; i < V4L2_JPEG_REF_HT_DC_LEN; i++) + header_write(ctx, buffer, offset, 1, luma_dc_table[i]); + + header_write(ctx, buffer, offset, 2, DHT_MARKER); + header_write(ctx, buffer, offset, 2, LH_AC); + header_write(ctx, buffer, offset, 1, V4L2_JPEG_LUM_HT | V4L2_JPEG_AC_HT); + for (i = 0 ; i < V4L2_JPEG_REF_HT_AC_LEN; i++) + header_write(ctx, buffer, offset, 1, luma_ac_table[i]); + + header_write(ctx, buffer, offset, 2, DHT_MARKER); + header_write(ctx, buffer, offset, 2, LH_DC); + header_write(ctx, buffer, offset, 1, V4L2_JPEG_CHR_HT | V4L2_JPEG_DC_HT); + for (i = 0 ; i < V4L2_JPEG_REF_HT_DC_LEN; i++) + header_write(ctx, buffer, offset, 1, chroma_dc_table[i]); + + header_write(ctx, buffer, offset, 2, DHT_MARKER); + header_write(ctx, buffer, offset, 2, LH_AC); + header_write(ctx, buffer, offset, 1, V4L2_JPEG_CHR_HT | V4L2_JPEG_AC_HT); + for (i = 0 ; i < V4L2_JPEG_REF_HT_AC_LEN; i++) + header_write(ctx, buffer, offset, 1, chroma_ac_table[i]); +} + +static void encode_frame_header(struct e5010_context *ctx, void *addr, unsigned int *offset) +{ + u8 *buffer = (u8 *)addr; + + header_write(ctx, buffer, offset, 2, SOF_BASELINE_DCT); + header_write(ctx, buffer, offset, 2, 8 + (3 * UC_NUM_COMP)); + header_write(ctx, buffer, offset, 1, PRECISION); + header_write(ctx, buffer, offset, 2, ctx->out_queue.crop.height); + header_write(ctx, buffer, offset, 2, ctx->out_queue.crop.width); + header_write(ctx, buffer, offset, 1, UC_NUM_COMP); + + /* Luma details */ + header_write(ctx, buffer, offset, 1, 1); + if (ctx->out_queue.fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422) + header_write(ctx, buffer, offset, 1, + HORZ_SAMPLING_FACTOR | (VERT_SAMPLING_FACTOR_422)); + else + header_write(ctx, buffer, offset, 1, + HORZ_SAMPLING_FACTOR | (VERT_SAMPLING_FACTOR_420)); + header_write(ctx, buffer, offset, 1, 0); + /* Chroma details */ + header_write(ctx, buffer, offset, 1, 2); + header_write(ctx, buffer, offset, 1, (HORZ_SAMPLING_FACTOR >> 1) | 1); + header_write(ctx, buffer, offset, 1, 1); + header_write(ctx, buffer, offset, 1, 3); + header_write(ctx, buffer, offset, 1, (HORZ_SAMPLING_FACTOR >> 1) | 1); + header_write(ctx, buffer, offset, 1, 1); +} + +static void jpg_encode_sos_header(struct e5010_context *ctx, void *addr, unsigned int *offset) +{ + u8 *buffer = (u8 *)addr; + int i; + + header_write(ctx, buffer, offset, 2, START_OF_SCAN); + header_write(ctx, buffer, offset, 2, 6 + (COMPONENTS_IN_SCAN << 1)); + header_write(ctx, buffer, offset, 1, COMPONENTS_IN_SCAN); + + for (i = 0; i < COMPONENTS_IN_SCAN; i++) { + header_write(ctx, buffer, offset, 1, i + 1); + if (i == 0) + header_write(ctx, buffer, offset, 1, 0); + else + header_write(ctx, buffer, offset, 1, 17); + } + + header_write(ctx, buffer, offset, 1, 0); + header_write(ctx, buffer, offset, 1, 63); + header_write(ctx, buffer, offset, 1, 0); +} + +static void write_header(struct e5010_context *ctx, void *addr) +{ + unsigned int offset = 0; + + encode_marker_segment(ctx, addr, &offset); + encode_frame_header(ctx, addr, &offset); + jpg_encode_sos_header(ctx, addr, &offset); +} + +static irqreturn_t e5010_irq(int irq, void *data) +{ + struct e5010_dev *e5010 = data; + struct e5010_context *ctx; + int output_size; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + bool pic_done, out_addr_err; + + spin_lock(&e5010->hw_lock); + pic_done = e5010_hw_pic_done_irq(e5010->core_base); + out_addr_err = e5010_hw_output_address_irq(e5010->core_base); + + if (!pic_done && !out_addr_err) { + spin_unlock(&e5010->hw_lock); + return IRQ_NONE; + } + + ctx = v4l2_m2m_get_curr_priv(e5010->m2m_dev); + if (WARN_ON(!ctx)) + goto job_unlock; + + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + if (!dst_buf || !src_buf) { + v4l2_err(&e5010->v4l2_dev, "ctx: 0x%p No source or destination buffer\n", ctx); + goto job_unlock; + } + + if (out_addr_err) { + e5010_hw_clear_output_error(e5010->core_base, 1); + v4l2_warn(&e5010->v4l2_dev, + "ctx: 0x%p Output bitstream size exceeded max size\n", ctx); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, dst_buf->planes[0].length); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); + if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) { + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx); + v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event); + dprintk(e5010, 2, "ctx: 0x%p Sending EOS\n", ctx); + } + } + + if (pic_done) { + e5010_hw_clear_picture_done(e5010->core_base, 1); + dprintk(e5010, 3, "ctx: 0x%p Got output bitstream of size %d bytes\n", + ctx, readl(e5010->core_base + JASPER_OUTPUT_SIZE_OFFSET)); + + if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) { + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx); + v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event); + dprintk(e5010, 2, "ctx: 0x%p Sending EOS\n", ctx); + } + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + output_size = e5010_hw_get_output_size(e5010->core_base); + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, output_size + HEADER_SIZE); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + dprintk(e5010, 3, + "ctx: 0x%p frame done for dst_buf->sequence: %d src_buf->sequence: %d\n", + ctx, dst_buf->sequence, src_buf->sequence); + } + + v4l2_m2m_job_finish(e5010->m2m_dev, ctx->fh.m2m_ctx); + dprintk(e5010, 3, "ctx: 0x%p Finish job\n", ctx); + +job_unlock: + spin_unlock(&e5010->hw_lock); + return IRQ_HANDLED; +} + +static int e5010_init_device(struct e5010_dev *e5010) +{ + int ret = 0; + + /*TODO: Set MMU in bypass mode until support for the same is added in driver*/ + e5010_hw_bypass_mmu(e5010->mmu_base, 1); + + if (e5010_hw_enable_auto_clock_gating(e5010->core_base, 1)) + v4l2_warn(&e5010->v4l2_dev, "failed to enable auto clock gating\n"); + + if (e5010_hw_enable_manual_clock_gating(e5010->core_base, 0)) + v4l2_warn(&e5010->v4l2_dev, "failed to disable manual clock gating\n"); + + if (e5010_hw_enable_crc_check(e5010->core_base, 0)) + v4l2_warn(&e5010->v4l2_dev, "failed to disable CRC check\n"); + + if (e5010_hw_enable_output_address_error_irq(e5010->core_base, 1)) + v4l2_err(&e5010->v4l2_dev, "failed to enable Output Address Error interrupts\n"); + + ret = e5010_hw_set_input_source_to_memory(e5010->core_base, 1); + if (ret) { + v4l2_err(&e5010->v4l2_dev, "failed to set input source to memory\n"); + return ret; + } + + ret = e5010_hw_enable_picture_done_irq(e5010->core_base, 1); + if (ret) + v4l2_err(&e5010->v4l2_dev, "failed to enable Picture Done interrupts\n"); + + return ret; +} + +static int e5010_probe(struct platform_device *pdev) +{ + struct e5010_dev *e5010; + int irq, ret = 0; + struct device *dev = &pdev->dev; + + ret = dma_set_mask(dev, DMA_BIT_MASK(32)); + if (ret) + return dev_err_probe(dev, ret, "32-bit consistent DMA enable failed\n"); + + e5010 = devm_kzalloc(dev, sizeof(*e5010), GFP_KERNEL); + if (!e5010) + return -ENOMEM; + + platform_set_drvdata(pdev, e5010); + + e5010->dev = dev; + + mutex_init(&e5010->mutex); + spin_lock_init(&e5010->hw_lock); + + e5010->vdev = video_device_alloc(); + if (!e5010->vdev) { + dev_err(dev, "failed to allocate video device\n"); + return -ENOMEM; + } + + snprintf(e5010->vdev->name, sizeof(e5010->vdev->name), "%s", E5010_MODULE_NAME); + e5010->vdev->fops = &e5010_fops; + e5010->vdev->ioctl_ops = &e5010_ioctl_ops; + e5010->vdev->minor = -1; + e5010->vdev->release = video_device_release; + e5010->vdev->vfl_dir = VFL_DIR_M2M; + e5010->vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + e5010->vdev->v4l2_dev = &e5010->v4l2_dev; + e5010->vdev->lock = &e5010->mutex; + + ret = v4l2_device_register(dev, &e5010->v4l2_dev); + if (ret) + return dev_err_probe(dev, ret, "failed to register v4l2 device\n"); + + e5010->m2m_dev = v4l2_m2m_init(&e5010_m2m_ops); + if (IS_ERR(e5010->m2m_dev)) { + ret = PTR_ERR(e5010->m2m_dev); + e5010->m2m_dev = NULL; + dev_err_probe(dev, ret, "failed to init mem2mem device\n"); + goto fail_after_v4l2_register; + } + + video_set_drvdata(e5010->vdev, e5010); + + e5010->core_base = devm_platform_ioremap_resource_byname(pdev, "core"); + if (IS_ERR(e5010->core_base)) { + ret = PTR_ERR(e5010->core_base); + dev_err_probe(dev, ret, "Missing 'core' resources area\n"); + goto fail_after_v4l2_register; + } + + e5010->mmu_base = devm_platform_ioremap_resource_byname(pdev, "mmu"); + if (IS_ERR(e5010->mmu_base)) { + ret = PTR_ERR(e5010->mmu_base); + dev_err_probe(dev, ret, "Missing 'mmu' resources area\n"); + goto fail_after_v4l2_register; + } + + e5010->last_context_run = NULL; + + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(dev, irq, e5010_irq, 0, + E5010_MODULE_NAME, e5010); + if (ret) { + dev_err_probe(dev, ret, "failed to register IRQ %d\n", irq); + goto fail_after_v4l2_register; + } + + e5010->clk = devm_clk_get(dev, NULL); + if (IS_ERR(e5010->clk)) { + ret = PTR_ERR(e5010->clk); + dev_err_probe(dev, ret, "failed to get clock\n"); + goto fail_after_v4l2_register; + } + + pm_runtime_enable(dev); + + ret = video_register_device(e5010->vdev, VFL_TYPE_VIDEO, 0); + if (ret) { + dev_err_probe(dev, ret, "failed to register video device\n"); + goto fail_after_video_register_device; + } + + v4l2_info(&e5010->v4l2_dev, "Device registered as /dev/video%d\n", + e5010->vdev->num); + + return 0; + +fail_after_video_register_device: + v4l2_m2m_release(e5010->m2m_dev); +fail_after_v4l2_register: + v4l2_device_unregister(&e5010->v4l2_dev); + return ret; +} + +static int e5010_remove(struct platform_device *pdev) +{ + struct e5010_dev *e5010 = platform_get_drvdata(pdev); + + pm_runtime_disable(e5010->dev); + video_unregister_device(e5010->vdev); + v4l2_m2m_release(e5010->m2m_dev); + v4l2_device_unregister(&e5010->v4l2_dev); + + return 0; +} + +static void e5010_vb2_buffers_return(struct vb2_queue *q, enum vb2_buffer_state state) +{ + struct vb2_v4l2_buffer *vbuf; + struct e5010_context *ctx = vb2_get_drv_priv(q); + + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) { + dprintk(ctx->e5010, 2, "ctx: 0x%p, buf type %s | index %d\n", + ctx, type_name(vbuf->vb2_buf.type), vbuf->vb2_buf.index); + v4l2_m2m_buf_done(vbuf, state); + } + } else { + while ((vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) { + dprintk(ctx->e5010, 2, "ctx: 0x%p, buf type %s | index %d\n", + ctx, type_name(vbuf->vb2_buf.type), vbuf->vb2_buf.index); + vb2_set_plane_payload(&vbuf->vb2_buf, 0, 0); + v4l2_m2m_buf_done(vbuf, state); + } + } +} + +static int e5010_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct e5010_context *ctx = vb2_get_drv_priv(vq); + struct e5010_q_data *queue; + int i; + + queue = get_queue(ctx, vq->type); + + if (*nplanes) { + if (*nplanes != queue->fmt->num_planes) + return -EINVAL; + for (i = 0; i < *nplanes; i++) { + if (sizes[i] < queue->sizeimage[i]) + return -EINVAL; + } + return 0; + } + + *nplanes = queue->fmt->num_planes; + for (i = 0; i < *nplanes; i++) + sizes[i] = queue->sizeimage[i]; + + dprintk(ctx->e5010, 2, + "ctx: 0x%p, type %s, buffer(s): %d, planes %d, plane1: bytes %d plane2: %d bytes\n", + ctx, type_name(vq->type), *nbuffers, *nplanes, sizes[0], sizes[1]); + + return 0; +} + +static void e5010_buf_finish(struct vb2_buffer *vb) +{ + struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue); + void *d_addr; + + if (vb->state != VB2_BUF_STATE_DONE || V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) + return; + + d_addr = vb2_plane_vaddr(vb, 0); + write_header(ctx, d_addr); +} + +static int e5010_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue); + + if (vbuf->field != V4L2_FIELD_NONE) + dprintk(ctx->e5010, 1, "ctx: 0x%p, field isn't supported\n", ctx); + + vbuf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int e5010_buf_prepare(struct vb2_buffer *vb) +{ + struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct e5010_q_data *queue; + int i; + + vbuf->field = V4L2_FIELD_NONE; + + queue = get_queue(ctx, vb->vb2_queue->type); + + for (i = 0; i < queue->fmt->num_planes; i++) { + if (vb2_plane_size(vb, i) < (unsigned long)queue->sizeimage[i]) { + v4l2_err(&ctx->e5010->v4l2_dev, "plane %d too small (%lu < %lu)", i, + vb2_plane_size(vb, i), (unsigned long)queue->sizeimage[i]); + + return -EINVAL; + } + } + + if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { + vb2_set_plane_payload(vb, 0, 0); + vb2_set_plane_payload(vb, 1, 0); + } + + return 0; +} + +static void e5010_buf_queue(struct vb2_buffer *vb) +{ + struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) && + vb2_is_streaming(vb->vb2_queue) && + v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { + struct e5010_q_data *queue = get_queue(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + + vbuf->sequence = queue->sequence++; + v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf); + v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event); + return; + } + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static int e5010_encoder_cmd(struct file *file, void *priv, + struct v4l2_encoder_cmd *cmd) +{ + struct e5010_context *ctx = file->private_data; + int ret; + struct vb2_queue *cap_vq; + + cap_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, &ctx->fh, cmd); + if (ret < 0) + return ret; + + if (!vb2_is_streaming(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)) || + !vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx))) + return 0; + + ret = v4l2_m2m_ioctl_encoder_cmd(file, &ctx->fh, cmd); + if (ret < 0) + return ret; + + if (cmd->cmd == V4L2_ENC_CMD_STOP && + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) + v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event); + + if (cmd->cmd == V4L2_ENC_CMD_START && + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) + vb2_clear_last_buffer_dequeued(cap_vq); + + return 0; +} + +static int e5010_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct e5010_context *ctx = vb2_get_drv_priv(q); + int ret; + + struct e5010_q_data *queue = get_queue(ctx, q->type); + + v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q); + queue->sequence = 0; + + ret = pm_runtime_resume_and_get(ctx->e5010->dev); + if (ret < 0) { + v4l2_err(&ctx->e5010->v4l2_dev, "failed to power up jpeg\n"); + goto fail; + } + + ret = e5010_init_device(ctx->e5010); + if (ret) { + v4l2_err(&ctx->e5010->v4l2_dev, "failed to Enable e5010 device\n"); + goto fail; + } + + return 0; + +fail: + e5010_vb2_buffers_return(q, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static void e5010_stop_streaming(struct vb2_queue *q) +{ + struct e5010_context *ctx = vb2_get_drv_priv(q); + + e5010_vb2_buffers_return(q, VB2_BUF_STATE_ERROR); + + if (V4L2_TYPE_IS_OUTPUT(q->type)) + v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); + + if (V4L2_TYPE_IS_OUTPUT(q->type) && + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) { + v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event); + } + + pm_runtime_put_sync(ctx->e5010->dev); +} + +static void e5010_device_run(void *priv) +{ + struct e5010_context *ctx = priv; + struct e5010_dev *e5010 = ctx->e5010; + struct vb2_v4l2_buffer *s_vb, *d_vb; + u32 reg = 0; + int ret = 0, luma_crop_offset = 0, chroma_crop_offset = 0; + unsigned long flags; + int num_planes = ctx->out_queue.fmt->num_planes; + + spin_lock_irqsave(&e5010->hw_lock, flags); + s_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + WARN_ON(!s_vb); + d_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + WARN_ON(!d_vb); + if (!s_vb || !d_vb) + goto no_ready_buf_err; + + s_vb->sequence = ctx->out_queue.sequence++; + d_vb->sequence = ctx->cap_queue.sequence++; + + v4l2_m2m_buf_copy_metadata(s_vb, d_vb, false); + + if (ctx != e5010->last_context_run || ctx->update_qp) { + dprintk(e5010, 1, "ctx updated: 0x%p -> 0x%p, updating qp tables\n", + e5010->last_context_run, ctx); + ret = update_qp_tables(ctx); + } + + if (ret) { + ctx->update_qp = true; + v4l2_err(&e5010->v4l2_dev, "failed to update QP tables\n"); + goto device_busy_err; + } else { + e5010->last_context_run = ctx; + ctx->update_qp = false; + } + + /* Set I/O Buffer addresses */ + reg = (u32)vb2_dma_contig_plane_dma_addr(&s_vb->vb2_buf, 0); + + if (ctx->out_queue.crop_set) { + luma_crop_offset = ctx->out_queue.bytesperline[0] * ctx->out_queue.crop.top + + ctx->out_queue.crop.left; + + if (ctx->out_queue.fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422) { + chroma_crop_offset = + ctx->out_queue.bytesperline[0] * ctx->out_queue.crop.top + + ctx->out_queue.crop.left; + } else { + chroma_crop_offset = + ctx->out_queue.bytesperline[0] * ctx->out_queue.crop.top / 2 + + ctx->out_queue.crop.left; + } + + dprintk(e5010, 1, "Luma crop offset : %x, chroma crop offset : %x\n", + luma_crop_offset, chroma_crop_offset); + } + + ret = e5010_hw_set_input_luma_addr(e5010->core_base, reg + luma_crop_offset); + if (ret || !reg) { + v4l2_err(&e5010->v4l2_dev, "failed to set input luma address\n"); + goto device_busy_err; + } + + if (num_planes == 1) + reg += (ctx->out_queue.bytesperline[0]) * (ctx->out_queue.height); + else + reg = (u32)vb2_dma_contig_plane_dma_addr(&s_vb->vb2_buf, 1); + + dprintk(e5010, 3, + "ctx: 0x%p, luma_addr: 0x%x, chroma_addr: 0x%x, out_addr: 0x%x\n", + ctx, (u32)vb2_dma_contig_plane_dma_addr(&s_vb->vb2_buf, 0) + luma_crop_offset, + reg + chroma_crop_offset, (u32)vb2_dma_contig_plane_dma_addr(&d_vb->vb2_buf, 0)); + + dprintk(e5010, 3, + "ctx: 0x%p, buf indices: src_index: %d, dst_index: %d\n", + ctx, s_vb->vb2_buf.index, d_vb->vb2_buf.index); + + ret = e5010_hw_set_input_chroma_addr(e5010->core_base, reg + chroma_crop_offset); + if (ret || !reg) { + v4l2_err(&e5010->v4l2_dev, "failed to set input chroma address\n"); + goto device_busy_err; + } + + reg = (u32)vb2_dma_contig_plane_dma_addr(&d_vb->vb2_buf, 0); + reg += HEADER_SIZE; + ret = e5010_hw_set_output_base_addr(e5010->core_base, reg); + if (ret || !reg) { + v4l2_err(&e5010->v4l2_dev, "failed to set output base address\n"); + goto device_busy_err; + } + + /* Set input settings */ + ret = e5010_hw_set_horizontal_size(e5010->core_base, ctx->out_queue.crop.width - 1); + if (ret) { + v4l2_err(&e5010->v4l2_dev, "failed to set input width\n"); + goto device_busy_err; + } + + ret = e5010_hw_set_vertical_size(e5010->core_base, ctx->out_queue.crop.height - 1); + if (ret) { + v4l2_err(&e5010->v4l2_dev, "failed to set input width\n"); + goto device_busy_err; + } + + ret = e5010_hw_set_luma_stride(e5010->core_base, ctx->out_queue.bytesperline[0]); + if (ret) { + v4l2_err(&e5010->v4l2_dev, "failed to set luma stride\n"); + goto device_busy_err; + } + + ret = e5010_hw_set_chroma_stride(e5010->core_base, ctx->out_queue.bytesperline[0]); + if (ret) { + v4l2_err(&e5010->v4l2_dev, "failed to set chroma stride\n"); + goto device_busy_err; + } + + ret = e5010_set_input_subsampling(e5010->core_base, ctx->out_queue.fmt->subsampling); + if (ret) { + v4l2_err(&e5010->v4l2_dev, "failed to set input subsampling\n"); + goto device_busy_err; + } + + ret = e5010_hw_set_chroma_order(e5010->core_base, ctx->out_queue.fmt->chroma_order); + if (ret) { + v4l2_err(&e5010->v4l2_dev, "failed to set chroma order\n"); + goto device_busy_err; + } + + e5010_hw_set_output_max_size(e5010->core_base, d_vb->planes[0].length); + e5010_hw_encode_start(e5010->core_base, 1); + + spin_unlock_irqrestore(&e5010->hw_lock, flags); + + return; + +device_busy_err: + e5010_reset(e5010->dev, e5010->core_base, e5010->mmu_base); + +no_ready_buf_err: + if (s_vb) { + v4l2_m2m_src_buf_remove_by_buf(ctx->fh.m2m_ctx, s_vb); + v4l2_m2m_buf_done(s_vb, VB2_BUF_STATE_ERROR); + } + + if (d_vb) { + v4l2_m2m_dst_buf_remove_by_buf(ctx->fh.m2m_ctx, d_vb); + /* Payload set to 1 since 0 payload can trigger EOS */ + vb2_set_plane_payload(&d_vb->vb2_buf, 0, 1); + v4l2_m2m_buf_done(d_vb, VB2_BUF_STATE_ERROR); + } + v4l2_m2m_job_finish(e5010->m2m_dev, ctx->fh.m2m_ctx); + spin_unlock_irqrestore(&e5010->hw_lock, flags); +} + +#ifdef CONFIG_PM +static int e5010_runtime_resume(struct device *dev) +{ + struct e5010_dev *e5010 = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(e5010->clk); + if (ret < 0) { + v4l2_err(&e5010->v4l2_dev, "failed to enable clock\n"); + return ret; + } + + return 0; +} + +static int e5010_runtime_suspend(struct device *dev) +{ + struct e5010_dev *e5010 = dev_get_drvdata(dev); + + clk_disable_unprepare(e5010->clk); + + return 0; +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int e5010_suspend(struct device *dev) +{ + struct e5010_dev *e5010 = dev_get_drvdata(dev); + + v4l2_m2m_suspend(e5010->m2m_dev); + + return pm_runtime_force_suspend(dev); +} + +static int e5010_resume(struct device *dev) +{ + struct e5010_dev *e5010 = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; + + ret = e5010_init_device(e5010); + if (ret) { + dev_err(dev, "Failed to re-enable e5010 device\n"); + return ret; + } + + v4l2_m2m_resume(e5010->m2m_dev); + + return ret; +} +#endif + +static const struct dev_pm_ops e5010_pm_ops = { + SET_RUNTIME_PM_OPS(e5010_runtime_suspend, + e5010_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(e5010_suspend, e5010_resume) +}; + +static const struct v4l2_ioctl_ops e5010_ioctl_ops = { + .vidioc_querycap = e5010_querycap, + + .vidioc_enum_fmt_vid_cap = e5010_enum_fmt, + .vidioc_g_fmt_vid_cap_mplane = e5010_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = e5010_try_fmt, + .vidioc_s_fmt_vid_cap_mplane = e5010_s_fmt, + + .vidioc_enum_fmt_vid_out = e5010_enum_fmt, + .vidioc_g_fmt_vid_out_mplane = e5010_g_fmt, + .vidioc_try_fmt_vid_out_mplane = e5010_try_fmt, + .vidioc_s_fmt_vid_out_mplane = e5010_s_fmt, + + .vidioc_g_selection = e5010_g_selection, + .vidioc_s_selection = e5010_s_selection, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_log_status = v4l2_ctrl_log_status, + + .vidioc_subscribe_event = e5010_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = e5010_encoder_cmd, + + .vidioc_enum_framesizes = e5010_enum_framesizes, +}; + +static const struct vb2_ops e5010_video_ops = { + .queue_setup = e5010_queue_setup, + .buf_queue = e5010_buf_queue, + .buf_finish = e5010_buf_finish, + .buf_prepare = e5010_buf_prepare, + .buf_out_validate = e5010_buf_out_validate, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = e5010_start_streaming, + .stop_streaming = e5010_stop_streaming, +}; + +static const struct v4l2_file_operations e5010_fops = { + .owner = THIS_MODULE, + .open = e5010_open, + .release = e5010_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static const struct v4l2_m2m_ops e5010_m2m_ops = { + .device_run = e5010_device_run, +}; + +static const struct of_device_id e5010_of_match[] = { + {.compatible = "img,e5010-jpeg-enc"}, { /* end */}, +}; +MODULE_DEVICE_TABLE(of, e5010_of_match); + +static struct platform_driver e5010_driver = { + .probe = e5010_probe, + .remove = e5010_remove, + .driver = { + .name = E5010_MODULE_NAME, + .of_match_table = e5010_of_match, + .pm = &e5010_pm_ops, + }, +}; +module_platform_driver(e5010_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Imagination E5010 JPEG encoder driver"); diff -Naur --no-dereference a/drivers/media/platform/imagination/e5010/e5010-jpeg-enc.h b/drivers/media/platform/imagination/e5010/e5010-jpeg-enc.h --- a/drivers/media/platform/imagination/e5010/e5010-jpeg-enc.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/e5010/e5010-jpeg-enc.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Imagination E5010 JPEG Encoder driver. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + * Author: David Huang + * Author: Devarsh Thakkar + */ + +#include +#include +#include + +#ifndef _E5010_JPEG_ENC_H +#define _E5010_JPEG_ENC_H + +#define MAX_PLANES 2 +#define HEADER_SIZE 0x025D +#define MIN_DIMENSION 64 +#define MAX_DIMENSION 8192 +#define DEFAULT_WIDTH 640 +#define DEFAULT_HEIGHT 480 +#define E5010_MODULE_NAME "e5010" +#define JPEG_MAX_BYTES_PER_PIXEL 2 + +/* JPEG marker definitions */ +#define START_OF_IMAGE 0xFFD8 +#define SOF_BASELINE_DCT 0xFFC0 +#define END_OF_IMAGE 0xFFD9 +#define START_OF_SCAN 0xFFDA + +/* Definitions for the huffman table specification in the Marker segment */ +#define DHT_MARKER 0xFFC4 +#define LH_DC 0x001F +#define LH_AC 0x00B5 + +/* Definitions for the quantization table specification in the Marker segment */ +#define DQT_MARKER 0xFFDB +#define ACMAX 0x03FF +#define DCMAX 0x07FF + +/* Length and precision of the quantization table parameters */ +#define LQPQ 0x00430 +#define QMAX 255 + +/* Misc JPEG header definitions */ +#define UC_NUM_COMP 3 +#define PRECISION 8 +#define HORZ_SAMPLING_FACTOR (2 << 4) +#define VERT_SAMPLING_FACTOR_422 1 +#define VERT_SAMPLING_FACTOR_420 2 +#define COMPONENTS_IN_SCAN 3 +#define PELS_IN_BLOCK 64 + +/* Used for Qp table generation */ +#define LUMINOSITY 10 +#define CONTRAST 1 +#define INCREASE 2 +#define QP_TABLE_SIZE (8 * 8) +#define QP_TABLE_FIELD_OFFSET 0x04 + +/* + * vb2 queue structure + * contains queue data information + * + * @fmt: format info + * @width: frame width + * @height: frame height + * @bytesperline: bytes per line in memory + * @size_image: image size in memory + */ +struct e5010_q_data { + struct e5010_fmt *fmt; + u32 width; + u32 height; + u32 width_adjusted; + u32 height_adjusted; + u32 sizeimage[MAX_PLANES]; + u32 bytesperline[MAX_PLANES]; + u32 sequence; + struct v4l2_rect crop; + bool crop_set; +}; + +/* + * Driver device structure + * Holds all memory handles and global parameters + * Shared by all instances + */ +struct e5010_dev { + struct device *dev; + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m_dev; + struct video_device *vdev; + void __iomem *core_base; + void __iomem *mmu_base; + struct clk *clk; + struct e5010_context *last_context_run; + /* Protect access to device data */ + struct mutex mutex; + /* Protect access to hardware*/ + spinlock_t hw_lock; +}; + +/* + * Driver context structure + * One of these exists for every m2m context + * Holds context specific data + */ +struct e5010_context { + struct v4l2_fh fh; + struct e5010_dev *e5010; + struct e5010_q_data out_queue; + struct e5010_q_data cap_queue; + int quality; + bool update_qp; + struct v4l2_ctrl_handler ctrl_handler; + u8 luma_qp[QP_TABLE_SIZE]; + u8 chroma_qp[QP_TABLE_SIZE]; +}; + +/* + * Buffer structure + * Contains info for all buffers + */ +struct e5010_buffer { + struct v4l2_m2m_buffer buffer; +}; + +enum { + CHROMA_ORDER_CB_CR = 0, //UV ordering + CHROMA_ORDER_CR_CB = 1, //VU ordering +}; + +enum { + SUBSAMPLING_420 = 1, + SUBSAMPLING_422 = 2, +}; + +/* + * e5010 format structure + * contains format information + */ +struct e5010_fmt { + u32 fourcc; + unsigned int num_planes; + unsigned int type; + u32 subsampling; + u32 chroma_order; + const struct v4l2_frmsize_stepwise frmsize; +}; + +/* + * struct e5010_ctrl - contains info for each supported v4l2 control + */ +struct e5010_ctrl { + unsigned int cid; + enum v4l2_ctrl_type type; + unsigned char name[32]; + int minimum; + int maximum; + int step; + int default_value; + unsigned char compound; +}; + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/e5010/e5010-jpeg-enc-hw.c b/drivers/media/platform/imagination/e5010/e5010-jpeg-enc-hw.c --- a/drivers/media/platform/imagination/e5010/e5010-jpeg-enc-hw.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/e5010/e5010-jpeg-enc-hw.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Imagination E5010 JPEG Encoder driver. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + * Author: David Huang + * Author: Devarsh Thakkar + */ + +#include +#include +#include +#include "e5010-jpeg-enc-hw.h" + +static void write_reg_field(void __iomem *base, unsigned int offset, u32 mask, + unsigned int shift, u32 value) +{ + u32 reg; + + value <<= shift; + if (mask != 0xffffffff) { + reg = readl(base + offset); + value = (value & mask) | (reg & ~mask); + } + writel(value, (base + offset)); +} + +static int write_reg_field_not_busy(void __iomem *jasper_base, void __iomem *wr_base, + unsigned int offset, u32 mask, unsigned int shift, + u32 value) +{ + int ret; + u32 val; + + ret = readl_poll_timeout_atomic(jasper_base + JASPER_STATUS_OFFSET, val, + (val & JASPER_STATUS_CR_JASPER_BUSY_MASK) == 0, + 2000, 50000); + if (ret) + return ret; + + write_reg_field(wr_base, offset, mask, shift, value); + + return 0; +} + +void e5010_reset(struct device *dev, void __iomem *core_base, void __iomem *mmu_base) +{ + int ret = 0; + u32 val; + + write_reg_field(core_base, JASPER_RESET_OFFSET, + JASPER_RESET_CR_CORE_RESET_MASK, + JASPER_RESET_CR_CORE_RESET_SHIFT, 1); + + write_reg_field(mmu_base, MMU_MMU_CONTROL1_OFFSET, + MMU_MMU_CONTROL1_MMU_SOFT_RESET_MASK, + MMU_MMU_CONTROL1_MMU_SOFT_RESET_SHIFT, 1); + + ret = readl_poll_timeout_atomic(mmu_base + MMU_MMU_CONTROL1_OFFSET, val, + (val & MMU_MMU_CONTROL1_MMU_SOFT_RESET_MASK) == 0, + 2000, 50000); + if (ret) + dev_warn(dev, "MMU soft reset timed out, forcing system soft reset\n"); + + write_reg_field(core_base, JASPER_RESET_OFFSET, + JASPER_RESET_CR_SYS_RESET_MASK, + JASPER_RESET_CR_SYS_RESET_SHIFT, 1); +} + +void e5010_hw_bypass_mmu(void __iomem *mmu_base, u32 enable) +{ + /* Bypass MMU */ + write_reg_field(mmu_base, + MMU_MMU_ADDRESS_CONTROL_OFFSET, + MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_MASK, + MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_SHIFT, + enable); +} + +int e5010_hw_enable_output_address_error_irq(void __iomem *core_base, u32 enable) +{ + return write_reg_field_not_busy(core_base, core_base, + JASPER_INTERRUPT_MASK_OFFSET, + JASPER_INTERRUPT_MASK_CR_OUTPUT_ADDRESS_ERROR_ENABLE_MASK, + JASPER_INTERRUPT_MASK_CR_OUTPUT_ADDRESS_ERROR_ENABLE_SHIFT, + enable); +} + +bool e5010_hw_pic_done_irq(void __iomem *core_base) +{ + u32 reg; + + reg = readl(core_base + JASPER_INTERRUPT_STATUS_OFFSET); + return reg & JASPER_INTERRUPT_STATUS_CR_PICTURE_DONE_IRQ_MASK; +} + +bool e5010_hw_output_address_irq(void __iomem *core_base) +{ + u32 reg; + + reg = readl(core_base + JASPER_INTERRUPT_STATUS_OFFSET); + return reg & JASPER_INTERRUPT_STATUS_CR_OUTPUT_ADDRESS_ERROR_IRQ_MASK; +} + +int e5010_hw_enable_picture_done_irq(void __iomem *core_base, u32 enable) +{ + return write_reg_field_not_busy(core_base, core_base, + JASPER_INTERRUPT_MASK_OFFSET, + JASPER_INTERRUPT_MASK_CR_PICTURE_DONE_ENABLE_MASK, + JASPER_INTERRUPT_MASK_CR_PICTURE_DONE_ENABLE_SHIFT, + enable); +} + +int e5010_hw_enable_auto_clock_gating(void __iomem *core_base, u32 enable) +{ + return write_reg_field_not_busy(core_base, core_base, + JASPER_CLK_CONTROL_OFFSET, + JASPER_CLK_CONTROL_CR_JASPER_AUTO_CLKG_ENABLE_MASK, + JASPER_CLK_CONTROL_CR_JASPER_AUTO_CLKG_ENABLE_SHIFT, + enable); +} + +int e5010_hw_enable_manual_clock_gating(void __iomem *core_base, u32 enable) +{ + return write_reg_field_not_busy(core_base, core_base, + JASPER_CLK_CONTROL_OFFSET, + JASPER_CLK_CONTROL_CR_JASPER_MAN_CLKG_ENABLE_MASK, + JASPER_CLK_CONTROL_CR_JASPER_MAN_CLKG_ENABLE_SHIFT, 0); +} + +int e5010_hw_enable_crc_check(void __iomem *core_base, u32 enable) +{ + return write_reg_field_not_busy(core_base, core_base, + JASPER_CRC_CTRL_OFFSET, + JASPER_CRC_CTRL_JASPER_CRC_ENABLE_MASK, + JASPER_CRC_CTRL_JASPER_CRC_ENABLE_SHIFT, enable); +} + +int e5010_hw_set_input_source_to_memory(void __iomem *core_base, u32 set) +{ + return write_reg_field_not_busy(core_base, core_base, + JASPER_INPUT_CTRL0_OFFSET, + JASPER_INPUT_CTRL0_CR_INPUT_SOURCE_MASK, + JASPER_INPUT_CTRL0_CR_INPUT_SOURCE_SHIFT, set); +} + +int e5010_hw_set_input_luma_addr(void __iomem *core_base, u32 val) +{ + return write_reg_field_not_busy(core_base, core_base, + INPUT_LUMA_BASE_OFFSET, + INPUT_LUMA_BASE_CR_INPUT_LUMA_BASE_MASK, 0, val); +} + +int e5010_hw_set_input_chroma_addr(void __iomem *core_base, u32 val) +{ + return write_reg_field_not_busy(core_base, core_base, + INPUT_CHROMA_BASE_OFFSET, + INPUT_CHROMA_BASE_CR_INPUT_CHROMA_BASE_MASK, 0, val); +} + +int e5010_hw_set_output_base_addr(void __iomem *core_base, u32 val) +{ + return write_reg_field_not_busy(core_base, core_base, + JASPER_OUTPUT_BASE_OFFSET, + JASPER_OUTPUT_BASE_CR_OUTPUT_BASE_MASK, + JASPER_OUTPUT_BASE_CR_OUTPUT_BASE_SHIFT, val); +} + +int e5010_hw_set_horizontal_size(void __iomem *core_base, u32 val) +{ + return write_reg_field_not_busy(core_base, core_base, + JASPER_IMAGE_SIZE_OFFSET, + JASPER_IMAGE_SIZE_CR_IMAGE_HORIZONTAL_SIZE_MASK, + JASPER_IMAGE_SIZE_CR_IMAGE_HORIZONTAL_SIZE_SHIFT, + val); +} + +int e5010_hw_set_vertical_size(void __iomem *core_base, u32 val) +{ + return write_reg_field_not_busy(core_base, core_base, + JASPER_IMAGE_SIZE_OFFSET, + JASPER_IMAGE_SIZE_CR_IMAGE_VERTICAL_SIZE_MASK, + JASPER_IMAGE_SIZE_CR_IMAGE_VERTICAL_SIZE_SHIFT, + val); +} + +int e5010_hw_set_luma_stride(void __iomem *core_base, u32 bytesperline) +{ + u32 val = bytesperline / 64; + + return write_reg_field_not_busy(core_base, core_base, + JASPER_INPUT_CTRL1_OFFSET, + JASPER_INPUT_CTRL1_CR_INPUT_LUMA_STRIDE_MASK, + JASPER_INPUT_CTRL1_CR_INPUT_LUMA_STRIDE_SHIFT, + val); +} + +int e5010_hw_set_chroma_stride(void __iomem *core_base, u32 bytesperline) +{ + u32 val = bytesperline / 64; + + return write_reg_field_not_busy(core_base, core_base, + JASPER_INPUT_CTRL1_OFFSET, + JASPER_INPUT_CTRL1_CR_INPUT_CHROMA_STRIDE_MASK, + JASPER_INPUT_CTRL1_CR_INPUT_CHROMA_STRIDE_SHIFT, + val); +} + +int e5010_hw_set_input_subsampling(void __iomem *core_base, u32 val) +{ + return write_reg_field_not_busy(core_base, core_base, + JASPER_INPUT_CTRL0_OFFSET, + JASPER_INPUT_CTRL0_CR_INPUT_SUBSAMPLING_MASK, + JASPER_INPUT_CTRL0_CR_INPUT_SUBSAMPLING_SHIFT, + val); +} + +int e5010_hw_set_chroma_order(void __iomem *core_base, u32 val) +{ + return write_reg_field_not_busy(core_base, core_base, + JASPER_INPUT_CTRL0_OFFSET, + JASPER_INPUT_CTRL0_CR_INPUT_CHROMA_ORDER_MASK, + JASPER_INPUT_CTRL0_CR_INPUT_CHROMA_ORDER_SHIFT, + val); +} + +void e5010_hw_set_output_max_size(void __iomem *core_base, u32 val) +{ + write_reg_field(core_base, JASPER_OUTPUT_MAX_SIZE_OFFSET, + JASPER_OUTPUT_MAX_SIZE_CR_OUTPUT_MAX_SIZE_MASK, + JASPER_OUTPUT_MAX_SIZE_CR_OUTPUT_MAX_SIZE_SHIFT, + val); +} + +int e5010_hw_set_qpvalue(void __iomem *core_base, u32 offset, u32 val) +{ + return write_reg_field_not_busy(core_base, core_base, offset, 0xffffffff, 0, val); +} + +void e5010_hw_clear_output_error(void __iomem *core_base, u32 clear) +{ + /* Make sure interrupts are clear */ + write_reg_field(core_base, JASPER_INTERRUPT_CLEAR_OFFSET, + JASPER_INTERRUPT_CLEAR_CR_OUTPUT_ERROR_CLEAR_MASK, + JASPER_INTERRUPT_CLEAR_CR_OUTPUT_ERROR_CLEAR_SHIFT, clear); +} + +void e5010_hw_clear_picture_done(void __iomem *core_base, u32 clear) +{ + write_reg_field(core_base, + JASPER_INTERRUPT_CLEAR_OFFSET, + JASPER_INTERRUPT_CLEAR_CR_PICTURE_DONE_CLEAR_MASK, + JASPER_INTERRUPT_CLEAR_CR_PICTURE_DONE_CLEAR_SHIFT, clear); +} + +int e5010_hw_get_output_size(void __iomem *core_base) +{ + return readl(core_base + JASPER_OUTPUT_SIZE_OFFSET); +} + +void e5010_hw_encode_start(void __iomem *core_base, u32 start) +{ + write_reg_field(core_base, JASPER_CORE_CTRL_OFFSET, + JASPER_CORE_CTRL_CR_JASPER_ENCODE_START_MASK, + JASPER_CORE_CTRL_CR_JASPER_ENCODE_START_SHIFT, start); +} diff -Naur --no-dereference a/drivers/media/platform/imagination/e5010/e5010-jpeg-enc-hw.h b/drivers/media/platform/imagination/e5010/e5010-jpeg-enc-hw.h --- a/drivers/media/platform/imagination/e5010/e5010-jpeg-enc-hw.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/e5010/e5010-jpeg-enc-hw.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Imagination E5010 JPEG Encoder driver. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + * Author: David Huang + * Author: Devarsh Thakkar + */ + +#ifndef _E5010_JPEG_ENC_HW_H +#define _E5010_JPEG_ENC_HW_H + +#include "e5010-core-regs.h" +#include "e5010-mmu-regs.h" + +int e5010_hw_enable_output_address_error_irq(void __iomem *core_offset, u32 enable); +int e5010_hw_enable_picture_done_irq(void __iomem *core_offset, u32 enable); +int e5010_hw_enable_auto_clock_gating(void __iomem *core_offset, u32 enable); +int e5010_hw_enable_manual_clock_gating(void __iomem *core_offset, u32 enable); +int e5010_hw_enable_crc_check(void __iomem *core_offset, u32 enable); +int e5010_hw_set_input_source_to_memory(void __iomem *core_offset, u32 set); +int e5010_hw_set_input_luma_addr(void __iomem *core_offset, u32 val); +int e5010_hw_set_input_chroma_addr(void __iomem *core_offset, u32 val); +int e5010_hw_set_output_base_addr(void __iomem *core_offset, u32 val); +int e5010_hw_get_output_size(void __iomem *core_offset); +int e5010_hw_set_horizontal_size(void __iomem *core_offset, u32 val); +int e5010_hw_set_vertical_size(void __iomem *core_offset, u32 val); +int e5010_hw_set_luma_stride(void __iomem *core_offset, u32 bytesperline); +int e5010_hw_set_chroma_stride(void __iomem *core_offset, u32 bytesperline); +int e5010_hw_set_input_subsampling(void __iomem *core_offset, u32 val); +int e5010_hw_set_chroma_order(void __iomem *core_offset, u32 val); +int e5010_hw_set_qpvalue(void __iomem *core_offset, u32 offset, u32 value); +void e5010_reset(struct device *dev, void __iomem *core_offset, void __iomem *mmu_offset); +void e5010_hw_set_output_max_size(void __iomem *core_offset, u32 val); +void e5010_hw_clear_picture_done(void __iomem *core_offset, u32 clear); +void e5010_hw_encode_start(void __iomem *core_offset, u32 start); +void e5010_hw_clear_output_error(void __iomem *core_offset, u32 clear); +void e5010_hw_bypass_mmu(void __iomem *mmu_base, u32 enable); +bool e5010_hw_pic_done_irq(void __iomem *core_base); +bool e5010_hw_output_address_irq(void __iomem *core_base); +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/e5010/e5010-mmu-regs.h b/drivers/media/platform/imagination/e5010/e5010-mmu-regs.h --- a/drivers/media/platform/imagination/e5010/e5010-mmu-regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/e5010/e5010-mmu-regs.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,311 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Imagination E5010 JPEG Encoder driver. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + * Author: David Huang + * Author: Devarsh Thakkar + */ + +#ifndef _E5010_MMU_REGS_H +#define _E5010_MMU_REGS_H + +#define MMU_MMU_DIR_BASE_ADDR_OFFSET (0x0020) +#define MMU_MMU_DIR_BASE_ADDR_STRIDE (4) +#define MMU_MMU_DIR_BASE_ADDR_NO_ENTRIES (4) + +#define MMU_MMU_DIR_BASE_ADDR_MMU_DIR_BASE_ADDR_MASK (0xFFFFFFFF) +#define MMU_MMU_DIR_BASE_ADDR_MMU_DIR_BASE_ADDR_SHIFT (0) + +#define MMU_MMU_TILE_CFG_OFFSET (0x0040) +#define MMU_MMU_TILE_CFG_STRIDE (4) +#define MMU_MMU_TILE_CFG_NO_ENTRIES (4) + +#define MMU_MMU_TILE_CFG_TILE_128INTERLEAVE_MASK (0x00000010) +#define MMU_MMU_TILE_CFG_TILE_128INTERLEAVE_SHIFT (4) + +#define MMU_MMU_TILE_CFG_TILE_ENABLE_MASK (0x00000008) +#define MMU_MMU_TILE_CFG_TILE_ENABLE_SHIFT (3) + +#define MMU_MMU_TILE_CFG_TILE_STRIDE_MASK (0x00000007) +#define MMU_MMU_TILE_CFG_TILE_STRIDE_SHIFT (0) + +#define MMU_MMU_TILE_MIN_ADDR_OFFSET (0x0050) +#define MMU_MMU_TILE_MIN_ADDR_STRIDE (4) +#define MMU_MMU_TILE_MIN_ADDR_NO_ENTRIES (4) + +#define MMU_MMU_TILE_MIN_ADDR_TILE_MIN_ADDR_MASK (0xFFFFFFFF) +#define MMU_MMU_TILE_MIN_ADDR_TILE_MIN_ADDR_SHIFT (0) + +#define MMU_MMU_TILE_MAX_ADDR_OFFSET (0x0060) +#define MMU_MMU_TILE_MAX_ADDR_STRIDE (4) +#define MMU_MMU_TILE_MAX_ADDR_NO_ENTRIES (4) + +#define MMU_MMU_TILE_MAX_ADDR_TILE_MAX_ADDR_MASK (0xFFFFFFFF) +#define MMU_MMU_TILE_MAX_ADDR_TILE_MAX_ADDR_SHIFT (0) + +#define MMU_MMU_CONTROL0_OFFSET (0x0000) + +#define MMU_MMU_CONTROL0_MMU_TILING_SCHEME_MASK (0x00000001) +#define MMU_MMU_CONTROL0_MMU_TILING_SCHEME_SHIFT (0) + +#define MMU_MMU_CONTROL0_MMU_CACHE_POLICY_MASK (0x00000100) +#define MMU_MMU_CONTROL0_MMU_CACHE_POLICY_SHIFT (8) + +#define MMU_MMU_CONTROL0_FORCE_CACHE_POLICY_BYPASS_MASK (0x00000200) +#define MMU_MMU_CONTROL0_FORCE_CACHE_POLICY_BYPASS_SHIFT (9) + +#define MMU_MMU_CONTROL0_STALL_ON_PROTOCOL_FAULT_MASK (0x00001000) +#define MMU_MMU_CONTROL0_STALL_ON_PROTOCOL_FAULT_SHIFT (12) + +#define MMU_MMU_CONTROL1_OFFSET (0x0008) + +#define MMU_MMU_CONTROL1_MMU_FLUSH_MASK (0x00000008) +#define MMU_MMU_CONTROL1_MMU_FLUSH_SHIFT (3) +#define MMU_MMU_CONTROL1_MMU_FLUSH_NO_REPS (4) +#define MMU_MMU_CONTROL1_MMU_FLUSH_SIZE (1) + +#define MMU_MMU_CONTROL1_MMU_INVALDC_MASK (0x00000800) +#define MMU_MMU_CONTROL1_MMU_INVALDC_SHIFT (11) +#define MMU_MMU_CONTROL1_MMU_INVALDC_NO_REPS (4) +#define MMU_MMU_CONTROL1_MMU_INVALDC_SIZE (1) + +#define MMU_MMU_CONTROL1_MMU_FAULT_CLEAR_MASK (0x00010000) +#define MMU_MMU_CONTROL1_MMU_FAULT_CLEAR_SHIFT (16) + +#define MMU_MMU_CONTROL1_PROTOCOL_FAULT_CLEAR_MASK (0x00100000) +#define MMU_MMU_CONTROL1_PROTOCOL_FAULT_CLEAR_SHIFT (20) + +#define MMU_MMU_CONTROL1_MMU_PAUSE_SET_MASK (0x01000000) +#define MMU_MMU_CONTROL1_MMU_PAUSE_SET_SHIFT (24) + +#define MMU_MMU_CONTROL1_MMU_PAUSE_CLEAR_MASK (0x02000000) +#define MMU_MMU_CONTROL1_MMU_PAUSE_CLEAR_SHIFT (25) + +#define MMU_MMU_CONTROL1_MMU_SOFT_RESET_MASK (0x10000000) +#define MMU_MMU_CONTROL1_MMU_SOFT_RESET_SHIFT (28) + +#define MMU_MMU_BANK_INDEX_OFFSET (0x0010) + +#define MMU_MMU_BANK_INDEX_MMU_BANK_INDEX_MASK (0xC0000000) +#define MMU_MMU_BANK_INDEX_MMU_BANK_INDEX_SHIFT (30) +#define MMU_MMU_BANK_INDEX_MMU_BANK_INDEX_NO_REPS (16) +#define MMU_MMU_BANK_INDEX_MMU_BANK_INDEX_SIZE (2) + +#define MMU_REQUEST_PRIORITY_ENABLE_OFFSET (0x0018) + +#define MMU_REQUEST_PRIORITY_ENABLE_CMD_PRIORITY_ENABLE_MASK (0x00008000) +#define MMU_REQUEST_PRIORITY_ENABLE_CMD_PRIORITY_ENABLE_SHIFT (15) +#define MMU_REQUEST_PRIORITY_ENABLE_CMD_PRIORITY_ENABLE_NO_REPS (16) +#define MMU_REQUEST_PRIORITY_ENABLE_CMD_PRIORITY_ENABLE_SIZE (1) + +#define MMU_REQUEST_PRIORITY_ENABLE_CMD_MMU_PRIORITY_ENABLE_MASK (0x00010000) +#define MMU_REQUEST_PRIORITY_ENABLE_CMD_MMU_PRIORITY_ENABLE_SHIFT (16) + +#define MMU_REQUEST_LIMITED_THROUGHPUT_OFFSET (0x001C) + +#define MMU_REQUEST_LIMITED_THROUGHPUT_LIMITED_WORDS_MASK (0x000003FF) +#define MMU_REQUEST_LIMITED_THROUGHPUT_LIMITED_WORDS_SHIFT (0) + +#define MMU_REQUEST_LIMITED_THROUGHPUT_REQUEST_GAP_MASK (0x0FFF0000) +#define MMU_REQUEST_LIMITED_THROUGHPUT_REQUEST_GAP_SHIFT (16) + +#define MMU_MMU_ADDRESS_CONTROL_OFFSET (0x0070) +#define MMU_MMU_ADDRESS_CONTROL_TRUSTED (IMG_TRUE) + +#define MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_MASK (0x00000001) +#define MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_SHIFT (0) + +#define MMU_MMU_ADDRESS_CONTROL_MMU_ENABLE_EXT_ADDRESSING_MASK (0x00000010) +#define MMU_MMU_ADDRESS_CONTROL_MMU_ENABLE_EXT_ADDRESSING_SHIFT (4) + +#define MMU_MMU_ADDRESS_CONTROL_UPPER_ADDRESS_FIXED_MASK (0x00FF0000) +#define MMU_MMU_ADDRESS_CONTROL_UPPER_ADDRESS_FIXED_SHIFT (16) + +#define MMU_MMU_CONFIG0_OFFSET (0x0080) + +#define MMU_MMU_CONFIG0_NUM_REQUESTORS_MASK (0x0000000F) +#define MMU_MMU_CONFIG0_NUM_REQUESTORS_SHIFT (0) + +#define MMU_MMU_CONFIG0_EXTENDED_ADDR_RANGE_MASK (0x000000F0) +#define MMU_MMU_CONFIG0_EXTENDED_ADDR_RANGE_SHIFT (4) + +#define MMU_MMU_CONFIG0_GROUP_OVERRIDE_SIZE_MASK (0x00000700) +#define MMU_MMU_CONFIG0_GROUP_OVERRIDE_SIZE_SHIFT (8) + +#define MMU_MMU_CONFIG0_ADDR_COHERENCY_SUPPORTED_MASK (0x00001000) +#define MMU_MMU_CONFIG0_ADDR_COHERENCY_SUPPORTED_SHIFT (12) + +#define MMU_MMU_CONFIG0_MMU_SUPPORTED_MASK (0x00002000) +#define MMU_MMU_CONFIG0_MMU_SUPPORTED_SHIFT (13) + +#define MMU_MMU_CONFIG0_TILE_ADDR_GRANULARITY_MASK (0x001F0000) +#define MMU_MMU_CONFIG0_TILE_ADDR_GRANULARITY_SHIFT (16) + +#define MMU_MMU_CONFIG0_NO_READ_REORDER_MASK (0x00200000) +#define MMU_MMU_CONFIG0_NO_READ_REORDER_SHIFT (21) + +#define MMU_MMU_CONFIG0_TAGS_SUPPORTED_MASK (0xFFC00000) +#define MMU_MMU_CONFIG0_TAGS_SUPPORTED_SHIFT (22) + +#define MMU_MMU_CONFIG1_OFFSET (0x0084) + +#define MMU_MMU_CONFIG1_PAGE_SIZE_MASK (0x0000000F) +#define MMU_MMU_CONFIG1_PAGE_SIZE_SHIFT (0) + +#define MMU_MMU_CONFIG1_PAGE_CACHE_ENTRIES_MASK (0x0000FF00) +#define MMU_MMU_CONFIG1_PAGE_CACHE_ENTRIES_SHIFT (8) + +#define MMU_MMU_CONFIG1_DIR_CACHE_ENTRIES_MASK (0x001F0000) +#define MMU_MMU_CONFIG1_DIR_CACHE_ENTRIES_SHIFT (16) + +#define MMU_MMU_CONFIG1_BANDWIDTH_COUNT_SUPPORTED_MASK (0x01000000) +#define MMU_MMU_CONFIG1_BANDWIDTH_COUNT_SUPPORTED_SHIFT (24) + +#define MMU_MMU_CONFIG1_STALL_COUNT_SUPPORTED_MASK (0x02000000) +#define MMU_MMU_CONFIG1_STALL_COUNT_SUPPORTED_SHIFT (25) + +#define MMU_MMU_CONFIG1_LATENCY_COUNT_SUPPORTED_MASK (0x04000000) +#define MMU_MMU_CONFIG1_LATENCY_COUNT_SUPPORTED_SHIFT (26) + +#define MMU_MMU_STATUS0_OFFSET (0x0088) + +#define MMU_MMU_STATUS0_MMU_PF_N_RW_MASK (0x00000001) +#define MMU_MMU_STATUS0_MMU_PF_N_RW_SHIFT (0) + +#define MMU_MMU_STATUS0_MMU_FAULT_ADDR_MASK (0xFFFFF000) +#define MMU_MMU_STATUS0_MMU_FAULT_ADDR_SHIFT (12) + +#define MMU_MMU_STATUS1_OFFSET (0x008C) + +#define MMU_MMU_STATUS1_MMU_FAULT_REQ_STAT_MASK (0x0000FFFF) +#define MMU_MMU_STATUS1_MMU_FAULT_REQ_STAT_SHIFT (0) + +#define MMU_MMU_STATUS1_MMU_FAULT_REQ_ID_MASK (0x000F0000) +#define MMU_MMU_STATUS1_MMU_FAULT_REQ_ID_SHIFT (16) + +#define MMU_MMU_STATUS1_MMU_FAULT_INDEX_MASK (0x03000000) +#define MMU_MMU_STATUS1_MMU_FAULT_INDEX_SHIFT (24) + +#define MMU_MMU_STATUS1_MMU_FAULT_RNW_MASK (0x10000000) +#define MMU_MMU_STATUS1_MMU_FAULT_RNW_SHIFT (28) + +#define MMU_MMU_MEM_REQ_OFFSET (0x0090) + +#define MMU_MMU_MEM_REQ_TAG_OUTSTANDING_MASK (0x000003FF) +#define MMU_MMU_MEM_REQ_TAG_OUTSTANDING_SHIFT (0) + +#define MMU_MMU_MEM_REQ_EXT_WRRESP_FAULT_MASK (0x00001000) +#define MMU_MMU_MEM_REQ_EXT_WRRESP_FAULT_SHIFT (12) + +#define MMU_MMU_MEM_REQ_EXT_RDRESP_FAULT_MASK (0x00002000) +#define MMU_MMU_MEM_REQ_EXT_RDRESP_FAULT_SHIFT (13) + +#define MMU_MMU_MEM_REQ_EXT_READ_BURST_FAULT_MASK (0x00004000) +#define MMU_MMU_MEM_REQ_EXT_READ_BURST_FAULT_SHIFT (14) + +#define MMU_MMU_MEM_REQ_INT_PROTOCOL_FAULT_MASK (0x80000000) +#define MMU_MMU_MEM_REQ_INT_PROTOCOL_FAULT_SHIFT (31) +#define MMU_MMU_MEM_REQ_INT_PROTOCOL_FAULT_NO_REPS (16) +#define MMU_MMU_MEM_REQ_INT_PROTOCOL_FAULT_SIZE (1) + +#define MMU_MMU_FAULT_SELECT_OFFSET (0x00A0) + +#define MMU_MMU_FAULT_SELECT_MMU_FAULT_SELECT_MASK (0x0000000F) +#define MMU_MMU_FAULT_SELECT_MMU_FAULT_SELECT_SHIFT (0) + +#define MMU_PROTOCOL_FAULT_OFFSET (0x00A8) + +#define MMU_PROTOCOL_FAULT_FAULT_PAGE_BREAK_MASK (0x00000001) +#define MMU_PROTOCOL_FAULT_FAULT_PAGE_BREAK_SHIFT (0) + +#define MMU_PROTOCOL_FAULT_FAULT_WRITE_MASK (0x00000010) +#define MMU_PROTOCOL_FAULT_FAULT_WRITE_SHIFT (4) + +#define MMU_PROTOCOL_FAULT_FAULT_READ_MASK (0x00000020) +#define MMU_PROTOCOL_FAULT_FAULT_READ_SHIFT (5) + +#define MMU_TOTAL_READ_REQ_OFFSET (0x0100) + +#define MMU_TOTAL_READ_REQ_TOTAL_READ_REQ_MASK (0xFFFFFFFF) +#define MMU_TOTAL_READ_REQ_TOTAL_READ_REQ_SHIFT (0) + +#define MMU_TOTAL_WRITE_REQ_OFFSET (0x0104) + +#define MMU_TOTAL_WRITE_REQ_TOTAL_WRITE_REQ_MASK (0xFFFFFFFF) +#define MMU_TOTAL_WRITE_REQ_TOTAL_WRITE_REQ_SHIFT (0) + +#define MMU_READS_LESS_64_REQ_OFFSET (0x0108) + +#define MMU_READS_LESS_64_REQ_READS_LESS_64_REQ_MASK (0xFFFFFFFF) +#define MMU_READS_LESS_64_REQ_READS_LESS_64_REQ_SHIFT (0) + +#define MMU_WRITES_LESS_64_REQ_OFFSET (0x010C) + +#define MMU_WRITES_LESS_64_REQ_WRITES_LESS_64_REQ_MASK (0xFFFFFFFF) +#define MMU_WRITES_LESS_64_REQ_WRITES_LESS_64_REQ_SHIFT (0) + +#define MMU_EXT_CMD_STALL_OFFSET (0x0120) + +#define MMU_EXT_CMD_STALL_EXT_CMD_STALL_MASK (0xFFFFFFFF) +#define MMU_EXT_CMD_STALL_EXT_CMD_STALL_SHIFT (0) + +#define MMU_WRITE_REQ_STALL_OFFSET (0x0124) + +#define MMU_WRITE_REQ_STALL_WRITE_REQ_STALL_MASK (0xFFFFFFFF) +#define MMU_WRITE_REQ_STALL_WRITE_REQ_STALL_SHIFT (0) + +#define MMU_MMU_MISS_STALL_OFFSET (0x0128) + +#define MMU_MMU_MISS_STALL_MMU_MISS_STALL_MASK (0xFFFFFFFF) +#define MMU_MMU_MISS_STALL_MMU_MISS_STALL_SHIFT (0) + +#define MMU_ADDRESS_STALL_OFFSET (0x012C) + +#define MMU_ADDRESS_STALL_ADDRESS_STALL_MASK (0xFFFFFFFF) +#define MMU_ADDRESS_STALL_ADDRESS_STALL_SHIFT (0) + +#define MMU_TAG_STALL_OFFSET (0x0130) + +#define MMU_TAG_STALL_TAG_STALL_MASK (0xFFFFFFFF) +#define MMU_TAG_STALL_TAG_STALL_SHIFT (0) + +#define MMU_PEAK_READ_OUTSTANDING_OFFSET (0x0140) + +#define MMU_PEAK_READ_OUTSTANDING_PEAK_TAG_OUTSTANDING_MASK (0x000003FF) +#define MMU_PEAK_READ_OUTSTANDING_PEAK_TAG_OUTSTANDING_SHIFT (0) + +#define MMU_PEAK_READ_OUTSTANDING_PEAK_READ_LATENCY_MASK (0xFFFF0000) +#define MMU_PEAK_READ_OUTSTANDING_PEAK_READ_LATENCY_SHIFT (16) + +#define MMU_AVERAGE_READ_LATENCY_OFFSET (0x0144) + +#define MMU_AVERAGE_READ_LATENCY_AVERAGE_READ_LATENCY_MASK (0xFFFFFFFF) +#define MMU_AVERAGE_READ_LATENCY_AVERAGE_READ_LATENCY_SHIFT (0) + +#define MMU_STATISTICS_CONTROL_OFFSET (0x0160) + +#define MMU_STATISTICS_CONTROL_BANDWIDTH_STATS_INIT_MASK (0x00000001) +#define MMU_STATISTICS_CONTROL_BANDWIDTH_STATS_INIT_SHIFT (0) + +#define MMU_STATISTICS_CONTROL_STALL_STATS_INIT_MASK (0x00000002) +#define MMU_STATISTICS_CONTROL_STALL_STATS_INIT_SHIFT (1) + +#define MMU_STATISTICS_CONTROL_LATENCY_STATS_INIT_MASK (0x00000004) +#define MMU_STATISTICS_CONTROL_LATENCY_STATS_INIT_SHIFT (2) + +#define MMU_MMU_VERSION_OFFSET (0x01D0) + +#define MMU_MMU_VERSION_MMU_MAJOR_REV_MASK (0x00FF0000) +#define MMU_MMU_VERSION_MMU_MAJOR_REV_SHIFT (16) + +#define MMU_MMU_VERSION_MMU_MINOR_REV_MASK (0x0000FF00) +#define MMU_MMU_VERSION_MMU_MINOR_REV_SHIFT (8) + +#define MMU_MMU_VERSION_MMU_MAINT_REV_MASK (0x000000FF) +#define MMU_MMU_VERSION_MMU_MAINT_REV_SHIFT (0) + +#define MMU_BYTE_SIZE (0x01D4) + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/e5010/Kconfig b/drivers/media/platform/imagination/e5010/Kconfig --- a/drivers/media/platform/imagination/e5010/Kconfig 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/e5010/Kconfig 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 +config VIDEO_E5010_JPEG_ENC + tristate "Imagination E5010 JPEG Encoder Driver" + depends on VIDEO_DEV + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_VMALLOC + select V4L2_MEM2MEM_DEV + select V4L2_JPEG_HELPER + help + This is a video4linux2 M2M driver for Imagination E5010 JPEG encoder, + which supports JPEG and MJPEG baseline encoding of YUV422 and YUV420 + semiplanar video formats, with resolution ranging from 64x64 to 8K x 8K + pixels. The module will be named as e5010_jpeg_enc. diff -Naur --no-dereference a/drivers/media/platform/imagination/e5010/Makefile b/drivers/media/platform/imagination/e5010/Makefile --- a/drivers/media/platform/imagination/e5010/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/e5010/Makefile 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +e5010_jpeg_enc-objs := e5010-jpeg-enc-hw.o e5010-jpeg-enc.o +obj-$(CONFIG_VIDEO_E5010_JPEG_ENC) += e5010_jpeg_enc.o diff -Naur --no-dereference a/drivers/media/platform/imagination/Kconfig b/drivers/media/platform/imagination/Kconfig --- a/drivers/media/platform/imagination/Kconfig 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/Kconfig 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0-only + +comment "IMG media platform drivers" + +config VIDEO_IMG_VXD_DEC + tristate "IMG VXD DEC (Video Decoder) driver" + depends on V4L_MEM2MEM_DRIVERS + depends on VIDEO_DEV + depends on ARCH_K3 || COMPILE_TEST + depends on V4L_PLATFORM_DRIVERS + select VIDEOBUF2_CORE + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_DMA_SG + select V4L2_MEM2MEM_DEV + help + This is an IMG VXD DEC V4L2 driver that adds support for the + Imagination D5520 (Video Decoder) hardware as used on the Texas + Instruments Jacinto and Sitara devices. + The module name when built is vxd-dec. + +config VIDEO_IMG_VXE_ENC + tristate "IMG VXE ENC (Video Encoder) driver" + depends on V4L_MEM2MEM_DRIVERS + depends on VIDEO_DEV + depends on ARCH_K3 || COMPILE_TEST + depends on V4L_PLATFORM_DRIVERS + select VIDEOBUF2_CORE + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_DMA_SG + select V4L2_MEM2MEM_DEV + help + This is an IMG VXE ENC V4L2 driver that adds support for the + Imagination VXE384 (Video Encoder) hardware as used on the Texas + Instruments Jacinto and Sitara devices. + The module name when built is vxe-enc. + +source "drivers/media/platform/imagination/e5010/Kconfig" + diff -Naur --no-dereference a/drivers/media/platform/imagination/Makefile b/drivers/media/platform/imagination/Makefile --- a/drivers/media/platform/imagination/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/Makefile 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += vxe-vxd/ e5010/ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/addr_alloc.c b/drivers/media/platform/imagination/vxe-vxd/common/addr_alloc.c --- a/drivers/media/platform/imagination/vxe-vxd/common/addr_alloc.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/addr_alloc.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,499 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Address allocation APIs - used to manage address allocation + * with a number of predefined regions. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Sidraya Jayagond + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "addr_alloc.h" +#include "hash.h" +#include "img_errors.h" + +/* Global context. */ +static struct addr_context global_ctx = {0}; +/* Sub-system initialized. */ +static int global_initialized; +/* Count of contexts. */ +static unsigned int num_ctx; +/* Global mutex */ +static struct mutex *global_lock; + +/** + * addr_initialise - addr_initialise + */ + +int addr_initialise(void) +{ + unsigned int result = IMG_ERROR_ALREADY_INITIALISED; + + /* If we are not initialized */ + if (!global_initialized) + result = addr_cx_initialise(&global_ctx); + return result; +} + +int addr_cx_initialise(struct addr_context * const context) +{ + unsigned int result = IMG_ERROR_FATAL; + + if (!context) + return IMG_ERROR_INVALID_PARAMETERS; + + if (!global_initialized) { + /* Initialise context */ + memset(context, 0x00, sizeof(struct addr_context)); + + /* If no mutex associated with this resource */ + if (!global_lock) { + /* Create one */ + + global_lock = kzalloc(sizeof(*global_lock), GFP_KERNEL); + if (!global_lock) + return -ENOMEM; + + mutex_init(global_lock); + } + + mutex_lock_nested(global_lock, SUBCLASS_ADDR_ALLOC); + + /* Initialise the hash functions. */ + result = vid_hash_initialise(); + if (result != IMG_SUCCESS) { + mutex_unlock(global_lock); + return IMG_ERROR_UNEXPECTED_STATE; + } + + /* Initialise the arena functions */ + result = vid_ra_initialise(); + if (result != IMG_SUCCESS) { + mutex_unlock(global_lock); + result = vid_hash_finalise(); + return IMG_ERROR_UNEXPECTED_STATE; + } + + /* We are now initialized */ + global_initialized = TRUE; + result = IMG_SUCCESS; + } else { + mutex_lock_nested(global_lock, SUBCLASS_ADDR_ALLOC); + } + + num_ctx++; + mutex_unlock(global_lock); + + return result; +} + +int addr_deinitialise(void) +{ + return addr_cx_deinitialise(&global_ctx); +} + +int addr_cx_deinitialise(struct addr_context * const context) +{ + struct addr_region *tmp_region = NULL; + unsigned int result = IMG_ERROR_FATAL; + + if (!context) + return IMG_ERROR_INVALID_PARAMETERS; + + if (global_initialized) { + mutex_lock_nested(global_lock, SUBCLASS_ADDR_ALLOC); + + tmp_region = context->regions; + + /* Delete all arena structure */ + if (context->default_region) + result = vid_ra_delete(context->default_region->arena); + + while (tmp_region) { + result = vid_ra_delete(tmp_region->arena); + tmp_region = tmp_region->nxt_region; + } + + if (num_ctx != 0) + num_ctx--; + + result = IMG_SUCCESS; + if (num_ctx == 0) { + /* Free off resources */ + result = vid_hash_finalise(); + result = vid_ra_deinit(); + global_initialized = FALSE; + + mutex_unlock(global_lock); + mutex_destroy(global_lock); + kfree(global_lock); + global_lock = NULL; + } else { + mutex_unlock(global_lock); + } + } + + return result; +} + +int addr_define_mem_region(struct addr_region * const region) +{ + return addr_cx_define_mem_region(&global_ctx, region); +} + +int addr_cx_define_mem_region(struct addr_context * const context, + struct addr_region * const region) +{ + struct addr_region *tmp_region = NULL; + unsigned int result = IMG_SUCCESS; + + if (!context || !region) + return IMG_ERROR_INVALID_PARAMETERS; + + mutex_lock_nested(global_lock, SUBCLASS_ADDR_ALLOC); + + tmp_region = context->regions; + + /* Ensure the link to the next is NULL */ + region->nxt_region = NULL; + + /* If this is the default memory region */ + if (!region->name) { + /* Should not previously have been defined */ + if (context->default_region) { + mutex_unlock(global_lock); + return IMG_ERROR_UNEXPECTED_STATE; + } + + context->default_region = region; + context->no_regions++; + + /* + * Create an arena for memory allocation + * name of resource arena for debug + * start of resource + * size of resource + * allocation quantum + * import allocator + * import deallocator + * import handle + */ + result = vid_ra_create("memory", + region->base_addr, + region->size, + 1, + NULL, + NULL, + NULL, + ®ion->arena); + + if (result != IMG_SUCCESS) { + mutex_unlock(global_lock); + return IMG_ERROR_UNEXPECTED_STATE; + } + } else { + /* + * Run down the list of existing named regions + * to check if there is a region with this name + */ + while (tmp_region && + (strcmp(region->name, tmp_region->name) != 0) && + tmp_region->nxt_region) { + tmp_region = tmp_region->nxt_region; + } + + /* If we have items in the list */ + if (tmp_region) { + /* + * Check we didn't stop because the name + * clashes with one already defined. + */ + + if (strcmp(region->name, tmp_region->name) == 0 || + tmp_region->nxt_region) { + mutex_unlock(global_lock); + return IMG_ERROR_UNEXPECTED_STATE; + } + + /* Add to end of list */ + tmp_region->nxt_region = region; + } else { + /* Add to head of list */ + context->regions = region; + } + + context->no_regions++; + + /* + * Create an arena for memory allocation + * name of resource arena for debug + * start of resource + * size of resource + * allocation quantum + * import allocator + * import deallocator + * import handle + */ + result = vid_ra_create(region->name, + region->base_addr, + region->size, + 1, + NULL, + NULL, + NULL, + ®ion->arena); + + if (result != IMG_SUCCESS) { + mutex_unlock(global_lock); + return IMG_ERROR_UNEXPECTED_STATE; + } + } + + mutex_unlock(global_lock); + + /* Check the arean was created OK */ + if (!region->arena) + return IMG_ERROR_UNEXPECTED_STATE; + + return result; +} + +int addr_malloc(const unsigned char * const name, + unsigned long long size, + unsigned long long * const base_adr) +{ + return addr_cx_malloc(&global_ctx, name, size, base_adr); +} + +int addr_cx_malloc(struct addr_context * const context, + const unsigned char * const name, + unsigned long long size, + unsigned long long * const base_adr) +{ + unsigned int result = IMG_ERROR_FATAL; + struct addr_region *tmp_region = NULL; + + if (!context || !base_adr || !name) + return IMG_ERROR_INVALID_PARAMETERS; + + *(base_adr) = (unsigned long long)-1LL; + + mutex_lock_nested(global_lock, SUBCLASS_ADDR_ALLOC); + + tmp_region = context->regions; + + /* + * Run down the list of existing named + * regions to locate this + */ + while (tmp_region && (strcmp(name, tmp_region->name) != 0) && (tmp_region->nxt_region)) + tmp_region = tmp_region->nxt_region; + + /* If there was no match. */ + if (!tmp_region || (strcmp(name, tmp_region->name) != 0)) { + /* Use the default */ + if (!context->default_region) { + mutex_unlock(global_lock); + return IMG_ERROR_UNEXPECTED_STATE; + } + + tmp_region = context->default_region; + } + + if (!tmp_region) { + mutex_unlock(global_lock); + return IMG_ERROR_UNEXPECTED_STATE; + } + + /* Allocate size + guard band */ + result = vid_ra_alloc(tmp_region->arena, + size + tmp_region->guard_band, + NULL, + NULL, + SEQUENTIAL_ALLOCATION, + 1, + base_adr); + if (result != IMG_SUCCESS) { + mutex_unlock(global_lock); + return IMG_ERROR_OUT_OF_MEMORY; + } + + mutex_unlock(global_lock); + + return result; +} + +int addr_cx_malloc_res(struct addr_context * const context, + const unsigned char * const name, + unsigned long long size, + unsigned long long * const base_adr) +{ + unsigned int result = IMG_ERROR_FATAL; + struct addr_region *tmp_region = NULL; + + if (!context || !base_adr || !name) + return IMG_ERROR_INVALID_PARAMETERS; + + mutex_lock_nested(global_lock, SUBCLASS_ADDR_ALLOC); + + tmp_region = context->regions; + /* If the allocation is for the default region */ + /* + * Run down the list of existing named + * regions to locate this + */ + while (tmp_region && (strcmp(name, tmp_region->name) != 0) && (tmp_region->nxt_region)) + tmp_region = tmp_region->nxt_region; + + /* If there was no match. */ + if (!tmp_region || (strcmp(name, tmp_region->name) != 0)) { + /* Use the default */ + if (!context->default_region) { + mutex_unlock(global_lock); + return IMG_ERROR_UNEXPECTED_STATE; + } + tmp_region = context->default_region; + } + if (!tmp_region) { + mutex_unlock(global_lock); + return IMG_ERROR_UNEXPECTED_STATE; + } + /* Allocate size + guard band */ + result = vid_ra_alloc(tmp_region->arena, size + tmp_region->guard_band, + NULL, NULL, SEQUENTIAL_ALLOCATION, 1, base_adr); + if (result != IMG_SUCCESS) { + mutex_unlock(global_lock); + return IMG_ERROR_OUT_OF_MEMORY; + } + mutex_unlock(global_lock); + + return result; +} + +int addr_cx_malloc_align_res(struct addr_context * const context, + const unsigned char * const name, + unsigned long long size, + unsigned long long alignment, + unsigned long long * const base_adr) +{ + unsigned int result; + struct addr_region *tmp_region = NULL; + + if (!context || !base_adr || !name) + return IMG_ERROR_INVALID_PARAMETERS; + + mutex_lock_nested(global_lock, SUBCLASS_ADDR_ALLOC); + + tmp_region = context->regions; + + /* + * Run down the list of existing named + * regions to locate this + */ + while (tmp_region && + (strcmp(name, tmp_region->name) != 0) && + (tmp_region->nxt_region)) { + tmp_region = tmp_region->nxt_region; + } + /* If there was no match. */ + if (!tmp_region || + (strcmp(name, tmp_region->name) != 0)) { + /* Use the default */ + if (!context->default_region) { + mutex_unlock(global_lock); + return IMG_ERROR_UNEXPECTED_STATE; + } + + tmp_region = context->default_region; + } + + if (!tmp_region) { + mutex_unlock(global_lock); + return IMG_ERROR_UNEXPECTED_STATE; + } + /* Allocate size + guard band */ + result = vid_ra_alloc(tmp_region->arena, + size + tmp_region->guard_band, + NULL, + NULL, + SEQUENTIAL_ALLOCATION, + alignment, + base_adr); + if (result != IMG_SUCCESS) { + mutex_unlock(global_lock); + return IMG_ERROR_OUT_OF_MEMORY; + } + + mutex_unlock(global_lock); + + return result; +} + +int addr_free(const unsigned char * const name, unsigned long long addr) +{ + return addr_cx_free(&global_ctx, name, addr); +} + +int addr_cx_free(struct addr_context * const context, + const unsigned char * const name, + unsigned long long addr) +{ + struct addr_region *tmp_region; + unsigned int result; + + if (!context) + return IMG_ERROR_INVALID_PARAMETERS; + + tmp_region = context->regions; + + mutex_lock_nested(global_lock, SUBCLASS_ADDR_ALLOC); + + /* If the allocation is for the default region */ + if (!name) { + if (!context->default_region) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + tmp_region = context->default_region; + } else { + /* + * Run down the list of existing named + * regions to locate this + */ + while (tmp_region && + (strcmp(name, tmp_region->name) != 0) && + tmp_region->nxt_region) { + tmp_region = tmp_region->nxt_region; + } + + /* If there was no match */ + if (!tmp_region || (strcmp(name, tmp_region->name) != 0)) { + /* Use the default */ + if (!context->default_region) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + tmp_region = context->default_region; + } + } + + /* Free the address */ + result = vid_ra_free(tmp_region->arena, addr); + +error: + mutex_unlock(global_lock); + return result; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/addr_alloc.h b/drivers/media/platform/imagination/vxe-vxd/common/addr_alloc.h --- a/drivers/media/platform/imagination/vxe-vxd/common/addr_alloc.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/addr_alloc.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,238 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Address allocation management API. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Sidraya Jayagond + */ +#ifndef __ADDR_ALLOC_H__ +#define __ADDR_ALLOC_H__ + +#include +#include "ra.h" + +/* Defines whether sequential or random allocation is used */ +enum { + SEQUENTIAL_ALLOCATION, + RANDOM_ALLOCATION, + RANDOM_FORCE32BITS = 0x7FFFFFFFU +}; + +/** + * struct addr_region - Memory region structure + *@name: A pointer to a sring containing the name of the region. + * NULL for the default memory region. + *@base_addr: The base address of the memory region. + *@size: The size of the memory region. + *@guard_band: The size of any guard band to be used. + * Guard bands can be useful in separating block allocations + * and allows the caller to detect erroneous accesses + * into these areas. + *@nxt_region:Used internally by the ADDR API.A pointer used to point + * to the next memory region. + *@arena: Used internally by the ADDR API. A to a structure used to + * maintain and perform address allocation. + * + * This structure contains information about the memory region. + */ +struct addr_region { + unsigned char *name; + unsigned long long base_addr; + unsigned long long size; + unsigned int guard_band; + struct addr_region *nxt_region; + void *arena; +}; + +/* + * This structure contains the context for allocation. + *@regions: Pointer the first region in the list. + *@default_region: Pointer the default region. + *@no_regions: Number of regions currently available (including default) + */ +struct addr_context { + struct addr_region *regions; + struct addr_region *default_region; + unsigned int no_regions; +}; + +/* + * @Function ADDR_Initialise + * @Description + * This function is used to initialise the address alocation sub-system. + * NOTE: This function may be called multiple times. The initialisation only + * happens the first time it is called. + * @Return IMG_SUCCESS or an error code. + */ +int addr_initialise(void); + +/* + * @Function addr_deinitialise + * @Description + * This function is used to de-initialise the address alocation sub-system. + * @Return IMG_SUCCESS or an error code. + */ +int addr_deinitialise(void); + +/* + * @Function addr_define_mem_region + * @Description + * This function is used define a memory region. + * NOTE: The region structure MUST be defined in static memory as this + * is retained and used by the ADDR sub-system. + * NOTE: Invalid parameters are trapped by asserts. + * @Input region: A pointer to a region structure. + * @Return IMG_RESULT : IMG_SUCCESS or an error code. + */ +int addr_define_mem_region(struct addr_region * const region); + +/* + * @Function addr_malloc + * @Description + * This function is used allocate space within a memory region. + * NOTE: Allocation failures or invalid parameters are trapped by asserts. + * @Input name: Is a pointer the name of the memory region. + * NULL can be used to allocate space from the + * default memory region. + * @Input size: The size (in bytes) of the allocation. + * @Output base_adr : The address of the allocated space. + * @Return IMG_SUCCESS or an error code. + */ +int addr_malloc(const unsigned char *const name, + unsigned long long size, + unsigned long long *const base_adr); + +/* + * @Function addr_free + * @Description + * This function is used free a previously allocate space within + * a memory region. + * NOTE: Invalid parameters are trapped by asserts. + * @Input name: Is a pointer to the name of the memory region. + * NULL is used to free space from the default memory region. + *@Input addr: The address allocated. + *@Return IMG_SUCCESS or an error code. + */ +int addr_free(const unsigned char * const name, unsigned long long addr); + +/* + * @Function addr_cx_initialise + * @Description + * This function is used to initialise the address allocation sub-system with + * an external context structure. + * NOTE: This function should be call only once for the context. + * @Input context : Pointer to context structure. + * @Return IMG_SUCCESS or an error code. + */ +int addr_cx_initialise(struct addr_context * const context); + +/* + * @Function addr_cx_deinitialise + * @Description + * This function is used to de-initialise the address allocation + * sub-system with an external context structure. + * @Input context : Pointer to context structure. + * @Return IMG_SUCCESS or an error code. + */ +int addr_cx_deinitialise(struct addr_context * const context); + +/* + * @Function addr_cx_define_mem_region + * @Description + * This function is used define a memory region with an external + * context structure. + * NOTE: The region structure MUST be defined in static memory as this + * is retained and used by the ADDR sub-system. + * NOTE: Invalid parameters are trapped by asserts. + * @Input context : Pointer to context structure. + * @Input region : A pointer to a region structure. + * @Return IMG_SUCCESS or an error code. + */ +int addr_cx_define_mem_region(struct addr_context *const context, + struct addr_region *const region); + +/* + * @Function addr_cx_malloc + * @Description + * This function is used allocate space within a memory region with + * an external context structure. + * NOTE: Allocation failures or invalid parameters are trapped by asserts. + * @Input context : Pointer to context structure. + * @Input name : Is a pointer the name of the memory region. + * NULL can be used to allocate space from the + * default memory region. + * @Input size : The size (in bytes) of the allocation. + * @Output base_adr : The address of the allocated space. + * @Return IMG_SUCCESS or an error code. + */ +int addr_cx_malloc(struct addr_context * const context, + const unsigned char *const name, + unsigned long long size, + unsigned long long *const base_adr); + +/* + * @Function addr_cx_malloc_res + * @Description + * This function is used allocate space within a memory region with + * an external context structure. + * NOTE: Allocation failures are returned in IMG_RESULT, however invalid + * parameters are trapped by asserts. + * @Input context : Pointer to context structure. + * @Input name : Is a pointer the name of the memory region. + * NULL can be used to allocate space from the + * default memory region. + * @Input size : The size (in bytes) of the allocation. + * @Input base_adr : Pointer to the address of the allocated space. + * @Return IMG_SUCCESS or an error code. + */ +int addr_cx_malloc_res(struct addr_context *const context, + const unsigned char *const name, + unsigned long long size, + unsigned long long * const base_adr); + +/* + * @Function addr_cx_malloc1_res + * @Description + * This function is used allocate space within a memory region with + * an external context structure. + * NOTE: Allocation failures are returned in IMG_RESULT, however invalid + * parameters are trapped by asserts. + * @Input context : Pointer to context structure. + * @Input name : Is a pointer the name of the memory region. + * NULL can be used to allocate space from the + * default memory region. + * @Input size : The size (in bytes) of the allocation. + * @Input alignment : The required byte alignment (1, 2, 4, 8, 16 etc). + * @Input base_adr : Pointer to the address of the allocated space. + * @Return IMG_SUCCESS or an error code. + */ +int addr_cx_malloc_align_res(struct addr_context *const context, + const unsigned char *const name, + unsigned long long size, + unsigned long long alignment, + unsigned long long *const base_adr); + +/* + * @Function addr_cx_free + * @Description + * This function is used free a previously allocate space within a memory region + * with an external context structure. + * NOTE: Invalid parameters are trapped by asserts. + * @Input context : Pointer to context structure. + * @Input name : Is a pointer the name of the memory region. + * NULL is used to free space from the + * default memory region. + * @Input addr : The address allocated. + * @Return IMG_SUCCESS or an error code. + */ +int addr_cx_free(struct addr_context *const context, + const unsigned char *const name, + unsigned long long addr); + +#endif /* __ADDR_ALLOC_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/dq.c b/drivers/media/platform/imagination/vxe-vxd/common/dq.c --- a/drivers/media/platform/imagination/vxe-vxd/common/dq.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/dq.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Utility module for doubly linked queues. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#include +#include +#include +#include +#include + +#include "dq.h" +#include "img_errors.h" + +void dq_init(struct dq_linkage_t *queue) +{ + queue->fwd = (struct dq_linkage_t *)queue; + queue->back = (struct dq_linkage_t *)queue; +} + +void dq_addhead(struct dq_linkage_t *queue, void *item) +{ + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->fwd); + + if (!((struct dq_linkage_t *)queue)->back || + !((struct dq_linkage_t *)queue)->fwd) + return; + + ((struct dq_linkage_t *)item)->back = (struct dq_linkage_t *)queue; + ((struct dq_linkage_t *)item)->fwd = + ((struct dq_linkage_t *)queue)->fwd; + ((struct dq_linkage_t *)queue)->fwd->back = (struct dq_linkage_t *)item; + ((struct dq_linkage_t *)queue)->fwd = (struct dq_linkage_t *)item; +} + +void dq_addtail(struct dq_linkage_t *queue, void *item) +{ + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->fwd); + + if (!((struct dq_linkage_t *)queue)->back || + !((struct dq_linkage_t *)queue)->fwd) + return; + + ((struct dq_linkage_t *)item)->fwd = (struct dq_linkage_t *)queue; + ((struct dq_linkage_t *)item)->back = + ((struct dq_linkage_t *)queue)->back; + ((struct dq_linkage_t *)queue)->back->fwd = (struct dq_linkage_t *)item; + ((struct dq_linkage_t *)queue)->back = (struct dq_linkage_t *)item; +} + +int dq_empty(struct dq_linkage_t *queue) +{ + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->fwd); + + if (!((struct dq_linkage_t *)queue)->back || + !((struct dq_linkage_t *)queue)->fwd) + return 1; + + return ((queue)->fwd == (struct dq_linkage_t *)(queue)); +} + +void *dq_first(struct dq_linkage_t *queue) +{ + struct dq_linkage_t *temp = queue->fwd; + + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->fwd); + + if (!((struct dq_linkage_t *)queue)->back || + !((struct dq_linkage_t *)queue)->fwd) + return NULL; + + return temp == (struct dq_linkage_t *)queue ? NULL : temp; +} + +void *dq_last(struct dq_linkage_t *queue) +{ + struct dq_linkage_t *temp = queue->back; + + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->fwd); + + if (!((struct dq_linkage_t *)queue)->back || + !((struct dq_linkage_t *)queue)->fwd) + return NULL; + + return temp == (struct dq_linkage_t *)queue ? NULL : temp; +} + +void *dq_next(void *item) +{ + IMG_DBG_ASSERT(((struct dq_linkage_t *)item)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)item)->fwd); + + if (!((struct dq_linkage_t *)item)->back || + !((struct dq_linkage_t *)item)->fwd) + return NULL; + + return ((struct dq_linkage_t *)item)->fwd; +} + +void *dq_previous(void *item) +{ + IMG_DBG_ASSERT(((struct dq_linkage_t *)item)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)item)->fwd); + + if (!((struct dq_linkage_t *)item)->back || + !((struct dq_linkage_t *)item)->fwd) + return NULL; + + return ((struct dq_linkage_t *)item)->back; +} + +void dq_remove(void *item) +{ + IMG_DBG_ASSERT(((struct dq_linkage_t *)item)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)item)->fwd); + + if (!((struct dq_linkage_t *)item)->back || + !((struct dq_linkage_t *)item)->fwd) + return; + + ((struct dq_linkage_t *)item)->fwd->back = + ((struct dq_linkage_t *)item)->back; + ((struct dq_linkage_t *)item)->back->fwd = + ((struct dq_linkage_t *)item)->fwd; + + /* make item linkages safe for "orphan" removes */ + ((struct dq_linkage_t *)item)->fwd = item; + ((struct dq_linkage_t *)item)->back = item; +} + +void *dq_removehead(struct dq_linkage_t *queue) +{ + struct dq_linkage_t *temp; + + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->fwd); + + if (!((struct dq_linkage_t *)queue)->back || + !((struct dq_linkage_t *)queue)->fwd) + return NULL; + + if ((queue)->fwd == (struct dq_linkage_t *)(queue)) + return NULL; + + temp = ((struct dq_linkage_t *)queue)->fwd; + temp->fwd->back = temp->back; + temp->back->fwd = temp->fwd; + + /* make item linkages safe for "orphan" removes */ + temp->fwd = temp; + temp->back = temp; + return temp; +} + +void *dq_removetail(struct dq_linkage_t *queue) +{ + struct dq_linkage_t *temp; + + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)queue)->fwd); + + if (!((struct dq_linkage_t *)queue)->back || + !((struct dq_linkage_t *)queue)->fwd) + return NULL; + + if ((queue)->fwd == (struct dq_linkage_t *)(queue)) + return NULL; + + temp = ((struct dq_linkage_t *)queue)->back; + temp->fwd->back = temp->back; + temp->back->fwd = temp->fwd; + + /* make item linkages safe for "orphan" removes */ + temp->fwd = temp; + temp->back = temp; + + return temp; +} + +void dq_addbefore(void *successor, void *item) +{ + IMG_DBG_ASSERT(((struct dq_linkage_t *)successor)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)successor)->fwd); + + if (!((struct dq_linkage_t *)successor)->back || + !((struct dq_linkage_t *)successor)->fwd) + return; + + ((struct dq_linkage_t *)item)->fwd = (struct dq_linkage_t *)successor; + ((struct dq_linkage_t *)item)->back = + ((struct dq_linkage_t *)successor)->back; + ((struct dq_linkage_t *)item)->back->fwd = (struct dq_linkage_t *)item; + ((struct dq_linkage_t *)successor)->back = (struct dq_linkage_t *)item; +} + +void dq_addafter(void *predecessor, void *item) +{ + IMG_DBG_ASSERT(((struct dq_linkage_t *)predecessor)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)predecessor)->fwd); + + if (!((struct dq_linkage_t *)predecessor)->back || + !((struct dq_linkage_t *)predecessor)->fwd) + return; + + ((struct dq_linkage_t *)item)->fwd = + ((struct dq_linkage_t *)predecessor)->fwd; + ((struct dq_linkage_t *)item)->back = + (struct dq_linkage_t *)predecessor; + ((struct dq_linkage_t *)item)->fwd->back = (struct dq_linkage_t *)item; + ((struct dq_linkage_t *)predecessor)->fwd = (struct dq_linkage_t *)item; +} + +void dq_move(struct dq_linkage_t *from, struct dq_linkage_t *to) +{ + IMG_DBG_ASSERT(((struct dq_linkage_t *)from)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)from)->fwd); + IMG_DBG_ASSERT(((struct dq_linkage_t *)to)->back); + IMG_DBG_ASSERT(((struct dq_linkage_t *)to)->fwd); + + if (!((struct dq_linkage_t *)from)->back || + !((struct dq_linkage_t *)from)->fwd || + !((struct dq_linkage_t *)to)->back || + !((struct dq_linkage_t *)to)->fwd) + return; + + if ((from)->fwd == (struct dq_linkage_t *)(from)) { + dq_init(to); + } else { + *to = *from; + to->fwd->back = (struct dq_linkage_t *)to; + to->back->fwd = (struct dq_linkage_t *)to; + dq_init(from); + } +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/dq.h b/drivers/media/platform/imagination/vxe-vxd/common/dq.h --- a/drivers/media/platform/imagination/vxe-vxd/common/dq.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/dq.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Utility module for doubly linked queues. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + */ +#ifndef DQ_H +#define DQ_H + +/* dq structure */ +struct dq_linkage_t { + struct dq_linkage_t *fwd; + struct dq_linkage_t *back; +}; + +/* Function Prototypes */ +void dq_addafter(void *predecessor, void *item); +void dq_addbefore(void *successor, void *item); +void dq_addhead(struct dq_linkage_t *queue, void *item); +void dq_addtail(struct dq_linkage_t *queue, void *item); +int dq_empty(struct dq_linkage_t *queue); +void *dq_first(struct dq_linkage_t *queue); +void *dq_last(struct dq_linkage_t *queue); +void dq_init(struct dq_linkage_t *queue); +void dq_move(struct dq_linkage_t *from, struct dq_linkage_t *to); +void *dq_next(void *item); +void *dq_previous(void *item); +void dq_remove(void *item); +void *dq_removehead(struct dq_linkage_t *queue); +void *dq_removetail(struct dq_linkage_t *queue); + +#endif /* #define DQ_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/hash.c b/drivers/media/platform/imagination/vxe-vxd/common/hash.c --- a/drivers/media/platform/imagination/vxe-vxd/common/hash.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/hash.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Self scaling hash tables. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Sidraya Jayagond + */ + +#include +#include +#include +#include + +#include "hash.h" +#include "img_errors.h" +#include "pool.h" + +/* pool of struct hash objects */ +static struct pool *global_hashpool; + +/* pool of struct bucket objects */ +static struct pool *global_bucketpool; + +static int global_initialized; + +/* Each entry in a hash table is placed into a bucket */ +struct bucket { + struct bucket *next; + unsigned long long key; + unsigned long long value; +}; + +struct hash { + struct bucket **table; + unsigned int size; + unsigned int count; + unsigned int minimum_size; +}; + +/** + * hash_func - Hash function intended for hashing addresses. + * @vale : The key to hash. + * @size : The size of the hash table + */ +static unsigned int hash_func(unsigned long long vale, + unsigned int size) +{ + unsigned int hash = (unsigned int)(vale); + + hash += (hash << 12); + hash ^= (hash >> 22); + hash += (hash << 4); + hash ^= (hash >> 9); + hash += (hash << 10); + hash ^= (hash >> 2); + hash += (hash << 7); + hash ^= (hash >> 12); + hash &= (size - 1); + return hash; +} + +/* + * @Function hash_chain_insert + * @Description + * Hash function intended for hashing addresses. + * @Input bucket : The bucket + * @Input table : The hash table + * @Input size : The size of the hash table + * @Return IMG_SUCCESS or an error code. + */ +static int hash_chain_insert(struct bucket *bucket, + struct bucket **table, + unsigned int size) +{ + unsigned int idx; + unsigned int result = IMG_ERROR_FATAL; + + if (!bucket || !table || !size) { + result = IMG_ERROR_INVALID_PARAMETERS; + return result; + } + + idx = hash_func(bucket->key, size); + + if (idx < size) { + result = IMG_SUCCESS; + bucket->next = table[idx]; + table[idx] = bucket; + } + + return result; +} + +/* + * @Function hash_rehash + * @Description + * Iterate over every entry in an old hash table and rehash into the new table. + * @Input old_table : The old hash table + * @Input old_size : The size of the old hash table + * @Input new_table : The new hash table + * @Input new_sz : The size of the new hash table + * @Return IMG_SUCCESS or an error code. + */ +static int hash_rehash(struct bucket **old_table, + unsigned int old_size, + struct bucket **new_table, + unsigned int new_sz) +{ + unsigned int idx; + unsigned int result = IMG_ERROR_FATAL; + + if (!old_table || !new_table) { + result = IMG_ERROR_INVALID_PARAMETERS; + return result; + } + + for (idx = 0; idx < old_size; idx++) { + struct bucket *bucket; + struct bucket *nex_bucket; + + bucket = old_table[idx]; + while (bucket) { + nex_bucket = bucket->next; + result = hash_chain_insert(bucket, new_table, new_sz); + if (result != IMG_SUCCESS) { + result = IMG_ERROR_UNEXPECTED_STATE; + return result; + } + bucket = nex_bucket; + } + } + result = IMG_SUCCESS; + + return result; +} + +/* + * @Function hash_resize + * @Description + * Attempt to resize a hash table, failure to allocate a new larger hash table + * is not considered a hard failure. We simply continue and allow the table to + * fill up, the effect is to allow hash chains to become longer. + * @Input hash_arg : Pointer to the hash table + * @Input new_sz : The size of the new hash table + * @Return IMG_SUCCESS or an error code. + */ +static int hash_resize(struct hash *hash_arg, + unsigned int new_sz) +{ + unsigned int malloc_sz = 0; + unsigned int result = IMG_ERROR_FATAL; + unsigned int idx; + + if (!hash_arg) { + result = IMG_ERROR_INVALID_PARAMETERS; + return result; + } + + if (new_sz != hash_arg->size) { + struct bucket **new_bkt_table; + + malloc_sz = (sizeof(struct bucket *) * new_sz); + new_bkt_table = kmalloc(malloc_sz, GFP_KERNEL); + + if (!new_bkt_table) { + result = IMG_ERROR_MALLOC_FAILED; + return result; + } + + for (idx = 0; idx < new_sz; idx++) + new_bkt_table[idx] = NULL; + + result = hash_rehash(hash_arg->table, + hash_arg->size, + new_bkt_table, + new_sz); + + if (result != IMG_SUCCESS) { + kfree(new_bkt_table); + new_bkt_table = NULL; + result = IMG_ERROR_UNEXPECTED_STATE; + return result; + } + + kfree(hash_arg->table); + hash_arg->table = new_bkt_table; + hash_arg->size = new_sz; + } + result = IMG_SUCCESS; + + return result; +} + +static unsigned int private_max(unsigned int a, unsigned int b) +{ + unsigned int ret = (a > b) ? a : b; + return ret; +} + +/* + * @Function vid_hash_initialise + * @Description + * To initialise the hash module. + * @Input None + * @Return IMG_SUCCESS or an error code. + */ +int vid_hash_initialise(void) +{ + unsigned int result = IMG_ERROR_ALREADY_COMPLETE; + + if (!global_initialized) { + if (global_hashpool || global_bucketpool) { + result = IMG_ERROR_UNEXPECTED_STATE; + return result; + } + + result = pool_create("img-hash", + sizeof(struct hash), + &global_hashpool); + + if (result != IMG_SUCCESS) { + result = IMG_ERROR_UNEXPECTED_STATE; + return result; + } + + result = pool_create("img-sBucket", + sizeof(struct bucket), + &global_bucketpool); + if (result != IMG_SUCCESS) { + if (global_bucketpool) { + result = pool_delete(global_bucketpool); + global_bucketpool = NULL; + } + result = IMG_ERROR_UNEXPECTED_STATE; + return result; + } + global_initialized = true; + result = IMG_SUCCESS; + } + return result; +} + +/* + * @Function vid_hash_finalise + * @Description + * To finalise the hash module. All allocated hash tables should + * be deleted before calling this function. + * @Input None + * @Return IMG_SUCCESS or an error code. + */ +int vid_hash_finalise(void) +{ + unsigned int result = IMG_ERROR_FATAL; + + if (global_initialized) { + if (global_hashpool) { + result = pool_delete(global_hashpool); + if (result != IMG_SUCCESS) + return result; + + global_hashpool = NULL; + } + + if (global_bucketpool) { + result = pool_delete(global_bucketpool); + if (result != IMG_SUCCESS) + return result; + + global_bucketpool = NULL; + } + global_initialized = false; + result = IMG_SUCCESS; + } + + return result; +} + +/* + * @Function vid_hash_create + * @Description + * Create a self scaling hash table. + * @Input initial_size : Initial and minimum size of the hash table. + * @Output hash_arg : Will countin the hash table handle or NULL. + * @Return IMG_SUCCESS or an error code. + */ +int vid_hash_create(unsigned int initial_size, + struct hash ** const hash_arg) +{ + unsigned int idx; + unsigned int tbl_sz = 0; + unsigned int result = IMG_ERROR_FATAL; + struct hash *local_hash = NULL; + + if (!hash_arg) { + result = IMG_ERROR_INVALID_PARAMETERS; + return result; + } + + if (global_initialized) { + pool_alloc(global_hashpool, ((void **)&local_hash)); + if (!local_hash) { + result = IMG_ERROR_UNEXPECTED_STATE; + *hash_arg = NULL; + return result; + } + + local_hash->count = 0; + local_hash->size = initial_size; + local_hash->minimum_size = initial_size; + + tbl_sz = (sizeof(struct bucket *) * local_hash->size); + local_hash->table = kmalloc(tbl_sz, GFP_KERNEL); + if (!local_hash->table) { + result = pool_free(global_hashpool, local_hash); + if (result != IMG_SUCCESS) + result = IMG_ERROR_UNEXPECTED_STATE; + result |= IMG_ERROR_MALLOC_FAILED; + *hash_arg = NULL; + return result; + } + + for (idx = 0; idx < local_hash->size; idx++) + local_hash->table[idx] = NULL; + + *hash_arg = local_hash; + result = IMG_SUCCESS; + } + return result; +} + +/* + * @Function vid_hash_delete + * @Description + * To delete a hash table, all entries in the table should be + * removed before calling this function. + * @Input hash_arg : Hash table pointer + * @Return IMG_SUCCESS or an error code. + */ +int vid_hash_delete(struct hash * const hash_arg) +{ + unsigned int result = IMG_ERROR_FATAL; + + if (!hash_arg) { + result = IMG_ERROR_INVALID_PARAMETERS; + return result; + } + + if (global_initialized) { + if (hash_arg->count != 0) { + result = IMG_ERROR_UNEXPECTED_STATE; + return result; + } + + kfree(hash_arg->table); + hash_arg->table = NULL; + + result = pool_free(global_hashpool, hash_arg); + if (result != IMG_SUCCESS) { + result = IMG_ERROR_UNEXPECTED_STATE; + return result; + } + } + return result; +} + +/* + * @Function vid_hash_insert + * @Description + * To insert a key value pair into a hash table. + * @Input hash_arg : Hash table pointer + * @Input key : Key value + * @Input value : The value associated with the key. + * @Return IMG_SUCCESS or an error code. + */ +int vid_hash_insert(struct hash * const hash_arg, + unsigned long long key, + unsigned long long value) +{ + struct bucket *ps_bucket = NULL; + unsigned int result = IMG_ERROR_FATAL; + + if (!hash_arg) { + result = IMG_ERROR_INVALID_PARAMETERS; + return result; + } + + if (global_initialized) { + result = pool_alloc(global_bucketpool, ((void **)&ps_bucket)); + if (result != IMG_SUCCESS || !ps_bucket) { + result = IMG_ERROR_UNEXPECTED_STATE; + return result; + } + ps_bucket->next = NULL; + ps_bucket->key = key; + ps_bucket->value = value; + + result = hash_chain_insert(ps_bucket, + hash_arg->table, + hash_arg->size); + + if (result != IMG_SUCCESS) { + pool_free(global_bucketpool, ((void **)&ps_bucket)); + result = IMG_ERROR_UNEXPECTED_STATE; + return result; + } + + hash_arg->count++; + + /* check if we need to think about re-balancing */ + if ((hash_arg->count << 1) > hash_arg->size) { + result = hash_resize(hash_arg, (hash_arg->size << 1)); + if (result != IMG_SUCCESS) { + result = IMG_ERROR_UNEXPECTED_STATE; + return result; + } + } + result = IMG_SUCCESS; + } + return result; +} + +/* + * @Function vid_hash_remove + * @Description + * To remove a key value pair from a hash table + * @Input hash_arg : Hash table pointer + * @Input key : Key value + * @Input ret_result : 0 if the key is missing or the value + * associated with the key. + * @Return IMG_SUCCESS or an error code. + */ +int vid_hash_remove(struct hash * const hash_arg, + unsigned long long key, + unsigned long * const ret_result) +{ + unsigned int idx; + unsigned int tmp1 = 0; + unsigned int tmp2 = 0; + unsigned int result = IMG_ERROR_FATAL; + struct bucket **bucket = NULL; + + if (!hash_arg) { + result = IMG_ERROR_INVALID_PARAMETERS; + return result; + } + + idx = hash_func(key, hash_arg->size); + + for (bucket = &hash_arg->table[idx]; (*bucket) != NULL; + bucket = &((*bucket)->next)) { + if ((*bucket)->key == key) { + struct bucket *ps_bucket = (*bucket); + + unsigned long long value = ps_bucket->value; + + *bucket = ps_bucket->next; + result = pool_free(global_bucketpool, ps_bucket); + + hash_arg->count--; + + /* check if we need to think about re-balencing */ + if (hash_arg->size > (hash_arg->count << 2) && + hash_arg->size > hash_arg->minimum_size) { + tmp1 = (hash_arg->size >> 1); + tmp2 = hash_arg->minimum_size; + result = hash_resize(hash_arg, + private_max(tmp1, tmp2)); + } + *ret_result = value; + result = IMG_SUCCESS; + break; + } + } + return result; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/hash.h b/drivers/media/platform/imagination/vxe-vxd/common/hash.h --- a/drivers/media/platform/imagination/vxe-vxd/common/hash.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/hash.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Self scaling hash tables. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Sidraya Jayagond + */ +#ifndef _HASH_H_ +#define _HASH_H_ + +#include +struct hash; + +/** + * vid_hash_initialise - VID_HASH_Initialise + * @Input None + * + * To initialise the hash module. + */ +int vid_hash_initialise(void); + +/* + * @Function VID_HASH_Finalise + * @Description + * To finalise the hash module. All allocated hash tables should + * be deleted before calling this function. + * @Input None + * @Return IMG_SUCCESS or an error code. + */ +int vid_hash_finalise(void); + +/* + * @Function VID_HASH_Create + * @Description + * Create a self scaling hash table. + * @Input initial_size : Initial and minimum size of the hash table. + * @Output hash : Hash table handle or NULL. + * @Return IMG_SUCCESS or an error code. + */ +int vid_hash_create(unsigned int initial_size, + struct hash ** const hash_hndl); + +/* + * @Function VID_HASH_Delete + * @Description + * To delete a hash table, all entries in the table should be + * removed before calling this function. + * @Input hash : Hash table pointer + * @Return IMG_SUCCESS or an error code. + */ +int vid_hash_delete(struct hash * const ps_hash); + +/* + * @Function VID_HASH_Insert + * @Description + * To insert a key value pair into a hash table. + * @Input ps_hash : Hash table pointer + * @Input key : Key value + * @Input value : The value associated with the key. + * @Return IMG_SUCCESS or an error code. + */ +int vid_hash_insert(struct hash * const ps_hash, + unsigned long long key, + unsigned long long value); + +/* + * @Function VID_HASH_Remove + * @Description + * To remove a key value pair from a hash table + * @Input ps_hash : Hash table pointer + * @Input key : Key value + * @Input result : 0 if the key is missing or the value + * associated with the key. + * @Return IMG_SUCCESS or an error code. + */ +int vid_hash_remove(struct hash * const ps_hash, + unsigned long long key, + unsigned long * const result); + +#endif /* _HASH_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/idgen_api.c b/drivers/media/platform/imagination/vxe-vxd/common/idgen_api.c --- a/drivers/media/platform/imagination/vxe-vxd/common/idgen_api.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/idgen_api.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,449 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ID generation manager API. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#include +#include +#include +#include + +#include "idgen_api.h" +#include "lst.h" + +/* + * This structure contains ID context. + */ +struct idgen_context { + /* List of handle block structures */ + struct lst_t hdlblklst; + /* Max ID - set by IDGEN_CreateContext(). */ + unsigned int maxid; + /* + * The number of handle per block. In case of + * incrementing ids, size of the Hash table. + */ + unsigned int blksize; + /* Next free slot. */ + unsigned int freeslot; + /* Max slot+1 for which we have allocated blocks. */ + unsigned int maxslotplus1; + /* Incrementing ID's */ + /* API needed to return incrementing IDs */ + int incids; + /* Latest ID given back */ + unsigned int latestincnumb; + /* Array of list to hold IDGEN_sHdlId */ + struct lst_t *incidlist; +}; + +/* + * This structure represents internal representation of an Incrementing ID. + */ +struct idgen_id { + void **link; /* to be part of single linked list */ + /* Incrementing ID returned */ + unsigned int incid; + void *hid; +}; + +/* + * Structure contains the ID context. + */ +struct idgen_hdblk { + void **link; /* to be part of single linked list */ + /* Array of handles in this block. */ + void *ahhandles[1]; +}; + +/* + * A hashing function could go here. Currently just makes a circular list of + * max number of concurrent Ids (idgen_context->blksize) in the system. + */ +static unsigned int idgen_func(struct idgen_context *idcontext, unsigned int id) +{ + return ((id - 1) % idcontext->blksize); +} + +int idgen_createcontext(unsigned int maxid, unsigned int blksize, + int incid, void **idgenhandle) +{ + struct idgen_context *idcontext; + + /* Create context structure */ + idcontext = kzalloc(sizeof(*idcontext), GFP_KERNEL); + if (!idcontext) + return IMG_ERROR_OUT_OF_MEMORY; + + /* InitIalise the context */ + lst_init(&idcontext->hdlblklst); + idcontext->maxid = maxid; + idcontext->blksize = blksize; + + /* If we need incrementing Ids */ + idcontext->incids = incid; + idcontext->latestincnumb = 0; + idcontext->incidlist = NULL; + if (idcontext->incids) { + unsigned int i = 0; + /* Initialise the hash table of lists of length ui32BlkSize */ + idcontext->incidlist = kzalloc((sizeof(*idcontext->incidlist) * + idcontext->blksize), GFP_KERNEL); + if (!idcontext->incidlist) { + kfree(idcontext); + return IMG_ERROR_OUT_OF_MEMORY; + } + + /* Initialise all the lists in the hash table */ + for (i = 0; i < idcontext->blksize; i++) + lst_init(&idcontext->incidlist[i]); + } + + /* Return context structure as handle */ + *idgenhandle = idcontext; + + return IMG_SUCCESS; +} + +int idgen_destroycontext(void *idgenhandle) +{ + struct idgen_context *idcontext = (struct idgen_context *)idgenhandle; + struct idgen_hdblk *hdblk; + + if (!idcontext) + return IMG_ERROR_INVALID_PARAMETERS; + + /* If incrementing Ids, free the List of Incrementing Ids */ + if (idcontext->incids) { + struct idgen_id *id; + unsigned int i = 0; + + for (i = 0; i < idcontext->blksize; i++) { + id = lst_removehead(&idcontext->incidlist[i]); + while (id) { + kfree(id); + id = lst_removehead(&idcontext->incidlist[i]); + } + } + kfree(idcontext->incidlist); + } + + /* Remove and free all handle blocks */ + hdblk = (struct idgen_hdblk *)lst_removehead(&idcontext->hdlblklst); + while (hdblk) { + kfree(hdblk); + hdblk = (struct idgen_hdblk *) + lst_removehead(&idcontext->hdlblklst); + } + + /* Free context structure */ + kfree(idcontext); + + return IMG_SUCCESS; +} + +static int idgen_findnextfreeslot(void *idgenhandle, unsigned int prevfreeslot) +{ + struct idgen_context *idcontext = (struct idgen_context *)idgenhandle; + struct idgen_hdblk *hdblk; + unsigned int freslotblk; + unsigned int freeslot; + + if (!idcontext) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Find the block containing the current free slot */ + freeslot = prevfreeslot; + freslotblk = prevfreeslot; + hdblk = (struct idgen_hdblk *)lst_first(&idcontext->hdlblklst); + if (!hdblk) + return IMG_ERROR_FATAL; + + while (freslotblk >= idcontext->blksize) { + freslotblk -= idcontext->blksize; + hdblk = (struct idgen_hdblk *)lst_next(hdblk); + } + + /* Locate the next free slot */ + while (hdblk) { + while (freslotblk < idcontext->blksize) { + if (!hdblk->ahhandles[freslotblk]) { + /* Found */ + idcontext->freeslot = freeslot; + return IMG_SUCCESS; + } + freeslot++; + freslotblk++; + } + freslotblk = 0; + hdblk = (struct idgen_hdblk *)lst_next(hdblk); + } + + /* Beyond the last block */ + idcontext->freeslot = freeslot; + return IMG_SUCCESS; +} + +/* + * This function returns ID structure ( + */ +static struct idgen_id *idgen_getid(struct lst_t *idlist, unsigned int id) +{ + struct idgen_id *idstruct; + + idstruct = lst_first(idlist); + while (idstruct) { + if (idstruct->incid == id) + break; + + idstruct = lst_next(idstruct); + } + return idstruct; +} + +/* + * This function does IDGEN allocation. + */ +int idgen_allocid(void *idgenhandle, void *handle, unsigned int *id) +{ + struct idgen_context *idcontext = (struct idgen_context *)idgenhandle; + struct idgen_hdblk *hdblk; + unsigned int size = 0; + unsigned int freeslot = 0; + unsigned int result = 0; + + if (!idcontext || !handle) + return IMG_ERROR_INVALID_PARAMETERS; + + if (!idcontext->incids) { + /* If the free slot is >= to the max id */ + if (idcontext->freeslot >= idcontext->maxid) { + result = IMG_ERROR_INVALID_ID; + goto error; + } + + /* If all of the allocated Ids have been used */ + if (idcontext->freeslot >= idcontext->maxslotplus1) { + /* Allocate a stream context */ + size = sizeof(*hdblk) + (sizeof(void *) * + (idcontext->blksize - 1)); + hdblk = kzalloc(size, GFP_KERNEL); + if (!hdblk) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + + lst_add(&idcontext->hdlblklst, hdblk); + idcontext->maxslotplus1 += idcontext->blksize; + } + + /* Find the block containing the next free slot */ + freeslot = idcontext->freeslot; + hdblk = (struct idgen_hdblk *)lst_first(&idcontext->hdlblklst); + if (!hdblk) { + result = IMG_ERROR_FATAL; + goto error; + } + while (freeslot >= idcontext->blksize) { + freeslot -= idcontext->blksize; + hdblk = (struct idgen_hdblk *)lst_next(hdblk); + if (!hdblk) { + result = IMG_ERROR_FATAL; + goto error; + } + } + + /* Put handle in the next free slot */ + hdblk->ahhandles[freeslot] = handle; + + *id = idcontext->freeslot + 1; + + /* Find a new free slot */ + result = idgen_findnextfreeslot(idcontext, idcontext->freeslot); + if (result != 0) + goto error; + /* + * If incrementing IDs, just add the ID node to the correct hash table + * list. + */ + } else { + struct idgen_id *psid; + unsigned int currentincnum, funcid; + /* + * If incrementing IDs, increment the id for returning back,and + * save the ID node in the list of ids, indexed by hash function + * (idgen_func). We might want to use a better hashing function + */ + currentincnum = (idcontext->latestincnumb + 1) % + idcontext->maxid; + + /* Increment the id. Wraps if greater then Max Id */ + if (currentincnum == 0) + currentincnum++; + + idcontext->latestincnumb = currentincnum; + + result = IMG_ERROR_INVALID_ID; + do { + /* Add to list in the correct hash table entry */ + funcid = idgen_func(idcontext, idcontext->latestincnumb); + if (idgen_getid(&idcontext->incidlist[funcid], + idcontext->latestincnumb) == NULL) { + psid = kmalloc(sizeof(*psid), GFP_KERNEL); + if (!psid) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + + psid->incid = idcontext->latestincnumb; + psid->hid = handle; + + funcid = idgen_func(idcontext, + idcontext->latestincnumb); + lst_add(&idcontext->incidlist[funcid], + psid); + + result = IMG_SUCCESS; + } else { + idcontext->latestincnumb = + (idcontext->latestincnumb + 1) % + idcontext->maxid; + if (idcontext->latestincnumb == 0) { + /* Do not want to have zero as pic id */ + idcontext->latestincnumb++; + } + /* + * We have reached a point where we have wrapped + * allowed Ids (MaxId) and we want to overwrite + * ID still not released + */ + if (idcontext->latestincnumb == currentincnum) + goto error; + } + } while (result != IMG_SUCCESS); + + *id = psid->incid; + } + return IMG_SUCCESS; +error: + return result; +} + +int idgen_freeid(void *idgenhandle, unsigned int id) +{ + struct idgen_context *idcontext = (struct idgen_context *)idgenhandle; + struct idgen_hdblk *hdblk; + unsigned int origslot; + unsigned int slot; + + if (idcontext->incids) { + /* + * Find the slot in the correct hash table entry, and + * remove the ID. + */ + struct idgen_id *psid; + + psid = idgen_getid(&idcontext->incidlist + [idgen_func(idcontext, id)], id); + if (psid) { + lst_remove(&idcontext->incidlist + [idgen_func(idcontext, id)], psid); + kfree(psid); + } else { + return IMG_ERROR_INVALID_ID; + } + } else { + /* If not incrementing id */ + slot = id - 1; + origslot = slot; + + if (slot >= idcontext->maxslotplus1) + return IMG_ERROR_INVALID_ID; + + /* Find the block containing the id */ + hdblk = (struct idgen_hdblk *)lst_first(&idcontext->hdlblklst); + if (!hdblk) + return IMG_ERROR_FATAL; + + while (slot >= idcontext->blksize) { + slot -= idcontext->blksize; + hdblk = (struct idgen_hdblk *)lst_next(hdblk); + if (!hdblk) + return IMG_ERROR_FATAL; + } + + /* Slot should be occupied */ + if (!hdblk->ahhandles[slot]) + return IMG_ERROR_INVALID_ID; + + /* Free slot */ + hdblk->ahhandles[slot] = NULL; + + /* If this slot is before the previous free slot */ + if ((origslot) < idcontext->freeslot) + idcontext->freeslot = origslot; + } + return IMG_SUCCESS; +} + +int idgen_gethandle(void *idgenhandle, unsigned int id, void **handle) +{ + struct idgen_context *idcontext = (struct idgen_context *)idgenhandle; + struct idgen_hdblk *hdblk; + unsigned int slot; + + if (!idcontext) + return IMG_ERROR_INVALID_PARAMETERS; + + if (idcontext->incids) { + /* + * Find the slot in the correct hash table entry, and return + * the handles. + */ + struct idgen_id *psid; + + psid = idgen_getid(&idcontext->incidlist + [idgen_func(idcontext, id)], id); + if (psid) + *handle = psid->hid; + + else + return IMG_ERROR_INVALID_ID; + } else { + /* If not incrementing IDs */ + slot = id - 1; + if (slot >= idcontext->maxslotplus1) + return IMG_ERROR_INVALID_ID; + + /* Find the block containing the id */ + hdblk = (struct idgen_hdblk *)lst_first(&idcontext->hdlblklst); + if (!hdblk) + return IMG_ERROR_INVALID_PARAMETERS; + + while (slot >= idcontext->blksize) { + slot -= idcontext->blksize; + hdblk = (struct idgen_hdblk *)lst_next(hdblk); + if (!hdblk) + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Slot should be occupied */ + if (!hdblk->ahhandles[slot]) + return IMG_ERROR_INVALID_ID; + + /* Return the handle */ + *handle = hdblk->ahhandles[slot]; + } + + return IMG_SUCCESS; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/idgen_api.h b/drivers/media/platform/imagination/vxe-vxd/common/idgen_api.h --- a/drivers/media/platform/imagination/vxe-vxd/common/idgen_api.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/idgen_api.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ID generation manager API. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ +#ifndef __IDGENAPI_H__ +#define __IDGENAPI_H__ + +#include + +#include "img_errors.h" + +/* + * This function is used to create Id generation context. + * NOTE: Should only be called once to setup the context structure. + * NOTE: The client is responsible for providing thread/process safe locks on + * the context structure to maintain coherence. + */ +int idgen_createcontext(unsigned int maxid, unsigned int blksize, + int incid, void **idgenhandle); + +/* + * This function is used to destroy an Id generation context. This function + * discards any handle blocks associated with the context. + * NOTE: The client is responsible for providing thread/process safe locks on + * the context structure to maintain coherence. + */ +int idgen_destroycontext(void *idgenhandle); + +/* + * This function is used to associate a handle with an Id. + * NOTE: The client is responsible for providing thread/process safe locks on + * the context structure to maintain coherency. + */ +int idgen_allocid(void *idgenhandle, void *handle, unsigned int *id); + +/* + * This function is used to free an Id. + * NOTE: The client is responsible for providing thread/process safe locks on + * the context structure to maintain coherency. + */ +int idgen_freeid(void *idgenhandle, unsigned int id); + +/* + * This function is used to get the handle associated with an Id. + * NOTE: The client is responsible for providing thread/process safe locks on + * the context structure to maintain coherency. + */ +int idgen_gethandle(void *idgenhandle, unsigned int id, void **handle); +#endif /* __IDGENAPI_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/img_errors.h b/drivers/media/platform/imagination/vxe-vxd/common/img_errors.h --- a/drivers/media/platform/imagination/vxe-vxd/common/img_errors.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/img_errors.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Error codes. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + */ +#ifndef __IMG_ERRORS__ +#define __IMG_ERRORS__ + +#include +#include +#include +#include + +#define IMG_DBG_ASSERT(expected) ({WARN_ON(!(expected)); 0; }) + +/* @brief Success */ +#define IMG_SUCCESS (0) +/* @brief Timeout */ +#define IMG_ERROR_TIMEOUT (1) +/* @brief memory allocation failed */ +#define IMG_ERROR_MALLOC_FAILED (2) +/* @brief Unspecified fatal error */ +#define IMG_ERROR_FATAL (3) +/* @brief Memory allocation failed */ +#define IMG_ERROR_OUT_OF_MEMORY (4) +/* @brief Device is not found */ +#define IMG_ERROR_DEVICE_NOT_FOUND (5) +/* @brief Device is not available/in use */ +#define IMG_ERROR_DEVICE_UNAVAILABLE (6) +/* @brief Generic/unspecified failure */ +#define IMG_ERROR_GENERIC_FAILURE (7) +/* @brief Operation was interrupted - retry */ +#define IMG_ERROR_INTERRUPTED (8) +/* @brief Invalid id */ +#define IMG_ERROR_INVALID_ID (9) +/* @brief A signature value was found to be incorrect */ +#define IMG_ERROR_SIGNATURE_INCORRECT (10) +/* @brief The provided parameters were inconsistent/incorrect */ +#define IMG_ERROR_INVALID_PARAMETERS (11) +/* @brief A list/pool has run dry */ +#define IMG_ERROR_STORAGE_TYPE_EMPTY (12) +/* @brief A list is full */ +#define IMG_ERROR_STORAGE_TYPE_FULL (13) +/* @brief Something has already occurred which the code thinks has not */ +#define IMG_ERROR_ALREADY_COMPLETE (14) +/* @brief A state machine is in an unexpected/illegal state */ +#define IMG_ERROR_UNEXPECTED_STATE (15) +/* @brief A required resource could not be created/locked */ +#define IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE (16) +/* + * @brief An attempt to access a structure/resource was + * made before it was initialised + */ +#define IMG_ERROR_NOT_INITIALISED (17) +/* + * @brief An attempt to initialise a structure/resource + * was made when it has already been initialised + */ +#define IMG_ERROR_ALREADY_INITIALISED (18) +/* @brief A provided value exceeded stated bounds */ +#define IMG_ERROR_VALUE_OUT_OF_RANGE (19) +/* @brief The operation has been cancelled */ +#define IMG_ERROR_CANCELLED (20) +/* @brief A specified minimum has not been met */ +#define IMG_ERROR_MINIMUM_LIMIT_NOT_MET (21) +/* @brief The requested feature or mode is not supported */ +#define IMG_ERROR_NOT_SUPPORTED (22) +/* @brief A device or process was idle */ +#define IMG_ERROR_IDLE (23) +/* @brief A device or process was busy */ +#define IMG_ERROR_BUSY (24) +/* @brief The device or resource has been disabled */ +#define IMG_ERROR_DISABLED (25) +/* @brief The requested operation is not permitted at this time */ +#define IMG_ERROR_OPERATION_PROHIBITED (26) +/* @brief The entry read from the MMU page directory is invalid */ +#define IMG_ERROR_MMU_PAGE_DIRECTORY_FAULT (27) +/* @brief The entry read from an MMU page table is invalid */ +#define IMG_ERROR_MMU_PAGE_TABLE_FAULT (28) +/* @brief The entry read from an MMU page catalogue is invalid */ +#define IMG_ERROR_MMU_PAGE_CATALOGUE_FAULT (29) +/* @brief Memory can not be freed as it is still been used */ +#define IMG_ERROR_MEMORY_IN_USE (30) +/* @brief A mismatch has unexpectedly occurred in data */ +#define IMG_ERROR_TEST_MISMATCH (31) + +#define IMG_ERROR_INVALID_CONTEXT (32) + +#define IMG_ERROR_RETRY (33) +#define IMG_ERROR_UNDEFINED (34) +#define IMG_ERROR_INVALID_SIZE (35) +#define IMG_ERROR_SURFACE_LOCKED (36) + +/* Mutex subclasses */ +#define SUBCLASS_BASE 0 +#define SUBCLASS_VXD_V4L2 1 +#define SUBCLASS_VXE_V4L2 1 +#define SUBCLASS_BSPP 1 +#define SUBCLASS_ADDR_ALLOC 7 +#define SUBCLASS_IMGMEM 6 +#define SUBCLASS_RMAN 1 +#define SUBCLASS_TALMMU 5 +#define SUBCLASS_VXD_CORE 2 +#define SUBCLASS_POOL 3 +#define SUBCLASS_POOL_RES 5 +#define SUBCLASS_TOPAZ_API 2 +#define SUBCLASS_TOPAZDD_TX 4 +#define SUBCLASS_TOPAZDD 3 + +#endif /* __IMG_ERRORS__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/img_mem.h b/drivers/media/platform/imagination/vxe-vxd/common/img_mem.h --- a/drivers/media/platform/imagination/vxe-vxd/common/img_mem.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/img_mem.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Typedefs for memory pool and attributes + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ +#ifndef __IMG_MEM__ +#define __IMG_MEM__ + +/* + * This type defines the memory attributes. + * @0x00000001: Memory to be allocated as cached + * @0x00000002: Memory to be allocated as uncached + * @0x00000004: Memory to be allocated as write-combined + * (or equivalent buffered/burst writes mechanism) + * @0x00001000: Memory can be read only by the core + * @0x00002000: Memory can be written only by the core + * @0x00010000: Memory should be readable by the cpu + * @0x00020000: Memory should be writable by the cpu + */ +enum sys_emem_attrib { + SYS_MEMATTRIB_CACHED = 0x00000001, + SYS_MEMATTRIB_UNCACHED = 0x00000002, + SYS_MEMATTRIB_WRITECOMBINE = 0x00000004, + SYS_MEMATTRIB_SECURE = 0x00000010, + SYS_MEMATTRIB_INPUT = 0x00000100, + SYS_MEMATTRIB_OUTPUT = 0x00000200, + SYS_MEMATTRIB_INTERNAL = 0x00000400, + SYS_MEMATTRIB_CORE_READ_ONLY = 0x00001000, + SYS_MEMATTRIB_CORE_WRITE_ONLY = 0x00002000, + SYS_MEMATTRIB_CPU_READ = 0x00010000, + SYS_MEMATTRIB_CPU_WRITE = 0x00020000, + SYS_MEMATTRIB_FORCE32BITS = 0x7FFFFFFFU +}; + +#endif /* __IMG_MEM__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/img_mem_man.c b/drivers/media/platform/imagination/vxe-vxd/common/img_mem_man.c --- a/drivers/media/platform/imagination/vxe-vxd/common/img_mem_man.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/img_mem_man.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,1125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMG DEC Memory Manager + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imgmmu.h" +#include "img_mem_man.h" +#include "img_errors.h" + +#define VXD_MMU_SHIFT 8 /* assume 40-bit MMU */ +/* heaps ids (global) */ +#define MIN_HEAP 1 +#define MAX_HEAP 16 + +/* + * struct dev_mem_man - the device memory management + * @heaps: idr list of heap for the device memory manager + * @mem_ctxs: contains lists of mem_ctx + * @mutex: mutex for this device + */ +struct mem_man { + void *dev; + struct idr *heaps; + struct list_head mem_ctxs; + struct mutex *mutex; /* mutex for this device */ +}; + +static struct mem_man mem_man_data = {0}; + +/** + * struct mmu_page - the mmu page information for the buffer + * @buffer: buffer pointer for the particular mmu_page + * @page_cfg: mmu page configuration of physical and virtual addr + * @addr_shift: address shifting information + */ +struct mmu_page { + struct buffer *buffer; + struct mmu_page_cfg page_cfg; + unsigned int addr_shift; +}; + +static void _img_mem_free(struct buffer *buffer); +static void _img_mmu_unmap(struct mmu_ctx_mapping *mapping); +static void _img_mmu_ctx_destroy(struct mmu_ctx *ctx); + +#if defined(DEBUG_DECODER_DRIVER) +static unsigned char *get_heap_name(enum heap_type type) +{ + switch (type) { + case MEM_HEAP_TYPE_UNIFIED: + return "unified"; + default: + return "unknown"; + } +} +#endif + +int img_mem_add_heap(const struct heap_config *heap_cfg, int *heap_id) +{ + struct mem_man *mem_man = &mem_man_data; + struct heap *heap; + int (*init_fn)(const struct heap_config *heap_cfg, struct heap *heap); + int ret; + + switch (heap_cfg->type) { + case MEM_HEAP_TYPE_UNIFIED: + init_fn = img_mem_unified_init; + break; + default: + dev_err(mem_man->dev, "%s: heap type %d unknown\n", __func__, + heap_cfg->type); + return -EINVAL; + } + + heap = kmalloc(sizeof(*heap), GFP_KERNEL); + if (!heap) + return -ENOMEM; + + ret = mutex_lock_interruptible_nested(mem_man->mutex, SUBCLASS_IMGMEM); + if (ret) + goto lock_failed; + + ret = idr_alloc(mem_man->heaps, heap, MIN_HEAP, MAX_HEAP, GFP_KERNEL); + if (ret < 0) { + dev_err(mem_man->dev, "%s: idr_alloc failed\n", __func__); + goto alloc_id_failed; + } + + heap->id = ret; + heap->type = heap_cfg->type; + heap->options = heap_cfg->options; + heap->to_dev_addr = heap_cfg->to_dev_addr; + heap->priv = NULL; + + ret = init_fn(heap_cfg, heap); + if (ret) { + dev_err(mem_man->dev, "%s: heap init failed\n", __func__); + goto heap_init_failed; + } + + *heap_id = heap->id; + mutex_unlock(mem_man->mutex); + +#ifdef DEBUG_DECODER_DRIVER + dev_info(mem_man->dev, "%s created heap %d type %d (%s)\n", + __func__, *heap_id, heap_cfg->type, get_heap_name(heap->type)); +#endif + return 0; + +heap_init_failed: + idr_remove(mem_man->heaps, heap->id); +alloc_id_failed: + mutex_unlock(mem_man->mutex); +lock_failed: + kfree(heap); + return ret; +} + +static void _img_mem_del_heap(struct heap *heap) +{ + struct mem_man *mem_man = &mem_man_data; + + if (heap->ops->destroy) + heap->ops->destroy(heap); + + idr_remove(mem_man->heaps, heap->id); +} + +void img_mem_del_heap(int heap_id) +{ + struct mem_man *mem_man = &mem_man_data; + struct heap *heap; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + + heap = idr_find(mem_man->heaps, heap_id); + if (!heap) { + dev_warn(mem_man->dev, "%s heap %d not found!\n", __func__, + heap_id); + mutex_unlock(mem_man->mutex); + return; + } + + _img_mem_del_heap(heap); + + mutex_unlock(mem_man->mutex); + + kfree(heap); +} + +int img_mem_create_ctx(struct mem_ctx **new_ctx) +{ + struct mem_man *mem_man = &mem_man_data; + struct mem_ctx *ctx; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->buffers = kzalloc(sizeof(*ctx->buffers), GFP_KERNEL); + if (!ctx->buffers) + return -ENOMEM; + idr_init(ctx->buffers); + + INIT_LIST_HEAD(&ctx->mmu_ctxs); + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + list_add(&ctx->mem_man_entry, &mem_man->mem_ctxs); + mutex_unlock(mem_man->mutex); + + *new_ctx = ctx; + return 0; +} + +static void _img_mem_destroy_ctx(struct mem_ctx *ctx) +{ + struct mem_man *mem_man = &mem_man_data; + struct buffer *buffer; + int buff_id; + + /* free derelict mmu contexts */ + while (!list_empty(&ctx->mmu_ctxs)) { + struct mmu_ctx *mc; + + mc = list_first_entry(&ctx->mmu_ctxs, + struct mmu_ctx, mem_ctx_entry); + dev_warn(mem_man->dev, "%s: found derelict mmu context %p\n", + __func__, mc); + _img_mmu_ctx_destroy(mc); + kfree(mc); + } + + /* free derelict buffers */ + buff_id = MEM_MAN_MIN_BUFFER; + buffer = idr_get_next(ctx->buffers, &buff_id); + while (buffer) { + dev_warn(mem_man->dev, "%s: found derelict buffer %d\n", + __func__, buff_id); + if (buffer->heap) + _img_mem_free(buffer); + else + idr_remove(ctx->buffers, buffer->id); + kfree(buffer); + buff_id = MEM_MAN_MIN_BUFFER; + buffer = idr_get_next(ctx->buffers, &buff_id); + } + + idr_destroy(ctx->buffers); + kfree(ctx->buffers); + __list_del_entry(&ctx->mem_man_entry); +} + +void img_mem_destroy_ctx(struct mem_ctx *ctx) +{ + struct mem_man *mem_man = &mem_man_data; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + _img_mem_destroy_ctx(ctx); + mutex_unlock(mem_man->mutex); + + kfree(ctx); +} + +static int _img_mem_alloc(void *device, struct mem_ctx *ctx, + struct heap *heap, unsigned long size, + enum mem_attr attr, struct buffer **buffer_new) +{ + struct buffer *buffer; + int ret; + + if (size == 0) { + dev_err(device, "%s: buffer size is zero\n", __func__); + return -EINVAL; + } + + if (!heap->ops || !heap->ops->alloc) { + dev_err(device, "%s: no alloc function in heap %d!\n", + __func__, heap->id); + return -EINVAL; + } + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + ret = idr_alloc(ctx->buffers, buffer, + MEM_MAN_MIN_BUFFER, MEM_MAN_MAX_BUFFER, GFP_KERNEL); + if (ret < 0) { + dev_err(device, "%s: idr_alloc failed\n", __func__); + goto idr_alloc_failed; + } + + buffer->id = ret; + buffer->request_size = size; + buffer->actual_size = ((size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; + buffer->device = device; + buffer->mem_ctx = ctx; + buffer->heap = heap; + INIT_LIST_HEAD(&buffer->mappings); + buffer->kptr = NULL; + buffer->priv = NULL; + + ret = heap->ops->alloc(device, heap, buffer->actual_size, attr, + buffer); + if (ret) { + dev_err(device, "%s: heap %d alloc failed\n", __func__, + heap->id); + goto heap_alloc_failed; + } + + *buffer_new = buffer; + + dev_dbg(device, "%s heap %p ctx %p created buffer %d (%p) actual_size %lu\n", + __func__, heap, ctx, buffer->id, buffer, buffer->actual_size); + return 0; + +heap_alloc_failed: + idr_remove(ctx->buffers, buffer->id); +idr_alloc_failed: + kfree(buffer); + return ret; +} + +int img_mem_alloc(void *device, struct mem_ctx *ctx, int heap_id, + unsigned long size, enum mem_attr attr, int *buf_id) +{ + struct mem_man *mem_man = &mem_man_data; + struct heap *heap; + struct buffer *buffer; + int ret; + + dev_dbg(device, "%s heap %d ctx %p size %lu\n", __func__, heap_id, + ctx, size); + + ret = mutex_lock_interruptible_nested(mem_man->mutex, SUBCLASS_IMGMEM); + if (ret) + return ret; + + heap = idr_find(mem_man->heaps, heap_id); + if (!heap) { + dev_err(device, "%s: heap id %d not found\n", __func__, + heap_id); + mutex_unlock(mem_man->mutex); + return -EINVAL; + } + + ret = _img_mem_alloc(device, ctx, heap, size, attr, &buffer); + if (ret) { + mutex_unlock(mem_man->mutex); + return ret; + } + + *buf_id = buffer->id; + mutex_unlock(mem_man->mutex); + + dev_dbg(device, "%s heap %d ctx %p created buffer %d (%p) size %lu\n", + __func__, heap_id, ctx, *buf_id, buffer, size); + return ret; +} + +static int _img_mem_import(void *device, struct mem_ctx *ctx, + unsigned long size, enum mem_attr attr, struct buffer **buffer_new) +{ + struct buffer *buffer; + int ret; + + if (size == 0) { + dev_err(device, "%s: buffer size is zero\n", __func__); + return -EINVAL; + } + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + ret = idr_alloc(ctx->buffers, buffer, + MEM_MAN_MIN_BUFFER, MEM_MAN_MAX_BUFFER, GFP_KERNEL); + if (ret < 0) { + dev_err(device, "%s: idr_alloc failed\n", __func__); + goto idr_alloc_failed; + } + + buffer->id = ret; + buffer->request_size = size; + buffer->actual_size = ((size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; + buffer->device = device; + buffer->mem_ctx = ctx; + buffer->heap = NULL; + INIT_LIST_HEAD(&buffer->mappings); + buffer->kptr = NULL; + buffer->priv = NULL; + + *buffer_new = buffer; + + dev_dbg(device, "%s ctx %p created buffer %d (%p) actual_size %lu\n", + __func__, ctx, buffer->id, buffer, buffer->actual_size); + return 0; + +idr_alloc_failed: + kfree(buffer); + return ret; +} + +int img_mem_import(void *device, struct mem_ctx *ctx, + unsigned long size, enum mem_attr attr, int *buf_id) +{ + struct mem_man *mem_man = &mem_man_data; + struct buffer *buffer; + int ret; + + dev_dbg(device, "%s ctx %p size %lu\n", __func__, ctx, size); + + ret = mutex_lock_interruptible_nested(mem_man->mutex, SUBCLASS_IMGMEM); + if (ret) + return ret; + + ret = _img_mem_import(device, ctx, size, attr, &buffer); + if (ret) { + mutex_unlock(mem_man->mutex); + return ret; + } + + *buf_id = buffer->id; + mutex_unlock(mem_man->mutex); + + dev_dbg(device, "%s ctx %p created buffer %d (%p) size %lu\n", + __func__, ctx, *buf_id, buffer, size); + return ret; +} + +static void _img_mem_free(struct buffer *buffer) +{ + void *dev = buffer->device; + struct heap *heap = buffer->heap; + struct mem_ctx *ctx = buffer->mem_ctx; + + if (!heap->ops || !heap->ops->free) { + dev_err(dev, "%s: no free function in heap %d!\n", + __func__, heap->id); + return; + } + + while (!list_empty(&buffer->mappings)) { + struct mmu_ctx_mapping *map; + + map = list_first_entry(&buffer->mappings, + struct mmu_ctx_mapping, buffer_entry); + dev_warn(dev, "%s: found mapping for buffer %d (size %lu)\n", + __func__, map->buffer->id, map->buffer->actual_size); + + _img_mmu_unmap(map); + + kfree(map); + } + + heap->ops->free(heap, buffer); + + idr_remove(ctx->buffers, buffer->id); +} + +void img_mem_free(struct mem_ctx *ctx, int buff_id) +{ + struct mem_man *mem_man = &mem_man_data; + struct buffer *buffer; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + + buffer = idr_find(ctx->buffers, buff_id); + if (!buffer) { + dev_err(mem_man->dev, "%s: buffer id %d not found\n", + __func__, buff_id); + mutex_unlock(mem_man->mutex); + return; + } + + _img_mem_free(buffer); + + mutex_unlock(mem_man->mutex); + + kfree(buffer); +} + +void img_mem_free_bufid(struct mem_ctx *ctx, int buff_id) +{ + struct mem_man *mem_man = &mem_man_data; + struct buffer *buffer; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + + buffer = idr_find(ctx->buffers, buff_id); + if (!buffer) { + dev_err(mem_man->dev, "%s: buffer id %d not found\n", + __func__, buff_id); + mutex_unlock(mem_man->mutex); + return; + } + + idr_remove(ctx->buffers, buffer->id); + + mutex_unlock(mem_man->mutex); + + kfree(buffer); +} + +static int _img_mem_map_km(struct buffer *buffer) +{ + void *dev = buffer->device; + struct heap *heap = buffer->heap; + + if (!heap->ops || !heap->ops->map_km) { + dev_err(dev, "%s: no map_km in heap %d!\n", __func__, heap->id); + return -EINVAL; + } + + return heap->ops->map_km(heap, buffer); +} + +int img_mem_map_km(struct mem_ctx *ctx, int buff_id) +{ + struct mem_man *mem_man = &mem_man_data; + struct buffer *buffer; + int ret; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + buffer = idr_find(ctx->buffers, buff_id); + if (!buffer) { + dev_err(mem_man->dev, "%s: buffer id %d not found\n", + __func__, buff_id); + mutex_unlock(mem_man->mutex); + return -EINVAL; + } + + ret = _img_mem_map_km(buffer); + + mutex_unlock(mem_man->mutex); + + return ret; +} + +void *img_mem_get_kptr(struct mem_ctx *ctx, int buff_id) +{ + struct mem_man *mem_man = &mem_man_data; + struct buffer *buffer; + void *kptr; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + buffer = idr_find(ctx->buffers, buff_id); + if (!buffer) { + dev_err(mem_man->dev, "%s: buffer id %d not found\n", __func__, + buff_id); + mutex_unlock(mem_man->mutex); + return NULL; + } + kptr = buffer->kptr; + mutex_unlock(mem_man->mutex); + return kptr; +} + +static void _img_mem_sync_cpu_to_device(struct buffer *buffer) +{ + struct heap *heap = buffer->heap; + + if (heap->ops && heap->ops->sync_cpu_to_dev) + heap->ops->sync_cpu_to_dev(heap, buffer); + + /* sync to device memory */ + mb(); +} + +int img_mem_sync_cpu_to_device(struct mem_ctx *ctx, int buff_id) +{ + struct mem_man *mem_man = &mem_man_data; + struct buffer *buffer; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + buffer = idr_find(ctx->buffers, buff_id); + if (!buffer) { + dev_err(mem_man->dev, "%s: buffer id %d not found\n", __func__, + buff_id); + mutex_unlock(mem_man->mutex); + return -EINVAL; + } + + _img_mem_sync_cpu_to_device(buffer); + + mutex_unlock(mem_man->mutex); + return 0; +} + +static void _img_mem_sync_device_to_cpu(struct buffer *buffer) +{ + struct heap *heap = buffer->heap; + + if (heap->ops && heap->ops->sync_dev_to_cpu) + heap->ops->sync_dev_to_cpu(heap, buffer); +} + +int img_mem_sync_device_to_cpu(struct mem_ctx *ctx, int buff_id) +{ + struct mem_man *mem_man = &mem_man_data; + struct buffer *buffer; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + buffer = idr_find(ctx->buffers, buff_id); + if (!buffer) { + dev_err(mem_man->dev, "%s: buffer id %d not found\n", __func__, + buff_id); + mutex_unlock(mem_man->mutex); + return -EINVAL; + } + + _img_mem_sync_device_to_cpu(buffer); + + mutex_unlock(mem_man->mutex); + return 0; +} + +static struct mmu_page_cfg *mmu_page_alloc(void *arg) +{ + struct mem_man *mem_man = &mem_man_data; + struct mmu_ctx *mmu_ctx = arg; + struct mmu_page *page; + struct buffer *buffer; + struct heap *heap; + int ret; + + dev_dbg(mmu_ctx->device, "%s:%d arg %p\n", __func__, __LINE__, arg); + + WARN_ON(!mutex_is_locked(mem_man->mutex)); + + page = kzalloc(sizeof(*page), GFP_KERNEL); + if (!page) + return NULL; + + ret = _img_mem_alloc(mmu_ctx->device, mmu_ctx->mem_ctx, + mmu_ctx->heap, PAGE_SIZE, (enum mem_attr)0, &buffer); + if (ret) { + dev_err(mmu_ctx->device, "%s: img_mem_alloc failed (%d)\n", + __func__, ret); + goto free_page; + } + + ret = _img_mem_map_km(buffer); + if (ret) { + dev_err(mmu_ctx->device, "%s: img_mem_map_km failed (%d)\n", + __func__, ret); + goto free_buffer; + } + + page->addr_shift = mmu_ctx->mmu_config_addr_width - 32; + page->buffer = buffer; + page->page_cfg.cpu_virt_addr = (unsigned long)buffer->kptr; + + heap = buffer->heap; + if (heap->ops && heap->ops->get_sg_table) { + void *sgt; + + ret = heap->ops->get_sg_table(heap, buffer, &sgt); + if (ret) { + dev_err(mmu_ctx->device, + "%s: heap %d buffer %d no sg_table!\n", + __func__, heap->id, buffer->id); + ret = -EINVAL; + goto free_buffer; + } + page->page_cfg.phys_addr = sg_phys(img_mmu_get_sgl(sgt)); + } else { + dev_err(mmu_ctx->device, "%s: heap %d buffer %d no get_sg!\n", + __func__, heap->id, buffer->id); + ret = -EINVAL; + goto free_buffer; + } + + dev_dbg(mmu_ctx->device, "%s:%d virt addr %#lx\n", __func__, __LINE__, + page->page_cfg.cpu_virt_addr); + dev_dbg(mmu_ctx->device, "%s:%d phys addr %#llx\n", __func__, __LINE__, + page->page_cfg.phys_addr); + return &page->page_cfg; + +free_buffer: + _img_mem_free(buffer); + kfree(buffer); +free_page: + kfree(page); + return NULL; +} + +static void mmu_page_free(struct mmu_page_cfg *arg) +{ + struct mem_man *mem_man = &mem_man_data; + struct mmu_page *page; + + page = container_of(arg, struct mmu_page, page_cfg); + + WARN_ON(!mutex_is_locked(mem_man->mutex)); + + _img_mem_free(page->buffer); + kfree(page->buffer); + kfree(page); +} + +static void mmu_page_write(struct mmu_page_cfg *page_cfg, + unsigned int offset, unsigned long long addr, + unsigned int flags) +{ + unsigned int *mem = (unsigned int *)page_cfg->cpu_virt_addr; + struct mmu_page *mmu_page; + struct heap *heap; + + mmu_page = container_of(page_cfg, struct mmu_page, page_cfg); + heap = mmu_page->buffer->heap; + + /* skip translation when flags are zero, assuming address is invalid */ + if (flags && heap->to_dev_addr) + addr = heap->to_dev_addr(&heap->options, addr); + addr >>= mmu_page->addr_shift; + + mem[offset] = addr | flags; +} + +static void mmu_update_page(struct mmu_page_cfg *arg) +{ + struct mem_man *mem_man = &mem_man_data; + struct mmu_page *page; + + page = container_of(arg, struct mmu_page, page_cfg); + + WARN_ON(!mutex_is_locked(mem_man->mutex)); + + _img_mem_sync_cpu_to_device(page->buffer); +} + +int img_mmu_ctx_create(void *device, unsigned int mmu_config_addr_width, + struct mem_ctx *mem_ctx, int heap_id, + void (*callback_fn)(enum mmu_callback_type type, + int buff_id, void *data), + void *callback_data, struct mmu_ctx **mmu_ctx) +{ + struct mem_man *mem_man = &mem_man_data; + + static struct mmu_info mmu_functions = { + .pfn_page_alloc = mmu_page_alloc, + .pfn_page_free = mmu_page_free, + .pfn_page_write = mmu_page_write, + .pfn_page_update = mmu_update_page, + }; + struct mmu_ctx *ctx; + int ret; + + if (mmu_config_addr_width < 32) { + dev_err(device, + "%s: invalid addr_width (%d) must be >= 32 !\n", + __func__, mmu_config_addr_width); + return -EINVAL; + } + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->device = device; + ctx->mem_ctx = mem_ctx; + ctx->mmu_config_addr_width = mmu_config_addr_width; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + + ctx->heap = idr_find(mem_man->heaps, heap_id); + if (!ctx->heap) { + dev_err(device, "%s: invalid heap_id (%d)!\n", __func__, + heap_id); + mutex_unlock(mem_man->mutex); + kfree(ctx); + return -EINVAL; + } + + mmu_functions.alloc_ctx = ctx; + ctx->mmu_dir = mmu_create_directory(&mmu_functions); + if (IS_ERR_VALUE((unsigned long)ctx->mmu_dir)) { + ret = (long)(ctx->mmu_dir); + dev_err(device, "%s: directory create failed (%d)!\n", __func__, + ret); + ctx->mmu_dir = NULL; + mutex_unlock(mem_man->mutex); + kfree(ctx); + return ret; + } + + list_add(&ctx->mem_ctx_entry, &mem_ctx->mmu_ctxs); + INIT_LIST_HEAD(&ctx->mappings); + + ctx->callback_fn = callback_fn; + ctx->callback_data = callback_data; + + *mmu_ctx = ctx; + + mutex_unlock(mem_man->mutex); + + return 0; +} + +static void _img_mmu_ctx_destroy(struct mmu_ctx *ctx) +{ + struct mem_man *mem_man = &mem_man_data; + int ret; + + while (!list_empty(&ctx->mappings)) { + struct mmu_ctx_mapping *map; + + map = list_first_entry(&ctx->mappings, + struct mmu_ctx_mapping, mmu_ctx_entry); +#ifdef DEBUG_DECODER_DRIVER + dev_info(ctx->device, + "%s: found mapped buffer %d (size %lu)\n", + __func__, map->buffer->id, map->buffer->request_size); +#endif + + _img_mmu_unmap(map); + + kfree(map); + } + + ret = mmu_destroy_directory(ctx->mmu_dir); + if (ret) + dev_err(mem_man->dev, "mmu_destroy_directory failed (%d)!\n", + ret); + __list_del_entry(&ctx->mem_ctx_entry); +} + +void img_mmu_ctx_destroy(struct mmu_ctx *ctx) +{ + struct mem_man *mem_man = &mem_man_data; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + _img_mmu_ctx_destroy(ctx); + mutex_unlock(mem_man->mutex); + + kfree(ctx); +} + +int img_mmu_map_sg(struct mmu_ctx *mmu_ctx, struct mem_ctx *mem_ctx, + int buff_id, void *sgt, unsigned int virt_addr, + unsigned int map_flags) +{ + struct mem_man *mem_man = &mem_man_data; + struct mmu_ctx_mapping *mapping; + struct mmu_heap_alloc heap_alloc; + struct buffer *buffer; + int ret = 0; + + dev_dbg(mmu_ctx->device, "%s sgt %p virt_addr %#x\n", __func__, + sgt, virt_addr); + + mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); + if (!mapping) + return -ENOMEM; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + buffer = idr_find(mem_ctx->buffers, buff_id); + if (!buffer) { + dev_err(mmu_ctx->device, "%s: buffer id %d not found\n", + __func__, buff_id); + ret = -EINVAL; + goto error; + } + dev_dbg(mmu_ctx->device, "%s buffer %d 0x%p size %lu virt_addr %#x\n", + __func__, buff_id, buffer, buffer->request_size, virt_addr); + + heap_alloc.virt_addr = virt_addr; + heap_alloc.alloc_size = buffer->actual_size; + + mapping->mmu_ctx = mmu_ctx; + mapping->buffer = buffer; + mapping->virt_addr = virt_addr; + + if (sgt) { + struct sg_table *sgt_new = sgt; + + mapping->map = mmu_directory_map_sg(mmu_ctx->mmu_dir, sgt_new->sgl, + &heap_alloc, map_flags); + if (IS_ERR_VALUE((unsigned long)mapping->map)) { + ret = (long)(mapping->map); + mapping->map = NULL; + } + } else { + dev_err(mmu_ctx->device, "%s: buffer %d no get_sg!\n", + __func__, buffer->id); + ret = -EINVAL; + goto error; + } + if (ret) { + dev_err(mmu_ctx->device, "mmu_directory_map_sg failed (%d)!\n", + ret); + goto error; + } + + list_add(&mapping->mmu_ctx_entry, &mmu_ctx->mappings); + list_add(&mapping->buffer_entry, &mapping->buffer->mappings); + + if (mmu_ctx->callback_fn) + mmu_ctx->callback_fn(MMU_CALLBACK_MAP, buffer->id, + mmu_ctx->callback_data); + + mutex_unlock(mem_man->mutex); + return 0; + +error: + mutex_unlock(mem_man->mutex); + kfree(mapping); + return ret; +} + +int img_mmu_map(struct mmu_ctx *mmu_ctx, struct mem_ctx *mem_ctx, + int buff_id, unsigned int virt_addr, unsigned int map_flags) +{ + struct mem_man *mem_man = &mem_man_data; + struct mmu_ctx_mapping *mapping; + struct mmu_heap_alloc heap_alloc; + struct buffer *buffer; + struct heap *heap; + int ret; + + dev_dbg(mmu_ctx->device, "%s buffer %d virt_addr %#x\n", __func__, + buff_id, virt_addr); + + mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); + if (!mapping) + return -ENOMEM; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + buffer = idr_find(mem_ctx->buffers, buff_id); + if (!buffer) { + dev_err(mmu_ctx->device, "%s: buffer id %d not found\n", + __func__, buff_id); + ret = -EINVAL; + goto error; + } + dev_dbg(mmu_ctx->device, "%s buffer %d 0x%p size %lu virt_addr %#x\n", + __func__, buff_id, buffer, buffer->request_size, virt_addr); + + heap_alloc.virt_addr = virt_addr; + heap_alloc.alloc_size = buffer->actual_size; + + mapping->mmu_ctx = mmu_ctx; + mapping->buffer = buffer; + mapping->virt_addr = virt_addr; + + heap = buffer->heap; + if (heap->ops && heap->ops->get_sg_table) { + void *sgt; + + ret = heap->ops->get_sg_table(heap, buffer, &sgt); + if (ret) { + dev_err(mmu_ctx->device, + "%s: heap %d buffer %d no sg_table!\n", + __func__, heap->id, buffer->id); + goto error; + } + + mapping->map = mmu_directory_map_sg(mmu_ctx->mmu_dir, img_mmu_get_sgl(sgt), + &heap_alloc, map_flags); + if (IS_ERR_VALUE((unsigned long)mapping->map)) { + ret = (long)(mapping->map); + mapping->map = NULL; + } + } else { + dev_err(mmu_ctx->device, "%s: heap %d buffer %d no get_sg!\n", + __func__, heap->id, buffer->id); + ret = -EINVAL; + goto error; + } + if (ret) { + dev_err(mmu_ctx->device, "mmu_directory_map failed (%d)!\n", + ret); + goto error; + } + + list_add(&mapping->mmu_ctx_entry, &mmu_ctx->mappings); + list_add(&mapping->buffer_entry, &mapping->buffer->mappings); + + if (mmu_ctx->callback_fn) + mmu_ctx->callback_fn(MMU_CALLBACK_MAP, buffer->id, + mmu_ctx->callback_data); + + mutex_unlock(mem_man->mutex); + return 0; + +error: + mutex_unlock(mem_man->mutex); + kfree(mapping); + return ret; +} + +static void _img_mmu_unmap(struct mmu_ctx_mapping *mapping) +{ + struct mmu_ctx *ctx = mapping->mmu_ctx; + int res; + + dev_dbg(ctx->device, "%s:%d mapping %p buffer %d\n", __func__, + __LINE__, mapping, mapping->buffer->id); + + res = mmu_directory_unmap(mapping->map); + if (res) + dev_warn(ctx->device, "mmu_directory_unmap failed (%d)!\n", + res); + + __list_del_entry(&mapping->mmu_ctx_entry); + __list_del_entry(&mapping->buffer_entry); + + if (ctx->callback_fn) + ctx->callback_fn(MMU_CALLBACK_UNMAP, mapping->buffer->id, + ctx->callback_data); +} + +int img_mmu_unmap(struct mmu_ctx *mmu_ctx, struct mem_ctx *mem_ctx, + int buff_id) +{ + struct mem_man *mem_man = &mem_man_data; + struct mmu_ctx_mapping *mapping; + struct list_head *lst; + + dev_dbg(mmu_ctx->device, "%s:%d buffer %d\n", __func__, __LINE__, + buff_id); + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + + mapping = NULL; + list_for_each(lst, &mmu_ctx->mappings) { + struct mmu_ctx_mapping *m; + + m = list_entry(lst, struct mmu_ctx_mapping, mmu_ctx_entry); + if (m->buffer->id == buff_id) { + mapping = m; + break; + } + } + + if (!mapping) { + dev_err(mmu_ctx->device, "%s: buffer id %d not found\n", + __func__, buff_id); + mutex_unlock(mem_man->mutex); + return -EINVAL; + } + + _img_mmu_unmap(mapping); + + mutex_unlock(mem_man->mutex); + kfree(mapping); + return 0; +} + +int img_mmu_get_ptd(const struct mmu_ctx *ctx, unsigned int *ptd) +{ + struct mem_man *mem_man = &mem_man_data; + struct mmu_page_cfg *page_cfg; + unsigned long long addr; + + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + + page_cfg = mmu_directory_get_page(ctx->mmu_dir); + if (!page_cfg) { + mutex_unlock(mem_man->mutex); + return -EINVAL; + } + + addr = page_cfg->phys_addr; + if (ctx->heap->to_dev_addr) + addr = ctx->heap->to_dev_addr(&ctx->heap->options, addr); + + mutex_unlock(mem_man->mutex); + + *ptd = (unsigned int)(addr >>= VXD_MMU_SHIFT); + + dev_dbg(ctx->device, "%s: addr %#llx ptd %#x\n", __func__, + page_cfg->phys_addr, *ptd); + return 0; +} + +int img_mmu_get_pagetable_entry(const struct mmu_ctx *ctx, unsigned long dev_virt_addr) +{ + if (!ctx) + return 0xFFFFFF; + + return mmu_directory_get_pagetable_entry(ctx->mmu_dir, dev_virt_addr); +} + +/* + * Initialisation + */ +int img_mem_init(void *dev) +{ + struct mem_man *mem_man = &mem_man_data; + + mem_man->dev = dev; + mem_man->heaps = kzalloc(sizeof(*mem_man->heaps), GFP_KERNEL); + if (!mem_man->heaps) + return -ENOMEM; + idr_init(mem_man->heaps); + INIT_LIST_HEAD(&mem_man->mem_ctxs); + mem_man->mutex = kzalloc(sizeof(*mem_man->mutex), GFP_KERNEL); + if (!mem_man->mutex) { + pr_err("Memory allocation failed for mutex\n"); + return -ENOMEM; + } + mutex_init(mem_man->mutex); + + return 0; +} + +void img_mem_exit(void) +{ + struct mem_man *mem_man = &mem_man_data; + struct heap *heap; + int heap_id; + + /* keeps mutex checks (WARN_ON) happy, this will never actually wait */ + mutex_lock_nested(mem_man->mutex, SUBCLASS_IMGMEM); + + while (!list_empty(&mem_man->mem_ctxs)) { + struct mem_ctx *mc; + + mc = list_first_entry(&mem_man->mem_ctxs, + struct mem_ctx, mem_man_entry); + dev_warn(mem_man->dev, "%s derelict memory context %p!\n", + __func__, mc); + _img_mem_destroy_ctx(mc); + kfree(mc); + } + + heap_id = MIN_HEAP; + heap = idr_get_next(mem_man->heaps, &heap_id); + while (heap) { + dev_warn(mem_man->dev, "%s derelict heap %d!\n", __func__, + heap_id); + _img_mem_del_heap(heap); + kfree(heap); + heap_id = MIN_HEAP; + heap = idr_get_next(mem_man->heaps, &heap_id); + } + idr_destroy(mem_man->heaps); + kfree(mem_man->heaps); + + mutex_unlock(mem_man->mutex); + + mutex_destroy(mem_man->mutex); + kfree(mem_man->mutex); + mem_man->mutex = NULL; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/img_mem_man.h b/drivers/media/platform/imagination/vxe-vxd/common/img_mem_man.h --- a/drivers/media/platform/imagination/vxe-vxd/common/img_mem_man.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/img_mem_man.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,231 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG DEC Memory Manager header file + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef _IMG_DEC_MEM_MGR_H +#define _IMG_DEC_MEM_MGR_H + +#include + +/* buffer ids (per memory context) */ +#define MEM_MAN_MIN_BUFFER 1 +#define MEM_MAN_MAX_BUFFER 16384 + +enum mem_attr { + MEM_ATTR_CACHED = 0x00000001, + MEM_ATTR_UNCACHED = 0x00000002, + MEM_ATTR_WRITECOMBINE = 0x00000004, + MEM_ATTR_SECURE = 0x00000010, + MEM_ATTR_FORCE32BITS = 0x7FFFFFFFU +}; + +enum mmu_callback_type { + MMU_CALLBACK_MAP = 1, + MMU_CALLBACK_UNMAP, + MMU_CALLBACK_FORCE32BITS = 0x7FFFFFFFU +}; + +enum heap_type { + MEM_HEAP_TYPE_UNIFIED = 1, + MEM_HEAP_TYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +union heap_options { + struct { + long long gfp_type; /* pool and flags for buffer allocations */ + } unified; +}; + +/** + * struct heap_config - contains heap configuration structure + * @type: enumeration of heap_type + * @options: pool and flags for buffer allocations, eg GFP_KERNEL + * @to_dev_addr: function pointer for retrieving device addr + */ +struct heap_config { + enum heap_type type; + union heap_options options; + unsigned long long (*to_dev_addr)(union heap_options *opts, unsigned long long addr); +}; + +/* + * struct mmu_heap - typedef for mmu_heap + * @virt_addr_start: start of the device virtual address + * @alloc_atom: atom allocation in bytes + * @size: total size of the heap in bytes + */ +struct mmu_heap { + unsigned long virt_addr_start; + unsigned long alloc_atom; + unsigned long size; +}; + +/* + * struct mem_ctx - the memory context + * @buffers: idr list of buffers + * @mmu_ctxs: contains linked lists of struct mmu_ctx + * @mem_man_entry: the entry list for dev_mem_main:mem_ctxs linked list + */ +struct mem_ctx { + struct idr *buffers; + struct list_head mmu_ctxs; + struct list_head mem_man_entry; +}; + +/* + * struct mmu_ctx_mapping - the mmu context mapping information + * @mmu_ctx: pointer to the mmu_ctx to which this mmu mapping information + * belongs + * @buffer: pointer to the buffer which this mmu_ctx_mapping is for + * @map: pointer to the mmu_map which this mmu_ctx_mapping belongs + * @virt_addr: Virtual address + * @mmu_ctx_entry: the entry list for mmu_ctx:mapping linked list. + * @buffer_entry: the entry list for buffer:mappings linked list. + */ +struct mmu_ctx_mapping { + struct mmu_ctx *mmu_ctx; + struct buffer *buffer; + struct mmu_map *map; + unsigned int virt_addr; + struct list_head mmu_ctx_entry; + struct list_head buffer_entry; +}; + +/* + * struct mmu_ctx - the mmu context information - one per stream + * @device: pointer to the device + * @mmu_config_addr_width: the address width for the mmu config + * @mem_ctx: pointer to mem_ctx where this mmu_ctx belongs to + * @heap: pointer to struct heap to where this mem_ctx belongs to + * @mmu_dir: pointer to the mmu_directory this mmu_ctx belongs to + * @mappings: contains linked list of struct mmu_ctx_mapping + * @mem_ctx_entry: the entry list for mem_ctx:mmu_ctxs + * @callback_fn: pointer to function callback + * @callback_data: pointer to the callback data + */ +struct mmu_ctx { + void *device; + unsigned int mmu_config_addr_width; + struct mem_ctx *mem_ctx; + struct heap *heap; + struct mmu_directory *mmu_dir; + struct list_head mappings; + struct list_head mem_ctx_entry; + void (*callback_fn)(enum mmu_callback_type type, int buff_id, + void *data); + void *callback_data; +}; + +/* + * struct buffer - the mmu context information - one per stream + * @id: buffer identification + * @request_size: request size for the allocation + * @actual_size: size aligned with the PAGE_SIZE allocation + * @device: pointer to the device + * @mem_ctx: pointer to struct mem_ctx to where this buffer belongs to + * @heap: pointer to struct heap to where this buffer belongs to + * @mappings: contains linked lists of struct mmu_ctx_mapping + * @kptr: pointer to virtual mapping for the buffer object into kernel address + * space + * @priv: pointer to priv data used for scaterlist table info + */ +struct buffer { + int id; /* Generated in */ + unsigned long request_size; + unsigned long actual_size; + void *device; + struct mem_ctx *mem_ctx; + struct heap *heap; + struct list_head mappings; /* contains */ + void *kptr; + void *priv; +}; + +struct heap_ops { + int (*alloc)(void *device, struct heap *heap, + unsigned long size, enum mem_attr attr, + struct buffer *buffer); + void (*free)(struct heap *heap, struct buffer *buffer); + int (*map_km)(struct heap *heap, struct buffer *buffer); + int (*get_sg_table)(struct heap *heap, struct buffer *buffer, + void **sg_table); + void (*sync_cpu_to_dev)(struct heap *heap, struct buffer *buffer); + void (*sync_dev_to_cpu)(struct heap *heap, struct buffer *buffer); + void (*destroy)(struct heap *heap); +}; + +struct heap { + int id; /* Generated in */ + enum heap_type type; + struct heap_ops *ops; + union heap_options options; + unsigned long long (*to_dev_addr)(union heap_options *opts, unsigned long long addr); + void *priv; +}; + +int img_mem_init(void *dev); +void img_mem_exit(void); + +int img_mem_create_ctx(struct mem_ctx **new_ctx); +void img_mem_destroy_ctx(struct mem_ctx *ctx); + +int img_mem_import(void *device, struct mem_ctx *ctx, + unsigned long size, enum mem_attr attr, int *buf_id); + +int img_mem_alloc(void *device, struct mem_ctx *ctx, int heap_id, + unsigned long size, enum mem_attr attributes, int *buf_id); +void img_mem_free(struct mem_ctx *ctx, int buff_id); + +void img_mem_free_bufid(struct mem_ctx *ctx, int buf_id); + +int img_mem_map_km(struct mem_ctx *ctx, int buf_id); +void *img_mem_get_kptr(struct mem_ctx *ctx, int buff_id); + +int img_mem_sync_cpu_to_device(struct mem_ctx *ctx, int buf_id); +int img_mem_sync_device_to_cpu(struct mem_ctx *ctx, int buf_id); + +int img_mmu_ctx_create(void *device, unsigned int mmu_config_addr_width, + struct mem_ctx *mem_ctx, int heap_id, + void (*callback_fn)(enum mmu_callback_type type, + int buff_id, void *data), + void *callback_data, struct mmu_ctx **mmu_ctx); +void img_mmu_ctx_destroy(struct mmu_ctx *ctx); + +int img_mmu_map(struct mmu_ctx *mmu_ctx, struct mem_ctx *mem_ctx, + int buff_id, unsigned int virt_addr, unsigned int map_flags); +int img_mmu_map_sg(struct mmu_ctx *mmu_ctx, struct mem_ctx *mem_ctx, + int buff_id, void *sgt, unsigned int virt_addr, + unsigned int map_flags); +int img_mmu_unmap(struct mmu_ctx *mmu_ctx, struct mem_ctx *mem_ctx, + int buff_id); + +int img_mmu_get_ptd(const struct mmu_ctx *ctx, unsigned int *ptd); + +int img_mmu_get_pagetable_entry(const struct mmu_ctx *ctx, unsigned long dev_virt_addr); + +int img_mem_add_heap(const struct heap_config *heap_cfg, int *heap_id); +void img_mem_del_heap(int heap_id); + +/* Heap operation related function */ +int img_mem_unified_init(const struct heap_config *config, + struct heap *heap); + +/* page and sg list related functions */ +void img_mmu_get_pages(void **page_args, void *sgt_args); +unsigned int img_mmu_get_orig_nents(void *sgt_args); +void img_mmu_set_sgt_nents(void *sgt_args, int ret); +void img_mmu_set_sg_table(void **sg_table_args, void *buffer); +unsigned int img_mmu_get_sgl_length(void *sgl_args); +void *img_mmu_get_sgl(void *sgt_args); + +#endif /* _IMG_DEC_MEM_MGR */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/img_mem_unified.c b/drivers/media/platform/imagination/vxe-vxd/common/img_mem_unified.c --- a/drivers/media/platform/imagination/vxe-vxd/common/img_mem_unified.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/img_mem_unified.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMG DEC Memory Manager for unified memory + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#include +#include +#include +#include + +#include "img_mem_man.h" + +void img_mmu_get_pages(void **page_args, void *sgt_args) +{ + struct page **pages = (struct page **)page_args; + struct sg_table *sgt = sgt_args; + struct scatterlist *sgl = sgt->sgl; + int i; + + i = 0; + while (sgl) { + pages[i++] = sg_page(sgl); + sgl = sg_next(sgl); + } +} + +unsigned int img_mmu_get_orig_nents(void *sgt_args) +{ + struct sg_table *sgt = sgt_args; + + return sgt->orig_nents; +} + +void img_mmu_set_sgt_nents(void *sgt_args, int ret) +{ + struct sg_table *sgt = sgt_args; + + sgt->nents = ret; +} + +void img_mmu_set_sg_table(void **sg_table_args, void *buffer) +{ + struct sg_table **sg_table = (struct sg_table **)sg_table_args; + + *sg_table = buffer; +} + +unsigned int img_mmu_get_sgl_length(void *sgl_args) +{ + struct scatterlist *sgl = (struct scatterlist *)sgl_args; + + return sgl->length; +} + +void *img_mmu_get_sgl(void *sgt_args) +{ + struct sg_table *sgt = sgt_args; + + return sgt->sgl; +} + +static int unified_alloc(void *device, struct heap *heap, + unsigned long size, enum mem_attr attr, + struct buffer *buffer) +{ + struct sg_table *sgt; + void *sgl; + int pages; + int ret; + + dev_dbg(device, "%s:%d buffer %d (0x%p)\n", __func__, __LINE__, + buffer->id, buffer); + + sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) + return -ENOMEM; + + pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; + + ret = sg_alloc_table(sgt, pages, GFP_KERNEL); + if (ret) + goto sg_alloc_table_failed; + + sgl = img_mmu_get_sgl(sgt); + while (sgl) { + void *page; + unsigned long long dma_addr; + + page = alloc_page(heap->options.unified.gfp_type); + if (!page) { + dev_err(device, "%s alloc_page failed!\n", __func__); + ret = -ENOMEM; + goto alloc_page_failed; + } + + /* + * dma_map_page() is probably going to fail if alloc flags are + * GFP_HIGHMEM, since it is not mapped to CPU. Hopefully, this + * will never happen because memory of this sort cannot be used + * for DMA anyway. To check if this is the case, build with + * debug, set trace_physical_pages=1 and check if page_address + * printed above is NULL + */ + dma_addr = dma_map_page(device, page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(device, dma_addr)) { + __free_page(page); + dev_err(device, "%s dma_map_page failed!\n", __func__); + ret = -EIO; + goto alloc_page_failed; + } + dma_unmap_page(device, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL); + + sg_set_page(sgl, page, PAGE_SIZE, 0); + + sgl = sg_next(sgl); + } + + buffer->priv = sgt; + return 0; + +alloc_page_failed: + sgl = img_mmu_get_sgl(sgt); + while (sgl) { + void *page = sg_page(sgl); + + if (page) + __free_page(page); + + sgl = sg_next(sgl); + } + sg_free_table(sgt); +sg_alloc_table_failed: + kfree(sgt); + return ret; +} + +static void unified_free(struct heap *heap, struct buffer *buffer) +{ + void *dev = buffer->device; + void *sgt = buffer->priv; + void *sgl; + + dev_dbg(dev, "%s:%d buffer %d (0x%p)\n", __func__, __LINE__, + buffer->id, buffer); + + if (buffer->kptr) { + dev_dbg(dev, "%s vunmap 0x%p\n", __func__, buffer->kptr); + dma_unmap_sg(dev, img_mmu_get_sgl(sgt), img_mmu_get_orig_nents(sgt), + DMA_FROM_DEVICE); + vunmap(buffer->kptr); + } + + sgl = img_mmu_get_sgl(sgt); + while (sgl) { + __free_page(sg_page(sgl)); + sgl = sg_next(sgl); + } + sg_free_table(sgt); + kfree(sgt); +} + +static int unified_map_km(struct heap *heap, struct buffer *buffer) +{ + void *dev = buffer->device; + void *sgt = buffer->priv; + void *sgl = img_mmu_get_sgl(sgt); + unsigned int num_pages = sg_nents(sgl); + unsigned int orig_nents = img_mmu_get_orig_nents(sgt); + void **pages; + int ret; + pgprot_t prot; + + dev_dbg(dev, "%s:%d buffer %d (0x%p)\n", __func__, __LINE__, buffer->id, buffer); + + if (buffer->kptr) { + dev_warn(dev, "%s called for already mapped buffer %d\n", __func__, buffer->id); + return 0; + } + + pages = kmalloc_array(num_pages, sizeof(void *), GFP_KERNEL); + if (!pages) + return -ENOMEM; + + img_mmu_get_pages(pages, sgt); + + prot = PAGE_KERNEL; + prot = pgprot_writecombine(prot); + buffer->kptr = vmap((struct page **)pages, num_pages, VM_MAP, prot); + kfree(pages); + if (!buffer->kptr) { + dev_err(dev, "%s vmap failed!\n", __func__); + return -EFAULT; + } + + ret = dma_map_sg(dev, sgl, orig_nents, DMA_FROM_DEVICE); + + if (ret <= 0) { + dev_err(dev, "%s dma_map_sg failed!\n", __func__); + vunmap(buffer->kptr); + return -EFAULT; + } + dev_dbg(dev, "%s:%d buffer %d orig_nents %d nents %d\n", __func__, + __LINE__, buffer->id, orig_nents, ret); + + img_mmu_set_sgt_nents(sgt, ret); + + dev_dbg(dev, "%s:%d buffer %d vmap to 0x%p\n", __func__, __LINE__, + buffer->id, buffer->kptr); + + return 0; +} + +static int unified_get_sg_table(struct heap *heap, struct buffer *buffer, void **sg_table) +{ + img_mmu_set_sg_table(sg_table, buffer->priv); + return 0; +} + +static void unified_sync_cpu_to_dev(struct heap *heap, struct buffer *buffer) +{ + void *dev = buffer->device; + void *sgt = buffer->priv; + + if (!buffer->kptr) + return; + + dev_dbg(dev, "%s:%d buffer %d (0x%p)\n", __func__, __LINE__, buffer->id, buffer); + + dma_sync_sg_for_device(dev, img_mmu_get_sgl(sgt), img_mmu_get_orig_nents(sgt), + DMA_TO_DEVICE); +} + +static void unified_sync_dev_to_cpu(struct heap *heap, struct buffer *buffer) +{ + void *dev = buffer->device; + void *sgt = buffer->priv; + + if (!buffer->kptr) + return; + + dev_dbg(dev, "%s:%d buffer %d (0x%p)\n", __func__, __LINE__, + buffer->id, buffer); + + dma_sync_sg_for_cpu(dev, img_mmu_get_sgl(sgt), img_mmu_get_orig_nents(sgt), + DMA_FROM_DEVICE); +} + +static void unified_heap_destroy(struct heap *heap) +{ +} + +static struct heap_ops unified_heap_ops = { + .alloc = unified_alloc, + .free = unified_free, + .map_km = unified_map_km, + .get_sg_table = unified_get_sg_table, + .sync_cpu_to_dev = unified_sync_cpu_to_dev, + .sync_dev_to_cpu = unified_sync_dev_to_cpu, + .destroy = unified_heap_destroy, +}; + +int img_mem_unified_init(const struct heap_config *heap_cfg, + struct heap *heap) +{ + heap->ops = &unified_heap_ops; + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/imgmmu.c b/drivers/media/platform/imagination/vxe-vxd/common/imgmmu.c --- a/drivers/media/platform/imagination/vxe-vxd/common/imgmmu.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/imgmmu.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,782 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMG DEC MMU function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#include +#include +#include +#include +#include "img_mem_man.h" +#include "imgmmu.h" + +/** + * struct mmu_directory - the MMU directory information + * @dir_page: pointer to the mmu_page_cfg_table (physical table used) which + * this mmu_directory belongs to + * @dir_page_table: All the page table structures in a static array of pointers + * @mmu_info_cfg: Functions to use to manage pages allocation, liberation and + * writing + * @num_mapping: number of mapping using this directory + */ +struct mmu_directory { + struct mmu_page_cfg *dir_page; + struct mmu_page_cfg_table **dir_page_table; + struct mmu_info mmu_info_cfg; + unsigned int num_mapping; +}; + +/* + * struct mmu_map - the MMU mapping information + * @mmu_dir: pointer to the mmu_directory which this mmu_map belongs to + * @dev_virt_addr: device virtual address root associated with this mapping + * @used_flag: flag used when allocating + * @n_entries: number of entries mapped + */ +struct mmu_map { + struct mmu_directory *mmu_dir; + struct mmu_heap_alloc dev_virt_addr; + unsigned int used_flag; + unsigned int n_entries; +}; + +/* + * struct mmu_page_cfg_table - the MMU page table information. + * One page table of the directory. + * @mmu_dir: pointer to the mmu_directory which this mmu_page_cfg_table + * belongs to + * @page: page used to store this mapping in the MMU + * @valid_entries: number of valid entries in this page + */ +struct mmu_page_cfg_table { + struct mmu_directory *mmu_dir; + struct mmu_page_cfg *page; + unsigned int valid_entries; +}; + +/* + * mmu_pgt_destroy() - Destruction of a page table (does not follow the + * child pointer) + * @pgt: pointer to the MMU page table information + * + * Warning: Does not verify if pages are still valid or not + */ +static void mmu_pgt_destroy(struct mmu_page_cfg_table *pgt) +{ + if (!pgt->mmu_dir || + !pgt->mmu_dir->mmu_info_cfg.pfn_page_free || + !pgt->page) { + return; + } + + pr_debug("%s:%d Destroy page table (phys addr %llu)\n", + __func__, __LINE__, pgt->page->phys_addr); + + pgt->mmu_dir->mmu_info_cfg.pfn_page_free(pgt->page); + pgt->page = NULL; + + kfree(pgt); +} + +/* + * mmu_dir_entry() - Extact the directory index from a virtual address + * @vaddr: virtual address + */ +static inline unsigned int mmu_dir_entry(unsigned long vaddr) +{ + return (unsigned int)((vaddr & VIRT_DIR_IDX_MASK) >> MMU_DIR_SHIFT); +} + +/* + * mmu_pg_entry() - Extract the page table index from a virtual address + * @vaddr: virtual address + */ +static inline unsigned int mmu_pg_entry(unsigned long vaddr) +{ + return (unsigned int)((vaddr & VIRT_PAGE_TBL_MASK) >> MMU_PAGE_SHIFT); +} + +/* + * mmu_pg_wr() - Default function used when a mmu_info structure has an empty + * pfn_page_write pointer + * @mmu_page: pointer to the mmu_page to update + * @offset: offset into the directory + * @pa_to_write: physical address value to add to the entr + * @mmu_flag: mmu flag(s) to set + */ +static void mmu_pg_wr(struct mmu_page_cfg *mmu_page, unsigned int offset, + unsigned long long pa_to_write, unsigned int mmu_flag) +{ + unsigned int *dir_mem = NULL; + unsigned long long cur_pa = pa_to_write; + + if (!mmu_page) + return; + + dir_mem = (unsigned int *)mmu_page->cpu_virt_addr; + /* + * assumes that the MMU HW has the extra-bits enabled (this default + * function has no way of knowing) + */ + if ((MMU_PHYS_SIZE - MMU_VIRT_SIZE) > 0) + cur_pa >>= (MMU_PHYS_SIZE - MMU_VIRT_SIZE); + /* + * The MMU_PAGE_SHIFT bottom bits should be masked because page + * allocation. + * MMU_PAGE_SHIFT-(MMU_PHYS_SIZE-MMU_VIRT_SIZE) are used for + * flags so it's ok + */ + dir_mem[offset] = (unsigned int)cur_pa | (mmu_flag); +} + +/* + * mmu_page_cfg_table() - Create a page table + * @mmu_dir: pointer to the mmu_directory in which to create the new page table + * structure + * + * Return: A pointer to the new page table structure in case of success. + * (void *) in case of error + */ +static struct mmu_page_cfg_table *mmu_pgt_create(struct mmu_directory *mmu_dir) +{ + struct mmu_page_cfg_table *neo = NULL; + unsigned int i; + + if (!mmu_dir || !mmu_dir->mmu_info_cfg.pfn_page_alloc || + !mmu_dir->mmu_info_cfg.pfn_page_write) + return (void *)(-EINVAL); + + neo = kmalloc(sizeof(*neo), GFP_KERNEL); + if (!neo) + return (void *)(-ENOMEM); + + neo->mmu_dir = mmu_dir; + + neo->page = + mmu_dir->mmu_info_cfg.pfn_page_alloc(mmu_dir->mmu_info_cfg.alloc_ctx); + if (!neo->page) { + pr_err("%s:%d failed to allocate Page Table physical page\n", + __func__, __LINE__); + kfree(neo); + return (void *)(-ENOMEM); + } + pr_debug("%s:%d Create page table (phys addr 0x%llx CPU Virt 0x%lx)\n", + __func__, __LINE__, neo->page->phys_addr, + neo->page->cpu_virt_addr); + + /* invalidate all pages */ + for (i = 0; i < MMU_N_PAGE; i++) { + mmu_dir->mmu_info_cfg.pfn_page_write(neo->page, i, 0, + MMU_FLAG_INVALID); + } + + /* + * When non-UMA need to update the device memory after setting + * it to 0 + */ + if (mmu_dir->mmu_info_cfg.pfn_page_update) + mmu_dir->mmu_info_cfg.pfn_page_update(neo->page); + + return neo; +} + +/* + * mmu_create_directory - Create a directory entry based on a given directory + * configuration + * @mmu_info_ops: contains the functions to use to manage page table memory. + * Is copied and not modified. + * + * @warning Obviously creation of the directory allocates memory - do not call + * while interrupts are disabled + * + * @return The opaque handle to the mmu_directory object and result to 0 + * @return (void *) in case of an error and result has the value: + * @li -EINVAL if mmu_info configuration is NULL or does not + * contain function pointers + * @li -ENOMEM if an internal allocation failed + * @li -ENOMEM if the given mmu_pfn_page_alloc returned NULL + */ +struct mmu_directory *mmu_create_directory(const struct mmu_info *mmu_info_ops) +{ + struct mmu_directory *neo = NULL; + unsigned int i; + + /* + * invalid information in the directory config: + * - invalid page allocator and dealloc (page write can be NULL) + * - invalid virtual address representation + * - invalid page size + * - invalid MMU size + */ + if (!mmu_info_ops || !mmu_info_ops->pfn_page_alloc || !mmu_info_ops->pfn_page_free) { + pr_err("%s:%d invalid MMU configuration\n", __func__, __LINE__); + return (void *)(-EINVAL); + } + + neo = kzalloc(sizeof(*neo), GFP_KERNEL); + if (!neo) + return (void *)(-ENOMEM); + + neo->dir_page_table = kcalloc(MMU_N_TABLE, sizeof(struct mmu_page_cfg_table *), + GFP_KERNEL); + if (!neo->dir_page_table) { + kfree(neo); + return (void *)(-ENOMEM); + } + + memcpy(&neo->mmu_info_cfg, mmu_info_ops, sizeof(struct mmu_info)); + if (!mmu_info_ops->pfn_page_write) { + pr_debug("%s:%d using default MMU write\n", __func__, __LINE__); + /* use internal function */ + neo->mmu_info_cfg.pfn_page_write = &mmu_pg_wr; + } + + neo->dir_page = mmu_info_ops->pfn_page_alloc(mmu_info_ops->alloc_ctx); + if (!neo->dir_page) { + kfree(neo->dir_page_table); + kfree(neo); + return (void *)(-ENOMEM); + } + + pr_debug("%s:%d (phys page 0x%llx; CPU virt 0x%lx)\n", __func__, + __LINE__, neo->dir_page->phys_addr, + neo->dir_page->cpu_virt_addr); + /* now we have a valid mmu_directory structure */ + + /* invalidate all entries */ + for (i = 0; i < MMU_N_TABLE; i++) { + neo->mmu_info_cfg.pfn_page_write(neo->dir_page, i, 0, + MMU_FLAG_INVALID); + } + + /* when non-UMA need to update the device memory */ + if (neo->mmu_info_cfg.pfn_page_update) + neo->mmu_info_cfg.pfn_page_update(neo->dir_page); + + return neo; +} + +/* + * mmu_destroy_directory - Destroy the mmu_directory - assumes that the HW is + * not going to access the memory any-more + * @mmu_dir: pointer to the mmu directory to destroy + * + * Does not invalidate any memory because it assumes that everything is not + * used any-more + */ +int mmu_destroy_directory(struct mmu_directory *mmu_dir) +{ + unsigned int i; + + if (!mmu_dir) { + /* could be an assert */ + pr_err("%s:%d mmu_dir is NULL\n", __func__, __LINE__); + return -EINVAL; + } + + if (mmu_dir->num_mapping > 0) + /* mappings should have been destroyed! */ + pr_err("%s:%d directory still has %u mapping attached to it\n", + __func__, __LINE__, mmu_dir->num_mapping); + /* + * not exiting because clearing the page table map is more + * important than losing a few structures + */ + + if (!mmu_dir->mmu_info_cfg.pfn_page_free || !mmu_dir->dir_page_table) + return -EINVAL; + + pr_debug("%s:%d destroy MMU dir (phys page 0x%llx)\n", + __func__, __LINE__, mmu_dir->dir_page->phys_addr); + + /* first we destroy the directory entry */ + mmu_dir->mmu_info_cfg.pfn_page_free(mmu_dir->dir_page); + mmu_dir->dir_page = NULL; + + /* destroy every mapping that still exists */ + for (i = 0; i < MMU_N_TABLE; i++) { + if (mmu_dir->dir_page_table[i]) { + mmu_pgt_destroy(mmu_dir->dir_page_table[i]); + mmu_dir->dir_page_table[i] = NULL; + } + } + + kfree(mmu_dir->dir_page_table); + kfree(mmu_dir); + return 0; +} + +/* + * mmu_directory_get_page - Get access to the page table structure used in the + * directory (to be able to write it to registers) + * @mmu_dir: pointer to the mmu directory. asserts if mmu_dir is NULL + * + * @return the page table structure used + */ +struct mmu_page_cfg *mmu_directory_get_page(struct mmu_directory *mmu_dir) +{ + if (!mmu_dir) + return NULL; + + return mmu_dir->dir_page; +} + +static struct mmu_map *mmu_directory_map(struct mmu_directory *mmu_dir, + const struct mmu_heap_alloc *dev_va, + unsigned int ui_map_flags, + int (*phys_iter_next)(void *arg, + unsigned long long *next), + void *phys_iter_arg) +{ + unsigned int first_dir = 0; + unsigned int first_pg = 0; + unsigned int dir_off = 0; + unsigned int pg_off = 0; + unsigned int n_entries = 0; + unsigned int i; + unsigned int d; + const unsigned int duplicate = PAGE_SIZE / mmu_get_page_size(); + int res = 0; + struct mmu_map *neo = NULL; + struct mmu_page_cfg_table **dir_pgtbl = NULL; + + /* + * in non UMA updates on pages needs to be done - store index of + * directory entry pages to update + */ + unsigned int *to_update; + /* + * number of pages in to_update (will be at least 1 for the first_pg to + * update) + */ + unsigned int n_pgs_to_update = 0; + /* + * to know if we also need to update the directory page (creation of new + * page) + */ + unsigned char dir_modified = FALSE; + + if (!mmu_dir || !dev_va || duplicate < 1) + return (void *)(-EINVAL); + + dir_pgtbl = mmu_dir->dir_page_table; + + n_entries = dev_va->alloc_size / PAGE_SIZE; + if (dev_va->alloc_size % MMU_PAGE_SIZE != 0 || n_entries == 0) { + pr_err("%s:%d invalid allocation size\n", __func__, __LINE__); + return (void *)(-EINVAL); + } + + if ((ui_map_flags & MMU_FLAG_VALID) != 0) { + pr_err("%s:%d valid flag (0x%x) is set in the falgs 0x%x\n", + __func__, __LINE__, MMU_FLAG_VALID, ui_map_flags); + return (void *)(-EINVAL); + } + + /* + * has to be dynamically allocated because it is bigger than 1k (max + * stack in the kernel) + * MMU_N_TABLE is 1024 for 4096B pages, that's a 4k allocation (1 page) + * - if it gets bigger may IMG_BIGALLOC should be used + */ + to_update = kcalloc(MMU_N_TABLE, sizeof(unsigned int), GFP_KERNEL); + if (!to_update) + return (void *)(-ENOMEM); + + /* manage multiple page table mapping */ + + first_dir = mmu_dir_entry(dev_va->virt_addr); + first_pg = mmu_pg_entry(dev_va->virt_addr); + + if (first_dir >= MMU_N_TABLE || first_pg >= MMU_N_PAGE) { + kfree(to_update); + return (void *)(-EINVAL); + } + + /* verify that the pages that should be used are available */ + dir_off = first_dir; + pg_off = first_pg; + + /* + * loop over the number of entries given by CPU allocator but CPU page + * size can be > than MMU page size therefore it may need to "duplicate" + * entries by creating a fake physical address + */ + for (i = 0; i < n_entries * duplicate; i++) { + if (pg_off >= MMU_N_PAGE) { + dir_off++; /* move to next directory */ + if (dir_off >= MMU_N_TABLE) { + res = -EINVAL; + break; + } + pg_off = 0; /* using its first page */ + } + + /* + * if dir_pgtbl[dir_off] == NULL not yet + * allocated it means all entries are available + */ + if (dir_pgtbl[dir_off]) { + /* + * inside a pagetable - verify that the required offset + * is invalid + */ + struct mmu_page_cfg_table *tbl = dir_pgtbl[dir_off]; + unsigned int *page_mem = (unsigned int *)tbl->page->cpu_virt_addr; + + if ((page_mem[pg_off] & MMU_FLAG_VALID) != 0) { + pr_err("%s:%d one of the required page is currently in use\n", + __func__, __LINE__); + res = -EPERM; + break; + } + } + /* PageTable struct exists */ + pg_off++; + } /* for all needed entries */ + + /* it means one entry was not invalid or not enough page were given */ + if (res != 0) { + /* + * message already printed + * IMG_ERROR_MEMORY_IN_USE when an entry is not invalid + * IMG_ERROR_INVALID_PARAMETERS when not enough pages are given + * (or too much) + */ + kfree(to_update); + return (void *)(unsigned long)(res); + } + + neo = kmalloc(sizeof(*neo), GFP_KERNEL); + if (!neo) { + kfree(to_update); + return (void *)(-ENOMEM); + } + neo->mmu_dir = mmu_dir; + neo->dev_virt_addr = *dev_va; + memcpy(&neo->dev_virt_addr, dev_va, sizeof(struct mmu_heap_alloc)); + neo->used_flag = ui_map_flags; + + /* we now know that all pages are available */ + dir_off = first_dir; + pg_off = first_pg; + + to_update[n_pgs_to_update] = first_dir; + n_pgs_to_update++; + + for (i = 0; i < n_entries; i++) { + unsigned long long cur_phys_addr; + + if (phys_iter_next(phys_iter_arg, &cur_phys_addr) != 0) { + pr_err("%s:%d not enough entries in physical address array\n", + __func__, __LINE__); + kfree(neo); + kfree(to_update); + return (void *)(-EBUSY); + } + for (d = 0; d < duplicate; d++) { + if (pg_off >= MMU_N_PAGE) { + /* move to next directory */ + dir_off++; + /* using its first page */ + pg_off = 0; + + to_update[n_pgs_to_update] = dir_off; + n_pgs_to_update++; + } + + /* this page table object does not exists, create it */ + if (!dir_pgtbl[dir_off]) { + dir_pgtbl[dir_off] = mmu_pgt_create(mmu_dir); + if (IS_ERR_VALUE((unsigned long)dir_pgtbl[dir_off])) { + dir_pgtbl[dir_off] = NULL; + goto cleanup_fail; + } + /* + * make this page table valid + * should be dir_off + */ + mmu_dir->mmu_info_cfg.pfn_page_write(mmu_dir->dir_page, + dir_off, + dir_pgtbl[dir_off]->page->phys_addr, + MMU_FLAG_VALID); + dir_modified = TRUE; + } + + /* + * map this particular page in the page table + * use d*(MMU page size) to add additional entries from + * the given physical address with the correct offset + * for the MMU + */ + mmu_dir->mmu_info_cfg.pfn_page_write(dir_pgtbl[dir_off]->page, + pg_off, + cur_phys_addr + d * + mmu_get_page_size(), + neo->used_flag | + MMU_FLAG_VALID); + dir_pgtbl[dir_off]->valid_entries++; + + pg_off++; + } /* for duplicate */ + } /* for entries */ + + neo->n_entries = n_entries * duplicate; + /* one more mapping is related to this directory */ + mmu_dir->num_mapping++; + + /* if non UMA we need to update device memory */ + if (mmu_dir->mmu_info_cfg.pfn_page_update) { + while (n_pgs_to_update > 0) { + unsigned int idx = to_update[n_pgs_to_update - 1]; + struct mmu_page_cfg_table *tbl = dir_pgtbl[idx]; + + mmu_dir->mmu_info_cfg.pfn_page_update(tbl->page); + n_pgs_to_update--; + } + if (dir_modified) + mmu_dir->mmu_info_cfg.pfn_page_update(mmu_dir->dir_page); + } + + kfree(to_update); + return neo; + +cleanup_fail: + pr_err("%s:%d failed to create a non-existing page table\n", __func__, __LINE__); + + /* + * invalidate all already mapped pages - + * do not destroy the created pages + */ + while (i > 1) { + if (d == 0) { + i--; + d = duplicate; + } + d--; + + if (pg_off == 0) { + pg_off = MMU_N_PAGE; + if (!dir_off) + continue; + dir_off--; + } + + pg_off--; + + /* it should have been used before */ + if (!dir_pgtbl[dir_off]) + continue; + + mmu_dir->mmu_info_cfg.pfn_page_write(dir_pgtbl[dir_off]->page, + pg_off, 0, + MMU_FLAG_INVALID); + dir_pgtbl[dir_off]->valid_entries--; + } + + kfree(neo); + kfree(to_update); + return (void *)(-ENOMEM); +} + +/* + * with sg + */ +struct sg_phys_iter { + void *sgl; + unsigned int offset; +}; + +static int sg_phys_iter_next(void *arg, unsigned long long *next) +{ + struct sg_phys_iter *iter = arg; + + if (!iter->sgl) + return -ENOENT; + + *next = sg_phys(iter->sgl) + iter->offset; /* phys_addr to dma_addr? */ + iter->offset += PAGE_SIZE; + + if (iter->offset == img_mmu_get_sgl_length(iter->sgl)) { + iter->sgl = sg_next(iter->sgl); + iter->offset = 0; + } + + return 0; +} + +/* + * mmu_directory_map_sg - Create a page table mapping for a list of physical + * pages and device virtual address + * + * @mmu_dir: directory to use for the mapping + * @phys_page_sg: sorted array of physical addresses (ascending order). The + * number of elements is dev_va->alloc_size/MMU_PAGE_SIZE + * @note This array can potentially be big, the caller may need to use vmalloc + * if running the linux kernel (e.g. mapping a 1080p NV12 is 760 entries, 6080 + * Bytes - 2 CPU pages needed, fine with kmalloc; 4k NV12 is 3038 entries, + * 24304 Bytes - 6 CPU pages needed, kmalloc would try to find 8 contiguous + * pages which may be problematic if memory is fragmented) + * @dev_va: associated device virtual address. Given structure is copied + * @map_flag: flags to apply on the page (typically 0x2 for Write Only, + * 0x4 for Read Only) - the flag should not set bit 1 as 0x1 is the + * valid flag. + * + * @warning Mapping can cause memory allocation (missing pages) - do not call + * while interrupts are disabled + * + * @return The opaque handle to the mmu_map object and result to 0 + * @return (void *) in case of an error with the following values: + * @li -EINVAL if the allocation size is not a multiple of MMU_PAGE_SIZE, + * if the given list of page table is too long or not long enough for the + * mapping or if the give flags set the invalid bit + * @li -EPERM if the virtual memory is already mapped + * @li -ENOMEM if an internal allocation failed + * @li -ENOMEM if a page creation failed + */ +struct mmu_map *mmu_directory_map_sg(struct mmu_directory *mmu_dir, + void *phys_page_sg, + const struct mmu_heap_alloc *dev_va, + unsigned int map_flag) +{ + struct sg_phys_iter arg = { phys_page_sg }; + + return mmu_directory_map(mmu_dir, dev_va, map_flag, + sg_phys_iter_next, &arg); +} + +/* + * mmu_directory_unmap - Un-map the mapped pages (invalidate their entries) and + * destroy the mapping object + * @map: pointer to the pages to un-map + * + * This does not destroy the created Page Table (even if they are becoming + * un-used) and does not change the Directory valid bits. + * + * @return 0 + */ +int mmu_directory_unmap(struct mmu_map *map) +{ + unsigned int first_dir = 0; + unsigned int first_pg = 0; + unsigned int dir_offset = 0; + unsigned int pg_offset = 0; + unsigned int i; + struct mmu_directory *mmu_dir = NULL; + + /* + * in non UMA updates on pages needs to be done - store index of + * directory entry pages to update + */ + unsigned int *to_update; + unsigned int n_pgs_to_update = 0; + + if (!map || map->n_entries <= 0 || !map->mmu_dir) + return -EINVAL; + + mmu_dir = map->mmu_dir; + + /* + * has to be dynamically allocated because it is bigger than 1k (max + * stack in the kernel) + */ + to_update = kcalloc(MMU_N_TABLE, sizeof(unsigned int), GFP_KERNEL); + if (!to_update) + return -ENOMEM; + + first_dir = mmu_dir_entry(map->dev_virt_addr.virt_addr); + first_pg = mmu_pg_entry(map->dev_virt_addr.virt_addr); + + /* verify that the pages that should be used are available */ + dir_offset = first_dir; + pg_offset = first_pg; + + to_update[n_pgs_to_update] = first_dir; + n_pgs_to_update++; + + for (i = 0; i < map->n_entries; i++) { + if (pg_offset >= MMU_N_PAGE) { + /* move to next directory */ + dir_offset++; + /* using its first page */ + pg_offset = 0; + + to_update[n_pgs_to_update] = dir_offset; + n_pgs_to_update++; + } + + /* + * this page table object does not exist, something destroyed + * it while the mapping was supposed to use it + */ + if (mmu_dir->dir_page_table[dir_offset]) { + mmu_dir->mmu_info_cfg.pfn_page_write + (mmu_dir->dir_page_table[dir_offset]->page, + pg_offset, 0, + MMU_FLAG_INVALID); + mmu_dir->dir_page_table[dir_offset]->valid_entries--; + } + + pg_offset++; + } + + mmu_dir->num_mapping--; + + if (mmu_dir->mmu_info_cfg.pfn_page_update) + while (n_pgs_to_update > 0) { + unsigned int idx = to_update[n_pgs_to_update - 1]; + struct mmu_page_cfg_table *tbl = mmu_dir->dir_page_table[idx]; + + mmu_dir->mmu_info_cfg.pfn_page_update(tbl->page); + n_pgs_to_update--; + } + + /* mapping does not own the given virtual address */ + kfree(map); + kfree(to_update); + return 0; +} + +unsigned int mmu_directory_get_pagetable_entry(struct mmu_directory *mmu_dir, + unsigned long dev_virt_addr) +{ + unsigned int dir_entry = 0; + unsigned int table_entry = 0; + struct mmu_page_cfg_table *tbl; + struct mmu_page_cfg_table **dir_pgtbl = NULL; + unsigned int *page_mem; + + if (!mmu_dir) { + pr_err("mmu directory table is NULL\n"); + return 0xFFFFFF; + } + + dir_pgtbl = mmu_dir->dir_page_table; + + dir_entry = mmu_dir_entry(dev_virt_addr); + table_entry = mmu_pg_entry(dev_virt_addr); + + tbl = dir_pgtbl[dir_entry]; + if (!tbl) { + pr_err("page table entry is NULL\n"); + return 0xFFFFFF; + } + + page_mem = (unsigned int *)tbl->page->cpu_virt_addr; + +#if defined(DEBUG_DECODER_DRIVER) || defined(DEBUG_ENCODER_DRIVER) + pr_info("Page table value@dir_entry:table_entry[%d : %d] = %x\n", + dir_entry, table_entry, page_mem[table_entry]); +#endif + + return page_mem[table_entry]; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/imgmmu.h b/drivers/media/platform/imagination/vxe-vxd/common/imgmmu.h --- a/drivers/media/platform/imagination/vxe-vxd/common/imgmmu.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/imgmmu.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG DEC MMU Library + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef IMG_DEC_MMU_MMU_H +#define IMG_DEC_MMU_MMU_H + +#include + +#ifndef MMU_PHYS_SIZE +/* @brief MMU physical address size in bits */ +#define MMU_PHYS_SIZE 40 +#endif + +#ifndef MMU_VIRT_SIZE +/* @brief MMU virtual address size in bits */ +#define MMU_VIRT_SIZE 32 +#endif + +#ifndef MMU_PAGE_SIZE +/* @brief Page size in bytes */ +#define MMU_PAGE_SIZE 4096u +#define MMU_PAGE_SHIFT 12 +#define MMU_DIR_SHIFT 22 +#endif + +#if MMU_VIRT_SIZE == 32 +/* @brief max number of pagetable that can be stored in the directory entry */ +#define MMU_N_TABLE (MMU_PAGE_SIZE / 4u) +/* @brief max number of page mapping in the pagetable */ +#define MMU_N_PAGE (MMU_PAGE_SIZE / 4u) +#endif + +/* @brief Memory flag used to mark a page mapping as invalid */ +#define MMU_FLAG_VALID 0x1 +#define MMU_FLAG_INVALID 0x0 + +/* + * This type defines MMU variant. + */ +enum mmu_etype { + MMU_TYPE_NONE = 0, + MMU_TYPE_32BIT, + MMU_TYPE_36BIT, + MMU_TYPE_40BIT, + MMU_TYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* @brief Page offset mask in virtual address - bottom bits */ +static const unsigned long VIRT_PAGE_OFF_MASK = ((1 << MMU_PAGE_SHIFT) - 1); +/* @brief Page table index mask in virtual address - middle bits */ +static const unsigned long VIRT_PAGE_TBL_MASK = + (((1 << MMU_DIR_SHIFT) - 1) & ~(((1 << MMU_PAGE_SHIFT) - 1))); +/* @brief Directory index mask in virtual address - high bits */ +static const unsigned long VIRT_DIR_IDX_MASK = (~((1 << MMU_DIR_SHIFT) - 1)); + +/* + * struct mmu_heap_alloc - information about a virtual mem heap allocation + * @virt_addr: pointer to start of the allocation + * @alloc_size: size in bytes + */ +struct mmu_heap_alloc { + unsigned long virt_addr; + unsigned long alloc_size; +}; + +/* + * struct mmu_page_cfg - mmu_page configuration + * @phys_addr: physical address - unsigned long long is used to support extended physical + * address on 32bit system + * @cpu_virt_addr: CPU virtual address pointer + */ +struct mmu_page_cfg { + unsigned long long phys_addr; + unsigned long cpu_virt_addr; +}; + +/* + * typedef mmu_pfn_page_alloc - page table allocation function + * + * Pointer to a function implemented by the used allocator to create 1 + * page table (used for the MMU mapping - directory page and mapping page) + * + * Return: + * * A populated mmu_page_cfg structure with the result of the page alloc. + * * NULL if the allocation failed. + */ +typedef struct mmu_page_cfg *(*mmu_pfn_page_alloc) (void *); + +/* + * typedef mmu_pfn_page_free + * @arg1: pointer to the mmu_page_cfg that is allocated using mmu_pfn_page_alloc + * + * Pointer to a function to free the allocated page table used for MMU mapping. + * + * @return void + */ +typedef void (*mmu_pfn_page_free) (struct mmu_page_cfg *arg1); + +/* + * typedef mmu_pfn_page_update + * @arg1: pointer to the mmu_page_cfg that is allocated using mmu_pfn_page_alloc + * + * Pointer to a function to update Device memory on non Unified Memory + * + * @return void + */ +typedef void (*mmu_pfn_page_update) (struct mmu_page_cfg *arg1); + +/* + * typedef mmu_pfn_page_write + * @mmu_page: mmu_page mmu page configuration to be written + * @offset: offset in entries (32b word) + * @pa_to_write: pa_to_write physical address to write + * @flags: flags bottom part of the entry used as flags for the MMU (including + * valid flag) + * + * Pointer to a function to write to a device address + * + * @return void + */ +typedef void (*mmu_pfn_page_write) (struct mmu_page_cfg *mmu_page, + unsigned int offset, + unsigned long long pa_to_write, unsigned int flags); + +/* + * struct mmu_info + * @pfn_page_alloc: function pointer for allocating a physical page used in + * MMU mapping + * @alloc_ctx: allocation context handler + * @pfn_page_free: function pointer for freeing a physical page used in + * MMU mapping + * @pfn_page_write: function pointer to write a physical address onto a page. + * If NULL, then internal function is used. Internal function + * assumes that MMU_PHYS_SIZE is the MMU size. + * @pfn_page_update: function pointer to update a physical page on device if + * non UMA. + */ +struct mmu_info { + mmu_pfn_page_alloc pfn_page_alloc; + void *alloc_ctx; + mmu_pfn_page_free pfn_page_free; + mmu_pfn_page_write pfn_page_write; + mmu_pfn_page_update pfn_page_update; +}; + +/* + * mmu_get_page_size() - Access the compilation specified page size of the + * MMU (in Bytes) + */ +static inline unsigned long mmu_get_page_size(void) +{ + return MMU_PAGE_SIZE; +} + +struct mmu_directory *mmu_create_directory(const struct mmu_info *mmu_info_ops); +int mmu_destroy_directory(struct mmu_directory *mmu_dir); + +struct mmu_page_cfg *mmu_directory_get_page(struct mmu_directory *mmu_dir); + +struct mmu_map *mmu_directory_map_sg(struct mmu_directory *mmu_dir, + void *phys_page_sg, + const struct mmu_heap_alloc *dev_va, + unsigned int map_flag); +int mmu_directory_unmap(struct mmu_map *map); + +unsigned int mmu_directory_get_pagetable_entry(struct mmu_directory *mmu_dir, + unsigned long dev_virt_addr); + +#endif /* IMG_DEC_MMU_MMU_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/lst.c b/drivers/media/platform/imagination/vxe-vxd/common/lst.c --- a/drivers/media/platform/imagination/vxe-vxd/common/lst.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/lst.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * List processing primitives. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Author: + * Lakshmi Sankar + */ + +#include "lst.h" + +#ifndef NULL +#define NULL ((void *)0) +#endif + +void lst_add(struct lst_t *list, void *item) +{ + if (!list->first) { + list->first = item; + list->last = item; + } else { + *list->last = item; + list->last = item; + } + *((void **)item) = NULL; +} + +void lst_addhead(struct lst_t *list, void *item) +{ + if (!list->first) { + list->first = item; + list->last = item; + *((void **)item) = NULL; + } else { + *((void **)item) = list->first; + list->first = item; + } +} + +int lst_empty(struct lst_t *list) +{ + if (!list->first) + return 1; + else + return 0; +} + +void *lst_first(struct lst_t *list) +{ + return list->first; +} + +void lst_init(struct lst_t *list) +{ + list->first = NULL; + list->last = NULL; +} + +void *lst_last(struct lst_t *list) +{ + return list->last; +} + +void *lst_next(void *item) +{ + return *((void **)item); +} + +void *lst_removehead(struct lst_t *list) +{ + void **temp = list->first; + + if (temp) { + list->first = *temp; + if (!list->first) + list->last = NULL; + } + return temp; +} + +void *lst_remove(struct lst_t *list, void *item) +{ + void **p; + void **q; + + p = (void **)list; + q = *p; + while (q) { + if (q == item) { + *p = *q; + if (list->last == q) + list->last = p; + return item; + } + p = q; + q = *p; + } + + return NULL; +} + +int lst_check(struct lst_t *list, void *item) +{ + void **p; + void **q; + + p = (void **)list; + q = *p; + while (q) { + if (q == item) + return 1; + p = q; + q = *p; + } + + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/lst.h b/drivers/media/platform/imagination/vxe-vxd/common/lst.h --- a/drivers/media/platform/imagination/vxe-vxd/common/lst.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/lst.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * List processing primitives. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Author: + * Lakshmi Sankar + */ +#ifndef __LIST_H__ +#define __LIST_H__ + +#include + +struct lst_t { + void **first; + void **last; +}; + +void lst_add(struct lst_t *list, void *item); +void lst_addhead(struct lst_t *list, void *item); + +/** + * lst_empty- Is list empty? + * @list: pointer to list + */ +int lst_empty(struct lst_t *list); +void *lst_first(struct lst_t *list); +void lst_init(struct lst_t *list); +void *lst_last(struct lst_t *list); +void *lst_next(void *item); +void *lst_remove(struct lst_t *list, void *item); +void *lst_removehead(struct lst_t *list); +int lst_check(struct lst_t *list, void *item); + +#endif /* __LIST_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/pool_api.c b/drivers/media/platform/imagination/vxe-vxd/common/pool_api.c --- a/drivers/media/platform/imagination/vxe-vxd/common/pool_api.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/pool_api.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,710 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Resource pool manager API. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "idgen_api.h" +#include "lst.h" +#include "pool_api.h" +#include "img_errors.h" + +/* + * list can be modified by different instances. So please, + * make sure to acquire mutex lock before initializing the list. + */ +static struct mutex *shared_res_mutex_handle; + +/* + * Max resource ID's. + */ +#define POOL_IDGEN_MAX_ID (0xFFFFFFFF) +/* + * Size of blocks used for ID's. + */ +#define POOL_IDGEN_BLOCK_SIZE (50) + +/* + * Indicates if the pool API has been indialized or not. + * zero if not done. 1 if done. + */ +static int poolinitdone; + +/* list of resource pool */ +static struct lst_t poollist = {0}; + +/** + * struct poollist - Structure contains resource list information. + * @link: to be able to part of single linked list + * @pool_mutex: lock + * @freereslst: list of free resource structure + * @actvreslst: list of active resource structure + * @pfnfree: pool free callback function + * @idgenhandle: ID generator context handl + */ +struct poollist { + void **link; + struct mutex *pool_mutex; /* Mutex lock */ + struct lst_t freereslst; + struct lst_t actvreslst; + pfrecalbkpntr pfnfree; + void *idgenhandle; +}; + +/* + * This structure contains pool resource. + */ +struct poolres { + void **link; /* to be able to part of single linked list */ + /* Resource id */ + unsigned int resid; + /* Pointer to destructor function */ + pdestcallbkptr desfunc; + /* resource param */ + void *resparam; + /* size of resource param in bytes */ + unsigned int resparmsize; + /* pointer to resource pool list */ + struct poollist *respoollst; + /* 1 if this is a clone of the original resource */ + int isclone; + /* pointer to original resource */ + struct poolres *origres; + /* list of cloned resource structures. Only used on the original */ + struct lst_t clonereslst; + /* reference count. Only used on the original resource */ + unsigned int refcnt; + void *cb_handle; +}; + +/* + * This function initializes the list if not done earlier. + */ +int pool_init(void) +{ + /* Check if list already initialized */ + if (!poolinitdone) { + /* + * list can be modified by different instances. So please, + * make sure to acquire mutex lock before initializing the list. + */ + + shared_res_mutex_handle = kzalloc(sizeof(*shared_res_mutex_handle), GFP_KERNEL); + if (!shared_res_mutex_handle) + return -ENOMEM; + + mutex_init(shared_res_mutex_handle); + + /* initialize the list of pools */ + lst_init(&poollist); + /* Get initialized flag to true */ + poolinitdone = 1; + } + + return 0; +} + +/* + * This function de-initializes the list. + */ +void pool_deinit(void) +{ + struct poollist *respoollist; + + /* Check if list initialized */ + if (poolinitdone) { + /* destroy any active pools */ + respoollist = (struct poollist *)lst_first(&poollist); + while (respoollist) { + pool_destroy(respoollist); + respoollist = (struct poollist *)lst_first(&poollist); + } + + /* Destroy mutex */ + mutex_destroy(shared_res_mutex_handle); + kfree(shared_res_mutex_handle); + shared_res_mutex_handle = NULL; + + /* set initialized flag to 0 */ + poolinitdone = 0; + } +} + +/* + * This function creates pool. + */ +int pool_api_create(void **poolhndle) +{ + struct poollist *respoollist; + unsigned int result = 0; + + /* Allocate a pool structure */ + respoollist = kzalloc(sizeof(*respoollist), GFP_KERNEL); + if (!respoollist) + return IMG_ERROR_OUT_OF_MEMORY; + + /* Initialize the pool info */ + lst_init(&respoollist->freereslst); + lst_init(&respoollist->actvreslst); + + /* Create mutex */ + respoollist->pool_mutex = kzalloc(sizeof(*respoollist->pool_mutex), GFP_KERNEL); + if (!respoollist->pool_mutex) { + result = ENOMEM; + goto error_create_context; + } + mutex_init(respoollist->pool_mutex); + + /* Create context for the Id generator */ + result = idgen_createcontext(POOL_IDGEN_MAX_ID, + POOL_IDGEN_BLOCK_SIZE, 0, + &respoollist->idgenhandle); + if (result != IMG_SUCCESS) + goto error_create_context; + + /* Disable interrupts */ + mutex_lock_nested(shared_res_mutex_handle, SUBCLASS_POOL_RES); + + /* Add to list of pools */ + lst_add(&poollist, respoollist); + + /* Enable interrupts */ + mutex_unlock(shared_res_mutex_handle); + + /* Return handle to pool */ + *poolhndle = respoollist; + + return IMG_SUCCESS; + + /* Error handling. */ +error_create_context: + kfree(respoollist); + + return result; +} + +/* + * This function destroys the pool. + */ +int pool_destroy(void *poolhndle) +{ + struct poollist *respoollist = poolhndle; + struct poolres *respool; + struct poolres *clonerespool; + unsigned int result = 0; + + if (!poolinitdone || !respoollist) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error_nolock; + } + + /* Lock the pool */ + mutex_lock_nested(respoollist->pool_mutex, SUBCLASS_POOL); + + /* Disable interrupts */ + /* + * We need to check if we really need to check disable, + * interrupts because before deleting we need to make sure the + * pool lst is not being used other process. As of now getting ipl + * global mutex + */ + mutex_lock_nested(shared_res_mutex_handle, SUBCLASS_POOL_RES); + + /* Remove the pool from the active list */ + lst_remove(&poollist, respoollist); + + /* Enable interrupts */ + mutex_unlock(shared_res_mutex_handle); + + /* Destroy any resources in the free list */ + respool = (struct poolres *)lst_removehead(&respoollist->freereslst); + while (respool) { + respool->desfunc(respool->resparam, respool->cb_handle); + kfree(respool); + respool = (struct poolres *) + lst_removehead(&respoollist->freereslst); + } + + /* Destroy any resources in the active list */ + respool = (struct poolres *)lst_removehead(&respoollist->actvreslst); + while (respool) { + clonerespool = (struct poolres *) + lst_removehead(&respool->clonereslst); + while (clonerespool) { + /* + * If we created a copy of the resources pvParam + * then free it. + * kfree(NULL) is safe and this check is probably not + * required + */ + kfree(clonerespool->resparam); + + kfree(clonerespool); + clonerespool = (struct poolres *) + lst_removehead(&respool->clonereslst); + } + + /* Call the resource destructor */ + respool->desfunc(respool->resparam, respool->cb_handle); + kfree(respool); + respool = (struct poolres *) + lst_removehead(&respoollist->actvreslst); + } + /* Destroy the context for the Id generator */ + if (respoollist->idgenhandle) + result = idgen_destroycontext(respoollist->idgenhandle); + + /* Unlock the pool */ + mutex_unlock(respoollist->pool_mutex); + + /* Destroy mutex */ + mutex_destroy(respoollist->pool_mutex); + kfree(respoollist->pool_mutex); + respoollist->pool_mutex = NULL; + + /* Free the pool structure */ + kfree(respoollist); + + return IMG_SUCCESS; + +error_nolock: + return result; +} + +int pool_setfreecalbck(void *poolhndle, pfrecalbkpntr pfnfree) +{ + struct poollist *respoollist = poolhndle; + struct poolres *respool; + unsigned int result = 0; + + if (!poolinitdone || !respoollist) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error_nolock; + } + + /* Lock the pool */ + mutex_lock_nested(respoollist->pool_mutex, SUBCLASS_POOL); + + respoollist->pfnfree = pfnfree; + + /* If free callback set */ + if (respoollist->pfnfree) { + /* Move resources from free to active list */ + respool = (struct poolres *) + lst_removehead(&respoollist->freereslst); + while (respool) { + /* Add to active list */ + lst_add(&respoollist->actvreslst, respool); + respool->refcnt++; + + /* Unlock the pool */ + mutex_unlock(respoollist->pool_mutex); + + /* Call the free callback */ + respoollist->pfnfree(respool->resid, respool->resparam); + + /* Lock the pool */ + mutex_lock_nested(respoollist->pool_mutex, SUBCLASS_POOL); + + /* Get next free resource */ + respool = (struct poolres *) + lst_removehead(&respoollist->freereslst); + } + } + + /* Unlock the pool */ + mutex_unlock(respoollist->pool_mutex); + + /* Return IMG_SUCCESS */ + return IMG_SUCCESS; + +error_nolock: + return result; +} + +int pool_resreg(void *poolhndle, pdestcallbkptr fndestructor, + void *resparam, unsigned int resparamsize, + int balloc, unsigned int *residptr, + void **poolreshndle, void *cb_handle) +{ + struct poollist *respoollist = poolhndle; + struct poolres *respool; + unsigned int result = 0; + + if (!poolinitdone || !respoollist) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error_nolock; + } + + /* Allocate a resource structure */ + respool = kzalloc(sizeof(*respool), GFP_KERNEL); + if (!respool) + return IMG_ERROR_OUT_OF_MEMORY; + + /* Setup the resource */ + respool->desfunc = fndestructor; + respool->cb_handle = cb_handle; + respool->resparam = resparam; + respool->resparmsize = resparamsize; + respool->respoollst = respoollist; + lst_init(&respool->clonereslst); + + /* Lock the pool */ + mutex_lock_nested(respoollist->pool_mutex, SUBCLASS_POOL); + + /* Set resource id */ + result = idgen_allocid(respoollist->idgenhandle, + (void *)respool, &respool->resid); + if (result != IMG_SUCCESS) { + kfree(respool); + /* Unlock the pool */ + mutex_unlock(respoollist->pool_mutex); + return result; + } + + /* If allocated or free callback not set */ + if (balloc || respoollist->pfnfree) { + /* Add to active list */ + lst_add(&respoollist->actvreslst, respool); + respool->refcnt++; + } else { + /* Add to free list */ + lst_add(&respoollist->freereslst, respool); + } + + /* Return the resource id */ + if (residptr) + *residptr = respool->resid; + + /* Return the handle to the resource */ + if (poolreshndle) + *poolreshndle = respool; + + /* Unlock the pool */ + mutex_unlock(respoollist->pool_mutex); + + /* If free callback set */ + if (respoollist->pfnfree) { + /* Call the free callback */ + respoollist->pfnfree(respool->resid, respool->resparam); + } + + /* Return IMG_SUCCESS */ + return IMG_SUCCESS; + +error_nolock: + return result; +} + +int pool_resdestroy(void *poolreshndle, int bforce) +{ + struct poolres *respool = poolreshndle; + struct poollist *respoollist; + struct poolres *origrespool; + unsigned int result = 0; + + if (!poolinitdone || !respool) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error_nolock; + } + + respoollist = respool->respoollst; + + /* If this is a clone */ + if (respool->isclone) { + /* Get access to the original */ + origrespool = respool->origres; + if (!origrespool) { + result = IMG_ERROR_UNEXPECTED_STATE; + goto error_nolock; + } + + if (origrespool->isclone) { + result = IMG_ERROR_UNEXPECTED_STATE; + goto error_nolock; + } + + /* Remove from the clone list */ + lst_remove(&origrespool->clonereslst, respool); + + /* Free resource id */ + result = idgen_freeid(respoollist->idgenhandle, + respool->resid); + if (result != IMG_SUCCESS) + return result; + + /* + * If we created a copy of the resources pvParam then free it + * kfree(NULL) is safe and this check is probably not required. + */ + kfree(respool->resparam); + + /* Free the clone resource structure */ + kfree(respool); + + /* Set resource to be "freed" to the original */ + respool = origrespool; + } + + /* If there are still outstanding references */ + if (!bforce && respool->refcnt != 0) { + /* + * We may need to mark the resource and destroy it when + * there are no outstanding references + */ + return IMG_SUCCESS; + } + + /* Has the resource outstanding references */ + if (respool->refcnt != 0) { + /* Remove the resource from the active list */ + lst_remove(&respoollist->actvreslst, respool); + } else { + /* Remove the resource from the free list */ + lst_remove(&respoollist->freereslst, respool); + } + + /* Free resource id */ + result = idgen_freeid(respoollist->idgenhandle, + respool->resid); + if (result != IMG_SUCCESS) + return result; + + /* Call the resource destructor */ + respool->desfunc(respool->resparam, respool->cb_handle); + kfree(respool); + + return IMG_SUCCESS; + +error_nolock: + return result; +} + +int pool_resalloc(void *poolhndle, void *poolreshndle) +{ + struct poollist *respoollist = poolhndle; + struct poolres *respool = poolreshndle; + unsigned int result = 0; + + if (!poolinitdone || !respoollist || !poolreshndle) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error_nolock; + } + + /* Lock the pool */ + mutex_lock_nested(respoollist->pool_mutex, SUBCLASS_POOL); + + /* Remove resource from free list */ + lst_remove(&respoollist->freereslst, respool); + + /* Add to active list */ + lst_add(&respoollist->actvreslst, respool); + respool->refcnt++; + + /* Unlock the pool */ + mutex_unlock(respoollist->pool_mutex); + + /* Return IMG_SUCCESS */ + return IMG_SUCCESS; + +error_nolock: + return result; +} + +int pool_resfree(void *poolreshndle) +{ + struct poolres *respool = poolreshndle; + struct poollist *respoollist; + struct poolres *origrespool; + unsigned int result = 0; + + if (!poolinitdone || !respool) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error_nolock; + } + + respoollist = respool->respoollst; + + /* Lock the pool */ + mutex_lock_nested(respoollist->pool_mutex, SUBCLASS_POOL); + + /* If this is a clone */ + if (respool->isclone) { + /* Get access to the original */ + origrespool = respool->origres; + if (!origrespool) { + mutex_unlock(respoollist->pool_mutex); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Remove from the clone list */ + lst_remove(&origrespool->clonereslst, respool); + + /* Free resource id */ + result = idgen_freeid(respoollist->idgenhandle, + respool->resid); + if (result != IMG_SUCCESS) { + /* Unlock the pool */ + mutex_unlock(respoollist->pool_mutex); + return result; + } + + /* + * If we created a copy of the resources pvParam then free it + * kfree(NULL) is safe and this check is probably not required. + */ + kfree(respool->resparam); + + /* Free the clone resource structure */ + kfree(respool); + + /* Set resource to be "freed" to the original */ + respool = origrespool; + } + + /* Update the reference count */ + respool->refcnt--; + + /* If there are still outstanding references */ + if (respool->refcnt != 0) { + /* Unlock the pool */ + mutex_unlock(respoollist->pool_mutex); + /* Return IMG_SUCCESS */ + return IMG_SUCCESS; + } + + /* Remove the resource from the active list */ + lst_remove(&respoollist->actvreslst, respool); + + /* If free callback set */ + if (respoollist->pfnfree) { + /* Add to active list */ + lst_add(&respoollist->actvreslst, respool); + respool->refcnt++; + } else { + /* Add to free list */ + lst_add(&respoollist->freereslst, respool); + } + + /* Unlock the pool */ + mutex_unlock(respoollist->pool_mutex); + + /* If free callback set */ + if (respoollist->pfnfree) { + /* Call the free callback */ + respoollist->pfnfree(respool->resid, respool->resparam); + } + + /* Return IMG_SUCCESS */ + return IMG_SUCCESS; + +error_nolock: + return result; +} + +int pool_resclone(void *poolreshndle, void **clonereshndle, void **resparam) +{ + struct poolres *respool = poolreshndle; + struct poollist *respoollist; + struct poolres *origrespool = respool; + struct poolres *clonerespool; + unsigned int result = 0; + + if (!poolinitdone || !respool) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error_nolock; + } + + /* Allocate a resource structure */ + clonerespool = kzalloc(sizeof(*clonerespool), GFP_KERNEL); + if (!clonerespool) + return IMG_ERROR_OUT_OF_MEMORY; + + respoollist = respool->respoollst; + if (!respoollist) + return IMG_ERROR_FATAL; + + /* Lock the pool */ + mutex_lock_nested(respoollist->pool_mutex, SUBCLASS_POOL); + + /* Set resource id */ + result = idgen_allocid(respoollist->idgenhandle, + (void *)clonerespool, &clonerespool->resid); + if (result != IMG_SUCCESS) + goto error_alloc_id; + + /* If this is a clone, set the original */ + if (respool->isclone) + origrespool = respool->origres; + + /* Setup the cloned resource */ + clonerespool->isclone = 1; + clonerespool->respoollst = respoollist; + clonerespool->origres = origrespool; + + /* Add to clone list */ + lst_add(&origrespool->clonereslst, clonerespool); + origrespool->refcnt++; + + /* If ppvParam is not IMG_NULL */ + if (resparam) { + /* If the size of the original vParam is 0 */ + if (origrespool->resparmsize == 0) { + *resparam = NULL; + } else { + /* Allocate memory for a copy of the original vParam */ + /* + * kmemdup allocates memory of length + * origrespool->resparmsize and to resparam and copy + * origrespool->resparam to resparam of the allocated + * length + */ + *resparam = kmemdup(origrespool->resparam, + origrespool->resparmsize, + GFP_KERNEL); + if (!(*resparam)) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error_copy_param; + } + } + } + + /* Unlock the pool */ + mutex_unlock(respoollist->pool_mutex); + + /* Return the cloned resource */ + *clonereshndle = clonerespool; + + /* Return IMG_SUCCESS */ + return IMG_SUCCESS; + + /* Error handling. */ +error_copy_param: + lst_remove(&origrespool->clonereslst, clonerespool); + origrespool->refcnt--; +error_alloc_id: + kfree(clonerespool); + + /* Unlock the pool */ + mutex_unlock(respoollist->pool_mutex); + +error_nolock: + return result; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/pool_api.h b/drivers/media/platform/imagination/vxe-vxd/common/pool_api.h --- a/drivers/media/platform/imagination/vxe-vxd/common/pool_api.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/pool_api.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Resource pool manager API. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ +#ifndef __POOLAPI_H__ +#define __POOLAPI_H__ + +#include "img_errors.h" +#include "lst.h" + +/* + * This is the prototype for "free" callback functions. This function + * is called when resources are returned to the pools list of free resources. + * NOTE: The "freed" resource is then allocated and passed to the callback + * function. + */ +typedef void (*pfrecalbkpntr)(unsigned int ui32resid, void *resparam); + +/* + * This is the prototype for "destructor" callback functions. This function + * is called when a resource registered with the resource pool manager is to + * be destroyed. + */ +typedef void (*pdestcallbkptr)(void *resparam, void *cb_handle); + +/* + * pool_init - This function is used to initializes the resource pool manager component + * and should be called at start-up. + */ +int pool_init(void); + +/* + * This function is used to deinitialises the resource pool manager component + * and would normally be called at shutdown. + */ +void pool_deinit(void); + +/* + * This function is used to create a resource pool into which resources can be + * placed. + */ +int pool_api_create(void **poolhndle); + +/* + * This function is used to destroy a resource pool. + * NOTE: Destroying a resource pool destroys all of the resources within the + * pool by calling the associated destructor function #POOL_pfnDestructor + * defined when the resource what registered using POOL_ResRegister(). + * + * NOTE: All of the pools resources must be in the pools free list - the + * allocated list must be empty. + */ +int pool_destroy(void *poolhndle); + +/* + * This function is used to set or remove a free callback function on a pool. + * The free callback function gets call for any resources already in the + * pools free list or for any resources that subsequently get freed. + * NOTE: The resource passed to the callback function has been allocated before + * the callback is made. + */ +int pool_setfreecalbck(void *poolhndle, pfrecalbkpntr pfnfree); + +/* + * This function is used to register a resource within a resource pool. The + * resource is added to the pools allocated or free list based on the value + * of bAlloc. + */ +int pool_resreg(void *poolhndle, pdestcallbkptr fndestructor, + void *resparam, unsigned int resparamsize, + int balloc, unsigned int *residptr, + void **poolreshndle, void *cb_handle); + +/* + * This function is used to destroy a resource. + */ +int pool_resdestroy(void *poolreshndle, int bforce); + +/* + * This function is used to get/allocate a resource from a pool. This moves + * the resource from the free to allocated list. + */ +int pool_resalloc(void *poolhndle, void *poolreshndle); + +/* + * This function is used to free a resource and return it to the pools lists of + * free resources. + * NOTE: The resources is only moved to the free list when all references to + * the resource have been freed. + */ +int pool_resfree(void *poolreshndle); + +/* + * This function is used to clone a resource - this creates an additional + * reference to the resource. + * NOTE: The resources is only moved to the free list when all references to + * the resource have been freed. + * NOTE: If this function is used to clone the resource's pvParam data then + * the clone of the data is freed when the clone of the resource is freed. + * The resource destructor is NOT used for this - simply an IMG_FREE. + */ +int pool_resclone(void *poolreshndle, void **clonereshndle, void **resparam); + +#endif /* __POOLAPI_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/pool.c b/drivers/media/platform/imagination/vxe-vxd/common/pool.c --- a/drivers/media/platform/imagination/vxe-vxd/common/pool.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/pool.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Object Pool Memory Allocator + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Sidraya Jayagond + */ + +#include +#include +#include +#include + +#include "img_errors.h" +#include "pool.h" + +#define BUFF_MAX_SIZE 4096 +#define BUFF_MAX_GROW 32 + +/* 64 bits */ +#define ALIGN_SIZE (sizeof(long long) - 1) + +struct pool { + unsigned char *name; + unsigned int size; + unsigned int grow; + struct buffer *buffers; + struct object *objects; +}; + +struct buffer { + struct buffer *next; +}; + +struct object { + struct object *next; +}; + +static inline unsigned char *strdup_cust(const unsigned char *str) +{ + unsigned char *r = kmalloc(strlen(str) + 1, GFP_KERNEL); + + if (r) + strcpy(r, str); + return r; +} + +/* + * pool_create - Create an sObject pool + * @name: Name of sObject pool for diagnostic purposes + * @obj_size: size of each sObject in the pool in bytes + * @pool_hdnl: Will contain NULL or sObject pool handle + * + * This function Create an sObject pool + */ + +int pool_create(const unsigned char * const name, + unsigned int obj_size, + struct pool ** const pool_hdnl) +{ + struct pool *local_pool = NULL; + unsigned int result = IMG_ERROR_FATAL; + + if (!name || !pool_hdnl) { + result = IMG_ERROR_INVALID_PARAMETERS; + return result; + } + + local_pool = kmalloc((sizeof(*local_pool)), GFP_KERNEL); + if (!local_pool) { + result = IMG_ERROR_INVALID_PARAMETERS; + return result; + } + + local_pool->name = strdup_cust((unsigned char *)name); + local_pool->size = obj_size; + local_pool->buffers = NULL; + local_pool->objects = NULL; + local_pool->grow = + (BUFF_MAX_SIZE - sizeof(struct buffer)) / + (obj_size + ALIGN_SIZE); + + if (local_pool->grow == 0) + local_pool->grow = 1; + else if (local_pool->grow > BUFF_MAX_GROW) + local_pool->grow = BUFF_MAX_GROW; + + *pool_hdnl = local_pool; + result = IMG_SUCCESS; + + return result; +} + +/* + * @Function pool_delete + * @Description + * Delete an sObject pool. All psObjects allocated from the pool must + * be free'd with pool_free() before deleting the sObject pool. + * @Input pool : Object Pool pointer + * @Return IMG_SUCCESS or an error code. + */ +int pool_delete(struct pool * const pool_arg) +{ + struct buffer *local_buf = NULL; + unsigned int result = IMG_ERROR_FATAL; + + if (!pool_arg) { + result = IMG_ERROR_INVALID_PARAMETERS; + return result; + } + + local_buf = pool_arg->buffers; + while (local_buf) { + local_buf = local_buf->next; + kfree(pool_arg->buffers); + pool_arg->buffers = local_buf; + } + + kfree(pool_arg->name); + pool_arg->name = NULL; + + kfree(pool_arg); + result = IMG_SUCCESS; + + return result; +} + +/* + * @Function pool_alloc + * @Description + * Allocate an sObject from an sObject pool. + * @Input pool_arg : Object Pool + * @Output obj_hndl : Pointer containing the handle to the + * object created or IMG_NULL + * @Return IMG_SUCCESS or an error code. + */ +int pool_alloc(struct pool * const pool_arg, + void ** const obj_hndl) +{ + struct object *local_obj1 = NULL; + struct buffer *local_buf = NULL; + unsigned int idx = 0; + unsigned int sz = 0; + unsigned int result = IMG_ERROR_FATAL; + + if (!pool_arg || !obj_hndl) { + result = IMG_ERROR_INVALID_PARAMETERS; + return result; + } + + if (!pool_arg->objects) { + sz = (pool_arg->size + ALIGN_SIZE); + sz *= (pool_arg->grow + sizeof(struct buffer)); + local_buf = kmalloc(sz, GFP_KERNEL); + if (!local_buf) { + result = IMG_ERROR_MALLOC_FAILED; + return result; + } + + local_buf->next = pool_arg->buffers; + pool_arg->buffers = local_buf; + + for (idx = 0; idx < pool_arg->grow; idx++) { + struct object *local_obj2; + unsigned char *temp_ptr = NULL; + + local_obj2 = (struct object *)(((unsigned char *)(local_buf + 1)) + + (idx * (pool_arg->size + ALIGN_SIZE))); + + temp_ptr = (unsigned char *)local_obj2; + if ((unsigned long)temp_ptr & ALIGN_SIZE) { + temp_ptr += ((ALIGN_SIZE + 1) + - ((unsigned long)temp_ptr & ALIGN_SIZE)); + local_obj2 = (struct object *)temp_ptr; + } + + local_obj2->next = pool_arg->objects; + pool_arg->objects = local_obj2; + } + } + + if (!pool_arg->objects) { + result = IMG_ERROR_UNEXPECTED_STATE; + return result; + } + + local_obj1 = pool_arg->objects; + pool_arg->objects = local_obj1->next; + + *obj_hndl = (void *)(local_obj1); + result = IMG_SUCCESS; + + return result; +} + +/* + * @Function pool_free + * @Description + * Free an sObject previously allocated from an sObject pool. + * @Input pool_arg : Object Pool pointer. + * @Output h_object : Handle to the object to be freed. + * @Return IMG_SUCCESS or an error code. + */ +int pool_free(struct pool * const pool_arg, + void * const obj_hndl) +{ + struct object *object = NULL; + unsigned int result = IMG_ERROR_FATAL; + + if (!pool_arg || !obj_hndl) { + result = IMG_ERROR_INVALID_PARAMETERS; + return result; + } + + object = (struct object *)obj_hndl; + object->next = pool_arg->objects; + pool_arg->objects = object; + + result = IMG_SUCCESS; + + return result; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/pool.h b/drivers/media/platform/imagination/vxe-vxd/common/pool.h --- a/drivers/media/platform/imagination/vxe-vxd/common/pool.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/pool.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Object Pool Memory Allocator header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Sidraya Jayagond + */ +#ifndef _pool_h_ +#define _pool_h_ + +#include + +struct pool; + +/** + * pool_create - Create an sObject pool + * @name: Name of sObject pool for diagnostic purposes + * @obj_size: size of each sObject in the pool in bytes + * @pool: Will contain NULL or sObject pool handle + * + * Return IMG_SUCCESS or an error code. + */ +int pool_create(const unsigned char * const name, + unsigned int obj_size, + struct pool ** const pool); + +/* + * @Function pool_delete + * @Description + * Delete an sObject pool. All psObjects allocated from the pool must + * be free'd with pool_free() before deleting the sObject pool. + * @Input pool : Object Pool pointer + * @Return IMG_SUCCESS or an error code. + */ +int pool_delete(struct pool * const pool); + +/* + * @Function pool_alloc + * @Description + * Allocate an Object from an Object pool. + * @Input pool : Object Pool + * @Output obj_hdnl : Pointer containing the handle to the + * object created or IMG_NULL + * @Return IMG_SUCCESS or an error code. + */ +int pool_alloc(struct pool * const pool, + void ** const obj_hdnl); + +/* + * @Function pool_free + * @Description + * Free an sObject previously allocated from an sObject pool. + * @Input pool : Object Pool pointer. + * @Output obj_hdnl : Handle to the object to be freed. + * @Return IMG_SUCCESS or an error code. + */ +int pool_free(struct pool * const pool, + void * const obj_hdnl); + +#endif /* _pool_h_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/ra.c b/drivers/media/platform/imagination/vxe-vxd/common/ra.c --- a/drivers/media/platform/imagination/vxe-vxd/common/ra.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/ra.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,972 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Implements generic resource allocation. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Sidraya Jayagond + */ + +#include +#include +#include +#include + +#include "hash.h" +#include "img_errors.h" +#include "pool.h" +#include "ra.h" + +static unsigned char global_init; + +/* pool of struct arena's */ +static struct pool *global_pool_arena; + +/* pool of struct boundary tag */ +static struct pool *global_pool_bt; + +/** + * ra_request_alloc_fail - ra_request_alloc_fail + * @import_hdnl : Callback handle. + * @requested_size : Requested allocation size. + * @ref : Pointer to user reference data. + * @alloc_flags : Allocation flags. + * @actual_size : Pointer to contain the actual allocated size. + * @base_addr : Allocation base(always 0,it is failing). + * + * Default callback allocator used if no callback is specified, always fails + * to allocate further resources to the arena. + */ +static int ra_request_alloc_fail(void *import_hdnl, + unsigned long long requested_size, + unsigned long long *actual_size, + void **ref, + unsigned int alloc_flags, + unsigned long long *base_addr) +{ + if (base_addr) + *base_addr = 0; + + return IMG_SUCCESS; +} + +/* + * @Function ra_log2 + * @Description + * Calculates the Log2(n) with n being a 64-bit value. + * + * @Input value : Input value. + * @Output None + * @Return result : Log2(ui64Value). + */ + +static unsigned int ra_log2(unsigned long long value) +{ + int res = 0; + + value >>= 1; + while (value > 0) { + value >>= 1; + res++; + } + return res; +} + +/* + * @Function ra_segment_list_insert_after + * @Description Insert a boundary tag into an arena segment list after a + * specified boundary tag. + * @Input arena_arg : Pointer to the input arena. + * @Input bt_here_arg : The boundary tag before which psBTToInsert + * will be added . + * @Input bt_to_insert_arg : The boundary tag to insert. + * @Output None + * @Return None + */ +static void ra_segment_list_insert_after(struct arena *arena_arg, + struct btag *bt_here_arg, + struct btag *bt_to_insert_arg) +{ + bt_to_insert_arg->nxt_seg = bt_here_arg->nxt_seg; + bt_to_insert_arg->prv_seg = bt_here_arg; + + if (!bt_here_arg->nxt_seg) + arena_arg->tail_seg = bt_to_insert_arg; + else + bt_here_arg->nxt_seg->prv_seg = bt_to_insert_arg; + + bt_here_arg->nxt_seg = bt_to_insert_arg; +} + +/* + * @Function ra_segment_list_insert + * @Description + * Insert a boundary tag into an arena segment list at the appropriate point. + * @Input arena_arg : Pointer to the input arena. + * @Input bt_to_insert_arg : The boundary tag to insert. + * @Output None + * @Return None + */ +static void ra_segment_list_insert(struct arena *arena_arg, + struct btag *bt_to_insert_arg) +{ + /* insert into the segment chain */ + if (!arena_arg->head_seg) { + arena_arg->head_seg = bt_to_insert_arg; + arena_arg->tail_seg = bt_to_insert_arg; + bt_to_insert_arg->nxt_seg = NULL; + bt_to_insert_arg->prv_seg = NULL; + } else { + struct btag *bt_scan = arena_arg->head_seg; + + while (bt_scan->nxt_seg && + bt_to_insert_arg->base >= + bt_scan->nxt_seg->base) { + bt_scan = bt_scan->nxt_seg; + } + ra_segment_list_insert_after(arena_arg, + bt_scan, + bt_to_insert_arg); + } +} + +/* + * @Function ra_SegmentListRemove + * @Description + * Insert a boundary tag into an arena segment list at the appropriate point. + * @Input arena_arg : Pointer to the input arena. + * @Input bt_to_remove_arg : The boundary tag to insert. + * @Output None + * @Return None + */ +static void ra_segment_list_remove(struct arena *arena_arg, + struct btag *bt_to_remove_arg) +{ + if (!bt_to_remove_arg->prv_seg) + arena_arg->head_seg = bt_to_remove_arg->nxt_seg; + else + bt_to_remove_arg->prv_seg->nxt_seg = bt_to_remove_arg->nxt_seg; + + if (!bt_to_remove_arg->nxt_seg) + arena_arg->tail_seg = bt_to_remove_arg->prv_seg; + else + bt_to_remove_arg->nxt_seg->prv_seg = bt_to_remove_arg->prv_seg; +} + +/* + * @Function ra_segment_split + * @Description + * Split a segment into two, maintain the arena segment list. + * The boundary tag should not be in the free table. Neither the original or + * the new psBTNeighbour bounary tag will be in the free table. + * @Input arena_arg : Pointer to the input arena. + * @Input bt_to_split_arg : The boundary tag to split. + * The required segment size of boundary tag after the split. + * @Output None + * @Return btag *: New boundary tag. + */ +static struct btag *ra_segment_split(struct arena *arena_arg, + struct btag *bt_to_split_arg, + unsigned long long size) +{ + struct btag *local_bt_neighbour = NULL; + int res = IMG_ERROR_FATAL; + + res = pool_alloc(global_pool_bt, ((void **)&local_bt_neighbour)); + if (res != IMG_SUCCESS) + return NULL; + + local_bt_neighbour->prv_seg = bt_to_split_arg; + local_bt_neighbour->nxt_seg = bt_to_split_arg->nxt_seg; + local_bt_neighbour->bt_type = RA_BOUNDARY_TAG_TYPE_FREE; + local_bt_neighbour->size = (bt_to_split_arg->size - size); + local_bt_neighbour->base = (bt_to_split_arg->base + size); + local_bt_neighbour->nxt_free = NULL; + local_bt_neighbour->prv_free = NULL; + local_bt_neighbour->ref = bt_to_split_arg->ref; + + if (!bt_to_split_arg->nxt_seg) + arena_arg->tail_seg = local_bt_neighbour; + else + bt_to_split_arg->nxt_seg->prv_seg = local_bt_neighbour; + + bt_to_split_arg->nxt_seg = local_bt_neighbour; + bt_to_split_arg->size = size; + + return local_bt_neighbour; +} + +/* + * @Function ra_free_list_insert + * @Description + * Insert a boundary tag into an arena free table. + * @Input arena_arg : Pointer to the input arena. + * @Input bt_arg : The boundary tag to insert into an arena + * free table. + * @Output None + * @Return None + */ +static void ra_free_list_insert(struct arena *arena_arg, + struct btag *bt_arg) +{ + unsigned int index = ra_log2(bt_arg->size); + + bt_arg->bt_type = RA_BOUNDARY_TAG_TYPE_FREE; + if (index < FREE_TABLE_LIMIT) + bt_arg->nxt_free = arena_arg->head_free[index]; + else + bt_arg->nxt_free = NULL; + + bt_arg->prv_free = NULL; + + if (index < FREE_TABLE_LIMIT) { + if (arena_arg->head_free[index]) + arena_arg->head_free[index]->prv_free = bt_arg; + } + + if (index < FREE_TABLE_LIMIT) + arena_arg->head_free[index] = bt_arg; +} + +/* + * @Function ra_free_list_remove + * @Description + * Remove a boundary tag from an arena free table. + * @Input arena_arg : Pointer to the input arena. + * @Input bt_arg : The boundary tag to remove from + * an arena free table. + * @Output None + * @Return None + */ +static void ra_free_list_remove(struct arena *arena_arg, + struct btag *bt_arg) +{ + unsigned int index = ra_log2(bt_arg->size); + + if (bt_arg->nxt_free) + bt_arg->nxt_free->prv_free = bt_arg->prv_free; + + if (!bt_arg->prv_free && index < FREE_TABLE_LIMIT) + arena_arg->head_free[index] = bt_arg->nxt_free; + else if (bt_arg->prv_free) + bt_arg->prv_free->nxt_free = bt_arg->nxt_free; +} + +/* + * @Function ra_build_span_marker + * @Description + * Construct a span marker boundary tag. + * @Input base : The base of the boundary tag. + * @Output None + * @Return btag * : New span marker boundary tag + */ +static struct btag *ra_build_span_marker(unsigned long long base) +{ + struct btag *local_bt = NULL; + int res = IMG_ERROR_FATAL; + + res = pool_alloc(global_pool_bt, ((void **)&local_bt)); + if (res != IMG_SUCCESS) + return NULL; + + local_bt->bt_type = RA_BOUNDARY_TAG_TYPE_SPAN; + local_bt->base = base; + local_bt->size = 0; + local_bt->nxt_seg = NULL; + local_bt->prv_seg = NULL; + local_bt->nxt_free = NULL; + local_bt->prv_free = NULL; + local_bt->ref = NULL; + + return local_bt; +} + +/* + * @Function ra_build_bt + * @Description + * Construct a boundary tag for a free segment. + * @Input ui64Base : The base of the resource segment. + * @Input ui64Size : The extent of the resource segment. + * @Output None + * @Return btag * : New boundary tag + */ +static struct btag *ra_build_bt(unsigned long long base, unsigned long long size) +{ + struct btag *local_bt = NULL; + int res = IMG_ERROR_FATAL; + + res = pool_alloc(global_pool_bt, ((void **)&local_bt)); + + if (res != IMG_SUCCESS) + return local_bt; + + local_bt->bt_type = RA_BOUNDARY_TAG_TYPE_FREE; + local_bt->base = base; + local_bt->size = size; + local_bt->nxt_seg = NULL; + local_bt->prv_seg = NULL; + local_bt->nxt_free = NULL; + local_bt->prv_free = NULL; + local_bt->ref = NULL; + + return local_bt; +} + +/* + * @Function ra_insert_resource + * @Description + * Add a free resource segment to an arena. + * @Input base : The base of the resource segment. + * @Input size : The size of the resource segment. + * @Output None + * @Return IMG_SUCCESS or an error code. + */ +static int ra_insert_resource(struct arena *arena_arg, + unsigned long long base, + unsigned long long size) +{ + struct btag *local_bt = NULL; + + local_bt = ra_build_bt(base, size); + if (!local_bt) + return IMG_ERROR_UNEXPECTED_STATE; + + ra_segment_list_insert(arena_arg, local_bt); + ra_free_list_insert(arena_arg, local_bt); + arena_arg->max_idx = ra_log2(size); + if (1ULL << arena_arg->max_idx < size) + arena_arg->max_idx++; + + return IMG_SUCCESS; +} + +/* + * @Function ra_insert_resource_span + * @Description + * Add a free resource span to an arena, complete with span markers. + * @Input arena_arg : Pointer to the input arena. + * @Input base : The base of the resource segment. + * @Input size : The size of the resource segment. + * @Output None + * @Return btag * : The boundary tag representing + * the free resource segment. + */ +static struct btag *ra_insert_resource_span(struct arena *arena_arg, + unsigned long long base, + unsigned long long size) +{ + struct btag *local_bt = NULL; + struct btag *local_bt_span_start = NULL; + struct btag *local_bt_span_end = NULL; + + local_bt_span_start = ra_build_span_marker(base); + if (!local_bt_span_start) + return NULL; + + local_bt_span_end = ra_build_span_marker(base + size); + if (!local_bt_span_end) { + pool_free(global_pool_bt, local_bt_span_start); + return NULL; + } + + local_bt = ra_build_bt(base, size); + if (!local_bt) { + pool_free(global_pool_bt, local_bt_span_end); + pool_free(global_pool_bt, local_bt_span_start); + return NULL; + } + + ra_segment_list_insert(arena_arg, local_bt_span_start); + ra_segment_list_insert_after(arena_arg, + local_bt_span_start, + local_bt); + ra_free_list_insert(arena_arg, local_bt); + ra_segment_list_insert_after(arena_arg, + local_bt, + local_bt_span_end); + + return local_bt; +} + +/* + * @Function ra_free_bt + * @Description + * Free a boundary tag taking care of the segment list and the + * boundary tag free table. + * @Input arena_arg : Pointer to the input arena. + * @Input bt_arg : The boundary tag to free. + * @Output None + * @Return None + */ +static void ra_free_bt(struct arena *arena_arg, + struct btag *bt_arg) +{ + struct btag *bt_neibr; + + /* try and coalesce with left bt_neibr */ + bt_neibr = bt_arg->prv_seg; + if (bt_neibr && + bt_neibr->bt_type == RA_BOUNDARY_TAG_TYPE_FREE && + bt_neibr->base + bt_neibr->size == bt_arg->base) { + ra_free_list_remove(arena_arg, bt_neibr); + ra_segment_list_remove(arena_arg, bt_neibr); + bt_arg->base = bt_neibr->base; + bt_arg->size += bt_neibr->size; + pool_free(global_pool_bt, bt_neibr); + } + + /* try to coalesce with right psBTNeighbour */ + bt_neibr = bt_arg->nxt_seg; + if (bt_neibr && + bt_neibr->bt_type == RA_BOUNDARY_TAG_TYPE_FREE && + bt_arg->base + bt_arg->size == bt_neibr->base) { + ra_free_list_remove(arena_arg, bt_neibr); + ra_segment_list_remove(arena_arg, bt_neibr); + bt_arg->size += bt_neibr->size; + pool_free(global_pool_bt, bt_neibr); + } + + if (bt_arg->nxt_seg && + bt_arg->nxt_seg->bt_type == RA_BOUNDARY_TAG_TYPE_SPAN && + bt_arg->prv_seg && bt_arg->prv_seg->bt_type == + RA_BOUNDARY_TAG_TYPE_SPAN) { + struct btag *ps_bt_nxt = bt_arg->nxt_seg; + struct btag *ps_bt_prev = bt_arg->prv_seg; + + ra_segment_list_remove(arena_arg, ps_bt_nxt); + ra_segment_list_remove(arena_arg, ps_bt_prev); + ra_segment_list_remove(arena_arg, bt_arg); + arena_arg->import_free_fxn(arena_arg->import_hdnl, + bt_arg->base, + bt_arg->ref); + pool_free(global_pool_bt, ps_bt_nxt); + pool_free(global_pool_bt, ps_bt_prev); + pool_free(global_pool_bt, bt_arg); + } else { + ra_free_list_insert(arena_arg, bt_arg); + } +} + +static int ra_check_btag(struct arena *arena_arg, + unsigned long long size_arg, + void **ref, + struct btag *bt_arg, + unsigned long long align_arg, + unsigned long long *base_arg, + unsigned int align_log2) +{ + unsigned long long local_align_base; + int res = IMG_ERROR_FATAL; + + while (bt_arg) { + if (align_arg > 1ULL) + local_align_base = ((bt_arg->base + align_arg - 1) + >> align_log2) << align_log2; + else + local_align_base = bt_arg->base; + + if ((bt_arg->base + bt_arg->size) >= + (local_align_base + size_arg)) { + ra_free_list_remove(arena_arg, bt_arg); + + /* + * with align_arg we might need to discard the front of + * this segment + */ + if (local_align_base > bt_arg->base) { + struct btag *btneighbor; + + btneighbor = ra_segment_split(arena_arg, + bt_arg, + (local_align_base - + bt_arg->base)); + /* + * Partition the buffer, create a new boundary + * tag + */ + if (!btneighbor) + return IMG_ERROR_UNEXPECTED_STATE; + + ra_free_list_insert(arena_arg, bt_arg); + bt_arg = btneighbor; + } + + /* + * The segment might be too big, if so, discard the back + * of the segment + */ + if (bt_arg->size > size_arg) { + struct btag *btneighbor; + + btneighbor = ra_segment_split(arena_arg, + bt_arg, + size_arg); + /* + * Partition the buffer, create a new boundary + * tag + */ + if (!btneighbor) + return IMG_ERROR_UNEXPECTED_STATE; + + ra_free_list_insert(arena_arg, btneighbor); + } + + bt_arg->bt_type = RA_BOUNDARY_TAG_TYPE_LIVE; + + res = vid_hash_insert(arena_arg->hash_tbl, + bt_arg->base, + (unsigned long)bt_arg); + if (res != IMG_SUCCESS) { + ra_free_bt(arena_arg, bt_arg); + *base_arg = 0; + return IMG_ERROR_UNEXPECTED_STATE; + } + + if (ref) + *ref = bt_arg->ref; + + *base_arg = bt_arg->base; + return IMG_SUCCESS; + } + bt_arg = bt_arg->nxt_free; + } + + return res; +} + +/* + * @Function ra_attempt_alloc_aligned + * @Description Attempt to allocate from an arena + * @Input arena_arg: Pointer to the input arena + * @Input size_arg: The requested allocation size + * @Input ref: The user references associated with the allocated + * segment + * @Input align_arg: Required alignment + * @Output base_arg: Allocated resource size + * @Return IMG_SUCCESS or an error code + */ +static int ra_attempt_alloc_aligned(struct arena *arena_arg, + unsigned long long size_arg, + void **ref, + unsigned long long align_arg, + unsigned long long *base_arg) +{ + unsigned int index; + unsigned int align_log2; + int res = IMG_ERROR_FATAL; + + if (!arena_arg || !base_arg) + return IMG_ERROR_INVALID_PARAMETERS; + + /* + * Take the log of the alignment to get number of bits to shift + * left/right for multiply/divide. Assumption made here is that + * alignment has to be a power of 2 value. Aserting otherwise. + */ + align_log2 = ra_log2(align_arg); + + /* + * Search for a near fit free boundary tag, start looking at the + * log2 free table for our required size and work on up the table. + */ + index = ra_log2(size_arg); + + /* + * If the Size required is exactly 2**n then use the n bucket, because + * we know that every free block in that bucket is larger than 2**n, + * otherwise start at then next bucket up. + */ + if (size_arg > (1ull << index)) + index++; + + while ((index < FREE_TABLE_LIMIT) && !arena_arg->head_free[index]) + index++; + + if (index >= FREE_TABLE_LIMIT) { + pr_err("requested allocation size doesn't fit in the arena. Increase MMU HEAP Size\n"); + return IMG_ERROR_OUT_OF_MEMORY; + } + + while (index < FREE_TABLE_LIMIT) { + if (arena_arg->head_free[index]) { + /* we have a cached free boundary tag */ + struct btag *local_bt = + arena_arg->head_free[index]; + + res = ra_check_btag(arena_arg, + size_arg, + ref, + local_bt, + align_arg, + base_arg, + align_log2); + if (res != IMG_SUCCESS) + return res; + } + index++; + } + + return IMG_SUCCESS; +} + +/* + * @Function vid_ra_init + * @Description Initializes the RA module. Must be called before any other + * ra API function + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_initialise(void) +{ + int res = IMG_ERROR_FATAL; + + if (!global_init) { + res = pool_create("img-arena", + sizeof(struct arena), + &global_pool_arena); + if (res != IMG_SUCCESS) + return IMG_ERROR_UNEXPECTED_STATE; + + res = pool_create("img-bt", + sizeof(struct btag), + &global_pool_bt); + if (res != IMG_SUCCESS) { + res = pool_delete(global_pool_arena); + global_pool_arena = NULL; + return IMG_ERROR_UNEXPECTED_STATE; + } + global_init = 1; + res = IMG_SUCCESS; + } + + return res; +} + +/* + * @Function vid_ra_deinit + * @Description Deinitializes the RA module + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_deinit(void) +{ + int res = IMG_ERROR_FATAL; + + if (global_init) { + if (global_pool_arena) { + res = pool_delete(global_pool_arena); + global_pool_arena = NULL; + } + if (global_pool_bt) { + res = pool_delete(global_pool_bt); + global_pool_bt = NULL; + } + global_init = 0; + res = IMG_SUCCESS; + } + return res; +} + +/* + * @Function vid_ra_create + * @Description Used to create a resource arena. + * @Input name: The name of the arena for diagnostic purposes + * @Input base_arg: The base of an initial resource span or 0 + * @Input size_arg: The size of an initial resource span or 0 + * @Input quantum: The arena allocation quantum + * @Input (*import_alloc_fxn): A resource allocation callback or NULL + * @Input (*import_free_fxn): A resource de-allocation callback or NULL + * @Input import_hdnl: Handle passed to alloc and free or NULL + * @Output arena_hndl: The handle for the arene being created, or NULL + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_create(const unsigned char * const name, + unsigned long long base_arg, + unsigned long long size_arg, + unsigned long quantum, + int (*import_alloc_fxn)(void * const import_hdnl, + unsigned long long req_sz, + unsigned long long * const actl_sz, + void ** const ref, + unsigned int alloc_flags, + unsigned long long * const base_arg), + int (*import_free_fxn)(void * const import_hdnl, + unsigned long long import_base, + void * const import_ref), + void *import_hdnl, + void **arena_hndl) +{ + struct arena *local_arena = NULL; + unsigned int idx = 0; + int res = IMG_ERROR_FATAL; + + if (!arena_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + *(arena_hndl) = NULL; + + if (global_init) { + res = pool_alloc(global_pool_arena, ((void **)&local_arena)); + if (!local_arena || res != IMG_SUCCESS) + return IMG_ERROR_UNEXPECTED_STATE; + + local_arena->name = NULL; + if (name) + local_arena->name = kstrdup((const signed char *)name, + GFP_KERNEL); + if (import_alloc_fxn) + local_arena->import_alloc_fxn = import_alloc_fxn; + else + local_arena->import_alloc_fxn = ra_request_alloc_fail; + + local_arena->import_free_fxn = import_free_fxn; + local_arena->import_hdnl = import_hdnl; + + for (idx = 0; idx < FREE_TABLE_LIMIT; idx++) + local_arena->head_free[idx] = NULL; + + local_arena->head_seg = NULL; + local_arena->tail_seg = NULL; + local_arena->quantum = quantum; + + res = vid_hash_create(MINIMUM_HASH_SIZE, + &local_arena->hash_tbl); + + if (!local_arena->hash_tbl) { + vid_hash_delete(local_arena->hash_tbl); + kfree(local_arena->name); + local_arena->name = NULL; + return IMG_ERROR_UNEXPECTED_STATE; + } + + //if (size_arg > (unsigned long long)0) { + if (size_arg > 0ULL) { + size_arg = (size_arg + quantum - 1) / quantum * quantum; + + res = ra_insert_resource(local_arena, + base_arg, + size_arg); + if (res != IMG_SUCCESS) { + vid_hash_delete(local_arena->hash_tbl); + pool_free(global_pool_arena, local_arena); + kfree(local_arena->name); + local_arena->name = NULL; + return IMG_ERROR_UNEXPECTED_STATE; + } + } + *(arena_hndl) = local_arena; + res = IMG_SUCCESS; + } + + return res; +} + +/* + * @Function vid_ra_delete + * @Description Used to delete a resource arena. All resources allocated from + * the arena must be freed before deleting the arena + * @Input arena_hndl: The handle to the arena to delete + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_delete(void * const arena_hndl) +{ + int res = IMG_ERROR_FATAL; + struct arena *local_arena = NULL; + unsigned int idx; + + if (!arena_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + if (global_init) { + local_arena = (struct arena *)arena_hndl; + kfree(local_arena->name); + local_arena->name = NULL; + for (idx = 0; idx < FREE_TABLE_LIMIT; idx++) + local_arena->head_free[idx] = NULL; + + while (local_arena->head_seg) { + struct btag *local_bt = local_arena->head_seg; + + ra_segment_list_remove(local_arena, local_bt); + } + res = vid_hash_delete(local_arena->hash_tbl); + if (res != IMG_SUCCESS) + return IMG_ERROR_UNEXPECTED_STATE; + + res = pool_free(global_pool_arena, local_arena); + if (res != IMG_SUCCESS) + return IMG_ERROR_UNEXPECTED_STATE; + } + + return res; +} + +/* + * @Function vid_ra_add + * @Description Used to add a resource span to an arena. The span must not + * overlap with any span previously added to the arena + * @Input base_arg: The base_arg of the span + * @Input size_arg: The size of the span + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_add(void * const arena_hndl, unsigned long long base_arg, unsigned long long size_arg) +{ + int res = IMG_ERROR_FATAL; + struct arena *local_arena = NULL; + + if (!arena_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + if (global_init) { + local_arena = (struct arena *)arena_hndl; + size_arg = (size_arg + local_arena->quantum - 1) / + local_arena->quantum * local_arena->quantum; + + res = ra_insert_resource(local_arena, base_arg, size_arg); + if (res != IMG_SUCCESS) + return IMG_ERROR_INVALID_PARAMETERS; + } + + return res; +} + +/* + * @Function vid_ra_alloc + * @Description Used to allocate resource from an arena + * @Input arena_hndl: The handle to the arena to create the resource + * @Input request_size: The requested size of resource segment + * @Input actl_size: The actualSize of resource segment + * @Input ref: The user reference associated with allocated resource + * span + * @Input alloc_flags: AllocationFlags influencing allocation policy + * @Input align_arg: The alignment constraint required for the allocated + * segment + * @Output base_args: The base of the allocated resource + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_alloc(void * const arena_hndl, + unsigned long long request_size, + unsigned long long * const actl_sz, + void ** const ref, + unsigned int alloc_flags, + unsigned long long alignarg, + unsigned long long * const basearg) +{ + int res = IMG_ERROR_FATAL; + struct arena *arn_ctx = NULL; + unsigned long long loc_size = request_size; + + if (!arena_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + if (global_init) { + arn_ctx = (struct arena *)arena_hndl; + loc_size = ((loc_size + arn_ctx->quantum - 1) / + arn_ctx->quantum) * arn_ctx->quantum; + + if (actl_sz) + *actl_sz = loc_size; + + /* + * If allocation failed then we might have an import source + * which can provide more resource, else we will have to fail + * the allocation to the caller. + */ + if (alloc_flags == RA_SEQUENTIAL_ALLOCATION) + res = ra_attempt_alloc_aligned(arn_ctx, + loc_size, + ref, + alignarg, + basearg); + + if (res != IMG_SUCCESS) { + void *import_ref = NULL; + unsigned long long import_base = 0ULL; + unsigned long long locimprt_reqsz = loc_size; + unsigned long long locimprt_actsz = 0ULL; + + res = arn_ctx->import_alloc_fxn(arn_ctx->import_hdnl, + locimprt_reqsz, + &locimprt_actsz, + &import_ref, + alloc_flags, + &import_base); + + if (res == IMG_SUCCESS) { + struct btag *local_bt = + ra_insert_resource_span(arn_ctx, + import_base, + locimprt_actsz); + + /* + * Successfully import more resource, create a + * span to represent it and retry the allocation + * attempt + */ + if (!local_bt) { + /* + * Insufficient resources to insert the + * newly acquired span, so free it back + */ + arn_ctx->import_free_fxn(arn_ctx->import_hdnl, + import_base, + import_ref); + return IMG_ERROR_UNEXPECTED_STATE; + } + local_bt->ref = import_ref; + if (alloc_flags == RA_SEQUENTIAL_ALLOCATION) { + res = ra_attempt_alloc_aligned(arn_ctx, + loc_size, + ref, + alignarg, + basearg); + } + } + } + } + + return res; +} + +/* + * @Function vid_ra_free + * @Description Used to free a resource segment + * @Input arena_hndl: The arena the segment was originally allocated from + * @Input base_arg: The base of the span + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_free(void * const arena_hndl, unsigned long long base_arg) +{ + int res = IMG_ERROR_FATAL; + struct arena *local_arena = NULL; + struct btag *local_bt = NULL; + unsigned long uip_res; + + if (!arena_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + if (global_init) { + local_arena = (struct arena *)arena_hndl; + + res = vid_hash_remove(local_arena->hash_tbl, + base_arg, + &uip_res); + if (res != IMG_SUCCESS) + return res; + local_bt = (struct btag *)uip_res; + + ra_free_bt(local_arena, local_bt); + } + + return res; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/ra.h b/drivers/media/platform/imagination/vxe-vxd/common/ra.h --- a/drivers/media/platform/imagination/vxe-vxd/common/ra.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/ra.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,200 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Implements generic resource allocation. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Sidraya Jayagond + */ +#ifndef _RA_H_ +#define _RA_H_ + +#define MINIMUM_HASH_SIZE (64) +#define FREE_TABLE_LIMIT (64) + +/* Defines whether sequential or random allocation is used */ +enum { + RA_SEQUENTIAL_ALLOCATION = 0, + RA_RANDOM_ALLOCATION, + RA_FORCE32BITS = 0x7FFFFFFFU +}; + +/* Defines boundary tag type */ +enum eboundary_tag_type { + RA_BOUNDARY_TAG_TYPE_SPAN = 0, + RA_BOUNDARY_TAG_TYPE_FREE, + RA_BOUNDARY_TAG_TYPE_LIVE, + RA_BOUNDARY_TAG_TYPE_MAX, + RA_BOUNDARY_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * @Description + * Boundary tags, used to describe a resource segment + * + * @enum0: span markers + * @enum1: free resource segment + * @enum2: allocated resource segment + * @enum3: max + * @base,size: The base resource of this segment and extent of this segment + * @nxt_seg, prv_seg: doubly linked ordered list of all segments + * within the arena + * @nxt_free, prv_free: doubly linked un-ordered list of free segments + * @reference : a user reference associated with this span, user + * references are currently only provided in + * the callback mechanism + */ +struct btag { + unsigned int bt_type; + unsigned long long base; + unsigned long long size; + struct btag *nxt_seg; + struct btag *prv_seg; + struct btag *nxt_free; + struct btag *prv_free; + void *ref; +}; + +/* + * @Description + * resource allocation arena + * + * @name: arena for diagnostics output + * @quantum: allocations within this arena are quantum sized + * @max_idx: index of the last position in the psBTHeadFree table, + * with available free space + * @import_alloc_fxn: import interface, if provided + * @import_free_fxn: import interface, if provided + * @import_hdnl: import interface, if provided + * @head_free: head of list of free boundary tags for indexed by Log2 + * of the boundary tag size. Power-of-two table of free lists + * @head_seg, tail_seg : resource ordered segment list + * @ps_hash : segment address to boundary tag hash table + */ +struct arena { + unsigned char *name; + unsigned long quantum; + unsigned int max_idx; + int (*import_alloc_fxn)(void *import_hdnl, + unsigned long long requested_size, + unsigned long long *actual_size, + void **ref, + unsigned int alloc_flags, + unsigned long long *base_addr); + int (*import_free_fxn)(void *import_hdnl, + unsigned long long base, + void *ref); + void *import_hdnl; + struct btag *head_free[FREE_TABLE_LIMIT]; + struct btag *head_seg; + struct btag *tail_seg; + struct hash *hash_tbl; +}; + +/* + * @Function vid_ra_init + * @Description Initializes the RA module. Must be called before any other + * ra API function + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_initialise(void); + +/* + * @Function vid_ra_deinit + * @Description Deinitializes the RA module + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_deinit(void); + +/* + * @Function vid_ra_create + * @Description Used to create a resource arena. + * @Input name: The name of the arena for diagnostic purposes + * @Input base_arg: The base of an initial resource span or 0 + * @Input size_arg: The size of an initial resource span or 0 + * @Input quantum: The arena allocation quantum + * @Input (*import_alloc_fxn): A resource allocation callback or NULL + * @Input (*import_free_fxn): A resource de-allocation callback or NULL + * @Input import_hdnl: Handle passed to alloc and free or NULL + * @Output arena_hndl: The handle for the arene being created, or NULL + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_create(const unsigned char * const name, + unsigned long long base_arg, + unsigned long long size_arg, + unsigned long quantum, + int (*import_alloc_fxn)(void * const import_hdnl, + unsigned long long req_sz, + unsigned long long * const actl_sz, + void ** const ref, + unsigned int alloc_flags, + unsigned long long * const base_arg), + int (*import_free_fxn)(void * const import_hdnl, + unsigned long long import_base, + void * const import_ref), + void *import_hdnl, + void **arena_hndl); + +/* + * @Function vid_ra_delete + * @Description Used to delete a resource arena. All resources allocated from + * the arena must be freed before deleting the arena + * @Input arena_hndl: The handle to the arena to delete + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_delete(void * const arena_hndl); + +/* + * @Function vid_ra_add + * @Description Used to add a resource span to an arena. The span must not + * overlap with any span previously added to the arena + * @Input base_arg: The base_arg of the span + * @Input size_arg: The size of the span + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_add(void * const arena_hndl, unsigned long long base_arg, unsigned long long size_arg); + +/* + * @Function vid_ra_alloc + * @Description Used to allocate resource from an arena + * @Input arena_hndl: The handle to the arena to create the resource + * @Input request_size: The requested size of resource segment + * @Input actl_size: The actualSize of resource segment + * @Input ref: The user reference associated with allocated resource + * span + * @Input alloc_flags: AllocationFlags influencing allocation policy + * @Input align_arg: The alignment constraint required for the allocated + * segment + * @Output base_args: The base of the allocated resource + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_alloc(void * const arena_hndl, + unsigned long long request_size, + unsigned long long * const actl_sz, + void ** const ref, + unsigned int alloc_flags, + unsigned long long align_arg, + unsigned long long * const base_arg); + +/* + * @Function vid_ra_free + * @Description Used to free a resource segment + * @Input arena_hndl: The arena the segment was originally allocated from + * @Input base_arg: The base of the span + * @Return IMG_SUCCESS or an error code + * + */ +int vid_ra_free(void * const arena_hndl, unsigned long long base_arg); + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/resource.c b/drivers/media/platform/imagination/vxe-vxd/common/resource.c --- a/drivers/media/platform/imagination/vxe-vxd/common/resource.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/resource.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,578 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VXD DEC Resource manager implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#include +#include +#include +#include +#include + +#include "dq.h" +#include "img_errors.h" +#include "lst.h" +#include "resource.h" + +struct resource_list_elem { + struct dq_linkage_t link; + void *item; + unsigned int id; + unsigned int *refcnt; +}; + +/* + * marks an item as used by incrementing the reference count + */ +int resource_item_use(unsigned int *refcnt) +{ + if (refcnt) + (*refcnt)++; + + return 0; +} + +/* + * returns an item by decrementing the reference count + */ +void resource_item_return(unsigned int *refcnt) +{ + if (refcnt && *refcnt > 0) + (*refcnt)--; +} + +/* + * releases an item by setting reference count to 1 (original owner) + */ +int resource_item_release(unsigned int *refcnt) +{ + if (refcnt) + *refcnt = 1; + + return 0; +} + +/* + * indicates whether an item is free to be used (no owners) + */ +int resource_item_isavailable(unsigned int *refcnt) +{ + if (refcnt) + return (*refcnt == 0) ? 1 : 0; + else + return 0; +} + +/* + * adds an item (and associated id) to a resource list + */ +int resource_list_add_img(struct lst_t *list, void *item, unsigned int id, unsigned int *refcnt) +{ + struct resource_list_elem *listelem = NULL; + int bfound = 0; + unsigned int result = 0; + + if (!list || !item) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + + /* + * Decrement the reference count on the item + * to signal that the owner has relinquished it. + */ + resource_item_return(refcnt); + + /* + * Determine whether this buffer is already in the list. + */ + listelem = lst_first(list); + while (listelem) { + if (listelem->item == item) { + bfound = 1; + break; + } + + listelem = lst_next(listelem); + } + + if (!bfound) { + /* + * allocate the image buffer list element structure. + */ + listelem = kmalloc(sizeof(*(listelem)), GFP_KERNEL); + if (!listelem) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + memset(listelem, 0, sizeof(*(listelem))); + + /* + * setup the list element. + */ + listelem->item = item; + listelem->id = id; + listelem->refcnt = refcnt; + + /* + * add the element to the list. + */ + lst_add(list, (void *)listelem); + } + + return 0; + +error: + return result; +} + +/* + * obtains pointer to item at head of resource list + */ +void *resource_list_pickhead(struct lst_t *list) +{ + struct resource_list_elem *listelem = NULL; + void *item = NULL; + + if (!list) + goto error; + /* + * peek the head item of the list. + */ + listelem = lst_first(list); + if (listelem) + item = listelem->item; + +error: + return item; +} + +/* + * removes item from resource list + */ +int resource_list_remove(struct lst_t *list, void *item) +{ + struct resource_list_elem *listelem = NULL; + unsigned int result = 0; + + if (!list || !item) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + + /* + * find the specified item in the list. + */ + listelem = lst_first(list); + while (listelem) { + if (listelem->item == item) { + if (*listelem->refcnt != 0) + pr_warn("item remove from list still in use\n"); + + /* + * Remove the item from the list. + */ + lst_remove(list, listelem); + /* + * Free the stream unit queue element. + */ + kfree(listelem); + listelem = NULL; + return 0; + } + + listelem = lst_next(listelem); + } + +#if defined(DEBUG_DECODER_DRIVER) || defined(DEBUG_ENCODER_DRIVER) + pr_info("item could not be located to remove from RESOURCE list\n"); +#endif + + return IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + +error: + return result; +} + +/* + * resource_list_removehead - removes item at head of resource list + * @list: head of resource list + */ +void *resource_list_removehead(struct lst_t *list) +{ + struct resource_list_elem *listelem = NULL; + void *item = NULL; + + if (!list) + goto error; + + /* + * peek the head item of the list. + */ + listelem = lst_removehead(list); + if (listelem) { + item = listelem->item; + kfree(listelem); + listelem = NULL; + } + +error: + return item; +} + +/* + * removes next available item from resource list. + * item is freed if no longer used + */ +int resource_list_remove_nextavail(struct lst_t *list, + resource_pfn_freeitem fn_freeitem, + void *free_cb_param) +{ + struct resource_list_elem *listelem = NULL; + unsigned int result = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + + if (!list) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + + /* + * find the next unused item in the list. + */ + listelem = lst_first(list); + while (listelem) { + if (resource_item_isavailable(listelem->refcnt)) { + resource_item_return(listelem->refcnt); + + if (*listelem->refcnt == 0) { + if (fn_freeitem) + fn_freeitem(listelem->item, free_cb_param); + else + kfree(listelem->item); + + listelem->item = NULL; + } + + /* + * get the next element from the list. + */ + lst_remove(list, listelem); + + /* + * free the buffer list element. + */ + kfree(listelem); + listelem = NULL; + + result = 0; + break; + } + + listelem = lst_next(listelem); + } + + if (result == IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE) + pr_debug("failed to locate an available resource element to remove\n"); + +error: + return result; +} + +/* + * obtains pointer to an available item from the resource list + */ +void *resource_list_get_avail(struct lst_t *list) +{ + struct resource_list_elem *listelem = NULL; + void *item = NULL; + + if (!list) + goto error; + + /* + * find the next unused item in the list. + */ + listelem = lst_first(list); + while (listelem) { + if (resource_item_isavailable(listelem->refcnt)) { + resource_item_use(listelem->refcnt); + item = listelem->item; + break; + } + listelem = lst_next(listelem); + } + +error: + return item; +} + +/* + * signal duplicate use of specified item with resource list + */ +void *resource_list_reuseitem(struct lst_t *list, void *item) +{ + struct resource_list_elem *listelem = NULL; + void *ret_item = NULL; + + if (!list || !item) + goto error; + + /* + * find the specified item in the list. + */ + listelem = lst_first(list); + + while (listelem) { + if (listelem->item == item) { + resource_item_use(listelem->refcnt); + ret_item = item; + break; + } + + listelem = lst_next(listelem); + } + +error: + return ret_item; +} + +/* + * obtain pointer to item from resource list with id + */ +void *resource_list_getbyid(struct lst_t *list, unsigned int id) +{ + struct resource_list_elem *listelem = NULL; + void *item = NULL; + + if (!list) + goto error; + + /* + * find the next unused buffer in the list. + */ + listelem = lst_first(list); + while (listelem) { + if (listelem->id == id) { + resource_item_use(listelem->refcnt); + item = listelem->item; + break; + } + + listelem = lst_next(listelem); + } + +error: + return item; +} + +/* + * obtain the number of available (unused) items within list. + */ +int resource_list_getnumavail(struct lst_t *list) +{ + struct resource_list_elem *listelem = NULL; + unsigned int num_items = 0; + + if (!list) + goto error; + + /* + * find the next unused buffer in the list. + */ + listelem = lst_first(list); + while (listelem) { + if (resource_item_isavailable(listelem->refcnt)) + num_items++; + + listelem = lst_next(listelem); + } + +error: + return num_items; +} + +/* + * Obtain the number of items within list + */ +int resource_list_getnum(struct lst_t *list) +{ + struct resource_list_elem *listelem = NULL; + unsigned int num_items = 0; + + if (!list) + goto error; + + /* + * find the next unused buffer in the list. + */ + listelem = lst_first(list); + while (listelem) { + num_items++; + listelem = lst_next(listelem); + } + +error: + return num_items; +} + +/* + * replaces an item (of specified id) within a resource list + */ +int resource_list_replace(struct lst_t *list, void *item, unsigned int id, unsigned int *refcnt, + resource_pfn_freeitem fn_freeitem, + void *free_cb_param) +{ + struct resource_list_elem *listelem = NULL; + unsigned int result = 0; + + if (!list || !item) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + + /* + * determine whether this sequence header is already in the list + */ + listelem = lst_first(list); + while (listelem) { + if (listelem->id == id) { + resource_item_return(listelem->refcnt); + if (*listelem->refcnt == 0) { + if (fn_freeitem) + fn_freeitem(listelem->item, + free_cb_param); + else { + if (!listelem->item) + kfree(listelem->item); + } + listelem->item = NULL; + } + + lst_remove(list, listelem); + break; + } + + listelem = lst_next(listelem); + } + + if (!listelem) { + /* + * Allocate the sequence header list element structure. + */ + listelem = kmalloc(sizeof(*(listelem)), GFP_KERNEL); + if (!listelem) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + memset(listelem, 0, sizeof(*(listelem))); + } + + /* + * setup the sequence header list element. + */ + resource_item_use(refcnt); + + listelem->item = item; + listelem->id = id; + listelem->refcnt = refcnt; + + /* + * Add the sequence header list element to the sequence header list. + */ + lst_add(list, (void *)listelem); + + return 0; + +error: + return result; +} + +/* + * removes all items from a resource list. + */ +int resource_list_empty(struct lst_t *list, unsigned int release_item, + resource_pfn_freeitem fn_freeitem, + void *free_cb_param) +{ + struct resource_list_elem *listelem = NULL; + unsigned int result = 0; + + if (!list) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + + /* + * remove all the buffer list elements from the image buffer list + */ + listelem = lst_removehead(list); + while (listelem) { + if (release_item) { + resource_item_release(listelem->refcnt); + } else { + /* + * Return and free. + */ + resource_item_return(listelem->refcnt); + + if (!listelem->refcnt || *listelem->refcnt == 0) { + if (fn_freeitem) + fn_freeitem(listelem->item, + free_cb_param); + else + kfree(listelem->item); + listelem->item = NULL; + } + } + + /* + * free the buffer list element. + */ + kfree(listelem); + listelem = NULL; + + /* + * Get the next element from the list. + */ + listelem = lst_removehead(list); + } + + return 0; + +error: + return result; +} + +/* + * obtain the number of pictures within list + */ +int resource_getnumpict(struct lst_t *list) +{ + struct resource_list_elem *listelem = NULL; + unsigned int num_pict = 0; + + if (!list) + goto error; + + /* + * find the next unused buffer in the list. + */ + listelem = lst_first(list); + while (listelem) { + num_pict++; + listelem = lst_next(listelem); + } + +error: + return num_pict; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/resource.h b/drivers/media/platform/imagination/vxe-vxd/common/resource.h --- a/drivers/media/platform/imagination/vxe-vxd/common/resource.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/resource.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD DEC SYSDEV and UI Interface header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#ifndef _VXD_RESOURCE_H +#define _VXD_RESOURCE_H + +typedef int (*resource_pfn_freeitem)(void *item, void *free_cb_param); + +int resource_item_use(unsigned int *refcnt); + +void resource_item_return(unsigned int *refcnt); + +int resource_item_release(unsigned int *refcnt); + +int resource_item_isavailable(unsigned int *refcnt); + +int resource_list_add_img(struct lst_t *list, void *item, unsigned int id, unsigned int *refcnt); + +void *resource_list_pickhead(struct lst_t *list); + +int resource_list_remove(struct lst_t *list, void *item); + +/** + * resource_list_removehead - removes item at head of resource list + * @list: head of resource list + */ + +void *resource_list_removehead(struct lst_t *list); + +int resource_list_remove_nextavail(struct lst_t *list, + resource_pfn_freeitem fn_freeitem, + void *free_cb_param); + +void *resource_list_get_avail(struct lst_t *list); + +void *resource_list_reuseitem(struct lst_t *list, void *item); + +void *resource_list_getbyid(struct lst_t *list, unsigned int id); + +int resource_list_getnumavail(struct lst_t *list); + +int resource_list_getnum(struct lst_t *list); + +int resource_list_replace(struct lst_t *list, void *item, unsigned int id, unsigned int *refcnt, + resource_pfn_freeitem fn_freeitem, + void *free_cb_param); + +int resource_list_empty(struct lst_t *list, unsigned int release_item, + resource_pfn_freeitem fn_freeitem, + void *free_cb_param); + +int resource_getnumpict(struct lst_t *list); + +#endif /* _VXD_RESOURCE_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/rman_api.c b/drivers/media/platform/imagination/vxe-vxd/common/rman_api.c --- a/drivers/media/platform/imagination/vxe-vxd/common/rman_api.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/rman_api.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,621 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This component is used to track decoder resources, + * and share them across other components. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dq.h" +#include "idgen_api.h" +#include "rman_api.h" +#include "img_errors.h" + +/* + * The following macros are used to build/decompose the composite resource Id + * made up from the bucket index + 1 and the allocated resource Id. + */ +#define RMAN_CRESID_BUCKET_INDEX_BITS (8) +#define RMAN_CRESID_RES_ID_BITS (32 - RMAN_CRESID_BUCKET_INDEX_BITS) +#define RMAN_CRESID_MAX_RES_ID ((1 << RMAN_CRESID_RES_ID_BITS) - 1) +#define RMAN_CRESID_RES_ID_MASK (RMAN_CRESID_MAX_RES_ID) +#define RMAN_CRESID_BUCKET_SHIFT (RMAN_CRESID_RES_ID_BITS) +#define RMAN_CRESID_MAX_BUCKET_INDEX \ + ((1 << RMAN_CRESID_BUCKET_INDEX_BITS) - 1) + +#define RMAN_MAX_ID 4096 +#define RMAN_ID_BLOCKSIZE 256 + +/* global state variable */ +static unsigned char inited; +static struct rman_bucket *bucket_array[RMAN_CRESID_MAX_BUCKET_INDEX] = {0}; +static struct rman_bucket *global_res_bucket; +static struct rman_bucket *shared_res_bucket; +static struct mutex *shared_res_mutex_handle; +static struct mutex *global_mutex; + +/* + * This structure contains the bucket information. + */ +struct rman_bucket { + void **link; /* to be part of single linked list */ + struct dq_linkage_t res_list; + unsigned int bucket_idx; + void *id_gen; + unsigned int res_cnt; +}; + +/* + * This structure contains the resource details for a resource registered with + * the resource manager. + */ +struct rman_res { + struct dq_linkage_t link; /* to be part of double linked list */ + struct rman_bucket *bucket; + unsigned int type_id; + rman_fn_free fn_free; + void *param; + unsigned int res_id; + struct mutex *mutex_handle; /*resource mutex */ + unsigned char *res_name; + struct rman_res *shared_res; + unsigned int ref_cnt; +}; + +/* + * initialization + */ +int rman_initialise(void) +{ + unsigned int ret; + + if (!inited) { + shared_res_mutex_handle = kzalloc(sizeof(*shared_res_mutex_handle), GFP_KERNEL); + if (!shared_res_mutex_handle) + return IMG_ERROR_OUT_OF_MEMORY; + + mutex_init(shared_res_mutex_handle); + + /* Set initialised flag */ + inited = TRUE; + + /* Create the global resource bucket */ + ret = rman_create_bucket((void **)&global_res_bucket); + IMG_DBG_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + /* Create the shared resource bucket */ + ret = rman_create_bucket((void **)&shared_res_bucket); + IMG_DBG_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + global_mutex = kzalloc(sizeof(*global_mutex), GFP_KERNEL); + if (!global_mutex) + return IMG_ERROR_OUT_OF_MEMORY; + + mutex_init(global_mutex); + } + return IMG_SUCCESS; +} + +/* + * deinitialization + */ +void rman_deinitialise(void) +{ + unsigned int i; + + if (inited) { + /* Destroy the golbal resource bucket */ + rman_destroy_bucket(global_res_bucket); + + /* Destroy the shared resource bucket */ + rman_destroy_bucket(shared_res_bucket); + + /* Make sure we destroy the mutex after destroying the bucket */ + mutex_destroy(global_mutex); + kfree(global_mutex); + global_mutex = NULL; + + /* Destroy mutex */ + mutex_destroy(shared_res_mutex_handle); + kfree(shared_res_mutex_handle); + shared_res_mutex_handle = NULL; + + /* Check all buckets destroyed */ + for (i = 0; i < RMAN_CRESID_MAX_BUCKET_INDEX; i++) + IMG_DBG_ASSERT(!bucket_array[i]); + + /* Reset initialised flag */ + inited = FALSE; + } +} + +int rman_create_bucket(void **res_bucket_handle) +{ + struct rman_bucket *bucket; + unsigned int i; + int ret; + + IMG_DBG_ASSERT(inited); + + /* Allocate a bucket structure */ + bucket = kzalloc(sizeof(*bucket), GFP_KERNEL); + IMG_DBG_ASSERT(bucket); + if (!bucket) + return IMG_ERROR_OUT_OF_MEMORY; + + /* Initialise the resource list */ + dq_init(&bucket->res_list); + + /* Then start allocating resource ids at the first */ + ret = idgen_createcontext(RMAN_MAX_ID, RMAN_ID_BLOCKSIZE, FALSE, + &bucket->id_gen); + if (ret != IMG_SUCCESS) { + kfree(bucket); + IMG_DBG_ASSERT("failed to create IDGEN context" == NULL); + return ret; + } + + /* Locate free bucket index within the table */ + mutex_lock_nested(shared_res_mutex_handle, SUBCLASS_RMAN); + for (i = 0; i < RMAN_CRESID_MAX_BUCKET_INDEX; i++) { + if (!bucket_array[i]) + break; + } + if (i >= RMAN_CRESID_MAX_BUCKET_INDEX) { + mutex_unlock(shared_res_mutex_handle); + idgen_destroycontext(bucket->id_gen); + kfree(bucket); + IMG_DBG_ASSERT("No free buckets left" == NULL); + return IMG_ERROR_GENERIC_FAILURE; + } + + /* Allocate bucket index */ + bucket->bucket_idx = i; + bucket_array[i] = bucket; + + mutex_unlock(shared_res_mutex_handle); + + /* Return the bucket handle */ + *res_bucket_handle = bucket; + + return IMG_SUCCESS; +} + +void rman_destroy_bucket(void *res_bucket_handle) +{ + struct rman_bucket *bucket = (struct rman_bucket *)res_bucket_handle; + + IMG_DBG_ASSERT(inited); + + IMG_DBG_ASSERT(bucket); + if (!bucket) + return; + + IMG_DBG_ASSERT(bucket->bucket_idx < RMAN_CRESID_MAX_BUCKET_INDEX); + IMG_DBG_ASSERT(bucket_array[bucket->bucket_idx]); + + /* Free all resources from the bucket */ + rman_free_resources(res_bucket_handle, RMAN_TYPE_P1); + rman_free_resources(res_bucket_handle, RMAN_TYPE_P2); + rman_free_resources(res_bucket_handle, RMAN_TYPE_P3); + rman_free_resources(res_bucket_handle, RMAN_ALL_TYPES); + + /* free sticky resources last: other resources are dependent on them */ + rman_free_resources(res_bucket_handle, RMAN_STICKY); + /* Use proper locking around global buckets. */ + mutex_lock_nested(shared_res_mutex_handle, SUBCLASS_RMAN); + + /* Free from array of bucket pointers */ + bucket_array[bucket->bucket_idx] = NULL; + + mutex_unlock(shared_res_mutex_handle); + + /* Free the bucket itself */ + idgen_destroycontext(bucket->id_gen); + kfree(bucket); +} + +void *rman_get_global_bucket(void) +{ + IMG_DBG_ASSERT(inited); + IMG_DBG_ASSERT(global_res_bucket); + + /* Return the handle of the global resource bucket */ + return global_res_bucket; +} + +int rman_register_resource(void *res_bucket_handle, unsigned int type_id, + rman_fn_free fnfree, void *param, + void **res_handle, unsigned int *res_id) +{ + struct rman_bucket *bucket = (struct rman_bucket *)res_bucket_handle; + struct rman_res *res; + int ret; + + IMG_DBG_ASSERT(inited); + IMG_DBG_ASSERT(type_id != RMAN_ALL_TYPES); + + IMG_DBG_ASSERT(res_bucket_handle); + if (!res_bucket_handle) + return IMG_ERROR_GENERIC_FAILURE; + + /* Allocate a resource structure */ + res = kzalloc(sizeof(*res), GFP_KERNEL); + IMG_DBG_ASSERT(res); + if (!res) + return IMG_ERROR_OUT_OF_MEMORY; + + /* Fill in the resource structure */ + res->bucket = bucket; + res->type_id = type_id; + res->fn_free = fnfree; + res->param = param; + + /* Allocate resource Id */ + mutex_lock_nested(global_mutex, SUBCLASS_RMAN); + ret = idgen_allocid(bucket->id_gen, res, &res->res_id); + mutex_unlock(global_mutex); + if (ret != IMG_SUCCESS) { + IMG_DBG_ASSERT("failed to allocate RMAN id" == NULL); + return ret; + } + IMG_DBG_ASSERT(res->res_id <= RMAN_CRESID_MAX_RES_ID); + + /* add this resource to the bucket */ + mutex_lock_nested(shared_res_mutex_handle, SUBCLASS_RMAN); + dq_addtail(&bucket->res_list, res); + + /* Update count of resources */ + bucket->res_cnt++; + mutex_unlock(shared_res_mutex_handle); + + /* If resource handle required */ + if (res_handle) + *res_handle = res; + + /* If resource id required */ + if (res_id) + *res_id = rman_get_resource_id(res); + + return IMG_SUCCESS; +} + +unsigned int rman_get_resource_id(void *res_handle) +{ + struct rman_res *res = res_handle; + unsigned int ext_res_id; + + IMG_DBG_ASSERT(res_handle); + if (!res_handle) + return 0; + + IMG_DBG_ASSERT(res->res_id <= RMAN_CRESID_MAX_RES_ID); + IMG_DBG_ASSERT(res->bucket->bucket_idx < RMAN_CRESID_MAX_BUCKET_INDEX); + if (res->bucket->bucket_idx >= RMAN_CRESID_MAX_BUCKET_INDEX) + return 0; + + ext_res_id = (((res->bucket->bucket_idx + 1) << + RMAN_CRESID_BUCKET_SHIFT) | res->res_id); + + return ext_res_id; +} + +static void *rman_getresource_int(void *res_bucket_handle, unsigned int res_id, + unsigned int type_id, void **res_handle) +{ + struct rman_bucket *bucket = (struct rman_bucket *)res_bucket_handle; + struct rman_res *res; + int ret; + + IMG_DBG_ASSERT(res_id <= RMAN_CRESID_MAX_RES_ID); + + /* Loop over the resources in this bucket till we find the required id */ + mutex_lock_nested(global_mutex, SUBCLASS_RMAN); + ret = idgen_gethandle(bucket->id_gen, res_id, (void **)&res); + mutex_unlock(global_mutex); + if (ret != IMG_SUCCESS) { + IMG_DBG_ASSERT("failed to get RMAN resource" == NULL); + return NULL; + } + + /* If the resource handle is required */ + if (res_handle) + *res_handle = res; /* Return it */ + + /* If the resource was not found */ + IMG_DBG_ASSERT(res); + IMG_DBG_ASSERT((void *)res != &bucket->res_list); + if (!res || ((void *)res == &bucket->res_list)) + return NULL; + + /* Cross check the type */ + IMG_DBG_ASSERT(type_id == res->type_id); + + /* Return the resource. */ + return res->param; +} + +int rman_get_resource(unsigned int res_id, unsigned int type_id, void **param, + void **res_handle) +{ + unsigned int bucket_idx = (res_id >> RMAN_CRESID_BUCKET_SHIFT) - 1; + unsigned int int_res_id = (res_id & RMAN_CRESID_RES_ID_MASK); + void *local_param; + + IMG_DBG_ASSERT(bucket_idx < RMAN_CRESID_MAX_BUCKET_INDEX); + if (bucket_idx >= RMAN_CRESID_MAX_BUCKET_INDEX) + return IMG_ERROR_INVALID_ID; /* Happens when bucket_idx == 0 */ + + IMG_DBG_ASSERT(bucket_array[bucket_idx]); + if (!bucket_array[bucket_idx]) + return IMG_ERROR_INVALID_ID; + + local_param = rman_getresource_int(bucket_array[bucket_idx], + int_res_id, type_id, + res_handle); + + /* If we didn't find the resource */ + if (!local_param) + return IMG_ERROR_INVALID_ID; + + /* Return the resource */ + if (param) + *param = local_param; + + return IMG_SUCCESS; +} + +int rman_get_named_resource(unsigned char *res_name, rman_fn_alloc fn_alloc, + void *alloc_info, void *res_bucket_handle, + unsigned int type_id, rman_fn_free fn_free, + void **param, void **res_handle, unsigned int *res_id) +{ + struct rman_bucket *bucket = res_bucket_handle; + struct rman_res *res; + unsigned int ret; + void *local_param; + unsigned char found = FALSE; + + IMG_DBG_ASSERT(inited); + + IMG_DBG_ASSERT(res_bucket_handle); + if (!res_bucket_handle) + return IMG_ERROR_GENERIC_FAILURE; + + /* Lock the shared resources */ + mutex_lock_nested(shared_res_mutex_handle, SUBCLASS_RMAN); + res = (struct rman_res *)dq_first(&bucket->res_list); + while (res && ((void *)res != &bucket->res_list)) { + /* If resource already in the shared list */ + if (res->res_name && (strcmp(res_name, + res->res_name) == 0)) { + IMG_DBG_ASSERT(res->fn_free == fn_free); + found = TRUE; + break; + } + + /* Move to next resource */ + res = (struct rman_res *)dq_next(res); + } + mutex_unlock(shared_res_mutex_handle); + + /* If the named resource was not found */ + if (!found) { + /* Allocate the resource */ + ret = fn_alloc(alloc_info, &local_param); + IMG_DBG_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + /* Register the named resource */ + ret = rman_register_resource(res_bucket_handle, type_id, + fn_free, local_param, + (void **)&res, NULL); + IMG_DBG_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + mutex_lock_nested(shared_res_mutex_handle, SUBCLASS_RMAN); + res->res_name = res_name; + mutex_unlock(shared_res_mutex_handle); + } + + /* Return the pvParam value */ + *param = res->param; + + /* If resource handle required */ + if (res_handle) + *res_handle = res; + + /* If resource id required */ + if (res_id) + *res_id = rman_get_resource_id(res); + + /* Exit */ + return IMG_SUCCESS; +} + +static void rman_free_resource_int(struct rman_res *res) +{ + struct rman_bucket *bucket = res->bucket; + + /* Remove the resource from the active list */ + mutex_lock_nested(shared_res_mutex_handle, SUBCLASS_RMAN); + + /* Remove from list */ + dq_remove(res); + + /* Update count of resources */ + bucket->res_cnt--; + + mutex_unlock(shared_res_mutex_handle); + + /* If mutex associated with the resource */ + if (res->mutex_handle) { + /* Destroy mutex */ + mutex_destroy(res->mutex_handle); + kfree(res->mutex_handle); + res->mutex_handle = NULL; + } + + /* If this resource is not already shared */ + if (res->shared_res) { + /* Lock the shared resources */ + mutex_lock_nested(shared_res_mutex_handle, SUBCLASS_RMAN); + + /* Update the reference count */ + IMG_DBG_ASSERT(res->shared_res->ref_cnt != 0); + res->shared_res->ref_cnt--; + + /* If this is the last free for the shared resource */ + if (res->shared_res->ref_cnt == 0) + /* Free the shared resource */ + rman_free_resource_int(res->shared_res); + + /* UnLock the shared resources */ + mutex_unlock(shared_res_mutex_handle); + } else { + /* If there is a free callback function. */ + if (res->fn_free) + /* Call resource free callback */ + res->fn_free(res->param); + } + + /* If the resource has a name then free it */ + kfree(res->res_name); + + /* Free the resource ID. */ + mutex_lock_nested(global_mutex, SUBCLASS_RMAN); + idgen_freeid(bucket->id_gen, res->res_id); + mutex_unlock(global_mutex); + + /* Free a resource structure */ + kfree(res); +} + +void rman_free_resource(void *res_handle) +{ + struct rman_res *res; + + IMG_DBG_ASSERT(inited); + + IMG_DBG_ASSERT(res_handle); + if (!res_handle) + return; + + /* Get access to the resource structure */ + res = (struct rman_res *)res_handle; + + /* Free resource */ + rman_free_resource_int(res); +} + +void rman_lock_resource(void *res_handle) +{ + struct rman_res *res; + + IMG_DBG_ASSERT(inited); + + IMG_DBG_ASSERT(res_handle); + if (!res_handle) + return; + + /* Get access to the resource structure */ + res = (struct rman_res *)res_handle; + + /* If this is a shared resource */ + if (res->shared_res) + /* We need to lock/unlock the underlying shared resource */ + res = res->shared_res; + + /* If no mutex associated with this resource */ + if (!res->mutex_handle) { + /* Create one */ + + res->mutex_handle = kzalloc(sizeof(*res->mutex_handle), GFP_KERNEL); + if (!res->mutex_handle) + return; + + mutex_init(res->mutex_handle); + } + + /* lock it */ + mutex_lock(res->mutex_handle); +} + +void rman_unlock_resource(void *res_handle) +{ + struct rman_res *res; + + IMG_DBG_ASSERT(inited); + + IMG_DBG_ASSERT(res_handle); + if (!res_handle) + return; + + /* Get access to the resource structure */ + res = (struct rman_res *)res_handle; + + /* If this is a shared resource */ + if (res->shared_res) + /* We need to lock/unlock the underlying shared resource */ + res = res->shared_res; + + IMG_DBG_ASSERT(res->mutex_handle); + + /* Unlock mutex */ + mutex_unlock(res->mutex_handle); +} + +void rman_free_resources(void *res_bucket_handle, unsigned int type_id) +{ + struct rman_bucket *bucket = (struct rman_bucket *)res_bucket_handle; + struct rman_res *res; + + IMG_DBG_ASSERT(inited); + + IMG_DBG_ASSERT(res_bucket_handle); + if (!res_bucket_handle) + return; + + /* Scan the active list looking for the resources to be freed */ + mutex_lock_nested(shared_res_mutex_handle, SUBCLASS_RMAN); + res = (struct rman_res *)dq_first(&bucket->res_list); + while ((res) && ((void *)res != &bucket->res_list)) { + /* If this is resource is to be removed */ + if ((type_id == RMAN_ALL_TYPES && + res->type_id != RMAN_STICKY) || + res->type_id == type_id) { + /* Yes, remove it, Free current resource */ + mutex_unlock(shared_res_mutex_handle); + rman_free_resource_int(res); + mutex_lock_nested(shared_res_mutex_handle, SUBCLASS_RMAN); + + /* Restart from the beginning of the list */ + res = (struct rman_res *)dq_first(&bucket->res_list); + } else { + /* Move to next resource */ + res = (struct rman_res *)lst_next(res); + } + } + mutex_unlock(shared_res_mutex_handle); +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/rman_api.h b/drivers/media/platform/imagination/vxe-vxd/common/rman_api.h --- a/drivers/media/platform/imagination/vxe-vxd/common/rman_api.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/rman_api.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This component is used to track decoder resources, + * and share them across other components. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef __RMAN_API_H__ +#define __RMAN_API_H__ + +#include + +#include "img_errors.h" +#include "lst.h" + +#define RMAN_ALL_TYPES (0xFFFFFFFF) +#define RMAN_TYPE_P1 (0xFFFFFFFE) +#define RMAN_TYPE_P2 (0xFFFFFFFE) +#define RMAN_TYPE_P3 (0xFFFFFFFE) +#define RMAN_STICKY (0xFFFFFFFD) + +int rman_initialise(void); + +void rman_deinitialise(void); + +int rman_create_bucket(void **res_handle); + +void rman_destroy_bucket(void *res_handle); + +void *rman_get_global_bucket(void); + +typedef void (*rman_fn_free) (void *param); + +int rman_register_resource(void *res_handle, unsigned int type_id, rman_fn_free fn_free, + void *param, void **res_handle_ptr, + unsigned int *res_id); + +typedef int (*rman_fn_alloc) (void *alloc_info, void **param); + +int rman_get_named_resource(unsigned char *res_name, rman_fn_alloc fn_alloc, + void *alloc_info, void *res_bucket_handle, + unsigned int type_id, rman_fn_free fn_free, + void **param, void **res_handle, unsigned int *res_id); + +unsigned int rman_get_resource_id(void *res_handle); + +int rman_get_resource(unsigned int res_id, unsigned int type_id, void **param, + void **res_handle); + +void rman_free_resource(void *res_handle); + +void rman_lock_resource(void *res_handle); + +void rman_unlock_resource(void *res_hanle); + +void rman_free_resources(void *res_bucket_handle, unsigned int type_id); + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/talmmu_api.c b/drivers/media/platform/imagination/vxe-vxd/common/talmmu_api.c --- a/drivers/media/platform/imagination/vxe-vxd/common/talmmu_api.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/talmmu_api.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,753 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TAL MMU Extensions. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Sidraya Jayagond + */ +#include +#include +#include +#include +#include +#include +#include + +#include "img_errors.h" +#include "lst.h" +#include "talmmu_api.h" + +static int global_init; +static struct lst_t gl_dmtmpl_lst = {0}; +static struct mutex *global_lock; + +static int talmmu_devmem_free(void *mem_hndl) +{ + struct talmmu_memory *mem = mem_hndl; + struct talmmu_devmem_heap *mem_heap; + + if (!mem_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + mem_heap = mem->devmem_heap; + + if (!mem->ext_dev_virtaddr) + addr_cx_free(&mem_heap->ctx, "", mem->dev_virtoffset); + + mutex_lock_nested(global_lock, SUBCLASS_TALMMU); + + lst_remove(&mem_heap->memory_list, mem); + + mutex_unlock(global_lock); + + kfree(mem); + + return IMG_SUCCESS; +} + +/* + * talmmu_devmem_heap_empty - talmmu_devmem_heap_empty + * @devmem_heap_hndl: device memory heap handle + * + * This function is used for emptying the device memory heap list + */ +int talmmu_devmem_heap_empty(void *devmem_heap_hndl) +{ + struct talmmu_devmem_heap *devmem_heap = devmem_heap_hndl; + + if (!devmem_heap) + return IMG_ERROR_INVALID_PARAMETERS; + + while (!lst_empty(&devmem_heap->memory_list)) + talmmu_devmem_free(lst_first(&devmem_heap->memory_list)); + + addr_cx_deinitialise(&devmem_heap->ctx); + + return IMG_SUCCESS; +} + +/* + * @Function talmmu_devmem_heap_destroy + * + * @Description This function is used for freeing the device memory heap + * + * @Input + * + * @Output + * + * @Return IMG_SUCCESS or an error code + * + */ +static void talmmu_devmem_heap_destroy(void *devmem_heap_hndl) +{ + struct talmmu_devmem_heap *devmem_heap = devmem_heap_hndl; + + talmmu_devmem_heap_empty(devmem_heap_hndl); + kfree(devmem_heap); +} + +/* + * @Function talmmu_init + * + * @Description This function is used to initialize the TALMMU component. + * + * @Input None. + * + * @Return IMG_SUCCESS or an error code + * + */ +int talmmu_init(void) +{ + if (!global_init) { + /* If no mutex associated with this resource */ + if (!global_lock) { + /* Create one */ + global_lock = kzalloc(sizeof(*global_lock), GFP_KERNEL); + if (!global_lock) + return IMG_ERROR_OUT_OF_MEMORY; + + mutex_init(global_lock); + } + + lst_init(&gl_dmtmpl_lst); + global_init = 1; + } + + return IMG_SUCCESS; +} + +/* + * @Function talmmu_deinit + * + * @Description This function is used to de-initialize the TALMMU component. + * + * @Input None. + * + * @Return IMG_SUCCESS or an error code + * + */ +int talmmu_deinit(void) +{ + struct talmmu_dm_tmpl *t; + + if (global_init) { + while (!lst_empty(&gl_dmtmpl_lst)) { + t = (struct talmmu_dm_tmpl *)lst_first(&gl_dmtmpl_lst); + talmmu_devmem_template_destroy((void *)t); + } + mutex_destroy(global_lock); + kfree(global_lock); + global_lock = NULL; + global_init = 0; + } + + return IMG_SUCCESS; +} + +/* + * @Function talmmu_devmem_template_create + * + * @Description This function is used to create a device memory template + * + * @Input devmem_info: A pointer to a talmmu_devmem_info structure. + * + * @Output devmem_template_hndl: A pointer used to return the template + * handle + * + * @Return IMG_SUCCESS or an error code + * + */ +int talmmu_devmem_template_create(struct talmmu_devmem_info *devmem_info, + void **devmem_template_hndl) +{ + struct talmmu_dm_tmpl *devmem_template; + struct talmmu_dm_tmpl *tmp_devmem_template; + + if (!devmem_info) + return IMG_ERROR_INVALID_PARAMETERS; + + devmem_template = kzalloc(sizeof(*devmem_template), GFP_KERNEL); + if (!devmem_template) + return IMG_ERROR_OUT_OF_MEMORY; + + devmem_template->devmem_info = *devmem_info; + + lst_init(&devmem_template->devmem_ctx_list); + + mutex_lock_nested(global_lock, SUBCLASS_TALMMU); + + tmp_devmem_template = lst_first(&gl_dmtmpl_lst); + while (tmp_devmem_template) + tmp_devmem_template = lst_next(tmp_devmem_template); + + devmem_template->page_num_shift = 12; + devmem_template->byte_in_pagemask = 0xFFF; + devmem_template->heap_alignment = 0x400000; + devmem_template->pagetable_entries_perpage = + (devmem_template->devmem_info.page_size / sizeof(unsigned int)); + devmem_template->pagetable_num_shift = 10; + devmem_template->index_in_pagetable_mask = 0x3FF; + devmem_template->pagedir_num_shift = 22; + + lst_add(&gl_dmtmpl_lst, devmem_template); + + mutex_unlock(global_lock); + + *devmem_template_hndl = devmem_template; + + return IMG_SUCCESS; +} + +/* + * @Function talmmu_devmem_template_destroy + * + * @Description This function is used to obtain the template from the list and + * destroy + * + * @Input devmem_tmplt_hndl: Device memory template handle + * + * @Return IMG_SUCCESS or an error code + * + */ +int talmmu_devmem_template_destroy(void *devmem_tmplt_hndl) +{ + struct talmmu_dm_tmpl *dm_tmpl = devmem_tmplt_hndl; + unsigned int i; + + if (!devmem_tmplt_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + while (!lst_empty(&dm_tmpl->devmem_ctx_list)) + talmmu_devmem_ctx_destroy(lst_first(&dm_tmpl->devmem_ctx_list)); + + for (i = 0; i < dm_tmpl->num_heaps; i++) + talmmu_devmem_heap_destroy(dm_tmpl->devmem_heap[i]); + + mutex_lock_nested(global_lock, SUBCLASS_TALMMU); + + lst_remove(&gl_dmtmpl_lst, dm_tmpl); + + mutex_unlock(global_lock); + + kfree(dm_tmpl); + + return IMG_SUCCESS; +} + +/* + * @Function talmmu_create_heap + * + * @Description This function is used to create a device memory heap + * + * @Input + * + * @Output + * + * @Return IMG_SUCCESS or an error code + * + */ +static int talmmu_create_heap(void *devmem_tmplt_hndl, + struct talmmu_heap_info *heap_info_arg, + unsigned char isfull, + struct talmmu_devmem_heap **devmem_heap_arg) +{ + struct talmmu_dm_tmpl *devmem_template = devmem_tmplt_hndl; + struct talmmu_devmem_heap *devmem_heap; + + /* Allocating memory for device memory heap */ + devmem_heap = kzalloc(sizeof(*devmem_heap), GFP_KERNEL); + if (!devmem_heap) + return IMG_ERROR_OUT_OF_MEMORY; + + /* + * Update the device memory heap structure members + * Update the device memory template + */ + devmem_heap->devmem_template = devmem_template; + /* Update the device memory heap information */ + devmem_heap->heap_info = *heap_info_arg; + + /* Initialize the device memory heap list */ + lst_init(&devmem_heap->memory_list); + + /* If full structure required */ + if (isfull) { + addr_cx_initialise(&devmem_heap->ctx); + devmem_heap->regions.base_addr = 0; + devmem_heap->regions.size = devmem_heap->heap_info.size; + addr_cx_define_mem_region(&devmem_heap->ctx, + &devmem_heap->regions); + } + + *devmem_heap_arg = devmem_heap; + + return IMG_SUCCESS; +} + +/* + * @Function talmmu_devmem_heap_add + * + * @Description This function is for creating and adding the heap to the + * device memory template + * + * @Input devmem_tmplt_hndl: device memory template handle + * + * @Input heap_info_arg: pointer to the heap info structure + * + * @Return IMG_SUCCESS or an error code + * + */ +int talmmu_devmem_heap_add(void *devmem_tmplt_hndl, + struct talmmu_heap_info *heap_info_arg) +{ + struct talmmu_dm_tmpl *devmem_template = devmem_tmplt_hndl; + struct talmmu_devmem_heap *devmem_heap; + unsigned int res; + + if (!devmem_tmplt_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + if (!heap_info_arg) + return IMG_ERROR_INVALID_PARAMETERS; + + res = talmmu_create_heap(devmem_tmplt_hndl, + heap_info_arg, + 1, + &devmem_heap); + if (res != IMG_SUCCESS) + return res; + + devmem_template->devmem_heap[devmem_template->num_heaps] = devmem_heap; + devmem_template->num_heaps++; + + return IMG_SUCCESS; +} + +/* + * @Function talmmu_devmem_ctx_create + * + * @Description This function is used to create a device memory context + * + * @Input devmem_tmplt_hndl: pointer to the device memory template handle + * + * @Input mmu_ctx_id: MMU context ID used with the TAL + * + * @Output devmem_ctx_hndl: pointer to the device memory context handle + * + * @Return IMG_SUCCESS or an error code + * + */ +int talmmu_devmem_ctx_create(void *devmem_tmplt_hndl, + unsigned int mmu_ctx_id, + void **devmem_ctx_hndl) +{ + struct talmmu_dm_tmpl *dm_tmpl = devmem_tmplt_hndl; + struct talmmu_devmem_ctx *dm_ctx; + struct talmmu_devmem_heap *dm_heap; + int i; + unsigned int res = IMG_SUCCESS; + + if (!devmem_tmplt_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Allocate memory for device memory context */ + dm_ctx = kzalloc((sizeof(struct talmmu_devmem_ctx)), GFP_KERNEL); + if (!dm_ctx) + return IMG_ERROR_OUT_OF_MEMORY; + + /* + * Update the device memory context structure members + * Update the device memory template + */ + dm_ctx->devmem_template = dm_tmpl; + /* Update MMU context ID */ + dm_ctx->mmu_ctx_id = mmu_ctx_id; + + /* Check for PTD Alignment */ + if (dm_tmpl->devmem_info.ptd_alignment == 0) + /* + * Make sure alignment is a multiple of page size. + * Set up PTD alignment to Page Size + */ + dm_tmpl->devmem_info.ptd_alignment = + dm_tmpl->devmem_info.page_size; + + /* Reference or create heaps for this context */ + for (i = 0; i < dm_tmpl->num_heaps; i++) { + dm_heap = dm_tmpl->devmem_heap[i]; + if (!dm_heap) + goto error_heap_create; + + switch (dm_heap->heap_info.heap_type) { + case TALMMU_HEAP_PERCONTEXT: + res = talmmu_create_heap(dm_tmpl, + &dm_heap->heap_info, + 1, + &dm_ctx->devmem_heap[i]); + if (res != IMG_SUCCESS) + goto error_heap_create; + break; + + default: + break; + } + + dm_ctx->num_heaps++; + } + + mutex_lock_nested(global_lock, SUBCLASS_TALMMU); + + /* Add the device memory context to the list */ + lst_add(&dm_tmpl->devmem_ctx_list, dm_ctx); + + dm_tmpl->num_ctxs++; + + mutex_unlock(global_lock); + + *devmem_ctx_hndl = dm_ctx; + + return IMG_SUCCESS; + +error_heap_create: + /* Destroy the device memory heaps which were already created */ + for (i--; i >= 0; i--) { + dm_heap = dm_ctx->devmem_heap[i]; + if (dm_heap->heap_info.heap_type == TALMMU_HEAP_PERCONTEXT) + talmmu_devmem_heap_destroy(dm_heap); + + dm_ctx->num_heaps--; + } + kfree(dm_ctx); + return res; +} + +/* + * @Function talmmu_devmem_ctx_destroy + * + * @Description This function is used to get the device memory context from + * the list and destroy + * + * @Input devmem_ctx_hndl: device memory context handle + * + * @Return IMG_SUCCESS or an error code + * + */ +int talmmu_devmem_ctx_destroy(void *devmem_ctx_hndl) +{ + struct talmmu_devmem_ctx *devmem_ctx = devmem_ctx_hndl; + struct talmmu_dm_tmpl *devmem_template; + struct talmmu_devmem_heap *devmem_heap; + unsigned int i; + + if (!devmem_ctx_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + devmem_template = devmem_ctx->devmem_template; + + for (i = 0; i < devmem_ctx->num_heaps; i++) { + devmem_heap = devmem_ctx->devmem_heap[i]; + if (!devmem_heap) + return IMG_ERROR_INVALID_PARAMETERS; + + talmmu_devmem_heap_destroy(devmem_heap); + } + + devmem_ctx->pagedir = NULL; + + mutex_lock_nested(global_lock, SUBCLASS_TALMMU); + + lst_remove(&devmem_template->devmem_ctx_list, devmem_ctx); + + devmem_ctx->devmem_template->num_ctxs--; + + mutex_unlock(global_lock); + + kfree(devmem_ctx); + + return IMG_SUCCESS; +} + +/* + * @Function talmmu_get_heap_handle + * + * @Description This function is used to get the device memory heap handle + * + * @Input hid: heap id + * + * @Input devmem_ctx_hndl: device memory context handle + * + * @Output devmem_heap_hndl: pointer to the device memory heap handle + * + * @Return IMG_SUCCESS or an error code + * + */ +int talmmu_get_heap_handle(unsigned int hid, + void *devmem_ctx_hndl, + void **devmem_heap_hndl) +{ + struct talmmu_devmem_ctx *devmem_ctx = devmem_ctx_hndl; + unsigned int i; + + if (!devmem_ctx_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + for (i = 0; i < devmem_ctx->num_heaps; i++) { + /* + * Checking for requested heap id match and return the device + * memory heap handle + */ + if (devmem_ctx->devmem_heap[i]->heap_info.heap_id == hid) { + *devmem_heap_hndl = devmem_ctx->devmem_heap[i]; + return IMG_SUCCESS; + } + } + + return IMG_ERROR_GENERIC_FAILURE; +} + +/* + * @Function talmmu_devmem_heap_options + * + * @Description This function is used to set additional heap options + * + * @Input devmem_heap_hndl: Handle for heap + * + * @Input heap_opt_id: Heap options ID + * + * @Input heap_options: Heap options + * + * @Return IMG_SUCCESS or an error code + * + */ +void talmmu_devmem_heap_options(void *devmem_heap_hndl, + enum talmmu_heap_option_id heap_opt_id, + union talmmu_heap_options heap_options) +{ + struct talmmu_devmem_heap *dm_heap = devmem_heap_hndl; + + switch (heap_opt_id) { + case TALMMU_HEAP_OPT_ADD_GUARD_BAND: + dm_heap->guardband = heap_options.guardband_opt.guardband; + break; + default: + break; + } +} + +/* + * @Function talmmu_devmem_malloc_nonmap + * + * @Description + * + * @Input + * + * @Output + * + * @Return IMG_SUCCESS or an error code + * + */ +static int talmmu_devmem_alloc_nonmap(void *devmem_ctx_hndl, + void *devmem_heap_hndl, + unsigned int size, + unsigned int align, + unsigned int dev_virt_ofset, + unsigned char ext_dev_vaddr, + void **mem_hndl) +{ + struct talmmu_devmem_ctx *dm_ctx = devmem_ctx_hndl; + struct talmmu_dm_tmpl *dm_tmpl; + struct talmmu_devmem_heap *dm_heap = devmem_heap_hndl; + struct talmmu_memory *mem; + unsigned long long ui64_dev_offset = 0; + int res = IMG_SUCCESS; + + if (!dm_ctx) + return IMG_ERROR_INVALID_PARAMETERS; + + if (!devmem_heap_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + dm_tmpl = dm_ctx->devmem_template; + + /* Allocate memory for memory structure */ + mem = kzalloc((sizeof(struct talmmu_memory)), GFP_KERNEL); + if (!mem) + return IMG_ERROR_OUT_OF_MEMORY; + + mem->devmem_heap = dm_heap; + mem->devmem_ctx = dm_ctx; + mem->ext_dev_virtaddr = ext_dev_vaddr; + + /* We always for to be at least page aligned */ + if (align >= dm_tmpl->devmem_info.page_size) + /* + * alignment is larger than page size - make sure alignment is + * a multiple of page size + */ + mem->alignment = align; + else + /* + * alignment is smaller than page size - make sure page size is + * a multiple of alignment. Now round up alignment to one page + */ + mem->alignment = dm_tmpl->devmem_info.page_size; + + /* Round size up to next multiple of physical pages */ + if ((size % dm_tmpl->devmem_info.page_size) != 0) + mem->size = ((size / dm_tmpl->devmem_info.page_size) + + 1) * dm_tmpl->devmem_info.page_size; + else + mem->size = size; + + /* If the device virtual address was externally defined */ + if (mem->ext_dev_virtaddr) { + res = IMG_ERROR_INVALID_PARAMETERS; + goto free_mem; + } + + res = addr_cx_malloc_align_res(&dm_heap->ctx, "", + (mem->size + dm_heap->guardband), + mem->alignment, + &ui64_dev_offset); + + mem->dev_virtoffset = (unsigned int)ui64_dev_offset; + if (res != IMG_SUCCESS) + /* + * If heap space is unavaliable return NULL, the caller must + * handle this condition + */ + goto free_virt; + + mutex_lock_nested(global_lock, SUBCLASS_TALMMU); + + /* + * Add memory allocation to the list for this heap... + * If the heap is empty... + */ + if (lst_empty(&dm_heap->memory_list)) + /* + * Save flag to indicate whether the device virtual address + * is allocated internally or externally... + */ + dm_heap->ext_dev_virtaddr = mem->ext_dev_virtaddr; + + /* + * Once we have started allocating in one way ensure that we continue + * to do this... + */ + lst_add(&dm_heap->memory_list, mem); + + mutex_unlock(global_lock); + + *mem_hndl = mem; + + return IMG_SUCCESS; + +free_virt: + addr_cx_free(&dm_heap->ctx, "", mem->dev_virtoffset); +free_mem: + kfree(mem); + + return res; +} + +/* + * @Function talmmu_devmem_addr_alloc + * + * @Description + * + * @Input + * + * @Output + * + * @Return IMG_SUCCESS or an error code + * + */ +int talmmu_devmem_addr_alloc(void *devmem_ctx_hndl, + void *devmem_heap_hndl, + unsigned int size, + unsigned int align, + void **mem_hndl) +{ + unsigned int res; + void *mem; + + res = talmmu_devmem_alloc_nonmap(devmem_ctx_hndl, + devmem_heap_hndl, + size, + align, + 0, + 0, + &mem); + if (res != IMG_SUCCESS) + return res; + + *mem_hndl = mem; + + return IMG_SUCCESS; +} + +/* + * @Function talmmu_devmem_addr_free + * + * @Description This function is used to free device memory allocated using + * talmmu_devmem_addr_alloc(). + * + * @Input mem_hndl : Handle for the memory object + * + * @Return IMG_SUCCESS or an error code + * + */ +int talmmu_devmem_addr_free(void *mem_hndl) +{ + unsigned int res; + + if (!mem_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + /* free device memory allocated by calling talmmu_devmem_free() */ + res = talmmu_devmem_free(mem_hndl); + + return res; +} + +/* + * @Function talmmu_get_dev_virt_addr + * + * @Description This function is use to obtain the device (virtual) memory + * address which may be required for as a device virtual address + * in some of the TAL image functions + * + * @Input mem_hndl : Handle for the memory object + * + * @Output dev_virt: A piointer used to return the device virtual address + * + * @Return IMG_SUCCESS or an error code + * + */ +int talmmu_get_dev_virt_addr(void *mem_hndl, + unsigned int *dev_virt) +{ + struct talmmu_memory *mem = mem_hndl; + struct talmmu_devmem_heap *devmem_heap; + + if (!mem_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + devmem_heap = mem->devmem_heap; + + /* + * Device virtual address is addition of the specific device virtual + * offset and the base device virtual address from the heap information + */ + *dev_virt = (devmem_heap->heap_info.basedev_virtaddr + + mem->dev_virtoffset); + + return IMG_SUCCESS; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/talmmu_api.h b/drivers/media/platform/imagination/vxe-vxd/common/talmmu_api.h --- a/drivers/media/platform/imagination/vxe-vxd/common/talmmu_api.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/talmmu_api.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,246 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * TAL MMU Extensions. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Sidraya Jayagond + */ +#include "addr_alloc.h" +#include "ra.h" +#include "lst.h" + +#ifndef __TALMMU_API_H__ +#define __TALMMU_API_H__ + +#define TALMMU_MAX_DEVICE_HEAPS (32) +#define TALMMU_MAX_TEMPLATES (32) + +/* MMU type */ +enum talmmu_mmu_type { + /* 4kb pages and 32-bit address range */ + TALMMU_MMUTYPE_4K_PAGES_32BIT_ADDR = 0x1, + /* variable size pages and 32-bit address */ + TALMMU_MMUTYPE_VAR_PAGES_32BIT_ADDR, + /* 4kb pages and 36-bit address range */ + TALMMU_MMUTYPE_4K_PAGES_36BIT_ADDR, + /* 4kb pages and 40-bit address range */ + TALMMU_MMUTYPE_4K_PAGES_40BIT_ADDR, + /* variable size pages and 40-bit address range */ + TALMMU_MMUTYPE_VP_40BIT, + TALMMU_MMUTYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* Device flags */ +enum talmmu_dev_flags { + TALMMU_DEVFLAGS_NONE = 0x0, + TALMMU_DEVFLAGS_FORCE32BITS = 0x7FFFFFFFU +}; + +/* Heap type */ +enum talmmu_heap_type { + TALMMU_HEAP_SHARED_EXPORTED, + TALMMU_HEAP_PERCONTEXT, + TALMMU_HEAP_FORCE32BITS = 0x7FFFFFFFU +}; + +/* Heap flags */ +enum talmmu_eheapflags { + TALMMU_HEAPFLAGS_NONE = 0x0, + TALMMU_HEAPFLAGS_SET_CACHE_CONSISTENCY = 0x00000001, + TALMMU_HEAPFLAGS_128BYTE_INTERLEAVE = 0x00000002, + TALMMU_HEAPFLAGS_256BYTE_INTERLEAVE = 0x00000004, + TALMMU_HEAPFLAGS_FORCE32BITS = 0x7FFFFFFFU +}; + +/* Contains the device memory information */ +struct talmmu_devmem_info { + /* device id */ + unsigned int device_id; + /* mmu type */ + enum talmmu_mmu_type mmu_type; + /* Device flags - bit flags that can be combined */ + enum talmmu_dev_flags dev_flags; + /* Name of the memory space for page directory allocations */ + unsigned char *pagedir_memspace_name; + /* Name of the memory space for page table allocations */ + unsigned char *pagetable_memspace_name; + /* Page size in bytes */ + unsigned int page_size; + /* PTD alignment, must be multiple of Page size */ + unsigned int ptd_alignment; +}; + +struct talmmu_heap_info { + /* heap id */ + unsigned int heap_id; + /* heap type */ + enum talmmu_heap_type heap_type; + /* heap flags - bit flags that can be combined */ + enum talmmu_eheapflags heap_flags; + /* Name of the memory space for memory allocations */ + unsigned char *memspace_name; + /* Base device virtual address */ + unsigned int basedev_virtaddr; + /* size in bytes */ + unsigned int size; +}; + +/* Device memory template information */ +struct talmmu_dm_tmpl { + /* list */ + struct lst_t list; + /* Copy of device memory info structure */ + struct talmmu_devmem_info devmem_info; + /* Memory space ID for PTD allocations */ + void *ptd_memspace_hndl; + /* Memory space ID for Page Table allocations */ + void *ptentry_memspace_hndl; + /* number of heaps */ + unsigned int num_heaps; + /* Array of heap pointers */ + struct talmmu_devmem_heap *devmem_heap[TALMMU_MAX_DEVICE_HEAPS]; + /* Number of active contexts */ + unsigned int num_ctxs; + /* List of device memory context created from this template */ + struct lst_t devmem_ctx_list; + /* Number of bits to shift right to obtain page number */ + unsigned int page_num_shift; + /* Mask to extract byte-within-page */ + unsigned int byte_in_pagemask; + /* Heap alignment */ + unsigned int heap_alignment; + /* Page table entries/page */ + unsigned int pagetable_entries_perpage; + /* Number of bits to shift right to obtain page table number */ + unsigned int pagetable_num_shift; + /* Mask to extract index-within-page-table */ + unsigned int index_in_pagetable_mask; + /* Number of bits to shift right to obtain page dir number */ + unsigned int pagedir_num_shift; +}; + +/* Device memory heap information */ +struct talmmu_devmem_heap { + /* list item */ + struct lst_t list; + /* Copy of the heap info structure */ + struct talmmu_heap_info heap_info; + /* Pointer to the device memory template */ + struct talmmu_dm_tmpl *devmem_template; + /* true if device virtual address offset allocated externally by user */ + unsigned int ext_dev_virtaddr; + /* list of memory allocations */ + struct lst_t memory_list; + /* Memory space ID for memory allocations */ + void *memspace_hndl; + /* Address context structure */ + struct addr_context ctx; + /* Regions structure */ + struct addr_region regions; + /* size of heap guard band */ + unsigned int guardband; +}; + +struct talmmu_devmem_ctx { + /* list item */ + struct lst_t list; + /* Pointer to device template */ + struct talmmu_dm_tmpl *devmem_template; + /* No. of heaps */ + unsigned int num_heaps; + /* Array of heap pointers */ + struct talmmu_devmem_heap *devmem_heap[TALMMU_MAX_DEVICE_HEAPS]; + /* The MMU context id */ + unsigned int mmu_ctx_id; + /* Pointer to the memory that represents Page directory */ + unsigned int *pagedir; +}; + +struct talmmu_memory { + /* list item */ + struct lst_t list; + /* Heap from which memory was allocated */ + struct talmmu_devmem_heap *devmem_heap; + /* Context through which memory was allocated */ + struct talmmu_devmem_ctx *devmem_ctx; + /* size */ + unsigned int size; + /* alignment */ + unsigned int alignment; + /* device virtual offset of allocation */ + unsigned int dev_virtoffset; + /* true if device virtual address offset allocated externally by user */ + unsigned int ext_dev_virtaddr; +}; + +/* This type defines the event types for the TALMMU callbacks */ +enum talmmu_event { + /* Function to flush the cache. */ + TALMMU_EVENT_FLUSH_CACHE, + /*! Function to write the page directory address to the device */ + TALMMU_EVENT_WRITE_PAGE_DIRECTORY_REF, + /* Placeholder*/ + TALMMU_NO_OF_EVENTS +}; + +enum talmmu_heap_option_id { + /* Add guard band to all mallocs */ + TALMMU_HEAP_OPT_ADD_GUARD_BAND, + TALMMU_HEAP_OPT_SET_MEM_ATTRIB, + TALMMU_HEAP_OPT_SET_MEM_POOL, + + /* Placeholder */ + TALMMU_NO_OF_OPTIONS, + TALMMU_NO_OF_FORCE32BITS = 0x7FFFFFFFU +}; + +struct talmmu_guardband_options { + unsigned int guardband; +}; + +union talmmu_heap_options { + /* Guardband parameters */ + struct talmmu_guardband_options guardband_opt; +}; + +int talmmu_init(void); +int talmmu_deinit(void); +int talmmu_devmem_template_create(struct talmmu_devmem_info *devmem_info, + void **devmem_template_hndl); +int talmmu_devmem_heap_add(void *devmem_tmplt_hndl, + struct talmmu_heap_info *heap_info_arg); +int talmmu_devmem_template_destroy(void *devmem_tmplt_hndl); +int talmmu_devmem_ctx_create(void *devmem_tmplt_hndl, + unsigned int mmu_ctx_id, + void **devmem_ctx_hndl); +int talmmu_devmem_ctx_destroy(void *devmem_ctx_hndl); +int talmmu_get_heap_handle(unsigned int hid, + void *devmem_ctx_hndl, + void **devmem_heap_hndl); +/** + * talmmu_devmem_heap_empty - talmmu_devmem_heap_empty + * @devmem_heap_hndl: device memory heap handle + * + * This function is used for emptying the device memory heap list + */ + +int talmmu_devmem_heap_empty(void *devmem_heap_hndl); +void talmmu_devmem_heap_options(void *devmem_heap_hndl, + enum talmmu_heap_option_id heap_opt_id, + union talmmu_heap_options heap_options); +int talmmu_devmem_addr_alloc(void *devmem_ctx_hndl, + void *devmem_heap_hndl, + unsigned int size, + unsigned int align, + void **mem_hndl); +int talmmu_devmem_addr_free(void *mem_hndl); +int talmmu_get_dev_virt_addr(void *mem_hndl, + unsigned int *dev_virt); + +#endif /* __TALMMU_API_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/vid_buf.h b/drivers/media/platform/imagination/vxe-vxd/common/vid_buf.h --- a/drivers/media/platform/imagination/vxe-vxd/common/vid_buf.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/vid_buf.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Low-level VXD interface component + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstream + * Sidraya Jayagond + */ + +#ifndef _VID_BUF_H +#define _VID_BUF_H + +/* + * struct vidio_ddbufinfo - contains information about virtual address + * @buf_size: the size of the buffer (in bytes). + * @cpu_virt: the cpu virtual address (mapped into the local cpu mmu) + * @dev_virt: device virtual address (pages mapped into IMG H/W mmu) + * @hndl_memory: handle to device mmu mapping + * @buff_id: buffer id used in communication with interface + * @is_internal: true, if the buffer is allocated internally + * @ref_count: reference count (number of users) + * @kmstr_id: stream id + * @core_id: core id + */ +struct vidio_ddbufinfo { + unsigned int buf_size; + void *cpu_virt; + unsigned int dev_virt; + void *hndl_memory; + unsigned int buff_id; + unsigned int is_internal; + unsigned int ref_count; + unsigned int kmstr_id; + unsigned int core_id; +}; + +#endif /* _VID_BUF_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/work_queue.c b/drivers/media/platform/imagination/vxe-vxd/common/work_queue.c --- a/drivers/media/platform/imagination/vxe-vxd/common/work_queue.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/work_queue.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Work Queue Handling for Linux + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Prashanth Kumar Amai + */ + +#include +#include +#include + +#include "work_queue.h" + +/* Defining and initilizing mutex + */ +DEFINE_MUTEX(mutex); + +#define false 0 +#define true 1 + +struct node { + void **key; + struct node *next; +}; + +struct node *work_head; +struct node *delayed_work_head; + +void init_work(void **work_args, void *work_fn, uint8_t hwa_id) +{ + struct work_struct **work = (struct work_struct **)work_args; + //create a link + struct node *link = kmalloc(sizeof(*link), GFP_KERNEL); + + *work = kzalloc(sizeof(*work), GFP_KERNEL); + if (!(*work)) { + pr_err("Memory allocation failed for work_queue\n"); + return; + } + INIT_WORK(*work, work_fn); + + link->key = (void **)work; + mutex_lock(&mutex); + //point it to old first node + link->next = work_head; + + //point first to new first node + work_head = link; + mutex_unlock(&mutex); +} + +void init_delayed_work(void **work_args, void *work_fn, uint8_t hwa_id) +{ + struct delayed_work **work = (struct delayed_work **)work_args; + //create a link + struct node *link = kmalloc(sizeof(*link), GFP_KERNEL); + + *work = kzalloc(sizeof(*work), GFP_KERNEL); + if (!(*work)) { + pr_err("Memory allocation failed for delayed_work_queue\n"); + return; + } + INIT_DELAYED_WORK(*work, work_fn); + + link->key = (void **)work; + mutex_lock(&mutex); + //point it to old first node + link->next = delayed_work_head; + + //point first to new first node + delayed_work_head = link; + mutex_unlock(&mutex); +} + +/** + * get_work_buff - get_work_buff + * @key: key value + * @flag: flag + */ + +void *get_work_buff(void *key, signed char flag) +{ + struct node *data = NULL; + void *work_new = NULL; + struct node *temp = NULL; + struct node *previous = NULL; + struct work_struct **work = NULL; + + //start from the first link + mutex_lock(&mutex); + temp = work_head; + + //if list is empty + if (!work_head) { + mutex_unlock(&mutex); + return NULL; + } + + work = ((struct work_struct **)(temp->key)); + //navigate through list + while (*work != key) { + //if it is last node + if (!temp->next) { + mutex_unlock(&mutex); + return NULL; + } + //store reference to current link + previous = temp; + //move to next link + temp = temp->next; + work = ((struct work_struct **)(temp->key)); + } + + if (flag) { + //found a match, update the link + if (temp == work_head) { + //change first to point to next link + work_head = work_head->next; + } else { + //bypass the current link + previous->next = temp->next; + } + } + + mutex_unlock(&mutex); + //return temp; + data = temp; + if (data) { + work_new = data->key; + if (flag) + kfree(data); + } + return work_new; +} + +void *get_delayed_work_buff(void *key, signed char flag) +{ + struct node *data = NULL; + void *dwork_new = NULL; + struct node *temp = NULL; + struct node *previous = NULL; + struct delayed_work **dwork = NULL; + + if (flag) { + /* This Condition is true when kernel module is removed */ + return delayed_work_head; + } + //start from the first link + mutex_lock(&mutex); + temp = delayed_work_head; + + //if list is empty + if (!delayed_work_head) { + mutex_unlock(&mutex); + return NULL; + } + + dwork = ((struct delayed_work **)(temp->key)); + //navigate through list + while (&(*dwork)->work != key) { + //if it is last node + if (!temp->next) { + mutex_unlock(&mutex); + return NULL; + } + //store reference to current link + previous = temp; + //move to next link + temp = temp->next; + dwork = ((struct delayed_work **)(temp->key)); + } + + mutex_unlock(&mutex); + data = temp; + if (data) { + dwork_new = data->key; + if (flag) + kfree(data); + } + return dwork_new; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/common/work_queue.h b/drivers/media/platform/imagination/vxe-vxd/common/work_queue.h --- a/drivers/media/platform/imagination/vxe-vxd/common/work_queue.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/common/work_queue.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Work Queue Related Definitions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Prashanth Kumar Amai + */ + +#ifndef WORKQUEUE_H_ +#define WORKQUEUE_H_ + +#include + +enum { + HWA_DECODER = 0, + HWA_ENCODER = 1, + HWA_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * init_work - This function provides the necessary initialization + * and saving given pointer(work_args) in linked list. + * @work_args: structure for the initialization + * @work_fn: work function pointer + * + * This function provides the necessary initialization + * and setting of the handler function (passed by the user). + */ +void init_work(void **work_args, void *work_fn, uint8_t hwa_id); + +/* + * init_delayed_work - This function provides the necessary initialization. + * and saving given pointer(work_args) in linked list. + * @work_args: structure for the initialization + * @work_fn: work function pointer + * + * This function provides the necessary initialization + * and setting of the handler function (passed by the user). + */ +void init_delayed_work(void **work_args, void *work_fn, uint8_t hwa_id); + +/* + * get_delayed_work_buff - This function return base address of given pointer + * @key: The given work struct pointer + * @flag: If TRUE, delete the node from the linked list. + * + * Return: Base address of the given input buffer. + */ +void *get_delayed_work_buff(void *key, signed char flag); + +/** + * get_work_buff - This function return base address of given pointer + * @key: The given work struct pointer + * @flag: If TRUE, delete the node from the linked list. + * + * Return: Base address of the given input buffer. + */ +void *get_work_buff(void *key, signed char flag); + +#endif /* WORKQUEUE_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/bspp.c b/drivers/media/platform/imagination/vxe-vxd/decoder/bspp.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/bspp.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/bspp.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,2488 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VXD Bitstream Buffer Pre-Parser + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstreming + * Prashanth Kumar Amai + * Sidraya Jayagond + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "bspp.h" +#include "h264_secure_parser.h" +#include "hevc_secure_parser.h" +#ifdef HAS_JPEG +#include "jpeg_secure_parser.h" +#endif +#include "lst.h" +#include "swsr.h" +#include "vdecdd_defs.h" +#include "img_errors.h" + +#define BSPP_ERR_MSG_LENGTH 1024 + +/* + * This type defines the exception flag to catch the error if more catch block + * is required to catch different kind of error then more enum can be added + * @breif BSPP exception handler to catch the errors + */ +enum bspp_exception_handler { + /* BSPP parse exception handler */ + BSPP_EXCEPTION_HANDLER_NONE = 0x00, + /* Jump at exception (external use) */ + BSPP_EXCEPTION_HANDLER_JUMP, + BSPP_EXCEPTION_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This structure contains bitstream buffer information. + * @brief BSPP Bitstream Buffer Information + */ +struct bspp_bitstream_buffer { + void **lst_link; + struct bspp_ddbuf_info ddbuf_info; + unsigned int data_size; + unsigned int bufmap_id; + enum vdec_bstr_element_type bstr_element_type; + unsigned long long bytes_read; + void *pict_tag_param; +}; + +/* + * This structure contains shift-register state. + * @brief BSPP Shift-register State + */ +struct bspp_parse_ctx { + void *swsr_context; + enum swsr_exception exception; +}; + +/* + * This structure contains context for the current picture. + * @brief BSPP Picture Context + */ +struct bspp_pict_ctx { + struct bspp_sequence_hdr_info *sequ_hdr_info; + int closed_gop; + struct bspp_pict_hdr_info pict_hdr_info[VDEC_H264_MVC_MAX_VIEWS]; + struct bspp_sequence_hdr_info *ext_sequ_hdr_info; + int present; + int invalid; + int unsupported; + int finished; + unsigned int new_pict_signalled; +}; + +/* + * This structure contains resources allocated for the stream. + * @brief BSPP Stream Resource Allocations + */ +struct bspp_stream_alloc_data { + struct lst_t sequence_data_list[SEQUENCE_SLOTS]; + struct lst_t pps_data_list[PPS_SLOTS]; + struct lst_t available_sequence_list; + struct lst_t available_ppss_list; + struct lst_t raw_data_list_available; + struct lst_t raw_data_list_used; + struct lst_t vps_data_list[VPS_SLOTS]; + struct lst_t raw_sei_alloc_list; + struct lst_t available_vps_list; +}; + +struct bspp_raw_sei_alloc { + void **lst_link; + struct vdec_raw_bstr_data raw_sei_data; +}; + +/* + * This structure contains bitstream parsing state information for the current + * group of buffers. + * @brief BSPP Bitstream Parsing State Information + */ +struct bspp_grp_bstr_ctx { + enum vdec_vid_std vid_std; + int disable_mvc; + int delim_present; + void *swsr_context; + enum bspp_unit_type unit_type; + enum bspp_unit_type last_unit_type; + int not_pic_unit_yet; + int not_ext_pic_unit_yet; + unsigned int total_data_size; + unsigned int total_bytes_read; + struct lst_t buffer_chain; + struct lst_t in_flight_bufs; + struct lst_t *pre_pict_seg_list[3]; + struct lst_t *pict_seg_list[3]; + void **pict_tag_param_array[3]; + struct lst_t *segment_list; + void **pict_tag_param; + struct lst_t *free_segments; + unsigned int segment_offset; + int insert_start_code; + unsigned char start_code_suffix; + unsigned char current_view_idx; +}; + +/* + * This structure contains the stream context information. + * @brief BSPP Stream Context Information + */ +struct bspp_str_context { + enum vdec_vid_std vid_std; + int disable_mvc; + int full_scan; + int immediate_decode; + enum vdec_bstr_format bstr_format; + struct vdec_codec_config codec_config; + unsigned int user_str_id; + struct bspp_vid_std_features vid_std_features; + struct bspp_swsr_ctx swsr_ctx; + struct bspp_parser_callbacks parser_callbacks; + struct bspp_stream_alloc_data str_alloc; + unsigned int sequ_hdr_id; + unsigned char *sequ_hdr_info; + unsigned char *secure_sequence_info; + unsigned char *pps_info; + unsigned char *secure_pps_info; + unsigned char *raw_data; + struct bspp_grp_bstr_ctx grp_bstr_ctx; + struct bspp_parse_ctx parse_ctx; + struct bspp_inter_pict_data inter_pict_data; + struct lst_t decoded_pictures_list; + /* Mutex for secure access */ + struct mutex *bspp_mutex; + int intra_frame_closed_gop; + struct bspp_pict_ctx pict_ctx; + struct bspp_parse_state parse_state; + unsigned int max_dec_frame_buffering; +}; + +/* + * This structure contains the standard related parser functions. + * @brief BSPP Standard Related Functions + */ +struct bspp_parser_functions { + /* Pointer to standard-specific parser configuration function */ + bspp_cb_set_parser_config set_parser_config; + /* Pointer to standard-specific unit type determining function */ + bspp_cb_determine_unit_type determine_unit_type; +}; + +static struct bspp_parser_functions parser_fxns[VDEC_STD_MAX] = { + /* VDEC_STD_UNDEFINED */ + { .set_parser_config = NULL, .determine_unit_type = NULL }, + /* VDEC_STD_MPEG2 */ + { .set_parser_config = NULL, .determine_unit_type = NULL }, + /* VDEC_STD_MPEG4 */ + { .set_parser_config = NULL, .determine_unit_type = NULL }, + /* VDEC_STD_H263 */ + { .set_parser_config = NULL, .determine_unit_type = NULL }, + /* VDEC_STD_H264 */ + { .set_parser_config = bspp_h264_set_parser_config, + .determine_unit_type = bspp_h264_determine_unittype }, + /* VDEC_STD_VC1 */ + { .set_parser_config = NULL, .determine_unit_type = NULL }, + /* VDEC_STD_AVS */ + { .set_parser_config = NULL, .determine_unit_type = NULL }, + /* VDEC_STD_REAL */ + { .set_parser_config = NULL, .determine_unit_type = NULL }, + /* VDEC_STD_JPEG */ +#ifdef HAS_JPEG + { .set_parser_config = bspp_jpeg_setparser_config, + .determine_unit_type = bspp_jpeg_determine_unit_type }, +#else + { .set_parser_config = NULL, .determine_unit_type = NULL }, +#endif + /* VDEC_STD_VP6 */ + { .set_parser_config = NULL, .determine_unit_type = NULL }, + /* VDEC_STD_VP8 */ + { .set_parser_config = NULL, .determine_unit_type = NULL }, + /* VDEC_STD_SORENSON */ + { .set_parser_config = NULL, .determine_unit_type = NULL }, + /* VDEC_STD_HEVC */ + { .set_parser_config = bspp_hevc_set_parser_config, + .determine_unit_type = bspp_hevc_determine_unittype }, +}; + +/* + * @Function bspp_get_pps_hdr + * @Description Obtains the most recent PPS header of a given Id. + */ +struct bspp_pps_info *bspp_get_pps_hdr(void *str_res_handle, unsigned int pps_id) +{ + struct bspp_stream_alloc_data *alloc_data = + (struct bspp_stream_alloc_data *)str_res_handle; + + if (pps_id >= PPS_SLOTS || !alloc_data) + return NULL; + + return lst_last(&alloc_data->pps_data_list[pps_id]); +} + +/* + * @Function bspp_get_sequ_hdr + * @Description Obtains the most recent sequence header of a given Id. + */ +struct bspp_sequence_hdr_info *bspp_get_sequ_hdr(void *str_res_handle, + unsigned int sequ_id) +{ + struct bspp_stream_alloc_data *alloc_data = + (struct bspp_stream_alloc_data *)str_res_handle; + if (sequ_id >= SEQUENCE_SLOTS || !alloc_data) + return NULL; + + return lst_last(&alloc_data->sequence_data_list[sequ_id]); +} + +/* + * @Function bspp_free_bitstream_elem + * @Description Frees a bitstream chain element. + */ +static void bspp_free_bitstream_elem(struct bspp_bitstream_buffer *bstr_buf) +{ + memset(bstr_buf, 0, sizeof(struct bspp_bitstream_buffer)); + + kfree(bstr_buf); +} + +/* + * @Function bspp_create_segment + * @Description Constructs a bitstream segment for the current unit and adds + * it to the list. + */ +static int bspp_create_segment(struct bspp_grp_bstr_ctx *grp_btsr_ctx, + struct bspp_bitstream_buffer *cur_buf) +{ + struct bspp_bitstr_seg *segment; + unsigned int result; + + /* + * Only create a segment when data (not in a previous segment) has been + * parsed from the buffer. + */ + if (cur_buf->bytes_read != grp_btsr_ctx->segment_offset) { + /* Allocate a software shift-register context structure */ + segment = lst_removehead(grp_btsr_ctx->free_segments); + if (!segment) { + result = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + goto error; + } + memset(segment, 0, sizeof(struct bspp_bitstr_seg)); + + segment->bufmap_id = cur_buf->bufmap_id; + segment->data_size = (unsigned int)cur_buf->bytes_read + - grp_btsr_ctx->segment_offset; + segment->data_byte_offset = grp_btsr_ctx->segment_offset; + + if (cur_buf->bytes_read == cur_buf->data_size) { + /* This is the last segment in the buffer. */ + segment->bstr_seg_flag |= VDECDD_BSSEG_LASTINBUFF; + } + + /* + * Next segment will start part way through the buffer + * (current read position). + */ + grp_btsr_ctx->segment_offset = (unsigned int)cur_buf->bytes_read; + + if (grp_btsr_ctx->insert_start_code) { + segment->bstr_seg_flag |= VDECDD_BSSEG_INSERT_STARTCODE; + segment->start_code_suffix = grp_btsr_ctx->start_code_suffix; + grp_btsr_ctx->insert_start_code = 0; + } + + lst_add(grp_btsr_ctx->segment_list, segment); + + /* + * If multiple segments correspond to the same (picture) + * stream-unit, update it only the first time + */ + if (cur_buf->pict_tag_param && grp_btsr_ctx->pict_tag_param && + (grp_btsr_ctx->segment_list == + grp_btsr_ctx->pict_seg_list[0] || + grp_btsr_ctx->segment_list == + grp_btsr_ctx->pict_seg_list[1] || + grp_btsr_ctx->segment_list == + grp_btsr_ctx->pict_seg_list[2])) + *grp_btsr_ctx->pict_tag_param = cur_buf->pict_tag_param; + } + + return IMG_SUCCESS; +error: + return result; +} + +/* + * @Function bspp_DetermineUnitType + * + */ +static int bspp_determine_unit_type(enum vdec_vid_std vid_std, + unsigned char unit_type, + int disable_mvc, + enum bspp_unit_type *unit_type_enum) +{ + /* Determine the unit type from the NAL type. */ + if (vid_std < VDEC_STD_MAX && parser_fxns[vid_std].determine_unit_type) + parser_fxns[vid_std].determine_unit_type(unit_type, disable_mvc, unit_type_enum); + else + return IMG_ERROR_INVALID_PARAMETERS; + + return IMG_SUCCESS; +} + +/* + * @Function bspp_shift_reg_cb + * + */ +static void bspp_shift_reg_cb(enum swsr_cbevent event, + struct bspp_grp_bstr_ctx *grp_btsr_ctx, + unsigned char nal_type, + unsigned char **data_buffer, + unsigned long long *data_size) +{ + unsigned int result; + + switch (event) { + case SWSR_EVENT_INPUT_BUFFER_START: { + struct bspp_bitstream_buffer *next_buf; + + /* Take the next bitstream buffer for use in shift-register. */ + next_buf = lst_removehead(&grp_btsr_ctx->buffer_chain); + + if (next_buf && data_buffer && data_size) { + lst_add(&grp_btsr_ctx->in_flight_bufs, next_buf); + + *data_buffer = next_buf->ddbuf_info.cpu_virt_addr; + *data_size = next_buf->data_size; + + next_buf->bytes_read = 0; + } else { + goto error; + } + } + break; + case SWSR_EVENT_OUTPUT_BUFFER_END: { + struct bspp_bitstream_buffer *cur_buf; + + cur_buf = lst_removehead(&grp_btsr_ctx->in_flight_bufs); + + if (cur_buf) { + /* + * Indicate that the whole buffer content has been + * used. + */ + cur_buf->bytes_read = cur_buf->data_size; + grp_btsr_ctx->total_bytes_read += (unsigned int)cur_buf->bytes_read; + + /* + * Construct segment for current buffer and add to + * active list. + */ + result = bspp_create_segment(grp_btsr_ctx, cur_buf); + if (result != IMG_SUCCESS) + goto error; + + /* + * Next segment will start at the beginning of the next + * buffer. + */ + grp_btsr_ctx->segment_offset = 0; + + /* Destroy the bitstream element. */ + bspp_free_bitstream_elem(cur_buf); + } else { + goto error; + } + } + break; + + case SWSR_EVENT_DELIMITER_NAL_TYPE: + /* + * Initialise the unit type with the last (unclassified or + * unsupported types are not retained since they. + */ + grp_btsr_ctx->unit_type = grp_btsr_ctx->last_unit_type; + + /* + * Determine the unit type without consuming any data (start + * code) from shift-register. Segments are created automatically + * when a new buffer is requested by the shift-register so the + * unit type must be known in order to switch over the segment + * list. + */ + result = bspp_determine_unit_type(grp_btsr_ctx->vid_std, nal_type, + grp_btsr_ctx->disable_mvc, + &grp_btsr_ctx->unit_type); + + /* + * Only look to change bitstream segment list when the unit type + * is different and the current unit contains data that could be + * placed in a new list. + */ + if (grp_btsr_ctx->last_unit_type != grp_btsr_ctx->unit_type && + grp_btsr_ctx->unit_type != BSPP_UNIT_UNSUPPORTED && + grp_btsr_ctx->unit_type != BSPP_UNIT_UNCLASSIFIED) { + int prev_pict_data; + int curr_pict_data; + + prev_pict_data = (grp_btsr_ctx->last_unit_type == BSPP_UNIT_PICTURE || + grp_btsr_ctx->last_unit_type == + BSPP_UNIT_SKIP_PICTURE) ? 1 : 0; + + curr_pict_data = (grp_btsr_ctx->unit_type == BSPP_UNIT_PICTURE || + grp_btsr_ctx->unit_type == + BSPP_UNIT_SKIP_PICTURE) ? 1 : 0; + + /* + * When switching between picture and non-picture + * units. + */ + if ((prev_pict_data && !curr_pict_data) || + (!prev_pict_data && curr_pict_data)) { + /* + * Only delimit unit change when we're not the + * first unit and we're not already in the last + * segment list. + */ + if (grp_btsr_ctx->last_unit_type != BSPP_UNIT_NONE && + grp_btsr_ctx->segment_list != + grp_btsr_ctx->pict_seg_list[2]) { + struct bspp_bitstream_buffer *cur_buf = + lst_first(&grp_btsr_ctx->in_flight_bufs); + if (!cur_buf) + goto error; + + /* + * Update the offset within current buf. + */ + swsr_get_byte_offset_curbuf(grp_btsr_ctx->swsr_context, + &cur_buf->bytes_read); + + /* + * Create the last segment of the + * previous type (which may split a + * buffer into two). If the unit is + * exactly at the start of a buffer this + * will not create a zero-byte segment. + */ + result = bspp_create_segment(grp_btsr_ctx, cur_buf); + if (result != IMG_SUCCESS) + goto error; + } + + /* Point at the next segment list. */ + if (grp_btsr_ctx->segment_list + == grp_btsr_ctx->pre_pict_seg_list[0]) { + grp_btsr_ctx->segment_list = + grp_btsr_ctx->pict_seg_list[0]; + grp_btsr_ctx->pict_tag_param = + grp_btsr_ctx->pict_tag_param_array[0]; + } else if (grp_btsr_ctx->segment_list + == grp_btsr_ctx->pict_seg_list[0]) + grp_btsr_ctx->segment_list = + grp_btsr_ctx->pre_pict_seg_list[1]; + else if (grp_btsr_ctx->segment_list + == grp_btsr_ctx->pre_pict_seg_list[1]) { + grp_btsr_ctx->segment_list = + grp_btsr_ctx->pict_seg_list[1]; + grp_btsr_ctx->pict_tag_param = + grp_btsr_ctx->pict_tag_param_array[1]; + } else if (grp_btsr_ctx->segment_list + == grp_btsr_ctx->pict_seg_list[1]) + grp_btsr_ctx->segment_list = + grp_btsr_ctx->pre_pict_seg_list[2]; + else if (grp_btsr_ctx->segment_list + == grp_btsr_ctx->pre_pict_seg_list[2]) { + grp_btsr_ctx->segment_list = + grp_btsr_ctx->pict_seg_list[2]; + grp_btsr_ctx->pict_tag_param = + grp_btsr_ctx->pict_tag_param_array[2]; + } + } + + grp_btsr_ctx->last_unit_type = grp_btsr_ctx->unit_type; + } + break; + + default: + break; + } + +error: + return; +} + +/* + * @Function bspp_exception_handler + * + */ +static void bspp_exception_handler(enum swsr_exception exception, void *parse_ctx_handle) +{ + struct bspp_parse_ctx *parse_ctx = (struct bspp_parse_ctx *)parse_ctx_handle; + + /* Store the exception. */ + parse_ctx->exception = exception; + + switch (parse_ctx->exception) { + case SWSR_EXCEPT_NO_EXCEPTION: + break; + case SWSR_EXCEPT_ENCAPULATION_ERROR1: + break; + case SWSR_EXCEPT_ENCAPULATION_ERROR2: + break; + case SWSR_EXCEPT_ACCESS_INTO_SCP: + break; + case SWSR_EXCEPT_ACCESS_BEYOND_EOD: + break; + case SWSR_EXCEPT_EXPGOULOMB_ERROR: + break; + case SWSR_EXCEPT_WRONG_CODEWORD_ERROR: + break; + case SWSR_EXCEPT_NO_SCP: + break; + case SWSR_EXCEPT_INVALID_CONTEXT: + break; + + default: + break; + } + + /* Clear the exception. */ + swsr_check_exception(parse_ctx->swsr_context); +} + +/* + * @Function bspp_reset_sequence + * + */ +static void bspp_reset_sequence(struct bspp_str_context *str_ctx, + struct bspp_sequence_hdr_info *sequ_hdr_info) +{ + /* Temporarily store relevant sequence fields. */ + struct bspp_ddbuf_array_info aux_fw_sequence = sequ_hdr_info->fw_sequence; + void *aux_secure_sequence_info_hndl = sequ_hdr_info->secure_sequence_info; + + struct bspp_ddbuf_array_info *tmp = &sequ_hdr_info->fw_sequence; + + /* Reset all related structures. */ + memset(((unsigned char *)tmp->ddbuf_info.cpu_virt_addr + tmp->buf_offset), 0x00, + sequ_hdr_info->fw_sequence.buf_element_size); + + if (str_ctx->parser_callbacks.reset_data_cb) + str_ctx->parser_callbacks.reset_data_cb(BSPP_UNIT_SEQUENCE, + sequ_hdr_info->secure_sequence_info); + else + memset(aux_secure_sequence_info_hndl, 0, str_ctx->vid_std_features.seq_size); + + memset(sequ_hdr_info, 0, sizeof(*sequ_hdr_info)); + + /* Restore relevant sequence fields. */ + sequ_hdr_info->fw_sequence = aux_fw_sequence; + sequ_hdr_info->sequ_hdr_info.bufmap_id = aux_fw_sequence.ddbuf_info.bufmap_id; + sequ_hdr_info->sequ_hdr_info.buf_offset = aux_fw_sequence.buf_offset; + sequ_hdr_info->secure_sequence_info = aux_secure_sequence_info_hndl; +} + +/* + * @Function bspp_reset_pps + * + */ +static void bspp_reset_pps(struct bspp_str_context *str_ctx, + struct bspp_pps_info *pps_info) +{ + /* Temporarily store relevant PPS fields. */ + struct bspp_ddbuf_array_info aux_fw_pps = pps_info->fw_pps; + void *aux_secure_pps_info_hndl = pps_info->secure_pps_info; + struct bspp_ddbuf_array_info *tmp = &pps_info->fw_pps; + + /* Reset all related structures. */ + memset(((unsigned char *)tmp->ddbuf_info.cpu_virt_addr + tmp->buf_offset), 0x00, + pps_info->fw_pps.buf_element_size); + + /* Reset the parser specific data. */ + if (str_ctx->parser_callbacks.reset_data_cb) + str_ctx->parser_callbacks.reset_data_cb(BSPP_UNIT_PPS, pps_info->secure_pps_info); + + /* Reset the common data. */ + memset(pps_info, 0, sizeof(*pps_info)); + + /* Restore relevant PPS fields. */ + pps_info->fw_pps = aux_fw_pps; + pps_info->bufmap_id = aux_fw_pps.ddbuf_info.bufmap_id; + pps_info->buf_offset = aux_fw_pps.buf_offset; + pps_info->secure_pps_info = aux_secure_pps_info_hndl; +} + +/* + * @Function bspp_stream_submit_buffer + * + */ +int bspp_stream_submit_buffer(void *str_context_handle, + const struct bspp_ddbuf_info *ddbuf_info, + unsigned int bufmap_id, + unsigned int data_size, + void *pict_tag_param, + enum vdec_bstr_element_type bstr_element_type) +{ + struct bspp_str_context *str_ctx = (struct bspp_str_context *)str_context_handle; + struct bspp_bitstream_buffer *bstr_buf; + unsigned int result = IMG_SUCCESS; + + if (!str_context_handle) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + + if (bstr_element_type == VDEC_BSTRELEMENT_UNDEFINED || + bstr_element_type >= VDEC_BSTRELEMENT_MAX) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + + /* + * Check that the new bitstream buffer is compatible with those + * before. + */ + bstr_buf = lst_last(&str_ctx->grp_bstr_ctx.buffer_chain); + if (bstr_buf && bstr_buf->bstr_element_type != bstr_element_type) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + + /* Allocate a bitstream buffer chain element structure */ + bstr_buf = kmalloc(sizeof(*bstr_buf), GFP_KERNEL); + if (!bstr_buf) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + memset(bstr_buf, 0, sizeof(*bstr_buf)); + + /* Queue buffer in a chain since units might span buffers. */ + if (ddbuf_info) + bstr_buf->ddbuf_info = *ddbuf_info; + + bstr_buf->data_size = data_size; + bstr_buf->bstr_element_type = bstr_element_type; + bstr_buf->pict_tag_param = pict_tag_param; + bstr_buf->bufmap_id = bufmap_id; + lst_add(&str_ctx->grp_bstr_ctx.buffer_chain, bstr_buf); + + str_ctx->grp_bstr_ctx.total_data_size += data_size; + +error: + return result; +} + +/* + * @Function bspp_sequence_hdr_info + * + */ +static struct bspp_sequence_hdr_info *bspp_obtain_sequence_hdr(struct bspp_str_context *str_ctx) +{ + struct bspp_stream_alloc_data *str_alloc = &str_ctx->str_alloc; + struct bspp_sequence_hdr_info *sequ_hdr_info; + + /* + * Obtain any partially filled sequence data else provide a new one + * (always new for H.264 and HEVC) + */ + sequ_hdr_info = lst_last(&str_alloc->sequence_data_list[BSPP_DEFAULT_SEQUENCE_ID]); + if (!sequ_hdr_info || sequ_hdr_info->ref_count > 0 || str_ctx->vid_std == VDEC_STD_H264 || + str_ctx->vid_std == VDEC_STD_HEVC) { + /* Get Sequence resource. */ + sequ_hdr_info = lst_removehead(&str_alloc->available_sequence_list); + if (sequ_hdr_info) { + bspp_reset_sequence(str_ctx, sequ_hdr_info); + sequ_hdr_info->sequ_hdr_info.sequ_hdr_id = BSPP_INVALID; + } + } + + return sequ_hdr_info; +} + +/* + * @Function bspp_submit_picture_decoded + * + */ +int bspp_submit_picture_decoded(void *str_context_handle, + struct bspp_picture_decoded *picture_decoded) +{ + struct bspp_picture_decoded *picture_decoded_elem; + struct bspp_str_context *str_ctx = (struct bspp_str_context *)str_context_handle; + + /* Validate input arguments. */ + if (!str_context_handle) + return IMG_ERROR_INVALID_PARAMETERS; + + picture_decoded_elem = kmalloc(sizeof(*picture_decoded_elem), GFP_KERNEL); + if (!picture_decoded_elem) + return IMG_ERROR_MALLOC_FAILED; + + *picture_decoded_elem = *picture_decoded; + + /* Lock access to the list for adding a picture - HIGH PRIORITY */ + mutex_lock_nested(str_ctx->bspp_mutex, SUBCLASS_BSPP); + + lst_add(&str_ctx->decoded_pictures_list, picture_decoded_elem); + + /* Unlock access to the list for adding a picture - HIGH PRIORITY */ + mutex_unlock(str_ctx->bspp_mutex); + + return IMG_SUCCESS; +} + +/* + * @Function bspp_check_and_detach_pps_info + * + */ +static void bspp_check_and_detach_pps_info(struct bspp_stream_alloc_data *str_alloc, + unsigned int pps_id) +{ + if (pps_id != BSPP_INVALID) { + struct bspp_pps_info *pps_info = lst_first(&str_alloc->pps_data_list[pps_id]); + + if (!pps_info) /* Invalid id */ + return; + + pps_info->ref_count--; + /* If nothing references it any more */ + if (pps_info->ref_count == 0) { + struct bspp_pps_info *next_pps_info = lst_next(pps_info); + + /* + * If it is not the last sequence in the slot list + * remove it and return it to the pool-list + */ + if (next_pps_info) { + lst_remove(&str_alloc->pps_data_list[pps_id], pps_info); + lst_addhead(&str_alloc->available_ppss_list, pps_info); + } + } + } +} + +/* + * @Function bspp_picture_decoded + * + */ +static int bspp_picture_decoded(struct bspp_str_context *str_ctx, + struct bspp_picture_decoded *picture_decoded) +{ + struct bspp_stream_alloc_data *str_alloc = &str_ctx->str_alloc; + + /* Manage Sequence */ + if (picture_decoded->sequ_hdr_id != BSPP_INVALID) { + struct bspp_sequence_hdr_info *seq = + lst_first(&str_alloc->sequence_data_list[picture_decoded->sequ_hdr_id]); + + if (!seq) + return IMG_ERROR_INVALID_ID; + + if (picture_decoded->not_decoded) { + /* Release sequence data. */ + if (str_ctx->parser_callbacks.release_data_cb) + str_ctx->parser_callbacks.release_data_cb((void *)str_alloc, + BSPP_UNIT_SEQUENCE, seq->secure_sequence_info); + } + + seq->ref_count--; + /* If nothing references it any more */ + if (seq->ref_count == 0) { + struct bspp_sequence_hdr_info *next_sequ_hdr_info = lst_next(seq); + + /* + * If it is not the last sequence in the slot list + * remove it and return it to the pool-list + */ + if (next_sequ_hdr_info) { + lst_remove(&str_alloc->sequence_data_list + [picture_decoded->sequ_hdr_id], seq); + /* Release sequence data. */ + if (str_ctx->parser_callbacks.release_data_cb) + str_ctx->parser_callbacks.release_data_cb((void *)str_alloc, + BSPP_UNIT_SEQUENCE, seq->secure_sequence_info); + + lst_addhead(&str_alloc->available_sequence_list, seq); + } + } + } + + /* + * Expect at least one valid PPS for H.264 and always invalid for all + * others + */ + bspp_check_and_detach_pps_info(str_alloc, picture_decoded->pps_id); + bspp_check_and_detach_pps_info(str_alloc, picture_decoded->second_pps_id); + + return IMG_SUCCESS; +} + +/* + * @Function bspp_service_pictures_decoded + * + */ +static int bspp_service_pictures_decoded(struct bspp_str_context *str_ctx) +{ + struct bspp_picture_decoded *picture_decoded; + + while (1) { + /* + * Lock access to the list for removing a picture - + * LOW PRIORITY + */ + mutex_lock_nested(str_ctx->bspp_mutex, SUBCLASS_BSPP); + + picture_decoded = lst_removehead(&str_ctx->decoded_pictures_list); + + /* + * Unlock access to the list for removing a picture - + * LOW PRIORITY + */ + mutex_unlock(str_ctx->bspp_mutex); + + if (!picture_decoded) + break; + + bspp_picture_decoded(str_ctx, picture_decoded); + kfree(picture_decoded); + } + + return IMG_SUCCESS; +} + +static void bspp_remove_unused_vps(struct bspp_str_context *str_ctx, unsigned int vps_id) +{ + struct bspp_stream_alloc_data *str_alloc = &str_ctx->str_alloc; + struct bspp_vps_info *temp_vps_info = NULL; + struct bspp_vps_info *next_temp_vps_info = NULL; + + /* + * Check the whole Vps slot list for any unused Vpss + * BEFORE ADDING THE NEW ONE, if found remove them + */ + next_temp_vps_info = lst_first(&str_alloc->vps_data_list[vps_id]); + while (next_temp_vps_info) { + /* Set Temp, it is the one which we will potentially remove */ + temp_vps_info = next_temp_vps_info; + /* + * Set Next Temp, it is the one for the next iteration + * (we cannot ask for next after removing it) + */ + next_temp_vps_info = lst_next(temp_vps_info); + /* If it is not used remove it */ + if (temp_vps_info->ref_count == 0 && next_temp_vps_info) { + /* Return resource to the available pool */ + lst_remove(&str_alloc->vps_data_list[vps_id], temp_vps_info); + lst_addhead(&str_alloc->available_vps_list, temp_vps_info); + } + } +} + +static void bspp_remove_unused_pps(struct bspp_str_context *str_ctx, unsigned int pps_id) +{ + struct bspp_stream_alloc_data *str_alloc = &str_ctx->str_alloc; + struct bspp_pps_info *temp_pps_info = NULL; + struct bspp_pps_info *next_temp_pps_info = NULL; + + /* + * Check the whole PPS slot list for any unused PPSs BEFORE ADDING + * THE NEW ONE, if found remove them + */ + next_temp_pps_info = lst_first(&str_alloc->pps_data_list[pps_id]); + while (next_temp_pps_info) { + /* Set Temp, it is the one which we will potentially remove */ + temp_pps_info = next_temp_pps_info; + /* + * Set Next Temp, it is the one for the next iteration + * (we cannot ask for next after removing it) + */ + next_temp_pps_info = lst_next(temp_pps_info); + /* If it is not used remove it */ + if (temp_pps_info->ref_count == 0 && next_temp_pps_info) { + /* Return resource to the available pool */ + lst_remove(&str_alloc->pps_data_list[pps_id], temp_pps_info); + lst_addhead(&str_alloc->available_ppss_list, temp_pps_info); + } + } +} + +static void bspp_remove_unused_sequence(struct bspp_str_context *str_ctx, unsigned int sps_id) +{ + struct bspp_stream_alloc_data *str_alloc = &str_ctx->str_alloc; + struct bspp_sequence_hdr_info *seq = NULL; + struct bspp_sequence_hdr_info *next_seq = NULL; + + /* + * Check the whole sequence slot list for any unused sequences, + * if found remove them + */ + next_seq = lst_first(&str_alloc->sequence_data_list[sps_id]); + while (next_seq) { + /* Set Temp, it is the one which we will potentially remove */ + seq = next_seq; + /* + * Set Next Temp, it is the one for the next iteration (we + * cannot ask for next after removing it) + */ + next_seq = lst_next(seq); + + /* + * If the head is no longer used and there is something after, + * remove it + */ + if (seq->ref_count == 0 && next_seq) { + /* Return resource to the pool-list */ + lst_remove(&str_alloc->sequence_data_list[sps_id], seq); + if (str_ctx->parser_callbacks.release_data_cb) { + str_ctx->parser_callbacks.release_data_cb + ((void *)str_alloc, + BSPP_UNIT_SEQUENCE, + seq->secure_sequence_info); + } + lst_addhead(&str_alloc->available_sequence_list, seq); + } + } +} + +/* + * @Function bspp_return_or_store_sequence_hdr + * + */ +static int bspp_return_or_store_sequence_hdr(struct bspp_str_context *str_ctx, + enum bspp_error_type parse_error, + struct bspp_sequence_hdr_info *sequ_hdr_info) +{ + struct bspp_stream_alloc_data *str_alloc = &str_ctx->str_alloc; + struct bspp_sequence_hdr_info *prev_sequ_hdr_info; + + if (((parse_error & BSPP_ERROR_UNRECOVERABLE) || (parse_error & BSPP_ERROR_UNSUPPORTED)) && + sequ_hdr_info->sequ_hdr_info.sequ_hdr_id != BSPP_INVALID) { + prev_sequ_hdr_info = + lst_last(&str_alloc->sequence_data_list + [sequ_hdr_info->sequ_hdr_info.sequ_hdr_id]); + + /* check if it's not the same pointer */ + if (prev_sequ_hdr_info && prev_sequ_hdr_info != sequ_hdr_info) { + /* + * Throw away corrupted sequence header if a previous "good" one exists. + */ + sequ_hdr_info->sequ_hdr_info.sequ_hdr_id = BSPP_INVALID; + } + } + + /* Store or return Sequence resource. */ + if (sequ_hdr_info->sequ_hdr_info.sequ_hdr_id != BSPP_INVALID) { + /* Only add when not already in list. */ + if (sequ_hdr_info != lst_last(&str_alloc->sequence_data_list + [sequ_hdr_info->sequ_hdr_info.sequ_hdr_id])) { + /* + * Add new sequence header (not already in list) to end + * of the slot-list. + */ + lst_add(&str_alloc->sequence_data_list + [sequ_hdr_info->sequ_hdr_info.sequ_hdr_id], sequ_hdr_info); + } + + bspp_remove_unused_sequence(str_ctx, sequ_hdr_info->sequ_hdr_info.sequ_hdr_id); + } else { + /* + * if unit was not a sequnce info, add resource to the + * pool-list + */ + lst_addhead(&str_alloc->available_sequence_list, sequ_hdr_info); + } + + return IMG_SUCCESS; +} + +/* + * @Function bspp_get_resource + * + */ +static int bspp_get_resource(struct bspp_str_context *str_ctx, + struct bspp_pict_hdr_info *pict_hdr_info, + struct bspp_unit_data *unit_data) +{ + int result = IMG_SUCCESS; + struct bspp_stream_alloc_data *str_alloc = &str_ctx->str_alloc; + + switch (unit_data->unit_type) { + case BSPP_UNIT_VPS: + /* Get VPS resource (HEVC only). */ + if (unit_data->vid_std != VDEC_STD_HEVC) + break; + unit_data->out.vps_info = lst_removehead(&str_alloc->available_vps_list); + if (!unit_data->out.vps_info) { + result = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + } else { + unit_data->out.vps_info->vps_id = BSPP_INVALID; + unit_data->out.vps_info->ref_count = 0; + } + break; + case BSPP_UNIT_SEQUENCE: + unit_data->out.sequ_hdr_info = bspp_obtain_sequence_hdr(str_ctx); + if (!unit_data->out.sequ_hdr_info) + result = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + + break; + + case BSPP_UNIT_PPS: + /* Get PPS resource (H.264 only). */ + unit_data->out.pps_info = lst_removehead(&str_alloc->available_ppss_list); + /* allocate and return extra resources */ + if (!unit_data->out.pps_info) { + result = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + } else { + bspp_reset_pps(str_ctx, unit_data->out.pps_info); + unit_data->out.pps_info->pps_id = BSPP_INVALID; + } + break; + + case BSPP_UNIT_PICTURE: + case BSPP_UNIT_SKIP_PICTURE: + unit_data->out.pict_hdr_info = pict_hdr_info; +#ifdef HAS_JPEG + if (unit_data->vid_std == VDEC_STD_JPEG) { + unit_data->impl_sequ_hdr_info = bspp_obtain_sequence_hdr(str_ctx); + if (!unit_data->impl_sequ_hdr_info) + result = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + } +#endif + break; + + default: + break; + } + + return result; +} + +/* + * @Function bspp_file_resource + * @Description Stores or returns all resources provided to parse unit. + */ +static int bspp_file_resource(struct bspp_str_context *str_ctx, struct bspp_unit_data *unit_data) +{ + unsigned int result = IMG_SUCCESS; + struct bspp_stream_alloc_data *str_alloc = &str_ctx->str_alloc; + + switch (unit_data->unit_type) { + case BSPP_UNIT_VPS: + /* Store or return VPS resource (HEVC only) */ + if (unit_data->vid_std != VDEC_STD_HEVC) + break; + + if (unit_data->out.vps_info->vps_id != BSPP_INVALID) { + lst_add(&str_alloc->vps_data_list[unit_data->out.vps_info->vps_id], + unit_data->out.vps_info); + + bspp_remove_unused_vps(str_ctx, unit_data->out.vps_info->vps_id); + } else { + lst_addhead(&str_alloc->available_vps_list, unit_data->out.vps_info); + } + break; + case BSPP_UNIT_SEQUENCE: + result = bspp_return_or_store_sequence_hdr(str_ctx, unit_data->parse_error, + unit_data->out.sequ_hdr_info); + VDEC_ASSERT(result == IMG_SUCCESS); + break; + + case BSPP_UNIT_PPS: + /* Store or return PPS resource (H.264 only). */ + if (unit_data->out.pps_info->pps_id != BSPP_INVALID) { + /* + * if unit was a PPS info, add resource to the slot-list + * AFTER REMOVING THE UNUSED ONES otherwise this will be + * removed along the rest unless special provision for + * last is made + */ + lst_add(&str_alloc->pps_data_list[unit_data->out.pps_info->pps_id], + unit_data->out.pps_info); + + bspp_remove_unused_pps(str_ctx, unit_data->out.pps_info->pps_id); + } else { + /* + * if unit was not a PPS info, add resource to the + * pool-list + */ + lst_addhead(&str_alloc->available_ppss_list, unit_data->out.pps_info); + } + break; + + case BSPP_UNIT_PICTURE: + case BSPP_UNIT_SKIP_PICTURE: +#ifdef HAS_JPEG + if (unit_data->vid_std == VDEC_STD_JPEG) { + result = bspp_return_or_store_sequence_hdr(str_ctx, + unit_data->parse_error, + unit_data->impl_sequ_hdr_info); + VDEC_ASSERT(result == IMG_SUCCESS); + } +#endif + break; + + default: + break; + } + + return result; +} + +/* + * @Function bspp_process_unit + * + */ +static int bspp_process_unit(struct bspp_str_context *str_ctx, + unsigned int size_delim_bits, + struct bspp_pict_ctx *pict_ctx, + struct bspp_parse_state *parse_state) +{ + struct bspp_unit_data unit_data; + unsigned long long unit_size = 0; /* Unit size (in bytes, size delimited only). */ + unsigned int result; + unsigned char vidx = str_ctx->grp_bstr_ctx.current_view_idx; + struct bspp_pict_hdr_info *curr_pict_hdr_info; + + /* + * during call to swsr_consume_delim(), above. + * Setup default unit data. + */ + memset(&unit_data, 0, sizeof(struct bspp_unit_data)); + + if (str_ctx->grp_bstr_ctx.delim_present) { + /* Consume delimiter and catch any exceptions. */ + /* + * Consume the bitstream unit delimiter (size or + * start code prefix). + * When size-delimited the unit size is also returned + * so that the next unit can be found. + */ + result = swsr_consume_delim(str_ctx->swsr_ctx.swsr_context, + str_ctx->swsr_ctx.emulation_prevention, + size_delim_bits, &unit_size); + if (result != IMG_SUCCESS) + goto error; + } + + unit_data.unit_type = str_ctx->grp_bstr_ctx.unit_type; + unit_data.vid_std = str_ctx->vid_std; + unit_data.delim_present = str_ctx->grp_bstr_ctx.delim_present; + unit_data.codec_config = &str_ctx->codec_config; + unit_data.parse_state = parse_state; + unit_data.pict_sequ_hdr_id = str_ctx->sequ_hdr_id; + unit_data.str_res_handle = &str_ctx->str_alloc; + unit_data.unit_data_size = str_ctx->grp_bstr_ctx.total_data_size; + unit_data.intra_frm_as_closed_gop = str_ctx->intra_frame_closed_gop; + + unit_data.max_dec_frame_buffering = str_ctx->max_dec_frame_buffering; + + /* ponit to picture headers, check boundaries */ + curr_pict_hdr_info = vidx < VDEC_H264_MVC_MAX_VIEWS ? + &pict_ctx->pict_hdr_info[vidx] : NULL; + unit_data.parse_state->next_pict_hdr_info = + vidx + 1 < VDEC_H264_MVC_MAX_VIEWS ? + &pict_ctx->pict_hdr_info[vidx + 1] : NULL; + unit_data.parse_state->is_prefix = 0; + + /* Obtain output data containers. */ + result = bspp_get_resource(str_ctx, curr_pict_hdr_info, &unit_data); + if (result != IMG_SUCCESS) + return result; + + /* Process Unit and catch any exceptions. */ + /* + * Call the standard-specific function to parse the bitstream + * unit. + */ + result = str_ctx->parser_callbacks.parse_unit_cb(str_ctx->swsr_ctx.swsr_context, + &unit_data); + if (result != IMG_SUCCESS) { + pr_err("Failed to process unit, error = %d", unit_data.parse_error); + goto error; + } + + if (unit_data.parse_error != BSPP_ERROR_NONE) + pr_err("Issues found while processing unit, error = %d\n", unit_data.parse_error); + + /* Store or return resource used for parsing unit. */ + result = bspp_file_resource(str_ctx, &unit_data); + + if (!str_ctx->inter_pict_data.seen_closed_gop && + str_ctx->grp_bstr_ctx.unit_type == BSPP_UNIT_PICTURE && + unit_data.slice && + (unit_data.out.pict_hdr_info && + unit_data.out.pict_hdr_info->intra_coded) && + str_ctx->vid_std != VDEC_STD_H264) + unit_data.new_closed_gop = 1; + + if (unit_data.new_closed_gop) { + str_ctx->inter_pict_data.seen_closed_gop = 1; + str_ctx->inter_pict_data.new_closed_gop = 1; + } + + /* + * Post-process unit (use local context in case + * parse function tried to change the unit type. + */ + if (str_ctx->grp_bstr_ctx.unit_type == BSPP_UNIT_PICTURE || + str_ctx->grp_bstr_ctx.unit_type == BSPP_UNIT_SKIP_PICTURE) { + if (str_ctx->inter_pict_data.new_closed_gop) { + pict_ctx->closed_gop = 1; + str_ctx->inter_pict_data.new_closed_gop = 0; + } + + if (unit_data.ext_slice && str_ctx->grp_bstr_ctx.not_ext_pic_unit_yet && + unit_data.pict_sequ_hdr_id != BSPP_INVALID) { + unsigned int id = unit_data.pict_sequ_hdr_id; + + str_ctx->grp_bstr_ctx.not_ext_pic_unit_yet = 0; + pict_ctx->ext_sequ_hdr_info = + lst_last(&str_ctx->str_alloc.sequence_data_list[id]); + } + + if (unit_data.slice) { + if (!curr_pict_hdr_info) { + VDEC_ASSERT(0); + return -EINVAL; + } + if (str_ctx->grp_bstr_ctx.not_pic_unit_yet && + unit_data.pict_sequ_hdr_id != BSPP_INVALID) { + str_ctx->grp_bstr_ctx.not_pic_unit_yet = 0; + + /* + * depend upon the picture header being + * populated (in addition to slice data). + */ + pict_ctx->present = 1; + + /* + * Update the picture context from the last unit parsed. + * This context must be stored since a non-picture unit may follow. + * Obtain current instance of sequence data for given ID. + */ + if (!pict_ctx->sequ_hdr_info) { + unsigned int id = unit_data.pict_sequ_hdr_id; + + pict_ctx->sequ_hdr_info = + lst_last(&str_ctx->str_alloc.sequence_data_list[id]); + + /* Do the sequence flagging/reference-counting */ + pict_ctx->sequ_hdr_info->ref_count++; + } + + /* Override the field here. */ + if (str_ctx->swsr_ctx.sr_config.delim_type == SWSR_DELIM_NONE) { + if (str_ctx->grp_bstr_ctx.unit_type == + BSPP_UNIT_SKIP_PICTURE) { + /* VDECFW_SKIPPED_PICTURE; */ + curr_pict_hdr_info->parser_mode = + VDECFW_SKIPPED_PICTURE; + curr_pict_hdr_info->pic_data_size = 0; + } else { + /* VDECFW_SIZE_SIDEBAND; */ + curr_pict_hdr_info->parser_mode = + VDECFW_SIZE_SIDEBAND; + curr_pict_hdr_info->pic_data_size = + str_ctx->grp_bstr_ctx.total_data_size; + } + } else if (str_ctx->swsr_ctx.sr_config.delim_type == + SWSR_DELIM_SIZE) { + if (str_ctx->swsr_ctx.sr_config.delim_length <= 8) + /* VDECFW_SIZE_DELIMITED_1_ONLY; */ + curr_pict_hdr_info->parser_mode = + VDECFW_SIZE_DELIMITED_1_ONLY; + else if (str_ctx->swsr_ctx.sr_config.delim_length <= 16) + /* VDECFW_SIZE_DELIMITED_2_ONLY; */ + curr_pict_hdr_info->parser_mode = + VDECFW_SIZE_DELIMITED_2_ONLY; + else if (str_ctx->swsr_ctx.sr_config.delim_length <= 32) + /* VDECFW_SIZE_DELIMITED_4_ONLY; */ + curr_pict_hdr_info->parser_mode = + VDECFW_SIZE_DELIMITED_4_ONLY; + + curr_pict_hdr_info->pic_data_size += + ((unsigned int)unit_size + + (size_delim_bits / 8)); + } else if (str_ctx->swsr_ctx.sr_config.delim_type == SWSR_DELIM_SCP) + /* VDECFW_SCP_ONLY; */ + curr_pict_hdr_info->parser_mode = VDECFW_SCP_ONLY; + } + + /* + * for MVC, the Slice Extension should also have the + * same ParserMode as the Base view. + */ + if (unit_data.parse_state->next_pict_hdr_info) { + unit_data.parse_state->next_pict_hdr_info->parser_mode = + curr_pict_hdr_info->parser_mode; + } + + if (unit_data.parse_error & BSPP_ERROR_UNSUPPORTED) { + pict_ctx->invalid = 1; + pict_ctx->unsupported = 1; + } else if (!str_ctx->full_scan) { + /* + * Only parse up to and including the first + * valid video slice unless full scanning. + */ + pict_ctx->finished = 1; + } + } + } + + if (unit_data.extracted_all_data) { + enum swsr_found found; + + swsr_byte_align(str_ctx->swsr_ctx.swsr_context); + + found = swsr_check_delim_or_eod(str_ctx->swsr_ctx.swsr_context); + if (found != SWSR_FOUND_DELIM && found != SWSR_FOUND_EOD) { + /* + * Should already be at the next delimiter or EOD. + * Any bits left at the end of the unit could indicate + * corrupted syntax or erroneous parsing. + */ + } + } + + return IMG_SUCCESS; + +error: + if (unit_data.unit_type == BSPP_UNIT_PICTURE || + unit_data.unit_type == BSPP_UNIT_SKIP_PICTURE) + pict_ctx->invalid = 1; + + /* + * Tidy-up resources. + * Store or return resource used for parsing unit. + */ + bspp_file_resource(str_ctx, &unit_data); + + return result; +} + +/* + * @Function bspp_terminate_buffer + * + */ +static int bspp_terminate_buffer(struct bspp_grp_bstr_ctx *grp_btsr_ctx, + struct bspp_bitstream_buffer *buf) +{ + int result = -1; + + /* Indicate that all the data in buffer should be added to segment. */ + buf->bytes_read = buf->data_size; + + result = bspp_create_segment(grp_btsr_ctx, buf); + if (result != IMG_SUCCESS) + return result; + + /* Next segment will start at the beginning of the next buffer. */ + grp_btsr_ctx->segment_offset = 0; + + bspp_free_bitstream_elem(buf); + + return result; +} + +/* + * @Function bspp_jump_to_next_view + * + */ +static int bspp_jump_to_next_view(struct bspp_grp_bstr_ctx *grp_btsr_ctx, + struct bspp_preparsed_data *preparsed_data, + struct bspp_parse_state *parse_state) +{ + struct bspp_bitstream_buffer *cur_buf; + int result; + unsigned int i; + unsigned char vidx; + + if (!grp_btsr_ctx || !parse_state || !preparsed_data) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + + vidx = grp_btsr_ctx->current_view_idx; + + if (vidx >= VDEC_H264_MVC_MAX_VIEWS) { + result = IMG_ERROR_NOT_SUPPORTED; + goto error; + } + + /* get current buffer */ + cur_buf = (struct bspp_bitstream_buffer *)lst_first(&grp_btsr_ctx->in_flight_bufs); + if (!cur_buf) { + result = IMG_ERROR_CANCELLED; + goto error; + } + + if (cur_buf->bufmap_id != parse_state->prev_buf_map_id) { + /* + * If we moved to the next buffer while parsing the slice + * header of the new view we have to reduce the size of + * the last segment up to the beginning of the new view slice + * and create a new segment from that point up to the end of + * the buffer. The new segment should belong to the new view. + * THIS ONLY WORKS IF THE SLICE HEADER DOES NOT SPAN MORE THAN + * TWO BUFFERS. If we want to support the case that the slice + * header of the new view spans multiple buffer we either have + * here remove all the segments up to the point were we find + * the buffer we are looking for, then adjust the size of this + * segment and then add the segments we removed to the next + * view list or we can implement a mechanism like the one that + * peeks for the NAL unit type and delimit the next view + * segment before parsing the first slice of the view. + */ + struct bspp_bitstr_seg *segment; + + segment = lst_last(grp_btsr_ctx->segment_list); + if (segment && segment->bufmap_id == parse_state->prev_buf_map_id) { + struct bspp_bitstream_buffer prev_buf; + + segment->data_size -= parse_state->prev_buf_data_size + - parse_state->prev_byte_offset_buf; + segment->bstr_seg_flag &= ~VDECDD_BSSEG_LASTINBUFF; + + /* + * Change the segmenOffset value with the value it + * would have if we had delemited the segment correctly + * beforehand. + */ + grp_btsr_ctx->segment_offset = parse_state->prev_byte_offset_buf; + + /* set lists of segments to new view... */ + for (i = 0; i < BSPP_MAX_PICTURES_PER_BUFFER; i++) { + grp_btsr_ctx->pre_pict_seg_list[i] = + &preparsed_data->ext_pictures_data[vidx].pre_pict_seg_list + [i]; + grp_btsr_ctx->pict_seg_list[i] = + &preparsed_data->ext_pictures_data[vidx].pict_seg_list[i]; + + lst_init(grp_btsr_ctx->pre_pict_seg_list[i]); + lst_init(grp_btsr_ctx->pict_seg_list[i]); + } + /* and current segment list */ + grp_btsr_ctx->segment_list = grp_btsr_ctx->pict_seg_list[0]; + + memset(&prev_buf, 0, sizeof(struct bspp_bitstream_buffer)); + prev_buf.bufmap_id = segment->bufmap_id; + prev_buf.data_size = parse_state->prev_buf_data_size; + prev_buf.bytes_read = prev_buf.data_size; + + /* Create the segment the first part of the next view */ + result = bspp_create_segment(grp_btsr_ctx, &prev_buf); + if (result != IMG_SUCCESS) + goto error; + } else { + result = IMG_ERROR_NOT_SUPPORTED; + goto error; + } + } else { + /* + * the data just parsed belongs to new view, so use previous byte + * offset + */ + cur_buf->bytes_read = parse_state->prev_byte_offset_buf; + + /* Create the segment for previous view */ + result = bspp_create_segment(grp_btsr_ctx, cur_buf); + if (result != IMG_SUCCESS) + goto error; + + /* set lists of segments to new view */ + for (i = 0; i < BSPP_MAX_PICTURES_PER_BUFFER; i++) { + grp_btsr_ctx->pre_pict_seg_list[i] = + &preparsed_data->ext_pictures_data[vidx].pre_pict_seg_list[i]; + grp_btsr_ctx->pict_seg_list[i] = + &preparsed_data->ext_pictures_data[vidx].pict_seg_list[i]; + + lst_init(grp_btsr_ctx->pre_pict_seg_list[i]); + lst_init(grp_btsr_ctx->pict_seg_list[i]); + } + /* and current segment list */ + grp_btsr_ctx->segment_list = grp_btsr_ctx->pict_seg_list[0]; + } + + /* update prefix flag */ + preparsed_data->ext_pictures_data[vidx].is_prefix = parse_state->is_prefix; + /* and view index */ + grp_btsr_ctx->current_view_idx++; + + /* set number of extended pictures */ + preparsed_data->num_ext_pictures = grp_btsr_ctx->current_view_idx; + +error: + return result; +} + +static void bspp_reset_pict_state(struct bspp_str_context *str_ctx, struct bspp_pict_ctx *pict_ctx, + struct bspp_parse_state *parse_state) +{ + memset(pict_ctx, 0, sizeof(struct bspp_pict_ctx)); + memset(parse_state, 0, sizeof(struct bspp_parse_state)); + + /* Setup group buffer processing state. */ + parse_state->inter_pict_ctx = &str_ctx->inter_pict_data; + parse_state->prev_bottom_pic_flag = (unsigned char)BSPP_INVALID; + parse_state->next_pic_is_new = 1; + parse_state->prev_frame_num = BSPP_INVALID; + parse_state->second_field_flag = 0; + parse_state->first_chunk = 1; +} + +/* + * @Function bspp_stream_preparse_buffers + * @Description Buffer list cannot be processed since units in this last buffer + * may not be complete. Must wait until a buffer is provided with end-of-picture + * signalled. When the buffer indicates that units won't span then we can + * process the bitstream buffer chain. + */ +int bspp_stream_preparse_buffers(void *str_context_handle, + const struct bspp_ddbuf_info *contig_buf_info, + unsigned int contig_buf_map_id, struct lst_t *segments, + struct bspp_preparsed_data *preparsed_data, + int end_of_pic) +{ + struct bspp_str_context *str_ctx = (struct bspp_str_context *)str_context_handle; + struct bspp_pict_ctx *pict_ctx = &str_ctx->pict_ctx; + struct bspp_parse_state *parse_state = &str_ctx->parse_state; + int i; + unsigned int unit_count = 0, num_arrays = 0; + unsigned int size_delim_bits = 0; + enum swsr_found found = SWSR_FOUND_NONE; + unsigned int result; + struct bspp_bitstr_seg *segment; + struct lst_t temp_list; + + /* + * since it is new picture, resetting the context status to + * beginning + */ + /* TODO: revisit this */ + pict_ctx->finished = 0; + pict_ctx->new_pict_signalled = 0; + + if (!str_context_handle) + return IMG_ERROR_INVALID_PARAMETERS; + + if (!segments || !preparsed_data) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Check that bitstream buffers have been registered. */ + if (!lst_last(&str_ctx->grp_bstr_ctx.buffer_chain)) + return IMG_ERROR_OPERATION_PROHIBITED; + + /* Initialise the output data. */ + memset(preparsed_data, 0, sizeof(struct bspp_preparsed_data)); + + if (!parse_state->initialised) { + bspp_reset_pict_state(str_ctx, pict_ctx, parse_state); + parse_state->initialised = 1; + } + + for (i = 0; i < 3; i++) { + lst_init(&preparsed_data->picture_data.pre_pict_seg_list[i]); + lst_init(&preparsed_data->picture_data.pict_seg_list[i]); + } + + /* Initialise parsing for this video standard. */ + if (str_ctx->parser_callbacks.initialise_parsing_cb && parse_state->first_chunk) + str_ctx->parser_callbacks.initialise_parsing_cb(parse_state); + + parse_state->first_chunk = 0; + + for (i = 0; i < VDEC_H264_MVC_MAX_VIEWS; i++) { + pict_ctx->pict_hdr_info[i].pict_aux_data.id = BSPP_INVALID; + pict_ctx->pict_hdr_info[i].second_pict_aux_data.id = BSPP_INVALID; + } + + /* Setup buffer group bitstream context. */ + str_ctx->grp_bstr_ctx.vid_std = str_ctx->vid_std; + str_ctx->grp_bstr_ctx.disable_mvc = str_ctx->disable_mvc; + str_ctx->grp_bstr_ctx.delim_present = 1; + str_ctx->grp_bstr_ctx.swsr_context = str_ctx->swsr_ctx.swsr_context; + str_ctx->grp_bstr_ctx.unit_type = BSPP_UNIT_NONE; + str_ctx->grp_bstr_ctx.last_unit_type = BSPP_UNIT_NONE; + str_ctx->grp_bstr_ctx.not_pic_unit_yet = 1; + str_ctx->grp_bstr_ctx.not_ext_pic_unit_yet = 1; + str_ctx->grp_bstr_ctx.total_bytes_read = 0; + str_ctx->grp_bstr_ctx.current_view_idx = 0; + + for (i = 0; i < 3; i++) { + str_ctx->grp_bstr_ctx.pre_pict_seg_list[i] = + &preparsed_data->picture_data.pre_pict_seg_list[i]; + str_ctx->grp_bstr_ctx.pict_seg_list[i] = + &preparsed_data->picture_data.pict_seg_list[i]; + str_ctx->grp_bstr_ctx.pict_tag_param_array[i] = + &preparsed_data->picture_data.pict_tag_param[i]; + } + str_ctx->grp_bstr_ctx.segment_list = str_ctx->grp_bstr_ctx.pre_pict_seg_list[0]; + str_ctx->grp_bstr_ctx.pict_tag_param = str_ctx->grp_bstr_ctx.pict_tag_param_array[0]; + str_ctx->grp_bstr_ctx.free_segments = segments; + str_ctx->grp_bstr_ctx.segment_offset = 0; + str_ctx->grp_bstr_ctx.insert_start_code = 0; + + /* + * Before processing the units service all the picture decoded events + * to free the resources1794 + */ + bspp_service_pictures_decoded(str_ctx); + + /* + * A picture currently being parsed is already decoded (may happen + * after dwr in low latency mode) and its recourses were freed. Skip + * the rest of the picture. + */ + if (pict_ctx->sequ_hdr_info && pict_ctx->sequ_hdr_info->ref_count == 0) { + pict_ctx->present = 0; + pict_ctx->finished = 1; + } + + /* + * For bitstreams without unit delimiters treat all the buffers as + * a single unit whose type is defined by the first buffer element. + */ + if (str_ctx->swsr_ctx.sr_config.delim_type == SWSR_DELIM_NONE) { + struct bspp_bitstream_buffer *cur_buf = + lst_first(&str_ctx->grp_bstr_ctx.buffer_chain); + + /* if there is no picture data we must be skipped. */ + if (!cur_buf || cur_buf->data_size == 0) { + str_ctx->grp_bstr_ctx.unit_type = BSPP_UNIT_SKIP_PICTURE; + } else if (cur_buf->bstr_element_type == VDEC_BSTRELEMENT_CODEC_CONFIG) { + str_ctx->grp_bstr_ctx.unit_type = BSPP_UNIT_SEQUENCE; + } else if (cur_buf->bstr_element_type == VDEC_BSTRELEMENT_PICTURE_DATA || + cur_buf->bstr_element_type == VDEC_BSTRELEMENT_UNSPECIFIED) { + str_ctx->grp_bstr_ctx.unit_type = BSPP_UNIT_PICTURE; + str_ctx->grp_bstr_ctx.segment_list = str_ctx->grp_bstr_ctx.pict_seg_list[0]; + } + + str_ctx->grp_bstr_ctx.delim_present = 0; + } + + /* + * Load the first section (buffer) of biststream into the software + * shift-register. BSPP maps "buffer" to "section" and allows for + * contiguous parsing of all buffers since unit boundaries are not + * known up-front. Unit parsing and segment creation is happening in a + * single pass. + */ + result = swsr_start_bitstream(str_ctx->swsr_ctx.swsr_context, + &str_ctx->swsr_ctx.sr_config, + str_ctx->grp_bstr_ctx.total_data_size, + str_ctx->swsr_ctx.emulation_prevention); + + /* Seek for next delimiter or end of data and catch any exceptions. */ + if (str_ctx->grp_bstr_ctx.delim_present) { + /* Locate the first bitstream unit. */ + found = swsr_seek_delim_or_eod(str_ctx->swsr_ctx.swsr_context); + } + + if (str_ctx->swsr_ctx.sr_config.delim_type == SWSR_DELIM_SIZE) { + struct bspp_bitstream_buffer *cur_buf = + lst_first(&str_ctx->grp_bstr_ctx.in_flight_bufs); + + if (cur_buf->bstr_element_type == VDEC_BSTRELEMENT_CODEC_CONFIG && + str_ctx->parser_callbacks.parse_codec_config_cb) { + /* Parse codec config header and catch any exceptions */ + str_ctx->parser_callbacks.parse_codec_config_cb + (str_ctx->swsr_ctx.swsr_context, + &unit_count, + &num_arrays, + &str_ctx->swsr_ctx.sr_config.delim_length, + &size_delim_bits); + } else { + size_delim_bits = str_ctx->swsr_ctx.sr_config.delim_length; + } + } + + /* Process all the bitstream units until the picture is located. */ + while (found != SWSR_FOUND_EOD && !pict_ctx->finished) { + struct bspp_bitstream_buffer *cur_buf = + lst_first(&str_ctx->grp_bstr_ctx.in_flight_bufs); + + if (!cur_buf) { + pr_err("%s: cur_buf pointer is NULL\n", __func__); + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + + if (str_ctx->swsr_ctx.sr_config.delim_type == + SWSR_DELIM_SIZE && cur_buf->bstr_element_type == + VDEC_BSTRELEMENT_CODEC_CONFIG && + str_ctx->parser_callbacks.update_unit_counts_cb) { + /* + * Parse middle part of codec config header and catch + * any exceptions. + */ + str_ctx->parser_callbacks.update_unit_counts_cb + (str_ctx->swsr_ctx.swsr_context, + &unit_count, + &num_arrays); + } + + /* Process the next unit. */ + result = bspp_process_unit(str_ctx, size_delim_bits, pict_ctx, parse_state); + if (result == IMG_ERROR_NOT_SUPPORTED) + goto error; + + if (str_ctx->swsr_ctx.sr_config.delim_type != SWSR_DELIM_NONE) + str_ctx->grp_bstr_ctx.delim_present = 1; + + /* jump to the next view */ + if (parse_state->new_view) { + result = bspp_jump_to_next_view(&str_ctx->grp_bstr_ctx, + preparsed_data, + parse_state); + if (result != IMG_SUCCESS) + goto error; + + parse_state->new_view = 0; + } + + if (!pict_ctx->finished) { + /* + * Seek for next delimiter or end of data and catch any + * exceptions. + */ + /* Locate the next bitstream unit or end of data */ + found = swsr_seek_delim_or_eod(str_ctx->swsr_ctx.swsr_context); + + { + struct bspp_bitstream_buffer *buf; + /* Update the offset within current buffer. */ + swsr_get_byte_offset_curbuf(str_ctx->grp_bstr_ctx.swsr_context, + &parse_state->prev_byte_offset_buf); + buf = lst_first(&str_ctx->grp_bstr_ctx.in_flight_bufs); + if (buf) { + parse_state->prev_buf_map_id = buf->bufmap_id; + parse_state->prev_buf_data_size = buf->data_size; + } + } + } + } + + /* Finalize parsing for this video standard. */ + if (str_ctx->parser_callbacks.finalise_parsing_cb && end_of_pic) { + str_ctx->parser_callbacks.finalise_parsing_cb((void *)&str_ctx->str_alloc, + parse_state); + } + + /* + * Create segments for each buffer held by the software shift register + * (and not yet processed). + */ + while (lst_first(&str_ctx->grp_bstr_ctx.in_flight_bufs)) { + struct bspp_bitstream_buffer *buf = + lst_removehead(&str_ctx->grp_bstr_ctx.in_flight_bufs); + + result = bspp_terminate_buffer(&str_ctx->grp_bstr_ctx, buf); + } + + /* + * Create segments for each buffer not yet requested by the shift + * register. + */ + while (lst_first(&str_ctx->grp_bstr_ctx.buffer_chain)) { + struct bspp_bitstream_buffer *buf = + lst_removehead(&str_ctx->grp_bstr_ctx.buffer_chain); + + result = bspp_terminate_buffer(&str_ctx->grp_bstr_ctx, buf); + } + + /* + * Populate the parsed data information for picture only if one is + * present. The anonymous data has already been added to the + * appropriate segment list. + */ + if (pict_ctx->present && !pict_ctx->invalid) { + if (!pict_ctx->new_pict_signalled) { + /* + * Provide data about sequence used by picture. + * Signal "new sequence" if the sequence header is new + * or has changed. always switch seq when changing base + * and additional views + */ + if (pict_ctx->sequ_hdr_info) { + if (pict_ctx->sequ_hdr_info->sequ_hdr_info.sequ_hdr_id != + str_ctx->sequ_hdr_id || + pict_ctx->sequ_hdr_info->ref_count == 1 || + pict_ctx->ext_sequ_hdr_info || + pict_ctx->closed_gop) { + preparsed_data->new_sequence = 1; + preparsed_data->sequ_hdr_info = + pict_ctx->sequ_hdr_info->sequ_hdr_info; + } + } + + /* Signal "new subsequence" and its common header information. */ + if (pict_ctx->ext_sequ_hdr_info) { + preparsed_data->new_sub_sequence = 1; + preparsed_data->ext_sequ_hdr_info = + pict_ctx->ext_sequ_hdr_info->sequ_hdr_info; + + for (i = 0; i < VDEC_H264_MVC_MAX_VIEWS - 1; + i++) { + /* + * prefix is always the last one + * do not attach any header info to it + */ + if (preparsed_data->ext_pictures_data[i].is_prefix) + break; + + /* attach headers */ + preparsed_data->ext_pictures_data[i].sequ_hdr_id = + pict_ctx->ext_sequ_hdr_info->sequ_hdr_info.sequ_hdr_id; + pict_ctx->ext_sequ_hdr_info->ref_count++; + preparsed_data->ext_pictures_data[i].pict_hdr_info = + pict_ctx->pict_hdr_info[i + 1]; + } + + preparsed_data->ext_pictures_data + [0].pict_hdr_info.first_pic_of_sequence = + preparsed_data->new_sub_sequence; + + /* + * Update the base view common sequence info + * with the number of views that the stream has. + * Otherwise the number of views is inconsistent + * between base view sequence and dependent view + * sequences. Also base view sequence appears + * with one view and the driver calculates the + * wrong number of resources. + */ + preparsed_data->sequ_hdr_info.com_sequ_hdr_info.num_views = + preparsed_data->ext_sequ_hdr_info.com_sequ_hdr_info.num_views; + } + + /* Signal if this picture is the first in a closed GOP */ + if (pict_ctx->closed_gop) { + preparsed_data->closed_gop = 1; + preparsed_data->sequ_hdr_info.com_sequ_hdr_info.not_dpb_flush = + str_ctx->inter_pict_data.not_dpb_flush; + } + + /* + * Signal "new picture" and its common header + * information. + */ + preparsed_data->new_picture = 1; + if (pict_ctx->sequ_hdr_info) { + preparsed_data->picture_data.sequ_hdr_id = + pict_ctx->sequ_hdr_info->sequ_hdr_info.sequ_hdr_id; + } + preparsed_data->picture_data.pict_hdr_info = pict_ctx->pict_hdr_info[0]; + + preparsed_data->picture_data.pict_hdr_info.first_pic_of_sequence = + preparsed_data->new_sequence; + if (contig_buf_info) + preparsed_data->picture_data.pict_hdr_info.fragmented_data = 1; + else + preparsed_data->picture_data.pict_hdr_info.fragmented_data = 0; + + str_ctx->sequ_hdr_id = preparsed_data->picture_data.sequ_hdr_id; + + pict_ctx->new_pict_signalled = 1; + + /* + * aso/fmo supported only when a frame is submitted as + * a whole + */ + if (parse_state->discontinuous_mb && !end_of_pic) + result = IMG_ERROR_NOT_SUPPORTED; + } else { + preparsed_data->new_fragment = 1; + + if (parse_state->discontinuous_mb) + result = IMG_ERROR_NOT_SUPPORTED; + } + + lst_init(&temp_list); + + segment = lst_removehead(&preparsed_data->picture_data.pict_seg_list[0]); + while (segment) { + lst_add(&temp_list, segment); + segment = lst_removehead(&preparsed_data->picture_data.pict_seg_list[0]); + } + + segment = lst_removehead(&str_ctx->inter_pict_data.pic_prefix_seg); + while (segment) { + lst_add(&preparsed_data->picture_data.pict_seg_list[0], + segment); + segment = lst_removehead(&str_ctx->inter_pict_data.pic_prefix_seg); + } + + segment = lst_removehead(&temp_list); + while (segment) { + lst_add(&preparsed_data->picture_data.pict_seg_list[0], + segment); + segment = lst_removehead(&temp_list); + } + + for (i = 0; i < VDEC_H264_MVC_MAX_VIEWS; i++) { + unsigned int j; + struct bspp_picture_data *ext_pic_data = + &preparsed_data->ext_pictures_data[i]; + + if (preparsed_data->ext_pictures_data[i].is_prefix) { + for (j = 0; j < BSPP_MAX_PICTURES_PER_BUFFER; + j++) { + segment = lst_removehead(&ext_pic_data->pict_seg_list[j]); + while (segment) { + lst_add(&str_ctx->inter_pict_data.pic_prefix_seg, + segment); + segment = lst_removehead + (&ext_pic_data->pict_seg_list[j]); + } + } + preparsed_data->num_ext_pictures--; + break; + } + } + } else if (pict_ctx->present && pict_ctx->sequ_hdr_info) { + /* + * Reduce the reference count since this picture will not be + * decoded. + */ + pict_ctx->sequ_hdr_info->ref_count--; + /* Release sequence data. */ + if (str_ctx->parser_callbacks.release_data_cb) { + str_ctx->parser_callbacks.release_data_cb((void *)&str_ctx->str_alloc, + BSPP_UNIT_SEQUENCE, + pict_ctx->sequ_hdr_info->secure_sequence_info); + } + } + + /* Reset the group bitstream context */ + lst_init(&str_ctx->grp_bstr_ctx.buffer_chain); + memset(&str_ctx->grp_bstr_ctx, 0, sizeof(str_ctx->grp_bstr_ctx)); + + /* + * for now: return IMG_ERROR_NOT_SUPPORTED only if explicitly set by + * parser + */ + result = (result == IMG_ERROR_NOT_SUPPORTED) ? + IMG_ERROR_NOT_SUPPORTED : IMG_SUCCESS; + + if (end_of_pic) + parse_state->initialised = 0; + + return result; + +error: + /* Free the SWSR list of buffers */ + while (lst_first(&str_ctx->grp_bstr_ctx.in_flight_bufs)) + lst_removehead(&str_ctx->grp_bstr_ctx.in_flight_bufs); + + return result; +} + +/* + * @Function bspp_stream_destroy + * + */ +int bspp_stream_destroy(void *str_context_handle) +{ + struct bspp_str_context *str_ctx = (struct bspp_str_context *)str_context_handle; + unsigned int i; + unsigned int sps_id; + unsigned int pps_id; + struct bspp_sequence_hdr_info *sequ_hdr_info; + struct bspp_pps_info *pps_info; + unsigned int result; + + /* Validate input arguments. */ + if (!str_context_handle) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + + swsr_deinitialise(str_ctx->swsr_ctx.swsr_context); + + /* + * Service all the picture decoded events and free any unused + * resources. + */ + bspp_service_pictures_decoded(str_ctx); + for (sps_id = 0; sps_id < SEQUENCE_SLOTS; sps_id++) + bspp_remove_unused_sequence(str_ctx, sps_id); + + if (str_ctx->vid_std_features.uses_pps) { + for (pps_id = 0; pps_id < PPS_SLOTS; pps_id++) + bspp_remove_unused_pps(str_ctx, pps_id); + } + + if (str_ctx->vid_std_features.uses_vps) { + struct bspp_vps_info *vps_info; + + for (i = 0; i < VPS_SLOTS; ++i) { + vps_info = lst_removehead(&str_ctx->str_alloc.vps_data_list[i]); + + if (vps_info) + lst_add(&str_ctx->str_alloc.available_vps_list, vps_info); + + /* + * when we are done with the stream we should have MAXIMUM 1 VPS + * per slot, so after removing this one we should have none + * In case of "decodenframes" this is not true because we send more + * pictures for decode than what we expect to receive back, which + * means that potentially additional sequences/PPS are in the list + */ + vps_info = lst_removehead(&str_ctx->str_alloc.vps_data_list[i]); + if (vps_info) { + do { + lst_add(&str_ctx->str_alloc.available_vps_list, vps_info); + vps_info = + lst_removehead(&str_ctx->str_alloc.vps_data_list[i]); + } while (vps_info); + } + VDEC_ASSERT(lst_empty(&str_ctx->str_alloc.vps_data_list[i])); + } + + vps_info = NULL; + for (i = 0; i < MAX_VPSS; ++i) { + VDEC_ASSERT(!lst_empty(&str_ctx->str_alloc.available_vps_list)); + vps_info = lst_removehead(&str_ctx->str_alloc.available_vps_list); + if (vps_info) { + kfree(vps_info->secure_vpsinfo); + kfree(vps_info); + } else { + VDEC_ASSERT(vps_info); + pr_err("vps still active at shutdown\n"); + } + } + VDEC_ASSERT(lst_empty(&str_ctx->str_alloc.available_vps_list)); + } + + /* Free the memory required for this stream. */ + for (i = 0; i < SEQUENCE_SLOTS; i++) { + sequ_hdr_info = lst_removehead(&str_ctx->str_alloc.sequence_data_list[i]); + if (sequ_hdr_info) { + if (str_ctx->parser_callbacks.release_data_cb) + str_ctx->parser_callbacks.release_data_cb + ((void *)&str_ctx->str_alloc, + BSPP_UNIT_SEQUENCE, + sequ_hdr_info->secure_sequence_info); + lst_add(&str_ctx->str_alloc.available_sequence_list, + sequ_hdr_info); + } + + /* + * when we are done with the stream we should have MAXIMUM 1 + * sequence per slot, so after removing this one we should have + * none In case of "decoded frames" this is not true because we + * send more pictures for decode than what we expect to receive + * back, which means that potentially additional sequences/PPS + * are in the list + */ + sequ_hdr_info = lst_removehead(&str_ctx->str_alloc.sequence_data_list[i]); + if (sequ_hdr_info) { + unsigned int count_extra_sequences = 0; + + do { + count_extra_sequences++; + if (str_ctx->parser_callbacks.release_data_cb) { + str_ctx->parser_callbacks.release_data_cb + ((void *)&str_ctx->str_alloc, + BSPP_UNIT_SEQUENCE, + sequ_hdr_info->secure_sequence_info); + } + lst_add(&str_ctx->str_alloc.available_sequence_list, + sequ_hdr_info); + sequ_hdr_info = + lst_removehead(&str_ctx->str_alloc.sequence_data_list[i]); + } while (sequ_hdr_info); + } + } + + if (str_ctx->vid_std_features.uses_pps) { + for (i = 0; i < PPS_SLOTS; i++) { + pps_info = lst_removehead(&str_ctx->str_alloc.pps_data_list[i]); + if (pps_info) + lst_add(&str_ctx->str_alloc.available_ppss_list, pps_info); + + /* + * when we are done with the stream we should have + * MAXIMUM 1 PPS per slot, so after removing this one + * we should have none + * In case of "decodedframes" this is not true because + * we send more pictures for decode than what we expect + * to receive back, which means that potentially + * additional sequences/PPS are in the list + */ + pps_info = lst_removehead(&str_ctx->str_alloc.pps_data_list[i]); + if (pps_info) { + unsigned int count_extra_ppss = 0; + + do { + count_extra_ppss++; + lst_add(&str_ctx->str_alloc.available_ppss_list, + pps_info); + pps_info = + lst_removehead(&str_ctx->str_alloc.pps_data_list[i]); + } while (pps_info); + } + } + } + + for (i = 0; i < MAX_SEQUENCES; i++) { + sequ_hdr_info = lst_removehead(&str_ctx->str_alloc.available_sequence_list); + if (sequ_hdr_info && str_ctx->parser_callbacks.destroy_data_cb) + str_ctx->parser_callbacks.destroy_data_cb + (BSPP_UNIT_SEQUENCE, sequ_hdr_info->secure_sequence_info); + } + + kfree(str_ctx->secure_sequence_info); + str_ctx->secure_sequence_info = NULL; + kfree(str_ctx->sequ_hdr_info); + str_ctx->sequ_hdr_info = NULL; + + if (str_ctx->vid_std_features.uses_pps) { + for (i = 0; i < MAX_PPSS; i++) { + pps_info = lst_removehead(&str_ctx->str_alloc.available_ppss_list); + if (pps_info && str_ctx->parser_callbacks.destroy_data_cb) + str_ctx->parser_callbacks.destroy_data_cb + (BSPP_UNIT_PPS, pps_info->secure_pps_info); + } + + kfree(str_ctx->secure_pps_info); + str_ctx->secure_pps_info = NULL; + kfree(str_ctx->pps_info); + str_ctx->pps_info = NULL; + } + + /* destroy mutex */ + mutex_destroy(str_ctx->bspp_mutex); + kfree(str_ctx->bspp_mutex); + str_ctx->bspp_mutex = NULL; + + kfree(str_ctx); + + return IMG_SUCCESS; +error: + return result; +} + +/* + * @Function bspp_set_codec_config + * + */ +int bspp_set_codec_config(const void *str_context_handle, + const struct vdec_codec_config *codec_config) +{ + struct bspp_str_context *str_ctx = (struct bspp_str_context *)str_context_handle; + unsigned int result = IMG_SUCCESS; + + /* Validate input arguments. */ + if (!str_context_handle || !codec_config) { + result = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + + switch (str_ctx->vid_std) { + default: + result = IMG_ERROR_NOT_SUPPORTED; + break; + } +error: + return result; +} + +/* + * @Function bspp_stream_create + * + */ +int bspp_stream_create(const struct vdec_str_configdata *str_config_data, + void **str_ctx_handle, + struct bspp_ddbuf_array_info fw_sequence[], + struct bspp_ddbuf_array_info fw_pps[]) +{ + struct bspp_str_context *str_ctx; + unsigned int result = IMG_SUCCESS; + unsigned int i; + struct bspp_sequence_hdr_info *sequ_hdr_info; + struct bspp_pps_info *pps_info; + struct bspp_parse_state *parse_state; + + /* Allocate a stream structure */ + str_ctx = kmalloc(sizeof(*str_ctx), GFP_KERNEL); + if (!str_ctx) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + memset(str_ctx, 0, sizeof(*str_ctx)); + + /* Initialise the stream context structure. */ + str_ctx->sequ_hdr_id = BSPP_INVALID; + str_ctx->vid_std = str_config_data->vid_std; + str_ctx->bstr_format = str_config_data->bstr_format; + str_ctx->disable_mvc = str_config_data->disable_mvc; + str_ctx->full_scan = str_config_data->full_scan; + str_ctx->immediate_decode = str_config_data->immediate_decode; + str_ctx->intra_frame_closed_gop = str_config_data->intra_frame_closed_gop; + + str_ctx->max_dec_frame_buffering = str_config_data->max_dec_frame_buffering; + + parse_state = &str_ctx->parse_state; + + /* Setup group buffer processing state. */ + parse_state->inter_pict_ctx = &str_ctx->inter_pict_data; + parse_state->prev_bottom_pic_flag = (unsigned char)BSPP_INVALID; + parse_state->next_pic_is_new = 1; + parse_state->prev_frame_num = BSPP_INVALID; + parse_state->second_field_flag = 0; + + lst_init(&str_ctx->grp_bstr_ctx.buffer_chain); + + if (str_ctx->vid_std < VDEC_STD_MAX && parser_fxns[str_ctx->vid_std].set_parser_config) { + parser_fxns[str_ctx->vid_std].set_parser_config(str_ctx->bstr_format, + &str_ctx->vid_std_features, + &str_ctx->swsr_ctx, + &str_ctx->parser_callbacks, + &str_ctx->inter_pict_data); + } else { + result = IMG_ERROR_NOT_SUPPORTED; + goto error; + } + + /* Allocate the memory required for this stream for Sequence/PPS info */ + lst_init(&str_ctx->str_alloc.available_sequence_list); + + str_ctx->sequ_hdr_info = kmalloc((MAX_SEQUENCES * sizeof(struct bspp_sequence_hdr_info)), + GFP_KERNEL); + if (!str_ctx->sequ_hdr_info) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + memset(str_ctx->sequ_hdr_info, 0x00, + (MAX_SEQUENCES * sizeof(struct bspp_sequence_hdr_info))); + + str_ctx->secure_sequence_info = + kmalloc((MAX_SEQUENCES * str_ctx->vid_std_features.seq_size), + GFP_KERNEL); + if (!str_ctx->secure_sequence_info) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + memset(str_ctx->secure_sequence_info, 0x00, + (MAX_SEQUENCES * str_ctx->vid_std_features.seq_size)); + + sequ_hdr_info = (struct bspp_sequence_hdr_info *)(str_ctx->sequ_hdr_info); + for (i = 0; i < MAX_SEQUENCES; i++) { + /* Deal with the device memory for FW SPS data */ + sequ_hdr_info->fw_sequence = fw_sequence[i]; + sequ_hdr_info->sequ_hdr_info.bufmap_id = + fw_sequence[i].ddbuf_info.bufmap_id; + sequ_hdr_info->sequ_hdr_info.buf_offset = + fw_sequence[i].buf_offset; + sequ_hdr_info->secure_sequence_info = (void *)(str_ctx->secure_sequence_info + + (i * str_ctx->vid_std_features.seq_size)); + + lst_add(&str_ctx->str_alloc.available_sequence_list, + sequ_hdr_info); + sequ_hdr_info++; + } + + if (str_ctx->vid_std_features.uses_pps) { + lst_init(&str_ctx->str_alloc.available_ppss_list); + str_ctx->pps_info = kmalloc((MAX_PPSS * sizeof(struct bspp_pps_info)), GFP_KERNEL); + if (!str_ctx->pps_info) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + memset(str_ctx->pps_info, 0x00, (MAX_PPSS * sizeof(struct bspp_pps_info))); + str_ctx->secure_pps_info = kmalloc((MAX_PPSS * str_ctx->vid_std_features.pps_size), + GFP_KERNEL); + if (!str_ctx->secure_pps_info) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + memset(str_ctx->secure_pps_info, 0x00, + (MAX_PPSS * str_ctx->vid_std_features.pps_size)); + + pps_info = (struct bspp_pps_info *)(str_ctx->pps_info); + for (i = 0; i < MAX_PPSS; i++) { + /* Deal with the device memory for FW PPS data */ + pps_info->fw_pps = fw_pps[i]; + pps_info->bufmap_id = fw_pps[i].ddbuf_info.bufmap_id; + pps_info->buf_offset = fw_pps[i].buf_offset; + + /* + * We have no container for the PPS that passes down to the kernel, + * for this reason the h264 secure parser needs to populate that + * info into the picture header (Second)PictAuxData. + */ + pps_info->secure_pps_info = (void *)(str_ctx->secure_pps_info + (i * + str_ctx->vid_std_features.pps_size)); + + lst_add(&str_ctx->str_alloc.available_ppss_list, pps_info); + pps_info++; + } + + /* As only standards that use PPS also use VUI, initialise + * the appropriate data structures here. + * Initialise the list of raw bitstream data containers. + */ + lst_init(&str_ctx->str_alloc.raw_data_list_available); + lst_init(&str_ctx->str_alloc.raw_data_list_used); + } + + if (str_ctx->vid_std_features.uses_vps) { + struct bspp_vps_info *vps_info; + + lst_init(&str_ctx->str_alloc.available_vps_list); + for (i = 0; i < MAX_VPSS; ++i) { + vps_info = kmalloc(sizeof(*vps_info), GFP_KERNEL); + VDEC_ASSERT(vps_info); + if (!vps_info) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + + memset(vps_info, 0x00, sizeof(struct bspp_vps_info)); + /* + * for VPS we do not allocate device memory since (at least for now) + * there is no need to pass any data from VPS directly to FW + */ + /* Allocate memory for BSPP local VPS data structure. */ + vps_info->secure_vpsinfo = + kmalloc(str_ctx->vid_std_features.vps_size, GFP_KERNEL); + + VDEC_ASSERT(vps_info->secure_vpsinfo); + if (!vps_info->secure_vpsinfo) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + memset(vps_info->secure_vpsinfo, 0, str_ctx->vid_std_features.vps_size); + + lst_add(&str_ctx->str_alloc.available_vps_list, vps_info); + } + } + + /* ... and initialise the lists that will use this data */ + for (i = 0; i < SEQUENCE_SLOTS; i++) + lst_init(&str_ctx->str_alloc.sequence_data_list[i]); + + if (str_ctx->vid_std_features.uses_pps) + for (i = 0; i < PPS_SLOTS; i++) + lst_init(&str_ctx->str_alloc.pps_data_list[i]); + + str_ctx->bspp_mutex = kzalloc(sizeof(*str_ctx->bspp_mutex), GFP_KERNEL); + if (!str_ctx->bspp_mutex) { + result = -ENOMEM; + goto error; + } + mutex_init(str_ctx->bspp_mutex); + + /* Initialise the software shift-register */ + swsr_initialise(bspp_exception_handler, &str_ctx->parse_ctx, + (swsr_callback_fxn) bspp_shift_reg_cb, + &str_ctx->grp_bstr_ctx, + &str_ctx->swsr_ctx.swsr_context); + + /* Setup the parse context */ + str_ctx->parse_ctx.swsr_context = str_ctx->swsr_ctx.swsr_context; + + *str_ctx_handle = str_ctx; + + return IMG_SUCCESS; + +error: + if (str_ctx) { + kfree(str_ctx->sequ_hdr_info); + kfree(str_ctx->secure_sequence_info); + kfree(str_ctx->pps_info); + kfree(str_ctx->secure_pps_info); + kfree(str_ctx); + } + + return result; +} + +void bspp_freeraw_sei_datacontainer(const void *str_res, + struct vdec_raw_bstr_data *rawsei_datacontainer) +{ + struct bspp_raw_sei_alloc *rawsei_alloc = NULL; + + /* Check input params. */ + if (str_res && rawsei_datacontainer) { + struct bspp_stream_alloc_data *alloc_data = + (struct bspp_stream_alloc_data *)str_res; + + rawsei_alloc = container_of(rawsei_datacontainer, + struct bspp_raw_sei_alloc, + raw_sei_data); + memset(&rawsei_alloc->raw_sei_data, 0, sizeof(rawsei_alloc->raw_sei_data)); + lst_remove(&alloc_data->raw_sei_alloc_list, rawsei_alloc); + kfree(rawsei_alloc); + } +} + +void bspp_freeraw_sei_datalist(const void *str_res, struct vdec_raw_bstr_data *rawsei_datalist) +{ + /* Check input params. */ + if (rawsei_datalist && str_res) { + struct vdec_raw_bstr_data *sei_raw_datacurr = NULL; + + /* Start fromm the first element... */ + sei_raw_datacurr = rawsei_datalist; + /* Free all the linked raw SEI data containers. */ + while (sei_raw_datacurr) { + struct vdec_raw_bstr_data *seiraw_datanext = + sei_raw_datacurr->next; + bspp_freeraw_sei_datacontainer(str_res, sei_raw_datacurr); + sei_raw_datacurr = seiraw_datanext; + } + } +} + +void bspp_streamrelese_rawbstrdataplain(const void *str_res, const void *rawdata) +{ + struct bspp_stream_alloc_data *str_alloc = + (struct bspp_stream_alloc_data *)str_res; + struct bspp_raw_bitstream_data *rawbstrdata = + (struct bspp_raw_bitstream_data *)rawdata; + + if (rawbstrdata) { + /* Decrement the raw bitstream data reference count. */ + rawbstrdata->ref_count--; + /* If no entity is referencing the raw + * bitstream data any more + */ + if (rawbstrdata->ref_count == 0) { + /* ... free the raw bistream data buffer... */ + kfree(rawbstrdata->raw_bitstream_data.data); + memset(&rawbstrdata->raw_bitstream_data, 0, + sizeof(rawbstrdata->raw_bitstream_data)); + /* ...and return it to the list. */ + lst_remove(&str_alloc->raw_data_list_used, rawbstrdata); + lst_add(&str_alloc->raw_data_list_available, rawbstrdata); + } + } +} + +struct bspp_vps_info *bspp_get_vpshdr(void *str_res, unsigned int vps_id) +{ + struct bspp_stream_alloc_data *alloc_data = + (struct bspp_stream_alloc_data *)str_res; + + if (vps_id >= VPS_SLOTS || !alloc_data) + return NULL; + + return lst_last(&alloc_data->vps_data_list[vps_id]); +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/bspp.h b/drivers/media/platform/imagination/vxe-vxd/decoder/bspp.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/bspp.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/bspp.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,363 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD Bitstream Buffer Pre-Parser + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * Re-written for upstreming + * Prashanth Kumar Amai + * Sidraya Jayagond + */ +#ifndef __BSPP_H__ +#define __BSPP_H__ + +#include + +#include "h264fw_data.h" +#include "lst.h" +#include "vdec_defs.h" + +/* + * There are up to 2 pictures in each buffer + * (plus trailing data for the next picture, e.g. PPS). + */ +#define BSPP_MAX_PICTURES_PER_BUFFER 3 + +#define BSPP_INVALID ((unsigned int)(-1)) + +/* + * This enables signalling of closed gop at every I frame. Add resilience to + * seeking functionality. + */ +#define I_FRAME_SIGNALS_CLOSED_GOP + +/* + * enum bspp_error_type - enumeration of parsing error , different error flag + * for different data unit + */ +enum bspp_error_type { + /* No Error in parsing. */ + BSPP_ERROR_NONE = (0), + /* Correction in VSH, Replaced VSH with faulty one */ + BSPP_ERROR_CORRECTION_VSH = (1 << 0), + /* + * Correction in parsed Value, clamp the value if it goes beyond + * the limit + */ + BSPP_ERROR_CORRECTION_VALIDVALUE = (1 << 1), + /* Error in Aux data (i.e. PPS in H.264) parsing */ + BSPP_ERROR_AUXDATA = (1 << 2), + /* Error in parsing, more data remains in VSH data unit after parsing */ + BSPP_ERROR_DATA_REMAINS = (1 << 3), + /* Error in parsing, parsed codeword is invalid */ + BSPP_ERROR_INVALID_VALUE = (1 << 4), + /* Error in parsing, parsing error */ + BSPP_ERROR_DECODE = (1 << 5), + /* reference frame is not available for decoding */ + BSPP_ERROR_NO_REF_FRAME = (1 << 6), + /* Non IDR frame loss detected */ + BSPP_ERROR_NONIDR_FRAME_LOSS = (1 << 7), + /* IDR frame loss detected */ + BSPP_ERROR_IDR_FRAME_LOSS = (1 << 8), + /* Error in parsing, insufficient data to complete parsing */ + BSPP_ERROR_INSUFFICIENT_DATA = (1 << 9), + /* Severe Error, Error indicates, no support for this picture data */ + BSPP_ERROR_UNSUPPORTED = (1 << 10), + /* Severe Error, Error in which could not be recovered */ + BSPP_ERROR_UNRECOVERABLE = (1 << 11), + /* Severe Error, to indicate that NAL Header is absent after SCP */ + BSPP_ERROR_NO_NALHEADER = (1 << 12), + BSPP_ERROR_NO_SEQUENCE_HDR = (1 << 13), + BSPP_ERROR_SIGNALED_IN_STREAM = (1 << 14), + BSPP_ERROR_UNKNOWN_DATAUNIT_DETECTED = (1 << 15), + BSPP_ERROR_NO_PPS = (1 << 16), + BSPP_ERROR_NO_VPS = (1 << 17), + BSPP_ERROR_OUT_OF_MEMORY = (1 << 18), + /* The shift value of the last error bit */ + BSPP_ERROR_MAX_SHIFT = 18, + BSPP_ERROR_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * struct bspp_ddbuf_info - Buffer info + * @buf_size: The size of the buffer (in bytes) + * @cpu_virt_addr: The CPU virtual address (mapped into the local cpu MMU) + * @mem_attrib: Memory attributes + * @bufmap_id: buffer mappind id + */ +struct bspp_ddbuf_info { + unsigned int buf_size; + void *cpu_virt_addr; + enum sys_emem_attrib mem_attrib; + unsigned int buf_id; + unsigned int bufmap_id; +}; + +/* + * struct bspp_ddbuf_array_info - Buffer array info + * @ddbuf_info: Buffer info (container) + * @buf_element_size: Size of each element + * @buf_offset: Offset for each element + */ +struct bspp_ddbuf_array_info { + struct bspp_ddbuf_info ddbuf_info; + unsigned int buf_element_size; + unsigned int buf_offset; +}; + +/** + * struct bspp_bitstr_seg - Bitstream segment + * @lst_padding: + * @data_size: Size of data + * @data_byte_offset: Offset for data + * @bstr_seg_flag: flag indicates the bitstream segment type + * @start_code_suffix: start code prefix + * @bufmap_id: Buffer map ID + */ +struct bspp_bitstr_seg { + void *lst_padding; + unsigned int data_size; + unsigned int data_byte_offset; + unsigned int bstr_seg_flag; + unsigned char start_code_suffix; + unsigned int bufmap_id; +}; + +/* + * struct bspp_pict_data - Picture Header Data Information + * @bufmap_id: Buffer ID to use inside kernel #VXDIO_sDdBufInfo + * @buf_offset: Buffer offset (for packed device buffers, e.g. PPS) + * @pic_data: Picture data + * @size: Size (in bytes) of data. + * @data_id: Data identifier. + */ +struct bspp_pict_data { + unsigned int bufmap_id; + unsigned int buf_offset; + void *pic_data; + unsigned int size; + unsigned int id; +}; + +/* + * struct bspp_pict_hdr_info - Picture Header Information + */ +struct bspp_pict_hdr_info { + /* + * Picture is entirely intra-coded and doesn't use any reference data. + * NOTE: should be IMG_FALSE if this cannot be determined. + */ + int intra_coded; + /* Picture might be referenced by subsequent pictures. */ + int ref; + /* Picture is a field as part of a frame. */ + int field; + /* Emulation prevention bytes are present in picture data. */ + int emulation_prevention; + /* Post Processing */ + int post_processing; + /* Macroblocks within the picture may not occur in raster-scan order */ + int discontinuous_mbs; + /* Flag to indicate data is span across mulitple buffer. */ + int fragmented_data; + /* SOS fields count value */ + unsigned char sos_count; + /* This picture is the first of the sequence or not */ + int first_pic_of_sequence; + + enum vdecfw_parsermode parser_mode; + /* Total size of picture data which is going to be submitted. */ + unsigned int pic_data_size; + /* Size of coded frame as specified in the bitstream. */ + struct vdec_pict_size coded_frame_size; + /* Display information for picture */ + struct vdec_pict_disp_info disp_info; + + /* Picture auxiliary data (e.g. H.264 SPS/PPS) */ + struct bspp_pict_data pict_aux_data; + /* Picture auxiliary data (e.g. H.264 SPS/PPS) for 2nd picture */ + struct bspp_pict_data second_pict_aux_data; + /* Slice group-map data. */ + struct bspp_pict_data pict_sgm_data; +#ifdef HAS_JPEG + /* JPEG specific picture header information.*/ + struct vdec_jpeg_pict_hdr_info jpeg_pict_hdr_info; +#endif + + struct h264_pict_hdr_info { + void *raw_vui_data; + void *raw_sei_data_list_first_field; + void *raw_sei_data_list_second_field; + unsigned char nal_ref_idc; + unsigned short frame_num; + } h264_pict_hdr_info; + + struct { /* HEVC specific frame information.*/ + int range_ext_present; + int is_full_range_ext; + void *raw_vui_data; + void *raw_sei_datalist_firstfield; + void *raw_sei_datalist_secondfield; + } hevc_pict_hdr_info; +}; + +/* + * struct bspp_sequ_hdr_info - Sequence header information + */ +struct bspp_sequ_hdr_info { + unsigned int sequ_hdr_id; + unsigned int ref_count; + struct vdec_comsequ_hdrinfo com_sequ_hdr_info; + unsigned int bufmap_id; + unsigned int buf_offset; +}; + +/* + * struct bspp_picture_data - Picture data + */ +struct bspp_picture_data { + /* Anonymous */ + /* + * Bitstream segments that contain other (non-picture) data before + * the picture in the buffer (elements of type #VDECDD_sBitStrSeg). + */ + struct lst_t pre_pict_seg_list[BSPP_MAX_PICTURES_PER_BUFFER]; + /* Picture */ + unsigned int sequ_hdr_id; + struct bspp_pict_hdr_info pict_hdr_info; + /* + * Bitstream segments that contain picture data, one for each field + * (if present in same group of buffers (elements of type + * #VDECDD_sBitStrSeg). + */ + struct lst_t pict_seg_list[BSPP_MAX_PICTURES_PER_BUFFER]; + void *pict_tag_param[BSPP_MAX_PICTURES_PER_BUFFER]; + int is_prefix; +}; + +/* + * struct bspp_preparsed_data - Pre-parsed buffer information + */ +struct bspp_preparsed_data { + /* Sequence */ + int new_sequence; + struct bspp_sequ_hdr_info sequ_hdr_info; + int sequence_end; + + /* Closed GOP */ + int closed_gop; + + /* Picture */ + int new_picture; + int new_fragment; + struct bspp_picture_data picture_data; + + /* Additional pictures (MVC extension) */ + int new_sub_sequence; + struct bspp_sequ_hdr_info ext_sequ_hdr_info; + /* non-base view pictures + picture prefix for next frame */ + struct bspp_picture_data ext_pictures_data[VDEC_H264_MVC_MAX_VIEWS]; + unsigned int num_ext_pictures; + + /* + * Additional information + * Flags word to indicate error in parsing/decoding - see + * #VDEC_eErrorType + */ + unsigned int error_flags; +}; + +/* + * struct bspp_picture_decoded - used to store picture-decoded information for + * resource handling (sequences/PPSs) + */ +struct bspp_picture_decoded { + void **lst_link; + unsigned int sequ_hdr_id; + unsigned int pps_id; + unsigned int second_pps_id; + int not_decoded; + struct vdec_raw_bstr_data *sei_raw_data_first_field; + struct vdec_raw_bstr_data *sei_raw_data_second_field; +}; + +/* + * @Function bspp_stream_create + * @Description Creates a stream context for which to pre-parse bitstream + * buffers. The following allocations will take place: + * - Local storage for high-level header parameters (secure) + * - Host memory for common sequence information (insecure) + * - Device memory for Sequence information (secure) + * - Device memory for PPS (secure, H.264 only) + * @Input vdec_str_configdata : config data corresponding to bitstream + * @Output str_context : A pointer used to return the stream context handle + * @Input fw_sequ: FW sequence data + * @Input fw_pps: FW pps data + * @Return This function returns either IMG_SUCCESS or an error code. + */ +int bspp_stream_create(const struct vdec_str_configdata *str_config_data, + void **str_context, + struct bspp_ddbuf_array_info fw_sequ[], + struct bspp_ddbuf_array_info fw_pps[]); + +/* + * @Function bspp_set_codec_config + * @Description This function is used to set the out-of-band codec config data. + * @Input str_context_handle : Stream context handle. + * @Input codec_config : Codec-config data + * @Return This function returns either IMG_SUCCESS or an error code. + */ +int bspp_set_codec_config(const void *str_context_handle, + const struct vdec_codec_config *codec_config); + +/* + * @Function bspp_stream_destroy + * @Description Destroys a stream context used to pre-parse bitstream buffers. + * @Input str_context_handle : Stream context handle. + * @Return This function returns either IMG_SUCCESS or an error code. + */ +int bspp_stream_destroy(void *str_context_handle); + +/* + * @Function bspp_submit_picture_decoded + */ +int bspp_submit_picture_decoded(void *str_context_handle, + struct bspp_picture_decoded *picture_decoded); + +/* + * @Function bspp_stream_submit_buffer + */ +int bspp_stream_submit_buffer(void *str_context_handle, + const struct bspp_ddbuf_info *ddbuf_info, + unsigned int bufmap_id, + unsigned int data_size, + void *pict_tag_param, + enum vdec_bstr_element_type bstr_element_type); + +/* + * @Function bspp_stream_preparse_buffers + * @Description Pre-parses bistream buffer and returns picture information in + * structure that also signals when the buffer is last in picture. + * @Input str_context_handle: Stream context handle. + * @Input contiguous_buf_info : Contiguous buffer information + * multiple segments that may be non contiguous in memory + * @Input contiguous_buf_map_id : Contiguous Buffer Map id + * @Input segments: Pointer to a list of segments (see #VDECDD_sBitStrSeg) + * @Output preparsed_data: Container to return picture information. Only + * provide when buffer is last in picture (see #bForceEop in + * function #VDEC_StreamSubmitBstrBuf) + * @Output eos_flag: flag indicates end of stream + * @Return int : This function returns either IMG_SUCCESS or an error code. + */ +int bspp_stream_preparse_buffers + (void *str_context_handle, + const struct bspp_ddbuf_info *contiguous_buf_info, + unsigned int contiguous_buf_map_id, + struct lst_t *segments, + struct bspp_preparsed_data *preparsed_data, + int eos_flag); + +#endif /* __BSPP_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/bspp_int.h b/drivers/media/platform/imagination/vxe-vxd/decoder/bspp_int.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/bspp_int.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/bspp_int.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,520 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD Bitstream Buffer Pre-Parser Internal + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ +#ifndef __BSPP_INT_H__ +#define __BSPP_INT_H__ + +#include "bspp.h" +#include "swsr.h" + +#define VDEC_MB_DIMENSION (16) +#define MAX_COMPONENTS (4) + +#define print_value(a, ...) + +#define BSPP_DEFAULT_SEQUENCE_ID (0) + +enum bspp_unit_type { + BSPP_UNIT_NONE = 0, + /* Only relevant for HEVC. */ + BSPP_UNIT_VPS, + /* Only relevant for h.264 and HEVC */ + BSPP_UNIT_SEQUENCE, BSPP_UNIT_PPS, + /* + * !< Data from these units should be placed in non-picture bitstream + * segment lists. In conformant streams these units should not occur + * in-between the picture data. + */ + BSPP_UNIT_PICTURE, + BSPP_UNIT_SKIP_PICTURE, + BSPP_UNIT_NON_PICTURE, + BSPP_UNIT_UNCLASSIFIED, + /* Unit is unsupported, don't change segment list */ + BSPP_UNIT_UNSUPPORTED, + BSPP_UNIT_MAX, + BSPP_UNIT_FORCE32BITS = 0x7FFFFFFFU +}; + +struct bspp_raw_bitstream_data { + void **lst_link; + unsigned int ref_count; + struct vdec_raw_bstr_data raw_bitstream_data; +}; + +/* + * struct bspp_h264_inter_pict_ctx + * @Brief: This structure contains H264 state to be retained between pictures. + */ +struct bspp_h264_inter_pict_ctx { + /* + * The following get applied to every picture until updated + * (bitstream properties) + */ + int disable_vdmc_filt; + int b4x4transform_mb_unavailable; + /* + * The following get applied to the next picture only + * (picture properties) + */ + int repeat_first_field; + unsigned int max_frm_repeat; + /* + * Control variable to decide when to attach the SEI info + * (picture properties) to a picture + */ + int sei_info_attached_to_pic; + /* + * The following variable is an approximation because we cannot + * parse out-of-order, it takes value as described: + * 1) Initially it is BSPP_INVALID + * 2) The first SPS sets it to its SPSid + * 3) The last bspp_H264SeiBufferingPeriod sets it, and it is used + * for every SEI parsing until updated by another + * bspp_H264SeiBufferingPeriod message + */ + unsigned int active_sps_for_sei_parsing; + unsigned short current_view_id; + struct vdec_raw_bstr_data *sei_raw_data_list; +}; + +/* This structure contains HEVC state to be retained between pictures. */ +struct bspp_hevc_inter_pict_ctx { + /* Picture count in a sequence */ + unsigned int seq_pic_count; + struct { + /* There was EOS NAL detected and no new picture yet */ + unsigned eos_detected : 1; + /* This is first picture after EOS NAL */ + unsigned first_after_eos : 1; + }; + + /* control variable to decide when to attach the SEI info + * (picture properties) to a picture. + */ + unsigned char sei_info_attached_to_pic; + /* Raw SEI list to be attached to a picture. */ + struct vdec_raw_bstr_data *sei_rawdata_list; + /* Handle to a picture header field to attach the raw SEI list to. */ + void **hndl_pichdr_sei_rawdata_list; +}; + +/* + * struct bspp_inter_pict_data + * @Brief This structure contains state to be retained between pictures. + */ +struct bspp_inter_pict_data { + /* A closed GOP has occurred in the bitstream. */ + int seen_closed_gop; + /* Closed GOP has been signaled by a unit before the next picture */ + int new_closed_gop; + /* Indicates whether or not DPB flush is needed */ + int not_dpb_flush; + struct lst_t pic_prefix_seg; + union { + struct bspp_h264_inter_pict_ctx h264_ctx; + struct bspp_hevc_inter_pict_ctx hevc_ctx; + }; +}; + +/* + * struct bspp_parse_state + * @Brief This structure contains parse state + */ +struct bspp_parse_state { + struct bspp_inter_pict_data *inter_pict_ctx; + int initialised; + + /* Input/Output (H264 etc. state). */ + /* For SCP ASO detection we need to log 3 components */ + unsigned int prev_first_mb_in_slice[MAX_COMPONENTS]; + struct bspp_pict_hdr_info *next_pict_hdr_info; + unsigned char prev_bottom_pic_flag; + unsigned char second_field_flag; + unsigned char next_pic_is_new; + unsigned int prev_frame_num; + unsigned int prev_pps_id; + unsigned int prev_field_pic_flag; + unsigned int prev_nal_ref_idc; + unsigned int prev_pic_order_cnt_lsb; + int prev_delta_pic_order_cnt_bottom; + int prev_delta_pic_order_cnt[2]; + int prev_nal_unit_type; + int prev_idr_pic_id; + int discontinuous_mb; + /* Position in bitstream before parsing a unit */ + unsigned long long prev_byte_offset_buf; + unsigned int prev_buf_map_id; + unsigned int prev_buf_data_size; + /* + * !< Flags word to indicate error in parsing/decoding + * - see #VDEC_eErrorType. + */ + unsigned int error_flags; + /* Outputs. */ + int new_closed_gop; + unsigned char new_view; + unsigned char is_prefix; + int first_chunk; +}; + +/* + * struct bspp_pps_info + * @Brief Contains PPS information + */ +struct bspp_pps_info { + void **lst_link; + /* PPS Id. INSECURE MEMORY HOST */ + unsigned int pps_id; + /* Reference count for PPS. INSECURE MEMORY HOST */ + unsigned int ref_count; + struct bspp_ddbuf_array_info fw_pps; + /* Buffer ID to be used in Kernel */ + unsigned int bufmap_id; + /* Parsing Info. SECURE MEMORY HOST */ + void *secure_pps_info; + /* Buffer Offset to be used in kernel */ + unsigned int buf_offset; +}; + +/* + * struct bspp_sequence_hdr_info + * @Brief Contains SPS information + */ +struct bspp_sequence_hdr_info { + void **lst_link; + /* Reference count for sequence header */ + unsigned int ref_count; + struct bspp_sequ_hdr_info sequ_hdr_info; + struct bspp_ddbuf_array_info fw_sequence; + /* Parsing Info. SECURE MEMORY HOST */ + void *secure_sequence_info; +}; + +enum bspp_element_status { + BSPP_UNALLOCATED = 0, + BSPP_AVAILABLE, + BSPP_UNAVAILABLE, + BSPP_STATUSMAX, + BSPP_FORCE32BITS = 0x7FFFFFFFU +}; + +struct bspp_vps_info { + void **lst_link; + /* VPS Id INSECURE MEMORY HOST */ + unsigned int vps_id; + /* Reference count for video header. INSECURE MEMORY HOST */ + unsigned int ref_count; + /*!< Parsing Info. SECURE MEMORY HOST */ + void *secure_vpsinfo; +}; + +/* + * struct bspp_unit_data + * @Brief Contains bitstream unit data + */ +struct bspp_unit_data { + /* Input. */ + /* Indicates which output data to populate */ + enum bspp_unit_type unit_type; + /* Video Standard of unit to parse */ + enum vdec_vid_std vid_std; + /* Indicates whether delimiter is present for unit */ + int delim_present; + /* Codec configuration used by this stream */ + const struct vdec_codec_config *codec_config; + void *str_res_handle; + /* Needed for calculating the size of the last fragment */ + unsigned int unit_data_size; + /* Input/Output. */ + struct bspp_parse_state *parse_state; + /* Output */ + /* eVidStd == VDEC_STD_H263 && BSPP_UNIT_PICTURE. */ + struct bspp_sequence_hdr_info *impl_sequ_hdr_info; + /* Union of output data for each of the unit types. */ + union { + /* BSPP_UNIT_SEQUENCE. */ + struct bspp_sequence_hdr_info *sequ_hdr_info; + /* BSPP_UNIT_PPS. */ + struct bspp_pps_info *pps_info; + /* BSPP_UNIT_PICTURE. */ + struct bspp_pict_hdr_info *pict_hdr_info; + /* For Video Header (HEVC) */ + struct bspp_vps_info *vps_info; + } out; + + /* + * For picture it should give the SequenceHdrId, for anything + * else it should contain BSPP_INVALID. This value is pre-loaded + * with the sequence ID of the last picture. + */ + unsigned int pict_sequ_hdr_id; + /* State: output. */ + /* + * Picture unit (BSPP_UNIT_PICTURE) contains slice data. + * Picture header information must be populated once this unit has been + * parsed. + */ + int slice; + int ext_slice; /* Current slice belongs to non-base view (MVC only) */ + /* + * True if we meet a unit that signifies closed gop, different + * for each standard. + */ + int new_closed_gop; + /* True if the end of a sequence of pictures has been reached. */ + int sequence_end; + /* + * Extracted all data from unit whereby shift-register should now + * be at the next delimiter or end of data (when byte-aligned). + */ + int extracted_all_data; + /* Indicates the presence of any errors while processing this unit. */ + enum bspp_error_type parse_error; + /* To turn on/off considering I-Frames as ClosedGop boundaries. */ + int intra_frm_as_closed_gop; + + /* + * constrain the amount of DPB's allowed + * a value of 0 means let the firmware decide + */ + unsigned int max_dec_frame_buffering; +}; + +/* + * struct bspp_swsr_ctx + * @brief BSPP Software Shift Register Context Information + */ +struct bspp_swsr_ctx { + /* + * Default configuration for the shift-register for this + * stream. The delimiter type may be adjusted for each unit + * where the buffer requires it. Information about how to + * process each unit will be passed down with the picture + * header information. + */ + struct swsr_config sr_config; + /* + * Emulation prevention scheme present in bitstream. This is + * sometimes not ascertained (e.g. VC-1) until the first + * bitstream buffer (often codec configuration) has been + * received. + */ + enum swsr_emprevent emulation_prevention; + /* Software shift-register context. */ + void *swsr_context; +}; + +/* + * struct bspp_vid_std_features + * @brief BSPP Video Standard Specific Features and Information + */ +struct bspp_vid_std_features { + /* The size of the sequence header structure for this video standard */ + unsigned long seq_size; + /* This video standard uses Picture Parameter Sets. */ + int uses_pps; + /* + * The size of the Picture Parameter Sets structure for + * this video standard. + */ + unsigned long pps_size; + /* This video standard uses Video Parameter Sets. */ + int uses_vps; + /* + * The size of the Video Parameter Sets structure for + * this video standard + */ + unsigned long vps_size; +}; + +/* + * @Function bspp_cb_parse_unit + * @Description Function prototype for the parse unit callback functions. + * @Input swsr_context_handle: A handle to software shift-register context + * @InOut unit_data: A pointer to unit data which includes input & output + * parameters as defined by structure. + * @Return int : This function returns either IMG_SUCCESS or an error code. + */ +typedef int (*bspp_cb_parse_unit)(void *swsr_context_handle, + struct bspp_unit_data *unit_data); + +/* + * @Function bspp_pfnReleaseData + * @Description This is a function prototype for the data releasing callback + * functions. + * @Input str_alloc_handle : A handle to stream related resources. + * @Input data_type : A type of data which is to be released. + * @Input data_handle : A handle for data which is to be released. + * @Return int : This function returns either IMG_SUCCESS or an error code. + */ +typedef int (*bspp_cb_release_data)(void *str_alloc_handle, + enum bspp_unit_type data_type, + void *data_handle); + +/* + * @Function bspp_cb_reset_data + * @Description This is a function prototype for the data resetting callback + * functions. + * @Input data_type : A type of data which is to be reset. + * @InOut data_handle : A handle for data which is to be reset. + * @Return int : This function returns either IMG_SUCCESS or an error code. + */ +typedef int (*bspp_cb_reset_data)(enum bspp_unit_type data_type, + void *data_handle); + +/* + * @Function bspp_cb_destroy_data + * @Description This is a function prototype for the data destruction callback + * functions. + * @Input data_type : A type of data which is to be destroyed. + * @InOut data_handle : A handle for data which is to be destroyed. + * @Return int : This function returns either IMG_SUCCESS or an error code. + */ +typedef int (*bspp_cb_destroy_data)(enum bspp_unit_type data_type, + void *data_handle); + +/* + * @Function bspp_cb_parse_codec_config + * @Description This is a function prototype for parsing codec config bitstream + * element for size delimited bitstreams. + * @Input swsr_context_handle: A handle to Shift Register processing + * current bitstream. + * @Output unit_count: A pointer to variable in which to return unit count. + * @Output unit_array_count: A pointer to variable in which to return unit + * array count. + * @Output delim_length: A pointer to variable in which to return NAL + * delimiter length in bits. + * @Output size_delim_length: A pointer to variable in which to return size + * delimiter length in bits. + * @Return None. + */ +typedef void (*bspp_cb_parse_codec_config)(void *swsr_context_handle, + unsigned int *unit_count, + unsigned int *unit_array_count, + unsigned int *delim_length, + unsigned int *size_delim_length); + +/* + * @Function bspp_cb_update_unit_counts + * @Description This is a function prototype for updating unit counts for size + * delimited bitstreams. + * @Input swsr_context_handle: A handle to Shift Register processing + * current bitstream. + * @InOut unit_count: A pointer to variable holding current unit count + * @InOut unit_array_count: A pointer to variable holding current unit + * array count. + * @Return None. + */ +typedef void (*bspp_cb_update_unit_counts)(void *swsr_context_handle, + unsigned int *unit_count, + unsigned int *unit_array_count); + +/* + * @Function bspp_cb_initialise_parsing + * @Description This prototype is for unit group parsing initialization. + * @InOut parse_state: The current unit group parsing state. + * @Return None. + */ +typedef void (*bspp_cb_initialise_parsing)(struct bspp_parse_state *prs_state); + +/* + * @Function bspp_cb_finalise_parsing + * @Description This is prototype is for unit group parsing finalization. + * @Input str_alloc_handle: A handle to stream related resources. + * @InOut parse_state: The current unit group parsing state. + * @Return None. + */ +typedef void (*bspp_cb_finalise_parsing)(void *str_alloc_handle, + struct bspp_parse_state *parse_state); + +/* + * struct bspp_parser_callbacks + * @brief BSPP Standard Related Parser Callback Functions + */ +struct bspp_parser_callbacks { + /* Pointer to standard-specific unit parsing callback function. */ + bspp_cb_parse_unit parse_unit_cb; + /* Pointer to standard-specific data releasing callback function. */ + bspp_cb_release_data release_data_cb; + /* Pointer to standard-specific data resetting callback function. */ + bspp_cb_reset_data reset_data_cb; + /* Pointer to standard-specific data destruction callback function. */ + bspp_cb_destroy_data destroy_data_cb; + /* Pointer to standard-specific codec config parsing callback function */ + bspp_cb_parse_codec_config parse_codec_config_cb; + /* Pointer to standard-specific unit count updating callback function */ + bspp_cb_update_unit_counts update_unit_counts_cb; + /* + * Pointer to standard-specific unit group parsing initialization + * function. + */ + bspp_cb_initialise_parsing initialise_parsing_cb; + /* + * Pointer to standard-specific unit group parsing finalization + * function + */ + bspp_cb_finalise_parsing finalise_parsing_cb; +}; + +/* + * @Function bspp_cb_set_parser_config + * @Description Prototype is for the setting parser config callback functions. + * @Input bstr_format: Input bitstream format. + * @Output vid_std_features: Features of video standard for this bitstream. + * @Output swsr_ctx: Software Shift Register settings for this bitstream. + * @Output parser_callbacks: Parser functions to be used for parsing this + * bitstream. + * @Output inter_pict_data: Inter-picture settings specific for this + * bitstream. + * @Return int : This function returns either IMG_SUCCESS or an error code. + */ +typedef int (*bspp_cb_set_parser_config)(enum vdec_bstr_format bstr_format, + struct bspp_vid_std_features *vid_std_features, + struct bspp_swsr_ctx *swsr_ctx, + struct bspp_parser_callbacks *parser_callbacks, + struct bspp_inter_pict_data *inter_pict_data); + +/* + * @Function bspp_cb_determine_unit_type + * @Description This is a function prototype for determining the BSPP unit type + * based on the bitstream (video standard specific) unit type + * callback functions. + * @Input bitstream_unit_type: Bitstream (video standard specific) unit + * type. + * @Input disable_mvc: Skip MVC related units (relevant for standards + * that support it). + * @InOut bspp_unit_type *: Last BSPP unit type on input. Current BSPP + * unit type on output. + * @Return None. + */ +typedef void (*bspp_cb_determine_unit_type)(unsigned char bitstream_unit_type, + int disable_mvc, + enum bspp_unit_type *bspp_unit_type); + +struct bspp_pps_info *bspp_get_pps_hdr(void *str_res_handle, unsigned int pps_id); + +struct bspp_sequence_hdr_info *bspp_get_sequ_hdr(void *str_res_handle, + unsigned int sequ_id); + +struct bspp_vps_info *bspp_get_vpshdr(void *str_res, unsigned int vps_id); + +void bspp_streamrelese_rawbstrdataplain(const void *str_res, + const void *rawdata); + +void bspp_freeraw_sei_datacontainer(const void *str_res, + struct vdec_raw_bstr_data *rawsei_datacontainer); + +void bspp_freeraw_sei_datalist(const void *str_res, + struct vdec_raw_bstr_data *rawsei_datalist); + +#endif /* __BSPP_INT_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/core.c b/drivers/media/platform/imagination/vxe-vxd/decoder/core.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/core.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/core.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,3723 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VXD Decoder Core component function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#include "core.h" +#include "decoder.h" +#include "img_errors.h" +#include "img_pixfmts.h" +#include "img_profiles_levels.h" +#include "lst.h" +#include "resource.h" +#include "rman_api.h" +#include "vdecdd_utils.h" +#include "vdec_mmu_wrapper.h" +#include "vxd_dec.h" + +#ifdef HAS_HEVC +#define SEQ_RES_NEEDED +#define GENC_BUFF_COUNT 4 +#endif + +/* + * This enum defines resource availability masks. + * @brief Resource Availability + */ +enum core_availability { + CORE_AVAIL_PICTBUF = (1 << 0), + CORE_AVAIL_PICTRES = (1 << 1), + CORE_AVAIL_CORE = (1 << 2), + CORE_AVAIL_MAX, + CORE_AVAIL_FORCE32BITS = 0x7FFFFFFFU +}; + +struct core_mbparam_alloc_info { + unsigned char alloc_mbparam_bufs; + unsigned int mbparam_size; + unsigned int overalloc_mbnum; +}; + +static struct core_mbparam_alloc_info mbparam_allocinfo[VDEC_STD_MAX - 1] = { + /* AllocFlag MBParamSize Overalloc */ + /* MPEG2 */ { TRUE, 0xc8, 0 }, + /* MPEG4 */ { TRUE, 0xc8, 0 }, + /* H263 */ { TRUE, 0xc8, 0 }, + /* H264 */ { TRUE, 0x80, 0 }, + /* VC1 */ { TRUE, 0x80, (4096 * 2) / 0x80 }, + /* AVS */ { TRUE, 0x80, 0 }, + /* REAL */ { TRUE, 0x80, 0 }, + /* JPEG */ { FALSE, 0x00, 0 }, + /* VP6 */ { TRUE, 0x80, 0 }, + /* VP8 */ { TRUE, 0x80, 0 }, + /* SORENSON */ { TRUE, 0xc8, 0 }, + /* HEVC */ { TRUE, 0x40, 0 }, +}; + +struct vxdio_mempool { + unsigned int mem_heap_id; + enum sys_emem_attrib mem_attrib; +}; + +static unsigned int global_avail_slots; +static unsigned char is_core_initialized; + +/* + * This structure contains the core Context. + * @brief core Context + */ +struct core_context { + struct vdecdd_dddev_context *dev_ctx; + /* List of stream context structures */ + struct lst_t core_str_ctx; + vxd_cb vxd_str_processed_cb; +}; + +/* Global Core Context */ +static struct core_context *global_core_ctx; + +/* + * This structure contains the picture buffer size info. + * @brief Picture Resource Info + */ +struct core_pict_bufsize_info { + unsigned int mbparams_bufsize; + +#ifdef HAS_HEVC + union { + struct hevc_bufsize_pict { + /* Size of GENC fragment buffer for HEVC */ + unsigned int genc_fragment_bufsize; + } hevc_bufsize_pict; + }; +#endif +}; + +/* + * This structure contains the sequence resource info. + * @brief Sequence Resource Info + */ +struct core_seq_resinfo { + union { +#ifdef HAS_HEVC + struct hevc_bufsize_seqres { + unsigned int genc_bufsize; /* Size of GEN buffers for HEVC */ + unsigned int intra_bufsize; /* Size of GEN buffers for HEVC */ + unsigned int aux_bufsize; /* Size of GEN buffers for HEVC */ + } hevc_bufsize_seqres; +#endif + +#ifndef SEQ_RES_NEEDED + unsigned int dummy; +#endif + }; +}; + +struct core_pict_resinfo { + unsigned int pict_res_num; + struct core_pict_bufsize_info size_info; + unsigned char is_valid; +}; + +/* + * This structure contains the standard specific part of plant context. + * @brief Standard Specific Context + */ +struct core_std_spec_context { + union { +#ifdef HAS_HEVC + struct hevc_ctx { + /* Counts genc buffer allocations */ + unsigned short genc_id_gen; + } hevc_ctx; +#else + unsigned int dummy; +#endif + }; +}; + +struct core_stream_context; + +struct core_std_spec_operations { + /* Allocates standard specific picture buffers. */ + int (*alloc_picture_buffers)(struct core_stream_context *core_strctx, + struct vdecdd_pict_resint *pict_resint, + struct vxdio_mempool mem_pool, + struct core_pict_resinfo *pict_res_info); + + /* Frees standard specific picture buffers. */ + int (*free_picture_resource)(struct core_stream_context *core_strctx, + struct vdecdd_pict_resint *pic_res_int); + + /* Allocates standard specific sequence buffers. */ + int (*alloc_sequence_buffers)(struct core_stream_context *core_strctx, + struct vdecdd_seq_resint *seq_res_int, + struct vxdio_mempool mem_pool, + struct core_seq_resinfo *seq_res_info); + + /* Frees standard specific sequence buffers. */ + int (*free_sequence_resource)(struct core_stream_context *core_strctx, + struct vdecdd_seq_resint *seq_res_int); + + /* Returns buffer's sizes (common and standard specific). */ + int (*bufs_get_size)(struct core_stream_context *core_strctx, + const struct vdec_comsequ_hdrinfo *seq_hdrinfo, + struct vdec_pict_size *max_pict_size, + struct core_pict_bufsize_info *size_info, + struct core_seq_resinfo *seq_resinfo, + unsigned char *resource_needed); + + /* Checks whether resource is still suitable. */ + unsigned char (*is_stream_resource_suitable)(struct core_pict_resinfo *pict_resinfo, + struct core_pict_resinfo *old_pict_resinfo, + struct core_seq_resinfo *seq_resinfo, + struct core_seq_resinfo *old_seq_resinfo); +}; + +/* + * This structure contains the core Stream Context. + * @brief core Stream Context + */ +struct core_stream_context { + void **link; /* to be part of single linked list */ + struct core_context *core_ctx; + struct vdecdd_ddstr_ctx *dd_str_ctx; + struct vxd_dec_ctx *vxd_dec_context; + + /* list of picture buffers */ + struct lst_t pict_buf_list; + + /* List of picture resources allocated for this stream */ + struct lst_t pict_res_list; + struct lst_t old_pict_res_list; + + struct lst_t aux_pict_res_list; + +#ifdef SEQ_RES_NEEDED + /* List of active sequence resources that are allocated for this stream. */ + struct lst_t seq_res_list; + /* + * List of sequence resources that are allocated for this stream but no + * longer suitable for new sequence(s). + */ + struct lst_t old_seq_res_list; +#endif + + /* List of sequence header information */ + struct lst_t seq_hdr_list; + /* Queue of stream units to be processed */ + struct lst_t str_unit_list; + + struct vdec_comsequ_hdrinfo comseq_hdr_info; + unsigned char opcfg_set; + /* Picture buffer layout to use for decoding. */ + struct vdecdd_ddpict_buf disp_pict_buf; + struct vdec_str_opconfig op_cfg; + unsigned char new_seq; + unsigned char new_op_cfg; + unsigned char no_prev_refs_used; + unsigned int avail_slots; + unsigned int res_avail; + unsigned char stopped; + struct core_pict_resinfo pict_resinfo; + /* Current sequence resource info. */ + struct core_seq_resinfo seq_resinfo; + + /* Reconstructed picture buffer */ + struct vdecdd_ddpict_buf recon_pictbuf; + /* Coded picture size of last reconfiguration */ + struct vdec_pict_size coded_pict_size; + /* Standard specific operations. */ + struct core_std_spec_operations *std_spec_ops; + /* Standard specific context. */ + struct core_std_spec_context std_spec_context; +}; + +#ifdef HAS_HEVC +static int core_free_hevc_picture_resource(struct core_stream_context *core_strctx, + struct vdecdd_pict_resint *pic_res_int); + +static int core_free_hevc_sequence_resource(struct core_stream_context *core_strctx, + struct vdecdd_seq_resint *seq_res_int); + +static int core_hevc_bufs_get_size(struct core_stream_context *core_str_ctx, + const struct vdec_comsequ_hdrinfo *seq_hdr_info, + struct vdec_pict_size *max_pict_size, + struct core_pict_bufsize_info *size_info, + struct core_seq_resinfo *seq_res_info, + unsigned char *resource_needed); + +static unsigned char core_is_hevc_stream_resource_suitable + (struct core_pict_resinfo *pict_res_info, + struct core_pict_resinfo *old_pict_res_info, + struct core_seq_resinfo *seq_res_info, + struct core_seq_resinfo *old_seq_res_info); + +static int core_alloc_hevc_specific_seq_buffers(struct core_stream_context *core_strctx, + struct vdecdd_seq_resint *seq_res_int, + struct vxdio_mempool mempool, + struct core_seq_resinfo *seq_res_info); + +static int core_alloc_hevc_specific_pict_buffers(struct core_stream_context *core_strctx, + struct vdecdd_pict_resint *pict_res_int, + struct vxdio_mempool mempool, + struct core_pict_resinfo *pict_res_info); +#endif + +static int +core_common_bufs_getsize(struct core_stream_context *core_str_ctx, + const struct vdec_comsequ_hdrinfo *comseq_hdrinfo, + struct vdec_pict_size *max_pict_size, + struct core_pict_bufsize_info *size_info, + struct core_seq_resinfo *seq_res_info, unsigned char *res_needed); + +static struct core_std_spec_operations std_specific_ops[VDEC_STD_MAX - 1] = { + /* AllocPicture FreePicture AllocSeq FreeSeq BufsGetSize IsStreamResourceSuitable */ + /* MPEG2 */ { .alloc_picture_buffers = NULL, + .free_picture_resource = NULL, + .alloc_sequence_buffers = NULL, + .free_sequence_resource = NULL, + .bufs_get_size = NULL, + .is_stream_resource_suitable = NULL}, + + /* MPEG4 */ { .alloc_picture_buffers = NULL, + .free_picture_resource = NULL, + .alloc_sequence_buffers = NULL, + .free_sequence_resource = NULL, + .bufs_get_size = NULL, + .is_stream_resource_suitable = NULL}, + + /* H263 */ { .alloc_picture_buffers = NULL, + .free_picture_resource = NULL, + .alloc_sequence_buffers = NULL, + .free_sequence_resource = NULL, + .bufs_get_size = NULL, + .is_stream_resource_suitable = NULL}, + + /* H264 */ { .alloc_picture_buffers = NULL, + .free_picture_resource = NULL, + .alloc_sequence_buffers = NULL, + .free_sequence_resource = NULL, + .bufs_get_size = core_common_bufs_getsize, + .is_stream_resource_suitable = NULL}, + + /* VC1 */ { .alloc_picture_buffers = NULL, + .free_picture_resource = NULL, + .alloc_sequence_buffers = NULL, + .free_sequence_resource = NULL, + .bufs_get_size = NULL, + .is_stream_resource_suitable = NULL}, + + /* AVS */ { .alloc_picture_buffers = NULL, + .free_picture_resource = NULL, + .alloc_sequence_buffers = NULL, + .free_sequence_resource = NULL, + .bufs_get_size = NULL, + .is_stream_resource_suitable = NULL}, + + /* REAL */ { .alloc_picture_buffers = NULL, + .free_picture_resource = NULL, + .alloc_sequence_buffers = NULL, + .free_sequence_resource = NULL, + .bufs_get_size = NULL, + .is_stream_resource_suitable = NULL}, + + /* JPEG */ { .alloc_picture_buffers = NULL, + .free_picture_resource = NULL, + .alloc_sequence_buffers = NULL, + .free_sequence_resource = NULL, + .bufs_get_size = NULL, + .is_stream_resource_suitable = NULL}, + + /* VP6 */ { .alloc_picture_buffers = NULL, + .free_picture_resource = NULL, + .alloc_sequence_buffers = NULL, + .free_sequence_resource = NULL, + .bufs_get_size = NULL, + .is_stream_resource_suitable = NULL}, + + /* VP8 */ { .alloc_picture_buffers = NULL, + .free_picture_resource = NULL, + .alloc_sequence_buffers = NULL, + .free_sequence_resource = NULL, + .bufs_get_size = NULL, + .is_stream_resource_suitable = NULL}, + + /* SORENSON */ { .alloc_picture_buffers = NULL, + .free_picture_resource = NULL, + .alloc_sequence_buffers = NULL, + .free_sequence_resource = NULL, + .bufs_get_size = NULL, + .is_stream_resource_suitable = NULL}, + +#ifdef HAS_HEVC + /* HEVC*/ { .alloc_picture_buffers = core_alloc_hevc_specific_pict_buffers, + .free_picture_resource = core_free_hevc_picture_resource, + .alloc_sequence_buffers = core_alloc_hevc_specific_seq_buffers, + .free_sequence_resource = core_free_hevc_sequence_resource, + .bufs_get_size = core_hevc_bufs_get_size, + .is_stream_resource_suitable = core_is_hevc_stream_resource_suitable}, +#else + /* HEVC */ { .alloc_picture_buffers = NULL, + .free_picture_resource = NULL, + .alloc_sequence_buffers = NULL, + .free_sequence_resource = NULL, + .bufs_get_size = NULL, + .is_stream_resource_suitable = NULL}, +#endif +}; + +#ifdef ERROR_CONCEALMENT +/* + * This structure contains the Error Recovery Frame Store info. + * @brief Error Recovery Frame Store Info + */ +struct core_err_recovery_frame_info { + /* Flag to indicate if Error Recovery Frame Store is enabled for standard. */ + unsigned char enabled; + /* Limitation for maximum frame size based on dimensions. */ + unsigned int max_size; +}; + +static struct core_err_recovery_frame_info err_recovery_frame_info[VDEC_STD_MAX - 1] = { + /* enabled max_frame_size */ + /* MPEG2 */ { TRUE, ~0 }, + /* MPEG4 */ { TRUE, ~0 }, + /* H263 */ { FALSE, 0 }, + /* H264 */ { TRUE, ~0 }, + /* VC1 */ { FALSE, 0 }, + /* AVS */ { FALSE, 0 }, + /* REAL */ { FALSE, 0 }, + /* JPEG */ { FALSE, 0 }, + /* VP6 */ { FALSE, 0 }, + /* VP8 */ { FALSE, 0 }, + /* SORENSON */ { FALSE, 0 }, + /* HEVC */ { TRUE, ~0 }, +}; +#endif + +static void core_fw_response_cb(int res_str_id, unsigned int *msg, unsigned int msg_size, + unsigned int msg_flags) +{ + struct core_stream_context *core_str_ctx; + int ret; + + /* extract core_str_ctx and dec_core_ctx from res_str_id */ + VDEC_ASSERT(res_str_id); + + /* Get access to stream context.. */ + ret = rman_get_resource(res_str_id, VDECDD_STREAM_TYPE_ID, (void **)&core_str_ctx, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + pr_err("could not extract core_str_context\n"); + + ret = decoder_service_firmware_response(core_str_ctx->dd_str_ctx->dec_ctx, + msg, msg_size, msg_flags); + VDEC_ASSERT((ret == IMG_SUCCESS) | (ret == IMG_ERROR_FATAL)); + if (ret != IMG_SUCCESS) + pr_err("decoder_service_firmware_response failed\n"); +} + +/* + * @Function core_initialise + */ +int core_initialise(void *dev_handle, unsigned int int_heap_id, void *vxd_cb_ptr) +{ + struct vdecdd_dd_devconfig dev_cfg_local; + unsigned int num_pipes_local; + int ret; + + if (is_core_initialized) + return IMG_ERROR_INVALID_PARAMETERS; + + is_core_initialized = TRUE; + + global_core_ctx = kzalloc(sizeof(*global_core_ctx), GFP_KERNEL); + if (!global_core_ctx) { + is_core_initialized = FALSE; + return IMG_ERROR_OUT_OF_MEMORY; + } + + global_core_ctx->dev_ctx = kzalloc(sizeof(*global_core_ctx->dev_ctx), GFP_KERNEL); + if (!global_core_ctx->dev_ctx) { + kfree(global_core_ctx); + global_core_ctx = NULL; + is_core_initialized = FALSE; + return IMG_ERROR_OUT_OF_MEMORY; + } + + /* Initialise device context. */ + global_core_ctx->dev_ctx->dev_handle = dev_handle; /* v4L2 dev handle */ + global_core_ctx->vxd_str_processed_cb = (vxd_cb)vxd_cb_ptr; + + ret = decoder_initialise(global_core_ctx->dev_ctx, int_heap_id, + &dev_cfg_local, &num_pipes_local, + &global_core_ctx->dev_ctx->dec_context); + if (ret != IMG_SUCCESS) + goto decoder_init_error; + + global_core_ctx->dev_ctx->internal_heap_id = int_heap_id; + +#ifdef DEBUG_DECODER_DRIVER + /* Dump codec config */ + pr_info("Decode slots/core: %d", dev_cfg_local.num_slots_per_pipe); +#endif + + lst_init(&global_core_ctx->core_str_ctx); + + /* Ensure the resource manager is initialised.. */ + ret = rman_initialise(); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto rman_init_error; + + /* Create resource bucket.. */ + ret = rman_create_bucket(&global_core_ctx->dev_ctx->res_buck_handle); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto create_bucket_error; + + return IMG_SUCCESS; + +create_bucket_error: + rman_deinitialise(); + +rman_init_error: + decoder_deinitialise(global_core_ctx->dev_ctx->dec_context); + +decoder_init_error: + kfree(global_core_ctx->dev_ctx); + global_core_ctx->dev_ctx = NULL; + kfree(global_core_ctx); + global_core_ctx = NULL; + + is_core_initialized = FALSE; + + return ret; +} + +/* + * @Function core_check_decoder_support + * @Description + * This function determines whether Decoder supports bitstream and + * configuration. + */ +static int +core_check_decoder_support(const struct vdecdd_dddev_context *dd_dev_ctx, + const struct vdec_str_configdata *str_cfg_data, + const struct vdec_comsequ_hdrinfo *prev_seq_hdrinfo, + const struct bspp_pict_hdr_info *prev_pict_hdrinfo, + const struct vdecdd_mapbuf_info *map_bufinfo, + struct vdecdd_supp_check *supp_check) +{ + int ret; + struct vdec_unsupp_flags unsupported; + struct vdec_pict_rendinfo disp_pict_rend_info; + + memset(&disp_pict_rend_info, 0, sizeof(struct vdec_pict_rendinfo)); + + /* + * If output picture buffer information is provided create another + * with properties required by bitstream so that it can be compared. + */ + if (supp_check->disp_pictbuf) { + struct vdec_pict_rend_config pict_rend_cfg; + + memset(&pict_rend_cfg, 0, sizeof(pict_rend_cfg)); + + /* + * Cannot validate the display picture buffer layout without + * knowing the pixel format required for the output and the + * sequence information. + */ + if (supp_check->comseq_hdrinfo && supp_check->op_cfg) { + pict_rend_cfg.coded_pict_size = + supp_check->comseq_hdrinfo->max_frame_size; + + pict_rend_cfg.byte_interleave = + supp_check->disp_pictbuf->buf_config.byte_interleave; + + pict_rend_cfg.packed = + supp_check->disp_pictbuf->buf_config.packed; + + pict_rend_cfg.stride_alignment = + supp_check->disp_pictbuf->buf_config.stride_alignment; + + /* + * Recalculate render picture layout based upon + * sequence and output config. + */ + vdecddutils_pictbuf_getinfo(str_cfg_data, + &pict_rend_cfg, + supp_check->op_cfg, + &disp_pict_rend_info); + } + } + /* Check that the decoder supports the picture. */ + ret = decoder_check_support(dd_dev_ctx->dec_context, str_cfg_data, + supp_check->op_cfg, + supp_check->disp_pictbuf, + (disp_pict_rend_info.rendered_size) ? + &disp_pict_rend_info : NULL, + supp_check->comseq_hdrinfo, + supp_check->pict_hdrinfo, + prev_seq_hdrinfo, + prev_pict_hdrinfo, + supp_check->non_cfg_req, + &unsupported, + &supp_check->features); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) { + if (ret == IMG_ERROR_NOT_SUPPORTED) + supp_check->unsupp_flags = unsupported; + } + + return ret; +} + +/* + * @Function core_supported_features + */ +int core_supported_features(struct vdec_features *features) +{ + struct vdecdd_dddev_context *dd_dev_ctx; + + VDEC_ASSERT(global_core_ctx); + + dd_dev_ctx = global_core_ctx->dev_ctx; + VDEC_ASSERT(dd_dev_ctx); + if (!dd_dev_ctx) + return IMG_ERROR_NOT_INITIALISED; + + return decoder_supported_features(dd_dev_ctx->dec_context, features); +} + +/* + * @Function core_stream_stop + */ +int core_stream_stop(unsigned int res_str_id) +{ + int ret = IMG_SUCCESS; + struct vdecdd_str_unit *stop_unit; + struct vdecdd_ddstr_ctx *ddstr_ctx; + struct core_stream_context *core_str_ctx; + + /* + * Stream based messages without a device context + * must have a stream ID. + */ + VDEC_ASSERT(res_str_id); + + if (res_str_id == 0) { + pr_err("Invalid params passed to %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Get access to stream context.. */ + ret = rman_get_resource(res_str_id, VDECDD_STREAM_TYPE_ID, + (void **)&core_str_ctx, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + VDEC_ASSERT(core_str_ctx); + + ddstr_ctx = core_str_ctx->dd_str_ctx; + + /* Validate input arguments */ + VDEC_ASSERT(ddstr_ctx); + + /* + * Disregard this stop request if the stream is currently + * stopped or being stopped. + */ + if (ddstr_ctx->dd_str_state == VDECDD_STRSTATE_PLAYING) { + vdecddutils_create_strunit(&stop_unit, NULL); + if (!stop_unit) { + pr_err("Failed to allocate memory for stop unit\n"); + return IMG_ERROR_OUT_OF_MEMORY; + } + memset(stop_unit, 0, sizeof(*stop_unit)); + + stop_unit->str_unit_type = VDECDD_STRUNIT_STOP; + stop_unit->str_unit_tag = NULL; + stop_unit->decode = FALSE; + + /* + * Since the stop is now to be passed to the decoder signal + * that we're stopping. + */ + ddstr_ctx->dd_str_state = VDECDD_STRSTATE_STOPPING; + decoder_stream_process_unit(ddstr_ctx->dec_ctx, stop_unit); + core_str_ctx->stopped = TRUE; + vdecddutils_free_strunit(stop_unit); + } + + return ret; +} + +/* + * @Function core_is_stream_idle + */ +static unsigned char core_is_stream_idle(struct vdecdd_ddstr_ctx *dd_str_ctx) +{ + unsigned char is_stream_idle; + + is_stream_idle = decoder_is_stream_idle(dd_str_ctx->dec_ctx); + + return is_stream_idle; +} + +/* + * @Function core_stream_destroy + */ +int core_stream_destroy(unsigned int res_str_id) +{ + struct vdecdd_ddstr_ctx *ddstr_ctx; + struct core_stream_context *core_str_ctx; + int ret; + + /* + * Stream based messages without a device context + * must have a stream ID. + */ + VDEC_ASSERT(res_str_id); + + if (res_str_id == 0) { + pr_err("Invalid params passed to %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Get access to stream context.. */ + ret = rman_get_resource(res_str_id, VDECDD_STREAM_TYPE_ID, + (void **)&core_str_ctx, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + VDEC_ASSERT(core_str_ctx); + + ddstr_ctx = core_str_ctx->dd_str_ctx; + + /* Validate input arguments */ + VDEC_ASSERT(ddstr_ctx); + + ret = core_stream_stop(res_str_id); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + lst_remove(&global_core_ctx->core_str_ctx, core_str_ctx); + + /* Destroy stream if idle otherwise wait and do it later */ + if (core_is_stream_idle(ddstr_ctx)) + rman_free_resource(ddstr_ctx->res_handle); + + pr_debug("Core stream destroy successfully\n"); + /* Return success.. */ + return IMG_SUCCESS; +} + +static int +core_picture_attach_resources(struct core_stream_context *core_str_ctx, + struct vdecdd_str_unit *str_unit, unsigned char check) +{ + unsigned int ret = IMG_SUCCESS; + + /* + * Take sequence header from cache. + * Note: sequence header id must be set in PICTURE_START unit + */ + str_unit->seq_hdr_info = resource_list_getbyid(&core_str_ctx->seq_hdr_list, + str_unit->seq_hdr_id); + + /* Check is not needed e.g. when freeing resources at stream destroy */ + if (check && !str_unit->seq_hdr_info) { + pr_err("[USERSID=0x%08X] Sequence header not available for current picture while attaching", + core_str_ctx->dd_str_ctx->str_config_data.user_str_id); + ret = IMG_ERROR_NOT_SUPPORTED; + } + + return ret; +} + +/* + * @Function core_handle_processed_unit + */ +static int core_handle_processed_unit(struct core_stream_context *c_str_ctx, + struct vdecdd_str_unit *str_unit) +{ + struct bspp_bitstr_seg *bstr_seg; + struct vdecdd_ddstr_ctx *dd_str_ctx = c_str_ctx->dd_str_ctx; + int ret; + struct core_context *g_ctx = global_core_ctx; + + pr_debug("%s stream unit type = %d\n", __func__, str_unit->str_unit_type); + /* check for type of the unit */ + switch (str_unit->str_unit_type) { + case VDECDD_STRUNIT_SEQUENCE_START: + /* nothing to be done as sps is maintained till it changes */ + break; + + case VDECDD_STRUNIT_PICTURE_START: + /* Loop over bit stream segments.. */ + bstr_seg = (struct bspp_bitstr_seg *) + lst_removehead(&str_unit->bstr_seg_list); + + while (bstr_seg) { + lst_add(&c_str_ctx->vxd_dec_context->seg_list, bstr_seg); + if (bstr_seg->bstr_seg_flag & VDECDD_BSSEG_LASTINBUFF && + dd_str_ctx->dd_str_state != VDECDD_STRSTATE_STOPPED) { + struct vdecdd_ddbuf_mapinfo *ddbuf_map_info; + /* Get access to map info context.. */ + ret = rman_get_resource(bstr_seg->bufmap_id, VDECDD_BUFMAP_TYPE_ID, + (void **)&ddbuf_map_info, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + g_ctx->vxd_str_processed_cb(c_str_ctx->vxd_dec_context, + VXD_CB_STRUNIT_PROCESSED, + bstr_seg->bufmap_id, 0); + } + /* Get next segment. */ + bstr_seg = (struct bspp_bitstr_seg *) + lst_removehead(&str_unit->bstr_seg_list); + } + break; + + case VDECDD_STRUNIT_PICTURE_END: + g_ctx->vxd_str_processed_cb(c_str_ctx->vxd_dec_context, + VXD_CB_PICT_END, 0xFFFF, 0); + break; + + case VDECDD_STRUNIT_STOP: + /* + * Signal that the stream has been stopped in the + * device driver. + */ + dd_str_ctx->dd_str_state = VDECDD_STRSTATE_STOPPED; + + break; + + default: + pr_err("Invalid stream unit type passed\n"); + return IMG_ERROR_GENERIC_FAILURE; + } + +#ifdef DEBUG_DECODER_DRIVER + pr_info("[SID=0x%08X] [UTYPE=0x%08X] PROCESSED", + dd_str_ctx->res_str_id, + str_unit->str_unit_type); +#endif + + /* Return success.. */ + return IMG_SUCCESS; +} + +static int +core_handle_decoded_picture(struct core_stream_context *core_str_ctx, + struct vdecdd_picture *picture, unsigned int type) +{ + /* Pick the client image buffer. */ + struct vdecdd_ddbuf_mapinfo *pictbuf_mapinfo = picture->disp_pict_buf.pict_buf; + + VDEC_ASSERT(pictbuf_mapinfo); + if (!pictbuf_mapinfo) + return IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + + global_core_ctx->vxd_str_processed_cb(core_str_ctx->vxd_dec_context, + (enum vxd_cb_type)type, pictbuf_mapinfo->buf_map_id, + picture->dec_pict_info->err_flags); + return IMG_SUCCESS; +} + +static int core_stream_processed_cb(void *handle, int cb_type, void *cb_item) +{ + int ret; + struct core_stream_context *core_str_ctx = + (struct core_stream_context *)handle; + VDEC_ASSERT(core_str_ctx); + if (!core_str_ctx) { + pr_err("NULL handle passed to core callback\n"); + return IMG_ERROR_GENERIC_FAILURE; + } + + pr_debug("%s callback type = %d\n", __func__, cb_type); + /* Based on callback type, retrieve the item */ + switch (cb_type) { + case VXD_CB_STRUNIT_PROCESSED: + { + struct vdecdd_str_unit *str_unit = + (struct vdecdd_str_unit *)cb_item; + VDEC_ASSERT(str_unit); + if (!str_unit) { + pr_err("NULL item passed to core callback type STRUNIT_PROCESSED\n"); + return IMG_ERROR_GENERIC_FAILURE; + } + ret = core_handle_processed_unit(core_str_ctx, str_unit); + if (ret != IMG_SUCCESS) { + pr_err("core_handle_processed_unit returned error\n"); + return ret; + } + break; + } + + case VXD_CB_PICT_DECODED: + case VXD_CB_PICT_DISPLAY: + case VXD_CB_PICT_RELEASE: + { + struct vdecdd_picture *picture = (struct vdecdd_picture *)cb_item; + + if (!picture) { + pr_err("NULL item passed to core callback type PICTURE_DECODED\n"); + return IMG_ERROR_GENERIC_FAILURE; + } + ret = core_handle_decoded_picture(core_str_ctx, picture, cb_type); + break; + } + + case VXD_CB_STR_END: + global_core_ctx->vxd_str_processed_cb(core_str_ctx->vxd_dec_context, + (enum vxd_cb_type)cb_type, 0, 0); + ret = IMG_SUCCESS; + + break; + case VXD_CB_ERROR_FATAL: + /* + * Whenever the error case occurs, we need to handle the error case. + * Need to forward this error to v4l2 glue layer. + * in this case the cb_item is the error_code as we may not have + * an associated picture. + */ + global_core_ctx->vxd_str_processed_cb(core_str_ctx->vxd_dec_context, + (enum vxd_cb_type)cb_type, 0, *((unsigned int *)cb_item)); + ret = IMG_SUCCESS; + break; + default: + return 0; + } + + return ret; +} + +static int core_decoder_queries(void *handle, int query, void *item) +{ + struct core_stream_context *core_str_ctx = + (struct core_stream_context *)handle; + VDEC_ASSERT(core_str_ctx); + if (!core_str_ctx) { + pr_err("NULL handle passed to %s callback\n", __func__); + return IMG_ERROR_GENERIC_FAILURE; + } + + switch (query) { + case DECODER_CORE_GET_RES_LIMIT: + { + unsigned int num_img_bufs; + unsigned int num_res; + + num_img_bufs = resource_list_getnum(&core_str_ctx->pict_buf_list); + + /* Return the number of internal resources. */ + num_res = core_str_ctx->pict_resinfo.pict_res_num; + + /* Return the minimum of the two. */ + *((unsigned int *)item) = vdec_size_min(num_img_bufs, num_res); + } + break; + + default: + return IMG_ERROR_GENERIC_FAILURE; + } + return IMG_SUCCESS; +} + +static int +core_free_common_picture_resource(struct core_stream_context *core_str_ctx, + struct vdecdd_pict_resint *pict_resint) +{ + int ret = IMG_SUCCESS; + + if (pict_resint->mb_param_buf && pict_resint->mb_param_buf->ddbuf_info.hndl_memory) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("mmu_free for buff_id[%d]\n", + pict_resint->mb_param_buf->ddbuf_info.buff_id); +#endif + ret = mmu_free_mem(core_str_ctx->dd_str_ctx->mmu_str_handle, + &pict_resint->mb_param_buf->ddbuf_info); + if (ret != IMG_SUCCESS) + pr_err("MMU_Free for MBParam buffer failed with error %u", ret); + + kfree(pict_resint->mb_param_buf); + pict_resint->mb_param_buf = NULL; + } + return ret; +} + +static int core_free_resbuf(struct vdecdd_ddbuf_mapinfo **buf_handle, void *mmu_handle) +{ + int ret = IMG_SUCCESS; + struct vdecdd_ddbuf_mapinfo *buf = *buf_handle; + + if (buf) { + if (buf->ddbuf_info.hndl_memory) { + ret = mmu_free_mem(mmu_handle, &buf->ddbuf_info); + VDEC_ASSERT(ret == IMG_SUCCESS); + } + kfree(buf); + *buf_handle = NULL; + } + return ret; +} + +/* + * @Function core_free_picture_resource + */ +static int +core_free_picture_resource(struct core_stream_context *core_strctx, + struct vdecdd_pict_resint *pict_resint) +{ + int result = IMG_SUCCESS; + + /* Check input arguments */ + if (!core_strctx || !pict_resint) { + VDEC_ASSERT(0); + return -EINVAL; + } + + result = core_free_common_picture_resource(core_strctx, pict_resint); + + VDEC_ASSERT(core_strctx->std_spec_ops); + if (core_strctx->std_spec_ops->free_picture_resource) + core_strctx->std_spec_ops->free_picture_resource(core_strctx, + pict_resint); + +#ifdef SEQ_RES_NEEDED + if (pict_resint->seq_resint) { + resource_item_return(&pict_resint->seq_resint->ref_count); + pict_resint->seq_resint = 0; + } +#endif + + if (result == IMG_SUCCESS) + kfree(pict_resint); + + return result; +} + +/* + * @Function core_free_sequence_resource + */ +#ifdef SEQ_RES_NEEDED +static int +core_free_common_sequence_resource(struct core_stream_context *core_strctx, + struct vdecdd_seq_resint *seqres_int) +{ + int result; + + result = core_free_resbuf(&seqres_int->err_pict_buf, + core_strctx->dd_str_ctx->mmu_str_handle); + if (result != IMG_SUCCESS) + pr_err("MMU_Free for Error Recover Frame Store buffer failed with error %u", + result); + + return result; +} + +static void +core_free_sequence_resource(struct core_stream_context *core_strctx, + struct vdecdd_seq_resint *seqres_int) +{ + VDEC_ASSERT(core_strctx->std_spec_ops); + core_free_common_sequence_resource(core_strctx, seqres_int); + + if (core_strctx->std_spec_ops->free_sequence_resource) + core_strctx->std_spec_ops->free_sequence_resource(core_strctx, seqres_int); + + kfree(seqres_int); +} +#endif + +/* + * @Function core_stream_resource_deprecate + */ +static int core_stream_resource_deprecate(struct core_stream_context *core_str_ctx) +{ + struct vdecdd_pict_resint *picres_int; + int ret; + + /* Free all "old" picture resources since these should now be unused. */ + picres_int = lst_first(&core_str_ctx->old_pict_res_list); + while (picres_int) { + if (picres_int->ref_cnt != 0) { + pr_warn("[USERSID=0x%08X] Internal resource should be unused since it has been deprecated before", + core_str_ctx->dd_str_ctx->str_config_data.user_str_id); + + picres_int = lst_next(picres_int); + } else { + struct vdecdd_pict_resint *picres_int_to_remove = picres_int; + + picres_int = lst_next(picres_int); + + lst_remove(&core_str_ctx->old_pict_res_list, picres_int_to_remove); + ret = core_free_picture_resource(core_str_ctx, picres_int_to_remove); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + } + + /* Move all "active" picture resources to the "old" list if they are still in use. */ + picres_int = lst_removehead(&core_str_ctx->pict_res_list); + while (picres_int) { + /* Remove picture resource from the list. */ + ret = resource_list_remove(&core_str_ctx->aux_pict_res_list, picres_int); + + /* IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE is a valid return code + * e.g. during reconfigure we are clearing the sPictBufferList list + * and then try to remove the buffers again from the same list (empty now) + * though core UNMAP_BUF messages + */ + if (ret != IMG_SUCCESS && ret != IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE) { + pr_err("[USERSID=0x%08X] Failed to remove picture resource", + core_str_ctx->dd_str_ctx->str_config_data.user_str_id); + return ret; + } + /* + * If the active resource is not being used, free now. + * Otherwise add to the old list to be freed later. + */ + if (picres_int->ref_cnt == 0) { + ret = core_free_picture_resource(core_str_ctx, picres_int); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } else { + lst_add(&core_str_ctx->old_pict_res_list, picres_int); + } + picres_int = lst_removehead(&core_str_ctx->pict_res_list); + } + + /* Reset the resource configuration. */ + memset(&core_str_ctx->pict_resinfo, 0, sizeof(core_str_ctx->pict_resinfo)); + +#ifdef SEQ_RES_NEEDED + { + struct vdecdd_seq_resint *seqres_int; + + /* Free all "old" sequence resources since these should now be unused. */ + seqres_int = lst_first(&core_str_ctx->old_seq_res_list); + while (seqres_int) { + if (seqres_int->ref_count != 0) { + pr_warn("[USERSID=0x%08X] Internal sequence resource should be unused since it has been deprecated before", + core_str_ctx->dd_str_ctx->str_config_data.user_str_id); + seqres_int = lst_next(seqres_int); + } else { + struct vdecdd_seq_resint *seqres_int_to_remove = seqres_int; + + seqres_int = lst_next(seqres_int); + + lst_remove(&core_str_ctx->old_seq_res_list, seqres_int_to_remove); + core_free_sequence_resource(core_str_ctx, seqres_int_to_remove); + } + } + + /* Move all "active" sequence resources to the "old" + * list if they are still in use. + */ + seqres_int = lst_removehead(&core_str_ctx->seq_res_list); + while (seqres_int) { + /* + * If the active resource is not being used, free now. + * Otherwise add to the old list to be freed later. + */ + seqres_int->ref_count == 0 ? core_free_sequence_resource(core_str_ctx, + seqres_int) : + lst_add(&core_str_ctx->old_seq_res_list, seqres_int); + + seqres_int = lst_removehead(&core_str_ctx->seq_res_list); + } + + /* Reset the resource configuration. */ + memset(&core_str_ctx->seq_resinfo, 0, sizeof(core_str_ctx->seq_resinfo)); + } +#endif + return IMG_SUCCESS; +} + +/* + * @Function core_stream_resource_destroy + */ +static int core_stream_resource_destroy(struct core_stream_context *core_str_ctx) +{ + struct vdecdd_pict_resint *picres_int; + int ret; + + /* Remove any "active" picture resources allocated for this stream. */ + picres_int = lst_removehead(&core_str_ctx->pict_res_list); + while (picres_int) { + ret = core_free_picture_resource(core_str_ctx, picres_int); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + picres_int = lst_removehead(&core_str_ctx->pict_res_list); + } + + /* Remove any "old" picture resources allocated for this stream. */ + picres_int = lst_removehead(&core_str_ctx->old_pict_res_list); + while (picres_int) { + ret = core_free_picture_resource(core_str_ctx, picres_int); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + picres_int = lst_removehead(&core_str_ctx->old_pict_res_list); + } + + /* Reset the resource configuration. */ + memset(&core_str_ctx->pict_resinfo, 0, sizeof(core_str_ctx->pict_resinfo)); + +#ifdef SEQ_RES_NEEDED + { + struct vdecdd_seq_resint *seqres_int; + + /* Remove any "active" sequence resources allocated for this stream. */ + seqres_int = lst_removehead(&core_str_ctx->seq_res_list); + while (seqres_int) { + core_free_sequence_resource(core_str_ctx, seqres_int); + seqres_int = lst_removehead(&core_str_ctx->seq_res_list); + } + + /* Remove any "old" sequence resources allocated for this stream. */ + seqres_int = lst_removehead(&core_str_ctx->old_seq_res_list); + while (seqres_int) { + core_free_sequence_resource(core_str_ctx, seqres_int); + seqres_int = lst_removehead(&core_str_ctx->old_seq_res_list); + } + + /* Reset the resource configuration. */ + memset(&core_str_ctx->seq_resinfo, 0, sizeof(core_str_ctx->seq_resinfo)); + } +#endif + return IMG_SUCCESS; +} + +/* + * @Function core_fn_free_stream_unit + */ +static int core_fn_free_stream_unit(struct vdecdd_str_unit *str_unit, void *param) +{ + struct core_stream_context *core_str_ctx = (struct core_stream_context *)param; + unsigned int ret = IMG_SUCCESS; + + /* Attach picture resources where required. */ + if (str_unit->str_unit_type == VDECDD_STRUNIT_PICTURE_START) + /* + * Do not force attachment because the resources can be + * unattached yet, e.g. in case of not yet processed picture + * units + */ + ret = core_picture_attach_resources(core_str_ctx, str_unit, FALSE); + + str_unit->decode = FALSE; + + return ret; +} + +/* + * @Function core_fn_free_stream + */ +static void core_fn_free_stream(void *param) +{ + int ret; + struct vdecdd_ddstr_ctx *dd_str_context; + struct vdecdd_dddev_context *dd_dev_ctx; + struct core_stream_context *core_str_ctx; + + /* Validate input arguments */ + VDEC_ASSERT(param); + + core_str_ctx = (struct core_stream_context *)param; + + dd_str_context = core_str_ctx->dd_str_ctx; + + VDEC_ASSERT(dd_str_context); + if (!dd_str_context) + return; + + dd_dev_ctx = dd_str_context->dd_dev_context; + VDEC_ASSERT(dd_dev_ctx); + + if (!lst_empty(&core_str_ctx->str_unit_list)) { + /* + * Try and empty the list. Since this function is tearing down the core stream, + * test result using assert and continue to tidy-up as much as possible. + */ + ret = resource_list_empty(&core_str_ctx->str_unit_list, FALSE, + (resource_pfn_freeitem)core_fn_free_stream_unit, + core_str_ctx); + VDEC_ASSERT(ret == IMG_SUCCESS); + } + + if (!lst_empty(&core_str_ctx->pict_buf_list)) { + /* + * Try and empty the list. Since this function is tearing down the core stream, + * test result using assert and continue to tidy-up as much as possible. + */ + ret = resource_list_empty(&core_str_ctx->pict_buf_list, TRUE, NULL, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + } + + if (!lst_empty(&core_str_ctx->aux_pict_res_list)) { + /* + * Try and empty the list. Since this function is tearing down the core stream, + * test result using assert and continue to tidy-up as much as possible. + */ + ret = resource_list_empty(&core_str_ctx->aux_pict_res_list, TRUE, NULL, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + } + + if (!lst_empty(&core_str_ctx->seq_hdr_list)) { + /* + * Try and empty the list. Since this function is tearing down the core stream, + * test result using assert and continue to tidy-up as much as possible. + */ + ret = resource_list_empty(&core_str_ctx->seq_hdr_list, FALSE, NULL, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + } + + /* Destroy stream in the Decoder. */ + if (dd_str_context->dec_ctx) { + ret = decoder_stream_destroy(dd_str_context->dec_ctx, FALSE); + VDEC_ASSERT(ret == IMG_SUCCESS); + dd_str_context->dec_ctx = NULL; + } + + core_stream_resource_destroy(core_str_ctx); + + /* Destroy the MMU context for this stream. */ + if (dd_str_context->mmu_str_handle) { + ret = mmu_stream_destroy(dd_str_context->mmu_str_handle); + + VDEC_ASSERT(ret == IMG_SUCCESS); + dd_str_context->mmu_str_handle = NULL; + } + + /* Destroy the stream resources. */ + if (dd_str_context->res_buck_handle) { + rman_destroy_bucket(dd_str_context->res_buck_handle); + dd_str_context->res_buck_handle = NULL; + } + + /* Free stream context. */ + kfree(dd_str_context); + + /* Free the stream context. */ + kfree(core_str_ctx); +} + +/* + * @Function core_is_unsupported + */ +static unsigned char core_is_unsupported(struct vdec_unsupp_flags *unsupp_flags) +{ + unsigned char unsupported = FALSE; + + if (unsupp_flags->str_cfg || unsupp_flags->seq_hdr || + unsupp_flags->pict_hdr || unsupp_flags->str_opcfg || + unsupp_flags->op_bufcfg) + unsupported = TRUE; + + return unsupported; +} + +int core_stream_create(void *vxd_dec_ctx_arg, + const struct vdec_str_configdata *str_cfg_data, + unsigned int *res_str_id) +{ + int ret; + struct vdecdd_ddstr_ctx *dd_str_context; + struct vdecdd_supp_check supp_check; + struct vdecdd_dddev_context *dd_dev_ctx; + struct core_stream_context *core_str_ctx; + + /* Validate input arguments */ + VDEC_ASSERT(str_cfg_data); + VDEC_ASSERT(res_str_id); + + VDEC_ASSERT(global_core_ctx); + dd_dev_ctx = global_core_ctx->dev_ctx; + + VDEC_ASSERT(dd_dev_ctx); + if (!dd_dev_ctx) + return IMG_ERROR_NOT_INITIALISED; + + /* Allocate Core Stream Context */ + core_str_ctx = kzalloc(sizeof(*core_str_ctx), GFP_KERNEL); + if (!core_str_ctx) + return IMG_ERROR_OUT_OF_MEMORY; + + core_str_ctx->core_ctx = global_core_ctx; + core_str_ctx->vxd_dec_context = (struct vxd_dec_ctx *)vxd_dec_ctx_arg; + + ((struct vxd_dec_ctx *)vxd_dec_ctx_arg)->dev_ctx = global_core_ctx->dev_ctx; + + /* register callback for firmware response */ + core_str_ctx->vxd_dec_context->cb = (decode_cb)core_fw_response_cb; + + lst_init(&core_str_ctx->pict_buf_list); + lst_init(&core_str_ctx->pict_res_list); + lst_init(&core_str_ctx->old_pict_res_list); + lst_init(&core_str_ctx->aux_pict_res_list); + lst_init(&core_str_ctx->seq_hdr_list); + lst_init(&core_str_ctx->str_unit_list); + +#ifdef SEQ_RES_NEEDED + lst_init(&core_str_ctx->seq_res_list); + lst_init(&core_str_ctx->old_seq_res_list); +#endif + + /* Allocate device stream context.. */ + dd_str_context = kzalloc(sizeof(*dd_str_context), GFP_KERNEL); + VDEC_ASSERT(dd_str_context); + if (!dd_str_context) { + kfree(core_str_ctx); + core_str_ctx = NULL; + return IMG_ERROR_OUT_OF_MEMORY; + } + + dd_str_context->dd_dev_context = dd_dev_ctx; + core_str_ctx->dd_str_ctx = dd_str_context; + + /* Check stream configuration. */ + memset(&supp_check, 0x0, sizeof(supp_check)); + ret = core_check_decoder_support(dd_dev_ctx, str_cfg_data, NULL, NULL, NULL, &supp_check); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + if (core_is_unsupported(&supp_check.unsupp_flags)) { + ret = IMG_ERROR_NOT_SUPPORTED; + goto error; + } + + /* Create a bucket for the resources.. */ + ret = rman_create_bucket(&dd_str_context->res_buck_handle); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + /* Register the stream as a device resource.. */ + ret = rman_register_resource(dd_dev_ctx->res_buck_handle, + VDECDD_STREAM_TYPE_ID, + core_fn_free_stream, core_str_ctx, + &dd_str_context->res_handle, + &dd_str_context->res_str_id); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + /* Create unique Stream Id */ + dd_str_context->km_str_id = core_str_ctx->vxd_dec_context->stream.id; + + /* + * Create stream in the Decoder. + * NOTE: this must take place first since it creates the MMU context. + */ + ret = decoder_stream_create(dd_dev_ctx->dec_context, *str_cfg_data, + dd_str_context->km_str_id, + &dd_str_context->mmu_str_handle, + core_str_ctx->vxd_dec_context, + core_str_ctx, &dd_str_context->dec_ctx, + (void *)core_stream_processed_cb, + (void *)core_decoder_queries); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + /* Setup stream context.. */ + dd_str_context->str_config_data = *str_cfg_data; + dd_str_context->dd_str_state = VDECDD_STRSTATE_STOPPED; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("[SID=0x%08X] New stream created [USERSID=0x%08X]", + dd_str_context->res_str_id, str_cfg_data->user_str_id); +#endif + + *res_str_id = dd_str_context->res_str_id; + if (str_cfg_data->vid_std > 0 && str_cfg_data->vid_std <= VDEC_STD_MAX) { + core_str_ctx->std_spec_ops = &std_specific_ops[str_cfg_data->vid_std - 1]; + } else { + pr_err("%s: Invalid parameters\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + lst_add(&global_core_ctx->core_str_ctx, core_str_ctx); + + /* Return success.. */ + return IMG_SUCCESS; + +error: + if (dd_str_context->res_handle) + rman_free_resource(dd_str_context->res_handle); + else + core_fn_free_stream(core_str_ctx); + + return ret; +} + +static int +core_get_resource_availability(struct core_stream_context *core_str_ctx) +{ + unsigned int avail = ~0; + + if (resource_list_getnumavail(&core_str_ctx->pict_buf_list) == 0) + avail &= ~CORE_AVAIL_PICTBUF; + + if (resource_list_getnumavail(&core_str_ctx->aux_pict_res_list) == 0) + avail &= ~CORE_AVAIL_PICTRES; + + if (global_avail_slots == 0) + avail &= ~CORE_AVAIL_CORE; + + return avail; +} + +static int +core_stream_set_pictbuf_config(struct vdecdd_ddstr_ctx *dd_str_ctx, + struct vdec_pict_bufconfig *pictbuf_cfg) +{ + int ret; + + /* Validate input arguments */ + VDEC_ASSERT(dd_str_ctx); + VDEC_ASSERT(pictbuf_cfg); + + /* + * If there are no buffers mapped or the configuration is not set + * (only done when reconfiguring output) then calculate the output + * picture buffer layout. + */ + if (dd_str_ctx->map_buf_info.num_buf == 0 || + dd_str_ctx->disp_pict_buf.buf_config.buf_size == 0) { + struct vdecdd_supp_check supp_check; + struct vdecdd_ddpict_buf disp_pictbuf; + + memset(&disp_pictbuf, 0, sizeof(disp_pictbuf)); + + disp_pictbuf.buf_config = *pictbuf_cfg; + + /* + * Ensure that the external picture buffer information + * is compatible with the hardware and convert to internal + * driver representation. + */ + ret = vdecddutils_convert_buffer_config(&dd_str_ctx->str_config_data, + &disp_pictbuf.buf_config, + &disp_pictbuf.rend_info); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + /* + * Provide the current state for validation against the new + * buffer configuration. + */ + memset(&supp_check, 0, sizeof(supp_check)); + supp_check.disp_pictbuf = &disp_pictbuf; + + if (dd_str_ctx->comseq_hdr_info.max_frame_size.width) + supp_check.comseq_hdrinfo = &dd_str_ctx->comseq_hdr_info; + + if (dd_str_ctx->str_op_configured) + supp_check.op_cfg = &dd_str_ctx->opconfig; + + ret = core_check_decoder_support(dd_str_ctx->dd_dev_context, + &dd_str_ctx->str_config_data, + &dd_str_ctx->prev_comseq_hdr_info, + &dd_str_ctx->prev_pict_hdr_info, + &dd_str_ctx->map_buf_info, + &supp_check); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + if (core_is_unsupported(&supp_check.unsupp_flags)) { + ret = IMG_ERROR_NOT_SUPPORTED; + goto error; + } + + dd_str_ctx->disp_pict_buf = disp_pictbuf; + } else { + /* + * Check configuration of buffer matches that for stream + * including any picture buffers that are already mapped. + */ + if (memcmp(pictbuf_cfg, &dd_str_ctx->disp_pict_buf.buf_config, + sizeof(*pictbuf_cfg))) { + /* + * Configuration of output buffer doesn't match the + * rest. + */ + pr_err("[SID=0x%08X] All output buffers must have the same properties.", + dd_str_ctx->res_str_id); + ret = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + } + + /* Return success.. */ + return IMG_SUCCESS; + +error: + return ret; +} + +int +core_stream_set_output_config(unsigned int res_str_id, + struct vdec_str_opconfig *str_opcfg, + struct vdec_pict_bufconfig *pict_bufcfg_handle) +{ + struct vdecdd_supp_check supp_check; + struct vdec_pict_bufconfig pict_buf_cfg; + struct vdec_pict_rendinfo disp_pict_rend_info; + int ret; + + struct vdecdd_ddstr_ctx *dd_str_context; + struct core_stream_context *core_str_ctx; + + /* + * Stream based messages without a device context + * must have a stream ID. + */ + VDEC_ASSERT(res_str_id); + + /* Get access to stream context */ + ret = rman_get_resource(res_str_id, VDECDD_STREAM_TYPE_ID, (void **)&core_str_ctx, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dd_str_context = core_str_ctx->dd_str_ctx; + + VDEC_ASSERT(dd_str_context); + VDEC_ASSERT(str_opcfg); + + memset(&supp_check, 0, sizeof(supp_check)); + if (core_str_ctx->new_seq) + supp_check.comseq_hdrinfo = &dd_str_context->comseq_hdr_info; + else + supp_check.comseq_hdrinfo = NULL; + + supp_check.op_cfg = str_opcfg; + + /* + * Validate stream output configuration against display + * buffer properties if no new picture buffer configuration + * is provided. + */ + if (!pict_bufcfg_handle) { + VDEC_ASSERT(dd_str_context->disp_pict_buf.rend_info.rendered_size); + supp_check.disp_pictbuf = &dd_str_context->disp_pict_buf; + } + + /* Validate output configuration. */ + ret = core_check_decoder_support(dd_str_context->dd_dev_context, + &dd_str_context->str_config_data, + &dd_str_context->prev_comseq_hdr_info, + &dd_str_context->prev_pict_hdr_info, + &dd_str_context->map_buf_info, + &supp_check); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return IMG_SUCCESS; + + if (core_is_unsupported(&supp_check.unsupp_flags)) + return IMG_ERROR_NOT_SUPPORTED; + + /* Update the stream output configuration. */ + dd_str_context->opconfig = *str_opcfg; + + /* Mark output as configured. */ + dd_str_context->str_op_configured = TRUE; + + if (pict_bufcfg_handle) { + /* + * Clear/invalidate the latest picture buffer configuration + * since it is easier to reuse the set function to calculate + * for this new output configuration than to determine + * compatibility. Keep a copy beforehand just in case the new + * configuration is invalid. + */ + if (dd_str_context->disp_pict_buf.rend_info.rendered_size != 0) { + pict_buf_cfg = dd_str_context->disp_pict_buf.buf_config; + disp_pict_rend_info = dd_str_context->disp_pict_buf.rend_info; + + memset(&dd_str_context->disp_pict_buf.buf_config, 0, + sizeof(dd_str_context->disp_pict_buf.buf_config)); + memset(&dd_str_context->disp_pict_buf.rend_info, 0, + sizeof(dd_str_context->disp_pict_buf.rend_info)); + } + + /* + * Recalculate the picture buffer internal layout from the + * externalconfiguration. These settings provided by the + * allocator should be adhered to since the display process + * will expect the decoder to use them. + * If the configuration is invalid we need to leave the + * decoder state as it was before. + */ + ret = core_stream_set_pictbuf_config(dd_str_context, pict_bufcfg_handle); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS && dd_str_context->disp_pict_buf.rend_info.rendered_size + != 0) { + /* Restore old picture buffer configuration */ + dd_str_context->disp_pict_buf.buf_config = + pict_buf_cfg; + dd_str_context->disp_pict_buf.rend_info = + disp_pict_rend_info; + return ret; + } + } else if (core_is_unsupported(&supp_check.unsupp_flags)) { + return IMG_ERROR_NOT_SUPPORTED; + } + + /* Return success.. */ + return ret; +} + +/* + * @Function core_stream_play + */ +int core_stream_play(unsigned int res_str_id) +{ + int ret; + struct vdecdd_ddstr_ctx *dd_str_context; + struct core_stream_context *core_str_ctx; + /* Picture buffer layout to use for decoding. */ + struct vdecdd_ddpict_buf *disp_pict_buf; + struct vdec_str_opconfig *op_cfg; + struct vdecdd_supp_check supp_check; + + /* + * Stream based messages without a device context + * must have a stream ID. + */ + VDEC_ASSERT(res_str_id); + + /* Get access to stream context.. */ + ret = rman_get_resource(res_str_id, VDECDD_STREAM_TYPE_ID, + (void **)&core_str_ctx, NULL); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dd_str_context = core_str_ctx->dd_str_ctx; + + VDEC_ASSERT(dd_str_context); + + /* Ensure we are stopped. */ + VDEC_ASSERT(dd_str_context->dd_str_state == VDECDD_STRSTATE_STOPPED); + + /* Set "playing". */ + dd_str_context->dd_str_state = VDECDD_STRSTATE_PLAYING; + + /* set that is it not yet in closed GOP */ + core_str_ctx->no_prev_refs_used = TRUE; + + disp_pict_buf = dd_str_context->disp_pict_buf.rend_info.rendered_size ? + &dd_str_context->disp_pict_buf : NULL; + op_cfg = dd_str_context->str_op_configured ? + &dd_str_context->opconfig : NULL; + + if (disp_pict_buf && op_cfg) { + VDEC_ASSERT(!disp_pict_buf->pict_buf); + + if (memcmp(&core_str_ctx->op_cfg, op_cfg, + sizeof(core_str_ctx->op_cfg)) || + memcmp(&core_str_ctx->disp_pict_buf, disp_pict_buf, + sizeof(core_str_ctx->disp_pict_buf))) + core_str_ctx->new_op_cfg = TRUE; + + core_str_ctx->disp_pict_buf = *disp_pict_buf; + core_str_ctx->op_cfg = *op_cfg; + + core_str_ctx->opcfg_set = TRUE; + } else { + core_str_ctx->opcfg_set = FALSE; + /* Must not be decoding without output configuration */ + VDEC_ASSERT(0); + } + + memset(&supp_check, 0, sizeof(supp_check)); + + if (vdec_size_nz(core_str_ctx->comseq_hdr_info.max_frame_size)) + supp_check.comseq_hdrinfo = &core_str_ctx->comseq_hdr_info; + + if (core_str_ctx->opcfg_set) { + supp_check.op_cfg = &core_str_ctx->op_cfg; + supp_check.disp_pictbuf = &core_str_ctx->disp_pict_buf; + } + supp_check.non_cfg_req = TRUE; + ret = core_check_decoder_support(dd_str_context->dd_dev_context, + &dd_str_context->str_config_data, + &dd_str_context->prev_comseq_hdr_info, + &dd_str_context->prev_pict_hdr_info, + &dd_str_context->map_buf_info, + &supp_check); + if (ret != IMG_SUCCESS) + return ret; + + /* Return success.. */ + return IMG_SUCCESS; +} + +/* + * @Function core_deinitialise + */ +int core_deinitialise(void) +{ + struct vdecdd_dddev_context *dd_dev_ctx; + int ret; + + dd_dev_ctx = global_core_ctx->dev_ctx; + VDEC_ASSERT(dd_dev_ctx); + if (!dd_dev_ctx) + return IMG_ERROR_NOT_INITIALISED; + + ret = decoder_deinitialise(dd_dev_ctx->dec_context); + VDEC_ASSERT(ret == IMG_SUCCESS); + + /* Free context resources.. */ + rman_destroy_bucket(dd_dev_ctx->res_buck_handle); + + rman_deinitialise(); + + kfree(dd_dev_ctx); + + global_core_ctx->dev_ctx = NULL; + + kfree(global_core_ctx); + global_core_ctx = NULL; + + is_core_initialized = FALSE; + + pr_debug("Core deinitialise successfully\n"); + return IMG_SUCCESS; +} + +static int core_get_mb_num(unsigned int width, unsigned int height) +{ + /* + * Calculate the number of MBs needed for current video + * sequence settings. + */ + unsigned int width_mb = ALIGN(width, VDEC_MB_DIMENSION) / VDEC_MB_DIMENSION; + unsigned int height_mb = ALIGN(height, 2 * VDEC_MB_DIMENSION) / VDEC_MB_DIMENSION; + + return width_mb * height_mb; +} + +static int core_common_bufs_getsize(struct core_stream_context *core_str_ctx, + const struct vdec_comsequ_hdrinfo *comseq_hdrinfo, + struct vdec_pict_size *max_pict_size, + struct core_pict_bufsize_info *size_info, + struct core_seq_resinfo *seq_res_info, + unsigned char *res_needed) +{ + enum vdec_vid_std vid_std = core_str_ctx->dd_str_ctx->str_config_data.vid_std; + unsigned int std_idx = vid_std - 1; + unsigned int mb_num = 0; + + if (core_str_ctx->dd_str_ctx->str_config_data.vid_std >= VDEC_STD_MAX) + return IMG_ERROR_GENERIC_FAILURE; + + /* Reset the MB parameters buffer size. */ + size_info->mbparams_bufsize = 0; + + if (mbparam_allocinfo[std_idx].alloc_mbparam_bufs) { + *res_needed = TRUE; + + /* + * Calculate the number of MBs needed for current video + * sequence settings. + */ + mb_num = core_get_mb_num(max_pict_size->width, max_pict_size->height); + + /* Calculate the final number of MBs needed. */ + mb_num += mbparam_allocinfo[std_idx].overalloc_mbnum; + + /* Calculate the MB params buffer size. */ + size_info->mbparams_bufsize = mb_num * mbparam_allocinfo[std_idx].mbparam_size; + + /* Adjust the buffer size for MSVDX. */ + vdecddutils_buf_vxd_adjust_size(&size_info->mbparams_bufsize); + + if (comseq_hdrinfo->separate_chroma_planes) + size_info->mbparams_bufsize *= 3; + } + + return IMG_SUCCESS; +} + +/* + * @Function core_pict_res_getinfo + */ +static int +core_pict_res_getinfo(struct core_stream_context *core_str_ctx, + const struct vdec_comsequ_hdrinfo *comseq_hdrinfo, + const struct vdec_str_opconfig *op_cfg, + const struct vdecdd_ddpict_buf *disp_pictbuf, + struct core_pict_resinfo *pict_resinfo, + struct core_seq_resinfo *seq_resinfo) +{ + struct vdec_pict_size coded_pict_size; + struct dec_ctx *decctx; + unsigned char res_needed = FALSE; + int ret; + + /* Reset the picture resource info. */ + memset(pict_resinfo, 0, sizeof(*pict_resinfo)); + + coded_pict_size = comseq_hdrinfo->max_frame_size; + + VDEC_ASSERT(core_str_ctx->std_spec_ops); + if (core_str_ctx->std_spec_ops->bufs_get_size) + core_str_ctx->std_spec_ops->bufs_get_size(core_str_ctx, comseq_hdrinfo, + &coded_pict_size, + &pict_resinfo->size_info, seq_resinfo, &res_needed); + + /* If any picture resources are needed... */ + if (res_needed) { + /* Get the number of resources required. */ + ret = vdecddutils_get_minrequired_numpicts + (&core_str_ctx->dd_str_ctx->str_config_data, + comseq_hdrinfo, op_cfg, + &pict_resinfo->pict_res_num); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + decctx = (struct dec_ctx *)global_core_ctx->dev_ctx->dec_context; + + if (core_str_ctx->dd_str_ctx->str_config_data.vid_std == VDEC_STD_HEVC) + pict_resinfo->pict_res_num += decctx->dev_cfg->num_slots_per_pipe - 1; + else + pict_resinfo->pict_res_num += + decctx->num_pipes * decctx->dev_cfg->num_slots_per_pipe - 1; + } + + return IMG_SUCCESS; +} + +static int core_alloc_resbuf(struct vdecdd_ddbuf_mapinfo **buf_handle, + unsigned int size, void *mmu_handle, + struct vxdio_mempool mem_pool) +{ + int ret; + struct vdecdd_ddbuf_mapinfo *buf; + + *buf_handle = kzalloc(sizeof(**buf_handle), GFP_KERNEL); + buf = *buf_handle; + VDEC_ASSERT(buf); + if (buf) { + buf->mmuheap_id = MMU_HEAP_STREAM_BUFFERS; +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s:%d calling MMU_StreamMalloc", __func__, __LINE__); +#endif + ret = mmu_stream_alloc(mmu_handle, buf->mmuheap_id, + mem_pool.mem_heap_id, + mem_pool.mem_attrib, size, + DEV_MMU_PAGE_SIZE, + &buf->ddbuf_info); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + ret = IMG_ERROR_OUT_OF_MEMORY; + } else { + ret = IMG_ERROR_OUT_OF_MEMORY; + } + return ret; +} + +#ifdef SEQ_RES_NEEDED +static int core_alloc_common_sequence_buffers(struct core_stream_context *core_str_ctx, + struct vdecdd_seq_resint *seqres_int, + struct vxdio_mempool mem_pool, + struct core_seq_resinfo *seqres_info, + struct core_pict_resinfo *pictres_info, + const struct vdec_str_opconfig *op_cfg, + const struct vdecdd_ddpict_buf *disp_pict_buf) +{ + int ret = IMG_SUCCESS; +#ifdef ERROR_CONCEALMENT + enum vdec_vid_std vid_std = core_str_ctx->dd_str_ctx->str_config_data.vid_std; + unsigned int std_idx = vid_std - 1; + struct vidio_ddbufinfo *err_buf_info; + + /* Allocate error concealment pattern frame for current sequence */ + if (err_recovery_frame_info[std_idx].enabled) { + struct vdec_pict_bufconfig buf_config; + unsigned int size; + + buf_config = disp_pict_buf->buf_config; + size = buf_config.coded_width * buf_config.coded_height; + + if (err_recovery_frame_info[std_idx].max_size > size) { + seqres_int->err_pict_buf = kzalloc(sizeof(*seqres_int->err_pict_buf), + GFP_KERNEL); + VDEC_ASSERT(seqres_int->err_pict_buf); + if (!seqres_int->err_pict_buf) + return IMG_ERROR_OUT_OF_MEMORY; + + seqres_int->err_pict_buf->mmuheap_id = MMU_HEAP_STREAM_BUFFERS; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("===== %s:%d calling MMU_StreamMalloc", __func__, __LINE__); +#endif + ret = mmu_stream_alloc(core_str_ctx->dd_str_ctx->mmu_str_handle, + seqres_int->err_pict_buf->mmuheap_id, + mem_pool.mem_heap_id, + (enum sys_emem_attrib)(mem_pool.mem_attrib | + SYS_MEMATTRIB_CPU_WRITE), + buf_config.buf_size, + DEV_MMU_PAGE_ALIGNMENT, + &seqres_int->err_pict_buf->ddbuf_info); + if (ret != IMG_SUCCESS) + return IMG_ERROR_OUT_OF_MEMORY; + + /* make grey pattern - luma & chroma at mid-rail */ + err_buf_info = &seqres_int->err_pict_buf->ddbuf_info; + if (op_cfg->pixel_info.mem_pkg == PIXEL_BIT10_MP) { + unsigned int *out = (unsigned int *)err_buf_info->cpu_virt; + unsigned int i; + + for (i = 0; i < err_buf_info->buf_size / sizeof(unsigned int); i++) + /* See PIXEL_BIT10_MP layout definition */ + out[i] = 0x20080200; + } else { + /* Note: Setting 0x80 also gives grey pattern + * for 10bit upacked MSB format. + */ + memset(err_buf_info->cpu_virt, 0x80, err_buf_info->buf_size); + } + } + } +#endif + return ret; +} +#endif + +/* + * @Function core_do_resource_realloc + */ +static unsigned char core_do_resource_realloc(struct core_stream_context *core_str_ctx, + struct core_pict_resinfo *pictres_info, + struct core_seq_resinfo *seqres_info) +{ + VDEC_ASSERT(core_str_ctx->std_spec_ops); + /* If buffer sizes are sufficient and only the greater number of resources is needed... */ + if (core_str_ctx->pict_resinfo.size_info.mbparams_bufsize >= + pictres_info->size_info.mbparams_bufsize && + (core_str_ctx->std_spec_ops->is_stream_resource_suitable ? + core_str_ctx->std_spec_ops->is_stream_resource_suitable(pictres_info, + &core_str_ctx->pict_resinfo, + seqres_info, &core_str_ctx->seq_resinfo) : TRUE) && + core_str_ctx->pict_resinfo.pict_res_num < pictres_info->pict_res_num) + /* ...full internal resource reallocation is not required. */ + return FALSE; + + /* Otherwise request full internal resource reallocation. */ + return TRUE; +} + +/* + * @Function core_is_stream_resource_suitable + */ +static unsigned char core_is_stream_resource_suitable + (struct core_stream_context *core_str_ctx, + const struct vdec_comsequ_hdrinfo *comseq_hdrinfo, + const struct vdec_str_opconfig *op_cfg, + const struct vdecdd_ddpict_buf *disp_pict_buf, + struct core_pict_resinfo *pictres_info, + struct core_seq_resinfo *seqres_info_ptr) +{ + int ret; + struct core_pict_resinfo aux_pictes_info; + struct core_pict_resinfo *aux_pictes_info_ptr; + struct core_seq_resinfo seqres_info; + + /* If resource info is needed externally, just use it. Otherwise use internal structure. */ + if (pictres_info) + aux_pictes_info_ptr = pictres_info; + else + aux_pictes_info_ptr = &aux_pictes_info; + + if (!seqres_info_ptr) + seqres_info_ptr = &seqres_info; + + /* Get the resource info for current settings. */ + ret = core_pict_res_getinfo(core_str_ctx, comseq_hdrinfo, op_cfg, disp_pict_buf, + aux_pictes_info_ptr, seqres_info_ptr); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return FALSE; + + VDEC_ASSERT(core_str_ctx->std_spec_ops); + if (core_str_ctx->std_spec_ops->is_stream_resource_suitable) { + if (!core_str_ctx->std_spec_ops->is_stream_resource_suitable + (aux_pictes_info_ptr, + &core_str_ctx->pict_resinfo, + seqres_info_ptr, &core_str_ctx->seq_resinfo)) + return FALSE; + } + + /* Check the number of picture resources required against the current number. */ + if (aux_pictes_info_ptr->pict_res_num > core_str_ctx->pict_resinfo.pict_res_num) + return FALSE; + + return TRUE; +} + +static int core_alloc_common_pict_buffers(struct core_stream_context *core_str_ctx, + struct vdecdd_pict_resint *pictres_int, + struct vxdio_mempool mem_pool, + struct core_pict_resinfo *pictres_info) +{ + int ret = IMG_SUCCESS; + + /* If MB params buffers are needed... */ + if (pictres_info->size_info.mbparams_bufsize > 0) + /* Allocate the MB parameters buffer info structure. */ + ret = core_alloc_resbuf(&pictres_int->mb_param_buf, + pictres_info->size_info.mbparams_bufsize, + core_str_ctx->dd_str_ctx->mmu_str_handle, + mem_pool); + + return ret; +} + +/* + * @Function core_stream_resource_create + */ +static int core_stream_resource_create(struct core_stream_context *core_str_ctx, + unsigned char closed_gop, unsigned int mem_heap_id, + const struct vdec_comsequ_hdrinfo *comseq_hdrinfo, + const struct vdec_str_opconfig *op_cfg, + const struct vdecdd_ddpict_buf *disp_pict_buf) +{ + struct vdecdd_pict_resint *pictres_int = NULL; + int ret = IMG_SUCCESS; + unsigned int i, start_cnt = 0; + struct core_pict_resinfo pictres_info; + struct vdecdd_seq_resint *seqres_int = NULL; + struct core_seq_resinfo seqres_info; + struct vxdio_mempool mem_pool; + + mem_pool.mem_heap_id = mem_heap_id; + mem_pool.mem_attrib = (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED + | SYS_MEMATTRIB_WRITECOMBINE | SYS_MEMATTRIB_INTERNAL); + +#ifdef SEQ_RES_NEEDED + seqres_int = lst_first(&core_str_ctx->seq_res_list); +#endif + /* + * Clear the reconstructed picture buffer layout if the previous + * references are no longer used. Only under these circumstances + * should the bitstream resolution change. + */ + if (closed_gop) { + memset(&core_str_ctx->recon_pictbuf.rend_info, 0, + sizeof(core_str_ctx->recon_pictbuf.rend_info)); + memset(&core_str_ctx->coded_pict_size, 0, sizeof(core_str_ctx->coded_pict_size)); + } else { + if (vdec_size_ne(core_str_ctx->coded_pict_size, comseq_hdrinfo->max_frame_size)) { + VDEC_ASSERT(FALSE); + pr_err("Coded picture size changed within the closed GOP (i.e. mismatched references)"); + } + } + + /* If current buffers are not suitable for specified VSH/Output config... */ + if (!core_is_stream_resource_suitable(core_str_ctx, comseq_hdrinfo, + op_cfg, disp_pict_buf, &pictres_info, + &seqres_info)) { + /* If full internal resource reallocation is needed... */ + if (core_do_resource_realloc(core_str_ctx, &pictres_info, &seqres_info)) { + /* + * Mark all the active resources as deprecated and + * free-up where no longer used. + */ + core_stream_resource_deprecate(core_str_ctx); + } else { + /* Use current buffer size settings. */ + pictres_info.size_info = core_str_ctx->pict_resinfo.size_info; + seqres_info = core_str_ctx->seq_resinfo; + + /* Set start counter to only allocate the number of + * resources that are missing. + */ + start_cnt = core_str_ctx->pict_resinfo.pict_res_num; + } + +#ifdef SEQ_RES_NEEDED + /* allocate sequence resources */ + { + seqres_int = kzalloc(sizeof(*seqres_int), GFP_KERNEL); + VDEC_ASSERT(seqres_int); + if (!seqres_int) + goto err_out_of_memory; + + lst_add(&core_str_ctx->seq_res_list, seqres_int); + /* Allocate sequence buffers common for all standards. */ + ret = core_alloc_common_sequence_buffers + (core_str_ctx, seqres_int, mem_pool, + &seqres_info, + &pictres_info, op_cfg, disp_pict_buf); + if (ret != IMG_SUCCESS) + goto err_out_of_memory; + + VDEC_ASSERT(core_str_ctx->std_spec_ops); + if (core_str_ctx->std_spec_ops->alloc_sequence_buffers) { + ret = core_str_ctx->std_spec_ops->alloc_sequence_buffers + (core_str_ctx, seqres_int, + mem_pool, &seqres_info); + if (ret != IMG_SUCCESS) + goto err_out_of_memory; + } + } +#endif + /* Allocate resources for current settings. */ + for (i = start_cnt; i < pictres_info.pict_res_num; i++) { + /* Allocate the picture resources structure. */ + pictres_int = kzalloc(sizeof(*pictres_int), GFP_KERNEL); + VDEC_ASSERT(pictres_int); + if (!pictres_int) + goto err_out_of_memory; + + /* Allocate picture buffers common for all standards. */ + ret = core_alloc_common_pict_buffers(core_str_ctx, pictres_int, + mem_pool, &pictres_info); + if (ret != IMG_SUCCESS) + goto err_out_of_memory; + + /* Allocate standard specific picture buffers. */ + VDEC_ASSERT(core_str_ctx->std_spec_ops); + if (core_str_ctx->std_spec_ops->alloc_picture_buffers) { + ret = core_str_ctx->std_spec_ops->alloc_picture_buffers + (core_str_ctx, pictres_int, + mem_pool, &pictres_info); + if (ret != IMG_SUCCESS) + goto err_out_of_memory; + } + + /* attach sequence resources */ +#ifdef SEQ_RES_NEEDED + resource_item_use(&seqres_int->ref_count); + pictres_int->seq_resint = seqres_int; +#endif + lst_add(&core_str_ctx->pict_res_list, pictres_int); + core_str_ctx->pict_resinfo.pict_res_num++; + } + } + + /* + * When demand for picture resources reduces (in quantity) the extra buffers + * are still retained. Preserve the existing count in case the demand increases + * again, at which time these residual buffers won't need to be reallocated. + */ + pictres_info.pict_res_num = core_str_ctx->pict_resinfo.pict_res_num; + + /* Store the current resource config. */ + core_str_ctx->pict_resinfo = pictres_info; + core_str_ctx->seq_resinfo = seqres_info; + + pictres_int = lst_first(&core_str_ctx->pict_res_list); + while (pictres_int) { + /* + * Increment the reference count to indicate that this resource is also + * held by plant until it is added to the Scheduler list. If the resource has + * not just been created it might already be in circulation. + */ + resource_item_use(&pictres_int->ref_cnt); +#ifdef SEQ_RES_NEEDED + /* attach sequence resources */ + resource_item_use(&seqres_int->ref_count); + pictres_int->seq_resint = seqres_int; +#endif + /* Add the internal picture resources to the list. */ + ret = resource_list_add_img(&core_str_ctx->aux_pict_res_list, + pictres_int, 0, &pictres_int->ref_cnt); + + pictres_int = lst_next(pictres_int); + } + + /* + * Set the reconstructed buffer properties if they + * may have been changed. + */ + if (core_str_ctx->recon_pictbuf.rend_info.rendered_size == 0) { + core_str_ctx->recon_pictbuf.rend_info = + disp_pict_buf->rend_info; + core_str_ctx->recon_pictbuf.buf_config = + disp_pict_buf->buf_config; + core_str_ctx->coded_pict_size = comseq_hdrinfo->max_frame_size; + } else { + if (memcmp(&disp_pict_buf->rend_info, + &core_str_ctx->recon_pictbuf.rend_info, + sizeof(core_str_ctx->recon_pictbuf.rend_info))) { + /* + * Reconstructed picture buffer information has changed + * during a closed GOP. + */ + VDEC_ASSERT + ("Reconstructed picture buffer information cannot change within a GOP" + == NULL); + pr_err("Reconstructed picture buffer information cannot change within a GOP."); + return IMG_ERROR_GENERIC_FAILURE; + } + } + + /* + * When demand for picture resources reduces (in quantity) the extra buffers + * are still retained. Preserve the existing count in case the demand increases + * again, at which time these residual buffers won't need to be reallocated. + */ + pictres_info.pict_res_num = core_str_ctx->pict_resinfo.pict_res_num; + + /* Store the current resource config. */ + core_str_ctx->pict_resinfo = pictres_info; + core_str_ctx->seq_resinfo = seqres_info; + + return IMG_SUCCESS; + + /* Handle out of memory errors. */ +err_out_of_memory: + /* Free resources being currently allocated. */ + if (pictres_int) { + core_free_common_picture_resource(core_str_ctx, pictres_int); + if (core_str_ctx->std_spec_ops->free_picture_resource) + core_str_ctx->std_spec_ops->free_picture_resource(core_str_ctx, + pictres_int); + + kfree(pictres_int); + } + +#ifdef SEQ_RES_NEEDED + if (seqres_int) { + core_free_common_sequence_resource(core_str_ctx, seqres_int); + + if (core_str_ctx->std_spec_ops->free_sequence_resource) + core_str_ctx->std_spec_ops->free_sequence_resource(core_str_ctx, + seqres_int); + + VDEC_ASSERT(lst_last(&core_str_ctx->seq_res_list) == seqres_int); + lst_remove(&core_str_ctx->seq_res_list, seqres_int); + kfree(seqres_int); + } +#endif + + /* Free all the other resources. */ + core_stream_resource_destroy(core_str_ctx); + + pr_err("[USERSID=0x%08X] Core not able to allocate stream resources due to lack of memory", + core_str_ctx->dd_str_ctx->str_config_data.user_str_id); + + return IMG_ERROR_OUT_OF_MEMORY; +} + +static int +core_reconfigure_recon_pictbufs(struct core_stream_context *core_str_ctx, + unsigned char no_references) +{ + struct vdecdd_ddstr_ctx *dd_str_ctx; + int ret; + + dd_str_ctx = core_str_ctx->dd_str_ctx; + VDEC_ASSERT(dd_str_ctx->str_op_configured); + + /* Re-configure the internal picture buffers now that none are held. */ + ret = core_stream_resource_create(core_str_ctx, no_references, + dd_str_ctx->dd_dev_context->internal_heap_id, + &dd_str_ctx->comseq_hdr_info, + &dd_str_ctx->opconfig, + &dd_str_ctx->disp_pict_buf); + return ret; +} + +/* + * @Function core_picture_prepare + */ +static int core_picture_prepare(struct core_stream_context *core_str_ctx, + struct vdecdd_str_unit *str_unit) +{ + int ret = IMG_SUCCESS; + struct vdecdd_picture *pict_local = NULL; + unsigned int avail = 0; + unsigned char need_pict_res; + + /* + * For normal decode, setup picture data. + * Preallocate the picture structure. + */ + pict_local = kzalloc(sizeof(*pict_local), GFP_KERNEL); + if (!pict_local) + return IMG_ERROR_OUT_OF_MEMORY; + + /* Determine whether the picture can be decoded. */ + ret = decoder_get_load(core_str_ctx->dd_str_ctx->dec_ctx, &global_avail_slots); + if (ret != IMG_SUCCESS) { + pr_err("No resources avaialable to decode this picture"); + ret = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + goto unwind; + } + + /* + * Load and availability is cached in stream context simply + * for status reporting. + */ + avail = core_get_resource_availability(core_str_ctx); + + if ((avail & CORE_AVAIL_CORE) == 0) { + /* Return straight away if the core is not available */ + ret = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + goto unwind; + } + + if (core_str_ctx->new_op_cfg || core_str_ctx->new_seq) { + /* + * Reconstructed buffers should be checked for reconfiguration + * under these conditions: + * 1. New output configuration, + * 2. New sequence. + * Core can decide to reset the reconstructed buffer properties + * if there are no previous reference pictures used + * (i.e. at a closed GOP). This code must go here because we + * may not stop when new sequence is found or references become + * unused. + */ + ret = core_reconfigure_recon_pictbufs(core_str_ctx, + core_str_ctx->no_prev_refs_used); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto unwind; + } + + /* Update the display information for this picture. */ + ret = vdecddutils_get_display_region(&str_unit->pict_hdr_info->coded_frame_size, + &str_unit->pict_hdr_info->disp_info.enc_disp_region, + &str_unit->pict_hdr_info->disp_info.disp_region); + + if (ret != IMG_SUCCESS) + goto unwind; + + /* Clear internal state */ + core_str_ctx->new_seq = FALSE; + core_str_ctx->new_op_cfg = FALSE; + core_str_ctx->no_prev_refs_used = FALSE; + + /* + * Recalculate this since we might have just created + * internal resources. + */ + core_str_ctx->res_avail = core_get_resource_availability(core_str_ctx); + + /* + * If picture resources were needed for this stream, picture resources + * list wouldn't be empty + */ + need_pict_res = !lst_empty(&core_str_ctx->aux_pict_res_list); + /* If there are resources available */ + if ((core_str_ctx->res_avail & CORE_AVAIL_PICTBUF) && + (!need_pict_res || (core_str_ctx->res_avail & CORE_AVAIL_PICTRES))) { + /* Pick internal picture resources. */ + if (need_pict_res) { + pict_local->pict_res_int = + resource_list_get_avail(&core_str_ctx->aux_pict_res_list); + + VDEC_ASSERT(pict_local->pict_res_int); + if (!pict_local->pict_res_int) { + ret = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + goto unwind; + } + } + + /* Pick the client image buffer. */ + pict_local->disp_pict_buf.pict_buf = + resource_list_get_avail(&core_str_ctx->pict_buf_list); + VDEC_ASSERT(pict_local->disp_pict_buf.pict_buf); + if (!pict_local->disp_pict_buf.pict_buf) { + ret = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + goto unwind; + } + } else { + /* Need resources to process picture start. */ + ret = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + goto unwind; + } + + /* Ensure that the buffer contains layout information. */ + pict_local->disp_pict_buf.rend_info = core_str_ctx->disp_pict_buf.rend_info; + pict_local->disp_pict_buf.buf_config = core_str_ctx->disp_pict_buf.buf_config; + pict_local->op_config = core_str_ctx->op_cfg; + pict_local->last_pict_in_seq = str_unit->last_pict_in_seq; + + str_unit->dd_pict_data = pict_local; + + /* Indicate that all necessary resources are now available. */ + if (core_str_ctx->res_avail != ~0) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("LAST AVAIL: 0x%08X\n", core_str_ctx->res_avail); +#endif + core_str_ctx->res_avail = ~0; + } + +#ifdef DEBUG_DECODER_DRIVER + /* dump decoder internal resource addresses */ + if (pict_local->pict_res_int) { + if (pict_local->pict_res_int->mb_param_buf) { + pr_info("[USERSID=0x%08X] MB parameter buffer device virtual address: 0x%08X", + core_str_ctx->dd_str_ctx->str_config_data.user_str_id, + pict_local->pict_res_int->mb_param_buf->ddbuf_info.dev_virt); + } + + if (core_str_ctx->comseq_hdr_info.separate_chroma_planes) { + pr_info("[USERSID=0x%08X] Display picture virtual address: LUMA 0x%08X, CHROMA 0x%08X, CHROMA2 0x%08X", + core_str_ctx->dd_str_ctx->str_config_data.user_str_id, + pict_local->disp_pict_buf.pict_buf->ddbuf_info.dev_virt, + pict_local->disp_pict_buf.pict_buf->ddbuf_info.dev_virt + + pict_local->disp_pict_buf.rend_info.plane_info + [VDEC_PLANE_VIDEO_U].offset, + pict_local->disp_pict_buf.pict_buf->ddbuf_info.dev_virt + + pict_local->disp_pict_buf.rend_info.plane_info + [VDEC_PLANE_VIDEO_V].offset); + } else { + pr_info("[USERSID=0x%08X] Display picture virtual address: LUMA 0x%08X, CHROMA 0x%08X", + core_str_ctx->dd_str_ctx->str_config_data.user_str_id, + pict_local->disp_pict_buf.pict_buf->ddbuf_info.dev_virt, + pict_local->disp_pict_buf.pict_buf->ddbuf_info.dev_virt + + pict_local->disp_pict_buf.rend_info.plane_info + [VDEC_PLANE_VIDEO_UV].offset); + } + } +#endif + + ret = core_picture_attach_resources(core_str_ctx, str_unit, TRUE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto unwind; + + return IMG_SUCCESS; + +unwind: + if (pict_local->pict_res_int) { + resource_item_return(&pict_local->pict_res_int->ref_cnt); + pict_local->pict_res_int = NULL; + } + if (pict_local->disp_pict_buf.pict_buf) { + resource_item_return(&pict_local->disp_pict_buf.pict_buf->ddbuf_info.ref_count); + pict_local->disp_pict_buf.pict_buf = NULL; + } + kfree(pict_local); + return ret; +} + +/* + * @Function core_validate_new_sequence + */ +static int core_validate_new_sequence(struct core_stream_context *core_str_ctx, + const struct vdec_comsequ_hdrinfo *comseq_hdrinfo) +{ + int ret; + struct vdecdd_supp_check supp_check; + struct vdecdd_ddstr_ctx *dd_str_ctx; + unsigned int num_req_bufs_prev, num_req_bufs_cur; + struct vdecdd_mapbuf_info mapbuf_info; + + memset(&supp_check, 0, sizeof(supp_check)); + + /* + * Omit picture header from this setup since we can'supp_check + * validate this here. + */ + supp_check.comseq_hdrinfo = comseq_hdrinfo; + + if (core_str_ctx->opcfg_set) { + supp_check.op_cfg = &core_str_ctx->op_cfg; + supp_check.disp_pictbuf = &core_str_ctx->disp_pict_buf; + + ret = vdecddutils_get_minrequired_numpicts + (&core_str_ctx->dd_str_ctx->str_config_data, + &core_str_ctx->comseq_hdr_info, + &core_str_ctx->op_cfg, + &num_req_bufs_prev); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + ret = vdecddutils_get_minrequired_numpicts + (&core_str_ctx->dd_str_ctx->str_config_data, + comseq_hdrinfo, + &core_str_ctx->op_cfg, + &num_req_bufs_cur); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + + /* Check if the output configuration is compatible with new VSH. */ + dd_str_ctx = core_str_ctx->dd_str_ctx; + mapbuf_info = dd_str_ctx->map_buf_info; + + /* Check the compatibility of the bitstream data and configuration */ + supp_check.non_cfg_req = TRUE; + ret = core_check_decoder_support(dd_str_ctx->dd_dev_context, + &dd_str_ctx->str_config_data, + &dd_str_ctx->prev_comseq_hdr_info, + &dd_str_ctx->prev_pict_hdr_info, + &mapbuf_info, &supp_check); + if (ret != IMG_SUCCESS) + return ret; + + core_str_ctx->new_seq = TRUE; + + return IMG_SUCCESS; +} + +static int +core_validate_new_picture(struct core_stream_context *core_str_ctx, + const struct bspp_pict_hdr_info *pict_hdrinfo, + unsigned int *features) +{ + int ret; + struct vdecdd_supp_check supp_check; + struct vdecdd_ddstr_ctx *dd_str_ctx; + struct vdecdd_mapbuf_info mapbuf_info; + + memset(&supp_check, 0, sizeof(supp_check)); + supp_check.comseq_hdrinfo = &core_str_ctx->comseq_hdr_info; + supp_check.pict_hdrinfo = pict_hdrinfo; + + /* + * They cannot become invalid during a sequence. + * However, output configuration may signal something that + * changes compatibility on a closed GOP within a sequence + * (e.g. resolution may significantly decrease + * in a GOP and scaling wouldn't be supported). This resolution shift + * would not be signalled in the sequence header + * (since that is the maximum) but only + * found now when validating the first picture in the GOP. + */ + if (core_str_ctx->opcfg_set) + supp_check.op_cfg = &core_str_ctx->op_cfg; + + /* + * Check if the new picture is compatible with the + * current driver state. + */ + dd_str_ctx = core_str_ctx->dd_str_ctx; + mapbuf_info = dd_str_ctx->map_buf_info; + + /* Check the compatibility of the bitstream data and configuration */ + supp_check.non_cfg_req = TRUE; + ret = core_check_decoder_support(dd_str_ctx->dd_dev_context, + &dd_str_ctx->str_config_data, + &dd_str_ctx->prev_comseq_hdr_info, + &dd_str_ctx->prev_pict_hdr_info, + &mapbuf_info, &supp_check); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + if (supp_check.unsupp_flags.str_opcfg || supp_check.unsupp_flags.pict_hdr) + return IMG_ERROR_NOT_SUPPORTED; + + /* + * Clear the reconfiguration flags unless triggered by + * unsupported output config. + */ + *features = supp_check.features; + + return IMG_SUCCESS; +} + +/* + * @Function core_stream_submit_unit + */ +int core_stream_submit_unit(unsigned int res_str_id, struct vdecdd_str_unit *str_unit) +{ + int ret; + unsigned char process_str_unit = TRUE; + + struct vdecdd_ddstr_ctx *dd_str_context; + struct core_stream_context *core_str_ctx; + + /* + * Stream based messages without a device context + * must have a stream ID. + */ + VDEC_ASSERT(res_str_id); + VDEC_ASSERT(str_unit); + + if (res_str_id == 0 || !str_unit) { + pr_err("Invalid params passed to %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Get access to stream context.. */ + ret = rman_get_resource(res_str_id, VDECDD_STREAM_TYPE_ID, (void **)&core_str_ctx, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + VDEC_ASSERT(core_str_ctx); + dd_str_context = core_str_ctx->dd_str_ctx; + VDEC_ASSERT(dd_str_context); + + ret = resource_list_add_img(&core_str_ctx->str_unit_list, str_unit, 0, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + + pr_debug("%s stream unit type = %d\n", __func__, str_unit->str_unit_type); + switch (str_unit->str_unit_type) { + case VDECDD_STRUNIT_SEQUENCE_START: + if (str_unit->seq_hdr_info) { + /* Add sequence header to cache. */ + ret = + resource_list_replace(&core_str_ctx->seq_hdr_list, + str_unit->seq_hdr_info, + str_unit->seq_hdr_info->sequ_hdr_id, + &str_unit->seq_hdr_info->ref_count, + NULL, NULL); + + if (ret != IMG_SUCCESS) + pr_err("[USERSID=0x%08X] Failed to replace resource", + res_str_id); + } else { + /* ...or take from cache. */ + str_unit->seq_hdr_info = + resource_list_getbyid(&core_str_ctx->seq_hdr_list, + str_unit->seq_hdr_id); + } + + VDEC_ASSERT(str_unit->seq_hdr_info); + if (!str_unit->seq_hdr_info) { + pr_err("Sequence header information not available for current picture"); + break; + } + /* + * Check that this latest sequence header information is + * compatible with current state and then if no errors store + * as current. + */ + core_str_ctx->comseq_hdr_info = str_unit->seq_hdr_info->com_sequ_hdr_info; + + ret = core_validate_new_sequence(core_str_ctx, + &str_unit->seq_hdr_info->com_sequ_hdr_info); + if (ret != IMG_SUCCESS) + return ret; + + dd_str_context->prev_comseq_hdr_info = + dd_str_context->comseq_hdr_info; + dd_str_context->comseq_hdr_info = + str_unit->seq_hdr_info->com_sequ_hdr_info; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("[SID=0x%08X] VSH: Maximum Frame Resolution [%dx%d]", + dd_str_context->res_str_id, + dd_str_context->comseq_hdr_info.max_frame_size.width, + dd_str_context->comseq_hdr_info.max_frame_size.height); +#endif + + break; + + case VDECDD_STRUNIT_PICTURE_START: + /* + * Check that the picture configuration is compatible + * with the current state. + */ + ret = core_validate_new_picture(core_str_ctx, + str_unit->pict_hdr_info, + &str_unit->features); + if (ret != IMG_SUCCESS) { + if (ret == IMG_ERROR_NOT_SUPPORTED) { + /* + * Do not process stream unit since there is + * something unsupported. + */ + process_str_unit = FALSE; + break; + } + } + + /* Prepare picture for decoding. */ + ret = core_picture_prepare(core_str_ctx, str_unit); + if (ret != IMG_SUCCESS) + if (ret == IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE || + ret == IMG_ERROR_NOT_SUPPORTED) + /* + * Do not process stream unit since there is + * something unsupported or resources are not + * available. + */ + process_str_unit = FALSE; + break; + + default: + /* + * Sequence/picture headers should only be attached to + * corresponding units. + */ + VDEC_ASSERT(!str_unit->seq_hdr_info); + VDEC_ASSERT(!str_unit->pict_hdr_info); + break; + } + + if (process_str_unit) { + /* Submit stream unit to the decoder for processing. */ + str_unit->decode = TRUE; + ret = decoder_stream_process_unit(dd_str_context->dec_ctx, + str_unit); + } else { + ret = IMG_ERROR_GENERIC_FAILURE; + } + + return ret; +} + +/* + * @Function core_stream_fill_pictbuf + */ +int core_stream_fill_pictbuf(unsigned int buf_map_id) +{ + int ret; + struct vdecdd_ddbuf_mapinfo *ddbuf_map_info; + struct vdecdd_ddstr_ctx *dd_str_ctx; + struct core_stream_context *core_str_ctx; + + /* Get access to map info context.. */ + ret = rman_get_resource(buf_map_id, VDECDD_BUFMAP_TYPE_ID, + (void **)&ddbuf_map_info, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dd_str_ctx = ddbuf_map_info->ddstr_context; + + /* Get access to stream context.. */ + ret = rman_get_resource(dd_str_ctx->res_str_id, VDECDD_STREAM_TYPE_ID, + (void **)&core_str_ctx, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + /* Check buffer type. */ + VDEC_ASSERT(ddbuf_map_info->buf_type == VDEC_BUFTYPE_PICTURE); + + /* Add the image buffer to the list */ + ret = resource_list_add_img(&core_str_ctx->pict_buf_list, ddbuf_map_info, + 0, &ddbuf_map_info->ddbuf_info.ref_count); + + return ret; +} + +/* + * @Function core_fn_free_mapped + */ +static void core_fn_free_mapped(void *param) +{ + struct vdecdd_ddbuf_mapinfo *ddbuf_map_info = + (struct vdecdd_ddbuf_mapinfo *)param; + + /* Validate input arguments */ + VDEC_ASSERT(param); + + /* Do not free the MMU mapping. It is handled by talmmu code. */ + kfree(ddbuf_map_info); +} + +/* + * @Function core_stream_map_buf + */ +int core_stream_map_buf(unsigned int res_str_id, enum vdec_buf_type buf_type, + struct vdec_buf_info *buf_info, unsigned int *buf_map_id) +{ + int ret; + struct vdecdd_ddstr_ctx *dd_str_ctx; + struct core_stream_context *core_str_ctx; + struct vdecdd_ddbuf_mapinfo *ddbuf_map_info; + + /* + * Stream based messages without a device context + * must have a stream ID. + */ + VDEC_ASSERT(res_str_id); + VDEC_ASSERT(buf_type < VDEC_BUFTYPE_MAX); + VDEC_ASSERT(buf_info); + VDEC_ASSERT(buf_map_id); + + /* Get access to stream context.. */ + ret = rman_get_resource(res_str_id, VDECDD_STREAM_TYPE_ID, + (void **)&core_str_ctx, NULL); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dd_str_ctx = core_str_ctx->dd_str_ctx; + + VDEC_ASSERT(dd_str_ctx); + + /* Allocate an active stream unit.. */ + ddbuf_map_info = kzalloc(sizeof(*ddbuf_map_info), GFP_KERNEL); + VDEC_ASSERT(ddbuf_map_info); + + if (!ddbuf_map_info) { + pr_err("[SID=0x%08X] Failed to allocate memory for DD buffer map information", + dd_str_ctx->res_str_id); + + return IMG_ERROR_OUT_OF_MEMORY; + } + memset(ddbuf_map_info, 0, sizeof(*ddbuf_map_info)); + + /* Save the stream context etc. */ + ddbuf_map_info->ddstr_context = dd_str_ctx; + ddbuf_map_info->buf_type = buf_type; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s:%d vdec2plus: vxd map buff id %d", __func__, __LINE__, + buf_info->buf_id); +#endif + ddbuf_map_info->buf_id = buf_info->buf_id; + + /* Register the allocation as a stream resource.. */ + ret = rman_register_resource(dd_str_ctx->res_buck_handle, + VDECDD_BUFMAP_TYPE_ID, + core_fn_free_mapped, + ddbuf_map_info, + &ddbuf_map_info->res_handle, + buf_map_id); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + ddbuf_map_info->buf_map_id = *buf_map_id; + + if (buf_type == VDEC_BUFTYPE_PICTURE) { + if (dd_str_ctx->map_buf_info.num_buf == 0) { + dd_str_ctx->map_buf_info.buf_size = buf_info->buf_size; + dd_str_ctx->map_buf_info.byte_interleave = + buf_info->pictbuf_cfg.byte_interleave; +#ifdef DEBUG_DECODER_DRIVER + pr_info("[SID=0x%08X] Mapped Buffer size: %d (bytes)", + dd_str_ctx->res_str_id, buf_info->buf_size); +#endif + } else { + /* + * Same byte interleaved setting should be used. + * Convert to actual bools by comparing with zero. + */ + if (buf_info->pictbuf_cfg.byte_interleave != + dd_str_ctx->map_buf_info.byte_interleave) { + pr_err("[SID=0x%08X] Buffer cannot be mapped since its byte interleave value (%s) is not the same as buffers already mapped (%s)", + dd_str_ctx->res_str_id, + buf_info->pictbuf_cfg.byte_interleave ? + "ON" : "OFF", + dd_str_ctx->map_buf_info.byte_interleave ? + "ON" : "OFF"); + ret = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + } + + /* Configure the buffer.. */ + ret = core_stream_set_pictbuf_config(dd_str_ctx, &buf_info->pictbuf_cfg); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + } + + /* Map heap from VDEC to MMU. */ + switch (buf_type) { + case VDEC_BUFTYPE_BITSTREAM: + ddbuf_map_info->mmuheap_id = MMU_HEAP_BITSTREAM_BUFFERS; + break; + + case VDEC_BUFTYPE_PICTURE: + mmu_get_heap(buf_info->pictbuf_cfg.stride[VDEC_PLANE_VIDEO_Y], + &ddbuf_map_info->mmuheap_id); + break; + + default: + VDEC_ASSERT(FALSE); + } + + /* Map this buffer into the MMU. */ +#ifdef DEBUG_DECODER_DRIVER + pr_info("----- %s:%d calling MMU_StreamMapExt", __func__, __LINE__); +#endif + ret = mmu_stream_map_ext(dd_str_ctx->mmu_str_handle, + (enum mmu_eheap_id)ddbuf_map_info->mmuheap_id, + ddbuf_map_info->buf_id, + buf_info->buf_size, DEV_MMU_PAGE_SIZE, + buf_info->mem_attrib, + buf_info->cpu_linear_addr, + &ddbuf_map_info->ddbuf_info); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + if (buf_type == VDEC_BUFTYPE_PICTURE) + dd_str_ctx->map_buf_info.num_buf++; + + /* + * Initialise the reference count to indicate that the client + * still holds the buffer. + */ + ddbuf_map_info->ddbuf_info.ref_count = 1; + + /* Return success.. */ + return IMG_SUCCESS; + +error: + if (ddbuf_map_info) { + if (ddbuf_map_info->res_handle) + rman_free_resource(ddbuf_map_info->res_handle); + else + kfree(ddbuf_map_info); + } + + return ret; +} + +/* + * @Function core_stream_map_buf_sg + */ +int core_stream_map_buf_sg(unsigned int res_str_id, enum vdec_buf_type buf_type, + struct vdec_buf_info *buf_info, + void *sgt, unsigned int *buf_map_id) +{ + int ret; + struct vdecdd_ddstr_ctx *dd_str_ctx; + struct core_stream_context *core_str_ctx; + struct vdecdd_ddbuf_mapinfo *ddbuf_map_info; + + /* + * Resource stream ID cannot be zero. If zero just warning and + * proceeding further will break the code. Return IMG_ERROR_INVALID_ID. + */ + if (res_str_id <= 0) + return IMG_ERROR_INVALID_ID; + + VDEC_ASSERT(buf_type < VDEC_BUFTYPE_MAX); + VDEC_ASSERT(buf_info); + VDEC_ASSERT(buf_map_id); + + /* Get access to stream context.. */ + ret = rman_get_resource(res_str_id, VDECDD_STREAM_TYPE_ID, (void **)&core_str_ctx, NULL); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dd_str_ctx = core_str_ctx->dd_str_ctx; + + VDEC_ASSERT(dd_str_ctx); + + /* Allocate an active stream unit.. */ + ddbuf_map_info = kzalloc(sizeof(*ddbuf_map_info), GFP_KERNEL); + VDEC_ASSERT(ddbuf_map_info); + + if (!ddbuf_map_info) { + pr_err("[SID=0x%08X] Failed to allocate memory for DD buffer map information", + dd_str_ctx->res_str_id); + + return IMG_ERROR_OUT_OF_MEMORY; + } + + /* Save the stream context etc. */ + ddbuf_map_info->ddstr_context = dd_str_ctx; + ddbuf_map_info->buf_type = buf_type; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s:%d vdec2plus: vxd map buff id %d", __func__, __LINE__, + buf_info->buf_id); +#endif + ddbuf_map_info->buf_id = buf_info->buf_id; + + /* Register the allocation as a stream resource.. */ + ret = rman_register_resource(dd_str_ctx->res_buck_handle, + VDECDD_BUFMAP_TYPE_ID, + core_fn_free_mapped, ddbuf_map_info, + &ddbuf_map_info->res_handle, buf_map_id); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + ddbuf_map_info->buf_map_id = *buf_map_id; + + if (buf_type == VDEC_BUFTYPE_PICTURE) { + if (dd_str_ctx->map_buf_info.num_buf == 0) { + dd_str_ctx->map_buf_info.buf_size = buf_info->buf_size; + + dd_str_ctx->map_buf_info.byte_interleave = + buf_info->pictbuf_cfg.byte_interleave; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("[SID=0x%08X] Mapped Buffer size: %d (bytes)", + dd_str_ctx->res_str_id, buf_info->buf_size); +#endif + } else { + /* + * Same byte interleaved setting should be used. + * Convert to actual bools by comparing with zero. + */ + if (buf_info->pictbuf_cfg.byte_interleave != + dd_str_ctx->map_buf_info.byte_interleave) { + pr_err("[SID=0x%08X] Buffer cannot be mapped since its byte interleave value (%s) is not the same as buffers already mapped (%s)", + dd_str_ctx->res_str_id, + buf_info->pictbuf_cfg.byte_interleave ? + "ON" : "OFF", + dd_str_ctx->map_buf_info.byte_interleave ? + "ON" : "OFF"); + ret = IMG_ERROR_INVALID_PARAMETERS; + goto error; + } + } + + /* Configure the buffer.. */ + ret = core_stream_set_pictbuf_config(dd_str_ctx, &buf_info->pictbuf_cfg); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + } + + /* Map heap from VDEC to MMU. */ + switch (buf_type) { + case VDEC_BUFTYPE_BITSTREAM: + ddbuf_map_info->mmuheap_id = MMU_HEAP_BITSTREAM_BUFFERS; + break; + + case VDEC_BUFTYPE_PICTURE: + mmu_get_heap(buf_info->pictbuf_cfg.stride[VDEC_PLANE_VIDEO_Y], + &ddbuf_map_info->mmuheap_id); + break; + + default: + VDEC_ASSERT(FALSE); + } + + /* Map this buffer into the MMU. */ +#ifdef DEBUG_DECODER_DRIVER + pr_info("----- %s:%d calling MMU_StreamMapExt_sg", __func__, __LINE__); +#endif + ret = + mmu_stream_map_ext_sg(dd_str_ctx->mmu_str_handle, + (enum mmu_eheap_id)ddbuf_map_info->mmuheap_id, + sgt, buf_info->buf_size, DEV_MMU_PAGE_SIZE, + buf_info->mem_attrib, buf_info->cpu_linear_addr, + &ddbuf_map_info->ddbuf_info, + &ddbuf_map_info->buf_id); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + if (buf_type == VDEC_BUFTYPE_PICTURE) + dd_str_ctx->map_buf_info.num_buf++; + + /* + * Initialise the reference count to indicate that the client + * still holds the buffer. + */ + ddbuf_map_info->ddbuf_info.ref_count = 1; + + /* Return success.. */ + return IMG_SUCCESS; + +error: + if (ddbuf_map_info->res_handle) + rman_free_resource(ddbuf_map_info->res_handle); + else + kfree(ddbuf_map_info); + + return ret; +} + +/* + * @Function core_stream_unmap_buf + */ +int core_stream_unmap_buf(unsigned int buf_map_id) +{ + int ret; + struct vdecdd_ddbuf_mapinfo *ddbuf_map_info; + struct vdecdd_ddstr_ctx *dd_str_ctx; + struct core_stream_context *core_str_ctx; + + /* Get access to map info context.. */ + ret = rman_get_resource(buf_map_id, VDECDD_BUFMAP_TYPE_ID, + (void **)&ddbuf_map_info, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dd_str_ctx = ddbuf_map_info->ddstr_context; + VDEC_ASSERT(dd_str_ctx); + + /* Get access to stream context.. */ + ret = rman_get_resource(dd_str_ctx->res_str_id, VDECDD_STREAM_TYPE_ID, + (void **)&core_str_ctx, NULL); + VDEC_ASSERT(core_str_ctx); +#ifdef DEBUG_DECODER_DRIVER + pr_info("UNMAP: PM [0x%p] --> VM [0x%08X - 0x%08X] (%d bytes)", + ddbuf_map_info->ddbuf_info.cpu_virt, + ddbuf_map_info->ddbuf_info.dev_virt, + ddbuf_map_info->ddbuf_info.dev_virt + + ddbuf_map_info->ddbuf_info.buf_size, + ddbuf_map_info->ddbuf_info.buf_size); +#endif + + /* Buffer should only be held by the client. */ + VDEC_ASSERT(ddbuf_map_info->ddbuf_info.ref_count == 1); + if (ddbuf_map_info->ddbuf_info.ref_count != 1) + return IMG_ERROR_MEMORY_IN_USE; + + ddbuf_map_info->ddbuf_info.ref_count = 0; + if (ddbuf_map_info->buf_type == VDEC_BUFTYPE_PICTURE) { + /* Remove this picture buffer from pictbuf list */ + ret = resource_list_remove(&core_str_ctx->pict_buf_list, ddbuf_map_info); + + VDEC_ASSERT(ret == IMG_SUCCESS || ret == IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE); + if (ret != IMG_SUCCESS && ret != IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE) + return ret; + + ddbuf_map_info->ddstr_context->map_buf_info.num_buf--; + + /* Clear some state if there are no more mapped buffers. */ + if (dd_str_ctx->map_buf_info.num_buf == 0) { + dd_str_ctx->map_buf_info.buf_size = 0; + dd_str_ctx->map_buf_info.byte_interleave = FALSE; + } + } + + /* Unmap this buffer from the MMU. */ + ret = mmu_free_mem(dd_str_ctx->mmu_str_handle, &ddbuf_map_info->ddbuf_info); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + /* Free buffer map info. */ + rman_free_resource(ddbuf_map_info->res_handle); + + /* Return success.. */ + return IMG_SUCCESS; +} + +/* + * @Function core_stream_unmap_buf_sg + */ +int core_stream_unmap_buf_sg(unsigned int buf_map_id) +{ + int ret; + struct vdecdd_ddbuf_mapinfo *ddbuf_map_info; + struct vdecdd_ddstr_ctx *dd_str_ctx; + struct core_stream_context *core_str_ctx; + + /* Get access to map info context.. */ + ret = rman_get_resource(buf_map_id, VDECDD_BUFMAP_TYPE_ID, (void **)&ddbuf_map_info, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dd_str_ctx = ddbuf_map_info->ddstr_context; + VDEC_ASSERT(dd_str_ctx); + + /* Get access to stream context.. */ + ret = rman_get_resource(dd_str_ctx->res_str_id, VDECDD_STREAM_TYPE_ID, + (void **)&core_str_ctx, NULL); + VDEC_ASSERT(core_str_ctx); + +#ifdef DEBUG_DECODER_DRIVER + pr_info("UNMAP: PM [0x%p] --> VM [0x%08X - 0x%08X] (%d bytes)", + ddbuf_map_info->ddbuf_info.cpu_virt, + ddbuf_map_info->ddbuf_info.dev_virt, + ddbuf_map_info->ddbuf_info.dev_virt + + ddbuf_map_info->ddbuf_info.buf_size, + ddbuf_map_info->ddbuf_info.buf_size); +#endif + + /* Buffer should only be held by the client. */ + VDEC_ASSERT(ddbuf_map_info->ddbuf_info.ref_count == 1); + if (ddbuf_map_info->ddbuf_info.ref_count != 1) + return IMG_ERROR_MEMORY_IN_USE; + + ddbuf_map_info->ddbuf_info.ref_count = 0; + + if (ddbuf_map_info->buf_type == VDEC_BUFTYPE_PICTURE) { + /* Remove this picture buffer from pictbuf list */ + ret = resource_list_remove(&core_str_ctx->pict_buf_list, ddbuf_map_info); + + VDEC_ASSERT(ret == IMG_SUCCESS || ret == IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE); + if (ret != IMG_SUCCESS && ret != IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE) + return ret; + + ddbuf_map_info->ddstr_context->map_buf_info.num_buf--; + + /* + * Clear some state if there are no more + * mapped buffers. + */ + if (dd_str_ctx->map_buf_info.num_buf == 0) { + dd_str_ctx->map_buf_info.buf_size = 0; + dd_str_ctx->map_buf_info.byte_interleave = FALSE; + } + } + + /* Unmap this buffer from the MMU. */ + ret = mmu_free_mem_sg(dd_str_ctx->mmu_str_handle, &ddbuf_map_info->ddbuf_info); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + /* Free buffer map info. */ + rman_free_resource(ddbuf_map_info->res_handle); + + /* Return success.. */ + return IMG_SUCCESS; +} + +/* + * @Function core_stream_flush + */ +int core_stream_flush(unsigned int res_str_id, unsigned char discard_refs) +{ + struct vdecdd_ddstr_ctx *dd_str_ctx; + struct core_stream_context *core_str_ctx; + int ret; + + /* Get access to stream context.. */ + ret = rman_get_resource(res_str_id, VDECDD_STREAM_TYPE_ID, + (void **)&core_str_ctx, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dd_str_ctx = core_str_ctx->dd_str_ctx; + + VDEC_ASSERT(dd_str_ctx); + VDEC_ASSERT(dd_str_ctx->dd_str_state == VDECDD_STRSTATE_STOPPED); + + /* + * If unsupported sequence is found, we need to do additional + * check for DPB flush condition + */ + if (!dd_str_ctx->comseq_hdr_info.not_dpb_flush) { + ret = decoder_stream_flush(dd_str_ctx->dec_ctx, discard_refs); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + + /* Return success.. */ + return IMG_SUCCESS; +} + +/* + * @Function core_stream_release_bufs + */ +int core_stream_release_bufs(unsigned int res_str_id, enum vdec_buf_type buf_type) +{ + int ret; + struct core_stream_context *core_str_ctx; + struct vdecdd_ddstr_ctx *dd_str_ctx; + + /* Get access to stream context.. */ + ret = rman_get_resource(res_str_id, VDECDD_STREAM_TYPE_ID, (void **)&core_str_ctx, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dd_str_ctx = core_str_ctx->dd_str_ctx; + + VDEC_ASSERT(dd_str_ctx); + VDEC_ASSERT(buf_type < VDEC_BUFTYPE_MAX); + + switch (buf_type) { + case VDEC_BUFTYPE_PICTURE: + { + /* Empty all the decoded picture related buffer lists. */ + ret = resource_list_empty(&core_str_ctx->pict_buf_list, TRUE, NULL, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + break; + } + + case VDEC_BUFTYPE_BITSTREAM: + { + /* Empty the stream unit queue. */ + ret = resource_list_empty(&core_str_ctx->str_unit_list, FALSE, + (resource_pfn_freeitem)core_fn_free_stream_unit, + core_str_ctx); + VDEC_ASSERT(ret == IMG_SUCCESS); + break; + } + + case VDEC_BUFTYPE_ALL: + { + /* Empty all the decoded picture related buffer lists. */ + ret = resource_list_empty(&core_str_ctx->pict_buf_list, TRUE, NULL, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + + /* Empty the stream unit queue. */ + ret = resource_list_empty(&core_str_ctx->str_unit_list, FALSE, + (resource_pfn_freeitem)core_fn_free_stream_unit, + core_str_ctx); + VDEC_ASSERT(ret == IMG_SUCCESS); + break; + } + + default: + { + ret = IMG_ERROR_INVALID_PARAMETERS; + VDEC_ASSERT(FALSE); + break; + } + } + + if (buf_type == VDEC_BUFTYPE_PICTURE || buf_type == VDEC_BUFTYPE_ALL) { + ret = decoder_stream_release_buffers(dd_str_ctx->dec_ctx); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + + /* Return success.. */ + return IMG_SUCCESS; +} + +/* + * @Function core_stream_get_status + */ +int core_stream_get_status(unsigned int res_str_id, + struct vdecdd_decstr_status *str_st) +{ + int ret; + struct core_stream_context *core_str_ctx; + struct vdecdd_ddstr_ctx *dd_str_ctx; + + /* Get access to stream context.. */ + ret = rman_get_resource(res_str_id, VDECDD_STREAM_TYPE_ID, (void **)&core_str_ctx, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dd_str_ctx = core_str_ctx->dd_str_ctx; + + VDEC_ASSERT(dd_str_ctx); + VDEC_ASSERT(str_st); + + ret = decoder_stream_get_status(dd_str_ctx->dec_ctx, str_st); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + /* Return success.. */ + return IMG_SUCCESS; +} + +#ifdef HAS_HEVC +/* + * @Function core_free_hevc_picture_resource + */ +static int core_free_hevc_picture_resource(struct core_stream_context *core_strctx, + struct vdecdd_pict_resint *pic_res_int) +{ + int ret = IMG_SUCCESS; + + ret = core_free_resbuf(&pic_res_int->genc_fragment_buf, + core_strctx->dd_str_ctx->mmu_str_handle); + if (ret != IMG_SUCCESS) + pr_err("MMU_Free for Genc Fragment buffer failed with error %u", ret); + + return ret; +} + +/* + * @Function core_free_hevc_sequence_resource + */ +static int core_free_hevc_sequence_resource(struct core_stream_context *core_strctx, + struct vdecdd_seq_resint *seq_res_int) +{ + unsigned int i; + int local_result = IMG_SUCCESS; + int ret = IMG_SUCCESS; + + for (i = 0; i < GENC_BUFF_COUNT; ++i) { + local_result = core_free_resbuf(&seq_res_int->genc_buffers[i], + core_strctx->dd_str_ctx->mmu_str_handle); + if (local_result != IMG_SUCCESS) { + ret = local_result; + pr_warn("MMU_Free for GENC buffer %u failed with error %u", i, + local_result); + } + } + + local_result = core_free_resbuf(&seq_res_int->intra_buffer, + core_strctx->dd_str_ctx->mmu_str_handle); + if (local_result != IMG_SUCCESS) { + ret = local_result; + pr_warn("MMU_Free for GENC buffer %u failed with error %u", i, local_result); + } + + local_result = core_free_resbuf(&seq_res_int->aux_buffer, + core_strctx->dd_str_ctx->mmu_str_handle); + if (local_result != IMG_SUCCESS) { + ret = local_result; + pr_warn("MMU_Free for GENC buffer %u failed with error %u", i, local_result); + } + + return ret; +} + +/* + * @Function core_hevc_bufs_get_size + */ +static int core_hevc_bufs_get_size(struct core_stream_context *core_strctx, + const struct vdec_comsequ_hdrinfo *seqhdr_info, + struct vdec_pict_size *max_pict_size, + struct core_pict_bufsize_info *size_info, + struct core_seq_resinfo *seqres_info, + unsigned char *resource_needed) +{ + enum vdec_vid_std vid_std = core_strctx->dd_str_ctx->str_config_data.vid_std; + unsigned int std_idx = vid_std - 1; + + static const unsigned short max_slice_segments_list + [HEVC_LEVEL_MAJOR_NUM][HEVC_LEVEL_MINOR_NUM] = { + /* level: 1.0 1.1 1.2 */ + { 16, 0, 0, }, + /* level: 2.0 2.1 2.2 */ + { 16, 20, 0, }, + /* level: 3.0 3.1 3.2 */ + { 30, 40, 0, }, + /* level: 4.0 4.1 4.2 */ + { 75, 75, 0, }, + /* level: 5.0 5.1 5.2 */ + { 200, 200, 200, }, + /* level: 6.0 6.1 6.2 */ + { 600, 600, 600, } + }; + + static const unsigned char max_tile_cols_list + [HEVC_LEVEL_MAJOR_NUM][HEVC_LEVEL_MINOR_NUM] = { + /* level: 1.0 1.1 1.2 */ + { 1, 0, 0, }, + /* level: 2.0 2.1 2.2 */ + { 1, 1, 0, }, + /* level: 3.0 3.1 3.2 */ + { 2, 3, 0, }, + /* level: 4.0 4.1 4.2 */ + { 5, 5, 0, }, + /* level: 5.0 5.1 5.2 */ + { 10, 10, 10, }, + /* level: 6.0 6.1 6.2 */ + { 20, 20, 20, } + }; + + /* TRM 3.11.11 */ + static const unsigned int total_sample_per_mb[PIXEL_FORMAT_444 + 1] = { + 256, 384, 384, 512, 768}; + + static const unsigned int HEVC_LEVEL_IDC_MIN = 30; + static const unsigned int HEVC_LEVEL_IDC_MAX = 186; + static const unsigned int GENC_ALIGNMENT = 0x1000; + static const unsigned int mb_size = 16; + static const unsigned int max_mb_rows_in_ctu = 4; + static const unsigned int bytes_per_fragment_pointer = 16; + + const unsigned int max_tile_height_in_mbs = + seqhdr_info->max_frame_size.height / mb_size; + + signed char level_maj = seqhdr_info->codec_level / 30; + signed char level_min = (seqhdr_info->codec_level % 30) / 3; + + /* + * If we are somehow able to deliver more information here (CTU size, + * number of tile columns/rows) then memory usage could be reduced + */ + const struct pixel_pixinfo *pix_info = &seqhdr_info->pixel_info; + const unsigned int bit_depth = pix_info->bitdepth_y >= pix_info->bitdepth_c ? + pix_info->bitdepth_y : pix_info->bitdepth_c; + unsigned short max_slice_segments; + unsigned char max_tile_cols; + unsigned int raw_byte_per_mb; + unsigned int *genc_fragment_bufsize; + unsigned int *genc_buf_size; + + /* Reset the MB parameters buffer size. */ + size_info->mbparams_bufsize = 0; + *resource_needed = TRUE; + + if (mbparam_allocinfo[std_idx].alloc_mbparam_bufs) { + /* shall be == 64 (0x40)*/ + const unsigned int align = mbparam_allocinfo[std_idx].mbparam_size; + const unsigned int dpb_width = (max_pict_size->width + align * 2 - 1) / align * 2; + const unsigned int pic_height = (max_pict_size->height + align - 1) / align; + const unsigned int pic_width = (max_pict_size->width + align - 1) / align; + + /* calculating for worst case: max frame size, B-frame */ + size_info->mbparams_bufsize = (align * 2) * pic_width * pic_height + + align * dpb_width * pic_height; + + /* Adjust the buffer size for MSVDX. */ + vdecddutils_buf_vxd_adjust_size(&size_info->mbparams_bufsize); + } + + if (seqhdr_info->codec_level > HEVC_LEVEL_IDC_MAX || + seqhdr_info->codec_level < HEVC_LEVEL_IDC_MIN) { + level_maj = 6; + level_min = 2; + } + + if (level_maj > 0 && level_maj <= HEVC_LEVEL_MAJOR_NUM && + level_min >= 0 && level_min < HEVC_LEVEL_MINOR_NUM) { + max_slice_segments = max_slice_segments_list[level_maj - 1][level_min]; + max_tile_cols = max_tile_cols_list[level_maj - 1][level_min]; + } else { + pr_err("%s: Invalid parameters\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + raw_byte_per_mb = total_sample_per_mb[pix_info->chroma_fmt_idc] * + VDEC_ALIGN_SIZE(bit_depth, 8, unsigned int, int) / 8; + + genc_fragment_bufsize = &size_info->hevc_bufsize_pict.genc_fragment_bufsize; + genc_buf_size = &seqres_info->hevc_bufsize_seqres.genc_bufsize; + + *genc_fragment_bufsize = bytes_per_fragment_pointer * (seqhdr_info->max_frame_size.height / + mb_size * max_tile_cols + max_slice_segments - 1) * max_mb_rows_in_ctu; + + /* + * GencBufferSize formula is taken from TRM and found by HW * CSIM teams for a sensible + * streams i.e. size_of_stream < size_of_output_YUV. In videostream data base it's + * possible to find pathological Argon streams that do not fulfill this sensible + * requirement. eg. #58417, #58419, #58421, #58423. To make a #58417 stream running the + * formula below should be changed from (2 * 384) *... ---> (3 * 384) *... + * This solution is applied by DEVA. + */ + *genc_buf_size = 2 * raw_byte_per_mb * seqhdr_info->max_frame_size.width / + mb_size * max_tile_height_in_mbs / 4; + + *genc_buf_size = VDEC_ALIGN_SIZE(*genc_buf_size, GENC_ALIGNMENT, + unsigned int, unsigned int); + *genc_fragment_bufsize = VDEC_ALIGN_SIZE(*genc_fragment_bufsize, GENC_ALIGNMENT, + unsigned int, unsigned int); + +#ifdef DEBUG_DECODER_DRIVER + pr_info("Sizes for GENC in HEVC: 0x%X (frag), 0x%X (x4)", + *genc_fragment_bufsize, + *genc_buf_size); +#endif + + seqres_info->hevc_bufsize_seqres.intra_bufsize = 4 * seqhdr_info->max_frame_size.width; + if (seqhdr_info->pixel_info.mem_pkg != PIXEL_BIT8_MP) + seqres_info->hevc_bufsize_seqres.intra_bufsize *= 2; + + seqres_info->hevc_bufsize_seqres.aux_bufsize = (512 * 1024); + + return IMG_SUCCESS; +} + +/* + * @Function core_is_hevc_stream_resource_suitable + */ +static unsigned char +core_is_hevc_stream_resource_suitable(struct core_pict_resinfo *pict_res_info, + struct core_pict_resinfo *old_pict_res_info, + struct core_seq_resinfo *seq_res_info, + struct core_seq_resinfo *old_seq_res_info) +{ + return (seq_res_info->hevc_bufsize_seqres.genc_bufsize <= + old_seq_res_info->hevc_bufsize_seqres.genc_bufsize && + seq_res_info->hevc_bufsize_seqres.intra_bufsize <= + old_seq_res_info->hevc_bufsize_seqres.intra_bufsize && + seq_res_info->hevc_bufsize_seqres.aux_bufsize <= + old_seq_res_info->hevc_bufsize_seqres.aux_bufsize && + pict_res_info->size_info.hevc_bufsize_pict.genc_fragment_bufsize <= + old_pict_res_info->size_info.hevc_bufsize_pict.genc_fragment_bufsize); +} + +/* + * @Function core_alloc_hevc_specific_seq_buffers + */ +static int +core_alloc_hevc_specific_seq_buffers(struct core_stream_context *core_strctx, + struct vdecdd_seq_resint *seqres_int, + struct vxdio_mempool mempool, + struct core_seq_resinfo *seqres_info) +{ + unsigned int i; + int ret = IMG_SUCCESS; + + /* Allocate GENC buffers */ + for (i = 0; i < GENC_BUFF_COUNT; ++i) { + /* Allocate the GENC buffer info structure. */ + ret = core_alloc_resbuf(&seqres_int->genc_buffers[i], + seqres_info->hevc_bufsize_seqres.genc_bufsize, + core_strctx->dd_str_ctx->mmu_str_handle, + mempool); + if (ret != IMG_SUCCESS) + return ret; + } + + seqres_int->genc_buf_id = ++core_strctx->std_spec_context.hevc_ctx.genc_id_gen; + + /* Allocate the intra buffer info structure. */ + ret = core_alloc_resbuf(&seqres_int->intra_buffer, + seqres_info->hevc_bufsize_seqres.intra_bufsize, + core_strctx->dd_str_ctx->mmu_str_handle, + mempool); + if (ret != IMG_SUCCESS) + return ret; + + /* Allocate the aux buffer info structure. */ + ret = core_alloc_resbuf(&seqres_int->aux_buffer, + seqres_info->hevc_bufsize_seqres.aux_bufsize, + core_strctx->dd_str_ctx->mmu_str_handle, + mempool); + if (ret != IMG_SUCCESS) + return ret; + + return IMG_SUCCESS; +} + +/* + * @Function core_alloc_hevc_specific_pict_buffers + */ +static int +core_alloc_hevc_specific_pict_buffers(struct core_stream_context *core_strctx, + struct vdecdd_pict_resint *pict_res_int, + struct vxdio_mempool mempool, + struct core_pict_resinfo *pict_res_info) +{ + int ret; + + /* Allocate the GENC fragment buffer. */ + ret = core_alloc_resbuf(&pict_res_int->genc_fragment_buf, + pict_res_info->size_info.hevc_bufsize_pict.genc_fragment_bufsize, + core_strctx->dd_str_ctx->mmu_str_handle, + mempool); + + return ret; +} +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/core.h b/drivers/media/platform/imagination/vxe-vxd/decoder/core.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/core.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/core.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD Decoder CORE and V4L2 Node Interface header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#ifndef __CORE_H__ +#define __CORE_H__ + +#include +#include "decoder.h" + +int core_initialise(void *dev_handle, unsigned int internal_heap_id, + void *cb); + +/** + * core_deinitialise - deinitialise core + */ +int core_deinitialise(void); + +int core_supported_features(struct vdec_features *features); + +int core_stream_create(void *vxd_dec_ctx_arg, + const struct vdec_str_configdata *str_cfgdata, + unsigned int *res_str_id); + +int core_stream_destroy(unsigned int res_str_id); + +int core_stream_play(unsigned int res_str_id); + +int core_stream_stop(unsigned int res_str_id); + +int core_stream_map_buf(unsigned int res_str_id, enum vdec_buf_type buf_type, + struct vdec_buf_info *buf_info, unsigned int *buf_map_id); + +int core_stream_map_buf_sg(unsigned int res_str_id, + enum vdec_buf_type buf_type, + struct vdec_buf_info *buf_info, + void *sgt, unsigned int *buf_map_id); + +int core_stream_unmap_buf(unsigned int buf_map_id); + +int core_stream_unmap_buf_sg(unsigned int buf_map_id); + +int core_stream_submit_unit(unsigned int res_str_id, + struct vdecdd_str_unit *str_unit); + +int core_stream_fill_pictbuf(unsigned int buf_map_id); + +/* This function to be called before stream play */ +int core_stream_set_output_config(unsigned int res_str_id, + struct vdec_str_opconfig *str_opcfg, + struct vdec_pict_bufconfig *pict_bufcg); + +int core_stream_flush(unsigned int res_str_id, unsigned char discard_refs); + +int core_stream_release_bufs(unsigned int res_str_id, + enum vdec_buf_type buf_type); + +int core_stream_get_status(unsigned int res_str_id, + struct vdecdd_decstr_status *str_status); + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/decoder.c b/drivers/media/platform/imagination/vxe-vxd/decoder/decoder.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/decoder.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/decoder.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,4629 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VXD Decoder Component function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#include "decoder.h" +#include "dec_resources.h" +#include "dq.h" +#include "hw_control.h" +#include "h264fw_data.h" +#include "idgen_api.h" +#include "img_errors.h" +#ifdef HAS_JPEG +#include "jpegfw_data.h" +#endif +#include "lst.h" +#include "pool_api.h" +#include "resource.h" +#include "translation_api.h" +#include "vdecdd_utils.h" +#include "vdec_mmu_wrapper.h" +#include "vxd_dec.h" + +#define MAX_PLATFORM_SUPPORTED_HEIGHT 65536 +#define MAX_PLATFORM_SUPPORTED_WIDTH 65536 + +#define MAX_CONCURRENT_STREAMS 16 + +/* Maximum number of unique picture ids within stream. */ +#define DECODER_MAX_PICT_ID GET_STREAM_PICTURE_ID(((1ULL << 32) - 1ULL)) + +/* Maximum number of concurrent pictures within stream. */ +#define DECODER_MAX_CONCURRENT_PICT 0x100 + +static inline unsigned int get_next_picture_id(unsigned int cur_pict_id) +{ + return(cur_pict_id == FWIF_BIT_MASK(FWIF_NUMBITS_STREAM_PICTURE_ID) ? + 1 : cur_pict_id + 1); +} + +static inline unsigned int get_prev_picture_id(unsigned int cur_pict_id) +{ + return(cur_pict_id == 1 ? + FWIF_BIT_MASK(FWIF_NUMBITS_STREAM_PICTURE_ID) : + cur_pict_id - 1); +} + +#define H264_SGM_BUFFER_BYTES_PER_MB 1 +#define H264_SGM_MAX_MBS 3600 + +#define CONTEXT_BUFF_SIZE (72) + +/* + * Number of bits in transaction ID used to represent + * picture number in stream. + */ +#define FWIF_NUMBITS_STREAM_PICTURE_ID 16 +/* + * Number of bits in transaction ID used to represent + * picture number in core. + */ +#define FWIF_NUMBITS_CORE_PICTURE_ID 4 +/* + * Number of bits in transaction ID used to represent + * stream id. + */ +#define FWIF_NUMBITS_STREAM_ID 8 +/* Number of bits in transaction ID used to represent core id. */ +#define FWIF_NUMBITS_CORE_ID 4 + +/* Offset in transaction ID to picture number in stream. */ +#define FWIF_OFFSET_STREAM_PICTURE_ID 0 +/* Offset in transaction ID to picture number in core. */ +#define FWIF_OFFSET_CORE_PICTURE_ID (FWIF_OFFSET_STREAM_PICTURE_ID + \ + FWIF_NUMBITS_STREAM_PICTURE_ID) +/* Offset in transaction ID to stream id. */ +#define FWIF_OFFSET_STREAM_ID (FWIF_OFFSET_CORE_PICTURE_ID + \ + FWIF_NUMBITS_CORE_PICTURE_ID) +/* Offset in transaction ID to core id. */ +#define FWIF_OFFSET_CORE_ID (FWIF_OFFSET_STREAM_ID + \ + FWIF_NUMBITS_STREAM_ID) + +/* Maximum number of unique picture ids within stream. */ +#define DECODER_MAX_PICT_ID GET_STREAM_PICTURE_ID(((1ULL << 32) - 1ULL)) + +/* Maximum number of concurrent pictures within stream. */ +#define DECODER_MAX_CONCURRENT_PICT 0x100 + +#define CREATE_TRANSACTION_ID(core_id, stream_id, core_pic, stream_pic) \ + (SET_CORE_ID((core_id)) | SET_STREAM_ID((stream_id)) | \ + SET_CORE_PICTURE_ID((core_pic)) | SET_STREAM_PICTURE_ID((stream_pic))) + +static inline struct dec_core_ctx *decoder_str_ctx_to_core_ctx(struct dec_str_ctx *decstrctx) +{ + if (decstrctx && decstrctx->decctx) + return decstrctx->decctx->dec_core_ctx; + + else + return NULL; +} + +static const struct vdecdd_dd_devconfig def_dev_cfg = { + CORE_NUM_DECODE_SLOTS, /* ui32NumSlotsPerPipe; */ +}; + +/* + * This array defines names of the VDEC standards. + * Shall be in sync with #VDEC_eVidStd + * @brief Names of the VDEC standards + */ +static unsigned char *vid_std_names[] = { + "VDEC_STD_UNDEFINED", + "VDEC_STD_MPEG2", + "VDEC_STD_MPEG4", + "VDEC_STD_H263", + "VDEC_STD_H264", + "VDEC_STD_VC1", + "VDEC_STD_AVS", + "VDEC_STD_REAL", + "VDEC_STD_JPEG", + "VDEC_STD_VP6", + "VDEC_STD_VP8", + "VDEC_STD_SORENSON", + "VDEC_STD_HEVC" +}; + +#ifdef ERROR_RECOVERY_SIMULATION +extern int fw_error_value; +#endif + +/* + * @Function decoder_set_device_config + */ +static int decoder_set_device_config(const struct vdecdd_dd_devconfig **dd_dev_config) +{ + struct vdecdd_dd_devconfig *local_dev_cfg; + + VDEC_ASSERT(dd_dev_config); + + /* Allocate device configuration structure */ + local_dev_cfg = kzalloc(sizeof(*local_dev_cfg), GFP_KERNEL); + VDEC_ASSERT(local_dev_cfg); + if (!local_dev_cfg) + return IMG_ERROR_OUT_OF_MEMORY; + + /* Set the default device configuration */ + *local_dev_cfg = def_dev_cfg; + + *dd_dev_config = local_dev_cfg; + + return IMG_SUCCESS; +} + +/* + * @Function decoder_set_feature_flags + * @Description + * This function sets the features flags from the core properties. + * @Input p : Pointer to core properties. + * @Input core_feat_flags : Pointer to core feature flags word. + */ +static void decoder_set_feature_flags(struct vxd_coreprops *core_props, + unsigned int *core_feat_flags, + unsigned int *pipe_feat_flags) +{ + unsigned char pipe_minus_one; + + VDEC_ASSERT(core_props); + VDEC_ASSERT(core_feat_flags); + VDEC_ASSERT(pipe_feat_flags); + + for (pipe_minus_one = 0; pipe_minus_one < core_props->num_pixel_pipes; + pipe_minus_one++) { + *core_feat_flags |= pipe_feat_flags[pipe_minus_one] |= + core_props->h264[pipe_minus_one] ? + VDECDD_COREFEATURE_H264 : 0; +#ifdef HAS_JPEG + *core_feat_flags |= pipe_feat_flags[pipe_minus_one] |= + core_props->jpeg[pipe_minus_one] ? + VDECDD_COREFEATURE_JPEG : 0; +#endif +#ifdef HAS_HEVC + *core_feat_flags |= pipe_feat_flags[pipe_minus_one] |= + core_props->hevc[pipe_minus_one] ? + VDECDD_COREFEATURE_HEVC : 0; +#endif + } +} + +/* + * @Function decoder_stream_get_context + * @Description + * This function returns the stream context structure for the given + * stream handle. + * @Return struct dec_str_ctx : This function returns a pointer + * to the stream + * context structure or NULL if not found. + */ +static struct dec_str_ctx *decoder_stream_get_context(void *dec_str_context) +{ + return (struct dec_str_ctx *)dec_str_context; +} + +/* + * @Function decoder_core_enumerate + * @Description + * This function enumerates a decoder core and returns its handle. + * Usage: before calls to other DECODE_Core or DECODE_Stream functions. + * @Input dec_context : Pointer to Decoder context. + * @Input dev_cfg : Device configuration. + * @Return This function returns either IMG_SUCCESS or an + * error code. + */ +static int decoder_core_enumerate(struct dec_ctx *dec_context, + const struct vdecdd_dd_devconfig *dev_cfg, + unsigned int *num_pipes) +{ + struct dec_core_ctx *dec_core_ctx_local; + unsigned int ret; + unsigned int ptd_align = DEV_MMU_PAGE_ALIGNMENT; + + /* Create the core. */ + dec_core_ctx_local = kzalloc(sizeof(*dec_core_ctx_local), GFP_KERNEL); + if (!dec_core_ctx_local) + return IMG_ERROR_OUT_OF_MEMORY; + + dec_core_ctx_local->dec_ctx = (struct dec_ctx *)dec_context; + + /* Initialise the hwctrl block here */ + ret = hwctrl_initialise(dec_core_ctx_local, dec_context->user_data, + dev_cfg, &dec_core_ctx_local->core_props, + &dec_core_ctx_local->hw_ctx); + if (ret != IMG_SUCCESS) + goto error; + + decoder_set_feature_flags(&dec_core_ctx_local->core_props, + &dec_core_ctx_local->core_features, + dec_core_ctx_local->pipe_features); + + /* Perform device setup for master core. */ + if (num_pipes) + *num_pipes = dec_core_ctx_local->core_props.num_pixel_pipes; + + /* DEVA PVDEC FW requires PTD to be 64k aligned. */ + ptd_align = 0x10000; + + /* Create a device MMU context. */ + ret = mmu_device_create(dec_core_ctx_local->core_props.mmu_type, + ptd_align, &dec_context->mmu_dev_handle); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + dec_core_ctx_local->enumerated = TRUE; + + dec_context->dec_core_ctx = dec_core_ctx_local; + + return IMG_SUCCESS; + +error: + if (dec_core_ctx_local) { + unsigned int deinit_result = IMG_SUCCESS; + + /* Destroy a device MMU context. */ + if (dec_context->mmu_dev_handle) { + deinit_result = + mmu_device_destroy(dec_context->mmu_dev_handle); + VDEC_ASSERT(deinit_result == IMG_SUCCESS); + if (deinit_result != IMG_SUCCESS) + pr_warn("MMU_DeviceDestroy() failed to tidy-up after error"); + } + + kfree(dec_core_ctx_local); + dec_core_ctx_local = NULL; + } + + return ret; +} + +/* + * @Function decoder_initialise + */ +int decoder_initialise(void *user_init_data, unsigned int int_heap_id, + struct vdecdd_dd_devconfig *dd_device_config, + unsigned int *num_pipes, + void **dec_ctx_handle) +{ + struct dec_ctx *dec_context = (struct dec_ctx *)*dec_ctx_handle; + int ret; + + if (!dec_context) { + dec_context = kzalloc(sizeof(*dec_context), GFP_KERNEL); + VDEC_ASSERT(dec_context); + if (!dec_context) + return IMG_ERROR_OUT_OF_MEMORY; + + *dec_ctx_handle = dec_context; + } + + /* Determine which standards are supported. */ + memset(&dec_context->sup_stds, 0x0, sizeof(dec_context->sup_stds[VDEC_STD_MAX])); + + dec_context->sup_stds[VDEC_STD_H264] = TRUE; +#ifdef HAS_HEVC + dec_context->sup_stds[VDEC_STD_HEVC] = TRUE; +#endif + if (!dec_context->inited) { + /* Check and store input parameters. */ + dec_context->user_data = user_init_data; + dec_context->dev_handle = + ((struct vdecdd_dddev_context *)user_init_data)->dev_handle; + + /* Initialise the context lists. */ + lst_init(&dec_context->str_list); + + /* Make sure POOL API is initialised */ + ret = pool_init(); + if (ret != IMG_SUCCESS) + goto pool_init_error; + + ret = decoder_set_device_config(&dec_context->dev_cfg); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + dec_context->internal_heap_id = int_heap_id; + + /* Enumerate the master core. */ + ret = decoder_core_enumerate(dec_context, dec_context->dev_cfg, + &dec_context->num_pipes); + if (ret != IMG_SUCCESS) + goto error; + + if (dd_device_config) + *dd_device_config = *dec_context->dev_cfg; + + if (num_pipes) + *num_pipes = dec_context->num_pipes; + + dec_context->inited = TRUE; + } + + return IMG_SUCCESS; + +error: + pool_deinit(); + +pool_init_error: + if (dec_context->dev_cfg) { + kfree((void *)dec_context->dev_cfg); + dec_context->dev_cfg = NULL; + } + + kfree(*dec_ctx_handle); + *dec_ctx_handle = NULL; + + return ret; +} + +/* + * @Function decoder_supported_features + */ +int decoder_supported_features(void *dec_ctx, struct vdec_features *features) +{ + struct dec_ctx *dec_context = (struct dec_ctx *)dec_ctx; + struct dec_core_ctx *dec_core_ctx_local; + + /* Check input parameters. */ + VDEC_ASSERT(dec_context); + VDEC_ASSERT(features); + if (!dec_context || !features) { + pr_err("Invalid parameters!"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Ensure that Decoder component is initialised. */ + VDEC_ASSERT(dec_context->inited); + + /* Loop over all cores checking for support. */ + dec_core_ctx_local = dec_context->dec_core_ctx; + VDEC_ASSERT(dec_core_ctx_local); + + /* + * Determine whether the required core attribute + * is present to support requested feature + */ + features->h264 |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_H264) ? TRUE : FALSE; + features->mpeg2 |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_MPEG2) ? TRUE : FALSE; + features->mpeg4 |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_MPEG4) ? TRUE : FALSE; + features->vc1 |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_VC1) ? TRUE : FALSE; + features->avs |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_AVS) ? TRUE : FALSE; + features->real |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_REAL) ? TRUE : FALSE; + features->jpeg |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_JPEG) ? TRUE : FALSE; + features->vp6 |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_VP6) ? TRUE : FALSE; + features->vp8 |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_VP8) ? TRUE : FALSE; + features->hd |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_HD_DECODE) ? TRUE : FALSE; + features->rotation |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_ROTATION) ? TRUE : FALSE; + features->scaling |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_SCALING) ? TRUE : FALSE; + features->hevc |= (dec_core_ctx_local->core_features & + VDECDD_COREFEATURE_HEVC) ? TRUE : FALSE; + + return IMG_SUCCESS; +} + +/* + * @Function decoder_stream_get_status + */ +int decoder_stream_get_status(void *dec_str_ctx_handle, + struct vdecdd_decstr_status *dec_str_st) +{ + struct dec_str_ctx *dec_str_ctx; + struct dec_decoded_pict *decoded_pict; + struct dec_core_ctx *dec_core_ctx; + unsigned int item; + + VDEC_ASSERT(dec_str_st); + if (!dec_str_st) { + pr_err("Invalid decoder streams status pointer!"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + dec_str_ctx = decoder_stream_get_context(dec_str_ctx_handle); + VDEC_ASSERT(dec_str_ctx); + if (!dec_str_ctx) { + pr_err("Invalid decoder stream context handle!"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Obtain the state of each core. */ + dec_core_ctx = decoder_str_ctx_to_core_ctx(dec_str_ctx); + VDEC_ASSERT(dec_core_ctx); + + /* + * Obtain the display and release list of first unprocessed + * picture in decoded list + */ + dec_str_ctx->dec_str_st.display_pics = 0; + dec_str_ctx->dec_str_st.release_pics = 0; + decoded_pict = dq_first(&dec_str_ctx->str_decd_pict_list); + while (decoded_pict) { + /* if this is the first unprocessed picture */ + if (!decoded_pict->processed) { + unsigned int idx; + struct vdecfw_buffer_control *buf_ctrl; + + VDEC_ASSERT(decoded_pict->pict_ref_res); + buf_ctrl = + (struct vdecfw_buffer_control *)decoded_pict->pict_ref_res->fw_ctrlbuf.cpu_virt; + VDEC_ASSERT(buf_ctrl); + + /* Get display pictures */ + idx = decoded_pict->disp_idx; + item = dec_str_ctx->dec_str_st.display_pics; + while (idx < buf_ctrl->display_list_length && + item < VDECFW_MAX_NUM_PICTURES) { + dec_str_ctx->dec_str_st.next_display_items[item] = + buf_ctrl->display_list[idx]; + dec_str_ctx->dec_str_st.next_display_item_parent[item] = + decoded_pict->transaction_id; + idx++; + item++; + } + dec_str_ctx->dec_str_st.display_pics = item; + + /* Get release pictures */ + idx = decoded_pict->rel_idx; + item = dec_str_ctx->dec_str_st.release_pics; + while (idx < buf_ctrl->release_list_length && + item < VDECFW_MAX_NUM_PICTURES) { + dec_str_ctx->dec_str_st.next_release_items[item] = + buf_ctrl->release_list[idx]; + dec_str_ctx->dec_str_st.next_release_item_parent[item] = + decoded_pict->transaction_id; + idx++; + item++; + } + dec_str_ctx->dec_str_st.release_pics = item; + break; + } + + if (decoded_pict != dq_last(&dec_str_ctx->str_decd_pict_list)) + decoded_pict = dq_next(decoded_pict); + else + decoded_pict = NULL; + } + + /* Get list of held decoded pictures */ + item = 0; + decoded_pict = dq_first(&dec_str_ctx->str_decd_pict_list); + while (decoded_pict) { + dec_str_ctx->dec_str_st.decoded_picts[item] = + decoded_pict->transaction_id; + item++; + + if (decoded_pict != dq_last(&dec_str_ctx->str_decd_pict_list)) + decoded_pict = dq_next(decoded_pict); + else + decoded_pict = NULL; + } + + VDEC_ASSERT(item == dec_str_ctx->dec_str_st.num_pict_decoded); + *dec_str_st = dec_str_ctx->dec_str_st; + + return IMG_SUCCESS; +} + +/* + * @Function decoder_deinitialise + */ +int decoder_deinitialise(void *dec_ctx) +{ + struct dec_ctx *dec_context = (struct dec_ctx *)dec_ctx; + int ret; + /* Remove and free all core context structures */ + struct dec_decpict *dec_pict; + + if (dec_context && dec_context->inited) { + struct dec_core_ctx *dec_core_ctx_local = + dec_context->dec_core_ctx; + + if (!dec_core_ctx_local) { + pr_warn("%s %d NULL Decoder context passed", __func__, __LINE__); + VDEC_ASSERT(0); + return -EFAULT; + } + + /* Stream list should be empty. */ + if (!lst_empty(&dec_context->str_list)) + pr_warn("%s %d stream list should be empty", __func__, __LINE__); + + /* + * All cores should now be idle since there are no + * connections/streams. + */ + ret = hwctrl_peekheadpiclist(dec_core_ctx_local->hw_ctx, &dec_pict); + VDEC_ASSERT(ret != IMG_SUCCESS); + + /* Destroy a device MMU context. */ + ret = mmu_device_destroy(dec_context->mmu_dev_handle); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + /* Remove and free core context structure */ + dec_core_ctx_local = dec_context->dec_core_ctx; + VDEC_ASSERT(dec_core_ctx_local); + + hwctrl_deinitialise(dec_core_ctx_local->hw_ctx); + + kfree(dec_core_ctx_local); + dec_core_ctx_local = NULL; + + VDEC_ASSERT(dec_context->dev_cfg); + if (dec_context->dev_cfg) + kfree((void *)dec_context->dev_cfg); + + dec_context->user_data = NULL; + + pool_deinit(); + + dec_context->inited = FALSE; + + kfree(dec_context); + } else { + pr_err("Decoder has not been initialised so cannot be de-initialised"); + return IMG_ERROR_NOT_INITIALISED; + } + + pr_debug("Decoder deinitialise successfully\n"); + return IMG_SUCCESS; +} + +/* + * @Function decoder_picture_destroy + * @Description + * Free the picture container and optionally release image buffer back to + * client. + * Default is to decrement the reference count held by this picture. + */ +static int decoder_picture_destroy(struct dec_str_ctx *dec_str_ctx, + unsigned int pict_id, + unsigned char release_image) +{ + struct vdecdd_picture *picture; + int ret; + + VDEC_ASSERT(dec_str_ctx); + + ret = idgen_gethandle(dec_str_ctx->pict_idgen, pict_id, (void **)&picture); + if (ret == IMG_SUCCESS) { + VDEC_ASSERT(picture); + ret = idgen_freeid(dec_str_ctx->pict_idgen, pict_id); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + if (picture->dec_pict_info) { + /* Destroy the picture */ + kfree(picture->dec_pict_info); + picture->dec_pict_info = NULL; + } + + /* Return unused picture and internal resources */ + if (picture->disp_pict_buf.pict_buf) { + if (release_image) + resource_item_release + (&picture->disp_pict_buf.pict_buf->ddbuf_info.ref_count); + else + resource_item_return + (&picture->disp_pict_buf.pict_buf->ddbuf_info.ref_count); + + memset(&picture->disp_pict_buf, 0, sizeof(picture->disp_pict_buf)); + } + + if (picture->pict_res_int) { + resource_item_return(&picture->pict_res_int->ref_cnt); + picture->pict_res_int = NULL; + } + + kfree(picture); + picture = NULL; + } else { + VDEC_ASSERT(ret == IMG_SUCCESS); + return ret; + } + + return IMG_SUCCESS; +} + +/* + * @Function decoder_decoded_picture_destroy + */ +static int +decoder_decoded_picture_destroy(struct dec_str_ctx *dec_str_ctx, + struct dec_decoded_pict *decoded_pict, + unsigned char release_image) +{ + int ret; + + VDEC_ASSERT(dec_str_ctx); + VDEC_ASSERT(decoded_pict); + + if (decoded_pict->pict) { + VDEC_ASSERT(decoded_pict->pict->pict_id == + GET_STREAM_PICTURE_ID(decoded_pict->transaction_id)); + + ret = decoder_picture_destroy(dec_str_ctx, decoded_pict->pict->pict_id, + release_image); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + decoded_pict->pict = NULL; + } + + dq_remove(decoded_pict); + dec_str_ctx->dec_str_st.num_pict_decoded--; + + resource_item_return(&decoded_pict->pict_ref_res->ref_cnt); + +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] [TID=0x%08X] COMPLETE", + GET_STREAM_ID(decoded_pict->transaction_id), + decoded_pict->transaction_id); +#endif + + kfree(decoded_pict->first_fld_fwmsg); + decoded_pict->first_fld_fwmsg = NULL; + + kfree(decoded_pict->second_fld_fwmsg); + decoded_pict->second_fld_fwmsg = NULL; + + kfree(decoded_pict); + decoded_pict = NULL; + + return IMG_SUCCESS; +} + +/* + * @Function decoder_stream_decode_resource_destroy + */ +static int decoder_stream_decode_resource_destroy(void *item, void *free_cb_param) +{ + struct dec_pictdec_res *pict_dec_res = item; + struct dec_str_ctx *dec_str_ctx_local = + (struct dec_str_ctx *)free_cb_param; + int ret; + + VDEC_ASSERT(pict_dec_res); + VDEC_ASSERT(resource_item_isavailable(&pict_dec_res->ref_cnt)); + + /* Free memory (device-based) to store fw contexts for stream. */ + ret = mmu_free_mem(dec_str_ctx_local->mmu_str_handle, &pict_dec_res->fw_ctx_buf); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + if (pict_dec_res->h264_sgm_buf.hndl_memory) { + /* Free memory (device-based) to store SGM. */ + ret = mmu_free_mem(dec_str_ctx_local->mmu_str_handle, &pict_dec_res->h264_sgm_buf); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + + kfree(pict_dec_res); + + return IMG_SUCCESS; +} + +/* + * @Function decoder_stream_release_buffers + */ +int decoder_stream_release_buffers(void *dec_str_ctx_handle) +{ + struct dec_str_ctx *dec_str_ctx; + struct dec_decoded_pict *decoded_pict; + int ret; + + dec_str_ctx = decoder_stream_get_context(dec_str_ctx_handle); + + /* Decoding queue should be empty since we are stopped */ + VDEC_ASSERT(dec_str_ctx); + if (!dec_str_ctx) { + pr_err("Invalid decoder stream context handle!"); + return IMG_ERROR_INVALID_PARAMETERS; + } + VDEC_ASSERT(lst_empty(&dec_str_ctx->pend_strunit_list)); + + /* Destroy all pictures in the decoded list */ + decoded_pict = dq_first(&dec_str_ctx->str_decd_pict_list); + while (decoded_pict) { + ret = decoder_decoded_picture_destroy(dec_str_ctx, decoded_pict, TRUE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + decoded_pict = dq_first(&dec_str_ctx->str_decd_pict_list); + } + + /* if and only if the output buffers were used for reference. */ + if (dec_str_ctx->last_be_pict_dec_res) { + /* + * Clear the firmware context so that reference pictures + * are no longer referred to. + */ + memset(dec_str_ctx->last_be_pict_dec_res->fw_ctx_buf.cpu_virt, 0, + dec_str_ctx->last_be_pict_dec_res->fw_ctx_buf.buf_size); + } + + return IMG_SUCCESS; +} + +/* + * @Function decoder_stream_reference_resource_destroy + */ +static int decoder_stream_reference_resource_destroy(void *item, void *free_cb_param) +{ + struct dec_pictref_res *pict_ref_res = item; + struct dec_str_ctx *dec_str_ctx_local = + (struct dec_str_ctx *)free_cb_param; + int ret; + + VDEC_ASSERT(pict_ref_res); + VDEC_ASSERT(resource_item_isavailable(&pict_ref_res->ref_cnt)); + + /* Free memory (device-based) to store fw contexts for stream */ + ret = mmu_free_mem(dec_str_ctx_local->mmu_str_handle, &pict_ref_res->fw_ctrlbuf); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + kfree(pict_ref_res); + + return IMG_SUCCESS; +} + +/* + * @Function decoder_stream_destroy + */ +int decoder_stream_destroy(void *dec_str_context, unsigned char abort) +{ + struct dec_str_ctx *dec_str_ctx_local; + struct dec_str_unit *dec_str_unit_local; + struct dec_decoded_pict *decoded_pict_local; + unsigned int i; + int ret; + unsigned int pict_id; + void **res_handle_local; + + /* Required for getting segments from decode picture to free */ + struct dec_decpict_seg *dec_pict_seg_local; + struct dec_ctx *dec_context; + struct dec_core_ctx *dec_core_ctx_local; + + /* Get the Decoder stream context. */ + dec_str_ctx_local = decoder_stream_get_context(dec_str_context); + + VDEC_ASSERT(dec_str_ctx_local); + if (!dec_str_ctx_local) { + pr_err("Invalid decoder stream context handle!"); + return FALSE; + } + VDEC_ASSERT(dec_str_ctx_local->decctx); + + /* Decrement the stream count */ + dec_str_ctx_local->decctx->str_cnt--; + + /* + * Ensure that there are no pictures for this stream outstanding + * on any decoder cores. + * This should not be removed, it is important to see it if + * it ever happens. + * In practice we see it many times with Application Timeout. + */ + if (!abort) + VDEC_ASSERT(lst_empty(&dec_str_ctx_local->pend_strunit_list)); + + /* + * At this point all resources for the stream are guaranteed to + * not be used and no further hardware interrupts will be received. + */ + + /* Destroy all stream units submitted for processing. */ + dec_str_unit_local = + lst_removehead(&dec_str_ctx_local->pend_strunit_list); + while (dec_str_unit_local) { + /* If the unit was submitted for decoding (picture)... */ + if (dec_str_unit_local->dec_pict) { + /* + * Explicitly remove picture from core decode queue + * and destroy. + */ + struct dec_core_ctx *dec_core_ctx_local = + decoder_str_ctx_to_core_ctx(dec_str_ctx_local); + VDEC_ASSERT(dec_core_ctx_local); + + res_handle_local = &dec_str_ctx_local->resources; + + if (!dec_core_ctx_local) { + VDEC_ASSERT(0); + return -EINVAL; + } + + hwctrl_removefrom_piclist(dec_core_ctx_local->hw_ctx, + dec_str_unit_local->dec_pict); + + /* Free decoder picture */ + kfree(dec_str_unit_local->dec_pict->first_fld_fwmsg); + dec_str_unit_local->dec_pict->first_fld_fwmsg = NULL; + + kfree(dec_str_unit_local->dec_pict->second_fld_fwmsg); + dec_str_unit_local->dec_pict->second_fld_fwmsg = NULL; + + dec_res_picture_detach(res_handle_local, dec_str_unit_local->dec_pict); + + /* Free all the segments of the picture */ + dec_pict_seg_local = + lst_removehead(&dec_str_unit_local->dec_pict->dec_pict_seg_list); + while (dec_pict_seg_local) { + if (dec_pict_seg_local->internal_seg) { + VDEC_ASSERT(dec_pict_seg_local->bstr_seg); + kfree(dec_pict_seg_local->bstr_seg); + dec_pict_seg_local->bstr_seg = NULL; + } + + kfree(dec_pict_seg_local); + dec_pict_seg_local = NULL; + + dec_pict_seg_local = + lst_removehead + (&dec_str_unit_local->dec_pict->dec_pict_seg_list); + } + + VDEC_ASSERT(dec_str_unit_local->dec_pict->dec_str_ctx == dec_str_ctx_local); + + dec_str_ctx_local->dec_str_st.num_pict_decoding--; + pict_id = + GET_STREAM_PICTURE_ID(dec_str_unit_local->dec_pict->transaction_id); + + ret = decoder_picture_destroy(dec_str_ctx_local, pict_id, TRUE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + kfree(dec_str_unit_local->dec_pict); + dec_str_unit_local->dec_pict = NULL; + } + + /* Free the picture container */ + kfree(dec_str_unit_local); + dec_str_unit_local = NULL; + + dec_str_unit_local = lst_removehead(&dec_str_ctx_local->pend_strunit_list); + } + + /* Destroy all pictures in the decoded list */ + decoded_pict_local = dq_first(&dec_str_ctx_local->str_decd_pict_list); + while (decoded_pict_local) { + ret = decoder_decoded_picture_destroy(dec_str_ctx_local, + decoded_pict_local, + TRUE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + decoded_pict_local = dq_first(&dec_str_ctx_local->str_decd_pict_list); + } + + /* Ensure all picture queues are empty */ + VDEC_ASSERT(lst_empty(&dec_str_ctx_local->pend_strunit_list)); + VDEC_ASSERT(dq_empty(&dec_str_ctx_local->str_decd_pict_list)); + + /* Free memory to store stream context buffer. */ + ret = mmu_free_mem(dec_str_ctx_local->mmu_str_handle, + &dec_str_ctx_local->pvdec_fw_ctx_buf); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + /* Release any fw contexts held by stream. */ + if (dec_str_ctx_local->prev_fe_pict_dec_res) + resource_item_return(&dec_str_ctx_local->prev_fe_pict_dec_res->ref_cnt); + + if (dec_str_ctx_local->cur_fe_pict_dec_res) + resource_item_return(&dec_str_ctx_local->cur_fe_pict_dec_res->ref_cnt); + + if (dec_str_ctx_local->last_be_pict_dec_res) + resource_item_return(&dec_str_ctx_local->last_be_pict_dec_res->ref_cnt); + + /* + * Remove the device resources used for decoding and the two + * added to hold the last on front and back-end for stream. + */ + for (i = 0; i < dec_str_ctx_local->num_dec_res + 2; i++) { + ret = resource_list_empty(&dec_str_ctx_local->dec_res_lst, FALSE, + decoder_stream_decode_resource_destroy, + dec_str_ctx_local); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + VDEC_ASSERT(lst_empty(&dec_str_ctx_local->dec_res_lst)); + + /* Remove all stream decode resources. */ + ret = resource_list_empty(&dec_str_ctx_local->ref_res_lst, FALSE, + decoder_stream_reference_resource_destroy, + dec_str_ctx_local); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + VDEC_ASSERT(lst_empty(&dec_str_ctx_local->ref_res_lst)); + + idgen_destroycontext(dec_str_ctx_local->pict_idgen); + + dec_context = dec_str_ctx_local->decctx; + dec_core_ctx_local = decoder_str_ctx_to_core_ctx(dec_str_ctx_local); + + VDEC_ASSERT(dec_context); + VDEC_ASSERT(dec_core_ctx_local); + + res_handle_local = &dec_str_ctx_local->resources; + + if (*res_handle_local) { + ret = dec_res_destroy(dec_str_ctx_local->mmu_str_handle, *res_handle_local); + if (ret != IMG_SUCCESS) + pr_warn("resourceS_Destroy() failed to tidy-up after error"); + + *res_handle_local = NULL; + } + + lst_remove(&dec_str_ctx_local->decctx->str_list, dec_str_ctx_local); + + kfree(dec_str_ctx_local); + dec_str_ctx_local = NULL; + + pr_debug("%s successfully", __func__); + return IMG_SUCCESS; +} + +/* + * @Function decoder_init_avail_slots + */ +static int decoder_init_avail_slots(struct dec_str_ctx *dec_str_context) +{ + VDEC_ASSERT(dec_str_context); + + switch (dec_str_context->config.vid_std) { + case VDEC_STD_H264: + /* + * only first pipe can be master when decoding H264 in + * multipipe mode (FW restriction) + */ + dec_str_context->avail_slots = + dec_str_context->decctx->dev_cfg->num_slots_per_pipe * + dec_str_context->decctx->num_pipes; + break; + + default: + /* all pipes by default */ + dec_str_context->avail_slots = + dec_str_context->decctx->dev_cfg->num_slots_per_pipe; + break; + } + + return IMG_SUCCESS; +} + +/* + * @Function decoder_stream_decode_resource_create + */ +static int decoder_stream_decode_resource_create(struct dec_str_ctx *dec_str_context) +{ + struct dec_pictdec_res *pict_dec_res; + int ret; + unsigned int mem_heap_id; + enum sys_emem_attrib mem_attribs; + + unsigned char fw_ctx_buf = FALSE; + + /* Validate input arguments */ + if (!dec_str_context || !dec_str_context->decctx || + !dec_str_context->decctx->dev_cfg) { + VDEC_ASSERT(0); + return -EINVAL; + } + + mem_heap_id = dec_str_context->decctx->internal_heap_id; + mem_attribs = (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE); + mem_attribs |= (enum sys_emem_attrib)SYS_MEMATTRIB_INTERNAL; + + /* Allocate the firmware context buffer info structure. */ + pict_dec_res = kzalloc(sizeof(*pict_dec_res), GFP_KERNEL); + VDEC_ASSERT(pict_dec_res); + if (!pict_dec_res) + return IMG_ERROR_OUT_OF_MEMORY; + + /* + * Allocate the firmware context buffer to contain + * data required for subsequent picture. + */ +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s:%d calling MMU_StreamMalloc", __func__, __LINE__); +#endif + + ret = mmu_stream_alloc(dec_str_context->mmu_str_handle, + MMU_HEAP_STREAM_BUFFERS, mem_heap_id, + (enum sys_emem_attrib)(mem_attribs | SYS_MEMATTRIB_CPU_READ | + SYS_MEMATTRIB_CPU_WRITE), + sizeof(union dec_fw_contexts), + DEV_MMU_PAGE_ALIGNMENT, + &pict_dec_res->fw_ctx_buf); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto err_out_of_memory; + + fw_ctx_buf = TRUE; + + /* + * Clear the context data in preparation for first time + * use by the firmware. + */ + memset(pict_dec_res->fw_ctx_buf.cpu_virt, 0, pict_dec_res->fw_ctx_buf.buf_size); + + switch (dec_str_context->config.vid_std) { + case VDEC_STD_H264: + /* Allocate the SGM buffer */ +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s:%d calling MMU_StreamMalloc", __func__, __LINE__); +#endif + ret = mmu_stream_alloc + (dec_str_context->mmu_str_handle, + MMU_HEAP_STREAM_BUFFERS, mem_heap_id, + (enum sys_emem_attrib)(mem_attribs | SYS_MEMATTRIB_CPU_WRITE), + H264_SGM_BUFFER_BYTES_PER_MB * + H264_SGM_MAX_MBS, + DEV_MMU_PAGE_ALIGNMENT, + &pict_dec_res->h264_sgm_buf); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto err_out_of_memory; + + /* Clear the SGM data. */ + memset(pict_dec_res->h264_sgm_buf.cpu_virt, 0, pict_dec_res->h264_sgm_buf.buf_size); + break; + + default: + break; + } + + pict_dec_res->ref_cnt = 1; + + ret = resource_list_add_img(&dec_str_context->dec_res_lst, pict_dec_res, 0, + &pict_dec_res->ref_cnt); + + if (ret != IMG_SUCCESS) { + pr_warn("[USERSID=0x%08X] Failed to add resource", + dec_str_context->config.user_str_id); + } + + return IMG_SUCCESS; + +err_out_of_memory: + if (pict_dec_res) { + if (fw_ctx_buf) + mmu_free_mem(dec_str_context->mmu_str_handle, &pict_dec_res->fw_ctx_buf); + + kfree(pict_dec_res); + pict_dec_res = NULL; + } + + pr_err("[USERSID=0x%08X] Failed to allocate device memory for stream decode resources", + dec_str_context->config.user_str_id); + + return IMG_ERROR_OUT_OF_MEMORY; +} + +/* + * @Function decoder_stream_create + */ +int decoder_stream_create(void *dec_ctx_arg, + struct vdec_str_configdata str_cfg, + unsigned int km_str_id, void **mmu_str_handle, + void *vxd_dec_ctx, void *str_user_int_data, + void **dec_str_ctx_arg, void *decoder_cb, + void *query_cb) +{ + struct dec_ctx *dec_context = (struct dec_ctx *)dec_ctx_arg; + struct dec_str_ctx *dec_str_ctx = NULL; + unsigned int i; + int ret; + unsigned int mem_heap_id; + enum sys_emem_attrib mem_attribs; + struct dec_core_ctx *dec_core_ctx_local; + + /* Check input parameters. */ + VDEC_ASSERT(dec_ctx_arg); + if (!dec_ctx_arg) { + pr_err("Invalid parameters!"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (dec_context->str_cnt >= MAX_CONCURRENT_STREAMS) { + pr_err("Device has too many concurrent streams. Number of Concurrent streams allowed: %d.", + MAX_CONCURRENT_STREAMS); + return IMG_ERROR_DEVICE_UNAVAILABLE; + } + + mem_heap_id = dec_context->internal_heap_id; + mem_attribs = (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE); + mem_attribs |= (enum sys_emem_attrib)SYS_MEMATTRIB_INTERNAL; + + /* Allocate Decoder Stream Context */ + dec_str_ctx = kzalloc(sizeof(*dec_str_ctx), GFP_KERNEL); + VDEC_ASSERT(dec_str_ctx); + if (!dec_str_ctx) + return IMG_ERROR_OUT_OF_MEMORY; + + /* Increment the stream counter */ + dec_context->str_cnt++; + + /* + * Initialise the context structure to NULL. Any non-zero + * default values should be set at this point. + */ + dec_str_ctx->config = str_cfg; + dec_str_ctx->vxd_dec_ctx = vxd_dec_ctx; + dec_str_ctx->usr_int_data = str_user_int_data; + dec_str_ctx->decctx = dec_context; + + decoder_init_avail_slots(dec_str_ctx); + + dec_str_ctx->next_dec_pict_id = 1; + dec_str_ctx->next_pict_id_expected = 1; + + dec_str_ctx->km_str_id = km_str_id; + VDEC_ASSERT(dec_str_ctx->km_str_id > 0); + + lst_init(&dec_str_ctx->pend_strunit_list); + dq_init(&dec_str_ctx->str_decd_pict_list); + lst_init(&dec_str_ctx->ref_res_lst); + lst_init(&dec_str_ctx->dec_res_lst); + + ret = idgen_createcontext(DECODER_MAX_PICT_ID + 1, + DECODER_MAX_CONCURRENT_PICT, + TRUE, + &dec_str_ctx->pict_idgen); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + /* Create an MMU context for this stream. */ + ret = mmu_stream_create(dec_context->mmu_dev_handle, + dec_str_ctx->km_str_id, + dec_str_ctx->vxd_dec_ctx, + &dec_str_ctx->mmu_str_handle); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + dec_core_ctx_local = dec_context->dec_core_ctx; + + VDEC_ASSERT(dec_core_ctx_local); + + /* Create core resources */ + ret = dec_res_create(dec_str_ctx->mmu_str_handle, + &dec_core_ctx_local->core_props, + dec_context->dev_cfg->num_slots_per_pipe * + dec_context->num_pipes, + dec_context->internal_heap_id, + &dec_str_ctx->resources); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + /* Allocate the PVDEC firmware context buffer */ +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s:%d calling MMU_StreamMalloc", __func__, __LINE__); +#endif + ret = mmu_stream_alloc(dec_str_ctx->mmu_str_handle, MMU_HEAP_STREAM_BUFFERS, + mem_heap_id, + (enum sys_emem_attrib)(mem_attribs | SYS_MEMATTRIB_CPU_WRITE), + CONTEXT_BUFF_SIZE, + DEV_MMU_PAGE_ALIGNMENT, + &dec_str_ctx->pvdec_fw_ctx_buf); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + /* + * Clear the context data in preparation for + * first time use by the firmware. + */ + memset(dec_str_ctx->pvdec_fw_ctx_buf.cpu_virt, 0, dec_str_ctx->pvdec_fw_ctx_buf.buf_size); + + /* + * Create enough device resources to hold last context on + * front and back-end for stream. + */ + dec_str_ctx->num_dec_res = + dec_str_ctx->decctx->dev_cfg->num_slots_per_pipe * + dec_str_ctx->decctx->num_pipes; + for (i = 0; i < dec_str_ctx->num_dec_res + 2; i++) { + ret = decoder_stream_decode_resource_create(dec_str_ctx); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + } + + dec_str_ctx->str_processed_cb = (strunit_processed_cb)decoder_cb; + + dec_str_ctx->core_query_cb = (core_gen_cb)query_cb; + + lst_add(&dec_context->str_list, dec_str_ctx); + + *dec_str_ctx_arg = (void *)dec_str_ctx; + *mmu_str_handle = dec_str_ctx->mmu_str_handle; + + return IMG_SUCCESS; + + /* Roll back in case of errors. */ +error: + decoder_stream_destroy((void *)dec_str_ctx, FALSE); + + return ret; +} + +/* + * @Function decoder_get_decoded_pict + */ +static struct dec_decoded_pict *decoder_get_decoded_pict(unsigned int transaction_id, + struct dq_linkage_t *dq_list) +{ + struct dec_decoded_pict *decoded_pict; + void *item = NULL; + + VDEC_ASSERT(dq_list); + + decoded_pict = dq_first(dq_list); + while (decoded_pict) { + if (decoded_pict->transaction_id == transaction_id) { + item = decoded_pict; + break; + } + + if (decoded_pict != dq_last(dq_list)) + decoded_pict = dq_next(decoded_pict); + else + decoded_pict = NULL; + } + + return item; +} + +/* + * @Function decoder_get_decoded_pict_of_stream + */ +static struct dec_decoded_pict *decoder_get_decoded_pict_of_stream(unsigned int pict_id, + struct dq_linkage_t *dq_list) +{ + struct dec_decoded_pict *decoded_pict; + void *item = NULL; + + VDEC_ASSERT(dq_list); + + decoded_pict = dq_first(dq_list); + while (decoded_pict) { + if (GET_STREAM_PICTURE_ID(decoded_pict->transaction_id) == pict_id) { + item = decoded_pict; + break; + } + + if (decoded_pict != dq_last(dq_list)) + decoded_pict = dq_next(decoded_pict); + else + decoded_pict = NULL; + } + return item; +} + +/* + * @Function decoder_get_next_decpict_contiguous + */ +static struct +dec_decoded_pict *decoder_get_next_decpict_contiguous(struct dec_decoded_pict *decoded_pict, + unsigned int next_dec_pict_id, + struct dq_linkage_t *str_decoded_pict_list) +{ + struct dec_decoded_pict *next_dec_pict = NULL; + struct dec_decoded_pict *result_dec_pict = NULL; + + VDEC_ASSERT(str_decoded_pict_list); + if (!str_decoded_pict_list) { + pr_err("Invalid parameter"); + return NULL; + } + + if (decoded_pict) { + if (decoded_pict != dq_last(str_decoded_pict_list)) { + next_dec_pict = dq_next(decoded_pict); + if (!next_dec_pict) { + VDEC_ASSERT(0); + return NULL; + } + + if (next_dec_pict->pict) { + /* + * If we have no holes in the decoded list + * (i.e. next decoded picture is next in + * bitstream decode order). + */ + if (HAS_X_REACHED_Y(next_dec_pict_id, next_dec_pict->pict->pict_id, + 1 << FWIF_NUMBITS_STREAM_PICTURE_ID, + unsigned int)) { + result_dec_pict = next_dec_pict; + } + } + } + } + + return result_dec_pict; +} + +/* + * @Function decoder_next_picture + * @Description + * Returns the next unprocessed picture or NULL if the next picture is not + * next in bitstream decode order or there are no more decoded pictures in the + * list. + + * @Input psCurrentDecodedPicture : Pointer to current decoded picture. + + * @Input ui32NextDecPictId : Picture ID of next picture in decode + * order. + + * @Input psStrDecdPictList : Pointer to decoded picture list. + + * @Return DECODER_sDecodedPict * : Pointer to next decoded picture to + * process. + */ +static struct dec_decoded_pict *decoder_next_picture(struct dec_decoded_pict *cur_decoded_pict, + unsigned int next_dec_pict_d, + struct dq_linkage_t *str_decodec_pict_list) +{ + struct dec_decoded_pict *ret = NULL; + + VDEC_ASSERT(str_decodec_pict_list); + if (!str_decodec_pict_list) + return NULL; + + if (!cur_decoded_pict) + cur_decoded_pict = dq_first(str_decodec_pict_list); + + if (cur_decoded_pict && !cur_decoded_pict->process_failed) { + /* Search for picture ID greater than picture in list */ + do { + if (!cur_decoded_pict->processed) { + /* + * Return the current one because it has not + * been processed + */ + ret = cur_decoded_pict; + break; + } + /* + * Obtain a pointer to the next picture in bitstream + * decode order. + */ + cur_decoded_pict = decoder_get_next_decpict_contiguous + (cur_decoded_pict, + next_dec_pict_d, + str_decodec_pict_list); + } while (cur_decoded_pict && + !cur_decoded_pict->process_failed); + } + return ret; +} + +/* + * @Function decoder_picture_display + */ +static int decoder_picture_display(struct dec_str_ctx *dec_str_ctx, + unsigned int pict_id, unsigned char last) +{ + struct vdecdd_picture *picture; + int ret; + static unsigned int display_num; + + VDEC_ASSERT(dec_str_ctx); + + ret = idgen_gethandle(dec_str_ctx->pict_idgen, pict_id, (void **)&picture); + if (ret == IMG_SUCCESS) { + struct vdecdd_ddbuf_mapinfo *pict_buf; + + /* validate pointers */ + if (!picture || !picture->dec_pict_info) { + VDEC_ASSERT(0); + return -EIO; + } + + pict_buf = picture->disp_pict_buf.pict_buf; + VDEC_ASSERT(pict_buf); + + /* + * Indicate whether there are more pictures + * coming for display. + */ + picture->dec_pict_info->last_in_seq = last; + + /* Set decode order id */ + picture->dec_pict_info->decode_id = pict_id; + + /* Return the picture to the client for display */ + dec_str_ctx->dec_str_st.total_pict_displayed++; + resource_item_use(&pict_buf->ddbuf_info.ref_count); + display_num++; +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] DISPLAY(%d): PIC_ID[%d]", + dec_str_ctx->config.user_str_id, display_num, pict_id); +#endif + + VDEC_ASSERT(dec_str_ctx->decctx); + ret = dec_str_ctx->str_processed_cb(dec_str_ctx->usr_int_data, + VXD_CB_PICT_DISPLAY, + picture); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + /* + * All handles will be freed after actually + * displaying the picture. + * Reset them to NULL here to avoid any confusion. + */ + memset(&picture->dec_pict_sup_data, 0, sizeof(picture->dec_pict_sup_data)); + } else { + pr_warn("[USERSID=0x%08X] ERROR: DISPLAY PICTURE HAS AN EXPIRED ID", + dec_str_ctx->config.user_str_id); + VDEC_ASSERT(ret == IMG_SUCCESS); + } + + return IMG_SUCCESS; +} + +#ifdef ERROR_CONCEALMENT +/* + * @Function decoder_get_pict_processing_info + */ +static unsigned char decoder_get_pict_processing_info(struct dec_core_ctx *dec_corectx, + struct dec_str_ctx *dec_strctx, + struct bspp_pict_hdr_info *pict_hdr_info, + struct dec_decoded_pict *decoded_pict, + struct dec_decpict *dec_pict, + unsigned int *pict_last_mb) +{ + int ret = IMG_SUCCESS; + unsigned char pipe_minus1; + struct hwctrl_state last_state; + unsigned int width_in_mb; + unsigned int height_in_mb; + unsigned int i; + + memset(&last_state, 0, sizeof(last_state)); + + VDEC_ASSERT(pict_hdr_info); + width_in_mb = (pict_hdr_info->coded_frame_size.width + + (VDEC_MB_DIMENSION - 1)) / VDEC_MB_DIMENSION; + height_in_mb = (pict_hdr_info->coded_frame_size.height + + (VDEC_MB_DIMENSION - 1)) / VDEC_MB_DIMENSION; + + VDEC_ASSERT(pict_last_mb); + *pict_last_mb = width_in_mb * height_in_mb; + VDEC_ASSERT(decoded_pict); + + if (decoded_pict->first_fld_fwmsg->pict_attrs.pict_attrs.dwrfired || + decoded_pict->second_fld_fwmsg->pict_attrs.pict_attrs.dwrfired || + decoded_pict->first_fld_fwmsg->pict_attrs.pict_attrs.mmufault || + decoded_pict->second_fld_fwmsg->pict_attrs.pict_attrs.mmufault) { + struct dec_pict_attrs *pict_attrs = &decoded_pict->first_fld_fwmsg->pict_attrs; + unsigned char be_found = FALSE; + unsigned int mbs_dropped = 0; + unsigned int mbs_recovered = 0; + unsigned int no_be_wdt = 0; + unsigned int max_y = 0; + unsigned int row_drop = 0; + + VDEC_ASSERT(dec_corectx); + /* Obtain the last available core status - + * cached before clocks where switched off + */ + ret = hwctrl_getcore_cached_status(dec_corectx->hw_ctx, &last_state); + if (ret != IMG_SUCCESS) + return FALSE; + + /* Try to determine pipe where the last picture was decoded on (BE) */ + for (pipe_minus1 = 0; pipe_minus1 < VDEC_MAX_PIXEL_PIPES; pipe_minus1++) { + for (i = VDECFW_CHECKPOINT_BE_END; i >= VDECFW_CHECKPOINT_BE_START; i--) { + struct vxd_pipestate *pipe_state = + &last_state.core_state.fw_state.pipe_state[pipe_minus1]; + + if (!pipe_state->is_pipe_present) + continue; + + if (pipe_state->acheck_point[i] == decoded_pict->transaction_id) { + row_drop += width_in_mb - pipe_state->be_mb.x; + if (pipe_state->be_mb.y > max_y) + max_y = pipe_state->be_mb.y; + + if (pipe_state->be_mbs_dropped > mbs_dropped) + mbs_dropped = pipe_state->be_mbs_dropped; + + if (pipe_state->be_mbs_recovered > mbs_recovered) + mbs_recovered = pipe_state->be_mbs_recovered; + + no_be_wdt += pipe_state->be_errored_slices; + be_found = TRUE; + } + } + if (be_found) + /* No need to check FE as we already have an info from BE */ + continue; + + /* If not found, we probbaly stuck on FE ? */ + for (i = VDECFW_CHECKPOINT_FE_END; i >= VDECFW_CHECKPOINT_FE_START; i--) { + struct vxd_pipestate *pipe_state = + &last_state.core_state.fw_state.pipe_state[pipe_minus1]; + + if (!pipe_state->is_pipe_present) + continue; + + if (pipe_state->acheck_point[i] == decoded_pict->transaction_id) { + /* Mark all MBs as dropped */ + pict_attrs->mbs_dropped = *pict_last_mb; + pict_attrs->mbs_recovered = 0; + return TRUE; + } + } + } + + if (be_found) { + /* Calculate last macroblock number processed on BE */ + unsigned int num_mb_processed = (max_y * width_in_mb) - row_drop; + + /* Sanity check, as HW may signal MbYX position + * beyond picture for corrupted streams + */ + if (num_mb_processed > (*pict_last_mb)) + num_mb_processed = (*pict_last_mb); /* trim */ + + if (((*pict_last_mb) - num_mb_processed) > mbs_dropped) + mbs_dropped = (*pict_last_mb) - num_mb_processed; + + pict_attrs->mbs_dropped = mbs_dropped; + pict_attrs->mbs_recovered = num_mb_processed; + pict_attrs->no_be_wdt = no_be_wdt; + return TRUE; + } + return FALSE; + } + /* Picture was decoded without DWR, so we have already the required info */ + return TRUE; +} +#endif + +/* + * @Function decoder_picture_release + */ +static int decoder_picture_release(struct dec_str_ctx *dec_str_ctx, + unsigned int pict_id, + unsigned char displayed, + unsigned char merged) +{ + struct vdecdd_picture *picture; + int ret; + + /* validate input arguments */ + if (!dec_str_ctx) { + VDEC_ASSERT(0); + return -EINVAL; + } + + ret = idgen_gethandle(dec_str_ctx->pict_idgen, pict_id, (void **)&picture); + if (ret == IMG_SUCCESS) { + if (!picture || !picture->dec_pict_info) { + VDEC_ASSERT(0); + return -EINVAL; + } + + /* Set decode order id */ + picture->dec_pict_info->decode_id = pict_id; + + VDEC_ASSERT(dec_str_ctx->decctx); + + pr_debug("Decoder picture released pict_id = %d\n", pict_id); + ret = dec_str_ctx->str_processed_cb(dec_str_ctx->usr_int_data, + VXD_CB_PICT_RELEASE, + picture); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + /* + * All handles will be freed after actually displaying + * the picture. Reset them to NULL here to avoid any + * confusion. + */ + memset(&picture->dec_pict_sup_data, 0, sizeof(picture->dec_pict_sup_data)); + } else { + pr_err("[USERSID=0x%08X] ERROR: RELEASE PICTURE HAS AN EXPIRED ID", + dec_str_ctx->config.user_str_id); + VDEC_ASSERT(ret == IMG_SUCCESS); + } + + return IMG_SUCCESS; +} + +/* + * @Function decoder_stream_flush_process_dpb_h264 + */ +static int +decoder_stream_flush_process_dpb_h264(struct dec_str_ctx *dec_str_ctx, + struct dec_decoded_pict *decoded_pict, + unsigned char discard_refs) +{ + int ret; + + struct h264fw_context_data *ctx_data = + (struct h264fw_context_data *)dec_str_ctx->last_be_pict_dec_res->fw_ctx_buf.cpu_virt; + unsigned char found = TRUE; + unsigned int i; + int min_cnt; + int min_cnt_idx; + unsigned int num_display_pics = 0; + unsigned int num_pics_displayed = 0; + struct dec_decoded_pict *display_pict = NULL; + unsigned int last_disp_pict_tid; + unsigned int pict_id; + + /* Determine how many display pictures reside in the DPB */ + if (ctx_data->dpb_size > H264FW_MAX_DPB_SIZE || ctx_data->dpb_size <= 0) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] Incorrect DPB size: %d", + dec_str_ctx->config.user_str_id, ctx_data->dpb_size); +#endif + ctx_data->dpb_size = H264FW_MAX_DPB_SIZE; + } + for (i = 0; i < ctx_data->dpb_size; i++) { + if (ctx_data->dpb[i].transaction_id) + if (ctx_data->dpb[i].needed_for_output) + num_display_pics++; + } + + last_disp_pict_tid = ctx_data->last_displayed_pic_data[0].transaction_id; + /* Check for picture stuck outside the dpb */ + if (last_disp_pict_tid) { + VDEC_ASSERT(last_disp_pict_tid != 0xffffffff); + + display_pict = decoder_get_decoded_pict(last_disp_pict_tid, + &dec_str_ctx->str_decd_pict_list); + + if (display_pict && display_pict->pict && + display_pict->pict->dec_pict_info) { + if (FLAG_IS_SET(ctx_data->prev_display_flags, + VDECFW_BUFFLAG_DISPLAY_FIELD_CODED)) { + if (!FLAG_IS_SET(ctx_data->prev_display_flags, + VDECFW_BUFFLAG_DISPLAY_SINGLE_FIELD)) + display_pict->pict->dec_pict_info->buf_type = + IMG_BUFFERTYPE_PAIR; + else + display_pict->pict->dec_pict_info->buf_type = + FLAG_IS_SET + (ctx_data->prev_display_flags, + VDECFW_BUFFLAG_DISPLAY_BOTTOM_FIELD) ? + IMG_BUFFERTYPE_FIELD_BOTTOM : + IMG_BUFFERTYPE_FIELD_TOP; + } else { + display_pict->pict->dec_pict_info->buf_type = + IMG_BUFFERTYPE_FRAME; + } + } else { + VDEC_ASSERT(display_pict); + VDEC_ASSERT(display_pict && display_pict->pict); + VDEC_ASSERT(display_pict && display_pict->pict && + display_pict->pict->dec_pict_info); + } + + if (display_pict && !display_pict->displayed) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] [TID=0x%08X] DISPLAY", + dec_str_ctx->config.user_str_id, + last_disp_pict_tid); +#endif + display_pict->displayed = TRUE; + ret = decoder_picture_display + (dec_str_ctx, GET_STREAM_PICTURE_ID(last_disp_pict_tid), + TRUE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + } + + while (found) { + min_cnt = ((unsigned int)(1 << 31)) - 1; + min_cnt_idx = -1; + found = FALSE; + + /* Loop over the DPB to find the first in order */ + for (i = 0; i < ctx_data->dpb_size; i++) { + if (ctx_data->dpb[i].transaction_id && + (ctx_data->dpb[i].needed_for_output || + discard_refs)) { + if (ctx_data->dpb[i].top_field_order_count < + min_cnt) { + min_cnt = + ctx_data->dpb[i].top_field_order_count; + min_cnt_idx = i; + found = TRUE; + } + } + } + + if (found) { + unsigned int umin_cnt_tid = ctx_data->dpb[min_cnt_idx].transaction_id; + + if (ctx_data->dpb[min_cnt_idx].needed_for_output) { + VDEC_ASSERT(umin_cnt_tid != 0xffffffff); + display_pict = + decoder_get_decoded_pict(umin_cnt_tid, + &dec_str_ctx->str_decd_pict_list); + + if ((display_pict && display_pict->pict && + display_pict->pict->dec_pict_info) && + FLAG_IS_SET(ctx_data->dpb[min_cnt_idx].display_flags, + VDECFW_BUFFLAG_DISPLAY_FIELD_CODED)) { + if (!FLAG_IS_SET(ctx_data->dpb[min_cnt_idx].display_flags, + VDECFW_BUFFLAG_DISPLAY_SINGLE_FIELD)) + display_pict->pict->dec_pict_info->buf_type = + IMG_BUFFERTYPE_PAIR; + else + display_pict->pict->dec_pict_info->buf_type = + FLAG_IS_SET + (ctx_data->dpb + [min_cnt_idx].display_flags, + VDECFW_BUFFLAG_DISPLAY_BOTTOM_FIELD) + ? + IMG_BUFFERTYPE_FIELD_BOTTOM : + IMG_BUFFERTYPE_FIELD_TOP; + display_pict->pict->dec_pict_info->view_id = + ctx_data->dpb[min_cnt_idx].view_id; + } else if ((display_pict && display_pict->pict && + display_pict->pict->dec_pict_info) && + (!FLAG_IS_SET(ctx_data->dpb[min_cnt_idx].display_flags, + VDECFW_BUFFLAG_DISPLAY_FIELD_CODED))){ + display_pict->pict->dec_pict_info->buf_type = + IMG_BUFFERTYPE_FRAME; + display_pict->pict->dec_pict_info->view_id = + ctx_data->dpb[min_cnt_idx].view_id; + } else { + VDEC_ASSERT(display_pict); + VDEC_ASSERT(display_pict && display_pict->pict); + VDEC_ASSERT(display_pict && display_pict->pict && + display_pict->pict->dec_pict_info); + } + + if (display_pict && !display_pict->displayed) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] [TID=0x%08X] DISPLAY", + dec_str_ctx->config.user_str_id, + umin_cnt_tid); +#endif + display_pict->displayed = TRUE; + num_pics_displayed++; + ret = decoder_picture_display + (dec_str_ctx, + GET_STREAM_PICTURE_ID(umin_cnt_tid), + num_pics_displayed == num_display_pics ? + TRUE : FALSE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + ctx_data->dpb[min_cnt_idx].needed_for_output = FALSE; + } + + if (discard_refs) { + decoded_pict = + decoder_get_decoded_pict(umin_cnt_tid, + &dec_str_ctx->str_decd_pict_list); + if (decoded_pict) { + /* Signal releasing this picture to upper layers. */ + pict_id = + GET_STREAM_PICTURE_ID(decoded_pict->transaction_id); + decoder_picture_release(dec_str_ctx, + pict_id, + decoded_pict->displayed, + decoded_pict->merged); + /* Destroy the decoded picture. */ + ret = decoder_decoded_picture_destroy(dec_str_ctx, + decoded_pict, FALSE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + ctx_data->dpb[min_cnt_idx].transaction_id = 0; + } + } + } + + VDEC_ASSERT(num_pics_displayed == num_display_pics); + + return IMG_SUCCESS; +} + +#ifdef HAS_HEVC +/* + * decoder_StreamFlushProcessDPB_HEVC + */ +static int decoder_stream_flush_process_dpb_hevc(struct dec_str_ctx *decstr_ctx, + struct dec_decoded_pict *decoded_pict, + unsigned char discard_refs) +{ + int result; + struct hevcfw_ctx_data *ctx = + (struct hevcfw_ctx_data *)decstr_ctx->last_be_pict_dec_res->fw_ctx_buf.cpu_virt; + struct hevcfw_decoded_picture_buffer *dpb; + unsigned char found = TRUE; + unsigned char idx; + int min_poc_val; + signed char dpb_idx; + unsigned char num_display_pics = 0; + unsigned char num_pics_displayed = 0; + struct dec_decoded_pict *display_pict = NULL; + + /* + * Update the fw context for analysing the dpb in order + * to display or release any outstanding picture + */ + dpb = &ctx->dpb; + + /* Determine how many display pictures reside in the DPB. */ + for (idx = 0; idx < HEVCFW_MAX_DPB_SIZE; ++idx) { + struct hevcfw_picture_in_dpb *dpb_pic = &dpb->pictures[idx]; + + if (dpb_pic->valid && dpb_pic->needed_for_output) + ++num_display_pics; + } + + while (found) { + struct hevcfw_picture_in_dpb *dpb_pic; + + min_poc_val = 0x7fffffff; + dpb_idx = HEVCFW_DPB_IDX_INVALID; + found = FALSE; + + /* Loop over the DPB to find the first in order */ + for (idx = 0; idx < HEVCFW_MAX_DPB_SIZE; ++idx) { + dpb_pic = &dpb->pictures[idx]; + if (dpb_pic->valid && (dpb_pic->needed_for_output || discard_refs)) { + if (dpb_pic->picture.pic_order_cnt_val < min_poc_val) { + min_poc_val = dpb_pic->picture.pic_order_cnt_val; + dpb_idx = idx; + found = TRUE; + } + } + } + + if (!found) + break; + + dpb_pic = &dpb->pictures[dpb_idx]; + + if (dpb_pic->needed_for_output) { + unsigned int str_pic_id = GET_STREAM_PICTURE_ID + (dpb_pic->picture.transaction_id); + + VDEC_ASSERT(dpb_pic->picture.transaction_id != 0xffffffff); + display_pict = decoder_get_decoded_pict(dpb_pic->picture.transaction_id, + &decstr_ctx->str_decd_pict_list); + + if (display_pict && display_pict->pict && + display_pict->pict->dec_pict_info) { + display_pict->pict->dec_pict_info->buf_type = IMG_BUFFERTYPE_FRAME; + } else { + VDEC_ASSERT(display_pict); + VDEC_ASSERT(display_pict && display_pict->pict); + VDEC_ASSERT(display_pict && display_pict->pict && + display_pict->pict->dec_pict_info); + + dpb_pic->valid = FALSE; + continue; + } + + if (!display_pict->displayed) { + display_pict->displayed = TRUE; + ++num_pics_displayed; + result = decoder_picture_display(decstr_ctx, str_pic_id, + num_pics_displayed == + num_display_pics); + VDEC_ASSERT(result == IMG_SUCCESS); + if (result != IMG_SUCCESS) + return result; + } + dpb_pic->needed_for_output = FALSE; + } + + if (discard_refs) { + decoded_pict = decoder_get_decoded_pict(dpb_pic->picture.transaction_id, + &decstr_ctx->str_decd_pict_list); + + if (decoded_pict) { + /* Signal releasing this picture to upper layers. */ + decoder_picture_release(decstr_ctx, + GET_STREAM_PICTURE_ID + (decoded_pict->transaction_id), + decoded_pict->displayed, + decoded_pict->merged); + /* Destroy the decoded picture. */ + result = decoder_decoded_picture_destroy(decstr_ctx, decoded_pict, + FALSE); + VDEC_ASSERT(result == IMG_SUCCESS); + if (result != IMG_SUCCESS) + return result; + } + dpb_pic->valid = FALSE; + } + } + + VDEC_ASSERT(num_pics_displayed == num_display_pics); + + return IMG_SUCCESS; +} +#endif + +/* + * @Function decoder_stream_flush_process_dpb + * @Description + * Process DPB fetched from firmware, display and release relevant pictures. + */ +static int decoder_stream_flush_process_dpb(struct dec_str_ctx *dec_str_ctx, + struct dec_decoded_pict *decoded_pict, + unsigned char discard_refs) +{ + int ret = 0; + /* Get oldest reference to display. */ + decoded_pict = dq_last(&dec_str_ctx->str_decd_pict_list); + if (decoded_pict) { + switch (dec_str_ctx->config.vid_std) { + case VDEC_STD_H264: + ret = decoder_stream_flush_process_dpb_h264(dec_str_ctx, decoded_pict, + discard_refs); + + break; +#ifdef HAS_HEVC + case VDEC_STD_HEVC: + decoder_stream_flush_process_dpb_hevc(dec_str_ctx, + decoded_pict, discard_refs); +#endif + break; + + default: + break; + } + } + + return ret; +} + +int decoder_stream_flush(void *dec_str_ctx_arg, unsigned char discard_refs) +{ + struct dec_str_ctx *dec_str_ctx; + struct dec_str_unit *dec_str_unit; + struct dec_decoded_pict *decoded_pict; + int ret = 0; + + dec_str_ctx = decoder_stream_get_context(dec_str_ctx_arg); + VDEC_ASSERT(dec_str_ctx); + if (!dec_str_ctx) { + pr_err("Invalid decoder stream context handle!"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* + * Since the stream should be stopped before flushing + * there should be no pictures in the stream list. + */ + dec_str_unit = lst_first(&dec_str_ctx->pend_strunit_list); + while (dec_str_unit) { + VDEC_ASSERT(dec_str_unit->str_unit->str_unit_type != + VDECDD_STRUNIT_PICTURE_START); + dec_str_unit = lst_next(dec_str_unit); + } + + decoded_pict = dq_last(&dec_str_ctx->str_decd_pict_list); + + ret = decoder_stream_flush_process_dpb(dec_str_ctx, decoded_pict, + discard_refs); + if (ret != IMG_SUCCESS) + return ret; + + if (discard_refs) { + while (!dq_empty(&dec_str_ctx->str_decd_pict_list)) { + struct dec_decoded_pict *non_decoded_pict = + dq_first(&dec_str_ctx->str_decd_pict_list); + + if (!non_decoded_pict) { + VDEC_ASSERT(0); + return -EINVAL; + } + +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] Decoded picture list contains item ID:0x%08x when DPB is empty", + dec_str_ctx->config.user_str_id, + non_decoded_pict->transaction_id); +#endif + + /* release the buffers back to vxd_decoder */ + decoder_picture_release(dec_str_ctx, GET_STREAM_PICTURE_ID + (non_decoded_pict->transaction_id), FALSE, + FALSE); + + ret = decoder_decoded_picture_destroy(dec_str_ctx, non_decoded_pict, FALSE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + VDEC_ASSERT(dq_empty(&dec_str_ctx->str_decd_pict_list)); + + if (dec_str_ctx->last_be_pict_dec_res) + /* + * Clear the firmware context so that reference + * pictures are no longer referred to. + */ + memset(dec_str_ctx->last_be_pict_dec_res->fw_ctx_buf.cpu_virt, 0, + dec_str_ctx->last_be_pict_dec_res->fw_ctx_buf.buf_size); + } + + pr_debug("Decoder stream flushed successfully\n"); + return IMG_SUCCESS; +} + +/* + * @Function decoder_stream_prepare_ctx + */ +int decoder_stream_prepare_ctx(void *dec_str_ctx_arg, unsigned char flush_dpb) +{ + struct dec_str_ctx *dec_str_ctx = + decoder_stream_get_context(dec_str_ctx_arg); + int ret; + + VDEC_ASSERT(dec_str_ctx); + if (!dec_str_ctx) + return IMG_ERROR_INVALID_PARAMETERS; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] [TID=0x%08X] Preparing stream context after seek", + dec_str_ctx->config.user_str_id, + dec_str_ctx->last_fe_transaction_id); +#endif + + if (flush_dpb) { + ret = decoder_stream_flush(dec_str_ctx, TRUE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + + /* Reset front-end temporary pointers */ + if (dec_str_ctx->prev_fe_pict_dec_res) { + resource_item_return(&dec_str_ctx->prev_fe_pict_dec_res->ref_cnt); + dec_str_ctx->prev_fe_pict_dec_res = NULL; + } + if (dec_str_ctx->cur_fe_pict_dec_res) { + resource_item_return(&dec_str_ctx->cur_fe_pict_dec_res->ref_cnt); + dec_str_ctx->cur_fe_pict_dec_res = NULL; + } + + return IMG_SUCCESS; +} + +/* + * @Function decoder_get_load + */ +int decoder_get_load(void *dec_str_ctx_arg, unsigned int *avail_slots) +{ + struct dec_str_ctx *dec_str_ctx = + decoder_stream_get_context(dec_str_ctx_arg); + struct dec_core_ctx *dec_core_ctx_local = NULL; + + /* Check input parameters. */ + VDEC_ASSERT(dec_str_ctx); + if (!dec_str_ctx || !avail_slots) { + pr_err("Invalid parameters!"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + dec_core_ctx_local = decoder_str_ctx_to_core_ctx(dec_str_ctx); + if (!dec_core_ctx_local) { + VDEC_ASSERT(0); + return -EIO; + } + + if (dec_core_ctx_local->busy) + *avail_slots = 0; + else + *avail_slots = dec_str_ctx->avail_slots; + + return IMG_SUCCESS; +} + +static int decoder_check_ref_errors(struct dec_str_ctx *dec_str_ctx, + struct vdecfw_buffer_control *buf_ctrl, + struct vdecdd_picture *picture) +{ + struct dec_decoded_pict *ref_pict; + unsigned int i; + + if (!dec_str_ctx) { + VDEC_ASSERT(0); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!buf_ctrl || !picture) { + pr_err("[USERSID=0x%08X] Invalid parameters for checking reference lists.", + dec_str_ctx->config.user_str_id); + VDEC_ASSERT(0); + return IMG_ERROR_INVALID_PARAMETERS; + } + + for (i = 0; i < VDECFW_MAX_NUM_PICTURES && buf_ctrl->ref_list[i]; + i++) { + ref_pict = decoder_get_decoded_pict_of_stream + (GET_STREAM_PICTURE_ID(buf_ctrl->ref_list[i]), + &dec_str_ctx->str_decd_pict_list); + if (ref_pict && ref_pict->pict && ref_pict->pict->dec_pict_info && + ref_pict->pict->dec_pict_info->err_flags) { + picture->dec_pict_info->err_flags |= + VDEC_ERROR_CORRUPTED_REFERENCE; + pr_warn("Picture decoded using corrupted reference: 0x%08X 0x%08X", + ref_pict->transaction_id, + ref_pict->pict->dec_pict_info->err_flags); + } + } + + return IMG_SUCCESS; +} + +static void decoder_clean_bitstr_segments(struct lst_t *decpict_seglist) +{ + struct dec_decpict_seg *dec_pict_seg; + + while (NULL != (dec_pict_seg = lst_removehead(decpict_seglist))) { + if (dec_pict_seg->internal_seg) { + VDEC_ASSERT(dec_pict_seg->bstr_seg); + kfree(dec_pict_seg->bstr_seg); + dec_pict_seg->bstr_seg = NULL; + } + kfree(dec_pict_seg); + } +} + +static int decoder_wrap_bitstr_segments(struct lst_t *bitstr_seglist, + struct lst_t *decpict_seglist, + unsigned int user_str_id) +{ + /* Required for attaching segments to the decode picture */ + struct bspp_bitstr_seg *bit_str_seg; + struct dec_decpict_seg *dec_pict_seg; + + VDEC_ASSERT(bitstr_seglist); + VDEC_ASSERT(decpict_seglist); + + /* Add the segments to the Decode Picture */ + bit_str_seg = lst_first(bitstr_seglist); + while (bit_str_seg) { + dec_pict_seg = kzalloc(sizeof(*dec_pict_seg), GFP_KERNEL); + VDEC_ASSERT(dec_pict_seg); + if (!dec_pict_seg) + return IMG_ERROR_OUT_OF_MEMORY; + + dec_pict_seg->bstr_seg = bit_str_seg; + dec_pict_seg->internal_seg = FALSE; + lst_add(decpict_seglist, dec_pict_seg); + + bit_str_seg = lst_next(bit_str_seg); + } + return IMG_SUCCESS; +} + +/* + * @Function decoder_picture_decode + */ +static int decoder_picture_decode(struct dec_str_ctx *dec_str_ctx, + struct vdecdd_str_unit *str_unit, + struct dec_decpict **dec_pict_ptr) +{ + struct vdecdd_picture *picture; + struct dec_core_ctx *dec_core_ctx; + struct dec_decpict *dec_pict; + int ret = IMG_SUCCESS; + struct decoder_regsoffsets regs_offsets; + + /* Validate input arguments */ + if (!dec_str_ctx || !str_unit || !str_unit->pict_hdr_info || !dec_pict_ptr) { + VDEC_ASSERT(0); + return -EIO; + } + + picture = (struct vdecdd_picture *)str_unit->dd_pict_data; + dec_core_ctx = decoder_str_ctx_to_core_ctx(dec_str_ctx); + + if (!picture || !dec_core_ctx) { + VDEC_ASSERT(0); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Ensure this is a new picture */ + VDEC_ASSERT(!dec_str_ctx->cur_pict); + VDEC_ASSERT(str_unit->str_unit_type == VDECDD_STRUNIT_PICTURE_START); + + dec_core_ctx->cum_pics++; + + /* Allocate a unique id to the picture */ + ret = idgen_allocid(dec_str_ctx->pict_idgen, picture, &picture->pict_id); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + /* Allocate the decoded picture information structure. */ + picture->dec_pict_info = kzalloc(sizeof(*picture->dec_pict_info), GFP_KERNEL); + VDEC_ASSERT(picture->dec_pict_info); + if (!picture->dec_pict_info) + return IMG_ERROR_OUT_OF_MEMORY; + + /* Extract decoded information from the stream unit */ + picture->dec_pict_info->err_flags = str_unit->err_flags; + picture->dec_pict_info->first_fld_tag_container.pict_tag_param = + (unsigned long)(str_unit->str_unit_tag); + picture->dec_pict_info->op_config = picture->op_config; + picture->dec_pict_info->rend_info = picture->disp_pict_buf.rend_info; + picture->dec_pict_info->disp_info = str_unit->pict_hdr_info->disp_info; + + /* Extract aux picture information from the stream unit */ + picture->dec_pict_aux_info.seq_hdr_id = + str_unit->seq_hdr_info->sequ_hdr_id; + picture->dec_pict_aux_info.pps_id = + str_unit->pict_hdr_info->pict_aux_data.id; + picture->dec_pict_aux_info.second_pps_id = + str_unit->pict_hdr_info->second_pict_aux_data.id; + + /* Create a new decoder picture container. */ + dec_pict = kzalloc(sizeof(*dec_pict), GFP_KERNEL); + VDEC_ASSERT(dec_pict); + if (!dec_pict) { + ret = IMG_ERROR_OUT_OF_MEMORY; + goto error_dec_pict; + } + + /* Attach decoder/picture context information. */ + dec_pict->dec_str_ctx = dec_str_ctx; + + /* + * Construct the transaction Id. + * This consists of stream and core number in addition to picture + * number in stream and a 4-bit value representing the picture number + * in core. + */ + dec_pict->transaction_id = + CREATE_TRANSACTION_ID(0, dec_str_ctx->km_str_id, dec_core_ctx->cum_pics, + picture->pict_id); + + /* Add picture to core decode list */ + dec_str_ctx->dec_str_st.num_pict_decoding++; + + /* Fake a FW message to process when decoded. */ + dec_pict->first_fld_fwmsg = kzalloc(sizeof(*dec_pict->first_fld_fwmsg), GFP_KERNEL); + VDEC_ASSERT(dec_pict->first_fld_fwmsg); + if (!dec_pict->first_fld_fwmsg) { + ret = IMG_ERROR_OUT_OF_MEMORY; + goto error_fw_msg; + } + + dec_pict->second_fld_fwmsg = + kzalloc(sizeof(*dec_pict->second_fld_fwmsg), GFP_KERNEL); + VDEC_ASSERT(dec_pict->second_fld_fwmsg); + if (!dec_pict->second_fld_fwmsg) { + ret = IMG_ERROR_OUT_OF_MEMORY; + goto error_fw_msg; + } + + /* Add the segments to the Decode Picture */ + ret = decoder_wrap_bitstr_segments(&str_unit->bstr_seg_list, + &dec_pict->dec_pict_seg_list, + dec_str_ctx->config.user_str_id); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error_segments; + + /* + * Shuffle the current and previous + * Hold a reference to the last context on the FE + */ + if (dec_str_ctx->prev_fe_pict_dec_res) { + /* Return previous last FW context. */ + resource_item_return(&dec_str_ctx->prev_fe_pict_dec_res->ref_cnt); + + if (resource_item_isavailable(&dec_str_ctx->prev_fe_pict_dec_res->ref_cnt)) { + resource_list_remove(&dec_str_ctx->dec_res_lst, + dec_str_ctx->prev_fe_pict_dec_res); + + resource_list_add_img(&dec_str_ctx->dec_res_lst, + dec_str_ctx->prev_fe_pict_dec_res, 0, + &dec_str_ctx->prev_fe_pict_dec_res->ref_cnt); + } + } + + dec_str_ctx->prev_fe_pict_dec_res = dec_str_ctx->cur_fe_pict_dec_res; + dec_pict->prev_pict_dec_res = dec_str_ctx->prev_fe_pict_dec_res; + + /* Get a new stream decode resource bundle for current picture. */ + dec_pict->cur_pict_dec_res = resource_list_get_avail(&dec_str_ctx->dec_res_lst); + VDEC_ASSERT(dec_pict->cur_pict_dec_res); + if (!dec_pict->cur_pict_dec_res) { + ret = IMG_ERROR_UNEXPECTED_STATE; + goto error_dec_res; + } + + if (dec_str_ctx->config.vid_std == VDEC_STD_H264) { + /* Copy any SGM for current picture. */ + if (str_unit->pict_hdr_info->pict_sgm_data.id != + BSPP_INVALID) { + VDEC_ASSERT(str_unit->pict_hdr_info->pict_sgm_data.size <= + dec_pict->cur_pict_dec_res->h264_sgm_buf.buf_size); + /* Updated in translation_api */ + memcpy(dec_pict->cur_pict_dec_res->h264_sgm_buf.cpu_virt, + str_unit->pict_hdr_info->pict_sgm_data.pic_data, + str_unit->pict_hdr_info->pict_sgm_data.size); + } + } + + dec_pict->cur_pict_dec_res->transaction_id = dec_pict->transaction_id; + dec_str_ctx->cur_fe_pict_dec_res = dec_pict->cur_pict_dec_res; + resource_item_use(&dec_str_ctx->cur_fe_pict_dec_res->ref_cnt); + + /* Get a new control buffer */ + dec_pict->pict_ref_res = + resource_list_get_avail(&dec_str_ctx->ref_res_lst); + VDEC_ASSERT(dec_pict->pict_ref_res); + if (!dec_pict->pict_ref_res) { + ret = IMG_ERROR_UNEXPECTED_STATE; + goto error_ref_res; + } + + VDEC_ASSERT(dec_str_ctx->decctx); + VDEC_ASSERT(dec_str_ctx->decctx->dev_cfg); + + dec_pict->str_pvdec_fw_ctxbuf = &dec_str_ctx->pvdec_fw_ctx_buf; + dec_pict->pict_hdr_info = str_unit->pict_hdr_info; + + /* Obtain (core) resources for the picture */ + ret = dec_res_picture_attach(&dec_str_ctx->resources, + dec_str_ctx->config.vid_std, dec_pict); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error_res_attach; + + /* Clear fw context data for re-use */ + memset(dec_pict->cur_pict_dec_res->fw_ctx_buf.cpu_virt, 0, + dec_pict->cur_pict_dec_res->fw_ctx_buf.buf_size); + + /* + * Clear the control data in case the picture is discarded before + * being prepared by firmware. + */ + memset(dec_pict->pict_ref_res->fw_ctrlbuf.cpu_virt, 0, + dec_pict->pict_ref_res->fw_ctrlbuf.buf_size); + + ret = hwctrl_getregsoffset(dec_core_ctx->hw_ctx, ®s_offsets); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error_other; + + ret = translation_ctrl_alloc_prepare(&dec_str_ctx->config, str_unit, + dec_pict, + &dec_core_ctx->core_props, + ®s_offsets); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error_other; + + ret = hwctrl_picture_submitbatch(dec_core_ctx->hw_ctx, dec_pict, + dec_str_ctx->vxd_dec_ctx); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error_other; + + VDEC_ASSERT(dec_str_ctx->avail_slots > 0); + dec_str_ctx->avail_slots--; + + VDEC_ASSERT(!dec_core_ctx->busy); + dec_core_ctx->busy = TRUE; + /* Store this transaction ID in stream context */ + dec_str_ctx->last_fe_transaction_id = dec_pict->transaction_id; + dec_str_ctx->cur_pict = (struct dec_decpict *)dec_pict; + + dec_str_ctx->dec_str_st.features = str_unit->features; + + if (str_unit->eop) + dec_pict->eop_found = TRUE; + + *dec_pict_ptr = dec_pict; + + return IMG_SUCCESS; + + /* Roll back in case of errors. */ +error_other: + dec_res_picture_detach(&dec_str_ctx->resources, dec_pict); +error_res_attach: +error_ref_res: +error_dec_res: +error_segments: + decoder_clean_bitstr_segments(&dec_pict->dec_pict_seg_list); + kfree(dec_pict->first_fld_fwmsg); + kfree(dec_pict->second_fld_fwmsg); +error_fw_msg: + kfree(dec_pict); +error_dec_pict: + kfree(picture->dec_pict_info); + + return ret; +} + +/* + * @Function decoder_stream_reference_resource_create + */ +static int +decoder_stream_reference_resource_create(struct dec_str_ctx *dec_str_ctx) +{ + struct dec_pictref_res *pict_ref_res; + int ret; + unsigned int mem_heap_id; + enum sys_emem_attrib mem_attribs; + + if (!dec_str_ctx || !dec_str_ctx->decctx) { + VDEC_ASSERT(0); + return -EINVAL; + } + + mem_heap_id = dec_str_ctx->decctx->internal_heap_id; + mem_attribs = (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE); + mem_attribs |= (enum sys_emem_attrib)SYS_MEMATTRIB_INTERNAL; + + /* Allocate the firmware context buffer info structure. */ + pict_ref_res = kzalloc(sizeof(*pict_ref_res), GFP_KERNEL); + VDEC_ASSERT(pict_ref_res); + if (!pict_ref_res) + return IMG_ERROR_OUT_OF_MEMORY; + + /* + * Allocate the firmware context buffer to contain data required for + * subsequent picture. + */ + +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s:%d calling MMU_StreamMalloc", __func__, __LINE__); +#endif + ret = mmu_stream_alloc(dec_str_ctx->mmu_str_handle, MMU_HEAP_STREAM_BUFFERS, mem_heap_id, + (enum sys_emem_attrib)(mem_attribs | SYS_MEMATTRIB_CPU_READ | + SYS_MEMATTRIB_CPU_WRITE), + sizeof(struct vdecfw_buffer_control), + DEV_MMU_PAGE_ALIGNMENT, + &pict_ref_res->fw_ctrlbuf); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto err_out_of_memory; + + /* + * Clear the context data in preparation for first time use by + * the firmware. + */ + memset(pict_ref_res->fw_ctrlbuf.cpu_virt, 0, pict_ref_res->fw_ctrlbuf.buf_size); + + pict_ref_res->ref_cnt = 1; + + ret = resource_list_add_img(&dec_str_ctx->ref_res_lst, pict_ref_res, 0, + &pict_ref_res->ref_cnt); + if (ret != IMG_SUCCESS) { + pr_err("[USERSID=0x%08X] Failed to add resource", dec_str_ctx->config.user_str_id); + return ret; + } + + return IMG_SUCCESS; + +err_out_of_memory: + + kfree(pict_ref_res); + pict_ref_res = NULL; + + pr_err("[USERSID=0x%08X] Failed to allocate device memory for stream reference resources", + dec_str_ctx->config.user_str_id); + + return IMG_ERROR_OUT_OF_MEMORY; +} + +/* + * @Function decoder_picture_finalize + */ +static int decoder_picture_finalize(struct dec_str_ctx *dec_str_ctx, + struct vdecdd_str_unit *str_unit) +{ + struct dec_decpict *dec_pict; + struct dec_core_ctx *dec_core_ctx = NULL; + + VDEC_ASSERT(dec_str_ctx); + + dec_pict = dec_str_ctx->cur_pict; + if (!dec_pict) { + pr_err("[USERSID=0x%08X] Unable to get the current picture from Decoder context", + dec_str_ctx->config.user_str_id); + return IMG_ERROR_GENERIC_FAILURE; + } + + dec_core_ctx = decoder_str_ctx_to_core_ctx(dec_str_ctx); + + if (!dec_core_ctx || !dec_core_ctx->busy) { + VDEC_ASSERT(0); + return -EINVAL; + } + + dec_core_ctx->busy = FALSE; + + /* Picture data are now complete, nullify pointer */ + dec_str_ctx->cur_pict = NULL; + + return IMG_SUCCESS; +} + +/* + * @Function decoder_submit_fragment + */ +static int decoder_submit_fragment(struct dec_str_ctx *dec_str_context, + struct vdecdd_str_unit *str_unit, + unsigned char eop) +{ + struct dec_core_ctx *dec_core_context = NULL; + struct lst_t dec_fragment_seg_list; + struct dec_decpict_seg *dec_pict_seg; + struct dec_pict_fragment *pict_fragment; + int ret = IMG_SUCCESS; + + if (!dec_str_context) { + VDEC_ASSERT(0); + return IMG_ERROR_GENERIC_FAILURE; + } + + if (!dec_str_context->cur_pict) { + pr_err("[USERSID=0x%08X] Unable to get the current picture from Decoder context", + dec_str_context->config.user_str_id); + VDEC_ASSERT(0); + return IMG_ERROR_GENERIC_FAILURE; + } + + dec_core_context = decoder_str_ctx_to_core_ctx(dec_str_context); + if (!dec_core_context) { + VDEC_ASSERT(0); + return IMG_ERROR_GENERIC_FAILURE; + } + + pict_fragment = kzalloc(sizeof(*pict_fragment), GFP_KERNEL); + VDEC_ASSERT(pict_fragment); + if (!pict_fragment) + return IMG_ERROR_OUT_OF_MEMORY; + + lst_init(&dec_fragment_seg_list); + + /* Add the segments to the temporary list */ + ret = decoder_wrap_bitstr_segments(&str_unit->bstr_seg_list, + &dec_fragment_seg_list, + dec_str_context->config.user_str_id); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + /* Prepare ctr alloc for the fragment */ + ret = translation_fragment_prepare(dec_str_context->cur_pict, + &dec_fragment_seg_list, eop, + pict_fragment); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + /* + * Move segments of the fragment from the temporary list to the picture + * segment list + */ + dec_pict_seg = lst_removehead(&dec_fragment_seg_list); + while (dec_pict_seg) { + lst_add(&dec_str_context->cur_pict->dec_pict_seg_list, + dec_pict_seg); + dec_pict_seg = lst_removehead(&dec_fragment_seg_list); + } + + /* Submit fragment */ + ret = hwctrl_picture_submit_fragment(dec_core_context->hw_ctx, + pict_fragment, + dec_str_context->cur_pict, + dec_str_context->vxd_dec_ctx); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + lst_add(&dec_str_context->cur_pict->fragment_list, pict_fragment); + + if (eop) + dec_str_context->cur_pict->eop_found = TRUE; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] [TID=0x%08X] FRAGMENT", + dec_str_context->config.user_str_id, + dec_str_context->last_fe_transaction_id); +#endif + + return IMG_SUCCESS; +error: + kfree(pict_fragment); + + return ret; +} + +/* + * @Function decoder_stream_process_unit + */ +int decoder_stream_process_unit(void *dec_str_ctx_arg, + struct vdecdd_str_unit *str_unit) +{ + struct dec_str_ctx *dec_str_ctx = + decoder_stream_get_context(dec_str_ctx_arg); + + struct dec_str_unit *dec_str_unit; + struct dec_decpict *dec_pict = NULL; + unsigned char processed = FALSE; + int ret; + + VDEC_ASSERT(dec_str_ctx); + VDEC_ASSERT(str_unit); + + if (!dec_str_ctx || !str_unit) { + pr_err("Invalid decoder stream context handle!\n"); + return IMG_ERROR_INVALID_PARAMETERS; + } + pr_debug("%s : stream unit type = %d\n" + , __func__, str_unit->str_unit_type); + /* Process the stream unit */ + switch (str_unit->str_unit_type) { + case VDECDD_STRUNIT_SEQUENCE_END: + case VDECDD_STRUNIT_ANONYMOUS: + case VDECDD_STRUNIT_CLOSED_GOP: + case VDECDD_STRUNIT_PICTURE_PORTENT: + case VDECDD_STRUNIT_FENCE: + /* Nothing more to do so mark the stream unit as processed */ + processed = TRUE; + break; + + case VDECDD_STRUNIT_STOP: + if (dec_str_ctx->cur_pict && !dec_str_ctx->cur_pict->eop_found) { + ret = decoder_submit_fragment(dec_str_ctx, str_unit, TRUE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + ret = decoder_picture_finalize(dec_str_ctx, str_unit); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] [TID=0x%08X] FORCED END", + dec_str_ctx->config.user_str_id, + dec_str_ctx->last_fe_transaction_id); +#endif + } + + processed = TRUE; + break; + + case VDECDD_STRUNIT_SEQUENCE_START: + { + unsigned int max_num_activ_pict = 0; + + VDEC_ASSERT(str_unit->seq_hdr_info); + /* + * Determine how many decoded pictures can be held for + * reference in the decoder for this stream. + */ + ret = vdecddutils_ref_pict_get_maxnum(&dec_str_ctx->config, + &str_unit->seq_hdr_info->com_sequ_hdr_info, + &max_num_activ_pict); + if (ret != IMG_SUCCESS) + return ret; + + /* Double for field coding */ + max_num_activ_pict *= 2; + + /* + * Ensure that there are enough resource to have pictures + * filling all slots on all cores. + */ + max_num_activ_pict += + dec_str_ctx->decctx->dev_cfg->num_slots_per_pipe * + dec_str_ctx->decctx->num_pipes; + + /* Increase decoder stream resources if necessary. */ + while (dec_str_ctx->num_ref_res < max_num_activ_pict) { + ret = decoder_stream_reference_resource_create(dec_str_ctx); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dec_str_ctx->num_ref_res++; + } + + /* Nothing more to do so mark the stream unit as processed */ + processed = TRUE; + break; + } + + case VDECDD_STRUNIT_PICTURE_START: + if (str_unit->decode) { + /* Prepare and submit picture to decode. */ + ret = decoder_picture_decode(dec_str_ctx, str_unit, &dec_pict); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] [TID=0x%08X] START", + dec_str_ctx->config.user_str_id, + dec_str_ctx->last_fe_transaction_id); +#endif + } else { + processed = TRUE; + } + break; + + case VDECDD_STRUNIT_PICTURE_END: + if (str_unit->decode) { + ret = decoder_picture_finalize(dec_str_ctx, str_unit); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] [TID=0x%08X] END", + dec_str_ctx->config.user_str_id, + dec_str_ctx->last_fe_transaction_id); +#endif + } else { + processed = TRUE; + } + break; + + default: + VDEC_ASSERT(FALSE); + break; + } + + /* + * If this or any preceding stream unit(s) could not be + * completely processed, add this unit to the queue. + */ + if (!processed) { + /* Add unit to stream decode list */ + dec_str_unit = kzalloc(sizeof(*dec_str_unit), GFP_KERNEL); + VDEC_ASSERT(dec_str_unit); + if (!dec_str_unit) + return IMG_ERROR_OUT_OF_MEMORY; + + dec_str_unit->str_unit = str_unit; + + /* make PICTURE_START owner of dec_pict */ + if (dec_pict) { + VDEC_ASSERT(str_unit->str_unit_type == VDECDD_STRUNIT_PICTURE_START); + dec_str_unit->dec_pict = dec_pict; + } + + lst_add(&dec_str_ctx->pend_strunit_list, dec_str_unit); + } else { + /* + * If there is nothing being decoded for this stream, + * immediately handle the unit (non-picture so doesn't need + * decoding). Report that this unit has been processed. + */ + VDEC_ASSERT(dec_str_ctx->decctx); + ret = dec_str_ctx->str_processed_cb(dec_str_ctx->usr_int_data, + VXD_CB_STRUNIT_PROCESSED, + str_unit); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + + return IMG_SUCCESS; +} + +static int +decoder_get_required_core_features(const struct vdec_str_configdata *str_cfg, + const struct vdec_str_opconfig *op_cfg, + unsigned int *features) +{ + unsigned int features_local = 0; + + VDEC_ASSERT(str_cfg); + VDEC_ASSERT(features); + + /* Check Video Standard. */ + switch (str_cfg->vid_std) { + case VDEC_STD_H264: + features_local = VDECDD_COREFEATURE_H264; + break; +#ifdef HAS_JPEG + case VDEC_STD_JPEG: + features_local = VDECDD_COREFEATURE_JPEG; + break; +#endif +#ifdef HAS_HEVC + case VDEC_STD_HEVC: + features_local = VDECDD_COREFEATURE_HEVC; + break; +#endif + default: + VDEC_ASSERT(FALSE); + break; + } + + *features = features_local; + + return IMG_SUCCESS; +} + +/* + * @Function decoder_is_supported_by_atleast_onepipe + */ +static unsigned char decoder_is_supported_by_atleast_onepipe(unsigned char *features, + unsigned int num_pipes) +{ + unsigned int i; + + VDEC_ASSERT(features); + VDEC_ASSERT(num_pipes <= VDEC_MAX_PIXEL_PIPES); + + for (i = 0; i < num_pipes; i++) { + if (features[i]) + return TRUE; + } + + return FALSE; +} + +/* + * @Function decoder_check_support + */ +int decoder_check_support(void *dec_ctx_arg, + const struct vdec_str_configdata *str_cfg, + const struct vdec_str_opconfig *str_op_cfg, + const struct vdecdd_ddpict_buf *disp_pict_buf, + const struct vdec_pict_rendinfo *req_pict_rendinfo, + const struct vdec_comsequ_hdrinfo *comseq_hdrinfo, + const struct bspp_pict_hdr_info *pict_hdrinfo, + const struct vdec_comsequ_hdrinfo *prev_comseq_hdrinfo, + const struct bspp_pict_hdr_info *prev_pict_hdrinfo, + unsigned char non_cfg_req, + struct vdec_unsupp_flags *unsupported, + unsigned int *features) +{ + struct dec_ctx *dec_ctx = (struct dec_ctx *)dec_ctx_arg; + struct dec_core_ctx *dec_core_ctx; + struct vxd_coreprops *core_props; + const struct vdec_pict_rendinfo *disp_pict_rendinfo = NULL; + int ret = IMG_ERROR_NOT_SUPPORTED; + + /* Ensure input parameters are valid. */ + VDEC_ASSERT(dec_ctx_arg); + VDEC_ASSERT(str_cfg); + VDEC_ASSERT(unsupported); + + if (!dec_ctx_arg || !str_cfg || !unsupported) { + pr_err("Invalid parameters!"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (disp_pict_buf) + disp_pict_rendinfo = &disp_pict_buf->rend_info; + + /* + * Validate compatibility between the supplied configuration/state + * and the master core only at the moment (assumed to have superset + * of features). + * Some features may not be present on any slave cores which might + * cause poor utilisation of hardware. + */ + memset(unsupported, 0, sizeof(*unsupported)); + + dec_core_ctx = dec_ctx->dec_core_ctx; + VDEC_ASSERT(dec_core_ctx); + + core_props = &dec_core_ctx->core_props; + VDEC_ASSERT(core_props); + + /* Check that the video standard is supported */ + switch (str_cfg->vid_std) { + case VDEC_STD_H264: + if (!decoder_is_supported_by_atleast_onepipe(core_props->h264, + core_props->num_pixel_pipes)) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: VIDEO STANDARD (H.264)", + str_cfg->user_str_id); + unsupported->str_cfg |= + VDECDD_UNSUPPORTED_STRCONFIG_STD; + } + + if (comseq_hdrinfo && (H264_PROFILE_MVC_HIGH == + comseq_hdrinfo->codec_profile || H264_PROFILE_MVC_STEREO == + comseq_hdrinfo->codec_profile) && comseq_hdrinfo->num_views > + VDEC_H264_MVC_MAX_VIEWS) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[SW]: NUMBER OF VIEWS", + str_cfg->user_str_id); + unsupported->seq_hdr |= VDECDD_UNSUPPORTED_SEQUHDR_NUM_OF_VIEWS; + } + break; +#ifdef HAS_HEVC + case VDEC_STD_HEVC: + if (!decoder_is_supported_by_atleast_onepipe(core_props->hevc, + core_props->num_pixel_pipes)) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: VIDEO STANDARD (HEVC)", + str_cfg->user_str_id); + unsupported->str_cfg |= VDECDD_UNSUPPORTED_STRCONFIG_STD; + } + if (pict_hdrinfo && pict_hdrinfo->hevc_pict_hdr_info.range_ext_present) + if ((pict_hdrinfo->hevc_pict_hdr_info.is_full_range_ext && + !decoder_is_supported_by_atleast_onepipe(core_props->hevc_range_ext, + core_props->num_pixel_pipes)) || + (!pict_hdrinfo->hevc_pict_hdr_info.is_full_range_ext && + core_props->vidstd_props[str_cfg->vid_std].max_chroma_format == + PIXEL_FORMAT_420)) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: HEVC RANGE EXTENSIONS", + str_cfg->user_str_id); + unsupported->pict_hdr |= VDECDD_UNSUPPORTED_PICTHDR_HEVC_RANGE_EXT; + } + break; +#endif +#ifdef HAS_JPEG + case VDEC_STD_JPEG: + if (!decoder_is_supported_by_atleast_onepipe(core_props->jpeg, + core_props->num_pixel_pipes)) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: VIDEO STANDARD (JPEG)", + str_cfg->user_str_id); + unsupported->str_cfg |= + VDECDD_UNSUPPORTED_STRCONFIG_STD; + } + break; +#endif + default: + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: VIDEO STANDARD (UNKNOWN)", + str_cfg->user_str_id); + unsupported->str_cfg |= + VDECDD_UNSUPPORTED_STRCONFIG_STD; + break; + } + + if (str_op_cfg) { + /* + * Ensure that each display feature is supported by the + * hardware. + */ + if (comseq_hdrinfo) { + /* Validate display pixel format */ + if (non_cfg_req && prev_comseq_hdrinfo && + vdec_size_nz(prev_comseq_hdrinfo->frame_size) && + prev_comseq_hdrinfo->pixel_info.chroma_fmt_idc == + str_op_cfg->pixel_info.chroma_fmt_idc && + comseq_hdrinfo->pixel_info.chroma_fmt_idc != + prev_comseq_hdrinfo->pixel_info.chroma_fmt_idc) { + /* + * If this is a non-configuration request and + * it looks like a new sequence with + * sub-sampling change, just indicate output + * format mismatch without any error messages. + */ + unsupported->str_opcfg |= VDECDD_UNSUPPORTED_OUTPUTCONFIG_PIXFORMAT; + } else { + switch (str_op_cfg->pixel_info.chroma_fmt_idc) { + case PIXEL_FORMAT_420: + if (comseq_hdrinfo->pixel_info.chroma_fmt_idc == + PIXEL_FORMAT_MONO) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: TRANSFORM PIXEL FORMAT FROM 400 TO 420", + str_cfg->user_str_id); + unsupported->str_opcfg |= + VDECDD_UNSUPPORTED_OUTPUTCONFIG_PIXFORMAT; + } + break; + + case PIXEL_FORMAT_422: + if (comseq_hdrinfo->pixel_info.chroma_fmt_idc == + PIXEL_FORMAT_420 && + str_op_cfg->pixel_info.num_planes > 1) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: REQUESTED NUMBER OF PLANES FOR 422 UPSAMPLING", + str_cfg->user_str_id); + unsupported->str_opcfg |= + VDECDD_UNSUPPORTED_OUTPUTCONFIG_PIXFORMAT; + } else if (comseq_hdrinfo->pixel_info.chroma_fmt_idc == + PIXEL_FORMAT_MONO) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: TRANSFORM PIXEL FORMAT FROM 400 TO 422", + str_cfg->user_str_id); + unsupported->str_opcfg |= + VDECDD_UNSUPPORTED_OUTPUTCONFIG_PIXFORMAT; + } + break; + + default: + break; + } + } + } + + if (str_op_cfg->pixel_info.bitdepth_y > + core_props->vidstd_props[str_cfg->vid_std].max_luma_bitdepth || + str_op_cfg->pixel_info.bitdepth_y < 8 || + str_op_cfg->pixel_info.bitdepth_y == 9) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: DISPLAY PICTURE LUMA BIT DEPTH %d [RANGE: 8->%d for %s]", + str_cfg->user_str_id, + str_op_cfg->pixel_info.bitdepth_y, + core_props->vidstd_props[str_cfg->vid_std].max_luma_bitdepth, + vid_std_names[str_cfg->vid_std]); + unsupported->str_opcfg |= + VDECDD_UNSUPPORTED_OUTPUTCONFIG_PIXFORMAT; + } + + if (str_op_cfg->pixel_info.chroma_fmt_idc != + PIXEL_FORMAT_MONO && + (str_op_cfg->pixel_info.bitdepth_c > + core_props->vidstd_props[str_cfg->vid_std].max_chroma_bitdepth || + str_op_cfg->pixel_info.bitdepth_c < 8 || + str_op_cfg->pixel_info.bitdepth_c == 9)) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: DISPLAY PICTURE CHROMA BIT DEPTH %d [RANGE: 8->%d for %s]", + str_cfg->user_str_id, + str_op_cfg->pixel_info.bitdepth_c, + core_props->vidstd_props[str_cfg->vid_std].max_chroma_bitdepth, + vid_std_names[str_cfg->vid_std]); + unsupported->str_opcfg |= + VDECDD_UNSUPPORTED_OUTPUTCONFIG_PIXFORMAT; + } + +#ifdef HAS_JPEG + /* Validate display configuration against existing stream configuration.*/ + if (str_cfg->vid_std == VDEC_STD_JPEG) { + if (str_op_cfg->force_oold) { + pr_err("[USERSID=0x%08X] UNSUPPORTED[HW]: OOLD WITH JPEG\n", + str_cfg->user_str_id); + unsupported->str_opcfg |= + VDECDD_UNSUPPORTED_OUTPUTCONFIG_X_WITH_JPEG; + } + } +#endif + } + + if (disp_pict_rendinfo) { + unsigned int stride_alignment = VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT; + + if (req_pict_rendinfo) { + /* + * Picture size declared in buffer must be at least as + * large as that required by bitstream/output config. + */ + if (!vdec_size_ge(disp_pict_rendinfo->rend_pict_size, + req_pict_rendinfo->rend_pict_size)) { + pr_warn("[USERSID=0x%08X] Picture size of output picture buffer [%d x %d] is not large enough for sequence [%d x %d]", + str_cfg->user_str_id, + disp_pict_rendinfo->rend_pict_size.width, + disp_pict_rendinfo->rend_pict_size.height, + req_pict_rendinfo->rend_pict_size.width, + req_pict_rendinfo->rend_pict_size.height); + unsupported->str_opcfg |= + VDECDD_UNSUPPORTED_OUTPUTBUFCONFIG_PICTURE_SIZE; + } + + /* + * Size of each plane must be at least as large + * as that required. + */ + if (disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_Y].size < + req_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_Y].size) { + pr_warn("[USERSID=0x%08X] Y plane of output picture buffer [%d bytes] is not large enough for bitstream/config [%d bytes]", + str_cfg->user_str_id, + disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_Y].size, + req_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_Y].size); + unsupported->op_bufcfg |= + VDECDD_UNSUPPORTED_OUTPUTBUFCONFIG_Y_SIZE; + } + + /* + * Stride of each plane must be at least as large as that + * required. + */ + if (disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_Y].stride < + req_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_Y].stride) { + pr_warn("[USERSID=0x%08X] Y stride of output picture buffer [%d bytes] is not large enough for bitstream/config [%d bytes]", + str_cfg->user_str_id, + disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_Y].stride, + req_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_Y].stride); + unsupported->op_bufcfg |= + VDECDD_UNSUPPORTED_OUTPUTBUFCONFIG_Y_STRIDE; + } + + /* + * Size of each plane must be at least + * as large as that required. + */ + if (disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_UV].size < + req_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_UV].size) { + pr_warn("[USERSID=0x%08X] UV plane of output picture buffer [%d bytes] is not large enough for bitstream/config [%d bytes]", + str_cfg->user_str_id, + disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_UV].size, + req_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_UV].size); + unsupported->op_bufcfg |= + VDECDD_UNSUPPORTED_OUTPUTBUFCONFIG_UV_SIZE; + } + + /* + * Stride of each plane must be at least + * as large as that required. + */ + if (disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_UV].stride < + req_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_UV].stride) { + pr_warn("[USERSID=0x%08X] UV stride of output picture buffer [%d bytes] is not large enough for bitstream/config [%d bytes]", + str_cfg->user_str_id, + disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_UV].stride, + req_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_UV].stride); + unsupported->op_bufcfg |= + VDECDD_UNSUPPORTED_OUTPUTBUFCONFIG_UV_STRIDE; + } + + if ((req_pict_rendinfo->stride_alignment & + (VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT - 1)) != 0) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: STRIDE ALIGNMENT [%d] must be a multiple of %d bytes", + str_cfg->user_str_id, + req_pict_rendinfo->stride_alignment, + VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT); + unsupported->op_bufcfg |= + VDECDD_UNSUPPORTED_OUTPUTBUFCONFIG_64BYTE_STRIDE; + } + + if (req_pict_rendinfo->stride_alignment > 0) + stride_alignment = req_pict_rendinfo->stride_alignment; + } + + if ((disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_Y].stride % + stride_alignment) != 0) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: Y STRIDE [%d] must be a multiple of %d bytes", + str_cfg->user_str_id, + disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_Y].stride, + stride_alignment); + unsupported->op_bufcfg |= + VDECDD_UNSUPPORTED_OUTPUTBUFCONFIG_64BYTE_STRIDE; + } + + if ((disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_UV].stride % + stride_alignment) != 0) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: UV STRIDE [%d] must be a multiple of %d bytes", + str_cfg->user_str_id, + disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_UV].stride, + stride_alignment); + unsupported->op_bufcfg |= + VDECDD_UNSUPPORTED_OUTPUTBUFCONFIG_64BYTE_STRIDE; + } + + if ((disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_V].stride % + stride_alignment) != 0) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: V STRIDE [%d] must be a multiple of %d bytes", + str_cfg->user_str_id, + disp_pict_rendinfo->plane_info[VDEC_PLANE_VIDEO_V].stride, + stride_alignment); + unsupported->op_bufcfg |= + VDECDD_UNSUPPORTED_OUTPUTBUFCONFIG_64BYTE_STRIDE; + } + + if (req_pict_rendinfo) { + if (str_op_cfg) { + if (str_cfg->vid_std != VDEC_STD_JPEG) { + if (str_op_cfg->pixel_info.num_planes <= 2) + /* + * V plane only required when chroma is + * separated. + */ + VDEC_ASSERT(req_pict_rendinfo->plane_info + [VDEC_PLANE_VIDEO_V].size == 0); + + if (str_op_cfg->pixel_info.num_planes <= 3) + /* Alpha planes should not be required. */ + VDEC_ASSERT(req_pict_rendinfo->plane_info + [VDEC_PLANE_VIDEO_A].size == 0); + } + } + + /* Size of buffer must be at least as large as that required. */ + if (disp_pict_rendinfo->rendered_size < + req_pict_rendinfo->rendered_size) { + pr_warn("[USERSID=0x%08X] Output picture buffer [%d bytes] is not large enough for bitstream/config [%d bytes]", + str_cfg->user_str_id, + disp_pict_rendinfo->rendered_size, + req_pict_rendinfo->rendered_size); + unsupported->op_bufcfg |= + VDECDD_UNSUPPORTED_OUTPUTBUFCONFIG_BUFFER_SIZE; + } + } + + if (str_op_cfg) { + if (comseq_hdrinfo) { + if (vdec_size_lt(disp_pict_rendinfo->rend_pict_size, + comseq_hdrinfo->max_frame_size)) { + pr_warn("[USERSID=0x%08X] Buffers [%d x %d] must be large enough to contain the maximum frame size [%d x %d] when not scaling", + str_cfg->user_str_id, + disp_pict_rendinfo->rend_pict_size.width, + disp_pict_rendinfo->rend_pict_size.height, + comseq_hdrinfo->max_frame_size.width, + comseq_hdrinfo->max_frame_size.height); + unsupported->op_bufcfg |= + VDECDD_UNSUPPORTED_OUTPUTBUFCONFIG_PICTURE_SIZE; + } + } + } + } + + if (comseq_hdrinfo) { + unsigned int max_width = + vdec_size_min(core_props->vidstd_props[str_cfg->vid_std].max_width, + MAX_PLATFORM_SUPPORTED_WIDTH); + + unsigned int max_height = + vdec_size_min(core_props->vidstd_props[str_cfg->vid_std].max_height, + MAX_PLATFORM_SUPPORTED_HEIGHT); + + if (comseq_hdrinfo->max_frame_size.width > max_width || + comseq_hdrinfo->max_frame_size.height > max_height) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: FRAME WIDTH %dpx or HEIGHT %dpx are over maximum allowed value [%d, %d]", + str_cfg->user_str_id, + comseq_hdrinfo->max_frame_size.width, + comseq_hdrinfo->max_frame_size.height, + max_width, max_height); + unsupported->seq_hdr |= + VDECDD_UNSUPPORTED_SEQUHDR_SIZE; + } + + if (comseq_hdrinfo->pixel_info.bitdepth_y > + core_props->vidstd_props[str_cfg->vid_std].max_luma_bitdepth || + comseq_hdrinfo->pixel_info.bitdepth_y < 8 || + comseq_hdrinfo->pixel_info.bitdepth_y == 9) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: CODED PICTURE LUMA BIT DEPTH %d [RANGE: 8->%d for %s]", + str_cfg->user_str_id, + comseq_hdrinfo->pixel_info.bitdepth_y, + core_props->vidstd_props[str_cfg->vid_std].max_luma_bitdepth, + vid_std_names[str_cfg->vid_std]); + unsupported->seq_hdr |= + VDECDD_UNSUPPORTED_SEQUHDR_PIXFORMAT_BIT_DEPTH; + } + + if (comseq_hdrinfo->pixel_info.chroma_fmt_idc != + PIXEL_FORMAT_MONO && + (comseq_hdrinfo->pixel_info.bitdepth_c > + core_props->vidstd_props[str_cfg->vid_std].max_chroma_bitdepth || + comseq_hdrinfo->pixel_info.bitdepth_c < 8 || + comseq_hdrinfo->pixel_info.bitdepth_c == 9)) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: CODED PICTURE CHROMA BIT DEPTH %d [RANGE: 8->%d for %s]", + str_cfg->user_str_id, + comseq_hdrinfo->pixel_info.bitdepth_c, + core_props->vidstd_props[str_cfg->vid_std].max_chroma_bitdepth, + vid_std_names[str_cfg->vid_std]); + unsupported->seq_hdr |= + VDECDD_UNSUPPORTED_SEQUHDR_PIXFORMAT_BIT_DEPTH; + } + + if (comseq_hdrinfo->pixel_info.chroma_fmt_idc != + PIXEL_FORMAT_MONO && + comseq_hdrinfo->pixel_info.bitdepth_y != + comseq_hdrinfo->pixel_info.bitdepth_c) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: CODED PICTURE MIXED BIT DEPTH [%d vs %d]", + str_cfg->user_str_id, + comseq_hdrinfo->pixel_info.bitdepth_y, + comseq_hdrinfo->pixel_info.bitdepth_c); + unsupported->seq_hdr |= + VDECDD_UNSUPPORTED_SEQUHDR_PIXFORMAT_BIT_DEPTH; + } + + if (comseq_hdrinfo->pixel_info.chroma_fmt_idc > + core_props->vidstd_props[str_cfg->vid_std].max_chroma_format) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: CODED PIXEL FORMAT IDC %s [for %s]", + str_cfg->user_str_id, + comseq_hdrinfo->pixel_info.chroma_fmt_idc < + ARRAY_SIZE + (pix_fmt_idc_names) ? (unsigned char *) + pix_fmt_idc_names[comseq_hdrinfo->pixel_info.chroma_fmt_idc] : + (unsigned char *)"Invalid", + vid_std_names[str_cfg->vid_std]); + unsupported->seq_hdr |= + VDECDD_UNSUPPORTED_SEQUHDR_PIXEL_FORMAT; + } + + if (comseq_hdrinfo->pixel_info.chroma_fmt_idc == + PIXEL_FORMAT_INVALID) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[SW]: UNKNOWN CODED PIXEL FORMAT", + str_cfg->user_str_id); + unsupported->seq_hdr |= + VDECDD_UNSUPPORTED_SEQUHDR_PIXEL_FORMAT; + } + } + + if (pict_hdrinfo && comseq_hdrinfo) { + unsigned int coded_cmd_width; + unsigned int coded_cmd_height; + unsigned int min_width = core_props->vidstd_props[str_cfg->vid_std].min_width; + unsigned int min_height = + ALIGN(core_props->vidstd_props[str_cfg->vid_std].min_height, + (pict_hdrinfo->field) ? + 2 * VDEC_MB_DIMENSION : VDEC_MB_DIMENSION); + unsigned int pict_size_in_mbs; + unsigned int max_height = core_props->vidstd_props[str_cfg->vid_std].max_height; + unsigned int max_width = core_props->vidstd_props[str_cfg->vid_std].max_width; + unsigned int max_mbs = core_props->vidstd_props[str_cfg->vid_std].max_macroblocks; + +#ifdef HAS_JPEG + /* For JPEG, max picture size of four plane images is 16k*16k. */ + if (str_cfg->vid_std == VDEC_STD_JPEG) { + if (comseq_hdrinfo->pixel_info.num_planes >= 4) { + max_width = (max_width > 16 * 1024) ? 16 * 1024 : max_width; + max_height = (max_height > 16 * 1024) ? 16 * 1024 : max_height; + } + } +#endif + + coded_cmd_width = + ALIGN(pict_hdrinfo->coded_frame_size.width, VDEC_MB_DIMENSION); + coded_cmd_height = + ALIGN(pict_hdrinfo->coded_frame_size.height, + pict_hdrinfo->field ? + 2 * VDEC_MB_DIMENSION : VDEC_MB_DIMENSION); + + pict_size_in_mbs = (coded_cmd_width * coded_cmd_height) / + (VDEC_MB_DIMENSION * VDEC_MB_DIMENSION); + + if ((str_cfg->vid_std == VDEC_STD_H264 && + max_mbs && pict_size_in_mbs > max_mbs) || + coded_cmd_width > max_width || + coded_cmd_height > max_height) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: CODED PICTURE SIZE %d x %d [MAX: %d x %d or %d MBs]", + str_cfg->user_str_id, + coded_cmd_width, coded_cmd_height, + max_width, max_height, max_mbs); + unsupported->pict_hdr |= VDECDD_UNSUPPORTED_PICTHDR_RESOLUTION; + } + + if (pict_hdrinfo->coded_frame_size.width < min_width || + pict_hdrinfo->coded_frame_size.height < min_height) { +#ifdef USE_STRICT_MIN_PIC_SIZE_CHECK + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: CODED PICTURE SIZE %d x %d [MIN: %d x %d]", + str_cfg->user_str_id, + pict_hdrinfo->coded_frame_size.width, + pict_hdrinfo->coded_frame_size.height, + min_width, min_height); + unsupported->pict_hdr |= VDECDD_UNSUPPORTED_PICTHDR_RESOLUTION; +#else /* ndef USE_STRICT_MIN_PIC_SIZE_CHECK */ + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: CODED PICTURE SIZE %d x %d [MIN: %d x %d]", + str_cfg->user_str_id, + pict_hdrinfo->coded_frame_size.width, + pict_hdrinfo->coded_frame_size.height, + min_width, min_height); +#endif /* ndef USE_STRICT_MIN_PIC_SIZE_CHECK */ + } + + if (pict_hdrinfo->pict_sgm_data.id != + BSPP_INVALID && pict_hdrinfo->coded_frame_size.width > 1280) { + pr_warn("[USERSID=0x%08X] UNSUPPORTED[HW]: SGM & coded frame width > 1280", + str_cfg->user_str_id); + unsupported->pict_hdr |= + VDECDD_UNSUPPORTED_PICTHDR_OVERSIZED_SGM; + } + + if (pict_hdrinfo->discontinuous_mbs) + pr_info("Stream has Discontinuous Macroblocks"); + + decoder_get_required_core_features(str_cfg, str_op_cfg, features); + } + + if (unsupported->str_cfg == 0 && unsupported->str_opcfg == 0 && + unsupported->op_bufcfg == 0 && unsupported->pict_hdr == 0) + ret = IMG_SUCCESS; + + return ret; +} + +/* + * @Function decoder_picture_decoded + */ +static int decoder_picture_decoded(struct dec_str_ctx *dec_str_ctx, + struct dec_core_ctx *dec_core_ctx, + struct vdecdd_picture *picture, + struct dec_decpict *dec_pict, + struct bspp_pict_hdr_info *pict_hdrinfo, + struct vdecdd_str_unit *str_unit) +{ + struct dec_fwmsg *first_fld_fwmsg; + struct dec_fwmsg *second_fld_fwmsg; + struct dec_pictref_res *pict_ref_res; + unsigned int transaction_id; + struct dec_decoded_pict *decoded_pict; + struct dec_decoded_pict *next_decoded_pict; + struct vdecdd_ddbuf_mapinfo *pict_buf; + struct dec_decoded_pict *prev_decoded_pict; + struct vdecfw_buffer_control *buf_control; + struct vdec_comsequ_hdrinfo *comseq_hdrinfo; + unsigned int res_limit = 0; + unsigned int dec_pict_num = 0; + unsigned int req_pict_num = 0; + struct dec_decoded_pict *aux_decoded_pict; + struct dec_decoded_pict *displayed_decoded_pict = NULL; + int ret; + unsigned int pict_id; + struct vdec_pict_tag_container *fld_tag_container; +#ifdef ERROR_CONCEALMENT + unsigned int first_field_err_level = 0; + unsigned int second_field_err_level = 0; + unsigned int pict_last_mb = 0; +#endif + struct vxd_dec_ctx *ctx; + unsigned int error_flag = 0; + + VDEC_ASSERT(dec_str_ctx); + VDEC_ASSERT(str_unit); + VDEC_ASSERT(dec_pict); + + first_fld_fwmsg = dec_pict->first_fld_fwmsg; + second_fld_fwmsg = dec_pict->second_fld_fwmsg; + pict_ref_res = dec_pict->pict_ref_res; + transaction_id = dec_pict->transaction_id; + + VDEC_ASSERT(picture); + pict_buf = picture->disp_pict_buf.pict_buf; + VDEC_ASSERT(pict_buf); + comseq_hdrinfo = &pict_buf->ddstr_context->comseq_hdr_info; + + /* Create a container for decoded picture. */ + decoded_pict = kzalloc(sizeof(*decoded_pict), GFP_KERNEL); + VDEC_ASSERT(decoded_pict); + if (!decoded_pict) + return IMG_ERROR_OUT_OF_MEMORY; + + decoded_pict->pict = picture; + decoded_pict->first_fld_fwmsg = first_fld_fwmsg; + decoded_pict->second_fld_fwmsg = second_fld_fwmsg; + decoded_pict->pict_ref_res = pict_ref_res; + decoded_pict->transaction_id = transaction_id; + + /* Populate the decoded picture information structure. */ + picture->dec_pict_info->pict_state = VDEC_PICT_STATE_DECODED; + + memcpy(&picture->dec_pict_info->first_fld_tag_container.pict_hwcrc, + &first_fld_fwmsg->pict_hwcrc, + sizeof(picture->dec_pict_info->first_fld_tag_container.pict_hwcrc)); + + memcpy(&picture->dec_pict_info->second_fld_tag_container.pict_hwcrc, + &second_fld_fwmsg->pict_hwcrc, + sizeof(picture->dec_pict_info->second_fld_tag_container.pict_hwcrc)); + + buf_control = + (struct vdecfw_buffer_control *)decoded_pict->pict_ref_res->fw_ctrlbuf.cpu_virt; + if (buf_control->second_field_of_pair) { + /* Search the first field and fill the second_fld_tag_container */ + unsigned int prev_dec_pict_id = + get_prev_picture_id(GET_STREAM_PICTURE_ID(decoded_pict->transaction_id)); + prev_decoded_pict = + decoder_get_decoded_pict_of_stream(prev_dec_pict_id, + &dec_str_ctx->str_decd_pict_list); + + if (prev_decoded_pict) { + memcpy(&picture->dec_pict_info->second_fld_tag_container.pict_hwcrc, + &prev_decoded_pict->first_fld_fwmsg->pict_hwcrc, + sizeof + (picture->dec_pict_info->second_fld_tag_container.pict_hwcrc)); + } else { + pr_warn("[USERSID=0x%08X] [TID 0x%08X] Failed to find decoded picture to attach second_fld_tag_container", + dec_str_ctx->config.user_str_id, + decoded_pict->transaction_id); + } + prev_decoded_pict = NULL; + } + + /* Report any issues in decoding */ + if (decoded_pict->pict->dec_pict_info->err_flags) + pr_warn("[USERSID=0x%08X] [PID=0x%08X] BSPP reported errors [flags: 0x%08X]", + dec_str_ctx->config.user_str_id, + decoded_pict->pict->pict_id, + decoded_pict->pict->dec_pict_info->err_flags); + + if ((decoded_pict->first_fld_fwmsg->pict_attrs.fe_err & + FLAG_MASK(VDECFW_MSGFLAG_DECODED_FEERROR_ENTDECERROR)) || + (decoded_pict->second_fld_fwmsg->pict_attrs.fe_err & + FLAG_MASK(VDECFW_MSGFLAG_DECODED_FEERROR_ENTDECERROR))) { + pr_warn("[USERSID=0x%08X] [TID 0x%08X] Front-end HW processing terminated prematurely due to an error.", + dec_str_ctx->config.user_str_id, + decoded_pict->transaction_id); + picture->dec_pict_info->err_flags |= VDEC_ERROR_FEHW_DECODE; + } + + if ((decoded_pict->first_fld_fwmsg->pict_attrs.fe_err & + FLAG_MASK(VDECFW_MSGFLAG_DECODED_FEERROR_SRERROR)) || + (decoded_pict->second_fld_fwmsg->pict_attrs.fe_err & + FLAG_MASK(VDECFW_MSGFLAG_DECODED_FEERROR_SRERROR))) { + pr_warn("[USERSID=0x%08X] [TID 0x%08X] HW Shift Register access returned an error during FEHW parsing.", + dec_str_ctx->config.user_str_id, + decoded_pict->transaction_id); + picture->dec_pict_info->err_flags |= VDEC_ERROR_SR_ERROR; + } + + if ((decoded_pict->first_fld_fwmsg->pict_attrs.fe_err & + FLAG_MASK(VDECFW_MSGFLAG_DECODED_FEERROR_HWWDT)) || + (decoded_pict->second_fld_fwmsg->pict_attrs.fe_err & + FLAG_MASK(VDECFW_MSGFLAG_DECODED_FEERROR_HWWDT))) { + pr_warn("[USERSID=0x%08X] [TID 0x%08X] Front-end HW processing timed-out.", + dec_str_ctx->config.user_str_id, + decoded_pict->transaction_id); + picture->dec_pict_info->err_flags |= VDEC_ERROR_FEHW_TIMEOUT; + } + + if ((decoded_pict->first_fld_fwmsg->pict_attrs.fe_err & + FLAG_MASK(VDECFW_MSGFLAG_DECODED_MISSING_REFERENCES)) || + (decoded_pict->second_fld_fwmsg->pict_attrs.fe_err & + FLAG_MASK(VDECFW_MSGFLAG_DECODED_MISSING_REFERENCES))) { + pr_warn("[USERSID=0x%08X] [TID 0x%08X] There are missing references for the current frame. May have corruption", + dec_str_ctx->config.user_str_id, + decoded_pict->transaction_id); + /* + * This is not a serious error, indicate host app to drop the + * frame as may have corruption. + */ + picture->dec_pict_info->err_flags |= + VDEC_ERROR_MISSING_REFERENCES; + } + + if ((decoded_pict->first_fld_fwmsg->pict_attrs.fe_err & + FLAG_MASK(VDECFW_MSGFLAG_DECODED_MMCO_ERROR)) || + (decoded_pict->second_fld_fwmsg->pict_attrs.fe_err & + FLAG_MASK(VDECFW_MSGFLAG_DECODED_MMCO_ERROR))) { + pr_warn("[USERSID=0x%08X] [TID 0x%08X] MMCO error accured when processing the current frame. May have corruption", + dec_str_ctx->config.user_str_id, + decoded_pict->transaction_id); + + /* + * This is not a serious error, indicate host app to drop + * the frame as may have corruption. + */ + picture->dec_pict_info->err_flags |= VDEC_ERROR_MMCO; + } + + if ((decoded_pict->first_fld_fwmsg->pict_attrs.fe_err & + FLAG_MASK(VDECFW_MSGFLAG_DECODED_MBS_DROPPED_ERROR)) || + (decoded_pict->second_fld_fwmsg->pict_attrs.fe_err & + FLAG_MASK(VDECFW_MSGFLAG_DECODED_MBS_DROPPED_ERROR))) { + pr_warn("[USERSID=0x%08X] [TID 0x%08X] Some macroblocks were dropped when processing the current frame. May have corruption", + dec_str_ctx->config.user_str_id, + decoded_pict->transaction_id); + + /* + * This is not a serious error, indicate host app to + * drop the frame as may have corruption. + */ + picture->dec_pict_info->err_flags |= VDEC_ERROR_MBS_DROPPED; + } + + if (decoded_pict->first_fld_fwmsg->pict_attrs.no_be_wdt > 0) { + pr_warn("[USERSID=0x%08X] [TID 0x%08X] Back-end HW processing timed-out. Aborted slices %d", + dec_str_ctx->config.user_str_id, + decoded_pict->transaction_id, + decoded_pict->first_fld_fwmsg->pict_attrs.no_be_wdt); + picture->dec_pict_info->err_flags |= VDEC_ERROR_BEHW_TIMEOUT; + } + + if (decoded_pict->second_fld_fwmsg->pict_attrs.no_be_wdt > 0) { + pr_warn("[USERSID=0x%08X] [TID 0x%08X] Back-end HW processing timed-out. Aborted slices %d", + dec_str_ctx->config.user_str_id, + decoded_pict->transaction_id, + decoded_pict->second_fld_fwmsg->pict_attrs.no_be_wdt); + picture->dec_pict_info->err_flags |= VDEC_ERROR_BEHW_TIMEOUT; + } + +#ifdef ERROR_CONCEALMENT + /* Estimate error level in percentage */ + if (decoder_get_pict_processing_info(dec_core_ctx, dec_str_ctx, pict_hdrinfo, + decoded_pict, dec_pict, &pict_last_mb) == TRUE) { + if (pict_last_mb) { + first_field_err_level = 100 - ((100 * (pict_last_mb - + decoded_pict->first_fld_fwmsg->pict_attrs.mbs_dropped + + decoded_pict->first_fld_fwmsg->pict_attrs.mbs_recovered)) / + pict_last_mb); + + second_field_err_level = 100 - ((100 * (pict_last_mb - + decoded_pict->second_fld_fwmsg->pict_attrs.mbs_dropped + + decoded_pict->second_fld_fwmsg->pict_attrs.mbs_recovered)) / + pict_last_mb); + } + + /* does not work properly with discontinuous mbs */ + if (!pict_hdrinfo->discontinuous_mbs) + picture->dec_pict_info->err_level = first_field_err_level > + second_field_err_level ? + first_field_err_level : second_field_err_level; + + VDEC_ASSERT(picture->dec_pict_info->err_level <= 100); + if (picture->dec_pict_info->err_level) + pr_warn("[USERSID=0x%08X] [TID 0x%08X] Picture error level: %d(%%)", + dec_str_ctx->config.user_str_id, decoded_pict->transaction_id, + picture->dec_pict_info->err_level); + } +#endif + + if (decoded_pict->first_fld_fwmsg->pict_attrs.pict_attrs.dwrfired || + decoded_pict->second_fld_fwmsg->pict_attrs.pict_attrs.dwrfired) { + pr_warn("[USERSID=0x%08X] VXD Device Reset (Lockup).", + dec_str_ctx->config.user_str_id); + picture->dec_pict_info->err_flags |= + VDEC_ERROR_SERVICE_TIMER_EXPIRY; + } + + if (decoded_pict->first_fld_fwmsg->pict_attrs.pict_attrs.mmufault || + decoded_pict->second_fld_fwmsg->pict_attrs.pict_attrs.mmufault) { + pr_warn("[USERSID=0x%08X] VXD Device Reset (MMU fault).", + dec_str_ctx->config.user_str_id); + picture->dec_pict_info->err_flags |= VDEC_ERROR_MMU_FAULT; + } + + if (decoded_pict->first_fld_fwmsg->pict_attrs.pict_attrs.deverror || + decoded_pict->second_fld_fwmsg->pict_attrs.pict_attrs.deverror) { + pr_warn("[USERSID=0x%08X] VXD Device Error (e.g. firmware load failed).", + dec_str_ctx->config.user_str_id); + picture->dec_pict_info->err_flags |= VDEC_ERROR_DEVICE; + } + + /* + * Assigned error flag from the decoder error flag for error recovery. + */ + error_flag = picture->dec_pict_info->err_flags; + /* + * Loop over references, for each one find the related picture + * on the decPictList, and propagate errors if needed + */ + ret = + decoder_check_ref_errors(dec_str_ctx, (struct vdecfw_buffer_control *) + decoded_pict->pict_ref_res->fw_ctrlbuf.cpu_virt, + picture); + VDEC_ASSERT(ret == IMG_SUCCESS); + + if (dec_str_ctx->config.vid_std == VDEC_STD_H264) { + /* Attach the supplementary data to the decoded picture. */ + picture->dec_pict_sup_data.raw_vui_data = + pict_hdrinfo->h264_pict_hdr_info.raw_vui_data; + pict_hdrinfo->h264_pict_hdr_info.raw_vui_data = NULL; + + picture->dec_pict_sup_data.raw_sei_list_first_fld = + pict_hdrinfo->h264_pict_hdr_info.raw_sei_data_list_first_field; + pict_hdrinfo->h264_pict_hdr_info.raw_sei_data_list_first_field = NULL; + + picture->dec_pict_sup_data.raw_sei_list_second_fld = + pict_hdrinfo->h264_pict_hdr_info.raw_sei_data_list_second_field; + pict_hdrinfo->h264_pict_hdr_info.raw_sei_data_list_second_field = NULL; + + picture->dec_pict_sup_data.h264_pict_supl_data.nal_ref_idc = + pict_hdrinfo->h264_pict_hdr_info.nal_ref_idc; + + picture->dec_pict_sup_data.h264_pict_supl_data.frame_num = + pict_hdrinfo->h264_pict_hdr_info.frame_num; + } + +#ifdef HAS_HEVC + if (dec_str_ctx->config.vid_std == VDEC_STD_HEVC) { + /* Attach the supplementary data to the decoded picture. */ + picture->dec_pict_sup_data.raw_vui_data = + pict_hdrinfo->hevc_pict_hdr_info.raw_vui_data; + + pict_hdrinfo->hevc_pict_hdr_info.raw_vui_data = NULL; + + picture->dec_pict_sup_data.raw_sei_list_first_fld = + pict_hdrinfo->hevc_pict_hdr_info.raw_sei_datalist_firstfield; + + pict_hdrinfo->hevc_pict_hdr_info.raw_sei_datalist_firstfield = NULL; + + picture->dec_pict_sup_data.raw_sei_list_second_fld = + pict_hdrinfo->hevc_pict_hdr_info.raw_sei_datalist_secondfield; + + pict_hdrinfo->hevc_pict_hdr_info.raw_sei_datalist_secondfield = NULL; + + picture->dec_pict_sup_data.hevc_pict_supl_data.pic_order_cnt = + buf_control->hevc_data.pic_order_count; + } +#endif + + if (!((buf_control->dec_pict_type == IMG_BUFFERTYPE_PAIR && + VDECFW_PICMGMT_FIELD_CODED_PICTURE_EXECUTED(buf_control->picmgmt_flags)) || + FLAG_IS_SET(buf_control->picmgmt_flags, VDECFW_PICMGMTFLAG_PICTURE_EXECUTED))) { + pr_warn("[USERSID=0x%08X] [TID 0x%08X] Picture management was not executed for this picture; forcing display.", + dec_str_ctx->config.user_str_id, + decoded_pict->transaction_id); + decoded_pict->force_display = TRUE; + } + + dec_str_ctx->dec_str_st.total_pict_finished++; + + /* + * Use NextPictIdExpected to do this check. ui32NextPictId could be + * different from what expected at this point because we failed to + * process a picture the last time run this function (this is still + * an error (unless doing multi-core) but not the error reported here. + */ + if (picture->pict_id != dec_str_ctx->next_pict_id_expected) { + pr_warn("[USERSID=0x%08X] ERROR: MISSING DECODED PICTURE (%d)", + dec_str_ctx->config.user_str_id, + dec_str_ctx->next_dec_pict_id); + } + + dec_str_ctx->next_dec_pict_id = + get_next_picture_id(GET_STREAM_PICTURE_ID(decoded_pict->transaction_id)); + dec_str_ctx->next_pict_id_expected = dec_str_ctx->next_dec_pict_id; + + /* Add the picture itself to the decoded list */ + next_decoded_pict = dq_first(&dec_str_ctx->str_decd_pict_list); + while (next_decoded_pict && + !HAS_X_REACHED_Y(GET_STREAM_PICTURE_ID(next_decoded_pict->transaction_id), + picture->pict_id, + 1 << FWIF_NUMBITS_STREAM_PICTURE_ID, unsigned int)) { + if (next_decoded_pict != + dq_last(&dec_str_ctx->str_decd_pict_list)) + next_decoded_pict = dq_next(next_decoded_pict); + else + next_decoded_pict = NULL; + } + + if (next_decoded_pict) + dq_addbefore(next_decoded_pict, decoded_pict); + else + dq_addtail(&dec_str_ctx->str_decd_pict_list, decoded_pict); + + dec_str_ctx->dec_str_st.num_pict_decoded++; + + pr_debug("%s : number of picture decoded = %d\n" + , __func__, dec_str_ctx->dec_str_st.num_pict_decoded); + /* Process the decoded pictures in the encoded order */ + decoded_pict = dq_first(&dec_str_ctx->str_decd_pict_list); + VDEC_ASSERT(decoded_pict); + if (!decoded_pict) + return IMG_ERROR_UNEXPECTED_STATE; + + ret = dec_str_ctx->str_processed_cb((void *)dec_str_ctx->usr_int_data, + VXD_CB_PICT_DECODED, (void *)picture); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + /* + * Loop on the unprocessed pictures until we failed to process one + * or we have processed them all + */ + for (next_decoded_pict = decoder_next_picture(decoded_pict, + dec_str_ctx->next_dec_pict_id, + &dec_str_ctx->str_decd_pict_list); + next_decoded_pict; + next_decoded_pict = decoder_next_picture(decoded_pict, + dec_str_ctx->next_dec_pict_id, + &dec_str_ctx->str_decd_pict_list)) { + unsigned int i = 0; + struct dec_decoded_pict *display_pict = NULL; + struct dec_decoded_pict *release_pict = NULL; + unsigned char last_to_display_for_seq = FALSE; + + /* + * next_decoded_pict is used to temporarily store decoded_pict + * so that we can clear the bProcessFailed flag before + * returning + */ + decoded_pict = next_decoded_pict; + if (!decoded_pict->force_display) { + struct vdecfw_buffer_control *buf_ctrl = NULL; + + buf_ctrl = (struct vdecfw_buffer_control *) + decoded_pict->pict_ref_res->fw_ctrlbuf.cpu_virt; + + if (buf_ctrl->real_data.width && buf_ctrl->real_data.height) { + /* + * Firmware sets image size as it is in + * bitstream. + */ + picture->dec_pict_info->disp_info.disp_region.width = + buf_ctrl->real_data.width; + picture->dec_pict_info->disp_info.disp_region.height = + buf_ctrl->real_data.height; + picture->dec_pict_info->disp_info.disp_region.top_offset = 0; + picture->dec_pict_info->disp_info.disp_region.left_offset = 0; + + picture->dec_pict_info->rend_info.rend_pict_size.width = + picture->dec_pict_info->disp_info.disp_region.width; + picture->dec_pict_info->rend_info.rend_pict_size.height = + picture->dec_pict_info->disp_info.disp_region.height; + + /* + * Update encoded size with values coded in + * bitstream,so golden image can be loaded + * correctly + */ + picture->dec_pict_info->disp_info.enc_disp_region.width = + buf_ctrl->real_data.width; + picture->dec_pict_info->disp_info.enc_disp_region.height = + buf_ctrl->real_data.height; + } + + decoded_pict->pict->dec_pict_info->timestamp = + buf_ctrl->real_data.timestamp; + decoded_pict->pict->dec_pict_info->disp_info.top_fld_first = + buf_ctrl->top_field_first; + decoded_pict->pict->dec_pict_info->disp_info.top_fld_first = + buf_ctrl->top_field_first; + + decoded_pict->pict->dec_pict_info->id_for_hwcrc_chk = + GET_STREAM_PICTURE_ID(decoded_pict->transaction_id) - 1; + decoded_pict->pict->dec_pict_info->id_for_hwcrc_chk += + dec_str_ctx->dec_str_st.flds_as_frm_decodes; + + if (buf_ctrl->dec_pict_type == IMG_BUFFERTYPE_PAIR && + !buf_ctrl->second_field_of_pair) + dec_str_ctx->dec_str_st.flds_as_frm_decodes++; + + if (buf_ctrl->second_field_of_pair) { + /* + * Second field of pair is always complementary + * type to the eFirstPictTagType of the + * previous picture + */ + unsigned int prev_dec_pict_id = + get_prev_picture_id(GET_STREAM_PICTURE_ID(decoded_pict->transaction_id)); + + prev_decoded_pict = + decoder_get_decoded_pict_of_stream + (prev_dec_pict_id, + &dec_str_ctx->str_decd_pict_list); + if (prev_decoded_pict) { + fld_tag_container = + &prev_decoded_pict->pict->dec_pict_info->second_fld_tag_container; + fld_tag_container->pict_tag_param = + decoded_pict->pict->dec_pict_info->first_fld_tag_container.pict_tag_param; + + /* + * Copy the first field info in the + * proper place + */ + memcpy(&fld_tag_container->pict_hwcrc, + &first_fld_fwmsg->pict_hwcrc, + sizeof(fld_tag_container->pict_hwcrc)); + + /* + * Attach the raw SEI data list for a + * second field to a picture. + */ + prev_decoded_pict->pict->dec_pict_sup_data.raw_sei_list_second_fld = + decoded_pict->pict->dec_pict_sup_data.raw_sei_list_first_fld; + + prev_decoded_pict->pict->dec_pict_info->disp_info.top_fld_first = + buf_ctrl->top_field_first; + + /* Mark this picture as merged fields. */ + prev_decoded_pict->pict->dec_pict_sup_data.merged_flds = + TRUE; + /* Mark the picture that was merged to the previous one. */ + decoded_pict->merged = TRUE; + } else { + pr_warn("[USERSID=0x%08X] [TID 0x%08X] Failed to find decoded picture to attach tag", + dec_str_ctx->config.user_str_id, + decoded_pict->transaction_id); + } + } else { + /* + * Not Second-field-of-pair picture tag + * correlates its Tag to the its type by + * setting the eFirstPictTagType in the + * following way + */ + decoded_pict->pict->dec_pict_info->first_fld_tag_container.pict_type + = + buf_ctrl->dec_pict_type; + memcpy(&picture->dec_pict_info->first_fld_tag_container.pict_hwcrc, + &first_fld_fwmsg->pict_hwcrc, + sizeof + (picture->dec_pict_info->first_fld_tag_container.pict_hwcrc)); + } + + /* + * Update the id of the next picture to process. It has + * to be update always (even if we fail to process) + * This has to be a global flag because it will be + * passed in both decoder_NextPicture (and then to + * DECODER_NextDecPictContiguous inside it) + * and to the corner case check below + */ + dec_str_ctx->next_dec_pict_id = + get_next_picture_id(GET_STREAM_PICTURE_ID + (decoded_pict->transaction_id)); + /* + * Display all the picture in the list that have been + * decoded and signalled by the fw to be displayed + */ + for (i = decoded_pict->disp_idx; + i < buf_ctrl->display_list_length && + !decoded_pict->process_failed; + i++, decoded_pict->disp_idx++) { + /* + * Display picture if it has been decoded + * (i.e. in decoded list). + */ + display_pict = decoder_get_decoded_pict + (buf_ctrl->display_list[i], + &dec_str_ctx->str_decd_pict_list); + if (display_pict) { + if (FLAG_IS_SET(buf_ctrl->display_flags[i], + VDECFW_BUFFLAG_DISPLAY_FIELD_CODED) && + (!FLAG_IS_SET + (buf_ctrl->display_flags[i], + VDECFW_BUFFLAG_DISPLAY_SINGLE_FIELD))) { + display_pict->pict->dec_pict_info->buf_type = + IMG_BUFFERTYPE_PAIR; + if (FLAG_IS_SET + (buf_ctrl->display_flags[i], + VDECFW_BUFFLAG_DISPLAY_INTERLACED_FIELDS)) + display_pict->pict->dec_pict_info->interlaced_flds = + TRUE; + } else if (FLAG_IS_SET + (buf_ctrl->display_flags[i], + VDECFW_BUFFLAG_DISPLAY_FIELD_CODED) && + FLAG_IS_SET + (buf_ctrl->display_flags[i], + VDECFW_BUFFLAG_DISPLAY_SINGLE_FIELD)) { + display_pict->pict->dec_pict_info->buf_type = + FLAG_IS_SET + (buf_ctrl->display_flags[i], + VDECFW_BUFFLAG_DISPLAY_BOTTOM_FIELD) ? + IMG_BUFFERTYPE_FIELD_BOTTOM : + IMG_BUFFERTYPE_FIELD_TOP; + } else { + display_pict->pict->dec_pict_info->buf_type = + IMG_BUFFERTYPE_FRAME; + } + + display_pict->pict->dec_pict_info->view_id = + buf_ctrl->display_view_ids[i]; + + /* + * When no reference pictures are left to + * display and this is the last display + * picture in response to the last decoded + * picture, signal. + */ + if (decoded_pict->pict->last_pict_in_seq && + i == (buf_ctrl->display_list_length - 1)) + last_to_display_for_seq = TRUE; + + if (!display_pict->displayed) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] [TID=0x%08X] DISPLAY", + dec_str_ctx->config.user_str_id, + buf_ctrl->display_list[i]); +#endif + display_pict->displayed = TRUE; + pict_id = GET_STREAM_PICTURE_ID + (buf_ctrl->display_list[i]); + + ret = decoder_picture_display + (dec_str_ctx, pict_id, + last_to_display_for_seq); + } + } else { + /* + * In single core scenario should + * not come here. + */ + pr_warn("[USERSID=0x%08X] Failed to find decoded picture [TID = 0x%08X] to send for display", + dec_str_ctx->config.user_str_id, + buf_ctrl->display_list[i]); + } + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + + /* Release all unused pictures (firmware request) */ + for (i = decoded_pict->rel_idx; + i < buf_ctrl->release_list_length && + !decoded_pict->process_failed; + i++, decoded_pict->rel_idx++) { + release_pict = decoder_get_decoded_pict + (buf_ctrl->release_list[i], + &dec_str_ctx->str_decd_pict_list); + if (release_pict) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] RELEASE( ): PIC_ID[%d]", + dec_str_ctx->config.user_str_id, + release_pict->pict->pict_id); +#endif + /* + * Signal releasing this picture to upper + * layers. + */ + decoder_picture_release(dec_str_ctx, + GET_STREAM_PICTURE_ID + (buf_ctrl->release_list[i]), + release_pict->displayed, + release_pict->merged); + if (release_pict->processed) { + /* + * If the decoded picture has been + * processed, destroy now. + */ + ret = decoder_decoded_picture_destroy(dec_str_ctx, + release_pict, + FALSE); + } else { + /* + * If the decoded picture is not + * processed just destroy the + * containing picture. + */ + pict_id = GET_STREAM_PICTURE_ID + (buf_ctrl->release_list[i]); + ret = decoder_picture_destroy(dec_str_ctx, + pict_id, FALSE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + release_pict->pict = NULL; + } + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } else { + /* + * In single core scenario should not + * come here. + */ +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] Failed to find decoded picture [TID = 0x%08X] to release", + dec_str_ctx->config.user_str_id, + buf_ctrl->release_list[i]); +#endif + } + } + } else { + /* Always display the picture if we have no hardware */ + if (!decoded_pict->displayed) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] [TID=0x%08X] DISPLAY", + dec_str_ctx->config.user_str_id, + decoded_pict->transaction_id); +#endif + decoded_pict->displayed = TRUE; + ret = decoder_picture_display + (dec_str_ctx, + decoded_pict->pict->pict_id, + decoded_pict->pict->last_pict_in_seq); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + + /* Always release the picture if we have no hardware */ + ret = decoder_picture_destroy(dec_str_ctx, + decoded_pict->pict->pict_id, + FALSE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + decoded_pict->pict = NULL; + } + + /* If we have processed the current picture */ + if (!decoded_pict->process_failed) { + decoded_pict->processed = TRUE; + + /* + * If the current picture has been released then + * remove the container from the decoded list + */ + if (!decoded_pict->pict) { + /* + * Only destroy the decoded picture once it is processed + * and the fw has instructed to release the picture. + */ + ret = decoder_decoded_picture_destroy(dec_str_ctx, + decoded_pict, FALSE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + decoded_pict = NULL; + } /* end if (decoded_pict->pict == NULL) */ + } /* end if (!decoded_pict->process_failed) */ + } /* end for */ + + /* + * Always clear the process_failed flag to ensure that this picture + * will be processed on the next function call + */ + if (decoded_pict) + decoded_pict->process_failed = FALSE; + + /* + * Go through the list of decoded pictures to check if there are any + * pictures left for displaying and that are still not displayed due + * to picture management errors. + * Get the minimum required number of picture buffers. + */ + vdecddutils_ref_pict_get_maxnum(&dec_str_ctx->config, + comseq_hdrinfo, &req_pict_num); + req_pict_num += comseq_hdrinfo->interlaced_frames ? 2 : 1; + + ret = dec_str_ctx->core_query_cb(dec_str_ctx->usr_int_data, + DECODER_CORE_GET_RES_LIMIT, + &res_limit); + + /* Start the procedure only if there is enough resources available. */ + if (res_limit >= req_pict_num) { + /* Allow for one picture buffer for display. */ + res_limit--; + + /* + * Count the number of decoded pictures that were not + * displayed yet. + */ + aux_decoded_pict = dq_first(&dec_str_ctx->str_decd_pict_list); + while (aux_decoded_pict) { + if (aux_decoded_pict->pict) { + dec_pict_num++; + if (!displayed_decoded_pict) + displayed_decoded_pict = + aux_decoded_pict; + } + if (aux_decoded_pict != + dq_last(&dec_str_ctx->str_decd_pict_list)) + aux_decoded_pict = dq_next(aux_decoded_pict); + else + aux_decoded_pict = NULL; + } + } + + /* If there is at least one not displayed picture... */ + if (displayed_decoded_pict) { + /* + * While the number of not displayed decoded pictures exceeds + * the number of maximum allowed number of pictures being held + * by VDEC... + */ + while (dec_pict_num > res_limit) { + pr_warn("[USERSID=0x%08X] Number of outstanding decoded pictures exceeded number of available pictures buffers.", + dec_str_ctx->config.user_str_id); + + if (!displayed_decoded_pict) { + VDEC_ASSERT(0); + return -EINVAL; + } + /* Find the picture with the least picture id. */ + aux_decoded_pict = dq_next(displayed_decoded_pict); + while (aux_decoded_pict) { + if (aux_decoded_pict != + dq_last(&dec_str_ctx->str_decd_pict_list)) { + if (aux_decoded_pict->pict && + aux_decoded_pict->pict->pict_id < + displayed_decoded_pict->pict->pict_id) + displayed_decoded_pict = aux_decoded_pict; + + aux_decoded_pict = dq_next(aux_decoded_pict); + } else { + if (aux_decoded_pict->pict && + aux_decoded_pict->pict->pict_id < + displayed_decoded_pict->pict->pict_id) + displayed_decoded_pict = aux_decoded_pict; + + aux_decoded_pict = NULL; + } + } + + /* Display and release the picture with the least picture id. */ + if (!displayed_decoded_pict->displayed) { + pr_warn("[USERSID=0x%08X] [TID=0x%08X] DISPLAY FORCED", + dec_str_ctx->config.user_str_id, + displayed_decoded_pict->transaction_id); + displayed_decoded_pict->displayed = TRUE; + ret = decoder_picture_display + (dec_str_ctx, + displayed_decoded_pict->pict->pict_id, + displayed_decoded_pict->pict->last_pict_in_seq); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } + + ret = decoder_picture_destroy(dec_str_ctx, + displayed_decoded_pict->pict->pict_id, + FALSE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + displayed_decoded_pict->pict = NULL; + displayed_decoded_pict->processed = TRUE; + + ret = decoder_decoded_picture_destroy(dec_str_ctx, displayed_decoded_pict, + FALSE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + displayed_decoded_pict = NULL; + + /* + * Decrease the number of not displayed decoded + * pictures. + */ + dec_pict_num--; + } + } + +#ifdef ERROR_RECOVERY_SIMULATION + /* + * This part of the code should execute only when, DEBUG_FW_ERR_RECOVERY + * flag is enabled. This basically reads the error flag attribute from + * user space to create fake errors for testing the firmware error + * recovery. + */ + if (fw_error_value != VDEC_ERROR_MAX) { + error_flag = error_flag | (1 << fw_error_value); + /* Now lets make it VDEC_ERROR_MAX */ + fw_error_value = VDEC_ERROR_MAX; + } +#endif + + /* + * Whenever the error flag is set, we need to handle the error case. + * Need to forward this error to stream processed callback. + */ + switch (error_flag) { + case VDEC_ERROR_NONE: + case VDEC_ERROR_CORRUPTED_REFERENCE: + case VDEC_ERROR_MISSING_REFERENCES: + case VDEC_ERROR_MMCO: + case VDEC_ERROR_MBS_DROPPED: + /* these are not fatal */ + break; + default: + /* anything else is */ + pr_err("%s : %d err_flags: 0x%x\n", __func__, __LINE__, error_flag); + ret = dec_str_ctx->str_processed_cb((void *)dec_str_ctx->usr_int_data, + VXD_CB_ERROR_FATAL, &error_flag); + break; + } + /* + * check for eos on bitstream and propagate the same to picture + * buffer + */ + ctx = dec_str_ctx->vxd_dec_ctx; + ctx->num_decoding--; + if (ctx->eos) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("EOS reached\n"); +#endif + ret = dec_str_ctx->str_processed_cb((void *)dec_str_ctx->usr_int_data, + VXD_CB_STR_END, NULL); + VDEC_ASSERT(ret == IMG_SUCCESS); + } + + return ret; +} + +/* + * @Function decoder_service_firmware_response + */ +int decoder_service_firmware_response(void *dec_str_ctx_arg, unsigned int *msg, + unsigned int msg_size, unsigned int msg_flags) +{ + int ret = IMG_SUCCESS; + struct dec_decpict *dec_pict = NULL; + unsigned char head_of_queue = TRUE; + struct dec_str_ctx *dec_str_ctx; + struct dec_str_unit *dec_str_unit; + unsigned char pict_start = FALSE; + enum vdecdd_str_unit_type str_unit_type; + struct vdecdd_picture *picture; + struct decoder_pict_fragment *pict_fragment; + struct dec_str_ctx *dec_strctx; + struct dec_core_ctx *dec_core_ctx; + + /* validate input arguments */ + if (!dec_str_ctx_arg || !msg) { + VDEC_ASSERT(0); + return IMG_ERROR_INVALID_PARAMETERS; + } + + dec_strctx = decoder_stream_get_context(dec_str_ctx_arg); + + dec_core_ctx = decoder_str_ctx_to_core_ctx(dec_strctx); + + if (!dec_core_ctx) { + pr_err("%s: dec_core_ctx is NULL\n", __func__); + VDEC_ASSERT(0); + return IMG_ERROR_INVALID_PARAMETERS; + } + + pr_debug("%s : process firmware response\n", __func__); + ret = hwctrl_process_msg(dec_core_ctx->hw_ctx, msg_flags, msg, &dec_pict); + VDEC_ASSERT((ret == IMG_SUCCESS) | (ret == IMG_ERROR_FATAL)); + if (ret != IMG_SUCCESS) + return ret; + + if (!dec_pict || (dec_pict->state != DECODER_PICTURE_STATE_DECODED && + dec_pict->state != DECODER_PICTURE_STATE_TO_DISCARD)) + return IMG_ERROR_UNEXPECTED_STATE; + + /* + * Try and locate the stream context in the list of active + * streams. + */ + VDEC_ASSERT(dec_core_ctx->dec_ctx); + dec_str_ctx = lst_first(&dec_core_ctx->dec_ctx->str_list); + if (!dec_str_ctx) { + VDEC_ASSERT(0); + return -EINVAL; + } + + while (dec_str_ctx) { + if (dec_str_ctx == dec_pict->dec_str_ctx) + break; + + dec_str_ctx = lst_next(dec_str_ctx); + } + + /* + * If the stream is not in the list of active streams then + * it must have been destroyed. + * This interrupt should be ignored. + */ + if (dec_str_ctx != dec_pict->dec_str_ctx) + return IMG_SUCCESS; + + /* + * Retrieve the picture from the head of the core decode queue + * primarily to obtain the correct stream context. + */ + hwctrl_removefrom_piclist(dec_core_ctx->hw_ctx, dec_pict); + + if (!dec_str_ctx) { + VDEC_ASSERT(0); + return -EINVAL; + } + dec_str_ctx->avail_slots++; + VDEC_ASSERT(dec_str_ctx->avail_slots > 0); + + /* + * Store the stream context of the picture that has been + * decoded. + */ + dec_str_ctx = dec_pict->dec_str_ctx; + VDEC_ASSERT(dec_str_ctx); + + if (!dec_str_ctx) + return IMG_ERROR_UNEXPECTED_STATE; + + /* + * Picture has been discarded before EOP unit, + * recover the decoder to valid state + */ + if (!dec_pict->eop_found) { + VDEC_ASSERT(dec_pict == dec_str_ctx->cur_pict); + + dec_core_ctx->busy = FALSE; + dec_str_ctx->cur_pict = NULL; + } + + /* + * Peek the first stream unit and validate against core + * queue to ensure that this really is the next picture + * for the stream. + */ + dec_str_unit = lst_first(&dec_str_ctx->pend_strunit_list); + if (dec_str_unit) { + if (dec_str_unit->dec_pict != dec_pict) { + head_of_queue = FALSE; + + /* + * For pictures to be decoded + * out-of-order there must be + * more than one decoder core. + */ + VDEC_ASSERT(dec_str_ctx->decctx->num_pipes > 1); + while (dec_str_unit) { + dec_str_unit = lst_next(dec_str_unit); + if (dec_str_unit->dec_pict == dec_pict) + break; + } + } + VDEC_ASSERT(dec_str_unit); + if (!dec_str_unit) + return IMG_ERROR_FATAL; + + VDEC_ASSERT(dec_str_unit->dec_pict == dec_pict); + VDEC_ASSERT(dec_str_unit->str_unit->str_unit_type == + VDECDD_STRUNIT_PICTURE_START); + } + + /* + * Process all units from the pending stream list until + * the next picture start. + */ + while (dec_str_unit && !pict_start) { + /* + * Actually remove the unit now from the + * pending stream list. + */ + lst_remove(&dec_str_ctx->pend_strunit_list, dec_str_unit); + if (!dec_str_unit->str_unit || !dec_pict) + break; + + str_unit_type = dec_str_unit->str_unit->str_unit_type; + + if (str_unit_type != VDECDD_STRUNIT_PICTURE_START) + break; + + dec_str_ctx = dec_pict->dec_str_ctx; + + dec_str_ctx->dec_str_st.num_pict_decoding--; + dec_str_ctx->dec_str_st.total_pict_decoded++; + + ret = idgen_gethandle(dec_str_ctx->pict_idgen, + GET_STREAM_PICTURE_ID(dec_str_unit->dec_pict->transaction_id), + (void **)&picture); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS || !picture) { + pr_err("[USERSID=0x%08X] Failed to find picture from ID", + dec_str_ctx->config.user_str_id); + return IMG_ERROR_INVALID_ID; + } + + VDEC_ASSERT(picture == dec_str_unit->str_unit->dd_pict_data); + + /* Hold a reference to the last context on the BE */ + if (dec_str_ctx->last_be_pict_dec_res && HAS_X_PASSED_Y + (picture->pict_id, + GET_STREAM_PICTURE_ID(dec_str_ctx->last_be_pict_dec_res->transaction_id), + 1 << FWIF_NUMBITS_STREAM_PICTURE_ID, unsigned int)) { + /* Return previous last FW context. */ + resource_item_return(&dec_str_ctx->last_be_pict_dec_res->ref_cnt); + + if (resource_item_isavailable(&dec_str_ctx->last_be_pict_dec_res->ref_cnt + )) { + resource_list_remove(&dec_str_ctx->dec_res_lst, + dec_str_ctx->last_be_pict_dec_res); + resource_list_add_img(&dec_str_ctx->dec_res_lst, + dec_str_ctx->last_be_pict_dec_res, 0, + &dec_str_ctx->last_be_pict_dec_res->ref_cnt); + } + } + if (!dec_str_ctx->last_be_pict_dec_res || + (dec_str_ctx->last_be_pict_dec_res && HAS_X_PASSED_Y + (picture->pict_id, + GET_STREAM_PICTURE_ID(dec_str_ctx->last_be_pict_dec_res->transaction_id), + 1 << FWIF_NUMBITS_STREAM_PICTURE_ID, unsigned int))) { + /* Hold onto last FW context. */ + dec_str_ctx->last_be_pict_dec_res = dec_pict->cur_pict_dec_res; + resource_item_use(&dec_str_ctx->last_be_pict_dec_res->ref_cnt); + } + resource_item_return(&dec_pict->cur_pict_dec_res->ref_cnt); + + if (resource_item_isavailable(&dec_pict->cur_pict_dec_res->ref_cnt)) { + resource_list_remove(&dec_str_ctx->dec_res_lst, + dec_pict->cur_pict_dec_res); + resource_list_add_img(&dec_str_ctx->dec_res_lst, + dec_pict->cur_pict_dec_res, 0, + &dec_pict->cur_pict_dec_res->ref_cnt); + } +#ifdef DEBUG_DECODER_DRIVER + pr_info("[USERSID=0x%08X] [TID=0x%08X] DECODED", + dec_str_ctx->config.user_str_id, + dec_pict->transaction_id); +#endif + + ret = decoder_picture_decoded(dec_str_ctx, dec_core_ctx, + picture, dec_pict, + dec_pict->pict_hdr_info, + dec_str_unit->str_unit); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dec_res_picture_detach(&dec_str_ctx->resources, dec_pict); + + /* Free the segments from the decode picture */ + decoder_clean_bitstr_segments(&dec_pict->dec_pict_seg_list); + + pict_fragment = lst_removehead(&dec_pict->fragment_list); + while (pict_fragment) { + kfree(pict_fragment); + pict_fragment = + lst_removehead(&dec_pict->fragment_list); + } + + pict_start = (!head_of_queue) ? TRUE : FALSE; + + ret = dec_str_ctx->str_processed_cb(dec_str_ctx->usr_int_data, + VXD_CB_STRUNIT_PROCESSED, + dec_str_unit->str_unit); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) { + /* Free decoder picture */ + kfree(dec_pict); + dec_pict = NULL; + return ret; + } + + /* Destroy the Decoder stream unit wrapper */ + kfree(dec_str_unit); + + /* Peek at the next stream unit */ + dec_str_unit = lst_first(&dec_str_ctx->pend_strunit_list); + if (dec_str_unit) + pict_start = (dec_str_unit->str_unit->str_unit_type == + VDECDD_STRUNIT_PICTURE_START && + dec_str_unit->dec_pict != dec_pict); + + /* Free decoder picture */ + kfree(dec_pict); + dec_pict = NULL; + } + + kfree(dec_str_unit); + return ret; +} + +/* + * @Function decoder_is_stream_idle + */ +unsigned char decoder_is_stream_idle(void *dec_str_ctx_handle) +{ + struct dec_str_ctx *dec_str_ctx; + + dec_str_ctx = decoder_stream_get_context(dec_str_ctx_handle); + VDEC_ASSERT(dec_str_ctx); + if (!dec_str_ctx) { + pr_err("Invalid decoder stream context handle!"); + return FALSE; + } + + return lst_empty(&dec_str_ctx->pend_strunit_list); +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/decoder.h b/drivers/media/platform/imagination/vxe-vxd/decoder/decoder.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/decoder.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/decoder.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,376 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD Decoder Component header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#ifndef __DECODER_H__ +#define __DECODER_H__ + +#include "bspp.h" +#include "dq.h" +#ifdef HAS_JPEG +#include "jpegfw_data.h" +#endif +#include "lst.h" +#include "vdecdd_defs.h" +#include "vdec_defs.h" +#include "vid_buf.h" +#include "vxd_ext.h" +#include "vxd_props.h" +#include "hevcfw_data.h" + +#define MAX_CONCURRENT_STREAMS 16 +#define CORE_NUM_DECODE_SLOTS 2 + +enum dec_pict_states { + DECODER_PICTURE_STATE_TO_DECODE = 0, + DECODER_PICTURE_STATE_DECODED, + DECODER_PICTURE_STATE_TO_DISCARD, + DECODER_PICTURE_STATE_MAX, + DECODER_PICTURE_FORCE32BITS = 0x7FFFFFFFU +}; + +enum dec_res_type { + DECODER_RESTYPE_TRANSACTION = 0, + DECODER_RESTYPE_HDR, + DECODER_RESTYPE_BATCH_MSG, +#ifdef HAS_HEVC + DECODER_RESTYPE_PVDEC_BUF, +#endif + DECODER_RESTYPE_MAX, + DECODER_RESTYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +enum dec_core_query_type { + DECODER_CORE_GET_RES_LIMIT = 0, + DECODER_CORE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * @Function pfnRefPicGetMaxNum + * @Description + * This is the prototype for functions calculating the maximum number + * of reference pictures required per video standard. + * + * @Input psComSequHdrInfo : A pointer to the common VSH information + * structure. + * + * @Output pui32MaxRefPicNum : A pointer used to return the maximum number + * of reference frames required. + * + * @Return IMG_RESULT : This function returns either IMG_SUCCESS or + * an error code. + */ +typedef int (*ref_pic_get_maximum)(const struct vdec_comsequ_hdrinfo *comseq_hdr_info, + unsigned int *max_ref_pict_num); + +typedef int (*strunit_processed_cb)(void *handle, int cb_type, void *item); + +typedef int (*core_gen_cb)(void *handle, int query, void *item); + +struct dec_ctx; + +/* + * This structure contains the core context. + * @brief Decoder Core Context + */ +struct dec_core_ctx { + void **link; /* to be part of single linked list */ + struct dec_ctx *dec_ctx; + unsigned char enumerated; + unsigned char master; + unsigned char configured; + unsigned int core_features; + unsigned int pipe_features[VDEC_MAX_PIXEL_PIPES]; + struct vxd_coreprops core_props; + void *resources; + void *hw_ctx; + unsigned int cum_pics; + unsigned char busy; +}; + +struct dec_ctx { + unsigned char inited; + void *user_data; + const struct vdecdd_dd_devconfig *dev_cfg; + unsigned int num_pipes; + struct dec_core_ctx *dec_core_ctx; + struct lst_t str_list; + void *mmu_dev_handle; + void *dev_handle; + struct vidio_ddbufinfo ptd_buf_info; + unsigned char sup_stds[VDEC_STD_MAX]; + unsigned int internal_heap_id; + unsigned int str_cnt; +}; + +/* + * This structure contains the device decode resource (used for decoding and + * held for subsequent decoding). + * @brief Decoder Device Resource + */ +struct dec_pictdec_res { + void **link; /* to be part of single linked list */ + unsigned int transaction_id; + struct vidio_ddbufinfo fw_ctx_buf; + struct vidio_ddbufinfo h264_sgm_buf; + unsigned int ref_cnt; +}; + +struct dec_decpict; + +/* + * + * This structure contains the stream context. + * @brief Decoder Stream Context + */ +struct dec_str_ctx { + void **link; /* to be part of single linked list */ + int km_str_id; + struct vdec_str_configdata config; + struct dec_ctx *decctx; + void *vxd_dec_ctx; + void *usr_int_data; + void *mmu_str_handle; + void *pict_idgen; + struct lst_t pend_strunit_list; + struct dq_linkage_t str_decd_pict_list; + unsigned int num_ref_res; + struct lst_t ref_res_lst; + unsigned int num_dec_res; + struct lst_t dec_res_lst; + unsigned int avail_pipes; + unsigned int avail_slots; + struct vdecdd_decstr_status dec_str_st; + struct vidio_ddbufinfo pvdec_fw_ctx_buf; + unsigned int last_fe_transaction_id; + unsigned int next_dec_pict_id; + unsigned int next_pict_id_expected; + struct dec_pictdec_res *cur_fe_pict_dec_res; + struct dec_pictdec_res *prev_fe_pict_dec_res; + struct dec_pictdec_res *last_be_pict_dec_res; + struct dec_decpict *cur_pict; + void *resources; + strunit_processed_cb str_processed_cb; + core_gen_cb core_query_cb; +}; + +/* + * Resource Structure for DECODER_sDdResourceInfo to be used with pools + */ +struct res_resinfo { + void **link; /* to be part of single linked list */ + void *res; + struct vidio_ddbufinfo *ddbuf_info; +}; + +struct vdecdd_ddstr_ctx; + +/* + * This structure contains the Decoded attributes + * @brief Decoded attributes + */ +struct dec_pict_attrs { + unsigned char first_fld_rcvd; + unsigned int fe_err; + unsigned int no_be_wdt; + unsigned int mbs_dropped; + unsigned int mbs_recovered; + struct vxd_pict_attrs pict_attrs; +}; + +/* + * This union contains firmware contexts. Used to allocate buffers for firmware + * context. + */ +union dec_fw_contexts { + struct h264fw_context_data h264_context; +#ifdef HAS_JPEG + struct jpegfw_context_data jpeg_context; +#endif +#ifdef HAS_HEVC + struct hevcfw_ctx_data hevc_context; +#endif +}; + +/* + * for debug + */ +struct dec_fwmsg { + void **link; + struct dec_pict_attrs pict_attrs; + struct vdec_pict_hwcrc pict_hwcrc; +}; + +/* + * This structure contains the stream decode resource (persistent for + * longer than decoding). + * @brief Decoder Stream Resource + */ +struct dec_pictref_res { + void **link; /* to be part of single linked list */ + struct vidio_ddbufinfo fw_ctrlbuf; + unsigned int ref_cnt; +}; + +/* + * This structure defines the decode picture. + * @brief Decoder Picture + */ +struct dec_decpict { + void **link; + unsigned int transaction_id; + void *dec_str_ctx; + unsigned char twopass; + unsigned char first_fld_rcvd; + struct res_resinfo *transaction_info; + struct res_resinfo *hdr_info; +#ifdef HAS_HEVC + struct res_resinfo *pvdec_info; + unsigned int temporal_out_addr; +#endif + struct vdecdd_ddpict_buf *recon_pict; + struct vdecdd_ddpict_buf *alt_pict; + struct res_resinfo *batch_msginfo; + struct vidio_ddbufinfo *intra_bufinfo; + struct vidio_ddbufinfo *auxline_bufinfo; + struct vidio_ddbufinfo *vlc_tables_bufinfo; + struct vidio_ddbufinfo *vlc_idx_tables_bufinfo; + struct vidio_ddbufinfo *start_code_bufinfo; + struct dec_fwmsg *first_fld_fwmsg; + struct dec_fwmsg *second_fld_fwmsg; + struct bspp_pict_hdr_info *pict_hdr_info; + struct dec_pictdec_res *cur_pict_dec_res; + struct dec_pictdec_res *prev_pict_dec_res; + struct dec_pictref_res *pict_ref_res; + struct lst_t dec_pict_seg_list; + struct lst_t fragment_list; + unsigned char eop_found; + unsigned int operating_op; + unsigned short genc_id; + struct vdecdd_ddbuf_mapinfo **genc_bufs; + struct vdecdd_ddbuf_mapinfo *genc_fragment_buf; + unsigned int ctrl_alloc_bytes; + unsigned int ctrl_alloc_offset; + enum dec_pict_states state; + struct vidio_ddbufinfo *str_pvdec_fw_ctxbuf; +}; + +/* + * + * This structure defines the decode picture reference. + * @brief Decoder Picture Reference + */ +struct dec_str_unit { + void **link; /* to be part of single linked list */ + struct dec_decpict *dec_pict; + struct vdecdd_str_unit *str_unit; +}; + +/* + * This structure defines the decoded picture. + * @brief Decoded Picture + */ +struct dec_decoded_pict { + struct dq_linkage_t link; /* to be part of double linked list */ + unsigned int transaction_id; + unsigned char processed; + unsigned char process_failed; + unsigned char force_display; + unsigned char displayed; + unsigned char merged; + unsigned int disp_idx; + unsigned int rel_idx; + struct vdecdd_picture *pict; + struct dec_fwmsg *first_fld_fwmsg; + struct dec_fwmsg *second_fld_fwmsg; + struct dec_pictref_res *pict_ref_res; +}; + +struct dec_pict_fragment { + void **link; /* to be part of single linked list */ + /* Control allocation size in bytes */ + unsigned int ctrl_alloc_bytes; + /* Control allocation offset in bytes */ + unsigned int ctrl_alloc_offset; +}; + +/* + * This structure contains the pointer to the picture segment. + * All the segments could be added to the list in struct dec_decpict, + * but because list items cannot belong to more than one list this wrapper + * is used which is added in the list sDecPictSegList inside struct dec_decpict + * @brief Decoder Picture Segment + */ +struct dec_decpict_seg { + void **link; /* to be part of single linked list */ + struct bspp_bitstr_seg *bstr_seg; + unsigned char internal_seg; +}; + +struct decoder_regsoffsets { + unsigned int vdmc_cmd_offset; + unsigned int vec_offset; + unsigned int entropy_offset; + unsigned int vec_be_regs_offset; + unsigned int vdec_be_codec_regs_offset; +}; + +int decoder_initialise(void *init_usr_data, unsigned int internal_heap_id, + struct vdecdd_dd_devconfig *dd_devcfg, unsigned int *num_pipes, + void **dec_ctx); + +int decoder_deinitialise(void *dec_ctx); + +int decoder_supported_features(void *dec_ctx, struct vdec_features *features); + +int decoder_stream_destroy(void *dec_str_ctx, unsigned char abort); + +int decoder_stream_create(void *dec_ctx, struct vdec_str_configdata str_cfg, + unsigned int kmstr_id, void **mmu_str_handle, + void *vxd_dec_ctx, void *str_usr_int_data, + void **dec_str_ctx, void *decoder_cb, void *query_cb); + +int decoder_stream_prepare_ctx(void *dec_str_ctx, unsigned char flush_dpb); + +int decoder_stream_process_unit(void *dec_str_ctx, + struct vdecdd_str_unit *str_unit); + +int decoder_get_load(void *dec_str_ctx, unsigned int *avail_slots); + +int +decoder_check_support(void *dec_ctx, + const struct vdec_str_configdata *str_cfg, + const struct vdec_str_opconfig *op_cfg, + const struct vdecdd_ddpict_buf *disp_pictbuf, + const struct vdec_pict_rendinfo *req_pict_rendinfo, + const struct vdec_comsequ_hdrinfo *comseq_hdrinfo, + const struct bspp_pict_hdr_info *pict_hdrinfo, + const struct vdec_comsequ_hdrinfo *prev_comseq_hdrinfo, + const struct bspp_pict_hdr_info *prev_pict_hdrinfo, + unsigned char non_cfg_req, struct vdec_unsupp_flags *unsupported, + unsigned int *features); + +unsigned char decoder_is_stream_idle(void *dec_str_ctx); + +int decoder_stream_flush(void *dec_str_ctx, unsigned char discard_refs); + +int decoder_stream_release_buffers(void *dec_str_ctx); + +int decoder_stream_get_status(void *dec_str_ctx, + struct vdecdd_decstr_status *dec_str_st); + +int decoder_service_firmware_response(void *dec_str_ctx_arg, unsigned int *msg, + unsigned int msg_size, unsigned int msg_flags); + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/dec_resources.c b/drivers/media/platform/imagination/vxe-vxd/decoder/dec_resources.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/dec_resources.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/dec_resources.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,554 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VXD Decoder resource allocation and tracking function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#include +#include +#include +#include + +#include "decoder.h" +#include "dec_resources.h" +#include "hw_control.h" +#include "h264fw_data.h" +#include "h264_idx.h" +#include "h264_vlc.h" +#include "img_mem.h" +#include "pool_api.h" +#include "vdecdd_utils.h" +#include "vdec_mmu_wrapper.h" +#include "vid_buf.h" +#include "vxd_mmu_defs.h" + +#define DECODER_END_BYTES_SIZE 40 + +#define BATCH_MSG_BUFFER_SIZE (8 * 4096) +#define INTRA_BUF_SIZE (1024 * 32) +#define AUX_LINE_BUFFER_SIZE (512 * 1024) + +static void decres_pack_vlc_tables(unsigned short *packed, + unsigned short *unpacked, + unsigned short size) +{ + unsigned short i, j; + + for (i = 0; i < size; i++) { + j = i * 3; + /* + * opcode 14:12 + * width 11:9 + * symbol 8:0 + */ + packed[i] = 0 | ((unpacked[j]) << 12) | + ((unpacked[j + 1]) << 9) | (unpacked[j + 2]); + } +} + +struct dec_vlctable { + void *data; + unsigned int num_entries; + void *index_table; + unsigned int num_tables; +}; + +/* + * Union with sizes of firmware parser header structure sizes. Dec_resources + * uses the largest to allocate the header buffer. + */ +union decres_fw_hdrs { + struct h264fw_header_data h264_header; +}; + +/* + * This array contains the size of each resource allocation. + * @brief Resource Allocation Sizes + * NOTE: This should be kept in step with #DECODER_eResType. + */ +static const unsigned int res_size[DECODER_RESTYPE_MAX] = { + sizeof(struct vdecfw_transaction), + sizeof(union decres_fw_hdrs), + BATCH_MSG_BUFFER_SIZE, +#ifdef HAS_HEVC + MEM_TO_REG_BUF_SIZE + SLICE_PARAMS_BUF_SIZE + ABOVE_PARAMS_BUF_SIZE, +#endif +}; + +static const unsigned char start_code[] = { + 0x00, 0x00, 0x01, 0x00, +}; + +static void decres_get_vlc_data(struct dec_vlctable *vlc_table, + enum vdec_vid_std vid_std) +{ + switch (vid_std) { + case VDEC_STD_H264: + vlc_table->data = h264_vlc_table_data; + vlc_table->num_entries = h264_vlc_table_size; + vlc_table->index_table = h264_vlc_index_data; + vlc_table->num_tables = h264_vlc_index_size; + break; + + default: + memset(vlc_table, 0x0, sizeof(*vlc_table)); + break; + } +} + +static void decres_fnbuf_info_destructor(void *param, void *cb_handle) +{ + struct vidio_ddbufinfo *dd_bufinfo = (struct vidio_ddbufinfo *)param; + int ret; + void *mmu_handle = cb_handle; + + VDEC_ASSERT(dd_bufinfo); + + ret = mmu_free_mem(mmu_handle, dd_bufinfo); + VDEC_ASSERT(ret == IMG_SUCCESS); + + kfree(dd_bufinfo); + dd_bufinfo = NULL; +} + +int dec_res_picture_detach(void **res_ctx, struct dec_decpict *dec_pict) +{ + struct dec_res_ctx *local_res_ctx; + + VDEC_ASSERT(res_ctx); + VDEC_ASSERT(res_ctx && *res_ctx); + VDEC_ASSERT(dec_pict); + VDEC_ASSERT(dec_pict && dec_pict->transaction_info); + + if (!res_ctx || !(*res_ctx) || !dec_pict || + !dec_pict->transaction_info) { + pr_err("Invalid parameters\n"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + local_res_ctx = (struct dec_res_ctx *)*res_ctx; + + /* return transaction buffer */ + lst_add(&local_res_ctx->pool_data_list[DECODER_RESTYPE_TRANSACTION], + dec_pict->transaction_info); + pool_resfree(dec_pict->transaction_info->res); + + /* return picture header information buffer */ + lst_add(&local_res_ctx->pool_data_list[DECODER_RESTYPE_HDR], + dec_pict->hdr_info); + pool_resfree(dec_pict->hdr_info->res); + + /* return batch message buffer */ + lst_add(&local_res_ctx->pool_data_list[DECODER_RESTYPE_BATCH_MSG], + dec_pict->batch_msginfo); + pool_resfree(dec_pict->batch_msginfo->res); + +#ifdef HAS_HEVC + if (dec_pict->pvdec_info) { + lst_add(&local_res_ctx->pool_data_list[DECODER_RESTYPE_PVDEC_BUF], + dec_pict->pvdec_info); + pool_resfree(dec_pict->pvdec_info->res); + } +#endif + + return IMG_SUCCESS; +} + +static int decres_get_resource(struct dec_res_ctx *res_ctx, + enum dec_res_type res_type, + struct res_resinfo **res_info, + unsigned char fill_zeros) +{ + struct res_resinfo *local_res_info = NULL; + unsigned int ret = IMG_SUCCESS; + + VDEC_ASSERT(res_ctx); + VDEC_ASSERT(res_info); + + local_res_info = lst_removehead(&res_ctx->pool_data_list[res_type]); + VDEC_ASSERT(local_res_info); + if (local_res_info) { + VDEC_ASSERT(local_res_info->ddbuf_info); + if (local_res_info->ddbuf_info) { + ret = pool_resalloc(res_ctx->res_pool[res_type], local_res_info->res); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) { + ret = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + return ret; + } + + if (fill_zeros) + memset(local_res_info->ddbuf_info->cpu_virt, 0, + local_res_info->ddbuf_info->buf_size); + + *res_info = local_res_info; + } else { + ret = IMG_ERROR_FATAL; + return ret; + } + } else { + ret = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + return ret; + } + + return ret; +} + +int dec_res_picture_attach(void **res_ctx, enum vdec_vid_std vid_std, + struct dec_decpict *dec_pict) +{ + struct dec_res_ctx *local_res_ctx; + int ret; + + VDEC_ASSERT(res_ctx); + VDEC_ASSERT(res_ctx && *res_ctx); + VDEC_ASSERT(dec_pict); + if (!res_ctx || !(*res_ctx) || !dec_pict) { + pr_err("Invalid parameters"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + local_res_ctx = (struct dec_res_ctx *)*res_ctx; + + /* Obtain transaction buffer. */ + ret = decres_get_resource(local_res_ctx, DECODER_RESTYPE_TRANSACTION, + &dec_pict->transaction_info, TRUE); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + /* Obtain picture header information buffer */ + ret = decres_get_resource(local_res_ctx, DECODER_RESTYPE_HDR, + &dec_pict->hdr_info, TRUE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + +#ifdef HAS_HEVC + /* Obtain HEVC buffer */ + if (vid_std == VDEC_STD_HEVC) { + ret = decres_get_resource(local_res_ctx, DECODER_RESTYPE_PVDEC_BUF, + &dec_pict->pvdec_info, TRUE); + + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + } +#endif + /* Obtain picture batch message buffer */ + ret = decres_get_resource(local_res_ctx, DECODER_RESTYPE_BATCH_MSG, + &dec_pict->batch_msginfo, TRUE); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + dec_pict->intra_bufinfo = &local_res_ctx->intra_bufinfo; + dec_pict->auxline_bufinfo = &local_res_ctx->auxline_bufinfo; + dec_pict->vlc_tables_bufinfo = + &local_res_ctx->vlc_tables_bufinfo[vid_std]; + dec_pict->vlc_idx_tables_bufinfo = + &local_res_ctx->vlc_idxtables_bufinfo[vid_std]; + dec_pict->start_code_bufinfo = &local_res_ctx->start_code_bufinfo; + + return IMG_SUCCESS; +} + +int dec_res_create(void *mmu_handle, struct vxd_coreprops *core_props, + unsigned int num_dec_slots, + unsigned int mem_heap_id, void **resources) +{ + struct dec_res_ctx *local_res_ctx; + int ret; + unsigned int i = 0; + struct dec_vlctable vlc_table; + enum sys_emem_attrib mem_attrib; + + VDEC_ASSERT(core_props); + VDEC_ASSERT(resources); + if (!core_props || !resources) { + pr_err("Invalid parameters"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + mem_attrib = (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE); + mem_attrib |= (enum sys_emem_attrib)SYS_MEMATTRIB_INTERNAL; + + local_res_ctx = kzalloc(sizeof(*local_res_ctx), GFP_KERNEL); + VDEC_ASSERT(local_res_ctx); + if (!local_res_ctx) + return IMG_ERROR_OUT_OF_MEMORY; + + /* Allocate Intra buffer. */ +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s:%d call MMU_StreamMalloc", __func__, __LINE__); +#endif + + ret = mmu_stream_alloc(mmu_handle, MMU_HEAP_STREAM_BUFFERS, mem_heap_id, + mem_attrib, + core_props->num_pixel_pipes * + INTRA_BUF_SIZE * 3, + DEV_MMU_PAGE_ALIGNMENT, + &local_res_ctx->intra_bufinfo); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + /* Allocate aux line buffer. */ +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s:%d call MMU_StreamMalloc", __func__, __LINE__); +#endif + ret = mmu_stream_alloc(mmu_handle, MMU_HEAP_STREAM_BUFFERS, mem_heap_id, + mem_attrib, + AUX_LINE_BUFFER_SIZE * 3 * + core_props->num_pixel_pipes, + DEV_MMU_PAGE_ALIGNMENT, + &local_res_ctx->auxline_bufinfo); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + /* Allocate standard-specific buffers. */ + for (i = VDEC_STD_UNDEFINED + 1; i < VDEC_STD_MAX; i++) { + decres_get_vlc_data(&vlc_table, (enum vdec_vid_std)i); + + if (vlc_table.num_tables > 0) { + /* + * Size of VLC IDX table in bytes. Has to be aligned + * to 4, so transfer to MTX succeeds. + * (VLC IDX is copied to local RAM of MTX) + */ + unsigned int vlc_idxtable_sz = + ALIGN((sizeof(unsigned short) * vlc_table.num_tables * 3), 4); + +#ifdef DEBUG_DECODER_DRIVER + pr_info(" %s:%d calling MMU_StreamMalloc", __func__, __LINE__); +#endif + + ret = mmu_stream_alloc(mmu_handle, + MMU_HEAP_STREAM_BUFFERS, + mem_heap_id, (enum sys_emem_attrib)(mem_attrib | + SYS_MEMATTRIB_CORE_READ_ONLY | + SYS_MEMATTRIB_CPU_WRITE), + sizeof(unsigned short) * vlc_table.num_entries, + DEV_MMU_PAGE_ALIGNMENT, + &local_res_ctx->vlc_tables_bufinfo[i]); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + if (vlc_table.data) + decres_pack_vlc_tables + (local_res_ctx->vlc_tables_bufinfo[i].cpu_virt, + vlc_table.data, + vlc_table.num_entries); + + /* VLC index table */ +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s:%d calling MMU_StreamMalloc", + __func__, __LINE__); +#endif + ret = mmu_stream_alloc(mmu_handle, + MMU_HEAP_STREAM_BUFFERS, + mem_heap_id, (enum sys_emem_attrib)(mem_attrib | + SYS_MEMATTRIB_CORE_READ_ONLY | + SYS_MEMATTRIB_CPU_WRITE), + vlc_idxtable_sz, + DEV_MMU_PAGE_ALIGNMENT, + &local_res_ctx->vlc_idxtables_bufinfo[i]); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + if (vlc_table.index_table) + memcpy(local_res_ctx->vlc_idxtables_bufinfo[i].cpu_virt, + vlc_table.index_table, + local_res_ctx->vlc_idxtables_bufinfo[i].buf_size); + } + } + + /* Start code */ +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s:%d calling MMU_StreamMalloc", __func__, __LINE__); +#endif + ret = mmu_stream_alloc(mmu_handle, MMU_HEAP_STREAM_BUFFERS, mem_heap_id, + (enum sys_emem_attrib)(mem_attrib | + SYS_MEMATTRIB_CORE_READ_ONLY | + SYS_MEMATTRIB_CPU_WRITE), + sizeof(start_code), + DEV_MMU_PAGE_ALIGNMENT, + &local_res_ctx->start_code_bufinfo); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + memcpy(local_res_ctx->start_code_bufinfo.cpu_virt, start_code, sizeof(start_code)); + + for (i = 0; i < DECODER_RESTYPE_MAX; i++) { + unsigned int j; + + ret = pool_api_create(&local_res_ctx->res_pool[i]); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error; + + lst_init(&local_res_ctx->pool_data_list[i]); + + for (j = 0; j < num_dec_slots; j++) { + struct res_resinfo *local_res_info; + + local_res_info = kzalloc(sizeof(*local_res_info), GFP_KERNEL); + + VDEC_ASSERT(local_res_info); + if (!local_res_info) { + pr_err("Failed to allocate memory\n"); + ret = IMG_ERROR_OUT_OF_MEMORY; + goto error_local_res_info_alloc; + } + + local_res_info->ddbuf_info = kzalloc(sizeof(*local_res_info->ddbuf_info), + GFP_KERNEL); + VDEC_ASSERT(local_res_info->ddbuf_info); + if (!local_res_info->ddbuf_info) { + pr_err("Failed to allocate memory for resource buffer information structure"); + ret = IMG_ERROR_OUT_OF_MEMORY; + goto error_local_dd_buf_alloc; + } + +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s:%d calling MMU_StreamMalloc", __func__, __LINE__); +#endif + ret = mmu_stream_alloc(mmu_handle, MMU_HEAP_STREAM_BUFFERS, + mem_heap_id, (enum sys_emem_attrib)(mem_attrib | + SYS_MEMATTRIB_CPU_READ | + SYS_MEMATTRIB_CPU_WRITE), + res_size[i], + DEV_MMU_PAGE_ALIGNMENT, + local_res_info->ddbuf_info); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error_local_res_alloc; + + /* Register with the buffer pool */ + ret = pool_resreg(local_res_ctx->res_pool[i], + decres_fnbuf_info_destructor, + local_res_info->ddbuf_info, + sizeof(*local_res_info->ddbuf_info), + FALSE, NULL, + &local_res_info->res, mmu_handle); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + goto error_local_res_register; + + lst_add(&local_res_ctx->pool_data_list[i], + local_res_info); + continue; + +/* Roll back in case of local errors. */ +error_local_res_register: mmu_free_mem(mmu_handle, local_res_info->ddbuf_info); + +error_local_res_alloc: kfree(local_res_info->ddbuf_info); + +error_local_dd_buf_alloc: kfree(local_res_info); + +error_local_res_info_alloc: goto error; + } + } + + *resources = (void *)local_res_ctx; + + return IMG_SUCCESS; + +/* Roll back in case of errors. */ +error: dec_res_destroy(mmu_handle, (void *)local_res_ctx); + + return ret; +} + +/* + *@Function RESOURCES_Destroy + * + */ +int dec_res_destroy(void *mmudev_handle, void *res_ctx) +{ + int ret = IMG_SUCCESS; + int ret1 = IMG_SUCCESS; + unsigned int i = 0; + struct res_resinfo *local_res_info; + struct res_resinfo *next_res_info; + + struct dec_res_ctx *local_res_ctx = (struct dec_res_ctx *)res_ctx; + + if (!local_res_ctx) { + pr_err("Invalid parameters"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (local_res_ctx->intra_bufinfo.hndl_memory) { + ret1 = mmu_free_mem(mmudev_handle, &local_res_ctx->intra_bufinfo); + VDEC_ASSERT(ret1 == IMG_SUCCESS); + if (ret1 != IMG_SUCCESS) + ret = ret1; + } + + if (local_res_ctx->auxline_bufinfo.hndl_memory) { + ret1 = mmu_free_mem(mmudev_handle, &local_res_ctx->auxline_bufinfo); + VDEC_ASSERT(ret1 == IMG_SUCCESS); + if (ret1 != IMG_SUCCESS) + ret = ret1; + } + + for (i = 0; i < VDEC_STD_MAX; i++) { + if (local_res_ctx->vlc_tables_bufinfo[i].hndl_memory) { + ret1 = mmu_free_mem(mmudev_handle, &local_res_ctx->vlc_tables_bufinfo[i]); + VDEC_ASSERT(ret1 == IMG_SUCCESS); + if (ret1 != IMG_SUCCESS) + ret = ret1; + } + + if (local_res_ctx->vlc_idxtables_bufinfo[i].hndl_memory) { + ret1 = mmu_free_mem(mmudev_handle, + &local_res_ctx->vlc_idxtables_bufinfo[i]); + VDEC_ASSERT(ret1 == IMG_SUCCESS); + if (ret1 != IMG_SUCCESS) + ret = ret1; + } + } + + if (local_res_ctx->start_code_bufinfo.hndl_memory) { + ret1 = mmu_free_mem(mmudev_handle, &local_res_ctx->start_code_bufinfo); + VDEC_ASSERT(ret1 == IMG_SUCCESS); + if (ret1 != IMG_SUCCESS) + ret = ret1; + } + + for (i = 0; i < DECODER_RESTYPE_MAX; i++) { + if (local_res_ctx->res_pool[i]) { + local_res_info = + lst_first(&local_res_ctx->pool_data_list[i]); + while (local_res_info) { + next_res_info = lst_next(local_res_info); + lst_remove(&local_res_ctx->pool_data_list[i], local_res_info); + ret1 = pool_resdestroy(local_res_info->res, TRUE); + VDEC_ASSERT(ret1 == IMG_SUCCESS); + if (ret1 != IMG_SUCCESS) + ret = ret1; + kfree(local_res_info); + local_res_info = next_res_info; + } + pool_destroy(local_res_ctx->res_pool[i]); + } + } + + kfree(local_res_ctx); + return ret; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/dec_resources.h b/drivers/media/platform/imagination/vxe-vxd/decoder/dec_resources.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/dec_resources.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/dec_resources.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD Decoder resource allocation and destroy Interface header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + */ + +#ifndef _DEC_RESOURCES_H_ +#define _DEC_RESOURCES_H_ + +#include "decoder.h" +#include "lst.h" + +/* + * This structure contains the core resources. + * @brief Decoder Core Resources + */ +struct dec_res_ctx { + struct vidio_ddbufinfo intra_bufinfo; + struct vidio_ddbufinfo auxline_bufinfo; + struct vidio_ddbufinfo start_code_bufinfo; + struct vidio_ddbufinfo vlc_tables_bufinfo[VDEC_STD_MAX]; + struct vidio_ddbufinfo vlc_idxtables_bufinfo[VDEC_STD_MAX]; + void *res_pool[DECODER_RESTYPE_MAX]; + struct lst_t pool_data_list[DECODER_RESTYPE_MAX]; +}; + +int dec_res_picture_detach(void **res_ctx, struct dec_decpict *dec_pict); + +int dec_res_picture_attach(void **res_ctx, enum vdec_vid_std vid_std, + struct dec_decpict *dec_pict); + +int dec_res_create(void *mmudev_handle, + struct vxd_coreprops *core_props, unsigned int num_dec_slots, + unsigned int mem_heap_id, void **resources); + +int dec_res_destroy(void *mmudev_handle, void *res_ctx); + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/fw_interface.h b/drivers/media/platform/imagination/vxe-vxd/decoder/fw_interface.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/fw_interface.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/fw_interface.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,818 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG MSVDX core Registers + * This file contains the MSVDX_CORE_REGS_H Definitions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef FW_INTERFACE_H_ +#define FW_INTERFACE_H_ + +/* TODO For now this macro defined, need to think and enable */ +#define VDEC_USE_PVDEC_COMPATIBILITY 1 + +#define MSG_TYPE_PADDING (0x00) +/* Start of parser specific Host->MTX messages */ +#define MSG_TYPE_START_PSR_HOSTMTX_MSG (0x80) +/* Start of parser specific MTX->Host message */ +#define MSG_TYPE_START_PSR_MTXHOST_MSG (0xC0) + +enum { + FW_DEVA_INIT = MSG_TYPE_START_PSR_HOSTMTX_MSG, + FW_DEVA_DECODE_FE, + FW_DEVA_RES_0, + FW_DEVA_RES_1, + FW_DEVA_DECODE_BE, + FW_DEVA_HOST_BE_OPP, + FW_DEVA_DEBLOCK, + FW_DEVA_INTRA_OOLD, + FW_DEVA_ENDFRAME, + + FW_DEVA_PARSE, + FW_DEVA_PARSE_FRAGMENT, + FW_DEVA_BEGINFRAME, + +#ifdef VDEC_USE_PVDEC_COMPATIBILITY +#ifdef VDEC_USE_PVDEC_SEC + FWBSP_INIT, + FWBSP_PARSE_BITSTREAM, + FWDEC_DECODE, +#endif /* VDEC_USE_PVDEC_SEC */ +#endif /* VDEC_USE_PVDEC_COMPATIBILITY */ + + /* Sent by the firmware on the MTX to the host. */ + FW_DEVA_COMPLETED = MSG_TYPE_START_PSR_MTXHOST_MSG, +#ifndef VDEC_USE_PVDEC_COMPATIBILITY + FW_DEVA_RES_2, + FW_DEVA_RES_3, + FW_DEVA_RES_4, + FW_DEVA_RES_5, + + FW_DEVA_RES_6, + FW_DEVA_CONTIGUITY_WARNING, + FW_DEVA_PANIC, + FW_DEVA_RES_7, + FW_DEVA_RES_8, +#else /* ndef VDEC_USE_PVDEC_COMPATIBILITY */ + FW_DEVA_PANIC, + FW_ASSERT, + FW_PERF, + /* An empty completion message sent by new vxd driver */ + FW_VXD_EMPTY_COMPL, + FW_DEC_REQ_RECEIVED, + FW_SO, +#ifdef VDEC_USE_PVDEC_SEC + FWBSP_NEW_SEQ, + FWBSP_NEW_PIC, + FWBSP_BUF_EMPTY, + FWBSP_ERROR, + FWDEC_COMPLETED, +#endif /* VDEC_USE_PVDEC_SEC */ +#endif /* VDEC_USE_PVDEC_COMPATIBILITY */ + FW_DEVA_SIGNATURES_LEGACY = 0xD0, + FW_DEVA_SIGNATURES_HEVC = 0xE0, + FW_DEVA_SIGNATURES_FORCE32BITS = 0x7FFFFFFFU +}; + +/* Defines the Host/Firmware communication area */ +#ifndef VDEC_USE_PVDEC_COMPATIBILITY +#define COMMS_HEADER_SIZE (0x34) +#else /* def VDEC_USE_PVDEC_COMPATIBILITY */ +#define COMMS_HEADER_SIZE (0x40) +#endif /* def VDEC_USE_PVDEC_COMPATIBILITY */ +/* dwords */ +#define PVDEC_COM_RAM_FW_STATUS_OFFSET 0x00 +#define PVDEC_COM_RAM_TASK_STATUS_OFFSET 0x04 +#define PVDEC_COM_RAM_FW_ID_OFFSET 0x08 +#define PVDEC_COM_RAM_FW_MTXPC_OFFSET 0x0c +#define PVDEC_COM_RAM_MSG_COUNTER_OFFSET 0x10 +#define PVDEC_COM_RAM_SIGNATURE_OFFSET 0x14 +#define PVDEC_COM_RAM_TO_HOST_BUF_SIZE_AND_OFFSET_OFFSET 0x18 +#define PVDEC_COM_RAM_TO_HOST_RD_INDEX_OFFSET 0x1c +#define PVDEC_COM_RAM_TO_HOST_WRT_INDEX_OFFSET 0x20 +#define PVDEC_COM_RAM_TO_MTX_BUF_SIZE_AND_OFFSET_OFFSET 0x24 +#define PVDEC_COM_RAM_TO_MTX_RD_INDEX_OFFSET 0x28 +#define PVDEC_COM_RAM_FLAGS_OFFSET 0x2c +#define PVDEC_COM_RAM_TO_MTX_WRT_INDEX_OFFSET 0x30 +#ifdef VDEC_USE_PVDEC_COMPATIBILITY +#define PVDEC_COM_RAM_STATE_BUF_SIZE_AND_OFFSET_OFFSET 0x34 +#define PVDEC_COM_RAM_FW_MMU_REPORT_OFFSET 0x38 +#endif /* VDEC_USE_PVDEC_COMPATIBILITY */ +/* fields */ +#define PVDEC_COM_RAM_TO_HOST_BUF_SIZE_AND_OFFSET_SIZE_MASK 0xFFFF +#define PVDEC_COM_RAM_TO_HOST_BUF_SIZE_AND_OFFSET_SIZE_SHIFT 0 +#define PVDEC_COM_RAM_TO_HOST_BUF_SIZE_AND_OFFSET_OFFSET_MASK 0xFFFF0000 +#define PVDEC_COM_RAM_TO_HOST_BUF_SIZE_AND_OFFSET_OFFSET_SHIFT 16 + +#define PVDEC_COM_RAM_TO_MTX_BUF_SIZE_AND_OFFSET_SIZE_MASK 0xFFFF +#define PVDEC_COM_RAM_TO_MTX_BUF_SIZE_AND_OFFSET_SIZE_SHIFT 0 +#define PVDEC_COM_RAM_TO_MTX_BUF_SIZE_AND_OFFSET_OFFSET_MASK 0xFFFF0000 +#define PVDEC_COM_RAM_TO_MTX_BUF_SIZE_AND_OFFSET_OFFSET_SHIFT 16 +#ifdef VDEC_USE_PVDEC_COMPATIBILITY +#define PVDEC_COM_RAM_STATE_BUF_SIZE_AND_OFFSET_SIZE_MASK 0xFFFF +#define PVDEC_COM_RAM_STATE_BUF_SIZE_AND_OFFSET_SIZE_SHIFT 0 +#define PVDEC_COM_RAM_STATE_BUF_SIZE_AND_OFFSET_OFFSET_MASK 0xFFFF0000 +#define PVDEC_COM_RAM_STATE_BUF_SIZE_AND_OFFSET_OFFSET_SHIFT 16 +#endif /* VDEC_USE_PVDEC_COMPATIBILITY */ +#define PVDEC_COM_RAM_BUF_GET_SIZE(_reg_, _name_) \ + (((_reg_) & PVDEC_COM_RAM_ ## _name_ ## _BUF_SIZE_AND_OFFSET_SIZE_MASK) >> \ + PVDEC_COM_RAM_ ## _name_ ## _BUF_SIZE_AND_OFFSET_SIZE_SHIFT) +#define PVDEC_COM_RAM_BUF_GET_OFFSET(_reg_, _name_) \ + (((_reg_) & \ + PVDEC_COM_RAM_ ## _name_ ## _BUF_SIZE_AND_OFFSET_OFFSET_MASK) >> \ + PVDEC_COM_RAM_ ## _name_ ## _BUF_SIZE_AND_OFFSET_OFFSET_SHIFT) +#define PVDEC_COM_RAM_BUF_SET_SIZE_AND_OFFSET(_name_, _size_, _offset_) \ + ((((_size_) << \ + PVDEC_COM_RAM_ ## _name_ ## _BUF_SIZE_AND_OFFSET_SIZE_SHIFT) \ + & PVDEC_COM_RAM_ ## _name_ ## _BUF_SIZE_AND_OFFSET_SIZE_MASK) | \ + (((_offset_) << \ + PVDEC_COM_RAM_ ## _name_ ## _BUF_SIZE_AND_OFFSET_OFFSET_SHIFT) \ + & PVDEC_COM_RAM_ ## _name_ ## _BUF_SIZE_AND_OFFSET_OFFSET_MASK)) +/* values */ +/* Firmware ready signature value */ + #define FW_READY_SIGNATURE (0xA5A5A5A5) + +/* Firmware status values */ + #define FW_STATUS_BUSY 0 + #define FW_STATUS_IDLE 1 + #define FW_STATUS_PANIC 2 + #define FW_STATUS_ASSERT 3 + #define FW_STATUS_GAMEOVER 4 + #define FW_STATUS_FEWATCHDOG 5 + #define FW_STATUS_EPWATCHDOG 6 + #define FW_STATUS_BEWATCHDOG 7 +#ifdef VDEC_USE_PVDEC_COMPATIBILITY + #define FW_STATUS_SO 8 + #define FW_STATUS_INIT 0xF +#endif + +/* Decode Message Flags */ + #define FW_DEVA_RENDER_IS_FIRST_SLICE (0x00000001) +/* This is H264 Mbaff - required for state store */ + #define FW_DEVA_FORCE_RECON_WRITE_DISABLE (0x00000002) + #define FW_DEVA_RENDER_IS_LAST_SLICE (0x00000004) +/* Prevents insertion of end of picture or flush at VEC EOS */ + #define FW_DEVA_DECODE_DISABLE_EOF_DETECTION (0x00000008) + + #define FW_DEVA_CONTEXT_BUFFER_INVALID (0x00000010) + #define FW_DEVA_FORCE_ALT_OUTPUT (0x00000020) + #define FW_SECURE_STREAM (0x00000040) + #define FW_LOW_LATENCY (0x00000080) + + #define FW_DEVA_CONTIGUITY_DETECTION (0x00000100) + #define FW_DEVA_FORCE_INIT_CMDS (0x00000200) + #define FW_DEVA_DEBLOCK_ENABLE (0x00000400) +#ifdef VDEC_USE_PVDEC_COMPATIBILITY + #define FW_VDEC_SEND_SIGNATURES (0x00000800) +#else +/* (0x00000800) */ +#endif /* VDEC_USE_PVDEC_COMPATIBILITY */ + + #define FW_DEVA_FORCE_AUX_LINE_BUF_DISABLE (0x00001000) +/* + * Cause no response message to be sent, and no interrupt + * generation on successful completion + */ + #define FW_DEVA_RENDER_NO_RESPONSE_MSG (0x00002000) +/* + * Cause an interrupt if a response message is generated + * on successful completion + */ + #define FW_DEVA_RENDER_HOST_INT (0x00004000) +/* Report contiguity errors to host */ + #define FW_DEVA_CONTIGUITY_REPORTING (0x00008000) + + #define FW_DEVA_VC1_SKIPPED_PICTURE (0x00010000) + #define FW_INTERNAL_RENDER_SWITCH (0x00020000) + #define FW_DEVA_UNSUPPORTED (0x00040000) + #define DEBLOCKING_FORCED_OFF (0x00080000) +#ifdef VDEC_USE_PVDEC_COMPATIBILITY + #define FW_VDEC_CMD_PENDING (0x00100000) +#else +/* (0x00100000) */ +#endif +/* Only for debug */ + #define DETECTED_RENDEC_FULL (0x00200000) +/* Only for debug */ + #define DETECTED_RENDEC_EMPTY (0x00400000) + #define FW_ONE_PASS_PARSE (0x00800000) + + #define FW_DEVA_EARLY_COMPLETE (0x01000000) + #define FW_DEVA_FE_EP_SIGNATURES_READY (0x02000000) + #define FW_VEC_EOS (0x04000000) +/* hardware has reported an error relating to this command */ + #define FW_DEVA_ERROR_DETECTED_ENT (0x08000000) + + #define FW_DEVA_ERROR_DETECTED_PIX (0x10000000) + #define FW_DEVA_MP_SYNC (0x20000000) + #define MORE_THAN_ONE_MB (0x40000000) + #define REATTEMPT_SINGLEPIPE (0x80000000) +/* end of message flags */ +#ifdef VDEC_USE_PVDEC_COMPATIBILITY +/* VDEC Decode Message Flags */ +/* + * H.264/H.265 are to be configured in SIZE_DELIMITED mode rather than SCP mode. + */ +#define FW_VDEC_NAL_SIZE_DELIM (0x00000001) +/* Indicates if MMU cache shall be flushed. */ +#define FW_VDEC_MMU_FLUSH_CACHE (0x00000002) +/* end of message flags */ +#endif /* VDEC_USE_PVDEC_COMPATIBILITY */ + +/* FW flags */ +/* TODO : Temporary for HW testing */ + #define FWFLAG_DISABLE_VDEB_PRELOAD (0x00000001) + #define FWFLAG_BIG_TO_HOST_BUFFER (0x00000002) +/* FS is default regarless of this flag */ + #define FWFLAG_FORCE_FS_FLOW (0x00000004) + #define FWFLAG_DISABLE_WATCHDOG_TIMERS (0x00000008) + + #define FWFLAG_DISABLE_AEH (0x00000020) + #define FWFLAG_DISABLE_AUTONOMOUS_RESET (0x00000040) + #define FWFLAG_NON_ACCUMULATING_HWSIGS (0x00000080) + + #define FWFLAG_DISABLE_2PASS_DEBLOCK (0x00000100) + #define FWFLAG_NO_INT_ON_TOHOST_FULL (0x00000200) + #define FWFLAG_RETURN_VDEB_CR (0x00000800) + + #define FWFLAG_DISABLE_AUTOCLOCKGATING (0x00001000) + #define FWFLAG_DISABLE_IDLE_GPIO (0x00002000) + #define FWFLAG_XPL (0x00004000) + #define FWFLAG_INFINITE_MTX_TIMEOUT (0x00008000) + + #define FWFLAG_DECOUPLE_BE_FE (0x00010000) + #define FWFLAG_ENABLE_SECURITY (0x00080000) + + #define FWFLAG_ENABLE_CONCEALMENT (0x00100000) +/* Not currently supported */ +/* #define FWFLAG_PREEMPT (0x00200000) */ +/* NA in FS */ + #define FWFLAG_FORCE_FLUSHING (0x00400000) +/* NA in FS */ + #define FWFLAG_DISABLE_GENC_FLUSHING (0x00800000) + + #define FWFLAG_DISABLE_COREWDT_TIMERS (0x01000000) + #define FWFLAG_DISABLE_RENDEC_AUTOFLUSH (0x02000000) + #define FWFLAG_FORCE_STRICT_SINGLEPIPE (0x04000000) + #define FWFLAG_CONSISTENT_MULTIPIPE_FLOW (0x08000000) + + #define FWFLAG_DISABLE_IDLE_FAST_EVAL (0x10000000) + #define FWFLAG_FAKE_COMPLETION (0x20000000) + #define FWFLAG_MAN_PP_CLK (0x40000000) + #define FWFLAG_STACK_CHK (0x80000000) + +/* end of FW flags */ + +#ifdef FW_STACK_USAGE_TRACKING +/* FW task identifiers */ +enum task_id { + TASK_ID_RX = 0, + TASK_ID_TX, + TASK_ID_EP1, + TASK_ID_FE1, + TASK_ID_FE2, + TASK_ID_FE3, + TASK_ID_BE1, + TASK_ID_BE2, + TASK_ID_BE3, + TASK_ID_PARSER, + TASK_ID_MAX, + TASK_ID_FORCE32BITS = 0x7FFFFFFFU +}; + +/* FW task stack info utility macros */ +#define TASK_STACK_SIZE_MASK 0xFFFF +#define TASK_STACK_SIZE_SHIFT 0 +#define TASK_STACK_USED_MASK 0xFFFF0000 +#define TASK_STACK_USED_SHIFT 16 +#define TASK_STACK_SET_INFO(_task_id_, _stack_info_, _size_, _used_) \ + (_stack_info_[_task_id_] = \ + ((_size_) << TASK_STACK_SIZE_SHIFT) | \ + ((_used_) << TASK_STACK_USED_SHIFT)) +#define TASK_STACK_GET_SIZE(_task_id_, _stack_info_) \ + ((_stack_info_[_task_id_] & TASK_STACK_SIZE_MASK) >> \ + TASK_STACK_SIZE_SHIFT) +#define TASK_STACK_GET_USED(_task_id_, _stack_info_) \ + ((_stack_info_[_task_id_] & TASK_STACK_USED_MASK) >> \ + TASK_STACK_USED_SHIFT) +#endif /* FW_STACK_USAGE_TRACKING */ + +/* Control Allocation */ +#define CMD_MASK (0xF0000000) + +/* Ctrl Allocation Header */ +#define CMD_CTRL_ALLOC_HEADER (0x90000000) + +struct ctrl_alloc_header { + unsigned int cmd_additional_params; + unsigned int slice_params; + union { + unsigned int vp8_probability_data; + unsigned int h264_pipeintra_buffersize; + }; + unsigned int chroma_strides; + unsigned int slice_first_mb_yx; + unsigned int pic_last_mb_yx; + /* VC1 only : Store Range Map flags in bottom bits of [0] */ + unsigned int alt_output_addr[2]; + unsigned int alt_output_flags; + /* H264 Only : Extended Operating Mode */ + unsigned int ext_opmode; +}; + +#define CMD_CTRL_ALLOC_HEADER_DWSIZE \ + (sizeof(struct ctrl_alloc_header) / sizeof(unsigned int)) + +/* Additional Parameter flags */ +#define VC1_PARSEHDR_MASK (0x00000001) +#define VC1_SKIPPIC_MASK (0x00000002) + +#define VP6_BUFFOFFSET_MASK (0x0000ffff) +#define VP6_MULTISTREAM_MASK (0x01000000) +#define VP6_FRAMETYPE_MASK (0x02000000) + +#define VP8_BUFFOFFSET_MASK (0x00ffffff) +#define VP8_PARTITIONSCOUNT_MASK (0x0f000000) +#define VP8_PARTITIONSCOUNT_SHIFT (24) + +/* Nop Command */ +#define CMD_NOP (0x00000000) +#define CMD_NOP_DWSIZE (1) + +/* Register Block */ +#define CMD_REGISTER_BLOCK (0x10000000) +#define CMD_REGISTER_BLOCK_PATCHING_REQUIRED (0x01000000) +#define CMD_REGISTER_BLOCK_FLAG_PRELOAD (0x04000000) +#define CMD_REGISTER_BLOCK_FLAG_VLC_DATA (0x08000000) + +/* Rendec Command */ +#define CMD_RENDEC_BLOCK (0x50000000) +#define CMD_RENDEC_BLOCK_FLAG_MASK (0x0F000000) +#define CMD_RENDEC_FORCE (0x08000000) +#define CMD_RENDEC_PATCHING_REQUIRED (0x01000000) +#define CMD_RENDEC_WORD_COUNT_MASK (0x00ff0000) +#define CMD_RENDEC_WORD_COUNT_SHIFT (16) +#define CMD_RENDEC_ADDRESS_MASK (0x0000ffff) +#define CMD_RENDEC_ADDRESS_SHIFT (0) + +#ifndef VDEC_USE_PVDEC_SEC +/* Deblock */ +#define CMD_DEBLOCK (0x70000000) +#define CMD_DEBLOCK_TYPE_STD (0x00000000) +#define CMD_DEBLOCK_TYPE_OOLD (0x00000001) +#define CMD_DEBLOCK_TYPE_SKIP (0x00000002) +/* End Of Frame */ +#define CMD_DEBLOCK_TYPE_EF (0x00000003) + +struct deblock_cmd { + unsigned int cmd; /* 0x70000000 */ + unsigned int source_mb_data; + unsigned int address_a[2]; +}; + +#define CMD_DEBLOCK_DWSIZE (sizeof(DEBLOCK_CMD) / sizeof(unsigned int)) +#endif /* !VDEC_USE_PVDEC_SEC */ + +/* Skip */ +#define CMD_CONDITIONAL_SKIP (0x80000000) +#define CMD_CONDITIONAL_SKIP_DWSIZE (1) +#define CMD_CONDITIONAL_SKIP_DWORDS (0x0000ffff) +#define CMD_CONDITIONAL_SKIP_CONTEXT_SWITCH BIT(20) + +/* DMA */ +#define CMD_DMA (0xE0000000) +#define CMD_DMA_DMA_TYPE_MASK (0x03000000) +#define CMD_DMA_DMA_TYPE_SHIFT (24) +#define CMD_DMA_FLAG_MASK (0x00100000) +#define CMD_DMA_FLAG_SHIFT (20) +#define CMD_DMA_DMA_SIZE_MASK (0x000fffff) + +#define CMD_DMA_OFFSET_FLAG (0x00100000) + +#define CMD_DMA_MAX_OFFSET (0xFFF) +#define CMD_DMA_TYPE_VLC_TABLE (0 << CMD_DMA_DMA_TYPE_SHIFT) +#define CMD_DMA_TYPE_PROBABILITY_DATA BIT(CMD_DMA_DMA_TYPE_SHIFT) + +struct dma_cmd { + unsigned int cmd; + unsigned int dev_virt_add; +}; + +#define CMD_DMA_DWSIZE (sizeof(DMA_CMD) / sizeof(unsigned int)) + +struct dma_cmd_offset_dwsize { + unsigned int cmd; + unsigned int dev_virt_add; + unsigned int byte_offset; +}; + +#define CMD_DMA_OFFSET_DWSIZE (sizeof(DMA_CMD_WITH_OFFSET) / sizeof(unsigned int)) + +/* HOST COPY */ +#define CMD_HOST_COPY (0xF0000000) +#define CMD_HOST_COPY_SIZE_MASK (0x000fffff) + +struct host_copy_cmd { + unsigned int cmd; + unsigned int src_dev_virt_add; + unsigned int dst_dev_virt_add; +}; + +#define CMD_HOST_COPY_DWSIZE (sizeof(HOST_COPY_CMD) / sizeof(unsigned int)) + +/* Shift register setup and Bitstream DMA */ +#define CMD_SR_SETUP (0xB0000000) +#define CMD_SR_ENABLE_RBDU_EXTRACTION (0x00000001) +#define CMD_SR_ENABLE_AES_COUNTER (0x00000002) +#define CMD_SR_VERIFY_STARTCODE (0x00000004) +#define CMD_SR_BITSTR_ADDR_DEREF (0x00000008) +#define CMD_SR_BITSTR_PARSE_KEY (0x00000010) + +struct sr_setup_cmd { + unsigned int cmd; + unsigned int bitstream_offset_bits; + unsigned int bitstream_size_bytes; +}; + +#define CMD_SR_DWSIZE (sizeof(SR_SETUP_CMD) / sizeof(unsigned int)) + +#define CMD_BITSTREAM_DMA (0xA0000000) +#define CMD_BITSTREAM_DMA_DWSIZE (2) +/* VC1 Parse Header Command */ +#define CMD_PARSE_HEADER (0x30000000) +#define CMD_PARSE_HEADER_CONTEXT_MASK (0x000000ff) +#define CMD_PARSE_HEADER_NEWSLICE (0x00000001) +#define CMD_PARSE_HEADER_SKIP_PIC (0x00000002) +#define CMD_PARSE_HEADER_ONEPASSPARSE (0x00000004) +#define CMD_PARSE_HEADER_NUMSLICE_MINUS1 (0x00ffff00) + +struct parse_header_cmd { + unsigned int cmd; + unsigned int seq_hdr_data; + unsigned int pic_dimensions; + unsigned int bitplane_addr[3]; + unsigned int vlc_table_addr; +}; + +#define CMD_PARSE_DWSIZE (sizeof(PARSE_HEADER_CMD) / sizeof(unsigned int)) + +#define CMD_SLICE_INFO (0x20000000) +#define CMD_SLICE_INFO_SLICENUM (0xff000000) +#define CMD_SLICE_INFO_FIRSTMBY (0x00ff0000) +#define CMD_SLICE_INFO_MBBITOFFSET (0x0000ffff) + +struct slice_info { + unsigned char slice_num; + unsigned char slice_first_mby; + unsigned short slice_mb_bitoffset; +}; + +#ifdef VDEC_USE_PVDEC_COMPATIBILITY +/* VDEC extension */ +#define CMD_VDEC_EXT (0xC0000000) +#ifdef VDEC_USE_PVDEC_SEC +/* + * Used only between firmware secure modules FWBSP->FWDEC, + * thus the structure is defined in firmware structures.h + */ +#define CMD_VDEC_SECURE_EXT (0x40000000) +#endif/* VDEC_USE_PVDEC_SEC */ + +#define MEM2REG_SIZE_HOST_PART_MASK 0x0000FFFF +#define MEM2REG_SIZE_HOST_PART_SHIFT 0 + +#define MEM2REG_SIZE_BUF_TOTAL_MASK 0xFFFF0000 +#define MEM2REG_SIZE_BUF_TOTAL_SHIFT 16 + +struct vdec_ext_cmd { + unsigned int cmd; + unsigned int trans_id; + unsigned int hdr_addr; + unsigned int hdr_size; + unsigned int ctx_save_addr; + unsigned int ctx_load_addr; + unsigned int buf_ctrl_addr; + unsigned int seq_addr; + unsigned int pps_addr; + unsigned int pps_2addr; + unsigned int mem_to_reg_addr; + /* 31-16: buff size, 15-0: size filled by host; dwords */ + unsigned int mem_to_reg_size; + unsigned int slice_params_addr; + unsigned int slice_params_size; /* dwords */ + unsigned int last_luma_recon; + unsigned int last_chroma_recon; + unsigned int luma_err_base; + unsigned int chroma_err_base; + unsigned int scaled_display_size; + unsigned int horz_scale_control; + unsigned int vert_scale_control; + unsigned int scale_output_size; + unsigned int vlc_idx_table_size; + unsigned int vlc_idx_table_addr; + unsigned int vlc_tables_size; + unsigned int vlc_tables_addr; + unsigned int display_picture_size; + unsigned int parser_mode; + /* needed for separate colour planes */ + unsigned int intra_buf_base_addr; + unsigned int intra_buf_size_per_plane; + unsigned int intra_buf_size_per_pipe; + unsigned int chroma2reconstructed_addr; + unsigned int luma_alt_addr; + unsigned int chroma_alt_addr; + unsigned int chroma2alt_addr; + unsigned int aux_line_buf_size_per_pipe; + unsigned int aux_line_buffer_base_addr; + unsigned int alt_output_pict_rotation; + /* miscellaneous flags */ + struct { + unsigned is_chromainterleaved : 1; + unsigned is_packedformat : 1; + unsigned is_discontinuousmbs : 1; + }; +}; + +#define CMD_VDEC_EXT_DWSIZE (sizeof(VDEC_EXT_CMD) / sizeof(unsigned int)) +#endif /* VDEC_USE_PVDEC_COMPATIBILITY */ + +/* Completion */ +#define CMD_COMPLETION (0x60000000) +#define CMD_COMPLETION_DWSIZE (1) + +#ifdef VDEC_USE_PVDEC_SEC +/* Slice done */ +#define CMD_SLICE_DONE (0x70000000) +#define CMD_SLICE_DONE_DWSIZE (1) +#endif /* VDEC_USE_PVDEC_SEC */ + +/* Bitstream segments */ +#define CMD_BITSTREAM_SEGMENTS (0xD0000000) +#define CMD_BITSTREAM_SEGMENTS_MINUS1_MASK (0x0000001F) +#define CMD_BITSTREAM_PARSE_BLK_MASK (0x0000FF00) +#ifdef VDEC_USE_PVDEC_COMPATIBILITY +#define CMD_BITSTREAM_SEGMENTS_MORE_FOLLOW_MASK (0x00000020) +#define CMD_BITSTREAM_EOP_MASK (0x00000040) +#define CMD_BITSTREAM_BS_TOT_SIZE_WORD_OFFSET (1) +#define CMD_BITSTREAM_BS_SEG_LIST_WORD_OFFSET (2) +#define CMD_BITSTREAM_HDR_DW_SIZE CMD_BITSTREAM_BS_SEG_LIST_WORD_OFFSET + +#define CMD_BITSTREAM_SEGMENTS_MAX_NUM (60) +#endif /* VDEC_USE_PVDEC_COMPATIBILITY */ + +#ifdef VDEC_USE_PVDEC_COMPATIBILITY +/* Signatures */ +/* Signature set ids (see hwSignatureModules.c for exact order). */ +/* -- FRONT END/ENTROPY_PIPE ----------------------------------- */ +/* + * Signature group 0: + * REG(PVDEC_ENTROPY, CR_SR_SIGNATURE) + * REG(MSVDX_VEC, CR_SR_CRC) + */ +#define PVDEC_SIGNATURE_GROUP_0 BIT(0) +/* + * Signature group 1: + * REG(PVDEC_ENTROPY, CR_HEVC_PARSER_SIGNATURE) + * REG(PVDEC_ENTROPY, CR_ENCAP_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_1 BIT(1) +/* + * Signature group 2: + * REG(PVDEC_ENTROPY, CR_GENC_ENGINE_OUTPUT_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_2 BIT(2) +/* + * Signature group 3: + * REGREP(PVDEC_ENTROPY, CR_GENC_BUFFER_SIGNATURE, 0) + * REGREP(PVDEC_ENTROPY, CR_GENC_BUFFER_SIGNATURE, 1) + * REGREP(PVDEC_ENTROPY, CR_GENC_BUFFER_SIGNATURE, 2) + * REGREP(PVDEC_ENTROPY, CR_GENC_BUFFER_SIGNATURE, 3) + * REG( PVDEC_ENTROPY, CR_GENC_FRAGMENT_SIGNATURE) + * REG( PVDEC_ENTROPY, CR_GENC_FRAGMENT_READ_SIGNATURE) + * REG( PVDEC_ENTROPY, CR_GENC_FRAGMENT_WRADDR_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_3 BIT(3) +/* -- GENC_DEC -------------------------------------------------- */ +/* + * Signature group 4: + * REG( PVDEC_VEC_BE, CR_GDEC_FRAGMENT_REQ_SIGNATURE) + * REG( PVDEC_VEC_BE, CR_GDEC_SYS_WR_SIGNATURE) + * REG( PVDEC_VEC_BE, CR_GDEC_MEM2REG_SYS_WR_SIGNATURE) + * REG( PVDEC_VEC_BE, CR_SLICE_STRUCTURE_REQ_SIGNATURE) + * REG( PVDEC_VEC_BE, CR_SLICE_STRUCTURE_OVER1K_REQ_SIGNATURE) + * REG( PVDEC_VEC_BE, CR_MEM_STRUCTURE_REQ_SIGNATURE) + * REGREP(PVDEC_VEC_BE, CR_GDEC_DATA_REQ_SIGNATURE, 0) + * REGREP(PVDEC_VEC_BE, CR_GDEC_DATA_REQ_SIGNATURE, 1) + * REGREP(PVDEC_VEC_BE, CR_GDEC_DATA_REQ_SIGNATURE, 2) + * REGREP(PVDEC_VEC_BE, CR_GDEC_DATA_REQ_SIGNATURE, 3) + */ +#define PVDEC_SIGNATURE_GROUP_4 BIT(4) +/* + * Signature group 5: + * REG( PVDEC_VEC_BE, CR_GDEC_FRAGMENT_SIGNATURE) + * REG( PVDEC_VEC_BE, CR_SLICE_STRUCTURE_SIGNATURE) + * REG( PVDEC_VEC_BE, CR_SLICE_STRUCTURE_OVER1K_SIGNATURE) + * REG( PVDEC_VEC_BE, CR_MEM_STRUCTURE_SIGNATURE) + * REGREP(PVDEC_VEC_BE, CR_GDEC_BUFFER_SIGNATURE, 0) + * REGREP(PVDEC_VEC_BE, CR_GDEC_BUFFER_SIGNATURE, 1) + * REGREP(PVDEC_VEC_BE, CR_GDEC_BUFFER_SIGNATURE, 2) + * REGREP(PVDEC_VEC_BE, CR_GDEC_BUFFER_SIGNATURE, 3) + */ +#define PVDEC_SIGNATURE_GROUP_5 BIT(5) +/* -- RESIDUAL AND COMMAND DEBUG--------------------------------- */ +/* + * Signature group 12: + * REG(PVDEC_VEC_BE, CR_DECODE_TO_COMMAND_PRIME_SIGNATURE) + * REG(PVDEC_VEC_BE, CR_DECODE_TO_COMMAND_SECOND_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_12 BIT(12) +/* + * Signature group 13: + * REG(PVDEC_VEC_BE, CR_DECODE_TO_RESIDUAL_PRIME_SIGNATURE) + * REG(PVDEC_VEC_BE, CR_DECODE_TO_RESIDUAL_SECOND_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_13 BIT(13) +/* + * Signature group 14: + * REG(PVDEC_VEC_BE, CR_COMMAND_ABOVE_READ_SIGNATURE) + * REG(PVDEC_VEC_BE, CR_COMMAND_ABOVE_WRITE_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_14 BIT(14) +/* + * Signature group 15: + * REG(PVDEC_VEC_BE, CR_TEMPORAL_READ_SIGNATURE) + * REG(PVDEC_VEC_BE, CR_TEMPORAL_WRITE_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_15 BIT(15) +/* --VEC--------------------------------------------------------- */ +/* + * Signature group 16: + * REG(PVDEC_VEC_BE, CR_COMMAND_OUTPUT_SIGNATURE) + * REG(MSVDX_VEC, CR_VEC_IXFORM_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_16 BIT(16) +/* + * Signature group 17: + * REG(PVDEC_VEC_BE, CR_RESIDUAL_OUTPUT_SIGNATURE) + * REG(MSVDX_VEC, CR_VEC_COMMAND_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_17 BIT(17) +/* --VDMC-------------------------------------------------------- */ +/* + * Signature group 18: + * REG(MSVDX_VDMC, CR_VDMC_REFERENCE_CACHE_SIGNATURE) + * REG(MSVDX_VDMC, CR_VDMC_REFERENCE_CACHE_MEM_WADDR_SIGNATURE) + * REG(MSVDX_VDMC, CR_VDMC_REFERENCE_CACHE_MEM_RADDR_SIGNATURE) + * REG(MSVDX_VDMC, CR_VDMC_REFERENCE_CACHE_MEM_WDATA_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_18 BIT(18) +/* + * Signature group 19: + * REG(MSVDX_VDMC, CR_VDMC_2D_FILTER_PIPELINE_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_19 BIT(19) +/* + * Signature group 20: + * REG(MSVDX_VDMC, CR_VDMC_PIXEL_RECONSTRUCTION_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_20 BIT(20) +/* + * Signature group 21: + * REG(MSVDX_VDMC, CR_VDMC_MCU_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_21 BIT(21) +/* ---VDEB------------------------------------------------------- */ +/* + * Signature group 22: + * REG(MSVDX_VDEB, CR_VDEB_SYS_MEM_RDATA_LUMA_SIGNATURE) + * REG(MSVDX_VDEB, CR_VDEB_SYS_MEM_RDATA_CHROMA_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_22 BIT(22) +/* + * Signature group 23: + * REG(MSVDX_VDEB, CR_VDEB_SYS_MEM_ADDR_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_23 BIT(23) +/* + * Signature group 24: + * REG(MSVDX_VDEB, CR_VDEB_SYS_MEM_WDATA_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_24 BIT(24) +/* ---SCALER----------------------------------------------------- */ +/* + * Signature group 25: + * REG(MSVDX_VDEB, CR_VDEB_SCALE_ADDR_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_25 BIT(25) +/* + * Signature group 26: + * REG(MSVDX_VDEB, CR_VDEB_SCALE_WDATA_SIGNATURE) + */ +#define PVDEC_SIGNATURE_GROUP_26 BIT(26) +/* ---PICTURE CHECKSUM------------------------------------------- */ +/* + * Signature group 27: + * REG(MSVDX_VDEB, CR_VDEB_HEVC_CHECKSUM_LUMA) + * REG(MSVDX_VDEB, CR_VDEB_HEVC_CHECKSUM_CB) + * REG(MSVDX_VDEB, CR_VDEB_HEVC_CHECKSUM_CR) + */ +#define PVDEC_SIGNATURE_GROUP_27 BIT(27) +#define PVDEC_SIGNATURE_NEW_METHOD BIT(31) + +/* Debug messages */ +#define DEBUG_DATA_TYPE_MASK 0xF +#define DEBUG_DATA_TYPE_SHIFT 28 + +#define DEBUG_DATA_MSG_TYPE_MASK 0x1 +#define DEBUG_DATA_MSG_TYPE_SHIFT 15 + +#define DEBUG_DATA_MSG_ARG_COUNT_MASK 0x7 +#define DEBUG_DATA_MSG_ARG_COUNT_SHIFT 12 + +#define DEBUG_DATA_MSG_LINE_NO_MASK 0xFFF +#define DEBUG_DATA_MSG_LINE_NO_SHIFT 0 + +#define DEBUG_DATA_TYPE_HEADER (0) +#define DEBUG_DATA_TYPE_STRING (1) +#define DEBUG_DATA_TYPE_PARAMS (2) +#define DEBUG_DATA_TYPE_MSG (3) +#define DEBUG_DATA_TYPE_PERF (6) + +#define DEBUG_DATA_MSG_TYPE_LOG 0 +#define DEBUG_DATA_MSG_TYPE_ASSERT 1 + +#define DEBUG_DATA_TAPE_PERF_INC_TIME_MASK 0x1 +#define DEBUG_DATA_TYPE_PERF_INC_TIME_SHIFT 28 +#define DEBUG_DATA_TYPE_PERF_INC_TIME 0x1 + +#define DEBUG_DATA_SET_TYPE(val, type, data_type) \ + ({ \ + data_type __val = val; \ + ((__val) = (__val & ~(DEBUG_DATA_TYPE_MASK << DEBUG_DATA_TYPE_SHIFT)) | \ + ((type) << DEBUG_DATA_TYPE_SHIFT)); }) + +#define DEBUG_DATA_MSG_SET_ARG_COUNT(val, ac, data_type) \ + ({ \ + data_type __val = val; \ + (__val = (__val & \ + ~(DEBUG_DATA_MSG_ARG_COUNT_MASK << DEBUG_DATA_MSG_ARG_COUNT_SHIFT)) \ + | ((ac) << DEBUG_DATA_MSG_ARG_COUNT_SHIFT)); }) + +#define DEBUG_DATA_MSG_SET_LINE_NO(val, ln, type) \ + ({ \ + type __val = val; \ + (__val = (__val & \ + ~(DEBUG_DATA_MSG_LINE_NO_MASK << DEBUG_DATA_MSG_LINE_NO_SHIFT)) \ + | ((ln) << DEBUG_DATA_MSG_LINE_NO_SHIFT)); }) + +#define DEBUG_DATA_MSG_SET_TYPE(val, tp, type) \ + ({ \ + type __val = val; \ + (__val = (__val & \ + ~(DEBUG_DATA_MSG_TYPE_MASK << DEBUG_DATA_MSG_TYPE_SHIFT)) \ + | ((tp) << DEBUG_DATA_MSG_TYPE_SHIFT)); }) + +#define DEBUG_DATA_GET_TYPE(val) \ + (((val) >> DEBUG_DATA_TYPE_SHIFT) & DEBUG_DATA_TYPE_MASK) +#define DEBUG_DATA_TYPE_PERF_IS_INC_TIME(val) \ + (((val) >> DEBUG_DATA_TYPE_PERF_INC_TIME_SHIFT) \ + & DEBUG_DATA_TAPE_PERF_INC_TIME_MASK) +#define DEBUG_DATA_MSG_GET_ARG_COUNT(val) \ + (((val) >> DEBUG_DATA_MSG_ARG_COUNT_SHIFT) \ + & DEBUG_DATA_MSG_ARG_COUNT_MASK) +#define DEBUG_DATA_MSG_GET_LINE_NO(val) \ + (((val) >> DEBUG_DATA_MSG_LINE_NO_SHIFT) \ + & DEBUG_DATA_MSG_LINE_NO_MASK) +#define DEBUG_DATA_MSG_GET_TYPE(val) \ + (((val) >> DEBUG_DATA_MSG_TYPE_SHIFT) & DEBUG_DATA_MSG_TYPE_MASK) +#define DEBUG_DATA_MSG_TYPE_IS_ASSERT(val) \ + (DEBUG_DATA_MSG_GET_TYPE(val) == DEBUG_DATA_MSG_TYPE_ASSERT \ + ? IMG_TRUE : IMG_FALSE) +#define DEBUG_DATA_MSG_TYPE_IS_LOG(val) \ + (DEBUG_DATA_MSG_GET_TYPE(val) == DEBUG_DATA_MSG_TYPE_LOG ? \ + IMG_TRUE : IMG_FALSE) + +#define DEBUG_DATA_MSG_LAT(ln, ac, tp) \ + (((ln) << DEBUG_DATA_MSG_LINE_NO_SHIFT) | \ + ((ac) << DEBUG_DATA_MSG_ARG_COUNT_SHIFT) | \ + ((tp) << DEBUG_DATA_MSG_TYPE_SHIFT)) +/* FWBSP-mode specific defines. */ +#ifdef VDEC_USE_PVDEC_SEC +/** + * FWBSP_ENC_BSTR_BUF_QUEUE_LEN - Suggested number of bitstream buffers submitted (queued) + * to firmware for processing at the same time. + */ +#define FWBSP_ENC_BSTR_BUF_QUEUE_LEN 1 + +#endif /* VDEC_USE_PVDEC_SEC */ + +#endif /* VDEC_USE_PVDEC_COMPATIBILITY */ +#endif /* FW_INTERFACE_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/h264fw_data.h b/drivers/media/platform/imagination/vxe-vxd/decoder/h264fw_data.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/h264fw_data.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/h264fw_data.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,652 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Public data structures for the h264 parser firmware module. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +/* Include shared header version here to replace the standard version */ +#include "h264fw_data_shared.h" + +#ifndef _H264FW_DATA_H_ +#define _H264FW_DATA_H_ + +#include "vdecfw_shared.h" + +/* Maximum number of alternative CPB specifications in the stream */ +#define H264_MAXIMUMVALUEOFCPB_CNT 32 + +/* + * The maximum DPB size is related to the number of MVC views supported + * The size is defined in H.10.2 for the H.264 spec. + * If the number of views needs to be changed the DPB size should be too + * The limits are as follows: + * NumViews 1, 2, 4, 8, 16 + * MaxDpbFrames: 16, 16, 32, 48, 64 + */ +#ifdef H264_ENABLE_MVC +#define H264FW_MAX_NUM_VIEWS 4 +#define H264FW_MAX_DPB_SIZE 32 +#define H264FW_MAX_NUM_MVC_REFS 16 +#else +#define H264FW_MAX_NUM_VIEWS 1 +#define H264FW_MAX_DPB_SIZE 16 +#define H264FW_MAX_NUM_MVC_REFS 1 +#endif + +/* Maximum value for num_ref_frames_in_pic_order_cnt_cycle */ +#define H264FW_MAX_CYCLE_REF_FRAMES 256 + +/* 4x4 scaling list size */ +#define H264FW_4X4_SIZE 16 +/* 8x8 scaling list size */ +#define H264FW_8X8_SIZE 64 +/* Number of 4x4 scaling lists */ +#define H264FW_NUM_4X4_LISTS 6 +/* Number of 8x8 scaling lists */ +#define H264FW_NUM_8X8_LISTS 6 + +/* Number of reference picture lists */ +#define H264FW_MAX_REFPIC_LISTS 2 + +/* + * The maximum number of slice groups + * remove if slice group map is prepared on the host + */ +#define H264FW_MAX_SLICE_GROUPS 8 + +/* The maximum number of planes for 4:4:4 separate color plane streams */ +#define H264FW_MAX_PLANES 3 + +#define H264_MAX_SGM_SIZE 8196 + +#define IS_H264_HIGH_PROFILE(profile_idc, type) \ + ({ \ + type __profile_idc = profile_idc; \ + ((__profile_idc) == H264_PROFILE_HIGH) || \ + ((__profile_idc) == H264_PROFILE_HIGH10) || \ + ((__profile_idc) == H264_PROFILE_HIGH422) || \ + ((__profile_idc) == H264_PROFILE_HIGH444) || \ + ((__profile_idc) == H264_PROFILE_CAVLC444) || \ + ((__profile_idc) == H264_PROFILE_MVC_HIGH) || \ + ((__profile_idc) == H264_PROFILE_MVC_STEREO); }) \ + +/* + * This type describes the H.264 NAL unit types + */ +enum h264_enaltype { + H264FW_NALTYPE_SLICE = 1, + H264FW_NALTYPE_IDRSLICE = 5, + H264FW_NALTYPE_SEI = 6, + H264FW_NALTYPE_SPS = 7, + H264FW_NALTYPE_PPS = 8, + H264FW_NALTYPE_AUD = 9, + H264FW_NALTYPE_EOSEQ = 10, + H264FW_NALTYPE_EOSTR = 11, + H264FW_NALTYPE_PREFIX = 14, + H264FW_NALTYPE_SUBSET_SPS = 15, + H264FW_NALTYPE_AUXILIARY_SLICE = 19, + H264FW_NALTYPE_EXTSLICE = 20, + H264FW_NALTYPE_EXTSLICE_DEPTH_VIEW = 21, + H264FW_NALTYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * AVC Profile IDC definitions + */ +enum h264_eprofileidc { + /* YUV 4:4:4/14 "CAVLC 4:4:4 */ + H264_PROFILE_CAVLC444 = 44, + /* YUV 4:2:0/8 "Baseline */ + H264_PROFILE_BASELINE = 66, + /* YUV 4:2:0/8 "Main */ + H264_PROFILE_MAIN = 77, + /* YUV 4:2:0/8 "Scalable" */ + H264_PROFILE_SCALABLE = 83, + /* YUV 4:2:0/8 "Extended" */ + H264_PROFILE_EXTENDED = 88, + /* YUV 4:2:0/8 "High" */ + H264_PROFILE_HIGH = 100, + /* YUV 4:2:0/10 "High 10" */ + H264_PROFILE_HIGH10 = 110, + /* YUV 4:2:0/8 "Multiview High" */ + H264_PROFILE_MVC_HIGH = 118, + /* YUV 4:2:2/10 "High 4:2:2" */ + H264_PROFILE_HIGH422 = 122, + /* YUV 4:2:0/8 "Stereo High" */ + H264_PROFILE_MVC_STEREO = 128, + /* YUV 4:4:4/14 "High 4:4:4" */ + H264_PROFILE_HIGH444 = 244, + H264_PROFILE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This type defines the constraint set flags + */ +enum h264fw_econstraint_flag { + /* Compatible with Baseline profile */ + H264FW_CONSTRAINT_BASELINE_SHIFT = 7, + /* Compatible with Main profile */ + H264FW_CONSTRAINT_MAIN_SHIFT = 6, + /* Compatible with Extended profile */ + H264FW_CONSTRAINT_EXTENDED_SHIFT = 5, + /* Compatible with Intra profiles */ + H264FW_CONSTRAINT_INTRA_SHIFT = 4, + /* Compatible with Multiview High profile */ + H264FW_CONSTRAINT_MULTIHIGH_SHIFT = 3, + /* Compatible with Stereo High profile */ + H264FW_CONSTRAINT_STEREOHIGH_SHIFT = 2, + /* Reserved flag */ + H264FW_CONSTRAINT_RESERVED6_SHIFT = 1, + /* Reserved flag */ + H264FW_CONSTRAINT_RESERVED7_SHIFT = 0, + H264FW_CONSTRAINT_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This enum describes the reference status of an H.264 picture. + * Unpaired fields should have all eRefStatusX set to the same value + * + * For Frame, Mbaff, and Pair types individual fields and frame ref status + * should be set accordingly. + * + * eRefStatusFrame eRefStatusTop eRefStatusBottom + * UNUSED UNUSED UNUSED + * SHORTTERM SHORTTERM SHORTTERM + * LONGTERM LONGTERM LONGTERM + * + * UNUSED SHORT/LONGTERM UNUSED + * UNUSED UNUSED SHORT/LONGTERM + * + * SHORTTERM LONGTERM SHORTTERM + * SHORTTERM SHORTTERM LONGTERM + * NB: It is not clear from the spec if the Frame should be marked as short + * or long term in this case + */ +enum h264fw_ereference { + /* Picture is unused for reference */ + H264FW_REF_UNUSED = 0, + /* used for short term reference */ + H264FW_REF_SHORTTERM, + /* used for Long Term reference */ + H264FW_REF_LONGTERM, + H264FW_REF_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This type defines the picture structure. + */ +enum h264fw_epicture_type { + /* No valid picture */ + H264FW_TYPE_NONE = 0, + /* Picture contains the top (even) lines of the frame */ + H264FW_TYPE_TOP, + /* Picture contains the bottom (odd) lines of the frame */ + H264FW_TYPE_BOTTOM, + /* Picture contains the entire frame */ + H264FW_TYPE_FRAME, + /* Picture contains an MBAFF frame */ + H264FW_TYPE_MBAFF, + /* Picture contains top and bottom lines of the frame */ + H264FW_TYPE_PAIR, + H264FW_TYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This describes the SPS header data required by the H264 firmware that should + * be supplied by the Host. + */ +struct h264fw_sequence_ps { + /* syntax elements from SPS */ + /* syntax element from bitstream - 8 bit */ + unsigned char profile_idc; + /* syntax element from bitstream - 2 bit */ + unsigned char chroma_format_idc; + /* syntax element from bitstream - 1 bit */ + unsigned char separate_colour_plane_flag; + /* syntax element from bitstream - 3 bit */ + unsigned char bit_depth_luma_minus8; + /* syntax element from bitstream - 3 bit */ + unsigned char bit_depth_chroma_minus8; + /* syntax element from bitstream - 1 bit */ + unsigned char delta_pic_order_always_zero_flag; + /* syntax element from bitstream - 4+ bit */ + unsigned char log2_max_pic_order_cnt_lsb; + /* syntax element from bitstream - 5 bit */ + unsigned char max_num_ref_frames; + /* syntax element from bitstream - 4+ bit */ + unsigned char log2_max_frame_num; + /* syntax element from bitstream - 2 bit */ + unsigned char pic_order_cnt_type; + /* syntax element from bitstream - 1 bit */ + unsigned char frame_mbs_only_flag; + /* syntax element from bitstream - 1 bit */ + unsigned char gaps_in_frame_num_value_allowed_flag; + + /* + * set0--7 flags as they occur in the bitstream (including reserved + * values) + */ + unsigned char constraint_set_flags; + /* syntax element from bitstream - 8 bit */ + unsigned char level_idc; + /* syntax element from bitstream - 8 bit */ + unsigned char num_ref_frames_in_pic_order_cnt_cycle; + /* syntax element from bitstream - 1 bit */ + unsigned char mb_adaptive_frame_field_flag; + /* syntax element from bitstream - 32 bit */ + int offset_for_non_ref_pic; + /* syntax element from bitstream - 32 bit */ + int offset_for_top_to_bottom_field; + + /* syntax element from bitstream */ + unsigned int pic_width_in_mbs_minus1; + /* syntax element from bitstream */ + unsigned int pic_height_in_map_units_minus1; + /* syntax element from bitstream - 1 bit */ + unsigned char direct_8x8_inference_flag; + /* syntax element from bitstream */ + unsigned char qpprime_y_zero_transform_bypass_flag; + + /* syntax element from bitstream - 32 bit each */ + int offset_for_ref_frame[H264FW_MAX_CYCLE_REF_FRAMES]; + + /* From VUI information */ + unsigned char num_reorder_frames; + /* + * From VUI/MVC SEI, 0 indicates not set, any actual 0 value will be + * inferred by the firmware + */ + unsigned char max_dec_frame_buffering; + + /* From SPS MVC Extension - for the current view_id */ + /* Number of views in this stream */ + unsigned char num_views; + /* a Map in order of VOIdx of view_id's */ + unsigned short view_ids[H264FW_MAX_NUM_VIEWS]; + + /* Disable VDMC horizontal/vertical filtering */ + unsigned char disable_vdmc_filt; + /* Disable CABAC 4:4:4 4x4 transform as not available */ + unsigned char transform4x4_mb_not_available; + + /* anchor reference list */ + unsigned short anchor_inter_view_reference_id_list[2] + [H264FW_MAX_NUM_VIEWS][H264FW_MAX_NUM_MVC_REFS]; + /* nonanchor reference list */ + unsigned short non_anchor_inter_view_reference_id_list[2] + [H264FW_MAX_NUM_VIEWS][H264FW_MAX_NUM_MVC_REFS]; + /* number of elements in aui16AnchorInterViewReferenceIndiciesLX[] */ + unsigned short num_anchor_refsx[2][H264FW_MAX_NUM_VIEWS]; + /* number of elements in aui16NonAnchorInterViewReferenceIndiciesLX[] */ + unsigned short num_non_anchor_refsx[2][H264FW_MAX_NUM_VIEWS]; +}; + +/* + * This structure represents HRD parameters. + */ +struct h264fw_hrd { + /* cpb_cnt_minus1 */ + unsigned char cpb_cnt_minus1; + /* bit_rate_scale */ + unsigned char bit_rate_scale; + /* cpb_size_scale */ + unsigned char cpb_size_scale; + /* bit_rate_value_minus1 */ + unsigned int bit_rate_value_minus1[H264_MAXIMUMVALUEOFCPB_CNT]; + /* cpb_size_value_minus1 */ + unsigned int cpb_size_value_minus1[H264_MAXIMUMVALUEOFCPB_CNT]; + /* cbr_flag */ + unsigned char cbr_flag[H264_MAXIMUMVALUEOFCPB_CNT]; + /* initial_cpb_removal_delay_length_minus1 */ + unsigned char initial_cpb_removal_delay_length_minus1; + /* cpb_removal_delay_length_minus1 */ + unsigned char cpb_removal_delay_length_minus1; + /* dpb_output_delay_length_minus1 */ + unsigned char dpb_output_delay_length_minus1; + /* time_offset_length */ + unsigned char time_offset_length; +}; + +/* + * This structure represents the VUI parameters data. + */ +struct h264fw_vui { + int aspect_ratio_info_present_flag; + unsigned char aspect_ratio_idc; + unsigned short sar_width; + unsigned short sar_height; + int overscan_info_present_flag; + int overscan_appropriate_flag; + int video_signal_type_present_flag; + unsigned char video_format; + int video_full_range_flag; + int colour_description_present_flag; + unsigned char colour_primaries; + unsigned char transfer_characteristics; + unsigned char matrix_coefficients; + int chroma_location_info_present_flag; + unsigned int chroma_sample_loc_type_top_field; + unsigned int chroma_sample_loc_type_bottom_field; + int timing_info_present_flag; + unsigned int num_units_in_tick; + unsigned int time_scale; + int fixed_frame_rate_flag; + int nal_hrd_parameters_present_flag; + struct h264fw_hrd nal_hrd_params; + int vcl_hrd_parameters_present_flag; + struct h264fw_hrd vcl_hrd_params; + int low_delay_hrd_flag; + int pic_struct_present_flag; + int bitstream_restriction_flag; + int motion_vectors_over_pic_boundaries_flag; + unsigned int max_bytes_per_pic_denom; + unsigned int max_bits_per_mb_denom; + unsigned int log2_max_mv_length_vertical; + unsigned int log2_max_mv_length_horizontal; + unsigned int num_reorder_frames; + unsigned int max_dec_frame_buffering; +}; + +/* + * This describes the HW specific SPS header data required by the H264 + * firmware that should be supplied by the Host. + */ +struct h264fw_ddsequence_ps { + /* pre-packed registers derived from SPS */ + /* Value for CR_VEC_ENTDEC_FE_CONTROL */ + unsigned int regentdec_control; + + /* NB: This register should contain the 4-bit SGM flag */ + /* Value for CR_VEC_H264_FE_SPS0 & CR_VEC_H264_BE_SPS0 combined */ + unsigned int reg_sps0; + /* Value of CR_VEC_H264_BE_INTRA_8x8 */ + unsigned int reg_beintra; + /* Value of CR_VEC_H264_FE_CABAC444 */ + unsigned int reg_fecaabac444; + /* Treat CABAC 4:4:4 4x4 transform as not available */ + unsigned char transform4x4_mb_notavialbale; + /* Disable VDMC horizontal/vertical filtering */ + unsigned char disable_vdmcfilt; +}; + +/* + * This describes the PPS header data required by the H264 firmware that should + * be supplied by the Host. + */ +struct h264fw_picture_ps { + /* syntax elements from the PPS */ + /* syntax element from bitstream - 1 bit */ + unsigned char deblocking_filter_control_present_flag; + /* syntax element from bitstream - 1 bit */ + unsigned char transform_8x8_mode_flag; + /* syntax element from bitstream - 1 bit */ + unsigned char entropy_coding_mode_flag; + /* syntax element from bitstream - 1 bit */ + unsigned char redundant_pic_cnt_present_flag; + + /* syntax element from bitstream - 2 bit */ + unsigned char weighted_bipred_idc; + /* syntax element from bitstream - 1 bit */ + unsigned char weighted_pred_flag; + /* syntax element from bitstream - 1 bit */ + unsigned char pic_order_present_flag; + + /* 26 + syntax element from bitstream - 7 bit */ + unsigned char pic_init_qp; + /* syntax element from bitstream - 1 bit */ + unsigned char constrained_intra_pred_flag; + /* syntax element from bitstream - 5 bit each */ + unsigned char num_ref_lx_active_minus1[H264FW_MAX_REFPIC_LISTS]; + + /* syntax element from bitstream - 3 bit */ + unsigned char slice_group_map_type; + /* syntax element from bitstream - 3 bit */ + unsigned char num_slice_groups_minus1; + /* syntax element from bitstream - 13 bit */ + unsigned short slice_group_change_rate_minus1; + + /* syntax element from bitstream */ + unsigned int chroma_qp_index_offset; + /* syntax element from bitstream */ + unsigned int second_chroma_qp_index_offset; + + /* scaling lists are derived from both SPS and PPS information */ + /* but will change whenever the PPS changes */ + /* The derived set of tables are associated here with the PPS */ + /* NB: These are in H.264 order */ + /* derived from SPS and PPS - 8 bit each */ + unsigned char scalinglist4x4[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE]; + /* derived from SPS and PPS - 8 bit each */ + unsigned char scalinglist8x8[H264FW_NUM_8X8_LISTS][H264FW_8X8_SIZE]; +}; + +/* + * This describes the HW specific PPS header data required by the H264 + * firmware that should be supplied by the Host. + */ +struct h264fw_dd_picture_ps { + /* values derived from the PPS */ + /* Value for MSVDX_CMDS_SLICE_PARAMS_MODE_CONFIG */ + unsigned char vdmc_mode_config; + + /* pre-packed registers derived from the PPS */ + /* Value for CR_VEC_H264_FE_PPS0 & CR_VEC_H264_BE_PPS0 combined */ + unsigned int reg_pps0; + + /* + * scaling lists are derived from both SPS and PPS information + * but will change whenever the PPS changes + * The derived set of tables are associated here with the PPS + * But this will become invalid if the SPS changes and will have to be + * recalculated + * These tables MUST be aligned on a 32-bit boundary + * NB: These are in MSVDX order + */ + /* derived from SPS and PPS - 8 bit each */ + unsigned char scalinglist4x4[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE]; + /* derived from SPS and PPS - 8 bit each */ + unsigned char scalinglist8x8[H264FW_NUM_8X8_LISTS][H264FW_8X8_SIZE]; +}; + +/* + * This describes the H.264 parser component "Header data", shown in the + * Firmware Memory Layout diagram. This data is required by the H264 firmware + * and should be supplied by the Host. + */ +struct h264fw_header_data { + /* Decode buffers and output control for the current picture */ + /* Primary decode buffer base addresses */ + struct vdecfw_image_buffer primary; + /* buffer base addresses for alternate output */ + struct vdecfw_image_buffer alternate; + /* Output control: rotation, scaling, oold, etc. */ + unsigned int pic_cmds[VDECFW_CMD_MAX]; + /* Macroblock parameters base address for the picture */ + unsigned int mbparams_base_address; + + unsigned int mbparams_size_per_plane; + + /* Buffers for context preload for colour plane switching (6.x.x) */ + unsigned int preload_buffer_base_address + [H264FW_MAX_PLANES]; + + /* + * slice group map should be calculated on Host + * (using some slice params) and base address provided here + */ + /* Base address of active slice group map */ + /* Base address of active slice group map */ + unsigned int slicegroupmap_base_address; + + /* H264 specific control */ + /* do second pass Intra Deblock on frame */ + unsigned int do_old __attribute__ (aligned(4)); + /* set to IMG_FALSE to disable second-pass deblock */ + unsigned int two_pass_flag __attribute__ (aligned(4)); + /* set to IMG_TRUE to disable MVC */ + unsigned int disable_mvc __attribute__ (aligned(4)); + /* + * Do we have second PPS in uipSecondPPSInfoSource provided for the + * second field + */ + unsigned int second_pps __attribute__ (aligned(4)); +}; + +/* + * This describes an H.264 picture. It is part of the Context data + */ +struct h264fw_picture { + /* Primary (reconstructed) picture buffers */ + struct vdecfw_image_buffer primary; + /* Secondary (alternative) picture buffers */ + struct vdecfw_image_buffer alternate; + /* Macroblock parameters base address for the picture */ + unsigned int mbparams_base_address; + + /* Unique ID for this picture */ + unsigned int transaction_id; + /* Picture type */ + enum h264fw_epicture_type pricture_type; + + /* Reference status of the picture */ + enum h264fw_ereference ref_status_bottom; + /* Reference status of the picture */ + enum h264fw_ereference ref_status_top; + /* Reference status of the picture */ + enum h264fw_ereference ref_status_frame; + + /* Frame Number */ + unsigned int frame_number; + /* Short term reference info */ + int fame_number_wrap; + /* long term reference number - should be 8-bit */ + unsigned int longterm_frame_idx; + + /* Top field order count for this picture */ + int top_field_order_count; + /* Bottom field order count for this picture */ + int bottom_field_order_count; + /* MVC view_id */ + unsigned short view_id; + /* + * When picture is in the DPB Offset to use into the MSVDX DPB reg table + * when the current picture is the same view as this. + */ + unsigned char view_dpb_offset; + /* Flags for this picture for the display process */ + unsigned char display_flags; + + /* IMG_FALSE if sent to display, or otherwise not needed for display */ + unsigned char needed_for_output; +}; + +/* + * This structure describes frame data for POC calculation + */ +struct h264fw_poc_picture_data { + /* type 0,1,2 */ + unsigned char mmco_5_flag; + + /* type 0 */ + unsigned char bottom_field_flag; + unsigned short pic_order_cnt_lsb; + int top_field_order_count; + int pic_order_count_msb; + + /* type 1,2 */ + int16 frame_num; + int frame_num_offset; + + /* output */ + int bottom_filed_order_count; +}; + +/* + * This structure describes picture data for determining Complementary + * Field Pairs + */ +struct h264fw_last_pic_data { + /* Unique ID for this picture */ + unsigned int transaction_id; + /* Picture type */ + enum h264fw_epicture_type picture_type; + /* Reference status of the picture */ + enum h264fw_ereference ref_status_frame; + /* Frame Number */ + unsigned int frame_number; + + unsigned int luma_recon; + unsigned int chroma_recon; + unsigned int chroma_2_recon; + unsigned int luma_alter; + unsigned int chroma_alter; + unsigned int chroma_2_alter; + struct vdecfw_image_buffer primary; + struct vdecfw_image_buffer alternate; + unsigned int mbparams_base_address; + /* Top field order count for this picture */ + int top_field_order_count; + /* Bottom field order count for this picture */ + int bottom_field_order_count; +}; + +/* + * This describes the H.264 parser component "Context data", shown in the + * Firmware Memory Layout diagram. This data is the state preserved across + * pictures. It is loaded and saved by the Firmware, but requires the host to + * provide buffer(s) for this. + */ +struct h264fw_context_data { + /* Decoded Picture Buffer */ + struct h264fw_picture dpb[H264FW_MAX_DPB_SIZE]; + /* + * Inter-view reference components - also used as detail of the previous + * picture for any particular view, can be used to determine + * complemetary field pairs + */ + struct h264fw_picture interview_prediction_ref[H264FW_MAX_NUM_VIEWS]; + /* previous ref pic for type0, previous pic for type1&2 */ + struct h264fw_poc_picture_data prev_poc_pic_data[H264FW_MAX_NUM_VIEWS]; + /* previous picture information to detect complementary field pairs */ + struct h264fw_last_pic_data last_pic_data[H264FW_MAX_NUM_VIEWS]; + struct h264fw_last_pic_data last_displayed_pic_data + [H264FW_MAX_NUM_VIEWS]; + + /* previous reference frame number for each view */ + unsigned short prev_ref_frame_num[H264FW_MAX_NUM_VIEWS]; + /* Bitmap of used slots in each view DPB */ + unsigned short dpb_bitmap[H264FW_MAX_NUM_VIEWS]; + + /* DPB size */ + unsigned int dpb_size; + /* Number of pictures in DPB */ + unsigned int dpb_fullness; + + unsigned char prev_display_flags; + int prev_display; + int prev_release; + /* Active parameter sets */ + /* Sequence Parameter Set data */ + struct h264fw_sequence_ps sps; + /* Picture Parameter Set data */ + struct h264fw_picture_ps pps; + /* + * Picture Parameter Set data for second field when in the same buffer + */ + struct h264fw_picture_ps second_pps; + + /* Set if stream is MVC */ + int mvc; + /* DPB long term reference information */ + int max_longterm_frame_idx[H264FW_MAX_NUM_VIEWS]; +}; + +#endif /* _H264FW_DATA_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/h264fw_data_shared.h b/drivers/media/platform/imagination/vxe-vxd/decoder/h264fw_data_shared.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/h264fw_data_shared.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/h264fw_data_shared.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,760 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Public data structures for the h264 parser firmware module + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ +#ifdef USE_SHARING +#endif + +#ifndef _H264FW_DATA_H_ +#define _H264FW_DATA_H_ + +#include "vdecfw_share.h" +#include "vdecfw_shared.h" + +#define H264_MAX_SPS_COUNT 32 +#define H264_MAX_PPS_COUNT 256 + +#define H264_SCALING_LISTS_NUM_CHROMA_IDC_NON_3 (8) +#define H264_SCALING_LISTS_NUM_CHROMA_IDC_3 (12) +#define MAX_PIC_SCALING_LIST (12) + +/* Maximum number of alternative CPB specifications in the stream */ +#define H264_MAXIMUMVALUEOFCPB_CNT 32 + +/* + * The maximum DPB size is related to the number of MVC views supported + * The size is defined in H.10.2 for the H.264 spec. + * If the number of views needs to be changed the DPB size should be too + * The limits are as follows: + * NumViews: 1, 2, 4, 8, 16 + * MaxDpbFrames: 16, 16, 32, 48, 64 + */ + +/* firmware supports MVC - so need 16 refs */ +#define H264FW_MAX_NUM_VIEWS 4 +#define H264FW_MAX_DPB_SIZE 32 +#define H264FW_MAX_NUM_MVC_REFS 16 + +/* Number of H264 VLC table configuration registers */ +#define H264FW_NUM_VLC_REG 22 + +/* Maximum value for num_ref_frames_in_pic_order_cnt_cycle */ +#define H264FW_MAX_CYCLE_REF_FRAMES 256 + +/* 4x4 scaling list size */ +#define H264FW_4X4_SIZE 16 +/* 8x8 scaling list size */ +#define H264FW_8X8_SIZE 64 +/* Number of 4x4 scaling lists */ +#define H264FW_NUM_4X4_LISTS 6 +/* Number of 8x8 scaling lists */ +#define H264FW_NUM_8X8_LISTS 6 + +/* Number of reference picture lists */ +#define H264FW_MAX_REFPIC_LISTS 2 + +/* + * The maximum number of slice groups + * remove if slice group map is prepared on the host + */ +#define H264FW_MAX_SLICE_GROUPS 8 + +/* The maximum number of planes for 4:4:4 separate colour plane streams */ +#define H264FW_MAX_PLANES 3 + +#define H264_MAX_SGM_SIZE 8196 + +#define IS_H264_HIGH_PROFILE(profile_idc, type) \ + ({ \ + type __profile_idc = profile_idc; \ + (__profile_idc == H264_PROFILE_HIGH) || \ + (__profile_idc == H264_PROFILE_HIGH10) || \ + (__profile_idc == H264_PROFILE_HIGH422) || \ + (__profile_idc == H264_PROFILE_HIGH444) || \ + (__profile_idc == H264_PROFILE_CAVLC444) || \ + (__profile_idc == H264_PROFILE_MVC_HIGH) || \ + (__profile_idc == H264_PROFILE_MVC_STEREO); }) \ + +/* This type describes the H.264 NAL unit types */ +enum h264_enaltype { + H264FW_NALTYPE_SLICE = 1, + H264FW_NALTYPE_IDRSLICE = 5, + H264FW_NALTYPE_SEI = 6, + H264FW_NALTYPE_SPS = 7, + H264FW_NALTYPE_PPS = 8, + H264FW_NALTYPE_AUD = 9, + H264FW_NALTYPE_EOSEQ = 10, + H264FW_NALTYPE_EOSTR = 11, + H264FW_NALTYPE_PREFIX = 14, + H264FW_NALTYPE_SUBSET_SPS = 15, + H264FW_NALTYPE_AUXILIARY_SLICE = 19, + H264FW_NALTYPE_EXTSLICE = 20, + H264FW_NALTYPE_EXTSLICE_DEPTH_VIEW = 21, + H264FW_NALTYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* AVC Profile IDC definitions */ +enum h264_eprofileidc { + H264_PROFILE_CAVLC444 = 44, + H264_PROFILE_BASELINE = 66, + H264_PROFILE_MAIN = 77, + H264_PROFILE_SCALABLE = 83, + H264_PROFILE_EXTENDED = 88, + H264_PROFILE_HIGH = 100, + H264_PROFILE_HIGH10 = 110, + H264_PROFILE_MVC_HIGH = 118, + H264_PROFILE_HIGH422 = 122, + H264_PROFILE_MVC_STEREO = 128, + H264_PROFILE_HIGH444 = 244, + H264_PROFILE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* This type defines the constraint set flags */ +enum h264fw_econstraint_flag { + H264FW_CONSTRAINT_BASELINE_SHIFT = 7, + H264FW_CONSTRAINT_MAIN_SHIFT = 6, + H264FW_CONSTRAINT_EXTENDED_SHIFT = 5, + H264FW_CONSTRAINT_INTRA_SHIFT = 4, + H264FW_CONSTRAINT_MULTIHIGH_SHIFT = 3, + H264FW_CONSTRAINT_STEREOHIGH_SHIFT = 2, + H264FW_CONSTRAINT_RESERVED6_SHIFT = 1, + H264FW_CONSTRAINT_RESERVED7_SHIFT = 0, + H264FW_CONSTRAINT_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This enum describes the reference status of an H.264 picture. + * + * Unpaired fields should have all eRefStatusX set to the same value + * + * For Frame, Mbaff, and Pair types individual fields and frame ref status + * should be set accordingly. + * + * eRefStatusFrame eRefStatusTop eRefStatusBottom + * UNUSED UNUSED UNUSED + * SHORTTERM SHORTTERM SHORTTERM + * LONGTERM LONGTERM LONGTERM + * + * UNUSED SHORT/LONGTERM UNUSED + * UNUSED UNUSED SHORT/LONGTERM + * + * SHORTTERM LONGTERM SHORTTERM + * SHORTTERM SHORTTERM LONGTERM + * - NB: It is not clear from the spec if the Frame should be marked as short + * or long term in this case + */ +enum h264fw_ereference { + H264FW_REF_UNUSED = 0, + H264FW_REF_SHORTTERM, + H264FW_REF_LONGTERM, + H264FW_REF_FORCE32BITS = 0x7FFFFFFFU +}; + +/* This type defines the picture structure. */ +enum h264fw_epicture_type { + H264FW_TYPE_NONE = 0, + H264FW_TYPE_TOP, + H264FW_TYPE_BOTTOM, + H264FW_TYPE_FRAME, + H264FW_TYPE_MBAFF, + H264FW_TYPE_PAIR, + H264FW_TYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This describes the SPS header data required by the H264 firmware that should + * be supplied by the Host. + */ +struct h264fw_sequence_ps { + /* syntax elements from SPS */ + + /* syntax element from bitstream - 8 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, profile_idc); + /* syntax element from bitstream - 2 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, chroma_format_idc); + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, separate_colour_plane_flag); + /* syntax element from bitstream - 3 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, bit_depth_luma_minus8); + /* syntax element from bitstream - 3 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, bit_depth_chroma_minus8); + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, delta_pic_order_always_zero_flag); + /* syntax element from bitstream - 4+ bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, log2_max_pic_order_cnt_lsb); + + /* syntax element from bitstream - 5 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, max_num_ref_frames); + /* syntax element from bitstream - 4+ bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, log2_max_frame_num); + /* syntax element from bitstream - 2 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pic_order_cnt_type); + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, frame_mbs_only_flag); + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, gaps_in_frame_num_value_allowed_flag); + + /* + * set0--7 flags as they occur in the bitstream + * (including reserved values) + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, constraint_set_flags); + /* syntax element from bitstream - 8 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, level_idc); + /* syntax element from bitstream - 8 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_ref_frames_in_pic_order_cnt_cycle); + + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, mb_adaptive_frame_field_flag); + /* syntax element from bitstream - 32 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, offset_for_non_ref_pic); + /* syntax element from bitstream - 32 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, offset_for_top_to_bottom_field); + + /* syntax element from bitstream */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, pic_width_in_mbs_minus1); + /* syntax element from bitstream */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, pic_height_in_map_units_minus1); + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, direct_8x8_inference_flag); + /* syntax element from bitstream */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, qpprime_y_zero_transform_bypass_flag); + + /* syntax element from bitstream - 32 bit each */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, offset_for_ref_frame[H264FW_MAX_CYCLE_REF_FRAMES]); + + /* From VUI information */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_reorder_frames); + /* + * From VUI/MVC SEI, 0 indicates not set, any actual 0 + * value will be inferred by the firmware + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, max_dec_frame_buffering); + + /* From SPS MVC Extension - for the current view_id */ + + /* Number of views in this stream */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_views); + /* a Map in order of VOIdx of view_id's */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, view_ids[H264FW_MAX_NUM_VIEWS]); + + /* Disable VDMC horizontal/vertical filtering */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, disable_vdmc_filt); + /* Disable CABAC 4:4:4 4x4 transform as not available */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, transform4x4_mb_not_available); + + /* anchor reference list */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned short, + anchor_inter_view_reference_id_list[2][H264FW_MAX_NUM_VIEWS] + [H264FW_MAX_NUM_MVC_REFS]); + /* nonanchor reference list */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned short, + non_anchor_inter_view_reference_id_list[2][H264FW_MAX_NUM_VIEWS] + [H264FW_MAX_NUM_MVC_REFS]); + /* number of elements in aui16AnchorInterViewReferenceIndiciesLX[] */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned short, + num_anchor_refsx[2][H264FW_MAX_NUM_VIEWS]); + /* number of elements in aui16NonAnchorInterViewReferenceIndiciesLX[] */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned short, + num_non_anchor_refsx[2][H264FW_MAX_NUM_VIEWS]); +}; + +/* + * This structure represents HRD parameters. + */ +struct h264fw_hrd { + /* cpb_cnt_minus1; */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, cpb_cnt_minus1); + /* bit_rate_scale; */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, bit_rate_scale); + /* cpb_size_scale; */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, cpb_size_scale); + /* bit_rate_value_minus1 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, + bit_rate_value_minus1[H264_MAXIMUMVALUEOFCPB_CNT]); + /* cpb_size_value_minus1 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, + cpb_size_value_minus1[H264_MAXIMUMVALUEOFCPB_CNT]); + /* cbr_flag */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + cbr_flag[H264_MAXIMUMVALUEOFCPB_CNT]); + /* initial_cpb_removal_delay_length_minus1; */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + initial_cpb_removal_delay_length_minus1); + /* cpb_removal_delay_length_minus1; */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + cpb_removal_delay_length_minus1); + /* dpb_output_delay_length_minus1; */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + dpb_output_delay_length_minus1); + /* time_offset_length; */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, time_offset_length); +}; + +/* + * This structure represents the VUI parameters data. + */ +struct h264fw_vui { + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, aspect_ratio_info_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, aspect_ratio_idc); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, sar_width); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, sar_height); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, overscan_info_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, overscan_appropriate_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, video_signal_type_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, video_format); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, video_full_range_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, colour_description_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, colour_primaries); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, transfer_characteristics); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, matrix_coefficients); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, chroma_location_info_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, chroma_sample_loc_type_top_field); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, chroma_sample_loc_type_bottom_field); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, timing_info_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, num_units_in_tick); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, time_scale); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, fixed_frame_rate_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, nal_hrd_parameters_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + struct h264fw_hrd, nal_hrd_params); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, vcl_hrd_parameters_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + struct h264fw_hrd, vcl_hrd_params); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, low_delay_hrd_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, pic_struct_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, bitstream_restriction_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, motion_vectors_over_pic_boundaries_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, max_bytes_per_pic_denom); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, max_bits_per_mb_denom); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, log2_max_mv_length_vertical); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, log2_max_mv_length_horizontal); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, num_reorder_frames); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, max_dec_frame_buffering); +}; + +/* + * This describes the HW specific SPS header data required by the H264 + * firmware that should be supplied by the Host. + */ +struct h264fw_ddsequence_ps { + /* Value for CR_VEC_ENTDEC_FE_CONTROL */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, regentdec_control); + + /* NB: This register should contain the 4-bit SGM flag */ + + /* Value for CR_VEC_H264_FE_SPS0 & CR_VEC_H264_BE_SPS0 combined */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, reg_sps0); + /* Value of CR_VEC_H264_BE_INTRA_8x8 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, reg_beintra); + /* Value of CR_VEC_H264_FE_CABAC444 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, reg_fecaabac444); + + /* Treat CABAC 4:4:4 4x4 transform as not available */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + transform4x4_mb_notavialbale); + /* Disable VDMC horizontal/vertical filtering */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + disable_vdmcfilt); +}; + +/* + * This describes the PPS header data required by the H264 firmware that should + * be supplied by the Host. + */ +struct h264fw_picture_ps { + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + deblocking_filter_control_present_flag); + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + transform_8x8_mode_flag); + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + entropy_coding_mode_flag); + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + redundant_pic_cnt_present_flag); + + /* syntax element from bitstream - 2 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + weighted_bipred_idc); + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + weighted_pred_flag); + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + pic_order_present_flag); + + /* 26 + syntax element from bitstream - 7 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, pic_init_qp); + /* syntax element from bitstream - 1 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + constrained_intra_pred_flag); + /* syntax element from bitstream - 5 bit each */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + num_ref_lx_active_minus1[H264FW_MAX_REFPIC_LISTS]); + + /* syntax element from bitstream - 3 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + slice_group_map_type); + /* syntax element from bitstream - 3 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + num_slice_groups_minus1); + /* syntax element from bitstream - 13 bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned short, + slice_group_change_rate_minus1); + + /* syntax element from bitstream */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, int, + chroma_qp_index_offset); + /* syntax element from bitstream */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, int, + second_chroma_qp_index_offset); + + /* + * scaling lists are derived from both SPS and PPS information + * but will change whenever the PPS changes + * The derived set of tables are associated here with the PPS + * NB: These are in H.264 order + */ + + /* derived from SPS and PPS - 8 bit each */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + scalinglist4x4[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE]); + /* derived from SPS and PPS - 8 bit each */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + scalinglist8x8[H264FW_NUM_8X8_LISTS][H264FW_8X8_SIZE]); +}; + +/* + * This describes the HW specific PPS header data required by the H264 + * firmware that should be supplied by the Host. + */ +struct h264fw_dd_picture_ps { + /* Value for MSVDX_CMDS_SLICE_PARAMS_MODE_CONFIG */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + vdmc_mode_config); + /* Value for CR_VEC_H264_FE_PPS0 & CR_VEC_H264_BE_PPS0 combined */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, reg_pps0); + + /* + * Scaling lists are derived from both SPS and PPS information + * but will change whenever the PPS changes. The derived set of tables + * are associated here with the PPS, but this will become invalid if + * the SPS changes and will have to be recalculated. + * These tables MUST be aligned on a 32-bit boundary + * NB: These are in MSVDX order + */ + + /* derived from SPS and PPS - 8 bit each */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + scalinglist4x4[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE]); + /* derived from SPS and PPS - 8 bit each */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + scalinglist8x8[H264FW_NUM_8X8_LISTS][H264FW_8X8_SIZE]); +}; + +/* + * This describes the H.264 parser component "Header data", shown in the + * Firmware Memory Layout diagram. This data is required by the H264 firmware + * and should be supplied by the Host. + */ +struct h264fw_header_data { + struct vdecfw_image_buffer primary; + struct vdecfw_image_buffer alternate; + + /* Output control: rotation, scaling, oold, etc. */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, + pic_cmds[VDECFW_CMD_MAX]); + /* Macroblock parameters base address for the picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, + mbparams_base_address); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, + mbparams_size_per_plane); + /* Buffers for context preload for colour plane switching (6.x.x) */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, + preload_buffer_base_address[H264FW_MAX_PLANES]); + /* Base address of active slice group map */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, + slicegroupmap_base_address); + + /* do second pass Intra Deblock on frame */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, do_old); + /* set to IMG_FALSE to disable second-pass deblock */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + two_pass_flag); + /* set to IMG_TRUE to disable MVC */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + disable_mvc); + /* + * Do we have second PPS in uipSecondPPSInfoSource provided + * for the second field. + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + second_pps); +}; + +/* This describes an H.264 picture. It is part of the Context data */ +struct h264fw_picture { + /* Primary (reconstructed) picture buffers */ + struct vdecfw_image_buffer primary; + /* Secondary (alternative) picture buffers */ + struct vdecfw_image_buffer alternate; + /* Macroblock parameters base address for the picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, mbparams_base_address); + + /* Unique ID for this picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, transaction_id); + /* Picture type */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + enum h264fw_epicture_type, pricture_type); + + /* Reference status of the picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + enum h264fw_ereference, ref_status_bottom); + /* Reference status of the picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + enum h264fw_ereference, ref_status_top); + /* Reference status of the picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + enum h264fw_ereference, ref_status_frame); + + /* Frame Number */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, frame_number); + /* Short term reference info */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, frame_number_wrap); + /* long term reference number - should be 8-bit */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, longterm_frame_idx); + + /* Top field order count for this picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, top_field_order_count); + /* Bottom field order count for this picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, bottom_field_order_count); + + /* MVC view_id */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, view_id); + + /* + * When picture is in the DPB Offset to use into + * the MSVDX DPB reg table when the current + * picture is the same view as this. + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, view_dpb_offset); + /* Flags for this picture for the display process */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, display_flags); + + /* IMG_FALSE if sent to display, or otherwise not needed for display */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, needed_for_output); +}; + +/* This structure describes frame data for POC calculation */ +struct h264fw_poc_picture_data { + /* type 0,1,2 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, mmco_5_flag); + + /* type 0 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, bottom_field_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, pic_order_cnt_lsb); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, top_field_order_count); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, pic_order_count_msb); + + /* type 1,2 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, short, frame_num); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, int, frame_num_offset); + + /* output */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, bottom_filed_order_count); +}; + +/* + * This structure describes picture data for determining + * Complementary Field Pairs + */ +struct h264fw_last_pic_data { + /* Unique ID for this picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, transaction_id); + /* Picture type */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + enum h264fw_epicture_type, picture_type); + /* Reference status of the picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + enum h264fw_ereference, ref_status_frame); + /* Frame Number */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, frame_number); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, luma_recon); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, chroma_recon); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, chroma_2_recon); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, luma_alter); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, chroma_alter); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, chroma_2_alter); + + struct vdecfw_image_buffer primary; + struct vdecfw_image_buffer alternate; + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, mbparams_base_address); + /* Top field order count for this picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, top_field_order_count); + /* Bottom field order count for this picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, bottom_field_order_count); +}; + +/* + * This describes the H.264 parser component "Context data", shown in the + * Firmware Memory Layout diagram. This data is the state preserved across + * pictures. It is loaded and saved by the Firmware, but requires the host to + * provide buffer(s) for this. + */ +struct h264fw_context_data { + struct h264fw_picture dpb[H264FW_MAX_DPB_SIZE]; + /* + * Inter-view reference components - also used as detail of the previous + * picture for any particular view, can be used to determine + * complemetary field pairs + */ + struct h264fw_picture interview_prediction_ref[H264FW_MAX_NUM_VIEWS]; + /* previous ref pic for type0, previous pic for type1&2 */ + struct h264fw_poc_picture_data prev_poc_pic_data[H264FW_MAX_NUM_VIEWS]; + /* previous picture information to detect complementary field pairs */ + struct h264fw_last_pic_data last_pic_data[H264FW_MAX_NUM_VIEWS]; + struct h264fw_last_pic_data + last_displayed_pic_data[H264FW_MAX_NUM_VIEWS]; + + /* previous reference frame number for each view */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned short, + prev_ref_frame_num[H264FW_MAX_NUM_VIEWS]); + /* Bitmap of used slots in each view DPB */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned short, + dpb_bitmap[H264FW_MAX_NUM_VIEWS]); + + /* DPB size */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, dpb_size); + /* Number of pictures in DPB */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, + dpb_fullness); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + prev_display_flags); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, int, prev_display); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, int, prev_release); + /* Sequence Parameter Set data */ + struct h264fw_sequence_ps sps; + /* Picture Parameter Set data */ + struct h264fw_picture_ps pps; + /* Picture Parameter Set data for second field if in the same buffer */ + struct h264fw_picture_ps second_pps; + + /* Set if stream is MVC */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, int, mvc); + /* DPB long term reference information */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, int, + max_longterm_frame_idx[H264FW_MAX_NUM_VIEWS]); +}; + +#endif /* _H264FW_DATA_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/h264_idx.h b/drivers/media/platform/imagination/vxe-vxd/decoder/h264_idx.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/h264_idx.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/h264_idx.h 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * h264 idx table definitions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + */ + +#ifndef __H264_IDX_H__ +#define __H264_IDX_H__ + +#include + +static unsigned short h264_vlc_index_data[38][3] = { + { 2, 5, 0 }, /* NumCoeffTrailingOnes_Table9-5_nC_0-1.out */ + { 0, 3, 76 }, /* NumCoeffTrailingOnes_Table9-5_nC_2-3.out */ + { 0, 3, 160 }, /* NumCoeffTrailingOnes_Table9-5_nC_4-7.out */ + { 0, 2, 231 }, /* NumCoeffTrailingOnesFixedLen.out */ + { 2, 2, 244 }, /* NumCoeffTrailingOnesChromaDC_YUV420.out */ + { 2, 5, 261 }, /* NumCoeffTrailingOnesChromaDC_YUV422.out */ + { 2, 5, 301 }, /* TotalZeros_00.out */ + { 0, 2, 326 }, /* TotalZeros_01.out */ + { 0, 2, 345 }, /* TotalZeros_02.out */ + { 0, 2, 363 }, /* TotalZeros_03.out */ + { 0, 2, 379 }, /* TotalZeros_04.out */ + { 0, 2, 394 }, /* TotalZeros_05.out */ + { 0, 2, 406 }, /* TotalZeros_06.out */ + { 0, 1, 418 }, /* TotalZeros_07.out */ + { 0, 1, 429 }, /* TotalZeros_08.out */ + { 0, 1, 438 }, /* TotalZeros_09.out */ + { 2, 2, 446 }, /* TotalZeros_10.out */ + { 2, 2, 452 }, /* TotalZeros_11.out */ + { 2, 1, 456 }, /* TotalZeros_12.out */ + { 0, 0, 459 }, /* TotalZeros_13.out */ + { 0, 0, 461 }, /* TotalZeros_14.out */ + { 2, 2, 463 }, /* TotalZerosChromaDC_YUV420_00.out */ + { 2, 1, 467 }, /* TotalZerosChromaDC_YUV420_01.out */ + { 0, 0, 470 }, /* TotalZerosChromaDC_YUV420_02.out */ + { 0, 0, 472 }, /* Run_00.out */ + { 2, 1, 474 }, /* Run_01.out */ + { 0, 1, 477 }, /* Run_02.out */ + { 0, 1, 481 }, /* Run_03.out */ + { 1, 1, 487 }, /* Run_04.out */ + { 0, 2, 494 }, /* Run_05.out */ + { 0, 2, 502 }, /* Run_06.out */ + { 2, 4, 520 }, /* TotalZerosChromaDC_YUV422_00.out */ + { 2, 2, 526 }, /* TotalZerosChromaDC_YUV422_01.out */ + { 0, 1, 530 }, /* TotalZerosChromaDC_YUV422_02.out */ + { 1, 2, 534 }, /* TotalZerosChromaDC_YUV422_03.out */ + { 0, 0, 538 }, /* TotalZerosChromaDC_YUV422_04.out */ + { 0, 0, 540 }, /* TotalZerosChromaDC_YUV422_05.out */ + { 0, 0, 542 }, /* TotalZerosChromaDC_YUV422_06.out */ +}; + +static const unsigned char h264_vlc_index_size = 38; + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/h264_secure_parser.c b/drivers/media/platform/imagination/vxe-vxd/decoder/h264_secure_parser.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/h264_secure_parser.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/h264_secure_parser.c 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,3047 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * h.264 secure data unit parsing API. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * Re-written for upstreming + * Prashanth Kumar Amai + * Sidraya Jayagond + */ + +#include +#include +#include +#include + +#include "bspp.h" +#include "bspp_int.h" +#include "h264_secure_parser.h" +#include "pixel_api.h" +#include "swsr.h" +#include "vdec_defs.h" + +/* + * Reduce DPB to 1 when no pic reordering. + */ +#define SL_MAX_REF_IDX 32 +#define VUI_CPB_CNT_MAX 32 +#define MAX_SPS_COUNT 32 +#define MAX_PPS_COUNT 256 +/* changed from 810 */ +#define MAX_SLICE_GROUPMBS 65536 +#define MAX_SPS_COUNT 32 +#define MAX_PPS_COUNT 256 +#define MAX_SLICEGROUP_COUNT 8 +#define MAX_WIDTH_IN_MBS 256 +#define MAX_HEIGHT_IN_MBS 256 +#define MAX_COLOR_PLANE 4 +#define H264_MAX_SGM_SIZE 8196 + +#define H264_MAX_CHROMA_QP_INDEX_OFFSET (12) +#define H264_MIN_CHROMA_QP_INDEX_OFFSET (-12) + +/* + * AVC Profile IDC definitions + */ +enum h264_profile_idc { + h264_profile_cavlc444 = 44, /* YUV 4:4:4/14 "CAVLC 4:4:4" */ + h264_profile_baseline = 66, /* YUV 4:2:0/8 "Baseline" */ + h264_profile_main = 77, /* YUV 4:2:0/8 "Main" */ + h264_profile_scalable = 83, /* YUV 4:2:0/8 "Scalable" */ + h264_profile_extended = 88, /* YUV 4:2:0/8 "Extended" */ + h264_profile_high = 100, /* YUV 4:2:0/8 "High" */ + h264_profile_hig10 = 110, /* YUV 4:2:0/10 "High 10" */ + h264_profile_mvc_high = 118, /* YUV 4:2:0/8 "Multiview High" */ + h264_profile_high422 = 122, /* YUV 4:2:2/10 "High 4:2:2" */ + h264_profile_mvc_stereo = 128, /* YUV 4:2:0/8 "Stereo High" */ + h264_profile_high444 = 244, /* YUV 4:4:4/14 "High 4:4:4" */ + h264_profile_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Remap H.264 colour format into internal representation. + */ +static const enum pixel_fmt_idc pixel_format_idc[] = { + PIXEL_FORMAT_MONO, + PIXEL_FORMAT_420, + PIXEL_FORMAT_422, + PIXEL_FORMAT_444, +}; + +/* + * Pixel Aspect Ratio + */ +static const unsigned short pixel_aspect[17][2] = { + { 0, 1 }, + { 1, 1 }, + { 12, 11 }, + { 10, 11 }, + { 16, 11 }, + { 40, 33 }, + { 24, 11 }, + { 20, 11 }, + { 32, 11 }, + { 80, 33 }, + { 18, 11 }, + { 15, 11 }, + { 64, 33 }, + { 160, 99 }, + { 4, 3 }, + { 3, 2 }, + { 2, 1 }, +}; + +/* + * Table 7-3, 7-4: Default Scaling lists + */ +static const unsigned char default_4x4_intra[16] = { + 6, 13, 13, 20, + 20, 20, 28, 28, + 28, 28, 32, 32, + 32, 37, 37, 42 +}; + +static const unsigned char default_4x4_inter[16] = { + 10, 14, 14, 20, + 20, 20, 24, 24, + 24, 24, 27, 27, + 27, 30, 30, 34 +}; + +static const unsigned char default_8x8_intra[64] = { + 6, 10, 10, 13, 11, 13, 16, 16, + 16, 16, 18, 18, 18, 18, 18, 23, + 23, 23, 23, 23, 23, 25, 25, 25, + 25, 25, 25, 25, 27, 27, 27, 27, + 27, 27, 27, 27, 29, 29, 29, 29, + 29, 29, 29, 31, 31, 31, 31, 31, + 31, 33, 33, 33, 33, 33, 36, 36, + 36, 36, 38, 38, 38, 40, 40, 42 +}; + +static const unsigned char default_8x8_inter[64] = { + 9, 13, 13, 15, 13, 15, 17, 17, + 17, 17, 19, 19, 19, 19, 19, 21, + 21, 21, 21, 21, 21, 22, 22, 22, + 22, 22, 22, 22, 24, 24, 24, 24, + 24, 24, 24, 24, 25, 25, 25, 25, + 25, 25, 25, 27, 27, 27, 27, 27, + 27, 28, 28, 28, 28, 28, 30, 30, + 30, 30, 32, 32, 32, 33, 33, 35 +}; + +/* + * to be use if no q matrix is chosen + */ +static const unsigned char default_4x4_org[16] = { + 16, 16, 16, 16, + 16, 16, 16, 16, + 16, 16, 16, 16, + 16, 16, 16, 16 +}; + +/* + * to be use if no q matrix is chosen + */ +static const unsigned char default_8x8_org[64] = { + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16 +}; + +/* + * source: ITU-T H.264 2010/03, page 20 Table 6-1 + */ +static const int bspp_subheightc[] = { -1, 2, 1, 1 }; + +/* + * source: ITU-T H.264 2010/03, page 20 Table 6-1 + */ +static const int bspp_subwidthc[] = { -1, 2, 2, 1 }; + +static inline int smin(int a, int b) +{ + return (((a) < (b)) ? (a) : (b)); +} + +static inline int smax(int a, int b) +{ + return (((a) > (b)) ? (a) : (b)); +} + +static void set_if_not_determined_yet(int *determined, + unsigned char condition, + int *target, + unsigned int value) +{ + if ((!(*determined)) && (condition)) { + *target = value; + *determined = 1; + } +} + +static int bspp_h264_get_subwidthc(int chroma_format_idc, int separate_colour_plane_flag) +{ + return bspp_subwidthc[chroma_format_idc]; +} + +static int bspp_h264_get_subheightc(int chroma_format_idc, int separate_colour_plane_flag) +{ + return bspp_subheightc[chroma_format_idc]; +} + +static unsigned int h264ceillog2(unsigned int value) +{ + unsigned int status = 0; + + value -= 1; + while (value > 0) { + value >>= 1; + status++; + } + return status; +} + +/* + * @Function bspp_h264_set_default_vui + * @Description Sets default values of the VUI info + */ +static void bspp_h264_set_default_vui(struct bspp_h264_vui_info *vui_info) +{ + unsigned int *nal_hrd_bitrate_valueminus1 = NULL; + unsigned int *vcl_hrd_bitrate_valueminus1 = NULL; + unsigned int *nal_hrd_cpbsize_valueminus1 = NULL; + unsigned int *vcl_hrd_cpbsize_valueminus1 = NULL; + unsigned char *nal_hrd_cbr_flag = NULL; + unsigned char *vcl_hrd_cbr_flag = NULL; + + /* Saving pointers */ + nal_hrd_bitrate_valueminus1 = vui_info->nal_hrd_parameters.bit_rate_value_minus1; + vcl_hrd_bitrate_valueminus1 = vui_info->vcl_hrd_parameters.bit_rate_value_minus1; + + nal_hrd_cpbsize_valueminus1 = vui_info->nal_hrd_parameters.cpb_size_value_minus1; + vcl_hrd_cpbsize_valueminus1 = vui_info->vcl_hrd_parameters.cpb_size_value_minus1; + + nal_hrd_cbr_flag = vui_info->nal_hrd_parameters.cbr_flag; + vcl_hrd_cbr_flag = vui_info->vcl_hrd_parameters.cbr_flag; + + /* Cleaning sVUIInfo */ + if (vui_info->nal_hrd_parameters.bit_rate_value_minus1) + memset(vui_info->nal_hrd_parameters.bit_rate_value_minus1, 0x00, + VDEC_H264_MAXIMUMVALUEOFCPB_CNT * sizeof(unsigned int)); + + if (vui_info->nal_hrd_parameters.cpb_size_value_minus1) + memset(vui_info->nal_hrd_parameters.cpb_size_value_minus1, 0x00, + VDEC_H264_MAXIMUMVALUEOFCPB_CNT * sizeof(unsigned int)); + + if (vui_info->vcl_hrd_parameters.cpb_size_value_minus1) + memset(vui_info->vcl_hrd_parameters.cpb_size_value_minus1, 0x00, + VDEC_H264_MAXIMUMVALUEOFCPB_CNT * sizeof(unsigned int)); + + if (vui_info->nal_hrd_parameters.cbr_flag) + memset(vui_info->nal_hrd_parameters.cbr_flag, 0x00, + VDEC_H264_MAXIMUMVALUEOFCPB_CNT * sizeof(unsigned char)); + + if (vui_info->vcl_hrd_parameters.cbr_flag) + memset(vui_info->vcl_hrd_parameters.cbr_flag, 0x00, + VDEC_H264_MAXIMUMVALUEOFCPB_CNT * sizeof(unsigned char)); + + /* Make sure you set default for everything */ + memset(vui_info, 0, sizeof(*vui_info)); + vui_info->video_format = 5; + vui_info->colour_primaries = 2; + vui_info->transfer_characteristics = 2; + vui_info->matrix_coefficients = 2; + vui_info->motion_vectors_over_pic_boundaries_flag = 1; + vui_info->max_bytes_per_pic_denom = 2; + vui_info->max_bits_per_mb_denom = 1; + vui_info->log2_max_mv_length_horizontal = 16; + vui_info->log2_max_mv_length_vertical = 16; + +#ifdef REDUCED_DPB_NO_PIC_REORDERING + vui_info->max_dec_frame_buffering = 1; + vui_info->num_reorder_frames = 0; +#else + vui_info->max_dec_frame_buffering = 0; + vui_info->num_reorder_frames = vui_info->max_dec_frame_buffering; +#endif + + /* Restoring pointers */ + vui_info->nal_hrd_parameters.bit_rate_value_minus1 = nal_hrd_bitrate_valueminus1; + vui_info->vcl_hrd_parameters.bit_rate_value_minus1 = vcl_hrd_bitrate_valueminus1; + + vui_info->nal_hrd_parameters.cpb_size_value_minus1 = nal_hrd_cpbsize_valueminus1; + vui_info->vcl_hrd_parameters.cpb_size_value_minus1 = vcl_hrd_cpbsize_valueminus1; + + vui_info->nal_hrd_parameters.cbr_flag = nal_hrd_cbr_flag; + vui_info->vcl_hrd_parameters.cbr_flag = vcl_hrd_cbr_flag; +} + +/* + * @Function bspp_h264_hrd_param_parser + * @Description Parse the HRD parameter + */ +static enum bspp_error_type bspp_h264_hrd_param_parser + (void *swsr_context, + struct bspp_h264_hrdparam_info *h264_hrd_param_info) +{ + unsigned int sched_sel_idx; + + VDEC_ASSERT(swsr_context); + h264_hrd_param_info->cpb_cnt_minus1 = swsr_read_unsigned_expgoulomb(swsr_context); + + if (h264_hrd_param_info->cpb_cnt_minus1 >= 32) + pr_info("pb_cnt_minus1 is not within the range"); + + h264_hrd_param_info->bit_rate_scale = swsr_read_bits(swsr_context, 4); + h264_hrd_param_info->cpb_size_scale = swsr_read_bits(swsr_context, 4); + + if (!h264_hrd_param_info->bit_rate_value_minus1) { + h264_hrd_param_info->bit_rate_value_minus1 = kcalloc + (VDEC_H264_MAXIMUMVALUEOFCPB_CNT, + sizeof(unsigned int), GFP_KERNEL); + VDEC_ASSERT(h264_hrd_param_info->bit_rate_value_minus1); + if (!h264_hrd_param_info->bit_rate_value_minus1) + return BSPP_ERROR_OUT_OF_MEMORY; + } + + if (!h264_hrd_param_info->cpb_size_value_minus1) { + h264_hrd_param_info->cpb_size_value_minus1 = kcalloc + (VDEC_H264_MAXIMUMVALUEOFCPB_CNT, + sizeof(unsigned int), + GFP_KERNEL); + VDEC_ASSERT(h264_hrd_param_info->cpb_size_value_minus1); + if (!h264_hrd_param_info->cpb_size_value_minus1) + return BSPP_ERROR_OUT_OF_MEMORY; + } + + if (!h264_hrd_param_info->cbr_flag) { + h264_hrd_param_info->cbr_flag = + kcalloc(VDEC_H264_MAXIMUMVALUEOFCPB_CNT, sizeof(unsigned char), GFP_KERNEL); + VDEC_ASSERT(h264_hrd_param_info->cbr_flag); + if (!h264_hrd_param_info->cbr_flag) + return BSPP_ERROR_OUT_OF_MEMORY; + } + + for (sched_sel_idx = 0; sched_sel_idx <= h264_hrd_param_info->cpb_cnt_minus1; + sched_sel_idx++) { + h264_hrd_param_info->bit_rate_value_minus1[sched_sel_idx] = + swsr_read_unsigned_expgoulomb(swsr_context); + h264_hrd_param_info->cpb_size_value_minus1[sched_sel_idx] = + swsr_read_unsigned_expgoulomb(swsr_context); + + if (h264_hrd_param_info->cpb_size_value_minus1[sched_sel_idx] == 0xffffffff) + /* 65 bit pattern, 32 0's -1 - 32 0's then value should be 0 */ + h264_hrd_param_info->cpb_size_value_minus1[sched_sel_idx] = 0; + + h264_hrd_param_info->cbr_flag[sched_sel_idx] = swsr_read_bits(swsr_context, 1); + } + + h264_hrd_param_info->initial_cpb_removal_delay_length_minus1 = swsr_read_bits(swsr_context, + 5); + h264_hrd_param_info->cpb_removal_delay_length_minus1 = swsr_read_bits(swsr_context, 5); + h264_hrd_param_info->dpb_output_delay_length_minus1 = swsr_read_bits(swsr_context, 5); + h264_hrd_param_info->time_offset_length = swsr_read_bits(swsr_context, 5); + + return BSPP_ERROR_NONE; +} + +/* + * @Function bspp_h264_get_default_hrd_param + * @Description Get default value of the HRD parameter + */ +static void bspp_h264_get_default_hrd_param(struct bspp_h264_hrdparam_info *h264_hrd_param_info) +{ + /* other parameters already set to '0' */ + h264_hrd_param_info->initial_cpb_removal_delay_length_minus1 = 23; + h264_hrd_param_info->cpb_removal_delay_length_minus1 = 23; + h264_hrd_param_info->dpb_output_delay_length_minus1 = 23; + h264_hrd_param_info->time_offset_length = 24; +} + +/* + * @Function bspp_h264_vui_parser + * @Description Parse the VUI info + */ +static enum bspp_error_type bspp_h264_vui_parser(void *swsr_context, + struct bspp_h264_vui_info *vui_info, + struct bspp_h264_sps_info *sps_info) +{ + enum bspp_error_type vui_parser_error = BSPP_ERROR_NONE; + + vui_info->aspect_ratio_info_present_flag = swsr_read_bits(swsr_context, 1); + if (vui_info->aspect_ratio_info_present_flag) { + vui_info->aspect_ratio_idc = swsr_read_bits(swsr_context, 8); + /* Extended SAR */ + if (vui_info->aspect_ratio_idc == 255) { + vui_info->sar_width = swsr_read_bits(swsr_context, 16); + vui_info->sar_height = swsr_read_bits(swsr_context, 16); + } else if (vui_info->aspect_ratio_idc < 17) { + vui_info->sar_width = pixel_aspect[vui_info->aspect_ratio_idc][0]; + vui_info->sar_height = pixel_aspect[vui_info->aspect_ratio_idc][1]; + } else { + /* we can consider this error as a aux data error */ + vui_parser_error |= BSPP_ERROR_INVALID_VALUE; + } + } + + vui_info->overscan_info_present_flag = swsr_read_bits(swsr_context, 1); + if (vui_info->overscan_info_present_flag) + vui_info->overscan_appropriate_flag = swsr_read_bits(swsr_context, 1); + + vui_info->video_signal_type_present_flag = swsr_read_bits(swsr_context, 1); + if (vui_info->video_signal_type_present_flag) { + vui_info->video_format = swsr_read_bits(swsr_context, 3); + vui_info->video_full_range_flag = swsr_read_bits(swsr_context, 1); + vui_info->colour_description_present_flag = swsr_read_bits(swsr_context, 1); + if (vui_info->colour_description_present_flag) { + vui_info->colour_primaries = swsr_read_bits(swsr_context, 8); + vui_info->transfer_characteristics = swsr_read_bits(swsr_context, 8); + vui_info->matrix_coefficients = swsr_read_bits(swsr_context, 8); + } + } + + vui_info->chroma_location_info_present_flag = swsr_read_bits(swsr_context, 1); + if (vui_info->chroma_location_info_present_flag) { + vui_info->chroma_sample_loc_type_top_field = swsr_read_unsigned_expgoulomb + (swsr_context); + vui_info->chroma_sample_loc_type_bottom_field = swsr_read_unsigned_expgoulomb + (swsr_context); + } + + vui_info->timing_info_present_flag = swsr_read_bits(swsr_context, 1); + if (vui_info->timing_info_present_flag) { + vui_info->num_units_in_tick = swsr_read_bits(swsr_context, 16); + vui_info->num_units_in_tick <<= 16; /* SR can only do up to 31 bit reads */ + vui_info->num_units_in_tick |= swsr_read_bits(swsr_context, 16); + vui_info->time_scale = swsr_read_bits(swsr_context, 16); + vui_info->time_scale <<= 16; /* SR can only do up to 31 bit reads */ + vui_info->time_scale |= swsr_read_bits(swsr_context, 16); + if (!vui_info->num_units_in_tick || !vui_info->time_scale) + vui_parser_error |= BSPP_ERROR_INVALID_VALUE; + + vui_info->fixed_frame_rate_flag = swsr_read_bits(swsr_context, 1); + } + + /* no default values */ + vui_info->nal_hrd_parameters_present_flag = swsr_read_bits(swsr_context, 1); + if (vui_info->nal_hrd_parameters_present_flag) + vui_parser_error |= bspp_h264_hrd_param_parser(swsr_context, + &vui_info->nal_hrd_parameters); + else + bspp_h264_get_default_hrd_param(&vui_info->nal_hrd_parameters); + + vui_info->vcl_hrd_parameters_present_flag = swsr_read_bits(swsr_context, 1); + + if (vui_info->vcl_hrd_parameters_present_flag) + vui_parser_error |= bspp_h264_hrd_param_parser(swsr_context, + &vui_info->vcl_hrd_parameters); + else + bspp_h264_get_default_hrd_param(&vui_info->vcl_hrd_parameters); + + if (vui_info->nal_hrd_parameters_present_flag || vui_info->vcl_hrd_parameters_present_flag) + vui_info->low_delay_hrd_flag = swsr_read_bits(swsr_context, 1); + + vui_info->pic_struct_present_flag = swsr_read_bits(swsr_context, 1); + vui_info->bitstream_restriction_flag = swsr_read_bits(swsr_context, 1); + if (vui_info->bitstream_restriction_flag) { + vui_info->motion_vectors_over_pic_boundaries_flag = swsr_read_bits(swsr_context, 1); + vui_info->max_bytes_per_pic_denom = swsr_read_unsigned_expgoulomb(swsr_context); + vui_info->max_bits_per_mb_denom = swsr_read_unsigned_expgoulomb(swsr_context); + vui_info->log2_max_mv_length_horizontal = + swsr_read_unsigned_expgoulomb(swsr_context); + vui_info->log2_max_mv_length_vertical = swsr_read_unsigned_expgoulomb(swsr_context); + vui_info->num_reorder_frames = swsr_read_unsigned_expgoulomb(swsr_context); + vui_info->max_dec_frame_buffering = swsr_read_unsigned_expgoulomb(swsr_context); + } + + if ((sps_info->profile_idc == h264_profile_baseline || + sps_info->profile_idc == h264_profile_extended) && + sps_info->max_num_ref_frames == 1) { + vui_info->bitstream_restriction_flag = 1; + vui_info->num_reorder_frames = 0; + vui_info->max_dec_frame_buffering = 1; + } + + if (vui_info->num_reorder_frames > 32) + vui_parser_error |= BSPP_ERROR_UNSUPPORTED; + + return vui_parser_error; +} + +/* + * Parse scaling list + */ +static enum bspp_error_type bspp_h264_scl_listparser(void *swsr_context, + unsigned char *scaling_list, + unsigned char sizeof_scaling_list, + unsigned char *usedefaultscalingmatrixflag) +{ + enum bspp_error_type parse_error = BSPP_ERROR_NONE; + int delta_scale; + unsigned int lastscale = 8; + unsigned int nextscale = 8; + unsigned int j; + + VDEC_ASSERT(swsr_context); + VDEC_ASSERT(scaling_list); + VDEC_ASSERT(usedefaultscalingmatrixflag); + + if (!scaling_list || !swsr_context || !usedefaultscalingmatrixflag) { + parse_error = BSPP_ERROR_UNRECOVERABLE; + return parse_error; + } + + /* 7.3.2.1.1 */ + for (j = 0; j < sizeof_scaling_list; j++) { + if (nextscale != 0) { + delta_scale = swsr_read_signed_expgoulomb(swsr_context); + if ((-128 > delta_scale) || delta_scale > 127) + parse_error |= BSPP_ERROR_INVALID_VALUE; + nextscale = (lastscale + delta_scale + 256) & 0xff; + *usedefaultscalingmatrixflag = (j == 0 && nextscale == 0); + } + scaling_list[j] = (nextscale == 0) ? lastscale : nextscale; + lastscale = scaling_list[j]; + } + return parse_error; +} + +/* + * Parse the SPS NAL unit + */ +static enum bspp_error_type bspp_h264_sps_parser(void *swsr_context, + void *str_res, + struct bspp_h264_seq_hdr_info *h264_seq_hdr_info) +{ + unsigned int i; + unsigned char scaling_list_num; + struct bspp_h264_sps_info *sps_info; + struct bspp_h264_vui_info *vui_info; + enum bspp_error_type sps_parser_error = BSPP_ERROR_NONE; + enum bspp_error_type vui_parser_error = BSPP_ERROR_NONE; + + sps_info = &h264_seq_hdr_info->sps_info; + vui_info = &h264_seq_hdr_info->vui_info; + + /* Set always the default VUI/MVCExt, their values + * may be used even if VUI/MVCExt not present + */ + bspp_h264_set_default_vui(vui_info); +#ifdef DEBUG_DECODER_DRIVER + pr_info("Parsing Sequence Parameter Set"); +#endif + sps_info->profile_idc = swsr_read_bits(swsr_context, 8); + if (sps_info->profile_idc != H264_PROFILE_BASELINE && + sps_info->profile_idc != H264_PROFILE_MAIN && + sps_info->profile_idc != H264_PROFILE_SCALABLE && + sps_info->profile_idc != H264_PROFILE_EXTENDED && + sps_info->profile_idc != H264_PROFILE_HIGH && + sps_info->profile_idc != H264_PROFILE_HIGH10 && + sps_info->profile_idc != H264_PROFILE_MVC_HIGH && + sps_info->profile_idc != H264_PROFILE_HIGH422 && + sps_info->profile_idc != H264_PROFILE_CAVLC444 && + sps_info->profile_idc != H264_PROFILE_MVC_STEREO && + sps_info->profile_idc != H264_PROFILE_HIGH444) { + pr_err("Invalid Profile ID [%d],Parsed by BSPP", sps_info->profile_idc); + return BSPP_ERROR_UNSUPPORTED; + } + sps_info->constraint_set_flags = swsr_read_bits(swsr_context, 8); + sps_info->level_idc = swsr_read_bits(swsr_context, 8); + + /* sequence parameter set id */ + sps_info->seq_parameter_set_id = swsr_read_unsigned_expgoulomb(swsr_context); + if (sps_info->seq_parameter_set_id >= MAX_SPS_COUNT) { + pr_err("SPS ID [%d] goes beyond the limit", sps_info->seq_parameter_set_id); + return BSPP_ERROR_UNSUPPORTED; + } + + /* High profile settings */ + if (sps_info->profile_idc == H264_PROFILE_HIGH || + sps_info->profile_idc == H264_PROFILE_HIGH10 || + sps_info->profile_idc == H264_PROFILE_HIGH422 || + sps_info->profile_idc == H264_PROFILE_HIGH444 || + sps_info->profile_idc == H264_PROFILE_CAVLC444 || + sps_info->profile_idc == H264_PROFILE_MVC_HIGH || + sps_info->profile_idc == H264_PROFILE_MVC_STEREO) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("This is High Profile Bitstream"); +#endif + sps_info->chroma_format_idc = swsr_read_unsigned_expgoulomb(swsr_context); + if (sps_info->chroma_format_idc > 3) { + pr_err("chroma_format_idc[%d] is not within the range", + sps_info->chroma_format_idc); + sps_parser_error |= BSPP_ERROR_INVALID_VALUE; + } + if (sps_info->chroma_format_idc == 3) + sps_info->separate_colour_plane_flag = swsr_read_bits(swsr_context, 1); + else + sps_info->separate_colour_plane_flag = 0; + + sps_info->bit_depth_luma_minus8 = swsr_read_unsigned_expgoulomb(swsr_context); + if (sps_info->bit_depth_luma_minus8 > 6) + sps_parser_error |= BSPP_ERROR_INVALID_VALUE; + + sps_info->bit_depth_chroma_minus8 = swsr_read_unsigned_expgoulomb(swsr_context); + if (sps_info->bit_depth_chroma_minus8 > 6) + sps_parser_error |= BSPP_ERROR_INVALID_VALUE; + + sps_info->qpprime_y_zero_transform_bypass_flag = swsr_read_bits(swsr_context, 1); + sps_info->seq_scaling_matrix_present_flag = swsr_read_bits(swsr_context, 1); + if (sps_info->seq_scaling_matrix_present_flag) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("seq_scaling_matrix_present_flag is available"); +#endif + scaling_list_num = (sps_info->chroma_format_idc != 3) ? 8 : 12; + + if (!sps_info->scllst4x4seq) { + sps_info->scllst4x4seq = + kmalloc((sizeof(unsigned char[H264FW_NUM_4X4_LISTS] + [H264FW_4X4_SIZE])), GFP_KERNEL); + if (!sps_info->scllst4x4seq) { + sps_parser_error |= BSPP_ERROR_OUT_OF_MEMORY; + } else { + VDEC_ASSERT(sps_info->scllst4x4seq); + memset(sps_info->scllst4x4seq, 0x00, + sizeof(unsigned char[H264FW_NUM_4X4_LISTS] + [H264FW_4X4_SIZE])); + } + } + if (!sps_info->scllst8x8seq) { + sps_info->scllst8x8seq = + kmalloc((sizeof(unsigned char[H264FW_NUM_8X8_LISTS] + [H264FW_8X8_SIZE])), GFP_KERNEL); + if (!sps_info->scllst8x8seq) { + sps_parser_error |= BSPP_ERROR_OUT_OF_MEMORY; + } else { + VDEC_ASSERT(sps_info->scllst8x8seq); + memset(sps_info->scllst8x8seq, 0x00, + sizeof(unsigned char[H264FW_NUM_8X8_LISTS] + [H264FW_8X8_SIZE])); + } + } + + { + unsigned char(*scllst4x4seq)[H264FW_NUM_4X4_LISTS] + [H264FW_4X4_SIZE] = + (unsigned char (*)[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE]) + sps_info->scllst4x4seq; + unsigned char(*scllst8x8seq)[H264FW_NUM_8X8_LISTS] + [H264FW_8X8_SIZE] = + (unsigned char (*)[H264FW_NUM_8X8_LISTS] + [H264FW_8X8_SIZE]) + sps_info->scllst8x8seq; + + for (i = 0; i < scaling_list_num; i++) { + unsigned char *ptr = + &sps_info->usedefaultscalingmatrixflag_seq[i]; + + sps_info->seq_scaling_list_present_flag[i] = + swsr_read_bits(swsr_context, 1); + if (sps_info->seq_scaling_list_present_flag[i]) { + if (i < 6) { + sps_parser_error |= + bspp_h264_scl_listparser + (swsr_context, + (*scllst4x4seq)[i], 16, + ptr); + } else { + sps_parser_error |= + bspp_h264_scl_listparser + (swsr_context, + (*scllst8x8seq)[i - 6], 64, + ptr); + } + } + } + } + } + } else { + /* default values in here */ + sps_info->chroma_format_idc = 1; + sps_info->bit_depth_luma_minus8 = 0; + sps_info->bit_depth_chroma_minus8 = 0; + sps_info->qpprime_y_zero_transform_bypass_flag = 0; + sps_info->seq_scaling_matrix_present_flag = 0; + } + + sps_info->log2_max_frame_num_minus4 = swsr_read_unsigned_expgoulomb(swsr_context); + if (sps_info->log2_max_frame_num_minus4 > 12) { + pr_err("log2_max_frame_num_minus4[%d] is not within range [0 - 12]", + sps_info->log2_max_frame_num_minus4); + sps_parser_error |= BSPP_ERROR_INVALID_VALUE; + } + + sps_info->pic_order_cnt_type = swsr_read_unsigned_expgoulomb(swsr_context); + if (sps_info->pic_order_cnt_type > 2) { + pr_err("pic_order_cnt_type[%d] is not within range [0 - 2]", + sps_info->pic_order_cnt_type); + sps_parser_error |= BSPP_ERROR_INVALID_VALUE; + } + + if (sps_info->pic_order_cnt_type == 0) { + sps_info->log2_max_pic_order_cnt_lsb_minus4 = swsr_read_unsigned_expgoulomb + (swsr_context); + if (sps_info->log2_max_pic_order_cnt_lsb_minus4 > 12) { + pr_err("log2_max_pic_order_cnt_lsb_minus4[%d] is not within range [0 - 12]", + sps_info->log2_max_pic_order_cnt_lsb_minus4); + sps_info->log2_max_pic_order_cnt_lsb_minus4 = 12; + sps_parser_error |= BSPP_ERROR_CORRECTION_VALIDVALUE; + } + } else if (sps_info->pic_order_cnt_type == 1) { + sps_info->delta_pic_order_always_zero_flag = swsr_read_bits(swsr_context, 1); + sps_info->offset_for_non_ref_pic = swsr_read_signed_expgoulomb(swsr_context); + sps_info->offset_for_top_to_bottom_field = swsr_read_signed_expgoulomb + (swsr_context); + sps_info->num_ref_frames_in_pic_order_cnt_cycle = swsr_read_unsigned_expgoulomb + (swsr_context); + if (sps_info->num_ref_frames_in_pic_order_cnt_cycle > 255) { + pr_err("num_ref_frames_in_pic_order_cnt_cycle[%d] is not within range [0 - 256]", + sps_info->num_ref_frames_in_pic_order_cnt_cycle); + sps_parser_error |= BSPP_ERROR_INVALID_VALUE; + } + + if (!sps_info->offset_for_ref_frame) { + sps_info->offset_for_ref_frame = + kmalloc((H264FW_MAX_CYCLE_REF_FRAMES * sizeof(unsigned int)), + GFP_KERNEL); + if (!sps_info->offset_for_ref_frame) { + pr_err("out of memory"); + sps_parser_error |= BSPP_ERROR_OUT_OF_MEMORY; + } + } + + if (sps_info->offset_for_ref_frame) { + VDEC_ASSERT(sps_info->num_ref_frames_in_pic_order_cnt_cycle <= + H264FW_MAX_CYCLE_REF_FRAMES); + memset(sps_info->offset_for_ref_frame, 0x00, + (H264FW_MAX_CYCLE_REF_FRAMES * sizeof(unsigned int))); + for (i = 0; i < sps_info->num_ref_frames_in_pic_order_cnt_cycle; i++) { + /* check the max value and if it crosses then exit from the loop */ + sps_info->offset_for_ref_frame[i] = swsr_read_signed_expgoulomb + (swsr_context); + } + } + } else if (sps_info->pic_order_cnt_type != 2) { + sps_parser_error |= BSPP_ERROR_INVALID_VALUE; + } + sps_info->max_num_ref_frames = swsr_read_unsigned_expgoulomb(swsr_context); + + if (sps_info->max_num_ref_frames > 16) { + pr_err("num_ref_frames[%d] is not within range [0 - 16]", + sps_info->max_num_ref_frames); + sps_parser_error |= BSPP_ERROR_INVALID_VALUE; + } + sps_info->gaps_in_frame_num_value_allowed_flag = swsr_read_bits(swsr_context, 1); + sps_info->pic_width_in_mbs_minus1 = swsr_read_unsigned_expgoulomb(swsr_context); + if (sps_info->pic_width_in_mbs_minus1 >= MAX_WIDTH_IN_MBS) { + pr_err("pic_width_in_mbs_minus1[%d] is not within range", + sps_info->pic_width_in_mbs_minus1); + sps_parser_error |= BSPP_ERROR_INVALID_VALUE; + } + sps_info->pic_height_in_map_units_minus1 = swsr_read_unsigned_expgoulomb(swsr_context); + if (sps_info->pic_height_in_map_units_minus1 >= MAX_HEIGHT_IN_MBS) { + pr_err("pic_height_in_map_units_minus1[%d] is not within range", + sps_info->pic_height_in_map_units_minus1); + sps_parser_error |= BSPP_ERROR_INVALID_VALUE; + } + + sps_info->frame_mbs_only_flag = swsr_read_bits(swsr_context, 1); + if (!sps_info->frame_mbs_only_flag) + sps_info->mb_adaptive_frame_field_flag = swsr_read_bits(swsr_context, 1); + else + sps_info->mb_adaptive_frame_field_flag = 0; + + sps_info->direct_8x8_inference_flag = swsr_read_bits(swsr_context, 1); + + sps_info->frame_cropping_flag = swsr_read_bits(swsr_context, 1); + if (sps_info->frame_cropping_flag) { + sps_info->frame_crop_left_offset = swsr_read_unsigned_expgoulomb(swsr_context); + sps_info->frame_crop_right_offset = swsr_read_unsigned_expgoulomb(swsr_context); + sps_info->frame_crop_top_offset = swsr_read_unsigned_expgoulomb(swsr_context); + sps_info->frame_crop_bottom_offset = swsr_read_unsigned_expgoulomb(swsr_context); + } else { + sps_info->frame_crop_left_offset = 0; + sps_info->frame_crop_right_offset = 0; + sps_info->frame_crop_top_offset = 0; + sps_info->frame_crop_bottom_offset = 0; + } + + sps_info->vui_parameters_present_flag = swsr_read_bits(swsr_context, 1); + /* initialise matrix_coefficients to 2 (unspecified) */ + vui_info->matrix_coefficients = 2; + + if (sps_info->vui_parameters_present_flag) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("vui_parameters_present_flag is available"); +#endif + /* save the SPS parse error in temp variable */ + vui_parser_error = bspp_h264_vui_parser(swsr_context, vui_info, sps_info); + if (vui_parser_error != BSPP_ERROR_NONE) + sps_parser_error |= BSPP_ERROR_AUXDATA; + +#ifdef REDUCED_DPB_NO_PIC_REORDERING + vui_info->max_dec_frame_buffering = 1; + vui_info->num_reorder_frames = 0; +#endif + } + + if (sps_info->profile_idc == H264_PROFILE_MVC_HIGH || + sps_info->profile_idc == H264_PROFILE_MVC_STEREO) { + pr_err("No MVC Support for this version\n"); + } + + if (swsr_check_exception(swsr_context) != SWSR_EXCEPT_NO_EXCEPTION) + sps_parser_error |= BSPP_ERROR_INSUFFICIENT_DATA; + + return sps_parser_error; +} + +/* + * Parse the PPS NAL unit + */ +static enum bspp_error_type bspp_h264_pps_parser(void *swsr_context, + void *str_res, + struct bspp_h264_pps_info *h264_pps_info) +{ + int i, group, chroma_format_idc; + unsigned int number_bits_per_slicegroup_id; + unsigned char n_scaling_list; + unsigned char more_rbsp_data; + unsigned int result; + enum bspp_error_type pps_parse_error = BSPP_ERROR_NONE; + + VDEC_ASSERT(swsr_context); + + h264_pps_info->pps_id = swsr_read_unsigned_expgoulomb(swsr_context); + if (h264_pps_info->pps_id >= MAX_PPS_COUNT) { + pr_err("Picture Parameter Set(PPS) ID is not within the range"); + h264_pps_info->pps_id = (int)BSPP_INVALID; + return BSPP_ERROR_UNSUPPORTED; + } + h264_pps_info->seq_parameter_set_id = swsr_read_unsigned_expgoulomb(swsr_context); + if (h264_pps_info->seq_parameter_set_id >= MAX_SPS_COUNT) { + pr_err("Sequence Parameter Set(SPS) ID is not within the range"); + h264_pps_info->seq_parameter_set_id = (int)BSPP_INVALID; + return BSPP_ERROR_UNSUPPORTED; + } + + { + /* + * Get the chroma_format_idc from sps. Because of MVC sharing sps and subset sps ids + * (H.7.4.1.2.1). + * At this point is not clear if this pps refers to an sps or a subset sps. + * It should be finehowever for the case of chroma_format_idc to try and locate + * a subset sps if there isn't a normal one. + */ + struct bspp_h264_seq_hdr_info *h264_seq_hdr_info; + struct bspp_sequence_hdr_info *seq_hdr_info; + + seq_hdr_info = bspp_get_sequ_hdr(str_res, h264_pps_info->seq_parameter_set_id); + + if (!seq_hdr_info) { + seq_hdr_info = bspp_get_sequ_hdr(str_res, + h264_pps_info->seq_parameter_set_id + 32); + if (!seq_hdr_info) + return BSPP_ERROR_NO_SEQUENCE_HDR; + } + + h264_seq_hdr_info = + (struct bspp_h264_seq_hdr_info *)seq_hdr_info->secure_sequence_info; + + chroma_format_idc = h264_seq_hdr_info->sps_info.chroma_format_idc; + } + + h264_pps_info->entropy_coding_mode_flag = swsr_read_bits(swsr_context, 1); + h264_pps_info->pic_order_present_flag = swsr_read_bits(swsr_context, 1); + h264_pps_info->num_slice_groups_minus1 = swsr_read_unsigned_expgoulomb(swsr_context); + if ((h264_pps_info->num_slice_groups_minus1 + 1) > + MAX_SLICEGROUP_COUNT) { + h264_pps_info->num_slice_groups_minus1 = + MAX_SLICEGROUP_COUNT - 1; + pps_parse_error |= BSPP_ERROR_UNRECOVERABLE; + } + + if (h264_pps_info->num_slice_groups_minus1 > 0) { + h264_pps_info->slice_group_map_type = swsr_read_unsigned_expgoulomb(swsr_context); + pr_err("slice_group_map_type is : %d, Parsed by BSPP", + h264_pps_info->slice_group_map_type); + if (h264_pps_info->slice_group_map_type > 6) { + pr_err("slice_group_map_type [%d] is not within the range [ 0- 6 ]", + h264_pps_info->slice_group_map_type); + pps_parse_error |= BSPP_ERROR_UNRECOVERABLE; + } + + if (h264_pps_info->slice_group_map_type == 0) { + for (group = 0; group <= h264_pps_info->num_slice_groups_minus1; group++) { + h264_pps_info->run_length_minus1[group] = + swsr_read_unsigned_expgoulomb(swsr_context); + } + } else if (h264_pps_info->slice_group_map_type == 2) { + for (group = 0; group < h264_pps_info->num_slice_groups_minus1; group++) { + h264_pps_info->top_left[group] = swsr_read_unsigned_expgoulomb + (swsr_context); + h264_pps_info->bottom_right[group] = + swsr_read_unsigned_expgoulomb(swsr_context); + } + } else if (h264_pps_info->slice_group_map_type == 3 || + h264_pps_info->slice_group_map_type == 4 || + h264_pps_info->slice_group_map_type == 5) { + h264_pps_info->slice_group_change_direction_flag = swsr_read_bits + (swsr_context, 1); + h264_pps_info->slice_group_change_rate_minus1 = + swsr_read_unsigned_expgoulomb(swsr_context); + } else if (h264_pps_info->slice_group_map_type == 6) { + h264_pps_info->pic_size_in_map_unit = swsr_read_unsigned_expgoulomb + (swsr_context); + if (h264_pps_info->pic_size_in_map_unit >= H264_MAX_SGM_SIZE) { + pr_err("pic_size_in_map_units_minus1 [%d] is not within the range", + h264_pps_info->pic_size_in_map_unit); + pps_parse_error |= BSPP_ERROR_UNRECOVERABLE; + } + number_bits_per_slicegroup_id = h264ceillog2 + (h264_pps_info->num_slice_groups_minus1 + 1); + + if ((h264_pps_info->pic_size_in_map_unit + 1) > + h264_pps_info->h264_ppssgm_info.slicegroupidnum) { + unsigned char *slice_group_id = + kmalloc(((h264_pps_info->pic_size_in_map_unit + 1) * + sizeof(unsigned char)), + GFP_KERNEL); + if (!slice_group_id) { + pr_err("out of memory"); + pps_parse_error |= BSPP_ERROR_OUT_OF_MEMORY; + } else { + pr_err("reallocating SGM info from size %lu bytes to size %lu bytes", + h264_pps_info->h264_ppssgm_info.slicegroupidnum * + sizeof(unsigned char), + (h264_pps_info->pic_size_in_map_unit + 1) * + sizeof(unsigned char)); + if (h264_pps_info->h264_ppssgm_info.slice_group_id) { + memcpy + (slice_group_id, + h264_pps_info->h264_ppssgm_info.slice_group_id, + h264_pps_info->h264_ppssgm_info.slicegroupidnum * + sizeof(unsigned char)); + kfree + (h264_pps_info->h264_ppssgm_info.slice_group_id); + } + h264_pps_info->h264_ppssgm_info.slicegroupidnum = + (h264_pps_info->pic_size_in_map_unit + 1); + h264_pps_info->h264_ppssgm_info.slice_group_id = + slice_group_id; + } + } + + VDEC_ASSERT((h264_pps_info->pic_size_in_map_unit + 1) <= + h264_pps_info->h264_ppssgm_info.slicegroupidnum); + for (i = 0; i <= h264_pps_info->pic_size_in_map_unit; i++) + h264_pps_info->h264_ppssgm_info.slice_group_id[i] = + swsr_read_bits(swsr_context, number_bits_per_slicegroup_id); + } + } + + for (i = 0; i < H264FW_MAX_REFPIC_LISTS; i++) { + h264_pps_info->num_ref_idx_lx_active_minus1[i] = swsr_read_unsigned_expgoulomb + (swsr_context); + if (h264_pps_info->num_ref_idx_lx_active_minus1[i] >= + SL_MAX_REF_IDX) { + pr_err("num_ref_idx_lx_active_minus1[%d] [%d] is not within the range", + i, h264_pps_info->num_ref_idx_lx_active_minus1[i]); + pps_parse_error |= BSPP_ERROR_UNRECOVERABLE; + } + } + + h264_pps_info->weighted_pred_flag = swsr_read_bits(swsr_context, 1); + h264_pps_info->weighted_bipred_idc = swsr_read_bits(swsr_context, 2); + h264_pps_info->pic_init_qp_minus26 = swsr_read_signed_expgoulomb(swsr_context); + if (h264_pps_info->pic_init_qp_minus26 > 26) + pr_err("pic_init_qp_minus26[%d] is not within the range [-25 , 26]", + h264_pps_info->pic_init_qp_minus26); + + h264_pps_info->pic_init_qs_minus26 = swsr_read_signed_expgoulomb(swsr_context); + if (h264_pps_info->pic_init_qs_minus26 > 26) + pr_err("pic_init_qs_minus26[%d] is not within the range [-25 , 26]", + h264_pps_info->pic_init_qs_minus26); + + h264_pps_info->chroma_qp_index_offset = swsr_read_signed_expgoulomb(swsr_context); + if (h264_pps_info->chroma_qp_index_offset > H264_MAX_CHROMA_QP_INDEX_OFFSET) + h264_pps_info->chroma_qp_index_offset = H264_MAX_CHROMA_QP_INDEX_OFFSET; + + else if (h264_pps_info->chroma_qp_index_offset < H264_MIN_CHROMA_QP_INDEX_OFFSET) + h264_pps_info->chroma_qp_index_offset = H264_MIN_CHROMA_QP_INDEX_OFFSET; + + h264_pps_info->deblocking_filter_control_present_flag = swsr_read_bits(swsr_context, 1); + h264_pps_info->constrained_intra_pred_flag = swsr_read_bits(swsr_context, 1); + h264_pps_info->redundant_pic_cnt_present_flag = swsr_read_bits(swsr_context, 1); + + /* Check for more rbsp data. */ + result = swsr_check_more_rbsp_data(swsr_context, &more_rbsp_data); + if (result == 0 && more_rbsp_data) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("More RBSP data is available"); +#endif + /* Fidelity Range Extensions Stuff */ + h264_pps_info->transform_8x8_mode_flag = swsr_read_bits(swsr_context, 1); + h264_pps_info->pic_scaling_matrix_present_flag = swsr_read_bits(swsr_context, 1); + if (h264_pps_info->pic_scaling_matrix_present_flag) { + if (!h264_pps_info->scllst4x4pic) { + h264_pps_info->scllst4x4pic = + kmalloc((sizeof(unsigned char[H264FW_NUM_4X4_LISTS] + [H264FW_4X4_SIZE])), GFP_KERNEL); + if (!h264_pps_info->scllst4x4pic) { + pps_parse_error |= BSPP_ERROR_OUT_OF_MEMORY; + } else { + VDEC_ASSERT(h264_pps_info->scllst4x4pic); + memset(h264_pps_info->scllst4x4pic, 0x00, + sizeof(unsigned char[H264FW_NUM_4X4_LISTS] + [H264FW_4X4_SIZE])); + } + } + if (!h264_pps_info->scllst8x8pic) { + h264_pps_info->scllst8x8pic = + kmalloc((sizeof(unsigned char[H264FW_NUM_8X8_LISTS] + [H264FW_8X8_SIZE])), GFP_KERNEL); + if (!h264_pps_info->scllst8x8pic) { + pps_parse_error |= BSPP_ERROR_OUT_OF_MEMORY; + } else { + VDEC_ASSERT(h264_pps_info->scllst8x8pic); + memset(h264_pps_info->scllst8x8pic, 0x00, + sizeof(unsigned char[H264FW_NUM_8X8_LISTS] + [H264FW_8X8_SIZE])); + } + } + { + unsigned char(*scllst4x4pic)[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE] = + (unsigned char (*)[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE]) + h264_pps_info->scllst4x4pic; + unsigned char(*scllst8x8pic)[H264FW_NUM_8X8_LISTS][H264FW_8X8_SIZE] = + (unsigned char (*)[H264FW_NUM_8X8_LISTS][H264FW_8X8_SIZE]) + h264_pps_info->scllst8x8pic; + + /* + * For chroma_format =3 (YUV444) total list would be 12 + * if transform_8x8_mode_flag is enabled else 6. + */ + n_scaling_list = 6 + (chroma_format_idc != 3 ? 2 : 6) * + h264_pps_info->transform_8x8_mode_flag; + if (n_scaling_list > 12) + pps_parse_error |= BSPP_ERROR_UNRECOVERABLE; + + VDEC_ASSERT(h264_pps_info->scllst4x4pic); + VDEC_ASSERT(h264_pps_info->scllst8x8pic); + for (i = 0; i < n_scaling_list; i++) { + unsigned char *ptr = + &h264_pps_info->usedefaultscalingmatrixflag_pic[i]; + + h264_pps_info->pic_scaling_list_present_flag[i] = + swsr_read_bits(swsr_context, 1); + if (h264_pps_info->pic_scaling_list_present_flag[i]) { + if (i < 6) + pps_parse_error |= + bspp_h264_scl_listparser + (swsr_context, + (*scllst4x4pic)[i], 16, ptr); + else + pps_parse_error |= + bspp_h264_scl_listparser + (swsr_context, + (*scllst8x8pic)[i - 6], 64, ptr); + } + } + } + } + h264_pps_info->second_chroma_qp_index_offset = swsr_read_signed_expgoulomb + (swsr_context); + + if (h264_pps_info->second_chroma_qp_index_offset > H264_MAX_CHROMA_QP_INDEX_OFFSET) + h264_pps_info->second_chroma_qp_index_offset = + H264_MAX_CHROMA_QP_INDEX_OFFSET; + else if (h264_pps_info->second_chroma_qp_index_offset < + H264_MIN_CHROMA_QP_INDEX_OFFSET) + h264_pps_info->second_chroma_qp_index_offset = + H264_MIN_CHROMA_QP_INDEX_OFFSET; + } else { + h264_pps_info->second_chroma_qp_index_offset = + h264_pps_info->chroma_qp_index_offset; + } + + if (swsr_check_exception(swsr_context) != SWSR_EXCEPT_NO_EXCEPTION) + pps_parse_error |= BSPP_ERROR_INSUFFICIENT_DATA; + + return pps_parse_error; +} + +static int bspp_h264_release_sequ_hdr_info(void *str_alloc, void *secure_sps_info) +{ + struct bspp_h264_seq_hdr_info *h264_seq_hdr_info = + (struct bspp_h264_seq_hdr_info *)secure_sps_info; + + if (!h264_seq_hdr_info) + return IMG_ERROR_INVALID_PARAMETERS; + + return 0; +} + +static int bspp_h264_reset_seq_hdr_info(void *secure_sps_info) +{ + struct bspp_h264_seq_hdr_info *h264_seq_hdr_info = NULL; + unsigned int *nal_hrd_bitrate_valueminus1 = NULL; + unsigned int *vcl_hrd_bitrate_valueminus1 = NULL; + unsigned int *nal_hrd_cpbsize_valueminus1 = NULL; + unsigned int *vcl_hrd_cpbsize_valueminus1 = NULL; + unsigned char *nal_hrd_cbrflag = NULL; + unsigned char *vcl_hrd_cbrflag = NULL; + unsigned int *offset_for_ref_frame = NULL; + unsigned char *scllst4x4seq = NULL; + unsigned char *scllst8x8seq = NULL; + + if (!secure_sps_info) + return IMG_ERROR_INVALID_PARAMETERS; + + h264_seq_hdr_info = (struct bspp_h264_seq_hdr_info *)secure_sps_info; + + offset_for_ref_frame = h264_seq_hdr_info->sps_info.offset_for_ref_frame; + scllst4x4seq = h264_seq_hdr_info->sps_info.scllst4x4seq; + scllst8x8seq = h264_seq_hdr_info->sps_info.scllst8x8seq; + nal_hrd_bitrate_valueminus1 = + h264_seq_hdr_info->vui_info.nal_hrd_parameters.bit_rate_value_minus1; + vcl_hrd_bitrate_valueminus1 = + h264_seq_hdr_info->vui_info.vcl_hrd_parameters.bit_rate_value_minus1; + nal_hrd_cpbsize_valueminus1 = + h264_seq_hdr_info->vui_info.nal_hrd_parameters.cpb_size_value_minus1; + vcl_hrd_cpbsize_valueminus1 = + h264_seq_hdr_info->vui_info.vcl_hrd_parameters.cpb_size_value_minus1; + nal_hrd_cbrflag = h264_seq_hdr_info->vui_info.nal_hrd_parameters.cbr_flag; + vcl_hrd_cbrflag = h264_seq_hdr_info->vui_info.vcl_hrd_parameters.cbr_flag; + + /* Cleaning vui_info */ + if (h264_seq_hdr_info->vui_info.nal_hrd_parameters.bit_rate_value_minus1) + memset(h264_seq_hdr_info->vui_info.nal_hrd_parameters.bit_rate_value_minus1, + 0x00, VDEC_H264_MAXIMUMVALUEOFCPB_CNT * sizeof(unsigned int)); + + if (h264_seq_hdr_info->vui_info.nal_hrd_parameters.cpb_size_value_minus1) + memset(h264_seq_hdr_info->vui_info.nal_hrd_parameters.cpb_size_value_minus1, + 0x00, VDEC_H264_MAXIMUMVALUEOFCPB_CNT * sizeof(unsigned int)); + + if (h264_seq_hdr_info->vui_info.vcl_hrd_parameters.cpb_size_value_minus1) + memset(h264_seq_hdr_info->vui_info.vcl_hrd_parameters.cpb_size_value_minus1, + 0x00, VDEC_H264_MAXIMUMVALUEOFCPB_CNT * sizeof(unsigned int)); + + if (h264_seq_hdr_info->vui_info.nal_hrd_parameters.cbr_flag) + memset(h264_seq_hdr_info->vui_info.nal_hrd_parameters.cbr_flag, + 0x00, VDEC_H264_MAXIMUMVALUEOFCPB_CNT * sizeof(unsigned char)); + + if (h264_seq_hdr_info->vui_info.vcl_hrd_parameters.cbr_flag) + memset(h264_seq_hdr_info->vui_info.vcl_hrd_parameters.cbr_flag, + 0x00, VDEC_H264_MAXIMUMVALUEOFCPB_CNT * sizeof(unsigned char)); + + /* Cleaning sps_info */ + if (h264_seq_hdr_info->sps_info.offset_for_ref_frame) + memset(h264_seq_hdr_info->sps_info.offset_for_ref_frame, 0x00, + H264FW_MAX_CYCLE_REF_FRAMES * sizeof(unsigned int)); + + if (h264_seq_hdr_info->sps_info.scllst4x4seq) + memset(h264_seq_hdr_info->sps_info.scllst4x4seq, 0x00, + sizeof(unsigned char[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE])); + + if (h264_seq_hdr_info->sps_info.scllst8x8seq) + memset(h264_seq_hdr_info->sps_info.scllst8x8seq, 0x00, + sizeof(unsigned char[H264FW_NUM_8X8_LISTS][H264FW_8X8_SIZE])); + + /* Erasing the structure */ + memset(h264_seq_hdr_info, 0, sizeof(*h264_seq_hdr_info)); + + /* Restoring pointers */ + h264_seq_hdr_info->sps_info.offset_for_ref_frame = offset_for_ref_frame; + h264_seq_hdr_info->sps_info.scllst4x4seq = scllst4x4seq; + h264_seq_hdr_info->sps_info.scllst8x8seq = scllst8x8seq; + + h264_seq_hdr_info->vui_info.nal_hrd_parameters.bit_rate_value_minus1 = + nal_hrd_bitrate_valueminus1; + h264_seq_hdr_info->vui_info.vcl_hrd_parameters.bit_rate_value_minus1 = + vcl_hrd_bitrate_valueminus1; + + h264_seq_hdr_info->vui_info.nal_hrd_parameters.cpb_size_value_minus1 = + nal_hrd_cpbsize_valueminus1; + h264_seq_hdr_info->vui_info.vcl_hrd_parameters.cpb_size_value_minus1 = + vcl_hrd_cpbsize_valueminus1; + + h264_seq_hdr_info->vui_info.nal_hrd_parameters.cbr_flag = nal_hrd_cbrflag; + h264_seq_hdr_info->vui_info.vcl_hrd_parameters.cbr_flag = vcl_hrd_cbrflag; + + return 0; +} + +static int bspp_h264_reset_pps_info(void *secure_pps_info) +{ + struct bspp_h264_pps_info *h264_pps_info = NULL; + unsigned short slicegroupidnum = 0; + unsigned char *slice_group_id = NULL; + unsigned char *scllst4x4pic = NULL; + unsigned char *scllst8x8pic = NULL; + + if (!secure_pps_info) + return IMG_ERROR_INVALID_PARAMETERS; + + h264_pps_info = (struct bspp_h264_pps_info *)secure_pps_info; + + /* + * Storing temp values (we want to leave the SGM structure + * it may be useful again instead of reallocating later + */ + slice_group_id = h264_pps_info->h264_ppssgm_info.slice_group_id; + slicegroupidnum = h264_pps_info->h264_ppssgm_info.slicegroupidnum; + scllst4x4pic = h264_pps_info->scllst4x4pic; + scllst8x8pic = h264_pps_info->scllst8x8pic; + + if (h264_pps_info->h264_ppssgm_info.slice_group_id) + memset(h264_pps_info->h264_ppssgm_info.slice_group_id, 0x00, + h264_pps_info->h264_ppssgm_info.slicegroupidnum * sizeof(unsigned char)); + + if (h264_pps_info->scllst4x4pic) + memset(h264_pps_info->scllst4x4pic, 0x00, + sizeof(unsigned char[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE])); + + if (h264_pps_info->scllst8x8pic) + memset(h264_pps_info->scllst8x8pic, 0x00, + sizeof(unsigned char[H264FW_NUM_8X8_LISTS][H264FW_8X8_SIZE])); + + /* Erasing the structure */ + memset(h264_pps_info, 0x00, sizeof(*h264_pps_info)); + + /* Copy the temp variable back */ + h264_pps_info->h264_ppssgm_info.slicegroupidnum = slicegroupidnum; + h264_pps_info->h264_ppssgm_info.slice_group_id = slice_group_id; + h264_pps_info->scllst4x4pic = scllst4x4pic; + h264_pps_info->scllst8x8pic = scllst8x8pic; + + return 0; +} + +static enum bspp_error_type bspp_h264_pict_hdr_parser + (void *swsr_context, void *str_res, + struct bspp_h264_slice_hdr_info *h264_slice_hdr_info, + struct bspp_pps_info **pps_info, + struct bspp_sequence_hdr_info **seq_hdr_info, + enum h264_nalunittype nal_unit_type, + unsigned char nal_ref_idc) +{ + enum bspp_error_type slice_parse_error = BSPP_ERROR_NONE; + struct bspp_h264_pps_info *h264_pps_info; + struct bspp_pps_info *pps_info_loc; + struct bspp_h264_seq_hdr_info *h264_seq_hdr_info; + struct bspp_sequence_hdr_info *seq_hdr_info_loc; + int id_loc; + + VDEC_ASSERT(swsr_context); + + memset(h264_slice_hdr_info, 0, sizeof(*h264_slice_hdr_info)); + + h264_slice_hdr_info->first_mb_in_slice = swsr_read_unsigned_expgoulomb(swsr_context); + h264_slice_hdr_info->slice_type = (enum bspp_h264_slice_type)swsr_read_unsigned_expgoulomb + (swsr_context); + if ((unsigned int)h264_slice_hdr_info->slice_type > 9) { + pr_err("Slice Type [%d] invalid, set to P", h264_slice_hdr_info->slice_type); + h264_slice_hdr_info->slice_type = (enum bspp_h264_slice_type)0; + slice_parse_error |= BSPP_ERROR_CORRECTION_VALIDVALUE; + } + h264_slice_hdr_info->slice_type = + (enum bspp_h264_slice_type)(h264_slice_hdr_info->slice_type % 5); + + h264_slice_hdr_info->pps_id = swsr_read_unsigned_expgoulomb(swsr_context); + if (h264_slice_hdr_info->pps_id >= MAX_PPS_COUNT) { + pr_err("Picture Parameter ID [%d] invalid, set to 0", h264_slice_hdr_info->pps_id); + h264_slice_hdr_info->pps_id = 0; + slice_parse_error |= BSPP_ERROR_CORRECTION_VALIDVALUE; + } + + /* Set relevant PPS and SPS */ + pps_info_loc = bspp_get_pps_hdr(str_res, h264_slice_hdr_info->pps_id); + + if (!pps_info_loc) { + slice_parse_error |= BSPP_ERROR_NO_PPS; + goto error; + } + h264_pps_info = (struct bspp_h264_pps_info *)pps_info_loc->secure_pps_info; + if (!h264_pps_info) { + slice_parse_error |= BSPP_ERROR_NO_PPS; + goto error; + } + VDEC_ASSERT(h264_pps_info->pps_id == h264_slice_hdr_info->pps_id); + *pps_info = pps_info_loc; + + /* seq_parameter_set_id is always in range 0-31, + * so we can add offset indicating subsequence header + */ + id_loc = h264_pps_info->seq_parameter_set_id; + id_loc = (nal_unit_type == H264_NALTYPE_SLICE_SCALABLE || + nal_unit_type == H264_NALTYPE_SLICE_IDR_SCALABLE || + nal_unit_type == H264_NALTYPE_SUBSET_SPS) ? id_loc + 32 : id_loc; + + seq_hdr_info_loc = bspp_get_sequ_hdr(str_res, id_loc); + + if (!seq_hdr_info_loc) { + slice_parse_error |= BSPP_ERROR_NO_SEQUENCE_HDR; + goto error; + } + h264_seq_hdr_info = (struct bspp_h264_seq_hdr_info *)seq_hdr_info_loc->secure_sequence_info; + VDEC_ASSERT((unsigned int)h264_seq_hdr_info->sps_info.seq_parameter_set_id == + h264_pps_info->seq_parameter_set_id); + *seq_hdr_info = seq_hdr_info_loc; + + /* + * For MINIMAL parsing in secure mode, slice header parsing can stop + * here, may be problematic with field-coded streams and splitting + * fields + */ + if (h264_seq_hdr_info->sps_info.separate_colour_plane_flag) + h264_slice_hdr_info->colour_plane_id = swsr_read_bits(swsr_context, 2); + + else + h264_slice_hdr_info->colour_plane_id = 0; + + h264_slice_hdr_info->frame_num = swsr_read_bits + (swsr_context, + h264_seq_hdr_info->sps_info.log2_max_frame_num_minus4 + + 4); + + VDEC_ASSERT(h264_slice_hdr_info->frame_num < + (1UL << (h264_seq_hdr_info->sps_info.log2_max_frame_num_minus4 + 4))); + + if (!h264_seq_hdr_info->sps_info.frame_mbs_only_flag) { + if (h264_slice_hdr_info->slice_type == B_SLICE && + !h264_seq_hdr_info->sps_info.direct_8x8_inference_flag) + slice_parse_error |= BSPP_ERROR_INVALID_VALUE; + + h264_slice_hdr_info->field_pic_flag = swsr_read_bits(swsr_context, 1); + if (h264_slice_hdr_info->field_pic_flag) + h264_slice_hdr_info->bottom_field_flag = swsr_read_bits(swsr_context, 1); + else + h264_slice_hdr_info->bottom_field_flag = 0; + } else { + h264_slice_hdr_info->field_pic_flag = 0; + h264_slice_hdr_info->bottom_field_flag = 0; + } + + /* + * At this point we have everything we need, but we still lack all the + * conditions for detecting new pictures (needed for error cases) + */ + if (nal_unit_type == H264_NALTYPE_IDR_SLICE) + h264_slice_hdr_info->idr_pic_id = swsr_read_unsigned_expgoulomb(swsr_context); + + if (h264_seq_hdr_info->sps_info.pic_order_cnt_type == 0) { + h264_slice_hdr_info->pic_order_cnt_lsb = swsr_read_bits + (swsr_context, + h264_seq_hdr_info->sps_info.log2_max_pic_order_cnt_lsb_minus4 + 4); + if (h264_pps_info->pic_order_present_flag && !h264_slice_hdr_info->field_pic_flag) + h264_slice_hdr_info->delta_pic_order_cnt_bottom = + swsr_read_signed_expgoulomb(swsr_context); + } + + if (h264_seq_hdr_info->sps_info.pic_order_cnt_type == 1 && + !h264_seq_hdr_info->sps_info.delta_pic_order_always_zero_flag) { + h264_slice_hdr_info->delta_pic_order_cnt[0] = swsr_read_signed_expgoulomb + (swsr_context); + if (h264_pps_info->pic_order_present_flag && !h264_slice_hdr_info->field_pic_flag) + h264_slice_hdr_info->delta_pic_order_cnt[1] = swsr_read_signed_expgoulomb + (swsr_context); + } + + if (h264_pps_info->redundant_pic_cnt_present_flag) + h264_slice_hdr_info->redundant_pic_cnt = + swsr_read_unsigned_expgoulomb(swsr_context); + + /* For FMO streams, we need to go further */ + if (h264_pps_info->num_slice_groups_minus1 != 0 && + h264_pps_info->slice_group_map_type >= 3 && + h264_pps_info->slice_group_map_type <= 5) { + if (h264_slice_hdr_info->slice_type == B_SLICE) + swsr_read_bits(swsr_context, 1); + + if (h264_slice_hdr_info->slice_type == P_SLICE || + h264_slice_hdr_info->slice_type == SP_SLICE || + h264_slice_hdr_info->slice_type == B_SLICE) { + h264_slice_hdr_info->num_ref_idx_active_override_flag = + swsr_read_bits(swsr_context, 1); + if (h264_slice_hdr_info->num_ref_idx_active_override_flag) { + h264_slice_hdr_info->num_ref_idx_lx_active_minus1[0] = + swsr_read_unsigned_expgoulomb(swsr_context); + if (h264_slice_hdr_info->slice_type == B_SLICE) + h264_slice_hdr_info->num_ref_idx_lx_active_minus1[1] = + swsr_read_unsigned_expgoulomb(swsr_context); + } + } + + if (h264_slice_hdr_info->slice_type != SI_SLICE && + h264_slice_hdr_info->slice_type != I_SLICE) { + /* Reference picture list modification */ + /* parse reordering info and pack into commands */ + unsigned int i; + unsigned int cmd_num, list_num; + unsigned int command; + + i = (h264_slice_hdr_info->slice_type == B_SLICE) ? 2 : 1; + + for (list_num = 0; list_num < i; list_num++) { + cmd_num = 0; + if (swsr_read_bits(swsr_context, 1)) { + do { + command = + swsr_read_unsigned_expgoulomb(swsr_context); + if (command != 3) { + swsr_read_unsigned_expgoulomb(swsr_context); + cmd_num++; + } + } while (command != 3 && cmd_num <= SL_MAX_REF_IDX); + } + } + } + + if ((h264_pps_info->weighted_pred_flag && + h264_slice_hdr_info->slice_type == P_SLICE) || + (h264_pps_info->weighted_bipred_idc && + h264_slice_hdr_info->slice_type == B_SLICE)) { + int mono_chrome; + unsigned int list, i, j, k; + + mono_chrome = (!h264_seq_hdr_info->sps_info.chroma_format_idc) ? 1 : 0; + + swsr_read_unsigned_expgoulomb(swsr_context); + if (!mono_chrome) + swsr_read_unsigned_expgoulomb(swsr_context); + + k = (h264_slice_hdr_info->slice_type == B_SLICE) ? 2 : 1; + + for (list = 0; list < k; list++) { + for (i = 0; + i <= + h264_slice_hdr_info->num_ref_idx_lx_active_minus1[list]; + i++) { + if (swsr_read_bits(swsr_context, 1)) { + swsr_read_signed_expgoulomb(swsr_context); + swsr_read_signed_expgoulomb(swsr_context); + } + + if (!mono_chrome && (swsr_read_bits(swsr_context, 1))) { + for (j = 0; j < 2; j++) { + swsr_read_signed_expgoulomb + (swsr_context); + swsr_read_signed_expgoulomb + (swsr_context); + } + } + } + } + } + + if (nal_ref_idc != 0) { + unsigned int memmanop; + + if (nal_unit_type == H264_NALTYPE_IDR_SLICE) { + swsr_read_bits(swsr_context, 1); + swsr_read_bits(swsr_context, 1); + } + if (swsr_read_bits(swsr_context, 1)) { + do { + /* clamp 0--6 */ + memmanop = swsr_read_unsigned_expgoulomb + (swsr_context); + if (memmanop != 0 && memmanop != 5) { + if (memmanop == 3) { + swsr_read_unsigned_expgoulomb + (swsr_context); + swsr_read_unsigned_expgoulomb + (swsr_context); + } else { + swsr_read_unsigned_expgoulomb + (swsr_context); + } + } + } while (memmanop != 0); + } + } + + if (h264_pps_info->entropy_coding_mode_flag && + h264_slice_hdr_info->slice_type != I_SLICE) + swsr_read_unsigned_expgoulomb(swsr_context); + + swsr_read_signed_expgoulomb(swsr_context); + + if (h264_slice_hdr_info->slice_type == SP_SLICE || + h264_slice_hdr_info->slice_type == SI_SLICE) { + if (h264_slice_hdr_info->slice_type == SP_SLICE) + swsr_read_bits(swsr_context, 1); + + /* slice_qs_delta */ + swsr_read_signed_expgoulomb(swsr_context); + } + + if (h264_pps_info->deblocking_filter_control_present_flag) { + if (swsr_read_unsigned_expgoulomb(swsr_context) != 1) { + swsr_read_signed_expgoulomb(swsr_context); + swsr_read_signed_expgoulomb(swsr_context); + } + } + + if (h264_pps_info->slice_group_map_type >= 3 && + h264_pps_info->slice_group_map_type <= 5) { + unsigned int num_slice_group_map_units = + (h264_seq_hdr_info->sps_info.pic_height_in_map_units_minus1 + 1) * + (h264_seq_hdr_info->sps_info.pic_width_in_mbs_minus1 + 1); + + unsigned short slice_group_change_rate = + (h264_pps_info->slice_group_change_rate_minus1 + 1); + + unsigned int width = h264ceillog2(num_slice_group_map_units / + slice_group_change_rate + + (num_slice_group_map_units % slice_group_change_rate == + 0 ? 0 : 1) + 1); /* (7-32) */ + h264_slice_hdr_info->slice_group_change_cycle = swsr_read_bits(swsr_context, + width); + } + } + +error: + return slice_parse_error; +} + +static void bspp_h264_select_scaling_list(struct h264fw_picture_ps *h264fw_pps_info, + struct bspp_h264_pps_info *h264_pps_info, + struct bspp_h264_seq_hdr_info *h264_seq_hdr_info) +{ + unsigned int num8x8_lists; + unsigned int i; + const unsigned char *quant_matrix = NULL; + unsigned char (*scllst4x4pic)[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE] = + (unsigned char (*)[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE])h264_pps_info->scllst4x4pic; + unsigned char (*scllst8x8pic)[H264FW_NUM_8X8_LISTS][H264FW_8X8_SIZE] = + (unsigned char (*)[H264FW_NUM_8X8_LISTS][H264FW_8X8_SIZE])h264_pps_info->scllst8x8pic; + + unsigned char (*scllst4x4seq)[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE] = + (unsigned char (*)[H264FW_NUM_4X4_LISTS][H264FW_4X4_SIZE]) + h264_seq_hdr_info->sps_info.scllst4x4seq; + unsigned char (*scllst8x8seq)[H264FW_NUM_8X8_LISTS][H264FW_8X8_SIZE] = + (unsigned char (*)[H264FW_NUM_8X8_LISTS][H264FW_8X8_SIZE]) + h264_seq_hdr_info->sps_info.scllst8x8seq; + + if (h264_seq_hdr_info->sps_info.seq_scaling_matrix_present_flag) { + VDEC_ASSERT(h264_seq_hdr_info->sps_info.scllst4x4seq); + VDEC_ASSERT(h264_seq_hdr_info->sps_info.scllst8x8seq); + } + + if (h264_pps_info->pic_scaling_matrix_present_flag) { + for (i = 0; i < H264FW_NUM_4X4_LISTS; i++) { + if (h264_pps_info->pic_scaling_list_present_flag[i]) { + if (h264_pps_info->usedefaultscalingmatrixflag_pic[i]) + quant_matrix = + (i > 2) ? default_4x4_inter : default_4x4_intra; + else + quant_matrix = (*scllst4x4pic)[i]; + + } else { + if (h264_seq_hdr_info->sps_info.seq_scaling_matrix_present_flag) { + /* SPS matrix present - use fallback rule B */ + /* first 4x4 Intra list */ + if (i == 0) { + if + (h264_seq_hdr_info->sps_info.seq_scaling_list_present_flag[i] && + !h264_seq_hdr_info->sps_info.usedefaultscalingmatrixflag_seq[i]) { + VDEC_ASSERT + (h264_seq_hdr_info->sps_info.scllst4x4seq); + if (scllst4x4seq) + quant_matrix = (*scllst4x4seq)[i]; + } else { + quant_matrix = default_4x4_intra; + } + } + /* first 4x4 Inter list */ + else if (i == 3) { + if + (h264_seq_hdr_info->sps_info.seq_scaling_list_present_flag[i] && + !h264_seq_hdr_info->sps_info.usedefaultscalingmatrixflag_seq[i]) { + VDEC_ASSERT + (h264_seq_hdr_info->sps_info.scllst4x4seq); + if (scllst4x4seq) + quant_matrix = (*scllst4x4seq)[i]; + } else { + quant_matrix = default_4x4_inter; + } + } else { + quant_matrix = + h264fw_pps_info->scalinglist4x4[i - 1]; + } + } else { + /* SPS matrix not present - use fallback rule A */ + /* first 4x4 Intra list */ + if (i == 0) + quant_matrix = default_4x4_intra; + /* first 4x4 Interlist */ + else if (i == 3) + quant_matrix = default_4x4_inter; + else + quant_matrix = + h264fw_pps_info->scalinglist4x4[i - 1]; + } + } + if (!quant_matrix) { + VDEC_ASSERT(0); + return; + } + /* copy correct 4x4 list to output - as selected by PPS */ + memcpy(h264fw_pps_info->scalinglist4x4[i], quant_matrix, + sizeof(h264fw_pps_info->scalinglist4x4[i])); + } + } else { + /* PPS matrix not present, use SPS information */ + if (h264_seq_hdr_info->sps_info.seq_scaling_matrix_present_flag) { + for (i = 0; i < H264FW_NUM_4X4_LISTS; i++) { + if (h264_seq_hdr_info->sps_info.seq_scaling_list_present_flag[i]) { + if + (h264_seq_hdr_info->sps_info.usedefaultscalingmatrixflag_seq + [i]) { + quant_matrix = (i > 2) ? default_4x4_inter + : default_4x4_intra; + } else { + VDEC_ASSERT + (h264_seq_hdr_info->sps_info.scllst4x4seq); + if (scllst4x4seq) + quant_matrix = (*scllst4x4seq)[i]; + } + } else { + /* SPS list not present - use fallback rule A */ + /* first 4x4 Intra list */ + if (i == 0) + quant_matrix = default_4x4_intra; + else if (i == 3) /* first 4x4 Inter list */ + quant_matrix = default_4x4_inter; + else + quant_matrix = + h264fw_pps_info->scalinglist4x4[i - 1]; + } + if (quant_matrix) { + /* copy correct 4x4 list to output - as selected by SPS */ + memcpy(h264fw_pps_info->scalinglist4x4[i], quant_matrix, + sizeof(h264fw_pps_info->scalinglist4x4[i])); + } + } + } else { + /* SPS matrix not present - use flat lists */ + quant_matrix = default_4x4_org; + for (i = 0; i < H264FW_NUM_4X4_LISTS; i++) + memcpy(h264fw_pps_info->scalinglist4x4[i], quant_matrix, + sizeof(h264fw_pps_info->scalinglist4x4[i])); + } + } + + /* 8x8 matrices */ + num8x8_lists = (h264_seq_hdr_info->sps_info.chroma_format_idc == 3) ? 6 : 2; + if (h264_pps_info->transform_8x8_mode_flag) { + unsigned char *seq_scllstflg = + h264_seq_hdr_info->sps_info.seq_scaling_list_present_flag; + unsigned char *def_sclmatflg_seq = + h264_seq_hdr_info->sps_info.usedefaultscalingmatrixflag_seq; + + if (h264_pps_info->pic_scaling_matrix_present_flag) { + for (i = 0; i < num8x8_lists; i++) { + if (h264_pps_info->pic_scaling_list_present_flag[i + + H264FW_NUM_4X4_LISTS]) { + if (h264_pps_info->usedefaultscalingmatrixflag_pic[i + + H264FW_NUM_4X4_LISTS]) { + quant_matrix = (i & 0x1) ? default_8x8_inter + : default_8x8_intra; + } else { + VDEC_ASSERT(h264_pps_info->scllst8x8pic); + if (scllst8x8pic) + quant_matrix = (*scllst8x8pic)[i]; + } + } else { + if + (h264_seq_hdr_info->sps_info.seq_scaling_matrix_present_flag) { + /* SPS matrix present - use fallback rule B */ + /* list 6 - first 8x8 Intra list */ + if (i == 0) { + if (seq_scllstflg[i + + H264FW_NUM_4X4_LISTS] && + !def_sclmatflg_seq[i + + H264FW_NUM_4X4_LISTS]) { + VDEC_ASSERT + (h264_seq_hdr_info->sps_info.scllst8x8seq); + if (scllst8x8seq) + quant_matrix = (*scllst8x8seq)[i]; + } else { + quant_matrix = default_8x8_intra; + } + /* list 7 - first 8x8 Inter list */ + } else if (i == 1) { + if (seq_scllstflg[i + + H264FW_NUM_4X4_LISTS] && + !def_sclmatflg_seq[i + + H264FW_NUM_4X4_LISTS]) { + VDEC_ASSERT + (h264_seq_hdr_info->sps_info.scllst8x8seq); + if (scllst8x8seq) + quant_matrix = (*scllst8x8seq)[i]; + } else { + quant_matrix = default_8x8_inter; + } + } else { + quant_matrix = + h264fw_pps_info->scalinglist8x8[i - 2]; + } + } else { + /* SPS matrix not present - use fallback rule A */ + /* list 6 - first 8x8 Intra list */ + if (i == 0) + quant_matrix = default_8x8_intra; + /* list 7 - first 8x8 Inter list */ + else if (i == 1) + quant_matrix = default_8x8_inter; + else + quant_matrix = + h264fw_pps_info->scalinglist8x8[i - 2]; + } + } + if (quant_matrix) { + /* copy correct 8x8 list to output - as selected by PPS */ + memcpy(h264fw_pps_info->scalinglist8x8[i], quant_matrix, + sizeof(h264fw_pps_info->scalinglist8x8[i])); + } + } + } else { + /* PPS matrix not present, use SPS information */ + if (h264_seq_hdr_info->sps_info.seq_scaling_matrix_present_flag) { + for (i = 0; i < num8x8_lists; i++) { + if (seq_scllstflg[i + H264FW_NUM_4X4_LISTS] && + def_sclmatflg_seq[i + H264FW_NUM_4X4_LISTS]) { + quant_matrix = + (i & 0x1) ? default_8x8_inter : + default_8x8_intra; + } else if ((seq_scllstflg[i + H264FW_NUM_4X4_LISTS]) && + !(def_sclmatflg_seq[i + H264FW_NUM_4X4_LISTS])) { + VDEC_ASSERT + (h264_seq_hdr_info->sps_info.scllst8x8seq); + if (scllst8x8seq) + quant_matrix = (*scllst8x8seq)[i]; + } else if (!(seq_scllstflg[i + H264FW_NUM_4X4_LISTS]) && + (i == 0)) { + /* SPS list not present - use fallback rule A */ + /* list 6 - first 8x8 Intra list */ + quant_matrix = default_8x8_intra; + } else if (!(seq_scllstflg[i + H264FW_NUM_4X4_LISTS]) && + (i == 1)) { + /* list 7 - first 8x8 Inter list */ + quant_matrix = default_8x8_inter; + } else { + quant_matrix = + h264fw_pps_info->scalinglist8x8 + [i - 2]; + } + if (quant_matrix) { + /* copy correct 8x8 list to output - + * as selected by SPS + */ + memcpy(h264fw_pps_info->scalinglist8x8[i], + quant_matrix, + sizeof(h264fw_pps_info->scalinglist8x8[i])); + } + } + } else { + /* SPS matrix not present - use flat lists */ + quant_matrix = default_8x8_org; + for (i = 0; i < num8x8_lists; i++) + memcpy(h264fw_pps_info->scalinglist8x8[i], quant_matrix, + sizeof(h264fw_pps_info->scalinglist8x8[i])); + } + } + } +} + +static void bspp_h264_fwpps_populate(struct bspp_h264_pps_info *h264_pps_info, + struct h264fw_picture_ps *h264fw_pps_info) +{ + h264fw_pps_info->deblocking_filter_control_present_flag = + h264_pps_info->deblocking_filter_control_present_flag; + h264fw_pps_info->transform_8x8_mode_flag = h264_pps_info->transform_8x8_mode_flag; + h264fw_pps_info->entropy_coding_mode_flag = h264_pps_info->entropy_coding_mode_flag; + h264fw_pps_info->redundant_pic_cnt_present_flag = + h264_pps_info->redundant_pic_cnt_present_flag; + h264fw_pps_info->weighted_bipred_idc = h264_pps_info->weighted_bipred_idc; + h264fw_pps_info->weighted_pred_flag = h264_pps_info->weighted_pred_flag; + h264fw_pps_info->pic_order_present_flag = h264_pps_info->pic_order_present_flag; + h264fw_pps_info->pic_init_qp = h264_pps_info->pic_init_qp_minus26 + 26; + h264fw_pps_info->constrained_intra_pred_flag = h264_pps_info->constrained_intra_pred_flag; + VDEC_ASSERT(sizeof(h264fw_pps_info->num_ref_lx_active_minus1) == + sizeof(h264_pps_info->num_ref_idx_lx_active_minus1)); + VDEC_ASSERT(sizeof(h264fw_pps_info->num_ref_lx_active_minus1) == + sizeof(unsigned char) * H264FW_MAX_REFPIC_LISTS); + memcpy(h264fw_pps_info->num_ref_lx_active_minus1, + h264_pps_info->num_ref_idx_lx_active_minus1, + sizeof(h264fw_pps_info->num_ref_lx_active_minus1)); + h264fw_pps_info->slice_group_map_type = h264_pps_info->slice_group_map_type; + h264fw_pps_info->num_slice_groups_minus1 = h264_pps_info->num_slice_groups_minus1; + h264fw_pps_info->slice_group_change_rate_minus1 = + h264_pps_info->slice_group_change_rate_minus1; + h264fw_pps_info->chroma_qp_index_offset = h264_pps_info->chroma_qp_index_offset; + h264fw_pps_info->second_chroma_qp_index_offset = + h264_pps_info->second_chroma_qp_index_offset; +} + +static void +bspp_h264_fwseq_hdr_populate(struct bspp_h264_seq_hdr_info *h264_seq_hdr_info, + struct h264fw_sequence_ps *h264_fwseq_hdr_info, + unsigned int max_dec_frame_buffering) +{ + /* Basic SPS */ + h264_fwseq_hdr_info->profile_idc = h264_seq_hdr_info->sps_info.profile_idc; + h264_fwseq_hdr_info->chroma_format_idc = h264_seq_hdr_info->sps_info.chroma_format_idc; + h264_fwseq_hdr_info->separate_colour_plane_flag = + h264_seq_hdr_info->sps_info.separate_colour_plane_flag; + h264_fwseq_hdr_info->bit_depth_luma_minus8 = + h264_seq_hdr_info->sps_info.bit_depth_luma_minus8; + h264_fwseq_hdr_info->bit_depth_chroma_minus8 = + h264_seq_hdr_info->sps_info.bit_depth_chroma_minus8; + h264_fwseq_hdr_info->delta_pic_order_always_zero_flag = + h264_seq_hdr_info->sps_info.delta_pic_order_always_zero_flag; + h264_fwseq_hdr_info->log2_max_pic_order_cnt_lsb = + h264_seq_hdr_info->sps_info.log2_max_pic_order_cnt_lsb_minus4 + 4; + h264_fwseq_hdr_info->max_num_ref_frames = h264_seq_hdr_info->sps_info.max_num_ref_frames; + h264_fwseq_hdr_info->log2_max_frame_num = + h264_seq_hdr_info->sps_info.log2_max_frame_num_minus4 + 4; + h264_fwseq_hdr_info->pic_order_cnt_type = h264_seq_hdr_info->sps_info.pic_order_cnt_type; + h264_fwseq_hdr_info->frame_mbs_only_flag = h264_seq_hdr_info->sps_info.frame_mbs_only_flag; + h264_fwseq_hdr_info->gaps_in_frame_num_value_allowed_flag = + h264_seq_hdr_info->sps_info.gaps_in_frame_num_value_allowed_flag; + h264_fwseq_hdr_info->constraint_set_flags = + h264_seq_hdr_info->sps_info.constraint_set_flags; + h264_fwseq_hdr_info->level_idc = h264_seq_hdr_info->sps_info.level_idc; + h264_fwseq_hdr_info->num_ref_frames_in_pic_order_cnt_cycle = + h264_seq_hdr_info->sps_info.num_ref_frames_in_pic_order_cnt_cycle; + h264_fwseq_hdr_info->mb_adaptive_frame_field_flag = + h264_seq_hdr_info->sps_info.mb_adaptive_frame_field_flag; + h264_fwseq_hdr_info->offset_for_non_ref_pic = + h264_seq_hdr_info->sps_info.offset_for_non_ref_pic; + h264_fwseq_hdr_info->offset_for_top_to_bottom_field = + h264_seq_hdr_info->sps_info.offset_for_top_to_bottom_field; + h264_fwseq_hdr_info->pic_width_in_mbs_minus1 = + h264_seq_hdr_info->sps_info.pic_width_in_mbs_minus1; + h264_fwseq_hdr_info->pic_height_in_map_units_minus1 = + h264_seq_hdr_info->sps_info.pic_height_in_map_units_minus1; + h264_fwseq_hdr_info->direct_8x8_inference_flag = + h264_seq_hdr_info->sps_info.direct_8x8_inference_flag; + h264_fwseq_hdr_info->qpprime_y_zero_transform_bypass_flag = + h264_seq_hdr_info->sps_info.qpprime_y_zero_transform_bypass_flag; + + if (h264_seq_hdr_info->sps_info.offset_for_ref_frame) + memcpy(h264_fwseq_hdr_info->offset_for_ref_frame, + h264_seq_hdr_info->sps_info.offset_for_ref_frame, + sizeof(h264_fwseq_hdr_info->offset_for_ref_frame)); + else + memset(h264_fwseq_hdr_info->offset_for_ref_frame, 0x00, + sizeof(h264_fwseq_hdr_info->offset_for_ref_frame)); + + memset(h264_fwseq_hdr_info->anchor_inter_view_reference_id_list, 0x00, + sizeof(h264_fwseq_hdr_info->anchor_inter_view_reference_id_list)); + memset(h264_fwseq_hdr_info->non_anchor_inter_view_reference_id_list, 0x00, + sizeof(h264_fwseq_hdr_info->non_anchor_inter_view_reference_id_list)); + +#ifdef REDUCED_DPB_NO_PIC_REORDERING + /* From VUI */ + h264_fwseq_hdr_info->max_dec_frame_buffering = + h264_seq_hdr_info->vui_info.max_dec_frame_buffering; + h264_fwseq_hdr_info->num_reorder_frames = h264_seq_hdr_info->vui_info.num_reorder_frames; +#else + /* From VUI */ + if (h264_seq_hdr_info->vui_info.bitstream_restriction_flag) { + VDEC_ASSERT(h264_seq_hdr_info->sps_info.vui_parameters_present_flag); + h264_fwseq_hdr_info->max_dec_frame_buffering = + h264_seq_hdr_info->vui_info.max_dec_frame_buffering; + h264_fwseq_hdr_info->num_reorder_frames = + h264_seq_hdr_info->vui_info.num_reorder_frames; + } else { + h264_fwseq_hdr_info->max_dec_frame_buffering = max_dec_frame_buffering; + h264_fwseq_hdr_info->num_reorder_frames = 16; + } +#endif +} + +static void bspp_h264_commonseq_hdr_populate(struct bspp_h264_seq_hdr_info *h264_seq_hdr_info, + struct vdec_comsequ_hdrinfo *comseq_hdr_info) +{ + struct bspp_h264_sps_info *sps_info = &h264_seq_hdr_info->sps_info; + struct bspp_h264_vui_info *vui_info = &h264_seq_hdr_info->vui_info; + + comseq_hdr_info->codec_profile = sps_info->profile_idc; + comseq_hdr_info->codec_level = sps_info->level_idc; + + if (sps_info->vui_parameters_present_flag && vui_info->timing_info_present_flag) { + comseq_hdr_info->frame_rate_num = vui_info->time_scale; + comseq_hdr_info->frame_rate_den = 2 * vui_info->num_units_in_tick; + comseq_hdr_info->frame_rate = ((long)comseq_hdr_info->frame_rate_num) / + ((long)comseq_hdr_info->frame_rate_den); + } + + /* + * ColorSpace Description was present in the VUI parameters. + * copy it in CommonSeqHdr info for use by application. + */ + if (vui_info->video_signal_type_present_flag & vui_info->colour_description_present_flag) { + comseq_hdr_info->color_space_info.is_present = TRUE; + comseq_hdr_info->color_space_info.color_primaries = vui_info->colour_primaries; + comseq_hdr_info->color_space_info.transfer_characteristics = + vui_info->transfer_characteristics; + comseq_hdr_info->color_space_info.matrix_coefficients = + vui_info->matrix_coefficients; + } + + if (vui_info->aspect_ratio_info_present_flag) { + comseq_hdr_info->aspect_ratio_num = vui_info->sar_width; + comseq_hdr_info->aspect_ratio_den = vui_info->sar_height; + } + + comseq_hdr_info->interlaced_frames = sps_info->frame_mbs_only_flag ? 0 : 1; + + /* pixel_info populate */ + VDEC_ASSERT(sps_info->chroma_format_idc < 4); + comseq_hdr_info->pixel_info.chroma_fmt = (sps_info->chroma_format_idc == 0) ? 0 : 1; + comseq_hdr_info->pixel_info.chroma_fmt_idc = pixel_format_idc[sps_info->chroma_format_idc]; + comseq_hdr_info->pixel_info.chroma_interleave = + ((sps_info->chroma_format_idc == 0) || + (sps_info->chroma_format_idc == 3 && sps_info->separate_colour_plane_flag)) ? + PIXEL_INVALID_CI : PIXEL_UV_ORDER; + comseq_hdr_info->pixel_info.num_planes = + (sps_info->chroma_format_idc == 0) ? 1 : + (sps_info->chroma_format_idc == 3 && sps_info->separate_colour_plane_flag) ? 3 : 2; + comseq_hdr_info->pixel_info.bitdepth_y = sps_info->bit_depth_luma_minus8 + 8; + comseq_hdr_info->pixel_info.bitdepth_c = sps_info->bit_depth_chroma_minus8 + 8; + comseq_hdr_info->pixel_info.mem_pkg = + (comseq_hdr_info->pixel_info.bitdepth_y > 8 || + comseq_hdr_info->pixel_info.bitdepth_c > 8) ? + PIXEL_BIT10_MSB_MP : PIXEL_BIT8_MP; + comseq_hdr_info->pixel_info.pixfmt = + pixel_get_pixfmt(comseq_hdr_info->pixel_info.chroma_fmt_idc, + comseq_hdr_info->pixel_info.chroma_interleave, + comseq_hdr_info->pixel_info.mem_pkg, + comseq_hdr_info->pixel_info.bitdepth_y, + comseq_hdr_info->pixel_info.bitdepth_c, + comseq_hdr_info->pixel_info.num_planes); + + /* max_frame_size populate */ + comseq_hdr_info->max_frame_size.width = (sps_info->pic_width_in_mbs_minus1 + 1) * 16; + /* + * H264 has always coded size MB aligned. For sequences which *may* have Field-Coded + * pictures, as described by the frame_mbs_only_flag, the pic_height_in_map_units_minus1 + * refers to field height in MBs, so to find the actual Frame height we need to do + * Field_MBs_InHeight * 32 + */ + comseq_hdr_info->max_frame_size.height = (sps_info->pic_height_in_map_units_minus1 + 1) * + (sps_info->frame_mbs_only_flag ? 1 : 2) * 16; + + /* Passing 2*N to vxd_dec so that get_nbuffers can use formula N+3 for all codecs*/ + comseq_hdr_info->max_ref_frame_num = 2 * sps_info->max_num_ref_frames; + + comseq_hdr_info->field_codec_mblocks = sps_info->mb_adaptive_frame_field_flag; + comseq_hdr_info->min_pict_buf_num = vui_info->max_dec_frame_buffering; + + /* orig_display_region populate */ + if (sps_info->frame_cropping_flag) { + int sub_width_c, sub_height_c, crop_unit_x, crop_unit_y; + int frame_crop_left, frame_crop_right, frame_crop_top, frame_crop_bottom; + + sub_width_c = bspp_h264_get_subwidthc(sps_info->chroma_format_idc, + sps_info->separate_colour_plane_flag); + + sub_height_c = bspp_h264_get_subheightc(sps_info->chroma_format_idc, + sps_info->separate_colour_plane_flag); + + /* equation source: ITU-T H.264 2010/03, page 77 */ + /* ChromaArrayType == 0 */ + if (sps_info->separate_colour_plane_flag || sps_info->chroma_format_idc == 0) { + /* (7-18) */ + crop_unit_x = 1; + /* (7-19) */ + crop_unit_y = 2 - sps_info->frame_mbs_only_flag; + /* ChromaArrayType == chroma_format_idc */ + } else { + /* (7-20) */ + crop_unit_x = sub_width_c; + /* (7-21) */ + crop_unit_y = sub_height_c * (2 - sps_info->frame_mbs_only_flag); + } + + VDEC_ASSERT(sps_info->frame_crop_left_offset <= + (comseq_hdr_info->max_frame_size.width / crop_unit_x) - + (sps_info->frame_crop_right_offset + 1)); + + VDEC_ASSERT(sps_info->frame_crop_top_offset <= + (comseq_hdr_info->max_frame_size.height / crop_unit_y) - + (sps_info->frame_crop_bottom_offset + 1)); + frame_crop_left = crop_unit_x * sps_info->frame_crop_left_offset; + frame_crop_right = comseq_hdr_info->max_frame_size.width - + (crop_unit_x * sps_info->frame_crop_right_offset); + frame_crop_top = crop_unit_y * sps_info->frame_crop_top_offset; + frame_crop_bottom = comseq_hdr_info->max_frame_size.height - + (crop_unit_y * sps_info->frame_crop_bottom_offset); + comseq_hdr_info->orig_display_region.left_offset = (unsigned int)frame_crop_left; + comseq_hdr_info->orig_display_region.top_offset = (unsigned int)frame_crop_top; + comseq_hdr_info->orig_display_region.width = (frame_crop_right - frame_crop_left); + comseq_hdr_info->orig_display_region.height = (frame_crop_bottom - frame_crop_top); + } else { + comseq_hdr_info->orig_display_region.left_offset = 0; + comseq_hdr_info->orig_display_region.top_offset = 0; + comseq_hdr_info->orig_display_region.width = comseq_hdr_info->max_frame_size.width; + comseq_hdr_info->orig_display_region.height = + comseq_hdr_info->max_frame_size.height; + } + +#ifdef REDUCED_DPB_NO_PIC_REORDERING + comseq_hdr_info->max_reorder_picts = vui_info->max_dec_frame_buffering; +#else + if (sps_info->vui_parameters_present_flag && vui_info->bitstream_restriction_flag) + comseq_hdr_info->max_reorder_picts = vui_info->max_dec_frame_buffering; + else + comseq_hdr_info->max_reorder_picts = 0; +#endif + comseq_hdr_info->separate_chroma_planes = + h264_seq_hdr_info->sps_info.separate_colour_plane_flag ? 1 : 0; +} + +static void bspp_h264_pict_hdr_populate(enum h264_nalunittype nal_unit_type, + struct bspp_h264_slice_hdr_info *h264_slice_hdr_info, + struct vdec_comsequ_hdrinfo *comseq_hdr_info, + struct bspp_pict_hdr_info *pict_hdr_info) +{ + /* + * H264 has slice coding type, not picture. The bReference contrary to the rest of the + * standards is set explicitly from the NAL externally (see just below the call to + * bspp_h264_pict_hdr_populate) pict_hdr_info->bReference = ? (Set externally for H264) + */ + pict_hdr_info->intra_coded = (nal_unit_type == H264_NALTYPE_IDR_SLICE) ? 1 : 0; + pict_hdr_info->field = h264_slice_hdr_info->field_pic_flag; + + pict_hdr_info->post_processing = 0; + /* For H264 Maximum and Coded sizes are the same */ + pict_hdr_info->coded_frame_size.width = comseq_hdr_info->max_frame_size.width; + /* For H264 Maximum and Coded sizes are the same */ + pict_hdr_info->coded_frame_size.height = comseq_hdr_info->max_frame_size.height; + /* + * For H264 Encoded Display size has been precomputed as part of the + * common sequence info + */ + pict_hdr_info->disp_info.enc_disp_region = comseq_hdr_info->orig_display_region; + /* + * For H264 there is no resampling, so encoded and actual display + * regions are the same + */ + pict_hdr_info->disp_info.disp_region = comseq_hdr_info->orig_display_region; + /* H264 does not have that */ + pict_hdr_info->disp_info.num_pan_scan_windows = 0; + memset(pict_hdr_info->disp_info.pan_scan_windows, 0, + sizeof(pict_hdr_info->disp_info.pan_scan_windows)); +} + +static int bspp_h264_destroy_seq_hdr_info(const void *secure_sps_info) +{ + struct bspp_h264_seq_hdr_info *h264_seq_hdr_info = NULL; + + if (!secure_sps_info) + return IMG_ERROR_INVALID_PARAMETERS; + + h264_seq_hdr_info = (struct bspp_h264_seq_hdr_info *)secure_sps_info; + + /* Cleaning vui_info */ + kfree(h264_seq_hdr_info->vui_info.nal_hrd_parameters.bit_rate_value_minus1); + kfree(h264_seq_hdr_info->vui_info.nal_hrd_parameters.cpb_size_value_minus1); + kfree(h264_seq_hdr_info->vui_info.nal_hrd_parameters.cbr_flag); + kfree(h264_seq_hdr_info->vui_info.vcl_hrd_parameters.bit_rate_value_minus1); + kfree(h264_seq_hdr_info->vui_info.vcl_hrd_parameters.cpb_size_value_minus1); + kfree(h264_seq_hdr_info->vui_info.vcl_hrd_parameters.cbr_flag); + + /* Cleaning sps_info */ + kfree(h264_seq_hdr_info->sps_info.offset_for_ref_frame); + kfree(h264_seq_hdr_info->sps_info.scllst4x4seq); + kfree(h264_seq_hdr_info->sps_info.scllst8x8seq); + + return 0; +} + +static int bspp_h264_destroy_pps_info(const void *secure_pps_info) +{ + struct bspp_h264_pps_info *h264_pps_info = NULL; + + if (!secure_pps_info) + return IMG_ERROR_INVALID_PARAMETERS; + + h264_pps_info = (struct bspp_h264_pps_info *)secure_pps_info; + kfree(h264_pps_info->h264_ppssgm_info.slice_group_id); + h264_pps_info->h264_ppssgm_info.slicegroupidnum = 0; + kfree(h264_pps_info->scllst4x4pic); + kfree(h264_pps_info->scllst8x8pic); + + return 0; +} + +static int bspp_h264_destroy_data(enum bspp_unit_type data_type, void *data_handle) +{ + int result = 0; + + if (!data_handle) + return IMG_ERROR_INVALID_PARAMETERS; + + switch (data_type) { + case BSPP_UNIT_SEQUENCE: + result = bspp_h264_destroy_seq_hdr_info(data_handle); + break; + case BSPP_UNIT_PPS: + result = bspp_h264_destroy_pps_info(data_handle); + break; + default: + break; + } + return result; +} + +static void bspp_h264_generate_slice_groupmap(struct bspp_h264_slice_hdr_info *h264_slice_hdr_info, + struct bspp_h264_seq_hdr_info *h264_seq_hdr_info, + struct bspp_h264_pps_info *h264_pps_info, + unsigned char *map_unit_to_slice_groupmap, + unsigned int map_size) +{ + int group; + unsigned int num_slice_group_mapunits; + unsigned int i = 0, j, k = 0; + unsigned char num_slice_groups = h264_pps_info->num_slice_groups_minus1 + 1; + unsigned int pic_width_in_mbs = h264_seq_hdr_info->sps_info.pic_width_in_mbs_minus1 + 1; + unsigned int pic_height_in_map_units = + h264_seq_hdr_info->sps_info.pic_height_in_map_units_minus1 + 1; + + num_slice_group_mapunits = map_size; + if (h264_pps_info->slice_group_map_type == 6) { + if ((unsigned int)num_slice_groups != num_slice_group_mapunits) { + VDEC_ASSERT + ("wrong pps->num_slice_group_map_units_minus1 for used SPS and FMO type 6" + == + NULL); + if (num_slice_group_mapunits > + h264_pps_info->h264_ppssgm_info.slicegroupidnum) + num_slice_group_mapunits = + h264_pps_info->h264_ppssgm_info.slicegroupidnum; + } + } + + /* only one slice group */ + if (h264_pps_info->num_slice_groups_minus1 == 0) { + memset(map_unit_to_slice_groupmap, 0, map_size * sizeof(unsigned char)); + return; + } + if (h264_pps_info->num_slice_groups_minus1 >= MAX_SLICEGROUP_COUNT) { + memset(map_unit_to_slice_groupmap, 0, map_size * sizeof(unsigned char)); + return; + } + if (h264_pps_info->slice_group_map_type == 0) { + do { + for (group = + 0; + group <= h264_pps_info->num_slice_groups_minus1 && + i < num_slice_group_mapunits; + i += h264_pps_info->run_length_minus1[group++] + 1) { + for (j = 0; + j <= h264_pps_info->run_length_minus1[group] && + i + j < num_slice_group_mapunits; + j++) + map_unit_to_slice_groupmap[i + j] = group; + } + } while (i < num_slice_group_mapunits); + } else if (h264_pps_info->slice_group_map_type == 1) { + for (i = 0; i < num_slice_group_mapunits; i++) { + map_unit_to_slice_groupmap[i] = ((i % pic_width_in_mbs) + + (((i / pic_width_in_mbs) * + (h264_pps_info->num_slice_groups_minus1 + 1)) / 2)) % + (h264_pps_info->num_slice_groups_minus1 + 1); + } + } else if (h264_pps_info->slice_group_map_type == 2) { + unsigned int y_top_left, x_top_left, y_bottom_right, x_bottom_right, x, y; + + for (i = 0; i < num_slice_group_mapunits; i++) + map_unit_to_slice_groupmap[i] = h264_pps_info->num_slice_groups_minus1; + + for (group = h264_pps_info->num_slice_groups_minus1 - 1; group >= 0; group--) { + y_top_left = h264_pps_info->top_left[group] / pic_width_in_mbs; + x_top_left = h264_pps_info->top_left[group] % pic_width_in_mbs; + y_bottom_right = h264_pps_info->bottom_right[group] / pic_width_in_mbs; + x_bottom_right = h264_pps_info->bottom_right[group] % pic_width_in_mbs; + for (y = y_top_left; y <= y_bottom_right; y++) + for (x = x_top_left; x <= x_bottom_right; x++) { + if (h264_pps_info->top_left[group] > + h264_pps_info->bottom_right[group] || + h264_pps_info->bottom_right[group] >= + num_slice_group_mapunits) + continue; + map_unit_to_slice_groupmap[y * pic_width_in_mbs + + x] = group; + } + } + } else if (h264_pps_info->slice_group_map_type == 3) { + int left_bound, top_bound, right_bound, bottom_bound; + int x, y, x_dir, y_dir; + int map_unit_vacant; + + unsigned int mapunits_in_slicegroup_0 = + umin((unsigned int)((h264_pps_info->slice_group_change_rate_minus1 + 1) * + h264_slice_hdr_info->slice_group_change_cycle), + (unsigned int)num_slice_group_mapunits); + + for (i = 0; i < num_slice_group_mapunits; i++) + map_unit_to_slice_groupmap[i] = 2; + + x = (pic_width_in_mbs - h264_pps_info->slice_group_change_direction_flag) / 2; + y = (pic_height_in_map_units - h264_pps_info->slice_group_change_direction_flag) / + 2; + + left_bound = x; + top_bound = y; + right_bound = x; + bottom_bound = y; + + x_dir = h264_pps_info->slice_group_change_direction_flag - 1; + y_dir = h264_pps_info->slice_group_change_direction_flag; + + for (k = 0; k < num_slice_group_mapunits; k += map_unit_vacant) { + map_unit_vacant = + (map_unit_to_slice_groupmap[y * pic_width_in_mbs + x] == + 2); + if (map_unit_vacant) + map_unit_to_slice_groupmap[y * pic_width_in_mbs + x] = + (k >= mapunits_in_slicegroup_0); + + if (x_dir == -1 && x == left_bound) { + left_bound = smax(left_bound - 1, 0); + x = left_bound; + x_dir = 0; + y_dir = 2 * h264_pps_info->slice_group_change_direction_flag - 1; + } else if (x_dir == 1 && x == right_bound) { + right_bound = smin(right_bound + 1, (int)pic_width_in_mbs - 1); + x = right_bound; + x_dir = 0; + y_dir = 1 - 2 * h264_pps_info->slice_group_change_direction_flag; + } else if (y_dir == -1 && y == top_bound) { + top_bound = smax(top_bound - 1, 0); + y = top_bound; + x_dir = 1 - 2 * h264_pps_info->slice_group_change_direction_flag; + y_dir = 0; + } else if (y_dir == 1 && y == bottom_bound) { + bottom_bound = smin(bottom_bound + 1, + (int)pic_height_in_map_units - 1); + y = bottom_bound; + x_dir = 2 * h264_pps_info->slice_group_change_direction_flag - 1; + y_dir = 0; + } else { + x = x + x_dir; + y = y + y_dir; + } + } + } else if (h264_pps_info->slice_group_map_type == 4) { + unsigned int mapunits_in_slicegroup_0 = + umin((unsigned int)((h264_pps_info->slice_group_change_rate_minus1 + 1) * + h264_slice_hdr_info->slice_group_change_cycle), + (unsigned int)num_slice_group_mapunits); + unsigned int sizeof_upper_left_group = + h264_pps_info->slice_group_change_direction_flag ? + (num_slice_group_mapunits - + mapunits_in_slicegroup_0) : mapunits_in_slicegroup_0; + for (i = 0; i < num_slice_group_mapunits; i++) { + if (i < sizeof_upper_left_group) + map_unit_to_slice_groupmap[i] = + h264_pps_info->slice_group_change_direction_flag; + + else + map_unit_to_slice_groupmap[i] = 1 - + h264_pps_info->slice_group_change_direction_flag; + } + } else if (h264_pps_info->slice_group_map_type == 5) { + unsigned int mapunits_in_slicegroup_0 = + umin((unsigned int)((h264_pps_info->slice_group_change_rate_minus1 + 1) * + h264_slice_hdr_info->slice_group_change_cycle), + (unsigned int)num_slice_group_mapunits); + unsigned int sizeof_upper_left_group = + h264_pps_info->slice_group_change_direction_flag ? + (num_slice_group_mapunits - + mapunits_in_slicegroup_0) : mapunits_in_slicegroup_0; + + for (j = 0; j < (unsigned int)pic_width_in_mbs; j++) { + for (i = 0; i < (unsigned int)pic_height_in_map_units; i++) { + if (k++ < sizeof_upper_left_group) + map_unit_to_slice_groupmap[i * pic_width_in_mbs + j] = + h264_pps_info->slice_group_change_direction_flag; + else + map_unit_to_slice_groupmap[i * pic_width_in_mbs + j] = + 1 - + h264_pps_info->slice_group_change_direction_flag; + } + } + } else if (h264_pps_info->slice_group_map_type == 6) { + VDEC_ASSERT(num_slice_group_mapunits <= + h264_pps_info->h264_ppssgm_info.slicegroupidnum); + for (i = 0; i < num_slice_group_mapunits; i++) + map_unit_to_slice_groupmap[i] = + h264_pps_info->h264_ppssgm_info.slice_group_id[i]; + } +} + +static int bspp_h264_parse_mvc_slice_extension(void *swsr_context, + struct bspp_h264_inter_pict_ctx *inter_pict_ctx) +{ + if (!swsr_read_bits(swsr_context, 1)) { + swsr_read_bits(swsr_context, 7); + inter_pict_ctx->current_view_id = swsr_read_bits(swsr_context, 10); + swsr_read_bits(swsr_context, 6); + return 1; + } + + return 0; +} + +static int bspp_h264_unitparser_compile_sgmdata + (struct bspp_h264_slice_hdr_info *h264_slice_hdr_info, + struct bspp_h264_seq_hdr_info *h264_seq_hdr_info, + struct bspp_h264_pps_info *h264_pps_info, + struct bspp_pict_hdr_info *pict_hdr_info) +{ + memset(&pict_hdr_info->pict_sgm_data, 0, sizeof(*&pict_hdr_info->pict_sgm_data)); + + pict_hdr_info->pict_sgm_data.id = 1; + + /* Allocate memory for SGM. */ + pict_hdr_info->pict_sgm_data.size = + (h264_seq_hdr_info->sps_info.pic_height_in_map_units_minus1 + 1) * + (h264_seq_hdr_info->sps_info.pic_width_in_mbs_minus1 + 1); + + pict_hdr_info->pict_sgm_data.pic_data = kmalloc((pict_hdr_info->pict_sgm_data.size), + GFP_KERNEL); + VDEC_ASSERT(pict_hdr_info->pict_sgm_data.pic_data); + if (!pict_hdr_info->pict_sgm_data.pic_data) { + pict_hdr_info->pict_sgm_data.id = BSPP_INVALID; + return IMG_ERROR_OUT_OF_MEMORY; + } + + bspp_h264_generate_slice_groupmap(h264_slice_hdr_info, h264_seq_hdr_info, h264_pps_info, + pict_hdr_info->pict_sgm_data.pic_data, + pict_hdr_info->pict_sgm_data.size); + + /* check the discontinuous_mbs_flaginCurrFrame flag for FMO */ + /* NO FMO support */ + pict_hdr_info->discontinuous_mbs = 0; + + return 0; +} + +static int bspp_h264_unit_parser(void *swsr_context, struct bspp_unit_data *unit_data) +{ + unsigned int result = 0; + enum bspp_error_type parse_error = BSPP_ERROR_NONE; + enum h264_nalunittype nal_unit_type; + unsigned char nal_ref_idc; + struct bspp_h264_inter_pict_ctx *interpicctx; + struct bspp_sequence_hdr_info *out_seq_info; + unsigned char id; + + interpicctx = &unit_data->parse_state->inter_pict_ctx->h264_ctx; + out_seq_info = unit_data->out.sequ_hdr_info; + + /* At this point we should be EXACTLY at the NALTYPE byte */ + /* parse the nal header type */ + swsr_read_bits(swsr_context, 1); + nal_ref_idc = swsr_read_bits(swsr_context, 2); + nal_unit_type = (enum h264_nalunittype)swsr_read_bits(swsr_context, 5); + + switch (unit_data->unit_type) { + case BSPP_UNIT_SEQUENCE: + VDEC_ASSERT(nal_unit_type == H264_NALTYPE_SEQUENCE_PARAMETER_SET || + nal_unit_type == H264_NALTYPE_SUBSET_SPS); + { + unsigned char id_loc; + /* Parse SPS structure */ + struct bspp_h264_seq_hdr_info *h264_seq_hdr_info = + (struct bspp_h264_seq_hdr_info *)(out_seq_info->secure_sequence_info); + /* FW SPS Data structure */ + struct bspp_ddbuf_array_info *tmp = &out_seq_info->fw_sequence; + struct h264fw_sequence_ps *h264_fwseq_hdr_info = + (struct h264fw_sequence_ps *)((unsigned char *)tmp->ddbuf_info.cpu_virt_addr + + tmp->buf_offset); + /* Common Sequence Header Info */ + struct vdec_comsequ_hdrinfo *comseq_hdr_info = + &out_seq_info->sequ_hdr_info.com_sequ_hdr_info; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("Unit Parser:Found SEQUENCE_PARAMETER_SET NAL unit"); +#endif + VDEC_ASSERT(h264_seq_hdr_info); + VDEC_ASSERT(h264_fwseq_hdr_info); + if (!h264_seq_hdr_info) + return IMG_ERROR_ALREADY_COMPLETE; + + if (!h264_fwseq_hdr_info) + return IMG_ERROR_ALREADY_COMPLETE; + + /* Call SPS parser to populate the "Parse SPS Structure" */ + unit_data->parse_error |= + bspp_h264_sps_parser(swsr_context, unit_data->str_res_handle, + h264_seq_hdr_info); + /* From "Parse SPS Structure" populate the "FW SPS Data Structure" */ + bspp_h264_fwseq_hdr_populate( + h264_seq_hdr_info, h264_fwseq_hdr_info, + unit_data->max_dec_frame_buffering); + /* + * From "Parse SPS Structure" populate the + * "Common Sequence Header Info" + */ + bspp_h264_commonseq_hdr_populate(h264_seq_hdr_info, comseq_hdr_info); + /* Set the SPS ID */ + /* + * seq_parameter_set_id is always in range 0-31, so we can + * add offset indicating subsequence header + */ + id_loc = h264_seq_hdr_info->sps_info.seq_parameter_set_id; + out_seq_info->sequ_hdr_info.sequ_hdr_id = + (nal_unit_type == H264_NALTYPE_SLICE_SCALABLE || + nal_unit_type == H264_NALTYPE_SLICE_IDR_SCALABLE || + nal_unit_type == H264_NALTYPE_SUBSET_SPS) ? id_loc + 32 : id_loc; + + /* + * Set the first SPS ID as Active SPS ID for SEI parsing + * to cover the case of not having SeiBufferingPeriod to + * give us the SPS ID + */ + if (interpicctx->active_sps_for_sei_parsing == BSPP_INVALID) + interpicctx->active_sps_for_sei_parsing = + h264_seq_hdr_info->sps_info.seq_parameter_set_id; + } + break; + + case BSPP_UNIT_PPS: + VDEC_ASSERT(nal_unit_type == H264_NALTYPE_PICTURE_PARAMETER_SET); + { + /* Parse PPS structure */ + struct bspp_h264_pps_info *h264_pps_info = + (struct bspp_h264_pps_info *)(unit_data->out.pps_info->secure_pps_info); + /* FW PPS Data structure */ + struct bspp_ddbuf_array_info *tmp = &unit_data->out.pps_info->fw_pps; + struct h264fw_picture_ps *h264fw_pps_info = + (struct h264fw_picture_ps *)((unsigned char *) + tmp->ddbuf_info.cpu_virt_addr + tmp->buf_offset); + +#ifdef DEBUG_DECODER_DRIVER + pr_info("Unit Parser:Found PICTURE_PARAMETER_SET NAL unit"); +#endif + VDEC_ASSERT(h264_pps_info); + VDEC_ASSERT(h264fw_pps_info); + + /* Call PPS parser to populate the "Parse PPS Structure" */ + unit_data->parse_error |= + bspp_h264_pps_parser(swsr_context, unit_data->str_res_handle, + h264_pps_info); + /* From "Parse PPS Structure" populate the "FW PPS Data Structure" + * - the scaling lists + */ + bspp_h264_fwpps_populate(h264_pps_info, h264fw_pps_info); + /* Set the PPS ID */ + unit_data->out.pps_info->pps_id = h264_pps_info->pps_id; + } + break; + + case BSPP_UNIT_PICTURE: + if (nal_unit_type == H264_NALTYPE_SLICE_PREFIX) { + if (bspp_h264_parse_mvc_slice_extension(swsr_context, interpicctx)) + pr_err("%s: No MVC support\n", __func__); + } else if (nal_unit_type == H264_NALTYPE_SLICE_SCALABLE || + nal_unit_type == H264_NALTYPE_SLICE_IDR_SCALABLE || + nal_unit_type == H264_NALTYPE_SLICE || + nal_unit_type == H264_NALTYPE_IDR_SLICE) { + struct bspp_h264_slice_hdr_info h264_slice_hdr_info; + struct bspp_h264_pps_info *h264_pps_info; + struct bspp_pps_info *pps_info; + struct h264fw_picture_ps *h264fw_pps_info; + struct h264fw_sequence_ps *h264_fwseq_hdr_info; + struct bspp_h264_seq_hdr_info *h264_seq_hdr_info; + struct bspp_sequence_hdr_info *sequ_hdr_info; + struct bspp_ddbuf_array_info *tmp1; + struct bspp_ddbuf_array_info *tmp2; + int current_pic_is_new = 0; + int determined = 0; + int id_loc; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("Unit Parser:Found PICTURE DATA unit"); +#endif + + unit_data->slice = 1; + unit_data->ext_slice = 0; + + if (nal_unit_type == H264_NALTYPE_SLICE_SCALABLE || + nal_unit_type == H264_NALTYPE_SLICE_IDR_SCALABLE) { + pr_err("%s: No SVC support\n", __func__); + } + + VDEC_ASSERT(unit_data->out.pict_hdr_info); + if (!unit_data->out.pict_hdr_info) + return IMG_ERROR_CANCELLED; + + /* Default */ + unit_data->out.pict_hdr_info->discontinuous_mbs = 0; + + /* + * Parse the Pic Header, return Parse SPS/PPS + * structures + */ + parse_error = bspp_h264_pict_hdr_parser(swsr_context, + unit_data->str_res_handle, + &h264_slice_hdr_info, + &pps_info, + &sequ_hdr_info, + nal_unit_type, + nal_ref_idc); + + if (parse_error) { + unit_data->parse_error |= parse_error; + return IMG_ERROR_CANCELLED; + } + + /* + * We are signalling closed GOP at every I frame + * This does not conform 100% with the + * specification but insures that seeking always + * works. + */ + unit_data->new_closed_gop = h264_slice_hdr_info.slice_type == + I_SLICE ? 1 : 0; + + /* + * Now pps_info and sequ_hdr_info contain the + * PPS/SPS info related to this picture + */ + h264_pps_info = (struct bspp_h264_pps_info *)pps_info->secure_pps_info; + h264_seq_hdr_info = + (struct bspp_h264_seq_hdr_info *)sequ_hdr_info->secure_sequence_info; + + tmp1 = &pps_info->fw_pps; + tmp2 = &sequ_hdr_info->fw_sequence; + + h264fw_pps_info = (struct h264fw_picture_ps *)((unsigned char *) + tmp1->ddbuf_info.cpu_virt_addr + tmp1->buf_offset); + h264_fwseq_hdr_info = (struct h264fw_sequence_ps *)((unsigned char *) + tmp2->ddbuf_info.cpu_virt_addr + tmp2->buf_offset); + VDEC_ASSERT(h264_slice_hdr_info.pps_id == h264_pps_info->pps_id); + VDEC_ASSERT(h264_pps_info->seq_parameter_set_id == + (unsigned int)h264_seq_hdr_info->sps_info.seq_parameter_set_id); + + /* + * Update the decoding-related FW SPS info related to the current picture + * with the SEI data that were potentially received and also relate to + * the current info. Until we receive the picture we do not know which + * sequence to update with the SEI data. + * Setfrom last SEI, needed for decoding + */ + h264_fwseq_hdr_info->disable_vdmc_filt = interpicctx->disable_vdmc_filt; + h264_fwseq_hdr_info->transform4x4_mb_not_available = + interpicctx->b4x4transform_mb_unavailable; + + /* + * Determine if current slice is a new picture, and update the related + * params for future reference + * Order of checks is important + */ + { + struct bspp_parse_state *state = unit_data->parse_state; + + set_if_not_determined_yet(&determined, state->new_view, + ¤t_pic_is_new, 1); + set_if_not_determined_yet(&determined, state->next_pic_is_new, + ¤t_pic_is_new, 1); + set_if_not_determined_yet + (&determined, + (h264_slice_hdr_info.redundant_pic_cnt > 0), + ¤t_pic_is_new, 0); + set_if_not_determined_yet + (&determined, + (state->prev_frame_num != + h264_slice_hdr_info.frame_num), + ¤t_pic_is_new, 1); + set_if_not_determined_yet + (&determined, + (state->prev_pps_id != h264_slice_hdr_info.pps_id), + ¤t_pic_is_new, 1); + set_if_not_determined_yet + (&determined, + (state->prev_field_pic_flag != + h264_slice_hdr_info.field_pic_flag), + ¤t_pic_is_new, 1); + set_if_not_determined_yet + (&determined, + ((h264_slice_hdr_info.field_pic_flag) && + (state->prev_bottom_pic_flag != + h264_slice_hdr_info.bottom_field_flag)), + ¤t_pic_is_new, 1); + set_if_not_determined_yet + (&determined, + ((state->prev_nal_ref_idc == 0 || nal_ref_idc == 0) && + (state->prev_nal_ref_idc != nal_ref_idc)), + ¤t_pic_is_new, 1); + set_if_not_determined_yet + (&determined, + ((h264_seq_hdr_info->sps_info.pic_order_cnt_type == 0) && + ((state->prev_pic_order_cnt_lsb != + h264_slice_hdr_info.pic_order_cnt_lsb) || + (state->prev_delta_pic_order_cnt_bottom != + h264_slice_hdr_info.delta_pic_order_cnt_bottom))), + ¤t_pic_is_new, 1); + set_if_not_determined_yet + (&determined, + ((h264_seq_hdr_info->sps_info.pic_order_cnt_type == 1) && + ((state->prev_delta_pic_order_cnt[0] != + h264_slice_hdr_info.delta_pic_order_cnt[0]) || + (state->prev_delta_pic_order_cnt[1] != + h264_slice_hdr_info.delta_pic_order_cnt[1]))), + ¤t_pic_is_new, 1); + set_if_not_determined_yet + (&determined, + ((state->prev_nal_unit_type == + (int)H264_NALTYPE_IDR_SLICE || + nal_unit_type == (int)H264_NALTYPE_IDR_SLICE) && + (state->prev_nal_unit_type != + (int)nal_unit_type)), + ¤t_pic_is_new, 1); + set_if_not_determined_yet(&determined, + ((state->prev_nal_unit_type == + (int)H264_NALTYPE_IDR_SLICE) && + (state->prev_idr_pic_id != + h264_slice_hdr_info.idr_pic_id)), + ¤t_pic_is_new, 1); + + /* + * Update whatever is not updated already in different places of + * the code or just needs to be updated here + */ + state->prev_frame_num = h264_slice_hdr_info.frame_num; + state->prev_pps_id = h264_slice_hdr_info.pps_id; + state->prev_field_pic_flag = + h264_slice_hdr_info.field_pic_flag; + state->prev_nal_ref_idc = nal_ref_idc; + state->prev_pic_order_cnt_lsb = + h264_slice_hdr_info.pic_order_cnt_lsb; + state->prev_delta_pic_order_cnt_bottom = + h264_slice_hdr_info.delta_pic_order_cnt_bottom; + state->prev_delta_pic_order_cnt[0] = + h264_slice_hdr_info.delta_pic_order_cnt[0]; + state->prev_delta_pic_order_cnt[1] = + h264_slice_hdr_info.delta_pic_order_cnt[1]; + state->prev_nal_unit_type = (int)nal_unit_type; + state->prev_idr_pic_id = h264_slice_hdr_info.idr_pic_id; + } + + /* Detect second field and manage the prev_bottom_pic_flag flag */ + if (h264_slice_hdr_info.field_pic_flag && current_pic_is_new) { + unit_data->parse_state->prev_bottom_pic_flag = + h264_slice_hdr_info.bottom_field_flag; + } + + /* Detect ASO Just met new pic */ + id = h264_slice_hdr_info.colour_plane_id; + if (current_pic_is_new) { + unsigned int i; + + for (i = 0; i < MAX_COMPONENTS; i++) + unit_data->parse_state->prev_first_mb_in_slice[i] = 0; + } else if (unit_data->parse_state->prev_first_mb_in_slice[id] > + h264_slice_hdr_info.first_mb_in_slice) { + /* We just found ASO */ + unit_data->parse_state->discontinuous_mb = 1; + } + unit_data->parse_state->prev_first_mb_in_slice[id] = + h264_slice_hdr_info.first_mb_in_slice; + + /* We may already knew we were DiscontinuousMB */ + if (unit_data->parse_state->discontinuous_mb) + unit_data->out.pict_hdr_info->discontinuous_mbs = + unit_data->parse_state->discontinuous_mb; + + /* + * We want to calculate the scaling lists only once per picture/field, + * not every slice We want to populate the VDEC Picture Header Info + * only once per picture/field, not every slice + */ + if (current_pic_is_new) { + /* Common Sequence Header Info fetched */ + struct vdec_comsequ_hdrinfo *comseq_hdr_info = + &sequ_hdr_info->sequ_hdr_info.com_sequ_hdr_info; + struct bspp_pict_data *type_pict_aux_data; + + unit_data->parse_state->next_pic_is_new = 0; + + /* Generate SGM for this picture */ + if (h264_pps_info->num_slice_groups_minus1 != 0 && + h264_pps_info->slice_group_map_type <= 6) { + bspp_h264_unitparser_compile_sgmdata + (&h264_slice_hdr_info, + h264_seq_hdr_info, + h264_pps_info, + unit_data->out.pict_hdr_info); + } else { + unit_data->out.pict_hdr_info->pict_sgm_data.pic_data = NULL; + unit_data->out.pict_hdr_info->pict_sgm_data.bufmap_id = 0; + unit_data->out.pict_hdr_info->pict_sgm_data.buf_offset = 0; + unit_data->out.pict_hdr_info->pict_sgm_data.id = + BSPP_INVALID; + unit_data->out.pict_hdr_info->pict_sgm_data.size = 0; + } + + unit_data->parse_state->discontinuous_mb = + unit_data->out.pict_hdr_info->discontinuous_mbs; + + /* + * Select the scaling lists based on h264_pps_info and + * h264_seq_hdr_info and pass them to h264fw_pps_info + */ + bspp_h264_select_scaling_list(h264fw_pps_info, + h264_pps_info, + h264_seq_hdr_info); + + /* + * Uses the common sequence/SINGLE-slice info to populate the + * VDEC Picture Header Info + */ + bspp_h264_pict_hdr_populate(nal_unit_type, &h264_slice_hdr_info, + comseq_hdr_info, + unit_data->out.pict_hdr_info); + + /* Store some raw bitstream fields for output. */ + unit_data->out.pict_hdr_info->h264_pict_hdr_info.frame_num = + h264_slice_hdr_info.frame_num; + unit_data->out.pict_hdr_info->h264_pict_hdr_info.nal_ref_idc = + nal_ref_idc; + + /* + * Update the display-related picture header information with + * the related SEI parsed data The display-related SEI is + * used only for the first picture after the SEI + */ + if (!interpicctx->sei_info_attached_to_pic) { + interpicctx->sei_info_attached_to_pic = 1; + if (interpicctx->active_sps_for_sei_parsing != + h264_seq_hdr_info->sps_info.seq_parameter_set_id) { + /* + * We tried to guess the SPS ID that we should use + * to parse the SEI, but we guessed wrong + */ + pr_err("Parsed SEI with wrong SPS, data may be parsed wrong"); + } + unit_data->out.pict_hdr_info->disp_info.repeat_first_fld = + interpicctx->repeat_first_field; + unit_data->out.pict_hdr_info->disp_info.max_frm_repeat = + interpicctx->max_frm_repeat; + /* SEI - Not supported */ + } + + /* + * For Idr slices update the Active + * Sequence ID for SEI parsing, + * error resilient + */ + if (nal_unit_type == H264_NALTYPE_IDR_SLICE) + interpicctx->active_sps_for_sei_parsing = + h264_seq_hdr_info->sps_info.seq_parameter_set_id; + + /* + * Choose the appropriate auxiliary data + * structure to populate. + */ + if (unit_data->parse_state->second_field_flag) + type_pict_aux_data = + &unit_data->out.pict_hdr_info->second_pict_aux_data; + + else + type_pict_aux_data = + &unit_data->out.pict_hdr_info->pict_aux_data; + + /* + * We have no container for the PPS that + * passes down to the kernel, for this + * reason the h264 secure parser needs + * to populate that info into the + * picture header (Second)PictAuxData. + */ + type_pict_aux_data->bufmap_id = pps_info->bufmap_id; + type_pict_aux_data->buf_offset = pps_info->buf_offset; + type_pict_aux_data->pic_data = (void *)h264fw_pps_info; + type_pict_aux_data->id = h264_pps_info->pps_id; + type_pict_aux_data->size = sizeof(struct h264fw_picture_ps); + + pps_info->ref_count++; + + /* This info comes from NAL directly */ + unit_data->out.pict_hdr_info->ref = (nal_ref_idc == 0) ? 0 : 1; + } + if (nal_unit_type == H264_NALTYPE_IDR_SLICE) + unit_data->new_closed_gop = 1; + + /* Return the SPS ID */ + /* + * seq_parameter_set_id is always in range 0-31, + * so we can add offset indicating subsequence header + */ + id_loc = h264_pps_info->seq_parameter_set_id; + unit_data->pict_sequ_hdr_id = + (nal_unit_type == H264_NALTYPE_SLICE_SCALABLE || + nal_unit_type == + H264_NALTYPE_SLICE_IDR_SCALABLE) ? id_loc + 32 : id_loc; + + } else if (nal_unit_type == H264_NALTYPE_SLICE_PARTITION_A || + nal_unit_type == H264_NALTYPE_SLICE_PARTITION_B || + nal_unit_type == H264_NALTYPE_SLICE_PARTITION_C) { + unit_data->slice = 1; + + pr_err("Unsupported Slice NAL type: %d", nal_unit_type); + unit_data->parse_error = BSPP_ERROR_UNSUPPORTED; + } + break; + + case BSPP_UNIT_UNCLASSIFIED: + if (nal_unit_type == H264_NALTYPE_ACCESS_UNIT_DELIMITER) { + unit_data->parse_state->next_pic_is_new = 1; + } else if (nal_unit_type == H264_NALTYPE_SLICE_PREFIX || + nal_unit_type == H264_NALTYPE_SUBSET_SPS) { + /* if mvc disabled do nothing */ + } else { + /* Should not have any other type of unclassified data. */ + pr_err("unclassified data detected!\n"); + } + break; + + case BSPP_UNIT_NON_PICTURE: + if (nal_unit_type == H264_NALTYPE_END_OF_SEQUENCE || + nal_unit_type == H264_NALTYPE_END_OF_STREAM) { + unit_data->parse_state->next_pic_is_new = 1; + } else if (nal_unit_type == H264_NALTYPE_FILLER_DATA || + nal_unit_type == H264_NALTYPE_SEQUENCE_PARAMETER_SET_EXTENSION || + nal_unit_type == H264_NALTYPE_AUXILIARY_SLICE) { + } else if (nal_unit_type == H264_NALTYPE_SLICE_SCALABLE || + nal_unit_type == H264_NALTYPE_SLICE_IDR_SCALABLE) { + /* if mvc disabled do nothing */ + } else { + /* Should not have any other type of non-picture data. */ + VDEC_ASSERT(0); + } + break; + + case BSPP_UNIT_UNSUPPORTED: + pr_err("Unsupported NAL type: %d", nal_unit_type); + unit_data->parse_error = BSPP_ERROR_UNKNOWN_DATAUNIT_DETECTED; + break; + + default: + VDEC_ASSERT(0); + break; + } + + return result; +} + +static int bspp_h264releasedata(void *str_alloc, enum bspp_unit_type data_type, void *data_handle) +{ + int result = 0; + + if (!data_handle) + return IMG_ERROR_INVALID_PARAMETERS; + + switch (data_type) { + case BSPP_UNIT_SEQUENCE: + result = bspp_h264_release_sequ_hdr_info(str_alloc, data_handle); + break; + default: + break; + } + + return result; +} + +static int bspp_h264resetdata(enum bspp_unit_type data_type, void *data_handle) +{ + int result = 0; + + if (!data_handle) + return IMG_ERROR_INVALID_PARAMETERS; + + switch (data_type) { + case BSPP_UNIT_SEQUENCE: + result = bspp_h264_reset_seq_hdr_info(data_handle); + break; + case BSPP_UNIT_PPS: + result = bspp_h264_reset_pps_info(data_handle); + break; + default: + break; + } + + return result; +} + +static void bspp_h264parse_codecconfig(void *swsr_ctx, + unsigned int *unitcount, + unsigned int *unit_arraycount, + unsigned int *delimlength, + unsigned int *size_delimlength) +{ + unsigned long long value = 6; + + /* + * Set the shift-register up to provide next 6 bytes + * without emulation prevention detection. + */ + swsr_consume_delim(swsr_ctx, SWSR_EMPREVENT_NONE, 0, &value); + + /* + * Codec config header must be read for size delimited data (H.264) + * to get to the start of each unit. + * This parsing follows section 5.2.4.1.1 of ISO/IEC 14496-15:2004(E). + */ + /* Configuration version. */ + swsr_read_bits(swsr_ctx, 8); + /* AVC Profile Indication. */ + swsr_read_bits(swsr_ctx, 8); + /* Profile compatibility. */ + swsr_read_bits(swsr_ctx, 8); + /* AVC Level Indication. */ + swsr_read_bits(swsr_ctx, 8); + *delimlength = ((swsr_read_bits(swsr_ctx, 8) & 0x3) + 1) * 8; + *unitcount = swsr_read_bits(swsr_ctx, 8) & 0x1f; + + /* Size delimiter is only 2 bytes for H.264 codec configuration. */ + *size_delimlength = 2 * 8; +} + +static void bspp_h264update_unitcounts(void *swsr_ctx, + unsigned int *unitcount, + unsigned int *unit_arraycount) +{ + if (*unitcount == 0) { + unsigned long long value = 1; + + /* + * Set the shift-register up to provide next 1 byte without + * emulation prevention detection. + */ + swsr_consume_delim(swsr_ctx, SWSR_EMPREVENT_NONE, 0, &value); + + *unitcount = swsr_read_bits(swsr_ctx, 8); + } + + (*unitcount)--; +} + +/* + * Sets the parser configuration + */ +int bspp_h264_set_parser_config(enum vdec_bstr_format bstr_format, + struct bspp_vid_std_features *pvidstd_features, + struct bspp_swsr_ctx *pswsr_ctx, + struct bspp_parser_callbacks *pparser_callbacks, + struct bspp_inter_pict_data *pinterpict_data) +{ + /* Set h.246 parser callbacks. */ + pparser_callbacks->parse_unit_cb = bspp_h264_unit_parser; + pparser_callbacks->release_data_cb = bspp_h264releasedata; + pparser_callbacks->reset_data_cb = bspp_h264resetdata; + pparser_callbacks->destroy_data_cb = bspp_h264_destroy_data; + pparser_callbacks->parse_codec_config_cb = bspp_h264parse_codecconfig; + pparser_callbacks->update_unit_counts_cb = bspp_h264update_unitcounts; + + /* Set h.246 specific features. */ + pvidstd_features->seq_size = sizeof(struct bspp_h264_seq_hdr_info); + pvidstd_features->uses_pps = 1; + pvidstd_features->pps_size = sizeof(struct bspp_h264_pps_info); + + /* Set h.246 specific shift register config. */ + pswsr_ctx->emulation_prevention = SWSR_EMPREVENT_00000300; + pinterpict_data->h264_ctx.active_sps_for_sei_parsing = BSPP_INVALID; + + if (bstr_format == VDEC_BSTRFORMAT_DEMUX_BYTESTREAM || + bstr_format == VDEC_BSTRFORMAT_ELEMENTARY) { + pswsr_ctx->sr_config.delim_type = SWSR_DELIM_SCP; + pswsr_ctx->sr_config.delim_length = 3 * 8; + pswsr_ctx->sr_config.scp_value = 0x000001; + } else if (bstr_format == VDEC_BSTRFORMAT_DEMUX_SIZEDELIMITED) { + pswsr_ctx->sr_config.delim_type = SWSR_DELIM_SIZE; + /* Set the default size-delimiter number of bits */ + pswsr_ctx->sr_config.delim_length = 4 * 8; + } else { + VDEC_ASSERT(0); + return IMG_ERROR_NOT_SUPPORTED; + } + + return 0; +} + +/* + * This function determines the BSPP unit type based on the + * provided bitstream (H264 specific) unit type + */ +void bspp_h264_determine_unittype(unsigned char bitstream_unittype, + int disable_mvc, + enum bspp_unit_type *bspp_unittype) +{ + unsigned char type = bitstream_unittype & 0x1f; + + switch (type) { + case H264_NALTYPE_SLICE_PREFIX: + *bspp_unittype = disable_mvc ? BSPP_UNIT_UNCLASSIFIED : BSPP_UNIT_PICTURE; + break; + case H264_NALTYPE_SUBSET_SPS: + *bspp_unittype = disable_mvc ? BSPP_UNIT_UNCLASSIFIED : BSPP_UNIT_SEQUENCE; + break; + case H264_NALTYPE_SLICE_SCALABLE: + case H264_NALTYPE_SLICE_IDR_SCALABLE: + *bspp_unittype = disable_mvc ? BSPP_UNIT_NON_PICTURE : BSPP_UNIT_PICTURE; + break; + case H264_NALTYPE_SEQUENCE_PARAMETER_SET: + *bspp_unittype = BSPP_UNIT_SEQUENCE; + break; + case H264_NALTYPE_PICTURE_PARAMETER_SET: + *bspp_unittype = BSPP_UNIT_PPS; + break; + case H264_NALTYPE_SLICE: + case H264_NALTYPE_SLICE_PARTITION_A: + case H264_NALTYPE_SLICE_PARTITION_B: + case H264_NALTYPE_SLICE_PARTITION_C: + case H264_NALTYPE_IDR_SLICE: + *bspp_unittype = BSPP_UNIT_PICTURE; + break; + case H264_NALTYPE_ACCESS_UNIT_DELIMITER: + case H264_NALTYPE_SUPPLEMENTAL_ENHANCEMENT_INFO: + /* + * Each of these NAL units should not change unit type if + * current is picture, since they can occur anywhere, any number + * of times + */ + *bspp_unittype = BSPP_UNIT_UNCLASSIFIED; + break; + case H264_NALTYPE_END_OF_SEQUENCE: + case H264_NALTYPE_END_OF_STREAM: + case H264_NALTYPE_FILLER_DATA: + case H264_NALTYPE_SEQUENCE_PARAMETER_SET_EXTENSION: + case H264_NALTYPE_AUXILIARY_SLICE: + *bspp_unittype = BSPP_UNIT_NON_PICTURE; + break; + default: + *bspp_unittype = BSPP_UNIT_UNSUPPORTED; + break; + } +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/h264_secure_parser.h b/drivers/media/platform/imagination/vxe-vxd/decoder/h264_secure_parser.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/h264_secure_parser.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/h264_secure_parser.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,278 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * h.264 secure data unit parsing API. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * Re-written for upstreming + * Prashanth Kumar Amai + * Sidraya Jayagond + */ +#ifndef __H264SECUREPARSER_H__ +#define __H264SECUREPARSER_H__ + +#include "bspp_int.h" +#include "vdec_defs.h" + +/* + * enum h264_nalunittype + * @Description Contains H264 NAL unit types + */ +enum h264_nalunittype { + H264_NALTYPE_UNSPECIFIED = 0, + H264_NALTYPE_SLICE = 1, + H264_NALTYPE_SLICE_PARTITION_A = 2, + H264_NALTYPE_SLICE_PARTITION_B = 3, + H264_NALTYPE_SLICE_PARTITION_C = 4, + H264_NALTYPE_IDR_SLICE = 5, + H264_NALTYPE_SUPPLEMENTAL_ENHANCEMENT_INFO = 6, + H264_NALTYPE_SEQUENCE_PARAMETER_SET = 7, + H264_NALTYPE_PICTURE_PARAMETER_SET = 8, + H264_NALTYPE_ACCESS_UNIT_DELIMITER = 9, + H264_NALTYPE_END_OF_SEQUENCE = 10, + H264_NALTYPE_END_OF_STREAM = 11, + H264_NALTYPE_FILLER_DATA = 12, + H264_NALTYPE_SEQUENCE_PARAMETER_SET_EXTENSION = 13, + H264_NALTYPE_SLICE_PREFIX = 14, + H264_NALTYPE_SUBSET_SPS = 15, + H264_NALTYPE_AUXILIARY_SLICE = 19, + H264_NALTYPE_SLICE_SCALABLE = 20, + H264_NALTYPE_SLICE_IDR_SCALABLE = 21, + H264_NALTYPE_MAX = 31, + H264_NALTYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * struct bspp_h264_sps_info + * @Description H264 SPS parsed information + */ +struct bspp_h264_sps_info { + unsigned int profile_idc; + unsigned int constraint_set_flags; + unsigned int level_idc; + unsigned char seq_parameter_set_id; + unsigned char chroma_format_idc; + int separate_colour_plane_flag; + unsigned int bit_depth_luma_minus8; + unsigned int bit_depth_chroma_minus8; + unsigned char qpprime_y_zero_transform_bypass_flag; + int seq_scaling_matrix_present_flag; + unsigned char seq_scaling_list_present_flag[12]; + unsigned int log2_max_frame_num_minus4; + unsigned int pic_order_cnt_type; + unsigned int log2_max_pic_order_cnt_lsb_minus4; + int delta_pic_order_always_zero_flag; + int offset_for_non_ref_pic; + int offset_for_top_to_bottom_field; + unsigned int num_ref_frames_in_pic_order_cnt_cycle; + unsigned int *offset_for_ref_frame; + unsigned int max_num_ref_frames; + int gaps_in_frame_num_value_allowed_flag; + unsigned int pic_width_in_mbs_minus1; + unsigned int pic_height_in_map_units_minus1; + int frame_mbs_only_flag; + int mb_adaptive_frame_field_flag; + int direct_8x8_inference_flag; + int frame_cropping_flag; + unsigned int frame_crop_left_offset; + unsigned int frame_crop_right_offset; + unsigned int frame_crop_top_offset; + unsigned int frame_crop_bottom_offset; + int vui_parameters_present_flag; + /* mvc_vui_parameters_present_flag; UNUSED */ + int bmvcvuiparameterpresentflag; + /* + * scaling lists are derived from both SPS and PPS information + * but will change whenever the PPS changes + * The derived set of tables are associated here with the PPS + * NB: These are in H.264 order + */ + /* derived from SPS and PPS - 8 bit each */ + unsigned char *scllst4x4seq; + /* derived from SPS and PPS - 8 bit each */ + unsigned char *scllst8x8seq; + /* This is not direct parsed data, though it is extracted */ + unsigned char usedefaultscalingmatrixflag_seq[12]; +}; + +struct bspp_h264_hrdparam_info { + unsigned char cpb_cnt_minus1; + unsigned char bit_rate_scale; + unsigned char cpb_size_scale; + unsigned int *bit_rate_value_minus1; + unsigned int *cpb_size_value_minus1; + unsigned char *cbr_flag; + unsigned char initial_cpb_removal_delay_length_minus1; + unsigned char cpb_removal_delay_length_minus1; + unsigned char dpb_output_delay_length_minus1; + unsigned char time_offset_length; +}; + +struct bspp_h264_vui_info { + unsigned char aspect_ratio_info_present_flag; + unsigned int aspect_ratio_idc; + unsigned int sar_width; + unsigned int sar_height; + unsigned char overscan_info_present_flag; + unsigned char overscan_appropriate_flag; + unsigned char video_signal_type_present_flag; + unsigned int video_format; + unsigned char video_full_range_flag; + unsigned char colour_description_present_flag; + unsigned int colour_primaries; + unsigned int transfer_characteristics; + unsigned int matrix_coefficients; + unsigned char chroma_location_info_present_flag; + unsigned int chroma_sample_loc_type_top_field; + unsigned int chroma_sample_loc_type_bottom_field; + unsigned char timing_info_present_flag; + unsigned int num_units_in_tick; + unsigned int time_scale; + unsigned char fixed_frame_rate_flag; + unsigned char nal_hrd_parameters_present_flag; + struct bspp_h264_hrdparam_info nal_hrd_parameters; + unsigned char vcl_hrd_parameters_present_flag; + struct bspp_h264_hrdparam_info vcl_hrd_parameters; + unsigned char low_delay_hrd_flag; + unsigned char pic_struct_present_flag; + unsigned char bitstream_restriction_flag; + unsigned char motion_vectors_over_pic_boundaries_flag; + unsigned int max_bytes_per_pic_denom; + unsigned int max_bits_per_mb_denom; + unsigned int log2_max_mv_length_vertical; + unsigned int log2_max_mv_length_horizontal; + unsigned int num_reorder_frames; + unsigned int max_dec_frame_buffering; +}; + +/* + * struct bspp_h264_seq_hdr_info + * @Description Contains everything parsed from the Sequence Header. + */ +struct bspp_h264_seq_hdr_info { + /* Video sequence header information */ + struct bspp_h264_sps_info sps_info; + /* VUI sequence header information. */ + struct bspp_h264_vui_info vui_info; +}; + +/** + * struct bspp_h264_ppssgm_info - This structure contains H264 PPS parse data. + * @slice_group_id: slice_group_id + * @slicegroupidnum: slicegroupidnum + */ +struct bspp_h264_ppssgm_info { + unsigned char *slice_group_id; + unsigned short slicegroupidnum; +}; + +/* + * struct bspp_h264_pps_info + * @Description This structure contains H264 PPS parse data. + */ +struct bspp_h264_pps_info { + /* pic_parameter_set_id: defines the PPS ID of the current PPS */ + int pps_id; + /* seq_parameter_set_id: defines the SPS that current PPS points to */ + int seq_parameter_set_id; + int entropy_coding_mode_flag; + int pic_order_present_flag; + unsigned char num_slice_groups_minus1; + unsigned char slice_group_map_type; + unsigned short run_length_minus1[8]; + unsigned short top_left[8]; + unsigned short bottom_right[8]; + int slice_group_change_direction_flag; + unsigned short slice_group_change_rate_minus1; + unsigned short pic_size_in_map_unit; + struct bspp_h264_ppssgm_info h264_ppssgm_info; + unsigned char num_ref_idx_lx_active_minus1[H264FW_MAX_REFPIC_LISTS]; + int weighted_pred_flag; + unsigned char weighted_bipred_idc; + int pic_init_qp_minus26; + int pic_init_qs_minus26; + int chroma_qp_index_offset; + int deblocking_filter_control_present_flag; + int constrained_intra_pred_flag; + int redundant_pic_cnt_present_flag; + int transform_8x8_mode_flag; + int pic_scaling_matrix_present_flag; + unsigned char pic_scaling_list_present_flag[12]; + int second_chroma_qp_index_offset; + + /* + * scaling lists are derived from both SPS and PPS information + * but will change whenever the PPS changes + * The derived set of tables are associated here with the PPS + * NB: These are in H.264 order + */ + /* derived from SPS and PPS - 8 bit each */ + unsigned char *scllst4x4pic; + /* derived from SPS and PPS - 8 bit each */ + unsigned char *scllst8x8pic; + /* This is not direct parsed data, though it is extracted */ + unsigned char usedefaultscalingmatrixflag_pic[12]; +}; + +/* + * enum bspp_h264_slice_type + * @Description contains H264 slice types + */ +enum bspp_h264_slice_type { + P_SLICE = 0, + B_SLICE, + I_SLICE, + SP_SLICE, + SI_SLICE, + SLICE_TYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * struct bspp_h264_slice_hdr_info + * @Description This structure contains H264 slice header information + */ +struct bspp_h264_slice_hdr_info { + unsigned short first_mb_in_slice; + enum bspp_h264_slice_type slice_type; + + /* data to ID new picture */ + unsigned int pps_id; + unsigned int frame_num; + unsigned char colour_plane_id; + unsigned char field_pic_flag; + unsigned char bottom_field_flag; + unsigned int idr_pic_id; + unsigned int pic_order_cnt_lsb; + int delta_pic_order_cnt_bottom; + int delta_pic_order_cnt[2]; + unsigned int redundant_pic_cnt; + + /* Things we need to read out when doing In Secure */ + unsigned char num_ref_idx_active_override_flag; + unsigned char num_ref_idx_lx_active_minus1[2]; + unsigned short slice_group_change_cycle; +}; + +/* + * @Function bspp_h264_set_parser_config + * @Description Sets the parser configuration + */ +int bspp_h264_set_parser_config(enum vdec_bstr_format bstr_format, + struct bspp_vid_std_features *pvidstd_features, + struct bspp_swsr_ctx *pswsr_ctx, + struct bspp_parser_callbacks *pparser_callbacks, + struct bspp_inter_pict_data *pinterpict_data); + +/* + * @Function bspp_h264_determine_unittype + * @Description This function determines the BSPP unit type based on the + * provided bitstream (H264 specific) unit type + */ +void bspp_h264_determine_unittype(unsigned char bitstream_unittype, + int disable_mvc, + enum bspp_unit_type *pbsppunittype); + +#endif /*__H264SECUREPARSER_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/h264_vlc.h b/drivers/media/platform/imagination/vxe-vxd/decoder/h264_vlc.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/h264_vlc.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/h264_vlc.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,604 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * h264 vlc table definitions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + */ + +#ifndef __H264_VLC_H__ +#define __H264_VLC_H__ + +#include + +static unsigned short h264_vlc_table_data[] = { +/* NumCoeffTrailingOnes_Table9-5_nC_0-1.out */ + 4, 0, 0, + 4, 1, 5, + 4, 2, 10, + 2, 1, 4, + 2, 1, 6, + 0, 1, 8, + 0, 2, 11, + 4, 0, 15, + 4, 1, 4, + 4, 1, 9, + 4, 0, 19, + 4, 1, 14, + 4, 1, 23, + 4, 1, 27, + 4, 1, 18, + 4, 1, 13, + 4, 1, 8, + 2, 5, 8, + 0, 1, 50, + 0, 0, 53, + 0, 0, 54, + 4, 2, 31, + 4, 2, 22, + 4, 2, 17, + 4, 2, 12, + 0, 2, 7, + 0, 2, 14, + 0, 2, 21, + 0, 2, 28, + 0, 1, 35, + 4, 5, 53, + 3, 5, 0, + 4, 2, 32, + 4, 2, 38, + 4, 2, 33, + 4, 2, 28, + 4, 2, 43, + 4, 2, 34, + 4, 2, 29, + 4, 2, 24, + 4, 2, 51, + 4, 2, 46, + 4, 2, 41, + 4, 2, 40, + 4, 2, 47, + 4, 2, 42, + 4, 2, 37, + 4, 2, 36, + 4, 2, 59, + 4, 2, 54, + 4, 2, 49, + 4, 2, 48, + 4, 2, 55, + 4, 2, 50, + 4, 2, 45, + 4, 2, 44, + 4, 2, 67, + 4, 2, 62, + 4, 2, 61, + 4, 2, 56, + 4, 2, 63, + 4, 2, 58, + 4, 2, 57, + 4, 2, 52, + 4, 1, 64, + 4, 1, 66, + 4, 1, 65, + 4, 1, 60, + 4, 1, 39, + 4, 1, 30, + 4, 1, 25, + 4, 1, 20, + 4, 0, 35, + 4, 0, 26, + 4, 0, 21, + 4, 0, 16, +/* NumCoeffTrailingOnes_Table9-5_nC_2-3.out */ + 0, 2, 16, + 0, 1, 73, + 0, 1, 76, + 0, 0, 79, + 4, 3, 19, + 4, 3, 15, + 4, 2, 10, + 4, 2, 10, + 4, 1, 5, + 4, 1, 5, + 4, 1, 5, + 4, 1, 5, + 4, 1, 0, + 4, 1, 0, + 4, 1, 0, + 4, 1, 0, + 2, 5, 8, + 0, 1, 49, + 0, 0, 52, + 0, 0, 53, + 4, 2, 35, + 4, 2, 22, + 4, 2, 21, + 4, 2, 12, + 0, 2, 7, + 0, 2, 14, + 0, 2, 21, + 1, 1, 28, + 0, 1, 34, + 4, 5, 63, + 3, 5, 0, + 4, 2, 47, + 4, 2, 38, + 4, 2, 37, + 4, 2, 32, + 4, 2, 43, + 4, 2, 34, + 4, 2, 33, + 4, 2, 28, + 4, 2, 44, + 4, 2, 46, + 4, 2, 45, + 4, 2, 40, + 4, 2, 51, + 4, 2, 42, + 4, 2, 41, + 4, 2, 36, + 4, 2, 59, + 4, 2, 54, + 4, 2, 53, + 4, 2, 52, + 4, 2, 55, + 4, 2, 50, + 4, 2, 49, + 4, 2, 48, + 0, 1, 3, + 4, 1, 58, + 4, 1, 56, + 4, 1, 61, + 4, 1, 60, + 4, 1, 62, + 4, 1, 57, + 4, 1, 67, + 4, 1, 66, + 4, 1, 65, + 4, 1, 64, + 4, 1, 39, + 4, 1, 30, + 4, 1, 29, + 4, 1, 24, + 4, 0, 20, + 4, 0, 26, + 4, 0, 25, + 4, 0, 16, + 4, 1, 31, + 4, 1, 18, + 4, 1, 17, + 4, 1, 8, + 4, 1, 27, + 4, 1, 14, + 4, 1, 13, + 4, 1, 4, + 4, 0, 23, + 4, 0, 9, +/* NumCoeffTrailingOnes_Table9-5_nC_4-7.out */ + 2, 1, 16, + 0, 2, 50, + 0, 1, 57, + 0, 1, 60, + 6, 0, 10, + 6, 0, 8, + 0, 0, 61, + 0, 0, 62, + 4, 3, 31, + 4, 3, 27, + 4, 3, 23, + 4, 3, 19, + 4, 3, 15, + 4, 3, 10, + 4, 3, 5, + 4, 3, 0, + 0, 2, 3, + 0, 2, 10, + 0, 3, 17, + 4, 2, 51, + 4, 2, 46, + 4, 2, 41, + 4, 2, 36, + 4, 2, 47, + 4, 2, 42, + 4, 2, 37, + 4, 2, 32, + 4, 2, 48, + 4, 2, 54, + 4, 2, 49, + 4, 2, 44, + 4, 2, 55, + 4, 2, 50, + 4, 2, 45, + 4, 2, 40, + 3, 3, 0, + 4, 3, 64, + 4, 3, 67, + 4, 3, 66, + 4, 3, 65, + 4, 3, 60, + 4, 3, 63, + 4, 3, 62, + 4, 3, 61, + 4, 3, 56, + 4, 3, 59, + 4, 3, 58, + 4, 3, 57, + 4, 3, 52, + 4, 2, 53, + 4, 2, 53, + 4, 2, 28, + 4, 2, 24, + 4, 2, 38, + 4, 2, 20, + 4, 2, 43, + 4, 2, 34, + 4, 2, 33, + 4, 2, 16, + 4, 1, 12, + 4, 1, 30, + 4, 1, 29, + 4, 1, 8, + 4, 1, 39, + 4, 1, 26, + 4, 1, 25, + 4, 1, 4, + 4, 0, 13, + 4, 0, 35, + 4, 0, 14, + 4, 0, 9, +/* NumCoeffTrailingOnesFixedLen.out */ + 2, 1, 8, + 5, 2, 6, + 5, 2, 10, + 5, 2, 14, + 5, 2, 18, + 5, 2, 22, + 5, 2, 26, + 5, 2, 30, + 5, 1, 4, + 0, 0, 2, + 5, 0, 2, + 3, 0, 0, + 4, 0, 0, +/* NumCoeffTrailingOnesChromaDC_YUV420.out */ + 4, 0, 5, + 4, 1, 0, + 4, 2, 10, + 0, 2, 1, + 1, 1, 8, + 0, 0, 10, + 4, 2, 16, + 4, 2, 12, + 4, 2, 8, + 4, 2, 15, + 4, 2, 9, + 4, 2, 4, + 4, 0, 19, + 4, 1, 18, + 4, 1, 17, + 4, 0, 14, + 4, 0, 13, +/* NumCoeffTrailingOnesChromaDC_YUV422.out */ + 4, 0, 0, + 4, 1, 5, + 4, 2, 10, + 0, 2, 4, + 4, 4, 15, + 4, 5, 19, + 2, 3, 9, + 4, 2, 27, + 4, 2, 23, + 4, 2, 18, + 4, 2, 14, + 4, 2, 13, + 4, 2, 9, + 4, 2, 8, + 4, 2, 4, + 0, 1, 5, + 0, 1, 8, + 0, 1, 11, + 0, 1, 14, + 1, 2, 17, + 4, 1, 22, + 4, 1, 17, + 4, 1, 16, + 4, 1, 12, + 4, 1, 31, + 4, 1, 26, + 4, 1, 21, + 4, 1, 20, + 4, 1, 35, + 4, 1, 30, + 4, 1, 25, + 4, 1, 24, + 4, 1, 34, + 4, 1, 33, + 4, 1, 29, + 4, 1, 28, + 3, 2, 0, + 3, 2, 0, + 3, 2, 0, + 4, 2, 32, +/* TotalZeros_00.out */ + 4, 0, 0, + 0, 0, 6, + 0, 0, 7, + 0, 0, 8, + 0, 0, 9, + 0, 0, 10, + 0, 2, 11, + 4, 0, 2, + 4, 0, 1, + 4, 0, 4, + 4, 0, 3, + 4, 0, 6, + 4, 0, 5, + 4, 0, 8, + 4, 0, 7, + 4, 0, 10, + 4, 0, 9, + 3, 2, 0, + 4, 2, 15, + 4, 2, 14, + 4, 2, 13, + 4, 1, 12, + 4, 1, 12, + 4, 1, 11, + 4, 1, 11, +/* TotalZeros_01.out */ + 1, 1, 8, + 0, 0, 14, + 0, 0, 15, + 4, 2, 4, + 4, 2, 3, + 4, 2, 2, + 4, 2, 1, + 4, 2, 0, + 0, 1, 3, + 4, 1, 10, + 4, 1, 9, + 4, 1, 14, + 4, 1, 13, + 4, 1, 12, + 4, 1, 11, + 4, 0, 8, + 4, 0, 7, + 4, 0, 6, + 4, 0, 5, +/* TotalZeros_02.out */ + 0, 1, 8, + 0, 0, 13, + 0, 0, 14, + 4, 2, 7, + 4, 2, 6, + 4, 2, 3, + 4, 2, 2, + 4, 2, 1, + 0, 0, 4, + 4, 1, 12, + 4, 1, 10, + 4, 1, 9, + 4, 0, 13, + 4, 0, 11, + 4, 0, 8, + 4, 0, 5, + 4, 0, 4, + 4, 0, 0, +/* TotalZeros_03.out */ + 0, 1, 8, + 0, 0, 11, + 0, 0, 12, + 4, 2, 8, + 4, 2, 6, + 4, 2, 5, + 4, 2, 4, + 4, 2, 1, + 4, 1, 12, + 4, 1, 11, + 4, 1, 10, + 4, 1, 0, + 4, 0, 9, + 4, 0, 7, + 4, 0, 3, + 4, 0, 2, +/* TotalZeros_04.out */ + 2, 1, 8, + 0, 0, 10, + 0, 0, 11, + 4, 2, 7, + 4, 2, 6, + 4, 2, 5, + 4, 2, 4, + 4, 2, 3, + 4, 0, 10, + 4, 1, 9, + 4, 1, 11, + 4, 0, 8, + 4, 0, 2, + 4, 0, 1, + 4, 0, 0, +/* TotalZeros_05.out */ + 2, 2, 8, + 4, 2, 9, + 4, 2, 7, + 4, 2, 6, + 4, 2, 5, + 4, 2, 4, + 4, 2, 3, + 4, 2, 2, + 4, 0, 8, + 4, 1, 1, + 4, 2, 0, + 4, 2, 10, +/* TotalZeros_06.out */ + 2, 2, 8, + 4, 2, 8, + 4, 2, 6, + 4, 2, 4, + 4, 2, 3, + 4, 2, 2, + 4, 1, 5, + 4, 1, 5, + 4, 0, 7, + 4, 1, 1, + 4, 2, 0, + 4, 2, 9, +/* TotalZeros_07.out */ + 2, 3, 4, + 0, 0, 8, + 4, 1, 5, + 4, 1, 4, + 4, 0, 7, + 4, 1, 1, + 4, 2, 2, + 4, 3, 0, + 4, 3, 8, + 4, 0, 6, + 4, 0, 3, +/* TotalZeros_08.out */ + 2, 3, 4, + 4, 1, 6, + 4, 1, 4, + 4, 1, 3, + 4, 0, 5, + 4, 1, 2, + 4, 2, 7, + 4, 3, 0, + 4, 3, 1, +/* TotalZeros_09.out */ + 2, 2, 4, + 4, 1, 5, + 4, 1, 4, + 4, 1, 3, + 4, 0, 2, + 4, 1, 6, + 4, 2, 0, + 4, 2, 1, +/* TotalZeros_10.out */ + 4, 0, 4, + 0, 0, 3, + 4, 2, 2, + 5, 0, 0, + 4, 0, 3, + 4, 0, 5, +/* TotalZeros_11.out */ + 4, 0, 3, + 4, 1, 2, + 4, 2, 4, + 5, 0, 0, +/* TotalZeros_12.out */ + 4, 0, 2, + 4, 1, 3, + 5, 0, 0, +/* TotalZeros_13.out */ + 5, 0, 0, + 4, 0, 2, +/* TotalZeros_14.out */ + 4, 0, 0, + 4, 0, 1, +/* TotalZerosChromaDC_YUV420_00.out */ + 4, 0, 0, + 4, 1, 1, + 4, 2, 2, + 4, 2, 3, +/* TotalZerosChromaDC_YUV420_01.out */ + 4, 0, 0, + 4, 1, 1, + 4, 1, 2, +/* TotalZerosChromaDC_YUV420_02.out */ + 4, 0, 1, + 4, 0, 0, +/* Run_00.out */ + 4, 0, 1, + 4, 0, 0, +/* Run_01.out */ + 4, 0, 0, + 4, 1, 1, + 4, 1, 2, +/* Run_02.out */ + 4, 1, 3, + 4, 1, 2, + 4, 1, 1, + 4, 1, 0, +/* Run_03.out */ + 0, 0, 4, + 4, 1, 2, + 4, 1, 1, + 4, 1, 0, + 4, 0, 4, + 4, 0, 3, +/* Run_04.out */ + 0, 1, 3, + 4, 1, 1, + 4, 1, 0, + 4, 1, 5, + 4, 1, 4, + 4, 1, 3, + 4, 1, 2, +/* Run_05.out */ + 4, 2, 1, + 4, 2, 2, + 4, 2, 4, + 4, 2, 3, + 4, 2, 6, + 4, 2, 5, + 4, 1, 0, + 4, 1, 0, +/* Run_06.out */ + 2, 5, 8, + 4, 2, 6, + 4, 2, 5, + 4, 2, 4, + 4, 2, 3, + 4, 2, 2, + 4, 2, 1, + 4, 2, 0, + 4, 0, 7, + 4, 1, 8, + 4, 2, 9, + 4, 3, 10, + 4, 4, 11, + 4, 5, 12, + 2, 1, 1, + 4, 0, 13, + 4, 1, 14, + 3, 1, 0, +/* TotalZerosChromaDC_YUV422_00.out */ + 4, 0, 0, + 6, 0, 0, + 6, 0, 1, + 4, 3, 5, + 4, 4, 6, + 4, 4, 7, +/* TotalZerosChromaDC_YUV422_01.out */ + 6, 1, 1, + 4, 1, 1, + 4, 2, 2, + 4, 2, 0, +/* TotalZerosChromaDC_YUV422_02.out */ + 5, 0, 0, + 4, 1, 2, + 4, 1, 3, + 5, 0, 2, +/* TotalZerosChromaDC_YUV422_03.out */ + 6, 0, 0, + 4, 1, 3, + 4, 2, 0, + 4, 2, 4, +/* TotalZerosChromaDC_YUV422_04.out */ + 5, 0, 0, + 5, 0, 1, +/* TotalZerosChromaDC_YUV422_05.out */ + 5, 0, 0, + 4, 0, 2, +/* TotalZerosChromaDC_YUV422_06.out */ + 4, 0, 0, + 4, 0, 1 +}; + +static const unsigned short h264_vlc_table_size = 544; + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/hevcfw_data.h b/drivers/media/platform/imagination/vxe-vxd/decoder/hevcfw_data.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/hevcfw_data.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/hevcfw_data.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,472 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Public data structures for the hevc parser firmware module. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +/* Include shared header version here to replace the standard version. */ +#include "hevcfw_data_shared.h" + +#ifndef _HEVCFW_DATA_H_ +#define _HEVCFW_DATA_H_ + +#include "vdecfw_shared.h" + +#define HEVC_MAX_SPS_COUNT 16 +#define HEVC_MAX_PPS_COUNT 64 + +#define HEVCFW_MAX_NUM_PROFILE_IDC 32 + +#define HEVCFW_MAX_NUM_REF_PICS 16 +#define HEVCFW_MAX_NUM_ST_REF_PIC_SETS 65 +#define HEVCFW_MAX_NUM_LT_REF_PICS 32 +#define HEVCFW_MAX_NUM_SUBLAYERS 7 +#define HEVCFW_SCALING_LISTS_BUFSIZE 256 +#define HEVCFW_MAX_TILE_COLS 20 +#define HEVCFW_MAX_TILE_ROWS 22 + +#define HEVCFW_MAX_CHROMA_QP 6 + +#define HEVCFW_MAX_DPB_SIZE HEVCFW_MAX_NUM_REF_PICS +#define HEVCFW_REF_PIC_LIST0 0 +#define HEVCFW_REF_PIC_LIST1 1 +#define HEVCFW_NUM_REF_PIC_LISTS 2 +#define HEVCFW_NUM_DPB_DIFF_REGS 4 + +/* non-critical errors */ +#define HEVC_ERR_INVALID_VALUE (20) +#define HEVC_ERR_CORRECTION_VALIDVALUE (21) + +#define HEVC_IS_ERR_CRITICAL(err) \ + ((err) > HEVC_ERR_CORRECTION_VALIDVALUE ? 1 : 0) + +/* critical errors */ +#define HEVC_ERR_INV_VIDEO_DIMENSION (22) +#define HEVC_ERR_NO_SEQUENCE_HDR (23) +#define HEVC_ERR_SPS_EXT_UNSUPP (24 | VDECFW_UNSUPPORTED_CODE_BASE) +#define HEVC_ERR_PPS_EXT_UNSUPP (25 | VDECFW_UNSUPPORTED_CODE_BASE) + +#define HEVC_ERR_FAILED_TO_STORE_VPS (100) +#define HEVC_ERR_FAILED_TO_STORE_SPS (101) +#define HEVC_ERR_FAILED_TO_STORE_PPS (102) + +#define HEVC_ERR_FAILED_TO_FETCH_VPS (103) +#define HEVC_ERR_FAILED_TO_FETCH_SPS (104) +#define HEVC_ERR_FAILED_TO_FETCH_PPS (105) +/* HEVC Scaling Lists (all values are maximum possible ones) */ +#define HEVCFW_SCALING_LIST_NUM_SIZES 4 +#define HEVCFW_SCALING_LIST_NUM_MATRICES 6 +#define HEVCFW_SCALING_LIST_MATRIX_SIZE 64 + +struct hevcfw_scaling_listdata { + unsigned char dc_coeffs + [HEVCFW_SCALING_LIST_NUM_SIZES - 2] + [HEVCFW_SCALING_LIST_NUM_MATRICES]; + unsigned char lists + [HEVCFW_SCALING_LIST_NUM_SIZES] + [HEVCFW_SCALING_LIST_NUM_MATRICES] + [HEVCFW_SCALING_LIST_MATRIX_SIZE]; +}; + +/* HEVC Video Profile_Tier_Level */ +struct hevcfw_profile_tier_level { + unsigned char general_profile_space; + unsigned char general_tier_flag; + unsigned char general_profile_idc; + unsigned char general_profile_compatibility_flag[HEVCFW_MAX_NUM_PROFILE_IDC]; + unsigned char general_progressive_source_flag; + unsigned char general_interlaced_source_flag; + unsigned char general_non_packed_constraint_flag; + unsigned char general_frame_only_constraint_flag; + unsigned char general_max_12bit_constraint_flag; + unsigned char general_max_10bit_constraint_flag; + unsigned char general_max_8bit_constraint_flag; + unsigned char general_max_422chroma_constraint_flag; + unsigned char general_max_420chroma_constraint_flag; + unsigned char general_max_monochrome_constraint_flag; + unsigned char general_intra_constraint_flag; + unsigned char general_one_picture_only_constraint_flag; + unsigned char general_lower_bit_rate_constraint_flag; + unsigned char general_level_idc; + unsigned char sub_layer_profile_present_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_level_present_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_profile_space[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_tier_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_profile_idc[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_profile_compatibility_flag[HEVCFW_MAX_NUM_SUBLAYERS - + 1][HEVCFW_MAX_NUM_PROFILE_IDC]; + unsigned char sub_layer_progressive_source_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_interlaced_source_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_non_packed_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_frame_only_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_max_12bit_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_max_10bit_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_max_8bit_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_max_422chroma_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_max_420chroma_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_max_monochrome_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_intra_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_one_picture_only_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_lower_bit_rate_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_level_idc[HEVCFW_MAX_NUM_SUBLAYERS - 1]; +}; + +struct hevcfw_video_ps { + int is_different; + int is_sent; + int is_available; + unsigned char vps_video_parameter_set_id; + unsigned char vps_reserved_three_2bits; + unsigned char vps_max_layers_minus1; + unsigned char vps_max_sub_layers_minus1; + unsigned char vps_temporal_id_nesting_flag; + unsigned short vps_reserved_0xffff_16bits; + struct hevcfw_profile_tier_level profile_tier_level; +}; + +/* HEVC Video Usability Information */ +struct hevcfw_vui_params { + unsigned char aspect_ratio_info_present_flag; + unsigned char aspect_ratio_idc; + unsigned short sar_width; + unsigned short sar_height; + unsigned char overscan_info_present_flag; + unsigned char overscan_appropriate_flag; + unsigned char video_signal_type_present_flag; + unsigned char video_format; + unsigned char video_full_range_flag; + unsigned char colour_description_present_flag; + unsigned char colour_primaries; + unsigned char transfer_characteristics; + unsigned char matrix_coeffs; + unsigned char chroma_loc_info_present_flag; + unsigned char chroma_sample_loc_type_top_field; + unsigned char chroma_sample_loc_type_bottom_field; + unsigned char neutral_chroma_indication_flag; + unsigned char field_seq_flag; + unsigned char frame_field_info_present_flag; + unsigned char default_display_window_flag; + unsigned short def_disp_win_left_offset; + unsigned short def_disp_win_right_offset; + unsigned short def_disp_win_top_offset; + unsigned short def_disp_win_bottom_offset; + unsigned char vui_timing_info_present_flag; + unsigned int vui_num_units_in_tick; + unsigned int vui_time_scale; +}; + +/* HEVC Short Term Reference Picture Set */ +struct hevcfw_short_term_ref_picset { + unsigned char num_negative_pics; + unsigned char num_positive_pics; + short delta_poc_s0[HEVCFW_MAX_NUM_REF_PICS]; + short delta_poc_s1[HEVCFW_MAX_NUM_REF_PICS]; + unsigned char used_bycurr_pic_s0[HEVCFW_MAX_NUM_REF_PICS]; + unsigned char used_bycurr_pic_s1[HEVCFW_MAX_NUM_REF_PICS]; + unsigned char num_delta_pocs; +}; + +/* + * This describes the SPS header data required by the HEVC firmware that should + * be supplied by the Host. + */ +struct hevcfw_sequence_ps { + /* syntax elements from SPS */ + unsigned short pic_width_in_luma_samples; + unsigned short pic_height_in_luma_samples; + unsigned char num_short_term_ref_pic_sets; + unsigned char num_long_term_ref_pics_sps; + unsigned short lt_ref_pic_poc_lsb_sps[HEVCFW_MAX_NUM_LT_REF_PICS]; + unsigned char used_by_curr_pic_lt_sps_flag[HEVCFW_MAX_NUM_LT_REF_PICS]; + struct hevcfw_short_term_ref_picset st_rps_list[HEVCFW_MAX_NUM_ST_REF_PIC_SETS]; + unsigned char sps_max_sub_layers_minus1; + unsigned char sps_max_dec_pic_buffering_minus1[HEVCFW_MAX_NUM_SUBLAYERS]; + unsigned char sps_max_num_reorder_pics[HEVCFW_MAX_NUM_SUBLAYERS]; + unsigned int sps_max_latency_increase_plus1[HEVCFW_MAX_NUM_SUBLAYERS]; + unsigned char max_transform_hierarchy_depth_inter; + unsigned char max_transform_hierarchy_depth_intra; + unsigned char log2_diff_max_min_transform_block_size; + unsigned char log2_min_transform_block_size_minus2; + unsigned char log2_diff_max_min_luma_coding_block_size; + unsigned char log2_min_luma_coding_block_size_minus3; + unsigned char chroma_format_idc; + unsigned char separate_colour_plane_flag; + unsigned char num_extra_slice_header_bits; + unsigned char log2_max_pic_order_cnt_lsb_minus4; + unsigned char long_term_ref_pics_present_flag; + unsigned char sample_adaptive_offset_enabled_flag; + unsigned char sps_temporal_mvp_enabled_flag; + unsigned char bit_depth_luma_minus8; + unsigned char bit_depth_chroma_minus8; + unsigned char pcm_sample_bit_depth_luma_minus1; + unsigned char pcm_sample_bit_depth_chroma_minus1; + unsigned char log2_min_pcm_luma_coding_block_size_minus3; + unsigned char log2_diff_max_min_pcm_luma_coding_block_size; + unsigned char pcm_loop_filter_disabled_flag; + unsigned char amp_enabled_flag; + unsigned char pcm_enabled_flag; + unsigned char strong_intra_smoothing_enabled_flag; + unsigned char scaling_list_enabled_flag; + unsigned char transform_skip_rotation_enabled_flag; + unsigned char transform_skip_context_enabled_flag; + unsigned char implicit_rdpcm_enabled_flag; + unsigned char explicit_rdpcm_enabled_flag; + unsigned char extended_precision_processing_flag; + unsigned char intra_smoothing_disabled_flag; + unsigned char high_precision_offsets_enabled_flag; + unsigned char persistent_rice_adaptation_enabled_flag; + unsigned char cabac_bypass_alignment_enabled_flag; + /* derived elements */ + unsigned int pic_size_in_ctbs_y; + unsigned short pic_height_in_ctbs_y; + unsigned short pic_width_in_ctbs_y; + unsigned char ctb_size_y; + unsigned char ctb_log2size_y; + int max_pic_order_cnt_lsb; + unsigned int sps_max_latency_pictures[HEVCFW_MAX_NUM_SUBLAYERS]; + unsigned char pps_seq_parameter_set_id; + unsigned char sps_video_parameter_set_id; + unsigned char sps_temporal_id_nesting_flag; + unsigned char sps_seq_parameter_set_id; + /* local */ + unsigned char conformance_window_flag; + unsigned short conf_win_left_offset; + unsigned short conf_win_right_offset; + unsigned short conf_win_top_offset; + unsigned short conf_win_bottom_offset; + unsigned char sps_sub_layer_ordering_info_present_flag; + unsigned char sps_scaling_list_data_present_flag; + unsigned char vui_parameters_present_flag; + unsigned char sps_extension_present_flag; + struct hevcfw_vui_params vui_params; + /* derived elements */ + unsigned char sub_width_c; + unsigned char sub_height_c; + struct hevcfw_profile_tier_level profile_tier_level; + struct hevcfw_scaling_listdata scaling_listdata; +}; + +/* + * This describes the HEVC parser component "Header data", shown in the + * Firmware Memory Layout diagram. This data is required by the HEVC firmware + * and should be supplied by the Host. + */ +struct hevcfw_headerdata { + /* Decode buffers and output control for the current picture */ + /* Primary decode buffer base addresses */ + struct vdecfw_image_buffer primary; + /* buffer base addresses for alternate output */ + struct vdecfw_image_buffer alternate; + /* address of buffer for temporal mv params */ + unsigned int temporal_outaddr; +}; + +/* + * This describes the PPS header data required by the HEVC firmware that should + * be supplied by the Host. + */ +struct hevcfw_picture_ps { + /* syntax elements from the PPS */ + unsigned char pps_pic_parameter_set_id; + unsigned char num_tile_columns_minus1; + unsigned char num_tile_rows_minus1; + unsigned char diff_cu_qp_delta_depth; + unsigned char init_qp_minus26; + unsigned char pps_beta_offset_div2; + unsigned char pps_tc_offset_div2; + unsigned char pps_cb_qp_offset; + unsigned char pps_cr_qp_offset; + unsigned char log2_parallel_merge_level_minus2; + unsigned char dependent_slice_segments_enabled_flag; + unsigned char output_flag_present_flag; + unsigned char num_extra_slice_header_bits; + unsigned char lists_modification_present_flag; + unsigned char cabac_init_present_flag; + unsigned char weighted_pred_flag; + unsigned char weighted_bipred_flag; + unsigned char pps_slice_chroma_qp_offsets_present_flag; + unsigned char deblocking_filter_override_enabled_flag; + unsigned char tiles_enabled_flag; + unsigned char entropy_coding_sync_enabled_flag; + unsigned char slice_segment_header_extension_present_flag; + unsigned char transquant_bypass_enabled_flag; + unsigned char cu_qp_delta_enabled_flag; + unsigned char transform_skip_enabled_flag; + unsigned char sign_data_hiding_enabled_flag; + unsigned char num_ref_idx_l0_default_active_minus1; + unsigned char num_ref_idx_l1_default_active_minus1; + unsigned char constrained_intra_pred_flag; + unsigned char pps_deblocking_filter_disabled_flag; + unsigned char pps_loop_filter_across_slices_enabled_flag; + unsigned char loop_filter_across_tiles_enabled_flag; + /* rewritten from SPS, maybe at some point we could get rid of this */ + unsigned char scaling_list_enabled_flag; + unsigned char log2_max_transform_skip_block_size_minus2; + unsigned char cross_component_prediction_enabled_flag; + unsigned char chroma_qp_offset_list_enabled_flag; + unsigned char diff_cu_chroma_qp_offset_depth; + /* + * PVDEC derived elements. HEVCFW_SCALING_LISTS_BUFSIZE is + * multiplied by 2 to ensure that there will be space for address of + * each element. These addresses are completed in lower layer. + */ + unsigned int scaling_lists[HEVCFW_SCALING_LISTS_BUFSIZE * 2]; + /* derived elements */ + unsigned short col_bd[HEVCFW_MAX_TILE_COLS + 1]; + unsigned short row_bd[HEVCFW_MAX_TILE_ROWS + 1]; + + unsigned char chroma_qp_offset_list_len_minus1; + unsigned char cb_qp_offset_list[HEVCFW_MAX_CHROMA_QP]; + unsigned char cr_qp_offset_list[HEVCFW_MAX_CHROMA_QP]; + + unsigned char uniform_spacing_flag; + unsigned char column_width_minus1[HEVCFW_MAX_TILE_COLS]; + unsigned char row_height_minus1[HEVCFW_MAX_TILE_ROWS]; + + unsigned char pps_seq_parameter_set_id; + unsigned char deblocking_filter_control_present_flag; + unsigned char pps_scaling_list_data_present_flag; + unsigned char pps_extension_present_flag; + + struct hevcfw_scaling_listdata scaling_list; +}; + +/* This enum determines reference picture status */ +enum hevcfw_reference_type { + HEVCFW_REF_UNUSED = 0, + HEVCFW_REF_SHORTTERM, + HEVCFW_REF_LONGTERM, + HEVCFW_REF_FORCE32BITS = 0x7FFFFFFFU +}; + +/* This describes an HEVC picture. It is part of the Context data */ +struct hevcfw_picture { + /* Primary (reconstructed) picture buffers */ + struct vdecfw_image_buffer primary; + /* Secondary (alternative) picture buffers */ + struct vdecfw_image_buffer alternate; + /* Unique ID for this picture */ + unsigned int transaction_id; + /* nut of first ssh of picture, determines picture type */ + unsigned char nalunit_type; + /* Picture Order Count (frame number) */ + int pic_order_cnt_val; + /* Slice Picture Order Count Lsb */ + int slice_pic_ordercnt_lsb; + unsigned char pic_output_flag; + /* information about long-term pictures */ + unsigned short dpb_longterm_flags; + unsigned int dpb_pic_order_diff[HEVCFW_NUM_DPB_DIFF_REGS]; + /* address of buffer for temporal mv params */ + unsigned int temporal_outaddr; + /* worst case Dpb diff for the current pic */ + unsigned int dpb_diff; +}; + +/* + * This is a wrapper for a picture to hold it in a Decoded Picture Buffer + * for further reference + */ +struct hevcfw_picture_in_dpb { + /* DPB data about the picture */ + enum hevcfw_reference_type ref_type; + unsigned char valid; + unsigned char needed_for_output; + unsigned char pic_latency_count; + /* Picture itself */ + struct hevcfw_picture picture; +}; + +/* + * This describes an HEVC's Decoded Picture Buffer (DPB). + * It is part of the Context data + */ +#define HEVCFW_DPB_IDX_INVALID -1 + +struct hevcfw_decoded_picture_buffer { + /* reference pictures */ + struct hevcfw_picture_in_dpb pictures[HEVCFW_MAX_DPB_SIZE]; + /* organizational data of DPB */ + unsigned int fullness; +}; + +/* + * This describes an HEVC's Reference Picture Set (RPS). + * It is part of the Context data + */ +struct hevcfw_reference_picture_set { + /* sizes of poc lists */ + unsigned char num_pocst_curr_before; + unsigned char num_pocst_curr_after; + unsigned char num_pocst_foll; + unsigned char num_poclt_curr; + unsigned char num_poclt_foll; + /* poc lists */ + int pocst_curr_before[HEVCFW_MAX_NUM_REF_PICS]; + int pocst_curr_after[HEVCFW_MAX_NUM_REF_PICS]; + int pocst_foll[HEVCFW_MAX_NUM_REF_PICS]; + int poclt_curr[HEVCFW_MAX_NUM_REF_PICS]; + int poclt_foll[HEVCFW_MAX_NUM_REF_PICS]; + /* derived elements */ + unsigned char curr_delta_pocmsb_presentflag[HEVCFW_MAX_NUM_REF_PICS]; + unsigned char foll_delta_pocmsb_presentflag[HEVCFW_MAX_NUM_REF_PICS]; + /* reference picture sets: indices in DPB */ + unsigned char ref_picsetlt_curr[HEVCFW_MAX_NUM_REF_PICS]; + unsigned char ref_picsetlt_foll[HEVCFW_MAX_NUM_REF_PICS]; + unsigned char ref_picsetst_curr_before[HEVCFW_MAX_NUM_REF_PICS]; + unsigned char ref_picsetst_curr_after[HEVCFW_MAX_NUM_REF_PICS]; + unsigned char ref_picsetst_foll[HEVCFW_MAX_NUM_REF_PICS]; +}; + +/* + * This describes the HEVC parser component "Context data", shown in the + * Firmware Memory Layout diagram. This data is the state preserved across + * pictures. It is loaded and saved by the Firmware, but requires the host to + * provide buffer(s) for this. + */ +struct hevcfw_ctx_data { + struct hevcfw_sequence_ps sps; + struct hevcfw_picture_ps pps; + /* + * data from last picture with TemporalId = 0 that is not a RASL, RADL + * or sub-layer non-reference picture + */ + int prev_pic_order_cnt_lsb; + int prev_pic_order_cnt_msb; + unsigned char last_irapnorasl_output_flag; + /* + * Decoded Pictures Buffer holds information about decoded pictures + * needed for further INTER decoding + */ + struct hevcfw_decoded_picture_buffer dpb; + /* Reference Picture Set is determined on per-picture basis */ + struct hevcfw_reference_picture_set rps; + /* + * Reference Picture List is determined using data from Reference + * Picture Set and from Slice (Segment) Header on per-slice basis + */ + unsigned char ref_pic_list[HEVCFW_NUM_REF_PIC_LISTS][HEVCFW_MAX_NUM_REF_PICS]; + /* + * Reference Picture List used to send reflist to the host, the only + * difference is that missing references are marked + * with HEVCFW_DPB_IDX_INVALID + */ + unsigned char ref_pic_listhlp[HEVCFW_NUM_REF_PIC_LISTS][HEVCFW_MAX_NUM_REF_PICS]; + + unsigned int pic_count; + unsigned int slice_segment_count; + /* There was EOS NAL detected and no new picture yet */ + int eos_detected; + /* This is first picture after EOS NAL */ + int first_after_eos; +}; + +#endif /* _HEVCFW_DATA_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/hevcfw_data_shared.h b/drivers/media/platform/imagination/vxe-vxd/decoder/hevcfw_data_shared.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/hevcfw_data_shared.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/hevcfw_data_shared.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,767 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Public data structures for the hevc parser firmware module + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstreming + * Sidraya Jayagond + */ +#ifdef USE_SHARING +#endif + +#ifndef _HEVCFW_DATA_H_ +#define _HEVCFW_DATA_H_ + +#include "vdecfw_share.h" +#include "vdecfw_shared.h" + +#define HEVC_MAX_VPS_COUNT 16 +#define HEVC_MAX_SPS_COUNT 16 +#define HEVC_MAX_PPS_COUNT 64 + +#define HEVCFW_MAX_NUM_PROFILE_IDC 32 +#define HEVCFW_MAX_VPS_OP_SETS_PLUS1 1024 +#define HEVCFW_MAX_VPS_NUH_RESERVED_ZERO_LAYER_ID_PLUS1 1 + +#define HEVCFW_MAX_NUM_REF_PICS 16 +#define HEVCFW_MAX_NUM_ST_REF_PIC_SETS 65 +#define HEVCFW_MAX_NUM_LT_REF_PICS 32 +#define HEVCFW_MAX_NUM_SUBLAYERS 7 +#define HEVCFW_SCALING_LISTS_BUFSIZE 256 +#define HEVCFW_MAX_TILE_COLS 20 +#define HEVCFW_MAX_TILE_ROWS 22 + +#define HEVCFW_MAX_CHROMA_QP 6 + +#define HEVCFW_MAX_DPB_SIZE HEVCFW_MAX_NUM_REF_PICS +#define HEVCFW_REF_PIC_LIST0 0 +#define HEVCFW_REF_PIC_LIST1 1 +#define HEVCFW_NUM_REF_PIC_LISTS 2 +#define HEVCFW_NUM_DPB_DIFF_REGS 4 + +/* non-critical errors*/ +#define HEVC_ERR_INVALID_VALUE (20) +#define HEVC_ERR_CORRECTION_VALIDVALUE (21) + +#define HEVC_IS_ERR_CRITICAL(err) \ + ((err) > HEVC_ERR_CORRECTION_VALIDVALUE ? 1 : 0) + +/* critical errors*/ +#define HEVC_ERR_INV_VIDEO_DIMENSION (22) +#define HEVC_ERR_NO_SEQUENCE_HDR (23) +#define HEVC_ERR_SPS_EXT_UNSUPP (24 | VDECFW_UNSUPPORTED_CODE_BASE) +#define HEVC_ERR_PPS_EXT_UNSUPP (25 | VDECFW_UNSUPPORTED_CODE_BASE) + +#define HEVC_ERR_FAILED_TO_STORE_VPS (100) +#define HEVC_ERR_FAILED_TO_STORE_SPS (101) +#define HEVC_ERR_FAILED_TO_STORE_PPS (102) + +#define HEVC_ERR_FAILED_TO_FETCH_VPS (103) +#define HEVC_ERR_FAILED_TO_FETCH_SPS (104) +#define HEVC_ERR_FAILED_TO_FETCH_PPS (105) +/* HEVC Scaling Lists (all values are maximum possible ones) */ +#define HEVCFW_SCALING_LIST_NUM_SIZES 4 +#define HEVCFW_SCALING_LIST_NUM_MATRICES 6 +#define HEVCFW_SCALING_LIST_MATRIX_SIZE 64 + +struct hevcfw_scaling_listdata { + unsigned char dc_coeffs + [HEVCFW_SCALING_LIST_NUM_SIZES - 2] + [HEVCFW_SCALING_LIST_NUM_MATRICES]; + + unsigned char lists + [HEVCFW_SCALING_LIST_NUM_SIZES] + [HEVCFW_SCALING_LIST_NUM_MATRICES] + [HEVCFW_SCALING_LIST_MATRIX_SIZE]; +}; + +/* HEVC Video Profile_Tier_Level */ +struct hevcfw_profile_tier_level { + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_profile_space); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_tier_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_profile_idc); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + general_profile_compatibility_flag + [HEVCFW_MAX_NUM_PROFILE_IDC]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_progressive_source_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_interlaced_source_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_non_packed_constraint_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_frame_only_constraint_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_max_12bit_constraint_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_max_10bit_constraint_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_max_8bit_constraint_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_max_422chroma_constraint_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_max_420chroma_constraint_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_max_monochrome_constraint_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_intra_constraint_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + general_one_picture_only_constraint_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_lower_bit_rate_constraint_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, general_level_idc); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_profile_present_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_level_present_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_profile_space[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_tier_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_profile_idc[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_profile_compatibility_flag + [HEVCFW_MAX_NUM_SUBLAYERS - 1][HEVCFW_MAX_NUM_PROFILE_IDC]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_progressive_source_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_interlaced_source_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_non_packed_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_frame_only_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_max_12bit_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_max_10bit_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_max_8bit_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_max_422chroma_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_max_420chroma_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_max_monochrome_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_intra_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_one_picture_only_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_lower_bit_rate_constraint_flag[HEVCFW_MAX_NUM_SUBLAYERS - 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sub_layer_level_idc[HEVCFW_MAX_NUM_SUBLAYERS - 1]); +}; + +struct hevcfw_video_ps { + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, is_different); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, is_sent); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, is_available); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, vps_video_parameter_set_id); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, vps_reserved_three_2bits); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, vps_max_layers_minus1); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, vps_max_sub_layers_minus1); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, vps_temporal_id_nesting_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, vps_reserved_0xffff_16bits); + struct hevcfw_profile_tier_level profile_tier_level; +}; + +/* HEVC Video Usability Information */ +struct hevcfw_vui_params { + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, aspect_ratio_info_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, aspect_ratio_idc); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, sar_width); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, sar_height); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, overscan_info_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, overscan_appropriate_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, video_signal_type_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, video_format); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, video_full_range_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, colour_description_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, colour_primaries); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, transfer_characteristics); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, matrix_coeffs); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, chroma_loc_info_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, chroma_sample_loc_type_top_field); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, chroma_sample_loc_type_bottom_field); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, neutral_chroma_indication_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, field_seq_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, frame_field_info_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, default_display_window_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, def_disp_win_left_offset); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, def_disp_win_right_offset); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, def_disp_win_top_offset); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, def_disp_win_bottom_offset); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, vui_timing_info_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, vui_num_units_in_tick); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, vui_time_scale); +}; + +/* HEVC Short Term Reference Picture Set */ +struct hevcfw_short_term_ref_picset { + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_negative_pics); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_positive_pics); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + short, delta_poc_s0[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + short, delta_poc_s1[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, used_bycurr_pic_s0[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, used_bycurr_pic_s1[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_delta_pocs); +}; + +/* + * This describes the SPS header data required by the HEVC firmware that should + * be supplied by the Host. + */ +struct hevcfw_sequence_ps { + /* syntax elements from SPS */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, pic_width_in_luma_samples); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, pic_height_in_luma_samples); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_short_term_ref_pic_sets); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_long_term_ref_pics_sps); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, + lt_ref_pic_poc_lsb_sps[HEVCFW_MAX_NUM_LT_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + used_by_curr_pic_lt_sps_flag[HEVCFW_MAX_NUM_LT_REF_PICS]); + struct hevcfw_short_term_ref_picset st_rps_list[HEVCFW_MAX_NUM_ST_REF_PIC_SETS]; + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, sps_max_sub_layers_minus1); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sps_max_dec_pic_buffering_minus1[HEVCFW_MAX_NUM_SUBLAYERS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + sps_max_num_reorder_pics[HEVCFW_MAX_NUM_SUBLAYERS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, + sps_max_latency_increase_plus1[HEVCFW_MAX_NUM_SUBLAYERS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, max_transform_hierarchy_depth_inter); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, max_transform_hierarchy_depth_intra); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, log2_diff_max_min_transform_block_size); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, log2_min_transform_block_size_minus2); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + log2_diff_max_min_luma_coding_block_size); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, log2_min_luma_coding_block_size_minus3); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, chroma_format_idc); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, separate_colour_plane_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_extra_slice_header_bits); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, log2_max_pic_order_cnt_lsb_minus4); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, long_term_ref_pics_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, sample_adaptive_offset_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, sps_temporal_mvp_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, bit_depth_luma_minus8); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, bit_depth_chroma_minus8); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pcm_sample_bit_depth_luma_minus1); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pcm_sample_bit_depth_chroma_minus1); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + log2_min_pcm_luma_coding_block_size_minus3); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + log2_diff_max_min_pcm_luma_coding_block_size); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pcm_loop_filter_disabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, amp_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pcm_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, strong_intra_smoothing_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, scaling_list_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, transform_skip_rotation_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, transform_skip_context_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, implicit_rdpcm_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, explicit_rdpcm_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, extended_precision_processing_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, intra_smoothing_disabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, high_precision_offsets_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, persistent_rice_adaptation_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, cabac_bypass_alignment_enabled_flag); + /* derived elements */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, pic_size_in_ctbs_y); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, pic_height_in_ctbs_y); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, pic_width_in_ctbs_y); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, ctb_size_y); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, ctb_log2size_y); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, max_pic_order_cnt_lsb); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, + sps_max_latency_pictures[HEVCFW_MAX_NUM_SUBLAYERS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pps_seq_parameter_set_id); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, sps_video_parameter_set_id); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, sps_temporal_id_nesting_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, sps_seq_parameter_set_id); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, conformance_window_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, conf_win_left_offset); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, conf_win_right_offset); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, conf_win_top_offset); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, conf_win_bottom_offset); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, sps_sub_layer_ordering_info_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, sps_scaling_list_data_present_flag); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, vui_parameters_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, sps_extension_present_flag); + + struct hevcfw_vui_params vui_params; + /* derived elements */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, sub_width_c); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, sub_height_c); + + struct hevcfw_profile_tier_level profile_tier_level; + struct hevcfw_scaling_listdata scaling_listdata; +}; + +/* + * This describes the HEVC parser component "Header data", shown in the + * Firmware Memory Layout diagram. This data is required by the HEVC firmware + * and should be supplied by the Host. + */ +struct hevcfw_headerdata { + /* Decode buffers and output control for the current picture */ + /* Primary decode buffer base addresses */ + struct vdecfw_image_buffer primary; + /* buffer base addresses for alternate output */ + struct vdecfw_image_buffer alternate; + /* address of buffer for temporal mv params */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, temporal_outaddr); +}; + +/* + * This describes the PPS header data required by the HEVC firmware that should + * be supplied by the Host. + */ +struct hevcfw_picture_ps { + /* syntax elements from the PPS */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pps_pic_parameter_set_id); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_tile_columns_minus1); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_tile_rows_minus1); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, diff_cu_qp_delta_depth); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, init_qp_minus26); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pps_beta_offset_div2); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pps_tc_offset_div2); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pps_cb_qp_offset); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pps_cr_qp_offset); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, log2_parallel_merge_level_minus2); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, dependent_slice_segments_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, output_flag_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_extra_slice_header_bits); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, lists_modification_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, cabac_init_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, weighted_pred_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, weighted_bipred_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + pps_slice_chroma_qp_offsets_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + deblocking_filter_override_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, tiles_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, entropy_coding_sync_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + slice_segment_header_extension_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, transquant_bypass_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, cu_qp_delta_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, transform_skip_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, sign_data_hiding_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_ref_idx_l0_default_active_minus1); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_ref_idx_l1_default_active_minus1); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, constrained_intra_pred_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pps_deblocking_filter_disabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + pps_loop_filter_across_slices_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, loop_filter_across_tiles_enabled_flag); + + /* rewritten from SPS, maybe at some point we could get rid of this */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, scaling_list_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + log2_max_transform_skip_block_size_minus2); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + cross_component_prediction_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, chroma_qp_offset_list_enabled_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, diff_cu_chroma_qp_offset_depth); + /* + * PVDEC derived elements. HEVCFW_SCALING_LISTS_BUFSIZE is + * multiplied by 2 to ensure that there will be space for address of + * each element. These addresses are completed in lower layer. + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, + scaling_lists[HEVCFW_SCALING_LISTS_BUFSIZE * 2]); + /* derived elements */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, col_bd[HEVCFW_MAX_TILE_COLS + 1]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, row_bd[HEVCFW_MAX_TILE_ROWS + 1]); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, chroma_qp_offset_list_len_minus1); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, cb_qp_offset_list[HEVCFW_MAX_CHROMA_QP]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, cr_qp_offset_list[HEVCFW_MAX_CHROMA_QP]); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, uniform_spacing_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + column_width_minus1[HEVCFW_MAX_TILE_COLS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + row_height_minus1[HEVCFW_MAX_TILE_ROWS]); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pps_seq_parameter_set_id); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, deblocking_filter_control_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pps_scaling_list_data_present_flag); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pps_extension_present_flag); + + struct hevcfw_scaling_listdata scaling_list; +}; + +/* This enum determines reference picture status */ +enum hevcfw_reference_type { + HEVCFW_REF_UNUSED = 0, + HEVCFW_REF_SHORTTERM, + HEVCFW_REF_LONGTERM, + HEVCFW_REF_FORCE32BITS = 0x7FFFFFFFU +}; + +/* This describes an HEVC picture. It is part of the Context data */ +struct hevcfw_picture { + /* Primary (reconstructed) picture buffers */ + struct vdecfw_image_buffer primary; + /* Secondary (alternative) picture buffers */ + struct vdecfw_image_buffer alternate; + /* Unique ID for this picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, transaction_id); + /* nut of first ssh of picture, determines picture type */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, nalunit_type); + /* Picture Order Count (frame number) */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, pic_order_cnt_val); + /* Slice Picture Order Count Lsb */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, slice_pic_ordercnt_lsb); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pic_output_flag); + /* information about long-term pictures */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, dpb_longterm_flags); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, + dpb_pic_order_diff[HEVCFW_NUM_DPB_DIFF_REGS]); + /* address of buffer for temporal mv params */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, temporal_outaddr); + /* worst case Dpb diff for the current pic */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, dpb_diff); +}; + +/* + * This is a wrapper for a picture to hold it in a Decoded Picture Buffer + * for further reference + */ +struct hevcfw_picture_in_dpb { + /* DPB data about the picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + enum hevcfw_reference_type, ref_type); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, valid); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, needed_for_output); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, pic_latency_count); + /* Picture itself */ + struct hevcfw_picture picture; +}; + +/* + * This describes an HEVC's Decoded Picture Buffer (DPB). + * It is part of the Context data + */ + +#define HEVCFW_DPB_IDX_INVALID -1 + +struct hevcfw_decoded_picture_buffer { + /* reference pictures */ + struct hevcfw_picture_in_dpb pictures[HEVCFW_MAX_DPB_SIZE]; + /* organizational data of DPB */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, fullness); +}; + +/* + * This describes an HEVC's Reference Picture Set (RPS). + * It is part of the Context data + */ +struct hevcfw_reference_picture_set { + /* sizes of poc lists */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_pocst_curr_before); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_pocst_curr_after); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_pocst_foll); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_poclt_curr); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, num_poclt_foll); + /* poc lists */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, pocst_curr_before[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, pocst_curr_after[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, pocst_foll[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, poclt_curr[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, poclt_foll[HEVCFW_MAX_NUM_REF_PICS]); + /* derived elements */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + curr_delta_pocmsb_presentflag[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + foll_delta_pocmsb_presentflag[HEVCFW_MAX_NUM_REF_PICS]); + /* reference picture sets: indices in DPB */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, ref_picsetlt_curr[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, ref_picsetlt_foll[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + ref_picsetst_curr_before[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + ref_picsetst_curr_after[HEVCFW_MAX_NUM_REF_PICS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, ref_picsetst_foll[HEVCFW_MAX_NUM_REF_PICS]); +}; + +/* + * This describes the HEVC parser component "Context data", shown in the + * Firmware Memory Layout diagram. This data is the state preserved across + * pictures. It is loaded and saved by the Firmware, but requires the host to + * provide buffer(s) for this. + */ +struct hevcfw_ctx_data { + struct hevcfw_sequence_ps sps; + struct hevcfw_picture_ps pps; + /* + * data from last picture with TemporalId = 0 that is not a RASL, RADL + * or sub-layer non-reference picture + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, prev_pic_order_cnt_lsb); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, prev_pic_order_cnt_msb); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, last_irapnorasl_output_flag); + /* + * Decoded Pictures Buffer holds information about decoded pictures + * needed for further INTER decoding + */ + struct hevcfw_decoded_picture_buffer dpb; + /* Reference Picture Set is determined on per-picture basis */ + struct hevcfw_reference_picture_set rps; + /* + * Reference Picture List is determined using data from Reference + * Picture Set and from Slice (Segment) Header on per-slice basis + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, + ref_pic_list[HEVCFW_NUM_REF_PIC_LISTS][HEVCFW_MAX_NUM_REF_PICS]); + /* + * Reference Picture List used to send reflist to the host, the only + * difference is that missing references are marked + * with HEVCFW_DPB_IDX_INVALID + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, + ref_pic_listhlp[HEVCFW_NUM_REF_PIC_LISTS][HEVCFW_MAX_NUM_REF_PICS]); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, pic_count); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, slice_segment_count); + /* There was EOS NAL detected and no new picture yet */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, eos_detected); + /* This is first picture after EOS NAL */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, first_after_eos); +}; + +#endif /* _HEVCFW_DATA_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/hevc_secure_parser.c b/drivers/media/platform/imagination/vxe-vxd/decoder/hevc_secure_parser.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/hevc_secure_parser.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/hevc_secure_parser.c 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,2895 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * hevc secure data unit parsing API. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * Re-written for upstreming + * Prashanth Kumar Amai + * Sidraya Jayagond + */ + +#include +#include +#include +#include + +#include "bspp_int.h" +#include "hevc_secure_parser.h" +#include "hevcfw_data.h" +#include "pixel_api.h" +#include "swsr.h" +#include "vdec_defs.h" +#include "vdecdd_utils.h" + +#if defined(DEBUG_DECODER_DRIVER) +#define BSPP_HEVC_SYNTAX(fmt, ...) pr_info("[hevc] " fmt, ## __VA_ARGS__) + +#else + +#define BSPP_HEVC_SYNTAX(fmt, ...) +#endif + +static void HEVC_SWSR_U1(unsigned char *what, unsigned char *where, void *swsr_ctx) +{ + *where = swsr_read_bits(swsr_ctx, 1); +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s, u(1) : %u", what, *where); +#endif +} + +static void HEVC_SWSR_UN(unsigned char *what, unsigned int *where, + unsigned char numbits, void *swsr_ctx) +{ + *where = swsr_read_bits(swsr_ctx, numbits); +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s, u(%u) : %u", what, numbits, *where); +#endif +} + +static void HEVC_SWSR_UE(unsigned char *what, unsigned int *where, void *swsr_ctx) +{ + *where = swsr_read_unsigned_expgoulomb(swsr_ctx); +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s, ue(v) : %u", what, *where); +#endif +} + +static void HEVC_SWSR_SE(unsigned char *what, int *where, void *swsr_ctx) +{ + *where = swsr_read_signed_expgoulomb(swsr_ctx); +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s, se(v) : %u", what, *where); +#endif +} + +static void HEVC_SWSR_FN(unsigned char *what, unsigned char *where, + unsigned char numbits, unsigned char pattern, + enum bspp_error_type *bspperror, void *swsr_ctx) +{ + *where = swsr_read_bits(swsr_ctx, numbits); +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s, f(%u) : %u", what, numbits, *where); +#endif + if (*where != pattern) { + *bspperror |= BSPP_ERROR_INVALID_VALUE; + pr_warn("Invalid value of %s (f(%u), expected: %u, got: %u)", + what, numbits, pattern, *where); + } +} + +static void HEVC_UCHECK(unsigned char *what, unsigned int val, + unsigned int expected, + enum bspp_error_type *bspperror) +{ + if (val != expected) { + *bspperror |= BSPP_ERROR_INVALID_VALUE; + pr_warn("Invalid value of %s (expected: %u, got: %u)", + what, expected, val); + } +} + +static void HEVC_RANGEUCHECK(unsigned char *what, unsigned int val, + unsigned int min, unsigned int max, + enum bspp_error_type *bspperror) +{ + if ((min > 0 && val < min) || val > max) { + *bspperror |= BSPP_ERROR_INVALID_VALUE; + pr_warn("Value of %s out of range (expected: [%u, %u], got: %u)", + what, min, max, val); + } +} + +static void HEVC_RANGESCHECK(unsigned char *what, int val, int min, int max, + enum bspp_error_type *bspperror) +{ + if (val < min || val > max) { + *bspperror |= BSPP_ERROR_INVALID_VALUE; + pr_warn("Value of %s out of range (expected: [%d, %d], got: %d)", + what, min, max, val); + } +} + +#define HEVC_STATIC_ASSERT(expr) ((void)sizeof(unsigned char[1 - 2 * !(expr)])) + +#define HEVC_MIN(a, b, type) ({ \ + type __a = a; \ + type __b = b; \ + (((__a) <= (__b)) ? (__a) : (__b)); }) +#define HEVC_MAX(a, b, type) ({ \ + type __a = a; \ + type __b = b; \ + (((__a) >= (__b)) ? (__a) : (__b)); }) +#define HEVC_ALIGN(_val, _alignment, type) ({ \ + type val = _val; \ + type alignment = _alignment; \ + (((val) + (alignment) - 1) & ~((alignment) - 1)); }) + +static const enum pixel_fmt_idc pixelformat_idc[] = { + PIXEL_FORMAT_MONO, + PIXEL_FORMAT_420, + PIXEL_FORMAT_422, + PIXEL_FORMAT_444 +}; + +static enum bspp_error_type bspp_hevc_parse_vps(void *sr_ctx, struct bspp_hevc_vps *vps); + +static void bspp_hevc_sublayhrdparams(void *sr_ctx, + struct bspp_hevc_hrd_parameters *hrdparams, + unsigned char sublayer_id); + +static void bspp_hevc_parsehrdparams(void *sr_ctx, + struct bspp_hevc_hrd_parameters *hrdparams, + unsigned char common_infpresent, + unsigned char max_numsublayers_minus1); + +static enum bspp_error_type bspp_hevc_parsesps(void *sr_ctx, + void *str_res, + struct bspp_hevc_sps *sps); + +static enum bspp_error_type bspp_hevc_parsepps(void *sr_ctx, void *str_res, + struct bspp_hevc_pps *pps); + +static int bspp_hevc_reset_ppsinfo(void *secure_ppsinfo); + +static void bspp_hevc_dotilecalculations(struct bspp_hevc_sps *sps, + struct bspp_hevc_pps *pps); + +static enum bspp_error_type bspp_hevc_parse_slicesegmentheader + (void *sr_ctx, void *str_res, + struct bspp_hevc_slice_segment_header *ssh, + unsigned char nalunit_type, + struct bspp_vps_info **vpsinfo, + struct bspp_sequence_hdr_info **spsinfo, + struct bspp_pps_info **ppsinfo); + +static enum bspp_error_type bspp_hevc_parse_profiletierlevel + (void *sr_ctx, + struct bspp_hevc_profile_tierlevel *ptl, + unsigned char vps_maxsublayers_minus1); + +static void bspp_hevc_getdefault_scalinglist(unsigned char size_id, unsigned char matrix_id, + const unsigned char **default_scalinglist, + unsigned int *size); + +static enum bspp_error_type bspp_hevc_parse_scalinglistdata + (void *sr_ctx, + struct bspp_hevc_scalinglist_data *scaling_listdata); + +static void bspp_hevc_usedefault_scalinglists(struct bspp_hevc_scalinglist_data *scaling_listdata); + +static enum bspp_error_type bspp_hevc_parse_shortterm_refpicset + (void *sr_ctx, + struct bspp_hevc_shortterm_refpicset *st_refpicset, + unsigned char st_rps_idx, + unsigned char in_slice_header); + +static void bspp_hevc_fillcommonseqhdr(struct bspp_hevc_sps *sps, + struct vdec_comsequ_hdrinfo *common_seq); + +static void bspp_hevc_fillpicturehdr(struct vdec_comsequ_hdrinfo *common_seq, + enum hevc_nalunittype nalunit_type, + struct bspp_pict_hdr_info *picture_hdr, + struct bspp_hevc_sps *sps, + struct bspp_hevc_pps *pps, + struct bspp_hevc_vps *vps); + +static void bspp_hevc_fill_fwsps(struct bspp_hevc_sps *sps, + struct hevcfw_sequence_ps *fwsps); + +static void bspp_hevc_fill_fwst_rps(struct bspp_hevc_shortterm_refpicset *strps, + struct hevcfw_short_term_ref_picset *fwstrps); + +static void bspp_hevc_fill_fwpps(struct bspp_hevc_pps *pps, + struct hevcfw_picture_ps *fw_pps); + +static void bspp_hevc_fill_fw_scaling_lists(struct bspp_hevc_pps *pps, + struct bspp_hevc_sps *sps, + struct hevcfw_picture_ps *fw_pps); + +static unsigned int bspp_ceil_log2(unsigned int linear_val); + +static unsigned char bspp_hevc_picture_is_irap(enum hevc_nalunittype nalunit_type); + +static unsigned char bspp_hevc_picture_is_cra(enum hevc_nalunittype nalunit_type); + +static unsigned char bspp_hevc_picture_is_idr(enum hevc_nalunittype nalunit_type); + +static unsigned char bspp_hevc_picture_is_bla(enum hevc_nalunittype nalunit_type); + +static unsigned char bspp_hevc_picture_getnorasl_outputflag + (enum hevc_nalunittype nalunit_type, + struct bspp_hevc_inter_pict_ctx *inter_pict_ctx); + +static unsigned char bspp_hevc_range_extensions_is_enabled + (struct bspp_hevc_profile_tierlevel *profile_tierlevel); + +static int bspp_hevc_unitparser(void *swsr_ctx, struct bspp_unit_data *unitdata) +{ + void *sr_ctx = swsr_ctx; + int result = 0; + enum bspp_error_type parse_err = BSPP_ERROR_NONE; + struct bspp_inter_pict_data *inter_pict_ctx = + unitdata->parse_state->inter_pict_ctx; + unsigned char forbidden_zero_bit = 0; + unsigned char nal_unit_type = 0; + unsigned char nuh_layer_id = 0; + unsigned char nuh_temporal_id_plus1 = 0; + + HEVC_SWSR_FN("forbidden_zero_bit", &forbidden_zero_bit, 1, 0, &parse_err, sr_ctx); + HEVC_SWSR_UN("nal_unit_type", (unsigned int *)&nal_unit_type, 6, sr_ctx); + /* for current version of HEVC nuh_layer_id "shall be equal to 0" */ + HEVC_SWSR_FN("nuh_layer_id", &nuh_layer_id, 6, 0, &parse_err, sr_ctx); + HEVC_SWSR_UN("nuh_temporal_id_plus1", (unsigned int *)&nuh_temporal_id_plus1, 3, sr_ctx); + + switch (unitdata->unit_type) { + case BSPP_UNIT_VPS: + { + struct bspp_hevc_vps *vps = + (struct bspp_hevc_vps *)unitdata->out.vps_info->secure_vpsinfo; + + unitdata->parse_error |= bspp_hevc_parse_vps(sr_ctx, vps); + unitdata->out.vps_info->vps_id = + vps->vps_video_parameter_set_id; + } + break; + + case BSPP_UNIT_SEQUENCE: + { + struct bspp_ddbuf_array_info *tmp; + struct hevcfw_sequence_ps *fwsps; + struct vdec_comsequ_hdrinfo *common_seq; + struct bspp_hevc_sps *sps = + (struct bspp_hevc_sps *)unitdata->out.sequ_hdr_info->secure_sequence_info; + + unitdata->parse_error |= bspp_hevc_parsesps(sr_ctx, + unitdata->str_res_handle, + sps); + unitdata->out.sequ_hdr_info->sequ_hdr_info.sequ_hdr_id = + sps->sps_seq_parameter_set_id; + + tmp = &unitdata->out.sequ_hdr_info->fw_sequence; + /* handle firmware headers */ + fwsps = + (struct hevcfw_sequence_ps *)((unsigned char *)tmp->ddbuf_info.cpu_virt_addr + + tmp->buf_offset); + + bspp_hevc_fill_fwsps(sps, fwsps); + + /* handle common sequence header */ + common_seq = + &unitdata->out.sequ_hdr_info->sequ_hdr_info.com_sequ_hdr_info; + + bspp_hevc_fillcommonseqhdr(sps, common_seq); + } + break; + + case BSPP_UNIT_PPS: + { + struct bspp_ddbuf_array_info *tmp; + struct hevcfw_picture_ps *fw_pps; + struct bspp_hevc_pps *pps = + (struct bspp_hevc_pps *)unitdata->out.pps_info->secure_pps_info; + + unitdata->parse_error |= bspp_hevc_parsepps(sr_ctx, + unitdata->str_res_handle, + pps); + unitdata->out.pps_info->pps_id = pps->pps_pic_parameter_set_id; + + tmp = &unitdata->out.pps_info->fw_pps; + /* handle firmware headers */ + fw_pps = + (struct hevcfw_picture_ps *)((unsigned char *)tmp->ddbuf_info.cpu_virt_addr + + tmp->buf_offset); + bspp_hevc_fill_fwpps(pps, fw_pps); + } + break; + + case BSPP_UNIT_PICTURE: + { + struct bspp_hevc_slice_segment_header ssh; + struct bspp_vps_info *vps_info = NULL; + struct bspp_sequence_hdr_info *sequ_hdr_info = NULL; + struct bspp_hevc_sps *hevc_sps = NULL; + struct bspp_pps_info *ppsinfo = NULL; + enum bspp_error_type parse_error; + struct bspp_ddbuf_array_info *tmp; + struct hevcfw_picture_ps *fw_pps; + struct bspp_pict_data *pictdata; + struct bspp_hevc_pps *pps; + + /* + * EOS has to be attached to picture data, so it can be used + * for NoRaslOutputFlag calculation in FW + */ + inter_pict_ctx->hevc_ctx.eos_detected = 0; + if (nal_unit_type == HEVC_NALTYPE_EOS) { + inter_pict_ctx->hevc_ctx.eos_detected = 1; + break; + } + + parse_error = bspp_hevc_parse_slicesegmentheader(sr_ctx, + unitdata->str_res_handle, + &ssh, + nal_unit_type, + &vps_info, + &sequ_hdr_info, + &ppsinfo); + unitdata->parse_error |= parse_error; + unitdata->slice = 1; + + if (parse_error != BSPP_ERROR_NONE && + parse_error != BSPP_ERROR_CORRECTION_VALIDVALUE) { + result = IMG_ERROR_CANCELLED; + break; + } + + /* if we just started new picture. */ + if (ssh.first_slice_segment_in_pic_flag) { + tmp = &ppsinfo->fw_pps; + /* handle firmware headers */ + fw_pps = + (struct hevcfw_picture_ps *)((unsigned char *)tmp->ddbuf_info.cpu_virt_addr + + tmp->buf_offset); + + inter_pict_ctx->hevc_ctx.first_after_eos = 0; + if (inter_pict_ctx->hevc_ctx.eos_detected) { + inter_pict_ctx->hevc_ctx.first_after_eos = 1; + inter_pict_ctx->hevc_ctx.eos_detected = 0; + } + + /* fill common picture header */ + bspp_hevc_fillpicturehdr(&sequ_hdr_info->sequ_hdr_info.com_sequ_hdr_info, + (enum hevc_nalunittype)nal_unit_type, + unitdata->out.pict_hdr_info, + (struct bspp_hevc_sps *) + sequ_hdr_info->secure_sequence_info, + (struct bspp_hevc_pps *)ppsinfo->secure_pps_info, + (struct bspp_hevc_vps *)vps_info->secure_vpsinfo); + + bspp_hevc_fill_fw_scaling_lists(ppsinfo->secure_pps_info, + sequ_hdr_info->secure_sequence_info, + fw_pps); + + pictdata = &unitdata->out.pict_hdr_info->pict_aux_data; + /* + * We have no container for the PPS that passes down + * to the kernel, for this reason the hevc secure parser + * needs to populate that info into the picture + * header PictAuxData. + */ + pictdata->bufmap_id = ppsinfo->bufmap_id; + pictdata->buf_offset = ppsinfo->buf_offset; + pictdata->pic_data = fw_pps; + pictdata->id = fw_pps->pps_pic_parameter_set_id; + pictdata->size = sizeof(*fw_pps); + + ppsinfo->ref_count++; + + /* new Coded Video Sequence indication */ + if (nal_unit_type == HEVC_NALTYPE_IDR_W_RADL || + nal_unit_type == HEVC_NALTYPE_IDR_N_LP || + nal_unit_type == HEVC_NALTYPE_BLA_N_LP || + nal_unit_type == HEVC_NALTYPE_BLA_W_RADL || + nal_unit_type == HEVC_NALTYPE_BLA_W_LP || + nal_unit_type == HEVC_NALTYPE_CRA) { + unitdata->new_closed_gop = 1; + inter_pict_ctx->hevc_ctx.seq_pic_count = 0; + } + + /* Attach SEI data to the picture. */ + if (!inter_pict_ctx->hevc_ctx.sei_info_attached_to_pic) { + /* + * If there is already a non-empty SEI list + * available + */ + if (inter_pict_ctx->hevc_ctx.sei_rawdata_list) { + /* attach it to the picture header. */ + unitdata->out.pict_hdr_info->hevc_pict_hdr_info.raw_sei_datalist_firstfield + = + (void *)inter_pict_ctx->hevc_ctx.sei_rawdata_list; + inter_pict_ctx->hevc_ctx.sei_info_attached_to_pic = 1; + } else { + /* Otherwise expose a handle a picture header field to + * attach SEI list later. + */ + inter_pict_ctx->hevc_ctx.hndl_pichdr_sei_rawdata_list = + &unitdata->out.pict_hdr_info->hevc_pict_hdr_info.raw_sei_datalist_firstfield; + } + } + + /* Attach raw VUI data to the picture header. */ + hevc_sps = (struct bspp_hevc_sps *)sequ_hdr_info->secure_sequence_info; + if (hevc_sps->vui_raw_data) { + hevc_sps->vui_raw_data->ref_count++; + unitdata->out.pict_hdr_info->hevc_pict_hdr_info.raw_vui_data = + (void *)hevc_sps->vui_raw_data; + } + + inter_pict_ctx->hevc_ctx.seq_pic_count++; + + /* NoOutputOfPriorPicsFlag */ + inter_pict_ctx->not_dpb_flush = 0; + if (unitdata->new_closed_gop && + bspp_hevc_picture_is_irap((enum hevc_nalunittype)nal_unit_type) && + bspp_hevc_picture_getnorasl_outputflag((enum hevc_nalunittype) + nal_unit_type, + &inter_pict_ctx->hevc_ctx)) { + if (bspp_hevc_picture_is_cra((enum hevc_nalunittype)nal_unit_type)) + inter_pict_ctx->not_dpb_flush = 1; + else + inter_pict_ctx->not_dpb_flush = + ssh.no_output_of_prior_pics_flag; + } + + unitdata->parse_state->next_pic_is_new = 0; + } + + pps = (struct bspp_hevc_pps *)ppsinfo->secure_pps_info; + unitdata->pict_sequ_hdr_id = pps->pps_seq_parameter_set_id; + } + break; + + case BSPP_UNIT_UNCLASSIFIED: + case BSPP_UNIT_NON_PICTURE: + case BSPP_UNIT_UNSUPPORTED: + break; + + default: + VDEC_ASSERT("Unknown BSPP Unit Type" == NULL); + break; + } + + return result; +} + +static void bspp_hevc_initialiseparsing(struct bspp_parse_state *parse_state) +{ + /* Indicate that SEI info has not yet been attached to this picture. */ + parse_state->inter_pict_ctx->hevc_ctx.sei_info_attached_to_pic = 0; +} + +static void bspp_hevc_finaliseparsing(void *str_alloc, struct bspp_parse_state *parse_state) +{ + /* + * If SEI info has not yet been attached to the picture and + * there is anything to be attached. + */ + if (!parse_state->inter_pict_ctx->hevc_ctx.sei_info_attached_to_pic && + parse_state->inter_pict_ctx->hevc_ctx.sei_rawdata_list) { + /* attach the SEI list if there is a handle provided for that. */ + if (parse_state->inter_pict_ctx->hevc_ctx.hndl_pichdr_sei_rawdata_list) { + /* Attach the raw SEI list to the picture. */ + *parse_state->inter_pict_ctx->hevc_ctx.hndl_pichdr_sei_rawdata_list = + (void *)parse_state->inter_pict_ctx->hevc_ctx.sei_rawdata_list; + /* Reset the inter-picture data. */ + parse_state->inter_pict_ctx->hevc_ctx.hndl_pichdr_sei_rawdata_list = NULL; + } else { + /* Nowhere to attach the raw SEI list, so just free it. */ + bspp_freeraw_sei_datalist + (str_alloc, parse_state->inter_pict_ctx->hevc_ctx.sei_rawdata_list); + } + } + + /* Indicate that SEI info has been attached to the picture. */ + parse_state->inter_pict_ctx->hevc_ctx.sei_info_attached_to_pic = 1; + /* Reset the inter-picture SEI list. */ + parse_state->inter_pict_ctx->hevc_ctx.sei_rawdata_list = NULL; +} + +static enum bspp_error_type bspp_hevc_parse_vps(void *sr_ctx, struct bspp_hevc_vps *vps) +{ + unsigned int parse_err = BSPP_ERROR_NONE; + unsigned int i, j; + + VDEC_ASSERT(vps); + VDEC_ASSERT(sr_ctx); + + memset(vps, 0, sizeof(struct bspp_hevc_vps)); + + HEVC_SWSR_UN("vps_video_parameter_set_id", + (unsigned int *)&vps->vps_video_parameter_set_id, 4, sr_ctx); + HEVC_SWSR_UN("vps_reserved_three_2bits", + (unsigned int *)&vps->vps_reserved_three_2bits, 2, sr_ctx); + HEVC_SWSR_UN("vps_max_layers_minus1", + (unsigned int *)&vps->vps_max_layers_minus1, 6, sr_ctx); + HEVC_SWSR_UN("vps_max_sub_layers_minus1", + (unsigned int *)&vps->vps_max_sub_layers_minus1, 3, sr_ctx); + HEVC_RANGEUCHECK("vps_max_sub_layers_minus1", vps->vps_max_sub_layers_minus1, 0, + HEVC_MAX_NUM_SUBLAYERS - 1, &parse_err); + HEVC_SWSR_U1("vps_temporal_id_nesting_flag", + &vps->vps_temporal_id_nesting_flag, sr_ctx); + HEVC_SWSR_UN("vps_reserved_0xffff_16bits", + (unsigned int *)&vps->vps_reserved_0xffff_16bits, 16, sr_ctx); + + if (vps->vps_max_sub_layers_minus1 == 0) + HEVC_UCHECK("vps_temporal_id_nesting_flag", + vps->vps_temporal_id_nesting_flag, 1, &parse_err); + + parse_err |= bspp_hevc_parse_profiletierlevel(sr_ctx, &vps->profiletierlevel, + vps->vps_max_sub_layers_minus1); + + HEVC_SWSR_U1("vps_sub_layer_ordering_info_present_flag", + &vps->vps_sub_layer_ordering_info_present_flag, sr_ctx); + for (i = vps->vps_sub_layer_ordering_info_present_flag ? + 0 : vps->vps_max_sub_layers_minus1; + i <= vps->vps_max_sub_layers_minus1; ++i) { + HEVC_SWSR_UE("vps_max_dec_pic_buffering_minus1", + (unsigned int *)&vps->vps_max_dec_pic_buffering_minus1[i], sr_ctx); + HEVC_SWSR_UE("vps_max_num_reorder_pics", + (unsigned int *)&vps->vps_max_num_reorder_pics[i], sr_ctx); + HEVC_SWSR_UE("vps_max_latency_increase_plus1", + (unsigned int *)&vps->vps_max_latency_increase_plus1[i], sr_ctx); + } + + HEVC_SWSR_UN("vps_max_layer_id", (unsigned int *)&vps->vps_max_layer_id, 6, sr_ctx); + HEVC_SWSR_UE("vps_num_layer_sets_minus1", + (unsigned int *)&vps->vps_num_layer_sets_minus1, sr_ctx); + + for (i = 1; i <= vps->vps_num_layer_sets_minus1; ++i) { + for (j = 0; j <= vps->vps_max_layer_id; ++j) { + HEVC_SWSR_U1("layer_id_included_flag", + &vps->layer_id_included_flag[i][j], sr_ctx); + } + } + + HEVC_SWSR_U1("vps_timing_info_present_flag", &vps->vps_timing_info_present_flag, sr_ctx); + if (vps->vps_timing_info_present_flag) { + HEVC_SWSR_UN("vps_num_units_in_tick", + (unsigned int *)&vps->vps_num_units_in_tick, 32, sr_ctx); + HEVC_SWSR_UN("vps_time_scale", + (unsigned int *)&vps->vps_time_scale, 32, sr_ctx); + HEVC_SWSR_U1("vps_poc_proportional_to_timing_flag", + &vps->vps_poc_proportional_to_timing_flag, sr_ctx); + if (vps->vps_poc_proportional_to_timing_flag) + HEVC_SWSR_UE("vps_num_ticks_poc_diff_one_minus1", + (unsigned int *)&vps->vps_num_ticks_poc_diff_one_minus1, + sr_ctx); + + HEVC_SWSR_UE("vps_num_hrd_parameters", + (unsigned int *)&vps->vps_num_hrd_parameters, sr_ctx); + + /* consume hrd_parameters */ + for (i = 0; i < vps->vps_num_hrd_parameters; i++) { + unsigned short hrd_layer_set_idx; + unsigned char cprms_present_flag = 1; + struct bspp_hevc_hrd_parameters hrdparams; + + HEVC_SWSR_UE("hrd_layer_set_idx", + (unsigned int *)&hrd_layer_set_idx, sr_ctx); + if (i > 0) + HEVC_SWSR_U1("cprms_present_flag", &cprms_present_flag, sr_ctx); + + bspp_hevc_parsehrdparams(sr_ctx, &hrdparams, + cprms_present_flag, + vps->vps_max_sub_layers_minus1); + } + } + HEVC_SWSR_U1("vps_extension_flag", &vps->vps_extension_flag, sr_ctx); + + return (enum bspp_error_type)parse_err; +} + +static void bspp_hevc_sublayhrdparams(void *sr_ctx, + struct bspp_hevc_hrd_parameters *hrdparams, + unsigned char sublayer_id) +{ + unsigned char i; + unsigned char cpb_cnt = hrdparams->cpb_cnt_minus1[sublayer_id]; + struct bspp_hevc_sublayer_hrd_parameters *sublay_hrdparams = + &hrdparams->sublayhrdparams[sublayer_id]; + + VDEC_ASSERT(sr_ctx); + VDEC_ASSERT(hrdparams); + VDEC_ASSERT(cpb_cnt < HEVC_MAX_CPB_COUNT); + VDEC_ASSERT(sublayer_id < HEVC_MAX_NUM_SUBLAYERS); + + for (i = 0; i <= cpb_cnt; i++) { + HEVC_SWSR_UE("bit_rate_value_minus1", + (unsigned int *)&sublay_hrdparams->bit_rate_value_minus1[i], sr_ctx); + HEVC_SWSR_UE("cpb_size_value_minus1", + (unsigned int *)&sublay_hrdparams->cpb_size_value_minus1[i], sr_ctx); + if (hrdparams->sub_pic_hrd_params_present_flag) { + HEVC_SWSR_UE("cpb_size_du_value_minus1", + (unsigned int *) + &sublay_hrdparams->cpb_size_du_value_minus1[i], + sr_ctx); + HEVC_SWSR_UE("bit_rate_du_value_minus1", + (unsigned int *) + &sublay_hrdparams->bit_rate_du_value_minus1[i], + sr_ctx); + } + HEVC_SWSR_U1("cbr_flag", &sublay_hrdparams->cbr_flag[i], sr_ctx); + } +} + +static void bspp_hevc_parsehrdparams(void *sr_ctx, + struct bspp_hevc_hrd_parameters *hrdparams, + unsigned char common_infpresent, + unsigned char max_numsublayers_minus1) +{ + unsigned char i; + + VDEC_ASSERT(sr_ctx); + VDEC_ASSERT(hrdparams); + VDEC_ASSERT(max_numsublayers_minus1 < HEVC_MAX_NUM_SUBLAYERS); + + memset(hrdparams, 0, sizeof(struct bspp_hevc_hrd_parameters)); + + if (common_infpresent) { + HEVC_SWSR_U1("nal_hrd_parameters_present_flag", + &hrdparams->nal_hrd_parameters_present_flag, sr_ctx); + HEVC_SWSR_U1("vcl_hrd_parameters_present_flag", + &hrdparams->vcl_hrd_parameters_present_flag, sr_ctx); + if (hrdparams->nal_hrd_parameters_present_flag || + hrdparams->vcl_hrd_parameters_present_flag) { + HEVC_SWSR_U1("sub_pic_hrd_params_present_flag", + &hrdparams->sub_pic_hrd_params_present_flag, + sr_ctx); + if (hrdparams->sub_pic_hrd_params_present_flag) { + HEVC_SWSR_UN("tick_divisor_minus2", + (unsigned int *)&hrdparams->tick_divisor_minus2, + 8, sr_ctx); + HEVC_SWSR_UN + ("du_cpb_removal_delay_increment_length_minus1", + (unsigned int *) + &hrdparams->du_cpb_removal_delay_increment_length_minus1, + 5, sr_ctx); + HEVC_SWSR_U1("sub_pic_cpb_params_in_pic_timing_sei_flag", + &hrdparams->sub_pic_cpb_params_in_pic_timing_sei_flag, + sr_ctx); + HEVC_SWSR_UN("dpb_output_delay_du_length_minus1", + (unsigned int *) + &hrdparams->dpb_output_delay_du_length_minus1, + 5, sr_ctx); + } + HEVC_SWSR_UN("bit_rate_scale", + (unsigned int *)&hrdparams->bit_rate_scale, 4, sr_ctx); + HEVC_SWSR_UN("cpb_size_scale", + (unsigned int *)&hrdparams->cpb_size_scale, 4, sr_ctx); + if (hrdparams->sub_pic_hrd_params_present_flag) + HEVC_SWSR_UN("cpb_size_du_scale", + (unsigned int *)&hrdparams->cpb_size_du_scale, + 4, sr_ctx); + + HEVC_SWSR_UN("initial_cpb_removal_delay_length_minus1", + (unsigned int *) + &hrdparams->initial_cpb_removal_delay_length_minus1, + 5, sr_ctx); + HEVC_SWSR_UN("au_cpb_removal_delay_length_minus1", + (unsigned int *)&hrdparams->au_cpb_removal_delay_length_minus1, + 5, sr_ctx); + HEVC_SWSR_UN("dpb_output_delay_length_minus1", + (unsigned int *)&hrdparams->dpb_output_delay_length_minus1, + 5, sr_ctx); + } + } + for (i = 0; i <= max_numsublayers_minus1; i++) { + HEVC_SWSR_U1("fixed_pic_rate_general_flag", + &hrdparams->fixed_pic_rate_general_flag[i], sr_ctx); + hrdparams->fixed_pic_rate_within_cvs_flag[i] = + hrdparams->fixed_pic_rate_general_flag[i]; + if (!hrdparams->fixed_pic_rate_general_flag[i]) + HEVC_SWSR_U1("fixed_pic_rate_within_cvs_flag", + &hrdparams->fixed_pic_rate_within_cvs_flag[i], + sr_ctx); + + if (hrdparams->fixed_pic_rate_within_cvs_flag[i]) + HEVC_SWSR_UE("elemental_duration_in_tc_minus1", + (unsigned int *)&hrdparams->elemental_duration_in_tc_minus1[i], + sr_ctx); + else + HEVC_SWSR_U1("low_delay_hrd_flag", + &hrdparams->low_delay_hrd_flag[i], sr_ctx); + + if (!hrdparams->low_delay_hrd_flag[i]) + HEVC_SWSR_UE("cpb_cnt_minus1", + (unsigned int *)&hrdparams->cpb_cnt_minus1[i], sr_ctx); + + if (hrdparams->nal_hrd_parameters_present_flag) + bspp_hevc_sublayhrdparams(sr_ctx, hrdparams, i); + + if (hrdparams->vcl_hrd_parameters_present_flag) + bspp_hevc_sublayhrdparams(sr_ctx, hrdparams, i); + } +} + +static enum bspp_error_type bspp_hevc_parsevui_parameters + (void *sr_ctx, + struct bspp_hevc_vui_params *vui_params, + unsigned char sps_max_sub_layers_minus1) +{ + enum bspp_error_type parse_err = BSPP_ERROR_NONE; + + VDEC_ASSERT(sr_ctx); + VDEC_ASSERT(vui_params); + + memset(vui_params, 0, sizeof(struct bspp_hevc_vui_params)); + + HEVC_SWSR_U1("aspect_ratio_info_present_flag", + &vui_params->aspect_ratio_info_present_flag, sr_ctx); + if (vui_params->aspect_ratio_info_present_flag) { + HEVC_SWSR_UN("aspect_ratio_idc", + (unsigned int *)&vui_params->aspect_ratio_idc, 8, sr_ctx); + if (vui_params->aspect_ratio_idc == HEVC_EXTENDED_SAR) { + HEVC_SWSR_UN("sar_width", + (unsigned int *)&vui_params->sar_width, 16, sr_ctx); + HEVC_SWSR_UN("sar_height", + (unsigned int *)&vui_params->sar_height, 16, sr_ctx); + } + } + HEVC_SWSR_U1("overscan_info_present_flag", + &vui_params->overscan_info_present_flag, sr_ctx); + + if (vui_params->overscan_info_present_flag) + HEVC_SWSR_U1("overscan_appropriate_flag", + &vui_params->overscan_appropriate_flag, sr_ctx); + + HEVC_SWSR_U1("video_signal_type_present_flag", + &vui_params->video_signal_type_present_flag, sr_ctx); + + if (vui_params->video_signal_type_present_flag) { + HEVC_SWSR_UN("video_format", + (unsigned int *)&vui_params->video_format, 3, sr_ctx); + HEVC_SWSR_U1("video_full_range_flag", + &vui_params->video_full_range_flag, sr_ctx); + HEVC_SWSR_U1("colour_description_present_flag", + &vui_params->colour_description_present_flag, + sr_ctx); + if (vui_params->colour_description_present_flag) { + HEVC_SWSR_UN("colour_primaries", + (unsigned int *)&vui_params->colour_primaries, 8, sr_ctx); + HEVC_SWSR_UN("transfer_characteristics", + (unsigned int *)&vui_params->transfer_characteristics, + 8, sr_ctx); + HEVC_SWSR_UN("matrix_coeffs", + (unsigned int *)&vui_params->matrix_coeffs, 8, sr_ctx); + } + } + + HEVC_SWSR_U1("chroma_loc_info_present_flag", + &vui_params->chroma_loc_info_present_flag, sr_ctx); + if (vui_params->chroma_loc_info_present_flag) { + HEVC_SWSR_UE("chroma_sample_loc_type_top_field", + (unsigned int *)&vui_params->chroma_sample_loc_type_top_field, + sr_ctx); + HEVC_RANGEUCHECK("chroma_sample_loc_type_top_field", + vui_params->chroma_sample_loc_type_top_field, + 0, 5, &parse_err); + HEVC_SWSR_UE("chroma_sample_loc_type_bottom_field", + (unsigned int *)&vui_params->chroma_sample_loc_type_bottom_field, + sr_ctx); + HEVC_RANGEUCHECK("chroma_sample_loc_type_bottom_field", + vui_params->chroma_sample_loc_type_bottom_field, + 0, 5, &parse_err); + } + HEVC_SWSR_U1("neutral_chroma_indication_flag", + &vui_params->neutral_chroma_indication_flag, sr_ctx); + HEVC_SWSR_U1("field_seq_flag", + &vui_params->field_seq_flag, sr_ctx); + HEVC_SWSR_U1("frame_field_info_present_flag", + &vui_params->frame_field_info_present_flag, sr_ctx); + HEVC_SWSR_U1("default_display_window_flag", + &vui_params->default_display_window_flag, sr_ctx); + if (vui_params->default_display_window_flag) { + HEVC_SWSR_UE("def_disp_win_left_offset", + (unsigned int *)&vui_params->def_disp_win_left_offset, sr_ctx); + HEVC_SWSR_UE("def_disp_win_right_offset", + (unsigned int *)&vui_params->def_disp_win_right_offset, sr_ctx); + HEVC_SWSR_UE("def_disp_win_top_offset", + (unsigned int *)&vui_params->def_disp_win_top_offset, sr_ctx); + HEVC_SWSR_UE("def_disp_win_bottom_offset", + (unsigned int *)&vui_params->def_disp_win_bottom_offset, sr_ctx); + } + HEVC_SWSR_U1("vui_timing_info_present_flag", + &vui_params->vui_timing_info_present_flag, sr_ctx); + if (vui_params->vui_timing_info_present_flag) { + HEVC_SWSR_UN("vui_num_units_in_tick", + (unsigned int *)&vui_params->vui_num_units_in_tick, 32, sr_ctx); + HEVC_SWSR_UN("vui_time_scale", + (unsigned int *)&vui_params->vui_time_scale, 32, sr_ctx); + HEVC_SWSR_U1("vui_poc_proportional_to_timing_flag", + &vui_params->vui_poc_proportional_to_timing_flag, + sr_ctx); + if (vui_params->vui_poc_proportional_to_timing_flag) + HEVC_SWSR_UE("vui_num_ticks_poc_diff_one_minus1", + (unsigned int *)&vui_params->vui_num_ticks_poc_diff_one_minus1, + sr_ctx); + + HEVC_SWSR_U1("vui_hrd_parameters_present_flag", + &vui_params->vui_hrd_parameters_present_flag, + sr_ctx); + if (vui_params->vui_hrd_parameters_present_flag) + bspp_hevc_parsehrdparams(sr_ctx, &vui_params->vui_hrd_params, + 1, sps_max_sub_layers_minus1); + } + HEVC_SWSR_U1("bitstream_restriction_flag", + &vui_params->bitstream_restriction_flag, sr_ctx); + + if (vui_params->bitstream_restriction_flag) { + HEVC_SWSR_U1("tiles_fixed_structure_flag", + &vui_params->tiles_fixed_structure_flag, sr_ctx); + HEVC_SWSR_U1("motion_vectors_over_pic_boundaries_flag", + &vui_params->motion_vectors_over_pic_boundaries_flag, + sr_ctx); + HEVC_SWSR_U1("restricted_ref_pic_lists_flag", + &vui_params->restricted_ref_pic_lists_flag, sr_ctx); + + HEVC_SWSR_UE("min_spatial_segmentation_idc", + (unsigned int *)&vui_params->min_spatial_segmentation_idc, sr_ctx); + HEVC_RANGEUCHECK("min_spatial_segmentation_idc", + vui_params->min_spatial_segmentation_idc, + 0, 4095, &parse_err); + + HEVC_SWSR_UE("max_bytes_per_pic_denom", + (unsigned int *)&vui_params->max_bytes_per_pic_denom, sr_ctx); + HEVC_RANGEUCHECK("max_bytes_per_pic_denom", vui_params->max_bytes_per_pic_denom, + 0, 16, &parse_err); + + HEVC_SWSR_UE("max_bits_per_min_cu_denom", + (unsigned int *)&vui_params->max_bits_per_min_cu_denom, sr_ctx); + HEVC_RANGEUCHECK("max_bits_per_min_cu_denom", vui_params->max_bits_per_min_cu_denom, + 0, 16, &parse_err); + + HEVC_SWSR_UE("log2_max_mv_length_horizontal", + (unsigned int *)&vui_params->log2_max_mv_length_horizontal, sr_ctx); + HEVC_RANGEUCHECK("log2_max_mv_length_horizontal", + vui_params->log2_max_mv_length_horizontal, + 0, 16, &parse_err); + + HEVC_SWSR_UE("log2_max_mv_length_vertical", + (unsigned int *)&vui_params->log2_max_mv_length_vertical, sr_ctx); + HEVC_RANGEUCHECK("log2_max_mv_length_vertical", + vui_params->log2_max_mv_length_vertical, + 0, 15, &parse_err); + } + + return parse_err; +} + +static enum bspp_error_type bspp_hevc_parse_spsrange_extensions + (void *sr_ctx, + struct bspp_hevc_sps_range_exts *range_exts) +{ + enum bspp_error_type parse_err = BSPP_ERROR_NONE; + + VDEC_ASSERT(sr_ctx); + VDEC_ASSERT(range_exts); + + memset(range_exts, 0, sizeof(struct bspp_hevc_sps_range_exts)); + + HEVC_SWSR_U1("transform_skip_rotation_enabled_flag", + &range_exts->transform_skip_rotation_enabled_flag, sr_ctx); + HEVC_SWSR_U1("transform_skip_context_enabled_flag", + &range_exts->transform_skip_context_enabled_flag, sr_ctx); + HEVC_SWSR_U1("implicit_rdpcm_enabled_flag", + &range_exts->implicit_rdpcm_enabled_flag, sr_ctx); + HEVC_SWSR_U1("explicit_rdpcm_enabled_flag", + &range_exts->explicit_rdpcm_enabled_flag, sr_ctx); + HEVC_SWSR_U1("extended_precision_processing_flag", + &range_exts->extended_precision_processing_flag, sr_ctx); + HEVC_UCHECK("extended_precision_processing_flag", + range_exts->extended_precision_processing_flag, + 0, &parse_err); + HEVC_SWSR_U1("intra_smoothing_disabled_flag", + &range_exts->intra_smoothing_disabled_flag, sr_ctx); + HEVC_SWSR_U1("high_precision_offsets_enabled_flag", + &range_exts->high_precision_offsets_enabled_flag, sr_ctx); + HEVC_SWSR_U1("persistent_rice_adaptation_enabled_flag", + &range_exts->persistent_rice_adaptation_enabled_flag, + sr_ctx); + HEVC_SWSR_U1("cabac_bypass_alignment_enabled_flag", + &range_exts->cabac_bypass_alignment_enabled_flag, sr_ctx); + + return parse_err; +} + +static unsigned char +bspp_hevc_checksps_range_extensions(struct bspp_hevc_sps_range_exts *range_exts) +{ + VDEC_ASSERT(range_exts); + + if (range_exts->transform_skip_rotation_enabled_flag || + range_exts->transform_skip_context_enabled_flag || + range_exts->implicit_rdpcm_enabled_flag || + range_exts->explicit_rdpcm_enabled_flag || + range_exts->extended_precision_processing_flag || + range_exts->intra_smoothing_disabled_flag || + range_exts->persistent_rice_adaptation_enabled_flag || + range_exts->cabac_bypass_alignment_enabled_flag) + return 1; + /* + * Note: high_precision_offsets_enabled_flag is supported even + * if hw capabilities (bHevcRangeExt is not set) + */ + return 0; +} + +static enum bspp_error_type bspp_hevc_parsesps(void *sr_ctx, + void *str_res, + struct bspp_hevc_sps *sps) +{ + enum bspp_error_type parse_err = BSPP_ERROR_NONE; + unsigned char i; + unsigned int min_cblog2_size_y; + + if (!sr_ctx || !sps) { + VDEC_ASSERT(0); + return BSPP_ERROR_INVALID_VALUE; + } + + memset(sps, 0, sizeof(struct bspp_hevc_sps)); + + HEVC_SWSR_UN("sps_video_parameter_set_id", + (unsigned int *)&sps->sps_video_parameter_set_id, 4, sr_ctx); + HEVC_SWSR_UN("sps_max_sub_layers_minus1", + (unsigned int *)&sps->sps_max_sub_layers_minus1, 3, sr_ctx); + HEVC_RANGEUCHECK("sps_max_sub_layers_minus1", sps->sps_max_sub_layers_minus1, 0, + HEVC_MAX_NUM_SUBLAYERS - 1, &parse_err); + HEVC_SWSR_U1("sps_temporal_id_nesting_flag", + &sps->sps_temporal_id_nesting_flag, sr_ctx); + + if (sps->sps_max_sub_layers_minus1 == 0) + HEVC_UCHECK("sps_temporal_id_nesting_flag", + sps->sps_temporal_id_nesting_flag, 1, &parse_err); + + parse_err |= bspp_hevc_parse_profiletierlevel + (sr_ctx, &sps->profile_tier_level, + sps->sps_max_sub_layers_minus1); + + HEVC_SWSR_UE("sps_seq_parameter_set_id", + (unsigned int *)&sps->sps_seq_parameter_set_id, sr_ctx); + HEVC_RANGEUCHECK("sps_seq_parameter_set_id", sps->sps_seq_parameter_set_id, 0, + HEVC_MAX_SPS_COUNT - 1, &parse_err); + + HEVC_SWSR_UE("chroma_format_idc", (unsigned int *)&sps->chroma_format_idc, sr_ctx); + HEVC_RANGEUCHECK("chroma_format_idc", sps->chroma_format_idc, 0, 3, &parse_err); + + if (sps->chroma_format_idc == 3) + HEVC_SWSR_U1("separate_colour_plane_flag", + &sps->separate_colour_plane_flag, sr_ctx); + + HEVC_SWSR_UE("pic_width_in_luma_samples", + (unsigned int *)&sps->pic_width_in_luma_samples, sr_ctx); + HEVC_SWSR_UE("pic_height_in_luma_samples", + (unsigned int *)&sps->pic_height_in_luma_samples, sr_ctx); + + HEVC_SWSR_U1("conformance_window_flag", &sps->conformance_window_flag, sr_ctx); + + if (sps->pic_width_in_luma_samples == 0 || + sps->pic_height_in_luma_samples == 0) { + pr_warn("Invalid video dimensions (%u, %u)", + sps->pic_width_in_luma_samples, + sps->pic_height_in_luma_samples); + parse_err |= BSPP_ERROR_UNRECOVERABLE; + } + + if (sps->conformance_window_flag) { + HEVC_SWSR_UE("conf_win_left_offset", + (unsigned int *)&sps->conf_win_left_offset, sr_ctx); + HEVC_SWSR_UE("conf_win_right_offset", + (unsigned int *)&sps->conf_win_right_offset, sr_ctx); + HEVC_SWSR_UE("conf_win_top_offset", + (unsigned int *)&sps->conf_win_top_offset, sr_ctx); + HEVC_SWSR_UE("conf_win_bottom_offset", + (unsigned int *)&sps->conf_win_bottom_offset, sr_ctx); + } + + HEVC_SWSR_UE("bit_depth_luma_minus8", + (unsigned int *)&sps->bit_depth_luma_minus8, sr_ctx); + HEVC_RANGEUCHECK("bit_depth_luma_minus8", + sps->bit_depth_luma_minus8, 0, 6, &parse_err); + HEVC_SWSR_UE("bit_depth_chroma_minus8", + (unsigned int *)&sps->bit_depth_chroma_minus8, sr_ctx); + HEVC_RANGEUCHECK("bit_depth_chroma_minus8", sps->bit_depth_chroma_minus8, + 0, 6, &parse_err); + + HEVC_SWSR_UE("log2_max_pic_order_cnt_lsb_minus4", + (unsigned int *)&sps->log2_max_pic_order_cnt_lsb_minus4, sr_ctx); + HEVC_RANGEUCHECK("log2_max_pic_order_cnt_lsb_minus4", + sps->log2_max_pic_order_cnt_lsb_minus4, + 0, 12, &parse_err); + + HEVC_SWSR_U1("sps_sub_layer_ordering_info_present_flag", + &sps->sps_sub_layer_ordering_info_present_flag, sr_ctx); + for (i = (sps->sps_sub_layer_ordering_info_present_flag ? + 0 : sps->sps_max_sub_layers_minus1); + i <= sps->sps_max_sub_layers_minus1; ++i) { + HEVC_SWSR_UE("sps_max_dec_pic_buffering_minus1", + (unsigned int *)&sps->sps_max_dec_pic_buffering_minus1[i], sr_ctx); + HEVC_SWSR_UE("sps_max_num_reorder_pics", + (unsigned int *)&sps->sps_max_num_reorder_pics[i], sr_ctx); + HEVC_SWSR_UE("sps_max_latency_increase_plus1", + (unsigned int *)&sps->sps_max_latency_increase_plus1[i], sr_ctx); + } + + HEVC_SWSR_UE("log2_min_luma_coding_block_size_minus3", + (unsigned int *)&sps->log2_min_luma_coding_block_size_minus3, sr_ctx); + HEVC_SWSR_UE("log2_diff_max_min_luma_coding_block_size", + (unsigned int *)&sps->log2_diff_max_min_luma_coding_block_size, sr_ctx); + HEVC_SWSR_UE("log2_min_transform_block_size_minus2", + (unsigned int *)&sps->log2_min_transform_block_size_minus2, sr_ctx); + HEVC_SWSR_UE("log2_diff_max_min_transform_block_size", + (unsigned int *)&sps->log2_diff_max_min_transform_block_size, sr_ctx); + HEVC_SWSR_UE("max_transform_hierarchy_depth_inter", + (unsigned int *)&sps->max_transform_hierarchy_depth_inter, sr_ctx); + HEVC_SWSR_UE("max_transform_hierarchy_depth_intra", + (unsigned int *)&sps->max_transform_hierarchy_depth_intra, sr_ctx); + + HEVC_SWSR_U1("scaling_list_enabled_flag", &sps->scaling_list_enabled_flag, sr_ctx); + + if (sps->scaling_list_enabled_flag) { + HEVC_SWSR_U1("sps_scaling_list_data_present_flag", + &sps->sps_scaling_list_data_present_flag, sr_ctx); + if (sps->sps_scaling_list_data_present_flag) + parse_err |= bspp_hevc_parse_scalinglistdata(sr_ctx, + &sps->scalinglist_data); + else + bspp_hevc_usedefault_scalinglists(&sps->scalinglist_data); + } + + HEVC_SWSR_U1("amp_enabled_flag", &sps->amp_enabled_flag, sr_ctx); + HEVC_SWSR_U1("sample_adaptive_offset_enabled_flag", + &sps->sample_adaptive_offset_enabled_flag, sr_ctx); + HEVC_SWSR_U1("pcm_enabled_flag", &sps->pcm_enabled_flag, sr_ctx); + + if (sps->pcm_enabled_flag) { + HEVC_SWSR_UN("pcm_sample_bit_depth_luma_minus1", + (unsigned int *)&sps->pcm_sample_bit_depth_luma_minus1, + 4, sr_ctx); + HEVC_SWSR_UN("pcm_sample_bit_depth_chroma_minus1", + (unsigned int *)&sps->pcm_sample_bit_depth_chroma_minus1, + 4, sr_ctx); + HEVC_SWSR_UE("log2_min_pcm_luma_coding_block_size_minus3", + (unsigned int *)&sps->log2_min_pcm_luma_coding_block_size_minus3, + sr_ctx); + HEVC_SWSR_UE("log2_diff_max_min_pcm_luma_coding_block_size", + (unsigned int *)&sps->log2_diff_max_min_pcm_luma_coding_block_size, + sr_ctx); + HEVC_SWSR_U1("pcm_loop_filter_disabled_flag", + &sps->pcm_loop_filter_disabled_flag, sr_ctx); + } else { + sps->pcm_sample_bit_depth_luma_minus1 = 7; + sps->pcm_sample_bit_depth_chroma_minus1 = 7; + sps->log2_min_pcm_luma_coding_block_size_minus3 = 0; + sps->log2_diff_max_min_pcm_luma_coding_block_size = 2; + } + + HEVC_SWSR_UE("num_short_term_ref_pic_sets", + (unsigned int *)&sps->num_short_term_ref_pic_sets, sr_ctx); + HEVC_RANGEUCHECK("num_short_term_ref_pic_sets", sps->num_short_term_ref_pic_sets, 0, + HEVC_MAX_NUM_ST_REF_PIC_SETS - 1, &parse_err); + + for (i = 0; i < sps->num_short_term_ref_pic_sets; ++i) { + parse_err |= bspp_hevc_parse_shortterm_refpicset(sr_ctx, + sps->rps_list, + i, + 0); + } + + HEVC_SWSR_U1("long_term_ref_pics_present_flag", + &sps->long_term_ref_pics_present_flag, sr_ctx); + if (sps->long_term_ref_pics_present_flag) { + HEVC_SWSR_UE("num_long_term_ref_pics_sps", + (unsigned int *)&sps->num_long_term_ref_pics_sps, sr_ctx); + HEVC_RANGEUCHECK("num_long_term_ref_pics_sps", + sps->num_long_term_ref_pics_sps, 0, + HEVC_MAX_NUM_LT_REF_PICS, &parse_err); + for (i = 0; i < sps->num_long_term_ref_pics_sps; ++i) { + HEVC_SWSR_UN("lt_ref_pic_poc_lsb_sps", + (unsigned int *)&sps->lt_ref_pic_poc_lsb_sps[i], + sps->log2_max_pic_order_cnt_lsb_minus4 + 4, + sr_ctx); + HEVC_SWSR_U1("used_by_curr_pic_lt_sps_flag", + &sps->used_by_curr_pic_lt_sps_flag[i], + sr_ctx); + } + } + + HEVC_SWSR_U1("sps_temporal_mvp_enabled_flag", &sps->sps_temporal_mvp_enabled_flag, sr_ctx); + HEVC_SWSR_U1("strong_intra_smoothing_enabled_flag", + &sps->strong_intra_smoothing_enabled_flag, sr_ctx); + HEVC_SWSR_U1("vui_parameters_present_flag", &sps->vui_parameters_present_flag, sr_ctx); + + if (sps->vui_parameters_present_flag) + bspp_hevc_parsevui_parameters(sr_ctx, &sps->vui_params, + sps->sps_max_sub_layers_minus1); + + HEVC_SWSR_U1("sps_extension_present_flag", &sps->sps_extension_present_flag, sr_ctx); + if (sps->sps_extension_present_flag && + bspp_hevc_range_extensions_is_enabled(&sps->profile_tier_level)) { + HEVC_SWSR_U1("sps_range_extensions_flag", &sps->sps_range_extensions_flag, sr_ctx); + + HEVC_SWSR_UN("sps_extension_7bits", (unsigned int *)&sps->sps_extension_7bits, 7, + sr_ctx); + /* + * ignore extension data. Although we inform + * if some non-zero data was found + */ + HEVC_UCHECK("sps_extension_7bits", sps->sps_extension_7bits, 0, &parse_err); + /* + * TODO ?: the newest HEVC spec (10/2014) splits + * "sps_extension_7bits" to * sps_multilayer_extension_flag (1) + * sps_extension_6bits (6) + */ + if (sps->sps_range_extensions_flag) + parse_err |= bspp_hevc_parse_spsrange_extensions + (sr_ctx, &sps->range_exts); + } + /* + * calculate "derived" variables needed further in the parsing process + * (of other headers) and save them for later use + */ + sps->sub_width_c = 1; + sps->sub_height_c = 1; + if (sps->chroma_format_idc == 2) { + sps->sub_width_c = 2; + } else if (sps->chroma_format_idc == 1) { + sps->sub_width_c = 2; + sps->sub_height_c = 2; + } + + min_cblog2_size_y = sps->log2_min_luma_coding_block_size_minus3 + 3; + sps->ctb_log2size_y = + min_cblog2_size_y + sps->log2_diff_max_min_luma_coding_block_size; + sps->ctb_size_y = 1 << sps->ctb_log2size_y; + + if (sps->ctb_size_y > 0) { + /* use integer division with rounding up */ + sps->pic_width_in_ctbs_y = + (sps->pic_width_in_luma_samples + sps->ctb_size_y - 1) + / sps->ctb_size_y; + sps->pic_height_in_ctbs_y = + (sps->pic_height_in_luma_samples + sps->ctb_size_y - 1) + / sps->ctb_size_y; + } else { + parse_err |= BSPP_ERROR_INVALID_VALUE; + } + + sps->pic_size_in_ctbs_y = + sps->pic_width_in_ctbs_y * sps->pic_height_in_ctbs_y; + + sps->max_pic_order_cnt_lsb = + 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + + for (i = 0; i <= sps->sps_max_sub_layers_minus1; ++i) { + sps->sps_max_latency_pictures[i] = + sps->sps_max_num_reorder_pics[i] + + sps->sps_max_latency_increase_plus1[i] - 1; + } + + BSPP_HEVC_SYNTAX("ctb_size_y: %u", sps->ctb_size_y); + BSPP_HEVC_SYNTAX("pic_width_in_ctbs_y: %u", sps->pic_width_in_ctbs_y); + BSPP_HEVC_SYNTAX("pic_height_in_ctbs_y: %u", sps->pic_height_in_ctbs_y); + BSPP_HEVC_SYNTAX("pic_size_in_ctbs_y: %u", sps->pic_size_in_ctbs_y); + + return parse_err; +} + +static int bspp_hevc_release_sequhdrinfo(void *str_alloc, void *secure_spsinfo) +{ + struct bspp_hevc_sps *hevc_sps = (struct bspp_hevc_sps *)secure_spsinfo; + + if (!hevc_sps) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Release the raw VIU data. */ + bspp_streamrelese_rawbstrdataplain(str_alloc, (void *)hevc_sps->vui_raw_data); + return 0; +} + +static int bspp_hevc_releasedata(void *str_alloc, enum bspp_unit_type data_type, + void *data_handle) +{ + int result = 0; + + if (!data_handle) + return IMG_ERROR_INVALID_PARAMETERS; + + switch (data_type) { + case BSPP_UNIT_SEQUENCE: + result = bspp_hevc_release_sequhdrinfo(str_alloc, data_handle); + break; + default: + break; + } + + return result; +} + +static int bspp_hevc_reset_ppsinfo(void *secure_ppsinfo) +{ + struct bspp_hevc_pps *hevc_pps = NULL; + + if (!secure_ppsinfo) + return IMG_ERROR_INVALID_PARAMETERS; + + hevc_pps = (struct bspp_hevc_pps *)secure_ppsinfo; + + memset(hevc_pps, 0, sizeof(*hevc_pps)); + + return 0; +} + +static int bspp_hevc_resetdata(enum bspp_unit_type data_type, void *data_handle) +{ + int result = 0; + + switch (data_type) { + case BSPP_UNIT_PPS: + result = bspp_hevc_reset_ppsinfo(data_handle); + break; + default: + break; + } + return result; +} + +static enum bspp_error_type bspp_hevc_parsepps_range_extensions + (void *sr_ctx, + struct bspp_hevc_pps_range_exts *range_exts, + unsigned char transform_skip_enabled_flag, + unsigned char log2_diff_max_min_luma_coding_block_size) +{ + enum bspp_error_type parse_err = BSPP_ERROR_NONE; + + VDEC_ASSERT(sr_ctx); + VDEC_ASSERT(range_exts); + + memset(range_exts, 0, sizeof(struct bspp_hevc_pps_range_exts)); + + if (transform_skip_enabled_flag) + HEVC_SWSR_UE("log2_max_transform_skip_block_size_minus2", + (unsigned int *)&range_exts->log2_max_transform_skip_block_size_minus2, + sr_ctx); + + HEVC_SWSR_U1("cross_component_prediction_enabled_flag", + &range_exts->cross_component_prediction_enabled_flag, + sr_ctx); + HEVC_UCHECK("cross_component_prediction_enabled_flag", + range_exts->cross_component_prediction_enabled_flag, 0, + &parse_err); + + HEVC_SWSR_U1("chroma_qp_offset_list_enabled_flag", + &range_exts->chroma_qp_offset_list_enabled_flag, sr_ctx); + + if (range_exts->chroma_qp_offset_list_enabled_flag) { + unsigned char i; + + HEVC_SWSR_UE("diff_cu_chroma_qp_offset_depth", + (unsigned int *)&range_exts->diff_cu_chroma_qp_offset_depth, + sr_ctx); + HEVC_RANGEUCHECK("diff_cu_chroma_qp_offset_depth", + range_exts->diff_cu_chroma_qp_offset_depth, 0, + log2_diff_max_min_luma_coding_block_size, + &parse_err); + + HEVC_SWSR_UE("chroma_qp_offset_list_len_minus1", + (unsigned int *)&range_exts->chroma_qp_offset_list_len_minus1, + sr_ctx); + HEVC_RANGEUCHECK("chroma_qp_offset_list_len_minus1", + range_exts->chroma_qp_offset_list_len_minus1, + 0, HEVC_MAX_CHROMA_QP - 1, &parse_err); + for (i = 0; i <= range_exts->chroma_qp_offset_list_len_minus1; i++) { + HEVC_SWSR_SE("cb_qp_offset_list", + (int *)&range_exts->cb_qp_offset_list[i], sr_ctx); + HEVC_RANGESCHECK("cb_qp_offset_list", range_exts->cb_qp_offset_list[i], + -12, 12, &parse_err); + HEVC_SWSR_SE("cr_qp_offset_list", + (int *)&range_exts->cr_qp_offset_list[i], sr_ctx); + HEVC_RANGESCHECK("cr_qp_offset_list", range_exts->cr_qp_offset_list[i], + -12, 12, &parse_err); + } + } + HEVC_SWSR_UE("log2_sao_offset_scale_luma", + (unsigned int *)&range_exts->log2_sao_offset_scale_luma, sr_ctx); + HEVC_UCHECK("log2_sao_offset_scale_luma", + range_exts->log2_sao_offset_scale_luma, 0, &parse_err); + HEVC_SWSR_UE("log2_sao_offset_scale_chroma", + (unsigned int *)&range_exts->log2_sao_offset_scale_chroma, sr_ctx); + HEVC_UCHECK("log2_sao_offset_scale_chroma", + range_exts->log2_sao_offset_scale_chroma, 0, &parse_err); + + return parse_err; +} + +static unsigned char bspp_hevc_checkppsrangeextensions + (struct bspp_hevc_pps_range_exts *range_exts) +{ + VDEC_ASSERT(range_exts); + + if (range_exts->log2_max_transform_skip_block_size_minus2 || + range_exts->cross_component_prediction_enabled_flag) + return 1; + /* + * Note: chroma_qp_offset_list_enabled_flag is supported even + * if hw capabilities (bHevcRangeExt is not set) + */ + return 0; +} + +static enum bspp_error_type bspp_hevc_parsepps + (void *sr_ctx, void *str_res, + struct bspp_hevc_pps *pps) +{ + enum bspp_error_type parse_err = BSPP_ERROR_NONE; + struct bspp_sequence_hdr_info *spsinfo = NULL; + struct bspp_hevc_sps *sps = NULL; + + VDEC_ASSERT(sr_ctx); + VDEC_ASSERT(pps); + memset(pps, 0, sizeof(struct bspp_hevc_pps)); + + HEVC_SWSR_UE("pps_pic_parameter_set_id", + (unsigned int *)&pps->pps_pic_parameter_set_id, sr_ctx); + HEVC_RANGEUCHECK("pps_pic_parameter_set_id", pps->pps_pic_parameter_set_id, 0, + HEVC_MAX_PPS_COUNT - 1, &parse_err); + HEVC_SWSR_UE("pps_seq_parameter_set_id", + (unsigned int *)&pps->pps_seq_parameter_set_id, sr_ctx); + HEVC_RANGEUCHECK("pps_seq_parameter_set_id", pps->pps_seq_parameter_set_id, 0, + HEVC_MAX_SPS_COUNT - 1, &parse_err); + + spsinfo = bspp_get_sequ_hdr(str_res, pps->pps_seq_parameter_set_id); + if (!spsinfo) { + parse_err |= BSPP_ERROR_NO_SEQUENCE_HDR; + } else { + sps = (struct bspp_hevc_sps *)spsinfo->secure_sequence_info; + VDEC_ASSERT(sps->sps_seq_parameter_set_id == + pps->pps_seq_parameter_set_id); + } + + HEVC_SWSR_U1("dependent_slice_segments_enabled_flag", + &pps->dependent_slice_segments_enabled_flag, sr_ctx); + HEVC_SWSR_U1("output_flag_present_flag", + &pps->output_flag_present_flag, sr_ctx); + HEVC_SWSR_UN("num_extra_slice_header_bits", + (unsigned int *)&pps->num_extra_slice_header_bits, 3, sr_ctx); + HEVC_SWSR_U1("sign_data_hiding_enabled_flag", &pps->sign_data_hiding_enabled_flag, sr_ctx); + HEVC_SWSR_U1("cabac_init_present_flag", &pps->cabac_init_present_flag, sr_ctx); + HEVC_SWSR_UE("num_ref_idx_l0_default_active_minus1", + (unsigned int *)&pps->num_ref_idx_l0_default_active_minus1, sr_ctx); + HEVC_RANGEUCHECK("num_ref_idx_l0_default_active_minus1", + pps->num_ref_idx_l0_default_active_minus1, 0, 14, &parse_err); + HEVC_SWSR_UE("num_ref_idx_l1_default_active_minus1", + (unsigned int *)&pps->num_ref_idx_l1_default_active_minus1, sr_ctx); + HEVC_RANGEUCHECK("num_ref_idx_l1_default_active_minus1", + pps->num_ref_idx_l1_default_active_minus1, 0, 14, &parse_err); + HEVC_SWSR_SE("init_qp_minus26", (int *)&pps->init_qp_minus26, sr_ctx); + + if (sps) + HEVC_RANGESCHECK("init_qp_minus26", pps->init_qp_minus26, + -(26 + (6 * sps->bit_depth_luma_minus8)), 25, &parse_err); + + HEVC_SWSR_U1("constrained_intra_pred_flag", &pps->constrained_intra_pred_flag, sr_ctx); + HEVC_SWSR_U1("transform_skip_enabled_flag", &pps->transform_skip_enabled_flag, sr_ctx); + + HEVC_SWSR_U1("cu_qp_delta_enabled_flag", &pps->cu_qp_delta_enabled_flag, sr_ctx); + + if (pps->cu_qp_delta_enabled_flag) + HEVC_SWSR_UE("diff_cu_qp_delta_depth", + (unsigned int *)&pps->diff_cu_qp_delta_depth, sr_ctx); + + HEVC_SWSR_SE("pps_cb_qp_offset", (int *)&pps->pps_cb_qp_offset, sr_ctx); + HEVC_RANGESCHECK("pps_cb_qp_offset", pps->pps_cb_qp_offset, -12, 12, &parse_err); + HEVC_SWSR_SE("pps_cr_qp_offset", (int *)&pps->pps_cr_qp_offset, sr_ctx); + HEVC_RANGESCHECK("pps_cr_qp_offset", pps->pps_cr_qp_offset, -12, 12, &parse_err); + HEVC_SWSR_U1("pps_slice_chroma_qp_offsets_present_flag", + &pps->pps_slice_chroma_qp_offsets_present_flag, sr_ctx); + HEVC_SWSR_U1("weighted_pred_flag", &pps->weighted_pred_flag, sr_ctx); + HEVC_SWSR_U1("weighted_bipred_flag", &pps->weighted_bipred_flag, sr_ctx); + HEVC_SWSR_U1("transquant_bypass_enabled_flag", + &pps->transquant_bypass_enabled_flag, sr_ctx); + HEVC_SWSR_U1("tiles_enabled_flag", &pps->tiles_enabled_flag, sr_ctx); + HEVC_SWSR_U1("entropy_coding_sync_enabled_flag", + &pps->entropy_coding_sync_enabled_flag, sr_ctx); + + if (pps->tiles_enabled_flag) { + HEVC_SWSR_UE("num_tile_columns_minus1", + (unsigned int *)&pps->num_tile_columns_minus1, sr_ctx); + HEVC_RANGEUCHECK("num_tile_columns_minus1", pps->num_tile_columns_minus1, 0, + HEVC_MAX_TILE_COLS - 1, &parse_err); + + if (pps->num_tile_columns_minus1 > HEVC_MAX_TILE_COLS) + pps->num_tile_columns_minus1 = HEVC_MAX_TILE_COLS; + + HEVC_SWSR_UE("num_tile_rows_minus1", (unsigned int *)&pps->num_tile_rows_minus1, + sr_ctx); + HEVC_RANGEUCHECK("num_tile_rows_minus1", pps->num_tile_rows_minus1, 0, + HEVC_MAX_TILE_ROWS - 1, &parse_err); + + if (pps->num_tile_rows_minus1 > HEVC_MAX_TILE_ROWS) + pps->num_tile_rows_minus1 = HEVC_MAX_TILE_ROWS; + + HEVC_SWSR_U1("uniform_spacing_flag", &pps->uniform_spacing_flag, sr_ctx); + + if (!pps->uniform_spacing_flag) { + unsigned char i = 0; + + for (i = 0; i < pps->num_tile_columns_minus1; ++i) + HEVC_SWSR_UE("column_width_minus1", + (unsigned int *)&pps->column_width_minus1[i], + sr_ctx); + + for (i = 0; i < pps->num_tile_rows_minus1; ++i) + HEVC_SWSR_UE("row_height_minus1", + (unsigned int *)&pps->row_height_minus1[i], + sr_ctx); + } + HEVC_SWSR_U1("loop_filter_across_tiles_enabled_flag", + &pps->loop_filter_across_tiles_enabled_flag, sr_ctx); + } else { + pps->loop_filter_across_tiles_enabled_flag = 1; + } + + HEVC_SWSR_U1("pps_loop_filter_across_slices_enabled_flag", + &pps->pps_loop_filter_across_slices_enabled_flag, sr_ctx); + + HEVC_SWSR_U1("deblocking_filter_control_present_flag", + &pps->deblocking_filter_control_present_flag, sr_ctx); + + if (pps->deblocking_filter_control_present_flag) { + HEVC_SWSR_U1("deblocking_filter_override_enabled_flag", + &pps->deblocking_filter_override_enabled_flag, sr_ctx); + HEVC_SWSR_U1("pps_deblocking_filter_disabled_flag", + &pps->pps_deblocking_filter_disabled_flag, sr_ctx); + if (!pps->pps_deblocking_filter_disabled_flag) { + HEVC_SWSR_SE("pps_beta_offset_div2", (int *)&pps->pps_beta_offset_div2, + sr_ctx); + HEVC_RANGESCHECK("pps_beta_offset_div2", pps->pps_beta_offset_div2, -6, 6, + &parse_err); + HEVC_SWSR_SE("pps_tc_offset_div2", (int *)&pps->pps_tc_offset_div2, sr_ctx); + HEVC_RANGESCHECK("pps_tc_offset_div2", pps->pps_tc_offset_div2, -6, 6, + &parse_err); + } + } + + HEVC_SWSR_U1("pps_scaling_list_data_present_flag", + &pps->pps_scaling_list_data_present_flag, sr_ctx); + if (pps->pps_scaling_list_data_present_flag) + parse_err |= bspp_hevc_parse_scalinglistdata(sr_ctx, &pps->scaling_list); + + HEVC_SWSR_U1("lists_modification_present_flag", + &pps->lists_modification_present_flag, sr_ctx); + HEVC_SWSR_UE("log2_parallel_merge_level_minus2", + (unsigned int *)&pps->log2_parallel_merge_level_minus2, sr_ctx); + HEVC_SWSR_U1("slice_segment_header_extension_present_flag", + &pps->slice_segment_header_extension_present_flag, sr_ctx); + + HEVC_SWSR_U1("pps_extension_present_flag", &pps->pps_extension_present_flag, sr_ctx); + if (pps->pps_extension_present_flag && + bspp_hevc_range_extensions_is_enabled(&sps->profile_tier_level)) { + HEVC_SWSR_U1("pps_range_extensions_flag", + &pps->pps_range_extensions_flag, sr_ctx); + HEVC_SWSR_UN("pps_extension_7bits", + (unsigned int *)&pps->pps_extension_7bits, 7, sr_ctx); + /* + * ignore extension data. Although we inform + * if some non-zero data was found + */ + HEVC_UCHECK("pps_extension_7bits", pps->pps_extension_7bits, 0, &parse_err); + + /* + * TODO ?: the newest HEVC spec (10/2014) splits "pps_extension_7bits" to + * pps_multilayer_extension_flag (1) + * pps_extension_6bits (6) + */ + if (pps->pps_range_extensions_flag && sps) { + parse_err |= bspp_hevc_parsepps_range_extensions + (sr_ctx, + &pps->range_exts, + pps->transform_skip_enabled_flag, + sps->log2_diff_max_min_luma_coding_block_size); + } + } + + /* calculate derived elements */ + if (pps->tiles_enabled_flag && sps) + bspp_hevc_dotilecalculations(sps, pps); + + return parse_err; +} + +static void bspp_hevc_dotilecalculations(struct bspp_hevc_sps *sps, + struct bspp_hevc_pps *pps) +{ + unsigned short colwidth[HEVC_MAX_TILE_COLS]; + unsigned short rowheight[HEVC_MAX_TILE_ROWS]; + unsigned char i; + + if (!pps->tiles_enabled_flag) { + pps->max_tile_height_in_ctbs_y = sps->pic_height_in_ctbs_y; + return; + } + + if (pps->uniform_spacing_flag) { + for (i = 0; i <= pps->num_tile_columns_minus1; ++i) { + colwidth[i] = ((i + 1) * sps->pic_width_in_ctbs_y) / + (pps->num_tile_columns_minus1 + 1) - + (i * sps->pic_width_in_ctbs_y) / + (pps->num_tile_columns_minus1 + 1); + } + + for (i = 0; i <= pps->num_tile_rows_minus1; ++i) { + rowheight[i] = ((i + 1) * sps->pic_height_in_ctbs_y) / + (pps->num_tile_rows_minus1 + 1) - + (i * sps->pic_height_in_ctbs_y) / + (pps->num_tile_rows_minus1 + 1); + } + + pps->max_tile_height_in_ctbs_y = rowheight[0]; + } else { + pps->max_tile_height_in_ctbs_y = 0; + + colwidth[pps->num_tile_columns_minus1] = sps->pic_width_in_ctbs_y; + for (i = 0; i <= pps->num_tile_columns_minus1; ++i) { + colwidth[i] = pps->column_width_minus1[i] + 1; + colwidth[pps->num_tile_columns_minus1] -= colwidth[i]; + } + + rowheight[pps->num_tile_rows_minus1] = sps->pic_height_in_ctbs_y; + for (i = 0; i <= pps->num_tile_rows_minus1; ++i) { + rowheight[i] = pps->row_height_minus1[i] + 1; + rowheight[pps->num_tile_rows_minus1] -= rowheight[i]; + + if (rowheight[i] > pps->max_tile_height_in_ctbs_y) + pps->max_tile_height_in_ctbs_y = rowheight[i]; + } + + if (rowheight[pps->num_tile_rows_minus1] > pps->max_tile_height_in_ctbs_y) + pps->max_tile_height_in_ctbs_y = + rowheight[pps->num_tile_rows_minus1]; + } + + for (i = 0; i <= pps->num_tile_columns_minus1; ++i) + pps->col_bd[i + 1] = pps->col_bd[i] + colwidth[i]; + + for (i = 0; i <= pps->num_tile_rows_minus1; ++i) + pps->row_bd[i + 1] = pps->row_bd[i] + rowheight[i]; +} + +static enum bspp_error_type bspp_hevc_parse_slicesegmentheader + (void *sr_ctx, void *str_res, + struct bspp_hevc_slice_segment_header *ssh, + unsigned char nalunit_type, + struct bspp_vps_info **vpsinfo, + struct bspp_sequence_hdr_info **spsinfo, + struct bspp_pps_info **ppsinfo) +{ + enum bspp_error_type parse_err = BSPP_ERROR_NONE; + struct bspp_hevc_pps *pps = NULL; + struct bspp_hevc_sps *sps = NULL; + struct bspp_hevc_vps *vps = NULL; + + VDEC_ASSERT(sr_ctx); + VDEC_ASSERT(ssh); + VDEC_ASSERT(vpsinfo); + VDEC_ASSERT(spsinfo); + VDEC_ASSERT(ppsinfo); + + memset(ssh, 0, sizeof(struct bspp_hevc_slice_segment_header)); + + HEVC_SWSR_U1("first_slice_segment_in_pic_flag", + &ssh->first_slice_segment_in_pic_flag, sr_ctx); + + if (bspp_hevc_picture_is_irap((enum hevc_nalunittype)nalunit_type)) + HEVC_SWSR_U1("no_output_of_prior_pics_flag", + &ssh->no_output_of_prior_pics_flag, sr_ctx); + + HEVC_SWSR_UE("slice_pic_parameter_set_id", (unsigned int *)&ssh->slice_pic_parameter_set_id, + sr_ctx); + HEVC_RANGEUCHECK("slice_pic_parameter_set_id", ssh->slice_pic_parameter_set_id, 0, + HEVC_MAX_PPS_COUNT - 1, &parse_err); + + if (ssh->slice_pic_parameter_set_id >= HEVC_MAX_PPS_COUNT) { + pr_warn("PPS Id invalid (%u), setting to 0", + ssh->slice_pic_parameter_set_id); + ssh->slice_pic_parameter_set_id = 0; + parse_err &= ~BSPP_ERROR_INVALID_VALUE; + parse_err |= BSPP_ERROR_CORRECTION_VALIDVALUE; + } + + /* set PPS */ + *ppsinfo = bspp_get_pps_hdr(str_res, ssh->slice_pic_parameter_set_id); + if (!(*ppsinfo)) { + parse_err |= BSPP_ERROR_NO_PPS; + goto error; + } + pps = (struct bspp_hevc_pps *)(*ppsinfo)->secure_pps_info; + if (!pps) { + parse_err |= BSPP_ERROR_NO_PPS; + goto error; + } + VDEC_ASSERT(pps->pps_pic_parameter_set_id == ssh->slice_pic_parameter_set_id); + + *spsinfo = bspp_get_sequ_hdr(str_res, pps->pps_seq_parameter_set_id); + if (!(*spsinfo)) { + parse_err |= BSPP_ERROR_NO_SEQUENCE_HDR; + goto error; + } + sps = (struct bspp_hevc_sps *)(*spsinfo)->secure_sequence_info; + VDEC_ASSERT(sps->sps_seq_parameter_set_id == pps->pps_seq_parameter_set_id); + + *vpsinfo = bspp_get_vpshdr(str_res, sps->sps_video_parameter_set_id); + if (!(*vpsinfo)) { + parse_err |= BSPP_ERROR_NO_VPS; + goto error; + } + vps = (struct bspp_hevc_vps *)(*vpsinfo)->secure_vpsinfo; + VDEC_ASSERT(vps->vps_video_parameter_set_id == sps->sps_video_parameter_set_id); + + if (!ssh->first_slice_segment_in_pic_flag) { + if (pps->dependent_slice_segments_enabled_flag) + HEVC_SWSR_U1("dependent_slice_segment_flag", + &ssh->dependent_slice_segment_flag, sr_ctx); + + HEVC_SWSR_UN("slice_segment_address", + (unsigned int *)&ssh->slice_segment_address, + bspp_ceil_log2(sps->pic_size_in_ctbs_y), sr_ctx); + } + +error: + return parse_err; +} + +static enum bspp_error_type bspp_hevc_parse_profiletierlevel + (void *sr_ctx, + struct bspp_hevc_profile_tierlevel *ptl, + unsigned char vps_maxsublayers_minus1) +{ + enum bspp_error_type parse_err = BSPP_ERROR_NONE; + unsigned char i, j; + unsigned int res = 0; + + VDEC_ASSERT(sr_ctx); + VDEC_ASSERT(ptl); + VDEC_ASSERT(vps_maxsublayers_minus1 < HEVC_MAX_NUM_SUBLAYERS); + + memset(ptl, 0, sizeof(struct bspp_hevc_profile_tierlevel)); + + HEVC_SWSR_UN("general_profile_space", (unsigned int *)&ptl->general_profile_space, 2, + sr_ctx); + HEVC_SWSR_U1("general_tier_flag", &ptl->general_tier_flag, sr_ctx); + HEVC_SWSR_UN("general_profile_idc", (unsigned int *)&ptl->general_profile_idc, 5, sr_ctx); + + for (j = 0; j < HEVC_MAX_NUM_PROFILE_IDC; ++j) { + HEVC_SWSR_U1("general_profile_compatibility_flag", + &ptl->general_profile_compatibility_flag[j], + sr_ctx); + } + + HEVC_SWSR_U1("general_progressive_source_flag", + &ptl->general_progressive_source_flag, sr_ctx); + HEVC_SWSR_U1("general_interlaced_source_flag", + &ptl->general_interlaced_source_flag, sr_ctx); + HEVC_SWSR_U1("general_non_packed_constraint_flag", + &ptl->general_non_packed_constraint_flag, sr_ctx); + HEVC_SWSR_U1("general_frame_only_constraint_flag", + &ptl->general_frame_only_constraint_flag, sr_ctx); + + if (ptl->general_profile_idc == 4 || + ptl->general_profile_compatibility_flag[4]) { + HEVC_SWSR_U1("general_max_12bit_constraint_flag", + &ptl->general_max_12bit_constraint_flag, sr_ctx); + HEVC_SWSR_U1("general_max_10bit_constraint_flag", + &ptl->general_max_10bit_constraint_flag, sr_ctx); + HEVC_SWSR_U1("general_max_8bit_constraint_flag", + &ptl->general_max_8bit_constraint_flag, sr_ctx); + HEVC_SWSR_U1("general_max_422chroma_constraint_flag", + &ptl->general_max_422chroma_constraint_flag, + sr_ctx); + HEVC_SWSR_U1("general_max_420chroma_constraint_flag", + &ptl->general_max_420chroma_constraint_flag, + sr_ctx); + HEVC_SWSR_U1("general_max_monochrome_constraint_flag", + &ptl->general_max_monochrome_constraint_flag, + sr_ctx); + HEVC_SWSR_U1("general_intra_constraint_flag", + &ptl->general_intra_constraint_flag, sr_ctx); + HEVC_SWSR_U1("general_one_picture_only_constraint_flag", + &ptl->general_one_picture_only_constraint_flag, + sr_ctx); + HEVC_SWSR_U1("general_lower_bit_rate_constraint_flag", + &ptl->general_lower_bit_rate_constraint_flag, + sr_ctx); + HEVC_SWSR_UN("general_reserved_zero_35bits", &res, 32, sr_ctx); + HEVC_UCHECK("general_reserved_zero_35bits", res, 0, &parse_err); + HEVC_SWSR_UN("general_reserved_zero_35bits", &res, 3, sr_ctx); + HEVC_UCHECK("general_reserved_zero_35bits", res, 0, &parse_err); + } else { + HEVC_SWSR_UN("general_reserved_zero_44bits (1)", &res, 32, sr_ctx); + HEVC_UCHECK("general_reserved_zero_44bits (1)", res, 0, &parse_err); + HEVC_SWSR_UN("general_reserved_zero_44bits (2)", &res, 12, sr_ctx); + HEVC_UCHECK("general_reserved_zero_44bits (2)", res, 0, &parse_err); + } + + HEVC_SWSR_UN("general_level_idc", (unsigned int *)&ptl->general_level_idc, 8, sr_ctx); + HEVC_RANGEUCHECK("general_level_idc", ptl->general_level_idc, + HEVC_LEVEL_IDC_MIN, HEVC_LEVEL_IDC_MAX, &parse_err); + + for (i = 0; i < vps_maxsublayers_minus1; ++i) { + HEVC_SWSR_U1("sub_layer_profile_present_flag", + &ptl->sub_layer_profile_present_flag[i], sr_ctx); + HEVC_SWSR_U1("sub_layer_level_present_flag", + &ptl->sub_layer_level_present_flag[i], sr_ctx); + } + + if (vps_maxsublayers_minus1 > 0) { + for (i = vps_maxsublayers_minus1; i < 8; ++i) { + HEVC_SWSR_UN("reserved_zero_2bits", &res, 2, sr_ctx); + HEVC_UCHECK("reserved_zero_2bits", res, 0, &parse_err); + } + } + + for (i = 0; i < vps_maxsublayers_minus1; ++i) { + if (ptl->sub_layer_profile_present_flag[i]) { + HEVC_SWSR_UN("sub_layer_profile_space", + (unsigned int *)&ptl->sub_layer_profile_space[i], 2, sr_ctx); + HEVC_SWSR_U1("sub_layer_tier_flag", &ptl->sub_layer_tier_flag[i], sr_ctx); + HEVC_SWSR_UN("sub_layer_profile_idc", + (unsigned int *)&ptl->sub_layer_profile_idc[i], 5, sr_ctx); + for (j = 0; j < HEVC_MAX_NUM_PROFILE_IDC; ++j) + HEVC_SWSR_U1("sub_layer_profile_compatibility_flag", + &ptl->sub_layer_profile_compatibility_flag[i][j], + sr_ctx); + + HEVC_SWSR_U1("sub_layer_progressive_source_flag", + &ptl->sub_layer_progressive_source_flag[i], + sr_ctx); + HEVC_SWSR_U1("sub_layer_interlaced_source_flag", + &ptl->sub_layer_interlaced_source_flag[i], + sr_ctx); + HEVC_SWSR_U1("sub_layer_non_packed_constraint_flag", + &ptl->sub_layer_non_packed_constraint_flag[i], + sr_ctx); + HEVC_SWSR_U1("sub_layer_frame_only_constraint_flag", + &ptl->sub_layer_frame_only_constraint_flag[i], + sr_ctx); + + if (ptl->sub_layer_profile_idc[i] == 4 || + ptl->sub_layer_profile_compatibility_flag[i][4]) { + HEVC_SWSR_U1("sub_layer_max_12bit_constraint_flag", + &ptl->sub_layer_max_12bit_constraint_flag[i], + sr_ctx); + HEVC_SWSR_U1("sub_layer_max_10bit_constraint_flag", + &ptl->sub_layer_max_10bit_constraint_flag[i], + sr_ctx); + HEVC_SWSR_U1("sub_layer_max_8bit_constraint_flag", + &ptl->sub_layer_max_8bit_constraint_flag[i], + sr_ctx); + HEVC_SWSR_U1("sub_layer_max_422chroma_constraint_flag", + &ptl->sub_layer_max_422chroma_constraint_flag[i], + sr_ctx); + HEVC_SWSR_U1("sub_layer_max_420chroma_constraint_flag", + &ptl->sub_layer_max_420chroma_constraint_flag[i], + sr_ctx); + HEVC_SWSR_U1("sub_layer_max_monochrome_constraint_flag", + &ptl->sub_layer_max_monochrome_constraint_flag[i], + sr_ctx); + HEVC_SWSR_U1("sub_layer_intra_constraint_flag", + &ptl->sub_layer_intra_constraint_flag[i], + sr_ctx); + HEVC_SWSR_U1("sub_layer_one_picture_only_constraint_flag", + &ptl->sub_layer_one_picture_only_constraint_flag[i], + sr_ctx); + HEVC_SWSR_U1("sub_layer_lower_bit_rate_constraint_flag", + &ptl->sub_layer_lower_bit_rate_constraint_flag[i], + sr_ctx); + HEVC_SWSR_UN("sub_layer_reserved_zero_35bits", + &res, 32, sr_ctx); + HEVC_UCHECK("sub_layer_reserved_zero_35bits", + res, 0, &parse_err); + HEVC_SWSR_UN("sub_layer_reserved_zero_35bits", + &res, 3, sr_ctx); + HEVC_UCHECK("sub_layer_reserved_zero_35bits", + res, 0, &parse_err); + } else { + HEVC_SWSR_UN("sub_layer_reserved_zero_44bits (1)", + &res, 32, sr_ctx); + HEVC_UCHECK("sub_layer_reserved_zero_44bits (1)", + res, 0, &parse_err); + HEVC_SWSR_UN("sub_layer_reserved_zero_44bits (2)", + &res, 12, sr_ctx); + HEVC_UCHECK("sub_layer_reserved_zero_44bits (2)", + res, 0, &parse_err); + } + } + if (ptl->sub_layer_level_present_flag[i]) + HEVC_SWSR_UN("sub_layer_level_idc", + (unsigned int *)&ptl->sub_layer_level_idc[i], 8, sr_ctx); + } + return parse_err; +} + +/* Default scaling lists */ +#define HEVC_SCALING_LIST_0_SIZE 16 +#define HEVC_SCALING_LIST_123_SIZE 64 + +static const unsigned char def_4x4[HEVC_SCALING_LIST_0_SIZE] = { + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 +}; + +static const unsigned char def_8x8_intra[HEVC_SCALING_LIST_123_SIZE] = { + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 16, 17, 16, 17, 18, + 17, 18, 18, 17, 18, 21, 19, 20, 21, 20, 19, 21, 24, 22, 22, 24, + 24, 22, 22, 24, 25, 25, 27, 30, 27, 25, 25, 29, 31, 35, 35, 31, + 29, 36, 41, 44, 41, 36, 47, 54, 54, 47, 65, 70, 65, 88, 88, 115 +}; + +static const unsigned char def_8x8_inter[HEVC_SCALING_LIST_123_SIZE] = { + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, + 18, 18, 18, 18, 18, 20, 20, 20, 20, 20, 20, 20, 24, 24, 24, 24, + 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 28, 28, 28, 28, 28, + 28, 33, 33, 33, 33, 33, 41, 41, 41, 41, 54, 54, 54, 71, 71, 91 +}; + +/* + * Scan order mapping when translating scaling lists from bitstream order + * to PVDEC order + */ +static const unsigned char HEVC_INV_ZZ_SCAN4[HEVC_SCALING_LIST_MATRIX_SIZE / 4] = { + 0, 1, 2, 4, 3, 6, 7, 10, 5, 8, 9, 12, 11, 13, 14, 15 +}; + +static const unsigned char HEVC_INV_ZZ_SCAN8[HEVC_SCALING_LIST_MATRIX_SIZE] = { + 0, 1, 2, 4, 3, 6, 7, 11, 5, 8, 9, 13, 12, 17, 18, 24, + 10, 15, 16, 22, 21, 28, 29, 36, 23, 30, 31, 38, 37, 43, 44, 49, + 14, 19, 20, 26, 25, 32, 33, 40, 27, 34, 35, 42, 41, 47, 48, 53, + 39, 45, 46, 51, 50, 54, 55, 58, 52, 56, 57, 60, 59, 61, 62, 63 +}; + +static void bspp_hevc_getdefault_scalinglist + (unsigned char size_id, unsigned char matrix_id, + const unsigned char **default_scalinglist, + unsigned int *size) +{ + static const unsigned char *defaultlists + [HEVC_SCALING_LIST_NUM_SIZES][HEVC_SCALING_LIST_NUM_MATRICES] = { + { def_4x4, def_4x4, def_4x4, def_4x4, def_4x4, def_4x4 }, + { def_8x8_intra, def_8x8_intra, def_8x8_intra, + def_8x8_inter, def_8x8_inter, def_8x8_inter }, + { def_8x8_intra, def_8x8_intra, def_8x8_intra, + def_8x8_inter, def_8x8_inter, def_8x8_inter }, + { def_8x8_intra, def_8x8_inter, NULL, NULL, NULL, NULL } + }; + + static const unsigned int lists_sizes + [HEVC_SCALING_LIST_NUM_SIZES][HEVC_SCALING_LIST_NUM_MATRICES] = { + { sizeof(def_4x4), sizeof(def_4x4), sizeof(def_4x4), + sizeof(def_4x4), sizeof(def_4x4), sizeof(def_4x4) }, + { sizeof(def_8x8_intra), sizeof(def_8x8_intra), + sizeof(def_8x8_intra), sizeof(def_8x8_inter), + sizeof(def_8x8_inter), sizeof(def_8x8_inter) }, + { sizeof(def_8x8_intra), sizeof(def_8x8_intra), + sizeof(def_8x8_intra), sizeof(def_8x8_inter), + sizeof(def_8x8_inter), sizeof(def_8x8_inter) }, + { sizeof(def_8x8_intra), sizeof(def_8x8_inter), 0, 0, 0, 0 } + }; + + /* to assert that input to this function was correct */ + VDEC_ASSERT(size_id < 4); + VDEC_ASSERT(size_id < 3 ? (matrix_id < 6) : (matrix_id < 2)); + + *default_scalinglist = defaultlists[size_id][matrix_id]; + *size = lists_sizes[size_id][matrix_id]; +} + +static enum bspp_error_type bspp_hevc_parse_scalinglistdata + (void *sr_ctx, + struct bspp_hevc_scalinglist_data *scaling_listdata) +{ + enum bspp_error_type parse_err = BSPP_ERROR_NONE; + unsigned char size_id, matrix_id; + + for (size_id = 0; size_id < HEVC_SCALING_LIST_NUM_SIZES; ++size_id) { + for (matrix_id = 0; matrix_id < ((size_id == 3) ? 2 : 6); + ++matrix_id) { + /* + * Select scaling list on which we will operate in + * the iteration + */ + unsigned char *scalinglist = scaling_listdata->lists[size_id][matrix_id]; + + unsigned char scaling_list_pred_mode_flag = 0; + + HEVC_SWSR_U1("scaling_list_pred_mode_flag", + &scaling_list_pred_mode_flag, sr_ctx); + if (!scaling_list_pred_mode_flag) { + unsigned char scaling_list_pred_matrix_id_delta = 0; + const unsigned char *defaultlist = NULL; + unsigned int listsize = 0; + + HEVC_SWSR_UE("scaling_list_pred_matrixid_delta", + (unsigned int *)&scaling_list_pred_matrix_id_delta, + sr_ctx); + + bspp_hevc_getdefault_scalinglist(size_id, + matrix_id, + &defaultlist, + &listsize); + + if (scaling_list_pred_matrix_id_delta == 0) { + /* use default one */ + memcpy(scalinglist, defaultlist, listsize); + if (size_id > 1) + scaling_listdata->dccoeffs[size_id - + 2][matrix_id] = 8 + 8; + } else { + unsigned char ref_matrix_id = + matrix_id - scaling_list_pred_matrix_id_delta; + unsigned char *refscalinglist = + scaling_listdata->lists[size_id][ref_matrix_id]; + /* + * use reference list given by + * scaling_list_pred_matrix_id_delta + */ + memcpy(scalinglist, refscalinglist, listsize); + if (size_id > 1) + scaling_listdata->dccoeffs[size_id - 2][matrix_id] = + scaling_listdata->dccoeffs[size_id - + 2][ref_matrix_id]; + } + } else { + /* + * scaling list coefficients + * signalled explicitly + */ + static const short coef_startvalue = 8; + static const unsigned char matrix_max_coef_num = 64; + + short next_coef = coef_startvalue; + unsigned char coef_num = + HEVC_MIN(matrix_max_coef_num, + (1 << (4 + (size_id << 1))), unsigned char); + + unsigned char i; + + if (size_id > 1) { + short scaling_list_dc_coef_minus8 = 0; + + HEVC_SWSR_SE("scaling_list_dc_coef_minus8", + (int *)&scaling_list_dc_coef_minus8, + sr_ctx); + HEVC_RANGESCHECK("scaling_list_dc_coef_minus8", + scaling_list_dc_coef_minus8, + -7, 247, &parse_err); + + next_coef = scaling_list_dc_coef_minus8 + 8; + scaling_listdata->dccoeffs[size_id - 2][matrix_id] = + (unsigned char)next_coef; + } + for (i = 0; i < coef_num; ++i) { + short scaling_list_delta_coef = 0; + + HEVC_SWSR_SE("scaling_list_delta_coef", + (int *)&scaling_list_delta_coef, sr_ctx); + HEVC_RANGESCHECK("scaling_list_delta_coef", + scaling_list_delta_coef, -128, 127, + &parse_err); + + next_coef = (next_coef + scaling_list_delta_coef + 256) & + 0xFF; + scalinglist[i] = next_coef; + } + } + } + } + +#ifdef DEBUG_DECODER_DRIVER + /* print calculated scaling lists */ + for (size_id = 0; size_id < HEVC_SCALING_LIST_NUM_SIZES; ++size_id) { + for (matrix_id = 0; matrix_id < ((size_id == 3) ? 2 : 6); + ++matrix_id) { + unsigned char i = 0; + /* + * Select scaling list on which we will operate + * in the iteration + */ + unsigned char *scalinglist = scaling_listdata->lists[size_id][matrix_id]; + + for (; i < ((size_id == 0) ? 16 : 64); ++i) { + BSPP_HEVC_SYNTAX("scalinglist[%u][%u][%u] = %u", + size_id, + matrix_id, + i, + scalinglist[i]); + } + } + } +#endif + + return parse_err; +} + +static void +bspp_hevc_usedefault_scalinglists(struct bspp_hevc_scalinglist_data *scaling_listdata) +{ + unsigned char size_id, matrix_id; + + for (size_id = 0; size_id < HEVC_SCALING_LIST_NUM_SIZES; ++size_id) { + for (matrix_id = 0; matrix_id < ((size_id == 3) ? 2 : 6); + ++matrix_id) { + unsigned char *list = scaling_listdata->lists[size_id][matrix_id]; + const unsigned char *defaultlist = NULL; + unsigned int listsize = 0; + + bspp_hevc_getdefault_scalinglist(size_id, matrix_id, &defaultlist, + &listsize); + + memcpy(list, defaultlist, listsize); + } + } + + memset(scaling_listdata->dccoeffs, 8 + 8, sizeof(scaling_listdata->dccoeffs)); +} + +static enum bspp_error_type bspp_hevc_parse_shortterm_refpicset + (void *sr_ctx, + struct bspp_hevc_shortterm_refpicset *st_refpicset, + unsigned char st_rps_idx, + unsigned char in_slice_header) +{ + /* + * Note: unfortunately short term ref pic set has to be + * "partially-decoded" and parsed at the same time because derived + * syntax elements are used for prediction of subsequent + * short term ref pic sets. + */ + enum bspp_error_type parse_err = BSPP_ERROR_NONE; + + struct bspp_hevc_shortterm_refpicset *strps = + &st_refpicset[st_rps_idx]; + unsigned char inter_ref_pic_set_prediction_flag = 0; + unsigned int i = 0; + + memset(strps, 0, sizeof(*strps)); + + if (st_rps_idx != 0) { + HEVC_SWSR_U1("inter_ref_pic_set_prediction_flag", + &inter_ref_pic_set_prediction_flag, sr_ctx); + } + + if (inter_ref_pic_set_prediction_flag) { + signed char j = 0; + unsigned char j_8 = 0; + unsigned char ref_rps_idx = 0; + int delta_rps = 0; + unsigned char i = 0; + unsigned char delta_idx_minus1 = 0; + unsigned char delta_rps_sign = 0; + unsigned short abs_delta_rps_minus1 = 0; + unsigned char used_by_curr_pic_flag[HEVC_MAX_NUM_REF_PICS]; + unsigned char use_delta_flag[HEVC_MAX_NUM_REF_PICS]; + + struct bspp_hevc_shortterm_refpicset *ref_strps = NULL; + + if (in_slice_header) { + HEVC_SWSR_UE("delta_idx_minus1", (unsigned int *)&delta_idx_minus1, sr_ctx); + HEVC_RANGEUCHECK("delta_idx_minus1", delta_idx_minus1, 0, st_rps_idx - 1, + &parse_err); + } + + HEVC_SWSR_U1("delta_rps_sign", &delta_rps_sign, sr_ctx); + HEVC_SWSR_UE("abs_delta_rps_minus1", (unsigned int *)&abs_delta_rps_minus1, sr_ctx); + HEVC_RANGEUCHECK("abs_delta_rps_minus1", abs_delta_rps_minus1, 0, ((1 << 15) - 1), + &parse_err); + + ref_rps_idx = st_rps_idx - (delta_idx_minus1 + 1); + ref_strps = &st_refpicset[ref_rps_idx]; + + memset(use_delta_flag, 1, sizeof(use_delta_flag)); + + for (j_8 = 0; j_8 <= ref_strps->num_delta_pocs; ++j_8) { + HEVC_SWSR_U1("used_by_curr_pic_flag", &used_by_curr_pic_flag[j_8], sr_ctx); + if (!used_by_curr_pic_flag[j_8]) + HEVC_SWSR_U1("use_delta_flag", &use_delta_flag[j_8], sr_ctx); + } + + delta_rps = + (1 - 2 * delta_rps_sign) * (abs_delta_rps_minus1 + 1); + + /* + * predict delta POC values of current strps from + * reference strps + */ + for (j = ref_strps->num_positive_pics - 1; j >= 0; --j) { + int dpoc = ref_strps->delta_poc_s1[j] + delta_rps; + + if (dpoc < 0 && use_delta_flag[ref_strps->num_negative_pics + j]) { + strps->delta_poc_s0[i] = dpoc; + strps->used_bycurr_pic_s0[i++] = + used_by_curr_pic_flag[ref_strps->num_negative_pics + j]; + } + } + + if (delta_rps < 0 && use_delta_flag[ref_strps->num_delta_pocs]) { + strps->delta_poc_s0[i] = delta_rps; + strps->used_bycurr_pic_s0[i++] = + used_by_curr_pic_flag[ref_strps->num_delta_pocs]; + } + + for (j_8 = 0; j_8 < ref_strps->num_negative_pics; ++j_8) { + int dpoc = ref_strps->delta_poc_s0[j_8] + delta_rps; + + if (dpoc < 0 && use_delta_flag[j_8]) { + strps->delta_poc_s0[i] = dpoc; + strps->used_bycurr_pic_s0[i++] = used_by_curr_pic_flag[j_8]; + } + } + + strps->num_negative_pics = i; + + i = 0; + for (j = ref_strps->num_negative_pics - 1; j >= 0; --j) { + int dpoc = ref_strps->delta_poc_s0[j] + delta_rps; + + if (dpoc > 0 && use_delta_flag[j]) { + strps->delta_poc_s1[i] = dpoc; + strps->used_bycurr_pic_s1[i++] = + used_by_curr_pic_flag[j]; + } + } + + if (delta_rps > 0 && use_delta_flag[ref_strps->num_delta_pocs]) { + strps->delta_poc_s1[i] = delta_rps; + strps->used_bycurr_pic_s1[i++] = + used_by_curr_pic_flag[ref_strps->num_delta_pocs]; + } + + for (j_8 = 0; j_8 < ref_strps->num_positive_pics; ++j_8) { + int dpoc = ref_strps->delta_poc_s1[j_8] + delta_rps; + + if (dpoc > 0 && use_delta_flag[ref_strps->num_negative_pics + j_8]) { + strps->delta_poc_s1[i] = dpoc; + strps->used_bycurr_pic_s1[i++] = + used_by_curr_pic_flag[ref_strps->num_negative_pics + j_8]; + } + } + + strps->num_positive_pics = i; + strps->num_delta_pocs = strps->num_negative_pics + strps->num_positive_pics; + if (strps->num_delta_pocs > (HEVC_MAX_NUM_REF_PICS - 1)) { + strps->num_delta_pocs = HEVC_MAX_NUM_REF_PICS - 1; + parse_err |= BSPP_ERROR_CORRECTION_VALIDVALUE; + } + } else { + unsigned char num_negative_pics = 0; + unsigned char num_positive_pics = 0; + unsigned short delta_poc_s0_minus1[HEVC_MAX_NUM_REF_PICS]; + unsigned char used_by_curr_pic_s0_flag[HEVC_MAX_NUM_REF_PICS]; + unsigned short delta_poc_s1_minus1[HEVC_MAX_NUM_REF_PICS]; + unsigned char used_by_curr_pic_s1_flag[HEVC_MAX_NUM_REF_PICS]; + unsigned char j = 0; + + HEVC_SWSR_UE("num_negative_pics", (unsigned int *)&num_negative_pics, sr_ctx); + if (num_negative_pics > HEVC_MAX_NUM_REF_PICS) { + num_negative_pics = HEVC_MAX_NUM_REF_PICS; + parse_err |= BSPP_ERROR_CORRECTION_VALIDVALUE; + } + HEVC_SWSR_UE("num_positive_pics", (unsigned int *)&num_positive_pics, sr_ctx); + if (num_positive_pics > HEVC_MAX_NUM_REF_PICS) { + num_positive_pics = HEVC_MAX_NUM_REF_PICS; + parse_err |= BSPP_ERROR_CORRECTION_VALIDVALUE; + } + + for (j = 0; j < num_negative_pics; ++j) { + HEVC_SWSR_UE("delta_poc_s0_minus1", + (unsigned int *)&delta_poc_s0_minus1[j], sr_ctx); + HEVC_RANGEUCHECK("delta_poc_s0_minus1", delta_poc_s0_minus1[j], 0, + ((1 << 15) - 1), &parse_err); + HEVC_SWSR_U1("used_by_curr_pic_s0_flag", + &used_by_curr_pic_s0_flag[j], sr_ctx); + + if (j == 0) + strps->delta_poc_s0[j] = + -(delta_poc_s0_minus1[j] + 1); + else + strps->delta_poc_s0[j] = strps->delta_poc_s0[j - 1] - + (delta_poc_s0_minus1[j] + 1); + + strps->used_bycurr_pic_s0[j] = used_by_curr_pic_s0_flag[j]; + } + + for (j = 0; j < num_positive_pics; j++) { + HEVC_SWSR_UE("delta_poc_s1_minus1", + (unsigned int *)&delta_poc_s1_minus1[j], sr_ctx); + HEVC_RANGEUCHECK("delta_poc_s1_minus1", delta_poc_s1_minus1[j], 0, + ((1 << 15) - 1), &parse_err); + HEVC_SWSR_U1("used_by_curr_pic_s1_flag", + &used_by_curr_pic_s1_flag[j], sr_ctx); + + if (j == 0) + strps->delta_poc_s1[j] = + (delta_poc_s1_minus1[j] + 1); + else + strps->delta_poc_s1[j] = strps->delta_poc_s1[j - 1] + + (delta_poc_s1_minus1[j] + 1); + strps->used_bycurr_pic_s1[j] = used_by_curr_pic_s1_flag[j]; + } + + strps->num_negative_pics = num_negative_pics; + strps->num_positive_pics = num_positive_pics; + strps->num_delta_pocs = strps->num_negative_pics + strps->num_positive_pics; + if (strps->num_delta_pocs > (HEVC_MAX_NUM_REF_PICS - 1)) { + strps->num_delta_pocs = HEVC_MAX_NUM_REF_PICS - 1; + parse_err |= BSPP_ERROR_CORRECTION_VALIDVALUE; + } + } + + BSPP_HEVC_SYNTAX + ("strps[%u]: num_delta_pocs: %u (%u (num_negative_pics) + %u (num_positive_pics))", + st_rps_idx, strps->num_delta_pocs, strps->num_negative_pics, + strps->num_positive_pics); + + for (i = 0; i < strps->num_negative_pics; ++i) { + BSPP_HEVC_SYNTAX("StRps[%u][%u]: delta_poc_s0: %d, used_bycurr_pic_s0: %u", + st_rps_idx, i, strps->delta_poc_s0[i], + strps->used_bycurr_pic_s0[i]); + } + + for (i = 0; i < strps->num_positive_pics; ++i) { + BSPP_HEVC_SYNTAX("StRps[%u][%u]: delta_poc_s1: %d, used_bycurr_pic_s1: %u", + st_rps_idx, i, strps->delta_poc_s1[i], + strps->used_bycurr_pic_s1[i]); + } + + return parse_err; +} + +static void bspp_hevc_fillcommonseqhdr(struct bspp_hevc_sps *sps, + struct vdec_comsequ_hdrinfo *common_seq) +{ + struct bspp_hevc_vui_params *vui = &sps->vui_params; + unsigned char chroma_idc = sps->chroma_format_idc; + struct pixel_pixinfo *pixel_info = &common_seq->pixel_info; + unsigned int maxsub_layersmin1; + unsigned int maxdpb_size; + struct vdec_rect *rawdisp_region; + + common_seq->codec_profile = sps->profile_tier_level.general_profile_idc; + common_seq->codec_level = sps->profile_tier_level.general_level_idc; + + if (sps->vui_parameters_present_flag && + vui->vui_timing_info_present_flag) { + common_seq->frame_rate_num = vui->vui_time_scale; + common_seq->frame_rate_den = vui->vui_num_units_in_tick; + common_seq->frame_rate = + 1 * common_seq->frame_rate_num / common_seq->frame_rate_den; + } + + if (vui->aspect_ratio_info_present_flag) { + common_seq->aspect_ratio_num = vui->sar_width; + common_seq->aspect_ratio_den = vui->sar_height; + } + + common_seq->interlaced_frames = 0; + + /* handle pixel format definitions */ + pixel_info->chroma_fmt = chroma_idc == 0 ? 0 : 1; + pixel_info->chroma_fmt_idc = pixelformat_idc[chroma_idc]; + pixel_info->chroma_interleave = + chroma_idc == 0 ? PIXEL_INVALID_CI : PIXEL_UV_ORDER; + pixel_info->bitdepth_y = sps->bit_depth_luma_minus8 + 8; + pixel_info->bitdepth_c = sps->bit_depth_chroma_minus8 + 8; + + pixel_info->mem_pkg = (pixel_info->bitdepth_y > 8 || + (pixel_info->bitdepth_c > 8 && pixel_info->chroma_fmt)) ? + PIXEL_BIT10_MSB_MP : PIXEL_BIT8_MP; + pixel_info->num_planes = + chroma_idc == 0 ? 1 : (sps->separate_colour_plane_flag ? 3 : 2); + + pixel_info->pixfmt = pixel_get_pixfmt(pixel_info->chroma_fmt_idc, + pixel_info->chroma_interleave, + pixel_info->mem_pkg, + pixel_info->bitdepth_y, + pixel_info->chroma_fmt ? + pixel_info->bitdepth_c : PIXEL_INVALID_BDC, + pixel_info->num_planes); + + common_seq->max_frame_size.width = sps->pic_width_in_ctbs_y * sps->ctb_size_y; + common_seq->max_frame_size.height = sps->pic_height_in_ctbs_y * sps->ctb_size_y; + + common_seq->frame_size.width = sps->pic_width_in_luma_samples; + common_seq->frame_size.height = sps->pic_height_in_luma_samples; + + /* Get HEVC max num ref pictures and pass to bspp info*/ + vdecddutils_ref_pic_hevc_get_maxnum(common_seq, &common_seq->max_ref_frame_num); + + common_seq->field_codec_mblocks = 0; + + maxsub_layersmin1 = sps->sps_max_sub_layers_minus1; + maxdpb_size = + HEVC_MAX(sps->sps_max_dec_pic_buffering_minus1[maxsub_layersmin1] + 1, + sps->sps_max_num_reorder_pics[maxsub_layersmin1], unsigned char); + + if (sps->sps_max_latency_increase_plus1[maxsub_layersmin1]) { + maxdpb_size = + HEVC_MAX(maxdpb_size, + sps->sps_max_latency_pictures[maxsub_layersmin1], unsigned int); + } + + maxdpb_size = HEVC_MIN(maxdpb_size, + HEVC_MAX_NUM_REF_IDX_ACTIVE + 1, unsigned int); + + common_seq->min_pict_buf_num = HEVC_MAX(maxdpb_size, 6, unsigned int); + + common_seq->picture_reordering = 1; + common_seq->post_processing = 0; + + /* handle display region calculation */ + rawdisp_region = &common_seq->raw_display_region; + + rawdisp_region->width = sps->pic_width_in_luma_samples; + rawdisp_region->height = sps->pic_height_in_luma_samples; + rawdisp_region->top_offset = 0; + rawdisp_region->left_offset = 0; + + if (sps->conformance_window_flag) { + struct vdec_rect *disp_region = + &common_seq->orig_display_region; + + disp_region->top_offset = + sps->sub_height_c * sps->conf_win_top_offset; + disp_region->left_offset = + sps->sub_width_c * sps->conf_win_left_offset; + disp_region->width = + sps->pic_width_in_luma_samples - + disp_region->left_offset - + sps->sub_width_c * sps->conf_win_right_offset; + disp_region->height = + sps->pic_height_in_luma_samples - + disp_region->top_offset - + sps->sub_height_c * sps->conf_win_bottom_offset; + } else { + common_seq->orig_display_region = + common_seq->raw_display_region; + } +} + +static void bspp_hevc_fillpicturehdr(struct vdec_comsequ_hdrinfo *common_seq, + enum hevc_nalunittype nalunit_type, + struct bspp_pict_hdr_info *picture_hdr, + struct bspp_hevc_sps *sps, + struct bspp_hevc_pps *pps, + struct bspp_hevc_vps *vps) +{ + picture_hdr->intra_coded = (nalunit_type == HEVC_NALTYPE_IDR_W_RADL || + nalunit_type == HEVC_NALTYPE_IDR_N_LP); + picture_hdr->field = 0; + picture_hdr->post_processing = 0; + picture_hdr->discontinuous_mbs = 0; + picture_hdr->pict_aux_data.id = BSPP_INVALID; + picture_hdr->second_pict_aux_data.id = BSPP_INVALID; + picture_hdr->pict_sgm_data.id = BSPP_INVALID; + picture_hdr->coded_frame_size.width = + HEVC_ALIGN(sps->pic_width_in_luma_samples, HEVC_MIN_CODED_UNIT_SIZE, unsigned int); + picture_hdr->coded_frame_size.height = + HEVC_ALIGN(sps->pic_height_in_luma_samples, HEVC_MIN_CODED_UNIT_SIZE, unsigned int); + picture_hdr->disp_info.enc_disp_region = common_seq->orig_display_region; + picture_hdr->disp_info.disp_region = common_seq->orig_display_region; + picture_hdr->disp_info.raw_disp_region = common_seq->raw_display_region; + picture_hdr->disp_info.num_pan_scan_windows = 0; + picture_hdr->hevc_pict_hdr_info.range_ext_present = + (sps->profile_tier_level.general_profile_idc == 4) || + sps->profile_tier_level.general_profile_compatibility_flag[4]; + + picture_hdr->hevc_pict_hdr_info.is_full_range_ext = 0; + if (picture_hdr->hevc_pict_hdr_info.range_ext_present && + (bspp_hevc_checkppsrangeextensions(&pps->range_exts) || + bspp_hevc_checksps_range_extensions(&sps->range_exts))) + picture_hdr->hevc_pict_hdr_info.is_full_range_ext = 1; + + memset(picture_hdr->disp_info.pan_scan_windows, 0, + sizeof(picture_hdr->disp_info.pan_scan_windows)); +} + +static void bspp_hevc_fill_fwsps(struct bspp_hevc_sps *sps, struct hevcfw_sequence_ps *fwsps) +{ + unsigned char i; + + fwsps->pic_width_in_luma_samples = sps->pic_width_in_luma_samples; + fwsps->pic_height_in_luma_samples = sps->pic_height_in_luma_samples; + fwsps->num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets; + fwsps->num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps; + fwsps->sps_max_sub_layers_minus1 = sps->sps_max_sub_layers_minus1; + fwsps->max_transform_hierarchy_depth_inter = + sps->max_transform_hierarchy_depth_inter; + fwsps->max_transform_hierarchy_depth_intra = + sps->max_transform_hierarchy_depth_intra; + fwsps->log2_diff_max_min_transform_block_size = + sps->log2_diff_max_min_transform_block_size; + fwsps->log2_min_transform_block_size_minus2 = + sps->log2_min_transform_block_size_minus2; + fwsps->log2_diff_max_min_luma_coding_block_size = + sps->log2_diff_max_min_luma_coding_block_size; + fwsps->log2_min_luma_coding_block_size_minus3 = + sps->log2_min_luma_coding_block_size_minus3; + + HEVC_STATIC_ASSERT(sizeof(sps->sps_max_dec_pic_buffering_minus1) == + sizeof(fwsps->sps_max_dec_pic_buffering_minus1)); + memcpy(fwsps->sps_max_dec_pic_buffering_minus1, sps->sps_max_dec_pic_buffering_minus1, + sizeof(fwsps->sps_max_dec_pic_buffering_minus1[0]) * + (sps->sps_max_sub_layers_minus1 + 1)); + + HEVC_STATIC_ASSERT(sizeof(sps->sps_max_num_reorder_pics) == + sizeof(fwsps->sps_max_num_reorder_pics)); + memcpy(fwsps->sps_max_num_reorder_pics, sps->sps_max_num_reorder_pics, + sizeof(fwsps->sps_max_num_reorder_pics[0]) * + (sps->sps_max_sub_layers_minus1 + 1)); + + HEVC_STATIC_ASSERT(sizeof(sps->sps_max_latency_increase_plus1) == + sizeof(fwsps->sps_max_latency_increase_plus1)); + memcpy(fwsps->sps_max_latency_increase_plus1, sps->sps_max_latency_increase_plus1, + sizeof(fwsps->sps_max_latency_increase_plus1[0]) * + (sps->sps_max_sub_layers_minus1 + 1)); + + fwsps->chroma_format_idc = sps->chroma_format_idc; + fwsps->separate_colour_plane_flag = sps->separate_colour_plane_flag; + fwsps->log2_max_pic_order_cnt_lsb_minus4 = + sps->log2_max_pic_order_cnt_lsb_minus4; + fwsps->long_term_ref_pics_present_flag = + sps->long_term_ref_pics_present_flag; + fwsps->sample_adaptive_offset_enabled_flag = + sps->sample_adaptive_offset_enabled_flag; + fwsps->sps_temporal_mvp_enabled_flag = + sps->sps_temporal_mvp_enabled_flag; + fwsps->bit_depth_luma_minus8 = sps->bit_depth_luma_minus8; + fwsps->bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8; + fwsps->pcm_sample_bit_depth_luma_minus1 = + sps->pcm_sample_bit_depth_luma_minus1; + fwsps->pcm_sample_bit_depth_chroma_minus1 = + sps->pcm_sample_bit_depth_chroma_minus1; + fwsps->log2_min_pcm_luma_coding_block_size_minus3 = + sps->log2_min_pcm_luma_coding_block_size_minus3; + fwsps->log2_diff_max_min_pcm_luma_coding_block_size = + sps->log2_diff_max_min_pcm_luma_coding_block_size; + fwsps->pcm_loop_filter_disabled_flag = + sps->pcm_loop_filter_disabled_flag; + fwsps->amp_enabled_flag = sps->amp_enabled_flag; + fwsps->pcm_enabled_flag = sps->pcm_enabled_flag; + fwsps->strong_intra_smoothing_enabled_flag = + sps->strong_intra_smoothing_enabled_flag; + fwsps->scaling_list_enabled_flag = sps->scaling_list_enabled_flag; + fwsps->transform_skip_rotation_enabled_flag = + sps->range_exts.transform_skip_rotation_enabled_flag; + fwsps->transform_skip_context_enabled_flag = + sps->range_exts.transform_skip_context_enabled_flag; + fwsps->implicit_rdpcm_enabled_flag = + sps->range_exts.implicit_rdpcm_enabled_flag; + fwsps->explicit_rdpcm_enabled_flag = + sps->range_exts.explicit_rdpcm_enabled_flag; + fwsps->extended_precision_processing_flag = + sps->range_exts.extended_precision_processing_flag; + fwsps->intra_smoothing_disabled_flag = + sps->range_exts.intra_smoothing_disabled_flag; + /* high precision makes no sense for 8 bit luma & chroma, + * so forward this parameter only when bitdepth > 8 + */ + if (sps->bit_depth_luma_minus8 || sps->bit_depth_chroma_minus8) + fwsps->high_precision_offsets_enabled_flag = + sps->range_exts.high_precision_offsets_enabled_flag; + + fwsps->persistent_rice_adaptation_enabled_flag = + sps->range_exts.persistent_rice_adaptation_enabled_flag; + fwsps->cabac_bypass_alignment_enabled_flag = + sps->range_exts.cabac_bypass_alignment_enabled_flag; + + HEVC_STATIC_ASSERT(sizeof(sps->lt_ref_pic_poc_lsb_sps) == + sizeof(fwsps->lt_ref_pic_poc_lsb_sps)); + HEVC_STATIC_ASSERT(sizeof(sps->used_by_curr_pic_lt_sps_flag) == + sizeof(fwsps->used_by_curr_pic_lt_sps_flag)); + memcpy(fwsps->lt_ref_pic_poc_lsb_sps, sps->lt_ref_pic_poc_lsb_sps, + sizeof(fwsps->lt_ref_pic_poc_lsb_sps[0]) * + sps->num_long_term_ref_pics_sps); + memcpy(fwsps->used_by_curr_pic_lt_sps_flag, sps->used_by_curr_pic_lt_sps_flag, + sizeof(fwsps->used_by_curr_pic_lt_sps_flag[0]) * sps->num_long_term_ref_pics_sps); + + for (i = 0; i < sps->num_short_term_ref_pic_sets; ++i) + bspp_hevc_fill_fwst_rps(&sps->rps_list[i], &fwsps->st_rps_list[i]); + + /* derived elements */ + fwsps->pic_size_in_ctbs_y = sps->pic_size_in_ctbs_y; + fwsps->pic_height_in_ctbs_y = sps->pic_height_in_ctbs_y; + fwsps->pic_width_in_ctbs_y = sps->pic_width_in_ctbs_y; + fwsps->ctb_size_y = sps->ctb_size_y; + fwsps->ctb_log2size_y = sps->ctb_log2size_y; + fwsps->max_pic_order_cnt_lsb = sps->max_pic_order_cnt_lsb; + + HEVC_STATIC_ASSERT(sizeof(sps->sps_max_latency_pictures) == + sizeof(fwsps->sps_max_latency_pictures)); + memcpy(fwsps->sps_max_latency_pictures, sps->sps_max_latency_pictures, + sizeof(fwsps->sps_max_latency_pictures[0]) * + (sps->sps_max_sub_layers_minus1 + 1)); +} + +static void bspp_hevc_fill_fwst_rps(struct bspp_hevc_shortterm_refpicset *strps, + struct hevcfw_short_term_ref_picset *fwstrps) +{ + fwstrps->num_delta_pocs = strps->num_delta_pocs; + fwstrps->num_negative_pics = strps->num_negative_pics; + fwstrps->num_positive_pics = strps->num_positive_pics; + + HEVC_STATIC_ASSERT(sizeof(strps->delta_poc_s0) == + sizeof(fwstrps->delta_poc_s0)); + memcpy(fwstrps->delta_poc_s0, strps->delta_poc_s0, + sizeof(fwstrps->delta_poc_s0[0]) * strps->num_negative_pics); + + HEVC_STATIC_ASSERT(sizeof(strps->delta_poc_s1) == + sizeof(fwstrps->delta_poc_s1)); + memcpy(fwstrps->delta_poc_s1, strps->delta_poc_s1, + sizeof(fwstrps->delta_poc_s1[0]) * strps->num_positive_pics); + + HEVC_STATIC_ASSERT(sizeof(strps->used_bycurr_pic_s0) == + sizeof(fwstrps->used_bycurr_pic_s0)); + memcpy(fwstrps->used_bycurr_pic_s0, strps->used_bycurr_pic_s0, + sizeof(fwstrps->used_bycurr_pic_s0[0]) * strps->num_negative_pics); + + HEVC_STATIC_ASSERT(sizeof(strps->used_bycurr_pic_s1) == + sizeof(fwstrps->used_bycurr_pic_s1)); + memcpy(fwstrps->used_bycurr_pic_s1, strps->used_bycurr_pic_s1, + sizeof(fwstrps->used_bycurr_pic_s1[0]) * strps->num_positive_pics); +} + +static void bspp_hevc_fill_fwpps(struct bspp_hevc_pps *pps, struct hevcfw_picture_ps *fw_pps) +{ + fw_pps->pps_pic_parameter_set_id = pps->pps_pic_parameter_set_id; + fw_pps->num_tile_columns_minus1 = pps->num_tile_columns_minus1; + fw_pps->num_tile_rows_minus1 = pps->num_tile_rows_minus1; + fw_pps->diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth; + fw_pps->init_qp_minus26 = pps->init_qp_minus26; + fw_pps->pps_beta_offset_div2 = pps->pps_beta_offset_div2; + fw_pps->pps_tc_offset_div2 = pps->pps_tc_offset_div2; + fw_pps->pps_cb_qp_offset = pps->pps_cb_qp_offset; + fw_pps->pps_cr_qp_offset = pps->pps_cr_qp_offset; + fw_pps->log2_parallel_merge_level_minus2 = + pps->log2_parallel_merge_level_minus2; + + fw_pps->dependent_slice_segments_enabled_flag = + pps->dependent_slice_segments_enabled_flag; + fw_pps->output_flag_present_flag = pps->output_flag_present_flag; + fw_pps->num_extra_slice_header_bits = pps->num_extra_slice_header_bits; + fw_pps->lists_modification_present_flag = + pps->lists_modification_present_flag; + fw_pps->cabac_init_present_flag = pps->cabac_init_present_flag; + fw_pps->weighted_pred_flag = pps->weighted_pred_flag; + fw_pps->weighted_bipred_flag = pps->weighted_bipred_flag; + fw_pps->pps_slice_chroma_qp_offsets_present_flag = + pps->pps_slice_chroma_qp_offsets_present_flag; + fw_pps->deblocking_filter_override_enabled_flag = + pps->deblocking_filter_override_enabled_flag; + fw_pps->tiles_enabled_flag = pps->tiles_enabled_flag; + fw_pps->entropy_coding_sync_enabled_flag = + pps->entropy_coding_sync_enabled_flag; + fw_pps->slice_segment_header_extension_present_flag = + pps->slice_segment_header_extension_present_flag; + fw_pps->transquant_bypass_enabled_flag = + pps->transquant_bypass_enabled_flag; + fw_pps->cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag; + fw_pps->transform_skip_enabled_flag = pps->transform_skip_enabled_flag; + fw_pps->sign_data_hiding_enabled_flag = + pps->sign_data_hiding_enabled_flag; + fw_pps->num_ref_idx_l0_default_active_minus1 = + pps->num_ref_idx_l0_default_active_minus1; + fw_pps->num_ref_idx_l1_default_active_minus1 = + pps->num_ref_idx_l1_default_active_minus1; + fw_pps->constrained_intra_pred_flag = pps->constrained_intra_pred_flag; + fw_pps->pps_deblocking_filter_disabled_flag = + pps->pps_deblocking_filter_disabled_flag; + fw_pps->pps_loop_filter_across_slices_enabled_flag = + pps->pps_loop_filter_across_slices_enabled_flag; + fw_pps->loop_filter_across_tiles_enabled_flag = + pps->loop_filter_across_tiles_enabled_flag; + fw_pps->log2_max_transform_skip_block_size_minus2 = + pps->range_exts.log2_max_transform_skip_block_size_minus2; + fw_pps->cross_component_prediction_enabled_flag = + pps->range_exts.cross_component_prediction_enabled_flag; + fw_pps->chroma_qp_offset_list_enabled_flag = + pps->range_exts.chroma_qp_offset_list_enabled_flag; + fw_pps->diff_cu_chroma_qp_offset_depth = + pps->range_exts.diff_cu_chroma_qp_offset_depth; + fw_pps->chroma_qp_offset_list_len_minus1 = + pps->range_exts.chroma_qp_offset_list_len_minus1; + memcpy(fw_pps->cb_qp_offset_list, pps->range_exts.cb_qp_offset_list, + sizeof(pps->range_exts.cb_qp_offset_list)); + memcpy(fw_pps->cr_qp_offset_list, pps->range_exts.cr_qp_offset_list, + sizeof(pps->range_exts.cr_qp_offset_list)); + + /* derived elements */ + HEVC_STATIC_ASSERT(sizeof(pps->col_bd) == sizeof(fw_pps->col_bd)); + HEVC_STATIC_ASSERT(sizeof(pps->row_bd) == sizeof(fw_pps->row_bd)); + memcpy(fw_pps->col_bd, pps->col_bd, sizeof(fw_pps->col_bd)); + memcpy(fw_pps->row_bd, pps->row_bd, sizeof(fw_pps->row_bd)); +} + +static void bspp_hevc_fill_fw_scaling_lists(struct bspp_hevc_pps *pps, + struct bspp_hevc_sps *sps, + struct hevcfw_picture_ps *fw_pps) +{ + signed char size_id, matrix_id; + unsigned char *scalinglist; + /* + * We are starting at 1 to leave space for addresses, + * filled by lower layer + */ + unsigned int *scaling_lists = &fw_pps->scaling_lists[1]; + unsigned char i; + + struct bspp_hevc_scalinglist_data *scaling_listdata = + pps->pps_scaling_list_data_present_flag ? + &pps->scaling_list : + &sps->scalinglist_data; + + if (!sps->scaling_list_enabled_flag) + return; + + fw_pps->scaling_list_enabled_flag = sps->scaling_list_enabled_flag; + + for (size_id = HEVC_SCALING_LIST_NUM_SIZES - 1; + size_id >= 0; --size_id) { + const unsigned char *zz = + (size_id == 0 ? HEVC_INV_ZZ_SCAN4 : HEVC_INV_ZZ_SCAN8); + + for (matrix_id = 0; matrix_id < ((size_id == 3) ? 2 : 6); + ++matrix_id) { + /* + * Select scaling list on which we will operate + * in the iteration + */ + scalinglist = + scaling_listdata->lists[size_id][matrix_id]; + + for (i = 0; i < ((size_id == 0) ? 16 : 64); i += 4) { + *scaling_lists = + scalinglist[zz[i + 3]] << 24 | + scalinglist[zz[i + 2]] << 16 | + scalinglist[zz[i + 1]] << 8 | + scalinglist[zz[i]]; + scaling_lists += 2; + } + } + } + + for (i = 0; i < 2; ++i) { + *scaling_lists = scaling_listdata->dccoeffs[1][i]; + scaling_lists += 2; + } + + for (i = 0; i < 6; ++i) { + *scaling_lists = scaling_listdata->dccoeffs[0][i]; + scaling_lists += 2; + } +} + +static unsigned int bspp_ceil_log2(unsigned int linear_val) +{ + unsigned int log_val = 0; + + if (linear_val > 0) + --linear_val; + + while (linear_val > 0) { + linear_val >>= 1; + ++log_val; + } + + return log_val; +} + +static unsigned char bspp_hevc_picture_is_irap(enum hevc_nalunittype nalunit_type) +{ + return (nalunit_type >= HEVC_NALTYPE_BLA_W_LP) && + (nalunit_type <= HEVC_NALTYPE_RSV_IRAP_VCL23); +} + +static unsigned char bspp_hevc_picture_is_cra(enum hevc_nalunittype nalunit_type) +{ + return (nalunit_type == HEVC_NALTYPE_CRA); +} + +static unsigned char bspp_hevc_picture_is_idr(enum hevc_nalunittype nalunit_type) +{ + return (nalunit_type == HEVC_NALTYPE_IDR_N_LP) || + (nalunit_type == HEVC_NALTYPE_IDR_W_RADL); +} + +static unsigned char bspp_hevc_picture_is_bla(enum hevc_nalunittype nalunit_type) +{ + return (nalunit_type >= HEVC_NALTYPE_BLA_W_LP) && + (nalunit_type <= HEVC_NALTYPE_BLA_N_LP); +} + +static unsigned char bspp_hevc_picture_getnorasl_outputflag + (enum hevc_nalunittype nalunit_type, + struct bspp_hevc_inter_pict_ctx *inter_pict_ctx) +{ + VDEC_ASSERT(inter_pict_ctx); + + if (bspp_hevc_picture_is_idr(nalunit_type) || + bspp_hevc_picture_is_bla(nalunit_type) || + inter_pict_ctx->first_after_eos || + (bspp_hevc_picture_is_cra(nalunit_type) && inter_pict_ctx->seq_pic_count == 1)) + return 1; + + return 0; +} + +static unsigned char bspp_hevc_range_extensions_is_enabled + (struct bspp_hevc_profile_tierlevel *profile_tierlevel) +{ + unsigned char is_enabled; + + is_enabled = profile_tierlevel->general_profile_idc >= 4 || + profile_tierlevel->general_profile_compatibility_flag[4]; + + return is_enabled; +} + +static void bspp_hevc_parse_codec_config(void *hndl_swsr_ctx, unsigned int *unit_count, + unsigned int *unit_array_count, + unsigned int *delim_length, + unsigned int *size_delim_length) +{ + unsigned long long value = 23; + + /* + * Set the shift-register up to provide next 23 bytes + * without emulation prevention detection. + */ + swsr_consume_delim(hndl_swsr_ctx, SWSR_EMPREVENT_NONE, 0, &value); + /* + * Codec config header must be read for size delimited data (HEVC) + * to get to the start of each unit. + * This parsing follows section 8.3.3.1.2 of ISO/IEC 14496-15:2013. + */ + swsr_read_bits(hndl_swsr_ctx, 8 * 4); + swsr_read_bits(hndl_swsr_ctx, 8 * 4); + swsr_read_bits(hndl_swsr_ctx, 8 * 4); + swsr_read_bits(hndl_swsr_ctx, 8 * 4); + swsr_read_bits(hndl_swsr_ctx, 8 * 4); + swsr_read_bits(hndl_swsr_ctx, 8); + + *delim_length = ((swsr_read_bits(hndl_swsr_ctx, 8) & 0x3) + 1) * 8; + *unit_array_count = swsr_read_bits(hndl_swsr_ctx, 8); + + /* Size delimiter is only 2 bytes for HEVC codec configuration. */ + *size_delim_length = 2 * 8; +} + +static void bspp_hevc_update_unitcounts(void *hndl_swsr_ctx, unsigned int *unit_count, + unsigned int *unit_array_count) +{ + if (*unit_array_count != 0) { + unsigned long long value = 3; + + if (*unit_count == 0) { + /* + * Set the shift-register up to provide next 3 bytes + * without emulation prevention detection. + */ + swsr_consume_delim(hndl_swsr_ctx, SWSR_EMPREVENT_NONE, 0, &value); + + swsr_read_bits(hndl_swsr_ctx, 8); + *unit_count = swsr_read_bits(hndl_swsr_ctx, 16); + + (*unit_array_count)--; + (*unit_count)--; + } + } +} + +void bspp_hevc_determine_unittype(unsigned char bitstream_unittype, + int disable_mvc, + enum bspp_unit_type *bspp_unittype) +{ + /* 6 bits for NAL Unit Type in HEVC */ + unsigned char type = (bitstream_unittype >> 1) & 0x3f; + + switch (type) { + case HEVC_NALTYPE_VPS: + *bspp_unittype = BSPP_UNIT_VPS; + break; + + case HEVC_NALTYPE_SPS: + *bspp_unittype = BSPP_UNIT_SEQUENCE; + break; + + case HEVC_NALTYPE_PPS: + *bspp_unittype = BSPP_UNIT_PPS; + break; + + case HEVC_NALTYPE_TRAIL_N: + case HEVC_NALTYPE_TRAIL_R: + case HEVC_NALTYPE_TSA_N: + case HEVC_NALTYPE_TSA_R: + case HEVC_NALTYPE_STSA_N: + case HEVC_NALTYPE_STSA_R: + case HEVC_NALTYPE_RADL_N: + case HEVC_NALTYPE_RADL_R: + case HEVC_NALTYPE_RASL_N: + case HEVC_NALTYPE_RASL_R: + case HEVC_NALTYPE_BLA_W_LP: + case HEVC_NALTYPE_BLA_W_RADL: + case HEVC_NALTYPE_BLA_N_LP: + case HEVC_NALTYPE_IDR_W_RADL: + case HEVC_NALTYPE_IDR_N_LP: + case HEVC_NALTYPE_CRA: + case HEVC_NALTYPE_EOS: + /* Attach EOS to picture data, so it can be detected in FW */ + *bspp_unittype = BSPP_UNIT_PICTURE; + break; + + case HEVC_NALTYPE_AUD: + case HEVC_NALTYPE_PREFIX_SEI: + case HEVC_NALTYPE_SUFFIX_SEI: + case HEVC_NALTYPE_EOB: + case HEVC_NALTYPE_FD: + *bspp_unittype = BSPP_UNIT_NON_PICTURE; + break; + + default: + *bspp_unittype = BSPP_UNIT_UNSUPPORTED; + break; + } +} + +int bspp_hevc_set_parser_config(enum vdec_bstr_format bstr_format, + struct bspp_vid_std_features *pvidstd_features, + struct bspp_swsr_ctx *pswsr_ctx, + struct bspp_parser_callbacks *parser_callbacks, + struct bspp_inter_pict_data *pinterpict_data) +{ + /* set HEVC parser callbacks. */ + parser_callbacks->parse_unit_cb = bspp_hevc_unitparser; + parser_callbacks->release_data_cb = bspp_hevc_releasedata; + parser_callbacks->reset_data_cb = bspp_hevc_resetdata; + parser_callbacks->parse_codec_config_cb = bspp_hevc_parse_codec_config; + parser_callbacks->update_unit_counts_cb = bspp_hevc_update_unitcounts; + parser_callbacks->initialise_parsing_cb = bspp_hevc_initialiseparsing; + parser_callbacks->finalise_parsing_cb = bspp_hevc_finaliseparsing; + + /* Set HEVC specific features. */ + pvidstd_features->seq_size = sizeof(struct bspp_hevc_sequ_hdr_info); + pvidstd_features->uses_vps = 1; + pvidstd_features->vps_size = sizeof(struct bspp_hevc_vps); + pvidstd_features->uses_pps = 1; + pvidstd_features->pps_size = sizeof(struct bspp_hevc_pps); + + /* Set HEVC specific shift register config. */ + pswsr_ctx->emulation_prevention = SWSR_EMPREVENT_00000300; + + if (bstr_format == VDEC_BSTRFORMAT_DEMUX_BYTESTREAM || + bstr_format == VDEC_BSTRFORMAT_ELEMENTARY) { + pswsr_ctx->sr_config.delim_type = SWSR_DELIM_SCP; + pswsr_ctx->sr_config.delim_length = 3 * 8; + pswsr_ctx->sr_config.scp_value = 0x000001; + } else if (bstr_format == VDEC_BSTRFORMAT_DEMUX_SIZEDELIMITED) { + pswsr_ctx->sr_config.delim_type = SWSR_DELIM_SIZE; + pswsr_ctx->sr_config.delim_length = 4 * 8; + } else { + return IMG_ERROR_NOT_SUPPORTED; + } + + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/hevc_secure_parser.h b/drivers/media/platform/imagination/vxe-vxd/decoder/hevc_secure_parser.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/hevc_secure_parser.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/hevc_secure_parser.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,455 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * h.264 secure data unit parsing API. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstreming + * Sidraya Jayagond + */ +#ifndef __HEVCSECUREPARSER_H__ +#define __HEVCSECUREPARSER_H__ + +#include "bspp_int.h" + +#define HEVC_MAX_NUM_PROFILE_IDC (32) +#define HEVC_MAX_NUM_SUBLAYERS (7) +#define HEVC_MAX_VPS_OP_SETS_PLUS1 (1024) +#define HEVC_MAX_VPS_NUH_RESERVED_ZERO_LAYER_ID_PLUS1 (1) +#define HEVC_MAX_NUM_REF_PICS (16) +#define HEVC_MAX_NUM_ST_REF_PIC_SETS (65) +#define HEVC_MAX_NUM_LT_REF_PICS (32) +#define HEVC_MAX_NUM_REF_IDX_ACTIVE (15) +#define HEVC_LEVEL_IDC_MIN (30) +#define HEVC_LEVEL_IDC_MAX (186) +#define HEVC_1_0_PROFILE_IDC_MAX (3) +#define HEVC_MAX_CPB_COUNT (32) +#define HEVC_MIN_CODED_UNIT_SIZE (8) + +/* hevc scaling lists (all values are maximum possible ones) */ +#define HEVC_SCALING_LIST_NUM_SIZES (4) +#define HEVC_SCALING_LIST_NUM_MATRICES (6) +#define HEVC_SCALING_LIST_MATRIX_SIZE (64) + +#define HEVC_MAX_TILE_COLS (20) +#define HEVC_MAX_TILE_ROWS (22) + +#define HEVC_EXTENDED_SAR (255) + +#define HEVC_MAX_CHROMA_QP (6) + +enum hevc_nalunittype { + HEVC_NALTYPE_TRAIL_N = 0, + HEVC_NALTYPE_TRAIL_R = 1, + HEVC_NALTYPE_TSA_N = 2, + HEVC_NALTYPE_TSA_R = 3, + HEVC_NALTYPE_STSA_N = 4, + HEVC_NALTYPE_STSA_R = 5, + HEVC_NALTYPE_RADL_N = 6, + HEVC_NALTYPE_RADL_R = 7, + HEVC_NALTYPE_RASL_N = 8, + HEVC_NALTYPE_RASL_R = 9, + HEVC_NALTYPE_RSV_VCL_N10 = 10, + HEVC_NALTYPE_RSV_VCL_R11 = 11, + HEVC_NALTYPE_RSV_VCL_N12 = 12, + HEVC_NALTYPE_RSV_VCL_R13 = 13, + HEVC_NALTYPE_RSV_VCL_N14 = 14, + HEVC_NALTYPE_RSV_VCL_R15 = 15, + HEVC_NALTYPE_BLA_W_LP = 16, + HEVC_NALTYPE_BLA_W_RADL = 17, + HEVC_NALTYPE_BLA_N_LP = 18, + HEVC_NALTYPE_IDR_W_RADL = 19, + HEVC_NALTYPE_IDR_N_LP = 20, + HEVC_NALTYPE_CRA = 21, + HEVC_NALTYPE_RSV_IRAP_VCL22 = 22, + HEVC_NALTYPE_RSV_IRAP_VCL23 = 23, + HEVC_NALTYPE_VPS = 32, + HEVC_NALTYPE_SPS = 33, + HEVC_NALTYPE_PPS = 34, + HEVC_NALTYPE_AUD = 35, + HEVC_NALTYPE_EOS = 36, + HEVC_NALTYPE_EOB = 37, + HEVC_NALTYPE_FD = 38, + HEVC_NALTYPE_PREFIX_SEI = 39, + HEVC_NALTYPE_SUFFIX_SEI = 40, + HEVC_NALTYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +enum bspp_hevcslicetype { + HEVC_SLICE_B = 0, + HEVC_SLICE_P = 1, + HEVC_SLICE_I = 2, + HEVC_SLICE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* HEVC NAL unit header */ +struct bspp_hevcnalheader { + unsigned char nal_unit_type; + unsigned char nuh_layer_id; + unsigned char nuh_temporal_id_plus1; +}; + +/* HEVC video profile_tier_level */ +struct bspp_hevc_profile_tierlevel { + unsigned char general_profile_space; + unsigned char general_tier_flag; + unsigned char general_profile_idc; + unsigned char general_profile_compatibility_flag[HEVC_MAX_NUM_PROFILE_IDC]; + unsigned char general_progressive_source_flag; + unsigned char general_interlaced_source_flag; + unsigned char general_non_packed_constraint_flag; + unsigned char general_frame_only_constraint_flag; + unsigned char general_max_12bit_constraint_flag; + unsigned char general_max_10bit_constraint_flag; + unsigned char general_max_8bit_constraint_flag; + unsigned char general_max_422chroma_constraint_flag; + unsigned char general_max_420chroma_constraint_flag; + unsigned char general_max_monochrome_constraint_flag; + unsigned char general_intra_constraint_flag; + unsigned char general_one_picture_only_constraint_flag; + unsigned char general_lower_bit_rate_constraint_flag; + unsigned char general_level_idc; + unsigned char sub_layer_profile_present_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_level_present_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_profile_space[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_tier_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_profile_idc[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_profile_compatibility_flag[HEVC_MAX_NUM_SUBLAYERS - + 1][HEVC_MAX_NUM_PROFILE_IDC]; + unsigned char sub_layer_progressive_source_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_interlaced_source_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_non_packed_constraint_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_frame_only_constraint_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_max_12bit_constraint_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_max_10bit_constraint_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_max_8bit_constraint_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_max_422chroma_constraint_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_max_420chroma_constraint_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_max_monochrome_constraint_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_intra_constraint_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_one_picture_only_constraint_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_lower_bit_rate_constraint_flag[HEVC_MAX_NUM_SUBLAYERS - 1]; + unsigned char sub_layer_level_idc[HEVC_MAX_NUM_SUBLAYERS - 1]; +}; + +/* HEVC sub layer HRD parameters */ +struct bspp_hevc_sublayer_hrd_parameters { + unsigned char bit_rate_value_minus1[HEVC_MAX_CPB_COUNT]; + unsigned char cpb_size_value_minus1[HEVC_MAX_CPB_COUNT]; + unsigned char cpb_size_du_value_minus1[HEVC_MAX_CPB_COUNT]; + unsigned char bit_rate_du_value_minus1[HEVC_MAX_CPB_COUNT]; + unsigned char cbr_flag[HEVC_MAX_CPB_COUNT]; +}; + +/* HEVC HRD parameters */ +struct bspp_hevc_hrd_parameters { + unsigned char nal_hrd_parameters_present_flag; + unsigned char vcl_hrd_parameters_present_flag; + unsigned char sub_pic_hrd_params_present_flag; + unsigned char tick_divisor_minus2; + unsigned char du_cpb_removal_delay_increment_length_minus1; + unsigned char sub_pic_cpb_params_in_pic_timing_sei_flag; + unsigned char dpb_output_delay_du_length_minus1; + unsigned char bit_rate_scale; + unsigned char cpb_size_scale; + unsigned char cpb_size_du_scale; + unsigned char initial_cpb_removal_delay_length_minus1; + unsigned char au_cpb_removal_delay_length_minus1; + unsigned char dpb_output_delay_length_minus1; + unsigned char fixed_pic_rate_general_flag[HEVC_MAX_NUM_SUBLAYERS]; + unsigned char fixed_pic_rate_within_cvs_flag[HEVC_MAX_NUM_SUBLAYERS]; + unsigned char elemental_duration_in_tc_minus1[HEVC_MAX_NUM_SUBLAYERS]; + unsigned char low_delay_hrd_flag[HEVC_MAX_NUM_SUBLAYERS]; + unsigned char cpb_cnt_minus1[HEVC_MAX_NUM_SUBLAYERS]; + struct bspp_hevc_sublayer_hrd_parameters sublayhrdparams[HEVC_MAX_NUM_SUBLAYERS]; +}; + +/* HEVC video parameter set */ +struct bspp_hevc_vps { + unsigned char is_different; + unsigned char is_sent; + unsigned char is_available; + unsigned char vps_video_parameter_set_id; + unsigned char vps_reserved_three_2bits; + unsigned char vps_max_layers_minus1; + unsigned char vps_max_sub_layers_minus1; + unsigned char vps_temporal_id_nesting_flag; + unsigned short vps_reserved_0xffff_16bits; + struct bspp_hevc_profile_tierlevel profiletierlevel; + unsigned char vps_max_dec_pic_buffering_minus1[HEVC_MAX_NUM_SUBLAYERS]; + unsigned char vps_max_num_reorder_pics[HEVC_MAX_NUM_SUBLAYERS]; + unsigned char vps_max_latency_increase_plus1[HEVC_MAX_NUM_SUBLAYERS]; + unsigned char vps_sub_layer_ordering_info_present_flag; + unsigned char vps_max_layer_id; + unsigned char vps_num_layer_sets_minus1; + unsigned char layer_id_included_flag[HEVC_MAX_VPS_OP_SETS_PLUS1] + [HEVC_MAX_VPS_NUH_RESERVED_ZERO_LAYER_ID_PLUS1]; + unsigned char vps_timing_info_present_flag; + unsigned int vps_num_units_in_tick; + unsigned int vps_time_scale; + unsigned char vps_poc_proportional_to_timing_flag; + unsigned char vps_num_ticks_poc_diff_one_minus1; + unsigned char vps_num_hrd_parameters; + unsigned char *hrd_layer_set_idx; + unsigned char *cprms_present_flag; + unsigned char vps_extension_flag; + unsigned char vps_extension_data_flag; +}; + +/* HEVC scaling lists */ +struct bspp_hevc_scalinglist_data { + unsigned char dccoeffs[HEVC_SCALING_LIST_NUM_SIZES - 2][HEVC_SCALING_LIST_NUM_MATRICES]; + unsigned char lists[HEVC_SCALING_LIST_NUM_SIZES][HEVC_SCALING_LIST_NUM_MATRICES] + [HEVC_SCALING_LIST_MATRIX_SIZE]; +}; + +/* HEVC short term reference picture set */ +struct bspp_hevc_shortterm_refpicset { + unsigned char num_negative_pics; + unsigned char num_positive_pics; + short delta_poc_s0[HEVC_MAX_NUM_REF_PICS]; + short delta_poc_s1[HEVC_MAX_NUM_REF_PICS]; + unsigned char used_bycurr_pic_s0[HEVC_MAX_NUM_REF_PICS]; + unsigned char used_bycurr_pic_s1[HEVC_MAX_NUM_REF_PICS]; + unsigned char num_delta_pocs; +}; + +/* HEVC video usability information */ +struct bspp_hevc_vui_params { + unsigned char aspect_ratio_info_present_flag; + unsigned char aspect_ratio_idc; + unsigned short sar_width; + unsigned short sar_height; + unsigned char overscan_info_present_flag; + unsigned char overscan_appropriate_flag; + unsigned char video_signal_type_present_flag; + unsigned char video_format; + unsigned char video_full_range_flag; + unsigned char colour_description_present_flag; + unsigned char colour_primaries; + unsigned char transfer_characteristics; + unsigned char matrix_coeffs; + unsigned char chroma_loc_info_present_flag; + unsigned char chroma_sample_loc_type_top_field; + unsigned char chroma_sample_loc_type_bottom_field; + unsigned char neutral_chroma_indication_flag; + unsigned char field_seq_flag; + unsigned char frame_field_info_present_flag; + unsigned char default_display_window_flag; + unsigned short def_disp_win_left_offset; + unsigned short def_disp_win_right_offset; + unsigned short def_disp_win_top_offset; + unsigned short def_disp_win_bottom_offset; + unsigned char vui_timing_info_present_flag; + unsigned int vui_num_units_in_tick; + unsigned int vui_time_scale; + unsigned char vui_poc_proportional_to_timing_flag; + unsigned int vui_num_ticks_poc_diff_one_minus1; + unsigned char vui_hrd_parameters_present_flag; + struct bspp_hevc_hrd_parameters vui_hrd_params; + unsigned char bitstream_restriction_flag; + unsigned char tiles_fixed_structure_flag; + unsigned char motion_vectors_over_pic_boundaries_flag; + unsigned char restricted_ref_pic_lists_flag; + unsigned short min_spatial_segmentation_idc; + unsigned char max_bytes_per_pic_denom; + unsigned char max_bits_per_min_cu_denom; + unsigned char log2_max_mv_length_horizontal; + unsigned char log2_max_mv_length_vertical; +}; + +/* HEVC sps range extensions */ +struct bspp_hevc_sps_range_exts { + unsigned char transform_skip_rotation_enabled_flag; + unsigned char transform_skip_context_enabled_flag; + unsigned char implicit_rdpcm_enabled_flag; + unsigned char explicit_rdpcm_enabled_flag; + unsigned char extended_precision_processing_flag; + unsigned char intra_smoothing_disabled_flag; + unsigned char high_precision_offsets_enabled_flag; + unsigned char persistent_rice_adaptation_enabled_flag; + unsigned char cabac_bypass_alignment_enabled_flag; +}; + +/* HEVC sequence parameter set */ +struct bspp_hevc_sps { + unsigned char is_different; + unsigned char is_sent; + unsigned char is_available; + unsigned char sps_video_parameter_set_id; + unsigned char sps_max_sub_layers_minus1; + unsigned char sps_temporal_id_nesting_flag; + struct bspp_hevc_profile_tierlevel profile_tier_level; + unsigned char sps_seq_parameter_set_id; + unsigned char chroma_format_idc; + unsigned char separate_colour_plane_flag; + unsigned int pic_width_in_luma_samples; + unsigned int pic_height_in_luma_samples; + unsigned char conformance_window_flag; + unsigned short conf_win_left_offset; + unsigned short conf_win_right_offset; + unsigned short conf_win_top_offset; + unsigned short conf_win_bottom_offset; + unsigned char bit_depth_luma_minus8; + unsigned char bit_depth_chroma_minus8; + unsigned char log2_max_pic_order_cnt_lsb_minus4; + unsigned char sps_sub_layer_ordering_info_present_flag; + unsigned char sps_max_dec_pic_buffering_minus1[HEVC_MAX_NUM_SUBLAYERS]; + unsigned char sps_max_num_reorder_pics[HEVC_MAX_NUM_SUBLAYERS]; + unsigned int sps_max_latency_increase_plus1[HEVC_MAX_NUM_SUBLAYERS]; + unsigned char log2_min_luma_coding_block_size_minus3; + unsigned char log2_diff_max_min_luma_coding_block_size; + unsigned char log2_min_transform_block_size_minus2; + unsigned char log2_diff_max_min_transform_block_size; + unsigned char max_transform_hierarchy_depth_inter; + unsigned char max_transform_hierarchy_depth_intra; + unsigned char scaling_list_enabled_flag; + unsigned char sps_scaling_list_data_present_flag; + struct bspp_hevc_scalinglist_data scalinglist_data; + unsigned char amp_enabled_flag; + unsigned char sample_adaptive_offset_enabled_flag; + unsigned char pcm_enabled_flag; + unsigned char pcm_sample_bit_depth_luma_minus1; + unsigned char pcm_sample_bit_depth_chroma_minus1; + unsigned char log2_min_pcm_luma_coding_block_size_minus3; + unsigned char log2_diff_max_min_pcm_luma_coding_block_size; + unsigned char pcm_loop_filter_disabled_flag; + unsigned char num_short_term_ref_pic_sets; + struct bspp_hevc_shortterm_refpicset rps_list[HEVC_MAX_NUM_ST_REF_PIC_SETS]; + unsigned char long_term_ref_pics_present_flag; + unsigned char num_long_term_ref_pics_sps; + unsigned short lt_ref_pic_poc_lsb_sps[HEVC_MAX_NUM_LT_REF_PICS]; + unsigned char used_by_curr_pic_lt_sps_flag[HEVC_MAX_NUM_LT_REF_PICS]; + unsigned char sps_temporal_mvp_enabled_flag; + unsigned char strong_intra_smoothing_enabled_flag; + unsigned char vui_parameters_present_flag; + struct bspp_hevc_vui_params vui_params; + unsigned char sps_extension_present_flag; + unsigned char sps_range_extensions_flag; + struct bspp_hevc_sps_range_exts range_exts; + unsigned char sps_extension_7bits; + unsigned char sps_extension_data_flag; + /* derived elements */ + unsigned char sub_width_c; + unsigned char sub_height_c; + unsigned char ctb_log2size_y; + unsigned char ctb_size_y; + unsigned int pic_width_in_ctbs_y; + unsigned int pic_height_in_ctbs_y; + unsigned int pic_size_in_ctbs_y; + int max_pic_order_cnt_lsb; + unsigned int sps_max_latency_pictures[HEVC_MAX_NUM_SUBLAYERS]; + /* raw vui data as extracted from bitstream. */ + struct bspp_raw_bitstream_data *vui_raw_data; +}; + +/** + * struct bspp_hevc_sequ_hdr_info - This structure contains HEVC sequence + * header information (VPS, SPS, VUI) + * contains everything parsed from the + * video/sequence header. + * @vps: HEVC sequence header information + * @sps:HEVC sequence header information + */ +struct bspp_hevc_sequ_hdr_info { + struct bspp_hevc_vps vps; + struct bspp_hevc_sps sps; +}; + +/* HEVC pps range extensions */ +struct bspp_hevc_pps_range_exts { + unsigned char log2_max_transform_skip_block_size_minus2; + unsigned char cross_component_prediction_enabled_flag; + unsigned char chroma_qp_offset_list_enabled_flag; + unsigned char diff_cu_chroma_qp_offset_depth; + unsigned char chroma_qp_offset_list_len_minus1; + unsigned char cb_qp_offset_list[HEVC_MAX_CHROMA_QP]; + unsigned char cr_qp_offset_list[HEVC_MAX_CHROMA_QP]; + unsigned char log2_sao_offset_scale_luma; + unsigned char log2_sao_offset_scale_chroma; +}; + +/* HEVC picture parameter set */ +struct bspp_hevc_pps { + unsigned char is_available; + unsigned char is_param_copied; + unsigned char pps_pic_parameter_set_id; + unsigned char pps_seq_parameter_set_id; + unsigned char dependent_slice_segments_enabled_flag; + unsigned char output_flag_present_flag; + unsigned char num_extra_slice_header_bits; + unsigned char sign_data_hiding_enabled_flag; + unsigned char cabac_init_present_flag; + unsigned char num_ref_idx_l0_default_active_minus1; + unsigned char num_ref_idx_l1_default_active_minus1; + unsigned char init_qp_minus26; + unsigned char constrained_intra_pred_flag; + unsigned char transform_skip_enabled_flag; + unsigned char cu_qp_delta_enabled_flag; + unsigned char diff_cu_qp_delta_depth; + int pps_cb_qp_offset; + int pps_cr_qp_offset; + unsigned char pps_slice_chroma_qp_offsets_present_flag; + unsigned char weighted_pred_flag; + unsigned char weighted_bipred_flag; + unsigned char transquant_bypass_enabled_flag; + unsigned char tiles_enabled_flag; + unsigned char entropy_coding_sync_enabled_flag; + unsigned char num_tile_columns_minus1; + unsigned char num_tile_rows_minus1; + unsigned char uniform_spacing_flag; + unsigned char column_width_minus1[HEVC_MAX_TILE_COLS]; + unsigned char row_height_minus1[HEVC_MAX_TILE_ROWS]; + unsigned char loop_filter_across_tiles_enabled_flag; + unsigned char pps_loop_filter_across_slices_enabled_flag; + unsigned char deblocking_filter_control_present_flag; + unsigned char deblocking_filter_override_enabled_flag; + unsigned char pps_deblocking_filter_disabled_flag; + unsigned char pps_beta_offset_div2; + unsigned char pps_tc_offset_div2; + unsigned char pps_scaling_list_data_present_flag; + struct bspp_hevc_scalinglist_data scaling_list; + unsigned char lists_modification_present_flag; + unsigned char log2_parallel_merge_level_minus2; + unsigned char slice_segment_header_extension_present_flag; + unsigned char pps_extension_present_flag; + unsigned char pps_range_extensions_flag; + struct bspp_hevc_pps_range_exts range_exts; + unsigned char pps_extension_7bits; + unsigned char pps_extension_data_flag; + /* derived elements */ + unsigned short col_bd[HEVC_MAX_TILE_COLS + 1]; + unsigned short row_bd[HEVC_MAX_TILE_ROWS + 1]; + /* PVDEC derived elements */ + unsigned int max_tile_height_in_ctbs_y; +}; + +/* HEVC slice segment header */ +struct bspp_hevc_slice_segment_header { + unsigned char bslice_is_idr; + unsigned char first_slice_segment_in_pic_flag; + unsigned char no_output_of_prior_pics_flag; + unsigned char slice_pic_parameter_set_id; + unsigned char dependent_slice_segment_flag; + unsigned int slice_segment_address; +}; + +/* + * @Function bspp_hevc_set_parser_config + * sets the parser configuration. + */ +int bspp_hevc_set_parser_config(enum vdec_bstr_format bstr_format, + struct bspp_vid_std_features *pvidstd_features, + struct bspp_swsr_ctx *pswsr_ctx, + struct bspp_parser_callbacks *pparser_callbacks, + struct bspp_inter_pict_data *pinterpict_data); + +void bspp_hevc_determine_unittype(unsigned char bitstream_unittype, + int disable_mvc, + enum bspp_unit_type *bspp_unittype); + +#endif /*__H264SECUREPARSER_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/hw_control.c b/drivers/media/platform/imagination/vxe-vxd/decoder/hw_control.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/hw_control.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/hw_control.c 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,1233 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VXD DEC Hardware control implementation + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#include +#include +#include +#include +#include + +#include "decoder.h" +#include "hw_control.h" +#include "img_msvdx_vdmc_regs.h" +#include "img_pvdec_core_regs.h" +#include "img_pvdec_pixel_regs.h" +#include "img_pvdec_test_regs.h" +#include "img_vdec_fw_msg.h" +#include "img_video_bus4_mmu_regs.h" +#include "img_msvdx_core_regs.h" +#include "reg_io2.h" +#include "vdecdd_defs.h" +#include "vxd_dec.h" +#include "vxd_ext.h" +#include "vxd_int.h" +#include "vxd_pvdec_priv.h" + +#define MSG_GROUP_MASK 0xf0 + +struct hwctrl_ctx { + unsigned int is_initialised; + unsigned int is_on_seq_replay; + unsigned int replay_tid; + unsigned int num_pipes; + struct vdecdd_dd_devconfig devconfig; + void *hndl_vxd; + void *dec_core; + void *comp_init_userdata; + struct vidio_ddbufinfo dev_ptd_bufinfo; + struct lst_t pend_pict_list; + struct hwctrl_msgstatus host_msg_status; + void *hmsg_task_event; + void *hmsg_task_kick; + void *hmsg_task; + unsigned int is_msg_task_active; + struct hwctrl_state state; + struct hwctrl_state prev_state; + unsigned int is_prev_hw_state_set; + unsigned int is_fatal_state; +}; + +struct vdeckm_context { + unsigned int core_num; + struct vxd_coreprops props; + unsigned short current_msgid; + unsigned char reader_active; + void *comms_ram_addr; + unsigned int state_offset; + unsigned int state_size; +}; + +/* + * Panic reason identifier. + */ +enum pvdec_panic_reason { + PANIC_REASON_OTHER = 0, + PANIC_REASON_WDT, + PANIC_REASON_READ_TIMEOUT, + PANIC_REASON_CMD_TIMEOUT, + PANIC_REASON_MMU_FAULT, + PANIC_REASON_MAX, + PANIC_REASON_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Panic reason strings. + * NOTE: Should match the pvdec_panic_reason ids. + */ +static unsigned char *apanic_reason[PANIC_REASON_MAX] = { + [PANIC_REASON_OTHER] = "Other", + [PANIC_REASON_WDT] = "Watch Dog Timeout", + [PANIC_REASON_READ_TIMEOUT] = "Read Timeout", + [PANIC_REASON_CMD_TIMEOUT] = "Command Timeout", + [PANIC_REASON_MMU_FAULT] = "MMU Page Fault" +}; + +/* + * Maximum length of the panic reason string. + */ +#define PANIC_REASON_LEN (255) + +static struct vdeckm_context acore_ctx[VXD_MAX_CORES] = {0}; + +static int vdeckm_getregsoffsets(const void *hndl_vxd, + struct decoder_regsoffsets *regs_offsets) +{ + struct vdeckm_context *core_ctx = (struct vdeckm_context *)hndl_vxd; + + if (!core_ctx) + return IMG_ERROR_INVALID_PARAMETERS; + + regs_offsets->vdmc_cmd_offset = MSVDX_CMD_OFFSET; + regs_offsets->vec_offset = MSVDX_VEC_OFFSET; + regs_offsets->entropy_offset = PVDEC_ENTROPY_OFFSET; + regs_offsets->vec_be_regs_offset = PVDEC_VEC_BE_OFFSET; + regs_offsets->vdec_be_codec_regs_offset = PVDEC_VEC_BE_CODEC_OFFSET; + + return IMG_SUCCESS; +} + +static int vdeckm_send_message(const void *hndl_vxd, + struct hwctrl_to_kernel_msg *to_kernelmsg, + void *vxd_dec_ctx) +{ + struct vdeckm_context *core_ctx = (struct vdeckm_context *)hndl_vxd; + unsigned int count = 0; + unsigned int *msg; + + if (!core_ctx || !to_kernelmsg) + return IMG_ERROR_INVALID_PARAMETERS; + + msg = kzalloc(VXD_SIZE_MSG_BUFFER, GFP_KERNEL); + if (!msg) + return IMG_ERROR_OUT_OF_MEMORY; + + msg[count++] = to_kernelmsg->flags; + msg[count++] = to_kernelmsg->msg_size; + + memcpy(&msg[count], to_kernelmsg->msg_hdr, to_kernelmsg->msg_size); + + core_ctx->reader_active = 1; + + if (!(to_kernelmsg->msg_hdr)) { + kfree(msg); + return IMG_ERROR_INVALID_PARAMETERS; + } + + pr_debug("[HWCTRL] adding message to vxd queue\n"); + vxd_send_msg(vxd_dec_ctx, (struct vxd_fw_msg *)msg); + + kfree(msg); + + return 0; +} + +static void vdeckm_return_msg(const void *hndl_vxd, + struct hwctrl_to_kernel_msg *to_kernelmsg) +{ + if (to_kernelmsg) + kfree(to_kernelmsg->msg_hdr); +} + +static int vdeckm_handle_mtxtohost_msg(unsigned int *msg, struct lst_t *pend_pict_list, + enum vxd_msg_attr *msg_attr, + struct dec_decpict **decpict, + unsigned char msg_type, + unsigned int trans_id) +{ + struct dec_decpict *pdec_pict; + + int ret = 0; + switch (msg_type) { + case FW_DEVA_COMPLETED: + { + struct dec_pict_attrs *pict_attrs = NULL; + unsigned short error_flags = 0; + unsigned int no_bewdts = 0; + unsigned int mbs_dropped = 0; + unsigned int mbs_recovered = 0; + unsigned char flag = 0; + + error_flags = MEMIO_READ_FIELD(msg, FW_DEVA_COMPLETED_ERROR_FLAGS); + + no_bewdts = MEMIO_READ_FIELD(msg, FW_DEVA_COMPLETED_NUM_BEWDTS); + + mbs_dropped = MEMIO_READ_FIELD(msg, FW_DEVA_COMPLETED_NUM_MBSDROPPED); + + mbs_recovered = MEMIO_READ_FIELD(msg, FW_DEVA_COMPLETED_NUM_MBSRECOVERED); + + pdec_pict = lst_first(pend_pict_list); + while (pdec_pict) { + if (pdec_pict->transaction_id == trans_id) + break; + pdec_pict = lst_next(pdec_pict); + } + /* + * We must have a picture in the list that matches + * the transaction id + */ + if (!pdec_pict) + return IMG_ERROR_FATAL; + + if (!(pdec_pict->first_fld_fwmsg) || !(pdec_pict->second_fld_fwmsg)) + return IMG_ERROR_FATAL; + + flag = pdec_pict->first_fld_fwmsg->pict_attrs.first_fld_rcvd; + if (flag) { + pict_attrs = &pdec_pict->second_fld_fwmsg->pict_attrs; + } else { + pict_attrs = &pdec_pict->first_fld_fwmsg->pict_attrs; + flag = 1; + } + + pict_attrs->fe_err = (unsigned int)error_flags; + pict_attrs->no_be_wdt = no_bewdts; + pict_attrs->mbs_dropped = mbs_dropped; + pict_attrs->mbs_recovered = mbs_recovered; + /* + * We may successfully replayed the picture, + * so reset the error flags + */ + pict_attrs->pict_attrs.dwrfired = 0; + pict_attrs->pict_attrs.mmufault = 0; + pict_attrs->pict_attrs.deverror = 0; + + *msg_attr = VXD_MSG_ATTR_DECODED; + *decpict = pdec_pict; + break; + } + + case FW_DEVA_PANIC: + { + unsigned int panic_info = MEMIO_READ_FIELD(msg, FW_DEVA_PANIC_ERROR_INT); + unsigned char panic_reason[PANIC_REASON_LEN] = "Reason(s): "; + unsigned char is_panic_reson_identified = 0; + /* + * Create panic reason string. + */ + if (REGIO_READ_FIELD(panic_info, PVDEC_CORE, CR_PVDEC_HOST_INTERRUPT_STATUS, + CR_HOST_SYS_WDT)) { + strncat(panic_reason, apanic_reason[PANIC_REASON_WDT], + PANIC_REASON_LEN - 1); + is_panic_reson_identified = 1; + } + if (REGIO_READ_FIELD(panic_info, PVDEC_CORE, CR_PVDEC_HOST_INTERRUPT_STATUS, + CR_HOST_READ_TIMEOUT_PROC_IRQ)) { + strncat(panic_reason, apanic_reason[PANIC_REASON_READ_TIMEOUT], + PANIC_REASON_LEN - 1); + is_panic_reson_identified = 1; + } + if (REGIO_READ_FIELD(panic_info, PVDEC_CORE, CR_PVDEC_HOST_INTERRUPT_STATUS, + CR_HOST_COMMAND_TIMEOUT_PROC_IRQ)) { + strncat(panic_reason, apanic_reason[PANIC_REASON_CMD_TIMEOUT], + PANIC_REASON_LEN - 1); + is_panic_reson_identified = 1; + } + if (!is_panic_reson_identified) { + strncat(panic_reason, apanic_reason[PANIC_REASON_OTHER], + PANIC_REASON_LEN - 1); + } + panic_reason[strlen(panic_reason) - 2] = 0; + if (trans_id != 0) + pr_err("TID=0x%08X [FIRMWARE PANIC %s]\n", trans_id, panic_reason); + else + pr_err("TID=NULL [GENERAL FIRMWARE PANIC %s]\n", panic_reason); + ret = IMG_ERROR_FATAL; + + break; + } + + case FW_ASSERT: + { + unsigned int fwfile_namehash = MEMIO_READ_FIELD(msg, FW_ASSERT_FILE_NAME_HASH); + unsigned int fwfile_line = MEMIO_READ_FIELD(msg, FW_ASSERT_FILE_LINE); + + pr_err("ASSERT file name hash:0x%08X line number:%d\n", + fwfile_namehash, fwfile_line); + ret = IMG_ERROR_FATAL; + break; + } + + case FW_SO: + { + unsigned int task_name = MEMIO_READ_FIELD(msg, FW_SO_TASK_NAME); + unsigned char sztaskname[sizeof(unsigned int) + 1]; + + sztaskname[0] = task_name >> 24; + sztaskname[1] = (task_name >> 16) & 0xff; + sztaskname[2] = (task_name >> 8) & 0xff; + sztaskname[3] = task_name & 0xff; + if (sztaskname[3] != 0) + sztaskname[4] = 0; + pr_warn("STACK OVERFLOW for %s task\n", sztaskname); + break; + } + + case FW_VXD_EMPTY_COMPL: + /* + * Empty completion message sent as response to init, + * configure etc The architecture of vxd.ko module + * requires the firmware to send a reply for every + * message submitted by the user space. + */ + break; + + default: + break; + } + + return ret; +} + +static int vdeckm_handle_hosttomtx_msg(unsigned int *msg, struct lst_t *pend_pict_list, + enum vxd_msg_attr *msg_attr, + struct dec_decpict **decpict, + unsigned char msg_type, + unsigned int trans_id, + unsigned int msg_flags) +{ + struct dec_decpict *pdec_pict; + + pr_debug("Received message from HOST\n"); + + switch (msg_type) { + case FW_DEVA_PARSE: + { + struct dec_pict_attrs *pict_attrs = NULL; + unsigned char flag = 0; + + pdec_pict = lst_first(pend_pict_list); + while (pdec_pict) { + if (pdec_pict->transaction_id == trans_id) + break; + + pdec_pict = lst_next(pdec_pict); + } + + /* + * We must have a picture in the list that matches + * the transaction id + */ + if (!pdec_pict) { + pr_err("Firmware decoded message received\n"); + pr_err("no pending picture\n"); + return IMG_ERROR_FATAL; + } + + if (!(pdec_pict->first_fld_fwmsg) || !(pdec_pict->second_fld_fwmsg)) { + pr_err("invalid pending picture struct\n"); + return IMG_ERROR_FATAL; + } + + flag = pdec_pict->first_fld_fwmsg->pict_attrs.first_fld_rcvd; + if (flag) { + pict_attrs = &pdec_pict->second_fld_fwmsg->pict_attrs; + } else { + pict_attrs = &pdec_pict->first_fld_fwmsg->pict_attrs; + flag = 1; + } + + /* + * The below info is fetched from firmware state + * afterwards, so just set this to zero for now. + */ + pict_attrs->fe_err = 0; + pict_attrs->no_be_wdt = 0; + pict_attrs->mbs_dropped = 0; + pict_attrs->mbs_recovered = 0; + + vxd_get_pictattrs(msg_flags, &pict_attrs->pict_attrs); + vxd_get_msgerrattr(msg_flags, msg_attr); + + if (*msg_attr == VXD_MSG_ATTR_FATAL) + pr_err("[TID=0x%08X] [DECODE_FAILED]\n", trans_id); + if (*msg_attr == VXD_MSG_ATTR_CANCELED) + pr_err("[TID=0x%08X] [DECODE_CANCELED]\n", trans_id); + + *decpict = pdec_pict; + break; + } + + case FW_DEVA_PARSE_FRAGMENT: + /* + * Do nothing - Picture holds the list of fragments. + * So, in case of any error those would be replayed + * anyway. + */ + break; + default: + pr_warn("Unknown message received 0x%02x\n", msg_type); + break; + } + + return 0; +} + +static int vdeckm_process_msg(const void *hndl_vxd, unsigned int *msg, + struct lst_t *pend_pict_list, + unsigned int msg_flags, + enum vxd_msg_attr *msg_attr, + struct dec_decpict **decpict) +{ + struct vdeckm_context *core_ctx = (struct vdeckm_context *)hndl_vxd; + unsigned char msg_type; + unsigned char msg_group; + unsigned int trans_id = 0; + int ret = 0; + struct vdec_pict_hwcrc *pict_hwcrc = NULL; + struct dec_decpict *pdec_pict; + + if (!core_ctx || !msg || !msg_attr || !pend_pict_list || !decpict) + return IMG_ERROR_INVALID_PARAMETERS; + + *msg_attr = VXD_MSG_ATTR_NONE; + *decpict = NULL; + + trans_id = MEMIO_READ_FIELD(msg, FW_DEVA_GENMSG_TRANS_ID); + msg_type = MEMIO_READ_FIELD(msg, FW_DEVA_GENMSG_MSG_TYPE); + msg_group = msg_type & MSG_GROUP_MASK; + + switch (msg_group) { + case MSG_TYPE_START_PSR_MTXHOST_MSG: + ret = vdeckm_handle_mtxtohost_msg(msg, pend_pict_list, msg_attr, + decpict, msg_type, trans_id); + break; + /* + * Picture decode has been returned as unprocessed. + * Locate the picture with corresponding TID and mark + * it as decoded with errors. + */ + case MSG_TYPE_START_PSR_HOSTMTX_MSG: + ret = vdeckm_handle_hosttomtx_msg(msg, pend_pict_list, msg_attr, + decpict, msg_type, trans_id, + msg_flags); + break; + + case FW_DEVA_SIGNATURES_HEVC: + case FW_DEVA_SIGNATURES_LEGACY: + { + unsigned int *signatures = msg + (FW_DEVA_SIGNATURES_SIGNATURES_OFFSET / + sizeof(unsigned int)); + unsigned char sigcount = MEMIO_READ_FIELD(msg, FW_DEVA_SIGNATURES_MSG_SIZE) - + ((FW_DEVA_SIGNATURES_SIZE / sizeof(unsigned int)) - 1); + unsigned int selected = MEMIO_READ_FIELD(msg, FW_DEVA_SIGNATURES_SIGNATURE_SELECT); + unsigned char i, j = 0; + + pdec_pict = lst_first(pend_pict_list); + while (pdec_pict) { + if (pdec_pict->transaction_id == trans_id) + break; + pdec_pict = lst_next(pdec_pict); + } + + /* We must have a picture in the list that matches the tid */ + VDEC_ASSERT(pdec_pict); + if (!pdec_pict) { + pr_err("Firmware signatures message received with no pending picture\n"); + return IMG_ERROR_FATAL; + } + + VDEC_ASSERT(pdec_pict->first_fld_fwmsg); + VDEC_ASSERT(pdec_pict->second_fld_fwmsg); + if (!pdec_pict->first_fld_fwmsg || !pdec_pict->second_fld_fwmsg) { + pr_err("Invalid pending picture struct\n"); + return IMG_ERROR_FATAL; + } + if (pdec_pict->first_fld_fwmsg->pict_hwcrc.first_fld_rcvd) { + pict_hwcrc = &pdec_pict->second_fld_fwmsg->pict_hwcrc; + } else { + pict_hwcrc = &pdec_pict->first_fld_fwmsg->pict_hwcrc; + if (selected & (PVDEC_SIGNATURE_GROUP_20 | PVDEC_SIGNATURE_GROUP_24)) + pdec_pict->first_fld_fwmsg->pict_hwcrc.first_fld_rcvd = TRUE; + } + + for (i = 0; i < 32; i++) { + unsigned int group = selected & (1 << i); + + switch (group) { + case PVDEC_SIGNATURE_GROUP_20: + pict_hwcrc->crc_vdmc_pix_recon = signatures[j++]; + break; + + case PVDEC_SIGNATURE_GROUP_24: + pict_hwcrc->vdeb_sysmem_wrdata = signatures[j++]; + break; + + default: + break; + } + } + + /* sanity check */ + sigcount -= j; + VDEC_ASSERT(sigcount == 0); + + /* + * suppress PVDEC_SIGNATURE_GROUP_1 and notify + * only about groups used for verification + */ +#ifdef DEBUG_DECODER_DRIVER + if (selected & (PVDEC_SIGNATURE_GROUP_20 | PVDEC_SIGNATURE_GROUP_24)) + pr_info("[TID=0x%08X] [SIGNATURES]\n", trans_id); +#endif + + *decpict = pdec_pict; + + break; + } + + default: { +#ifdef DEBUG_DECODER_DRIVER + unsigned short msg_size, i; + + pr_warn("Unknown message type received: 0x%x", msg_type); + + msg_size = MEMIO_READ_FIELD(msg, FW_DEVA_GENMSG_MSG_SIZE); + + for (i = 0; i < msg_size; i++) + pr_info("0x%04x: 0x%08x\n", i, msg[i]); +#endif + break; + } + } + + return ret; +} + +static void vdeckm_vlr_copy(void *dst, void *src, unsigned int size) +{ + unsigned int *pdst = (unsigned int *)dst; + unsigned int *psrc = (unsigned int *)src; + + size /= 4; + while (size--) + *pdst++ = *psrc++; +} + +static int vdeckm_get_core_state(const void *hndl_vxd, struct vxd_states *state) +{ + struct vdeckm_context *core_ctx = (struct vdeckm_context *)hndl_vxd; + struct vdecfw_pvdecfirmwarestate firmware_state; + unsigned char pipe = 0; + +#ifdef ERROR_RECOVERY_SIMULATION + /* + * if disable_fw_irq_value is not zero, return error. If processed further + * the kernel will crash because we have ignored the interrupt, but here + * we will try to access comms_ram_addr which will result in crash. + */ + if (disable_fw_irq_value != 0) + return IMG_ERROR_INVALID_PARAMETERS; +#endif + + if (!core_ctx || !state) + return IMG_ERROR_INVALID_PARAMETERS; + + /* + * If state is requested for the first time. + */ + if (core_ctx->state_size == 0) { + unsigned int regval; + /* + * get the state buffer info. + */ + regval = *((unsigned int *)core_ctx->comms_ram_addr + + (PVDEC_COM_RAM_STATE_BUF_SIZE_AND_OFFSET_OFFSET / sizeof(unsigned int))); + core_ctx->state_size = PVDEC_COM_RAM_BUF_GET_SIZE(regval, STATE); + core_ctx->state_offset = PVDEC_COM_RAM_BUF_GET_OFFSET(regval, STATE); + } + + /* + * If state buffer is available. + */ + if (core_ctx->state_size) { + /* + * Determine the latest transaction to have passed each + * checkpoint in the firmware. + * Read the firmware state from VEC Local RAM + */ + vdeckm_vlr_copy(&firmware_state, (unsigned char *)core_ctx->comms_ram_addr + + core_ctx->state_offset, core_ctx->state_size); + + for (pipe = 0; pipe < core_ctx->props.num_pixel_pipes; pipe++) { + /* + * Set pipe presence. + */ + state->fw_state.pipe_state[pipe].is_pipe_present = 1; + + /* + * For checkpoints copy message ids here. These will + * be translated into transaction ids later. + */ + memcpy(state->fw_state.pipe_state[pipe].acheck_point, + firmware_state.pipestate[pipe].check_point, + sizeof(state->fw_state.pipe_state[pipe].acheck_point)); + state->fw_state.pipe_state[pipe].firmware_action = + firmware_state.pipestate[pipe].firmware_action; + state->fw_state.pipe_state[pipe].cur_codec = + firmware_state.pipestate[pipe].curr_codec; + state->fw_state.pipe_state[pipe].fe_slices = + firmware_state.pipestate[pipe].fe_slices; + state->fw_state.pipe_state[pipe].be_slices = + firmware_state.pipestate[pipe].be_slices; + state->fw_state.pipe_state[pipe].fe_errored_slices = + firmware_state.pipestate[pipe].fe_errored_slices; + state->fw_state.pipe_state[pipe].be_errored_slices = + firmware_state.pipestate[pipe].be_errored_slices; + state->fw_state.pipe_state[pipe].be_mbs_dropped = + firmware_state.pipestate[pipe].be_mbs_dropped; + state->fw_state.pipe_state[pipe].be_mbs_recovered = + firmware_state.pipestate[pipe].be_mbs_recovered; + state->fw_state.pipe_state[pipe].fe_mb.x = + firmware_state.pipestate[pipe].last_fe_mb_xy & 0xFF; + state->fw_state.pipe_state[pipe].fe_mb.y = + (firmware_state.pipestate[pipe].last_fe_mb_xy >> 16) & 0xFF; + state->fw_state.pipe_state[pipe].be_mb.x = + REGIO_READ_FIELD(firmware_state.pipestate[pipe].last_be_mb_xy, + MSVDX_VDMC, + CR_VDMC_MACROBLOCK_NUMBER, + CR_VDMC_MACROBLOCK_X_OFFSET); + state->fw_state.pipe_state[pipe].be_mb.y = + REGIO_READ_FIELD(firmware_state.pipestate[pipe].last_be_mb_xy, + MSVDX_VDMC, + CR_VDMC_MACROBLOCK_NUMBER, + CR_VDMC_MACROBLOCK_Y_OFFSET); + } + } + + return 0; +} + +static int vdeckm_prepare_batch(struct vdeckm_context *core_ctx, + const struct hwctrl_batch_msgdata *batch_msgdata, + unsigned char **msg) +{ + unsigned char vdec_flags = 0; + unsigned short flags = 0; + unsigned char *pmsg = kzalloc(FW_DEVA_DECODE_SIZE, GFP_KERNEL); + struct vidio_ddbufinfo *pbatch_msg_bufinfo = batch_msgdata->batchmsg_bufinfo; + + if (!pmsg) + return IMG_ERROR_MALLOC_FAILED; + + if (batch_msgdata->size_delimited_mode) + vdec_flags |= FW_VDEC_NAL_SIZE_DELIM; + + flags |= FW_DEVA_RENDER_HOST_INT; + + /* + * Message type and stream ID + */ + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_GENMSG_MSG_TYPE, FW_DEVA_PARSE, unsigned char*); + + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_CTRL_ALLOC_ADDR, + (unsigned int)pbatch_msg_bufinfo->dev_virt, unsigned char*); + + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_BUFFER_SIZE, + batch_msgdata->ctrl_alloc_bytes / sizeof(unsigned int), unsigned char*); + + /* + * Operating mode and decode flags + */ + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_OPERATING_MODE, batch_msgdata->operating_mode, + unsigned char*); + + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_FLAGS, flags, unsigned char*); + + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_VDEC_FLAGS, vdec_flags, unsigned char*); + + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_GENC_ID, batch_msgdata->genc_id, unsigned char*); + + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_MB_LOAD, batch_msgdata->mb_load, unsigned char*); + + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_STREAMID, + GET_STREAM_ID(batch_msgdata->transaction_id), unsigned char*); + + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_EXT_STATE_BUFFER, + (unsigned int)batch_msgdata->pvdec_fwctx->dev_virt, unsigned char*); + + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_MSG_ID, ++core_ctx->current_msgid, + unsigned char*); + + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_TRANS_ID, batch_msgdata->transaction_id, + unsigned char*); + + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_TILE_CFG, batch_msgdata->tile_cfg, unsigned char*); + + /* + * size of message + */ + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_GENMSG_MSG_SIZE, + FW_DEVA_DECODE_SIZE / sizeof(unsigned int), unsigned char*); + + *msg = pmsg; + + return 0; +} + +static int vdeckm_prepare_fragment(struct vdeckm_context *core_ctx, + const struct hwctrl_fragment_msgdata + *fragment_msgdata, + unsigned char **msg) +{ + struct vidio_ddbufinfo *pbatch_msg_bufinfo = NULL; + unsigned char *pmsg = NULL; + + pbatch_msg_bufinfo = fragment_msgdata->batchmsg_bufinfo; + + if (!(fragment_msgdata->batchmsg_bufinfo)) { + pr_err("Batch message info missing!\n"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + pmsg = kzalloc(FW_DEVA_DECODE_FRAGMENT_SIZE, GFP_KERNEL); + if (!pmsg) + return IMG_ERROR_MALLOC_FAILED; + /* + * message type and stream id + */ + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_GENMSG_MSG_TYPE, + FW_DEVA_PARSE_FRAGMENT, unsigned char*); + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_MSG_ID, ++core_ctx->current_msgid, unsigned char*); + + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_FRAGMENT_CTRL_ALLOC_ADDR, + (unsigned int)pbatch_msg_bufinfo->dev_virt + + fragment_msgdata->ctrl_alloc_offset, unsigned char*); + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_DECODE_FRAGMENT_BUFFER_SIZE, + fragment_msgdata->ctrl_alloc_bytes / sizeof(unsigned int), + unsigned char*); + + /* + * size of message + */ + MEMIO_WRITE_FIELD(pmsg, FW_DEVA_GENMSG_MSG_SIZE, + FW_DEVA_DECODE_FRAGMENT_SIZE / sizeof(unsigned int), unsigned char*); + + *msg = pmsg; + + return 0; +} + +static int vdeckm_get_message(const void *hndl_vxd, const enum hwctrl_msgid msgid, + const struct hwctrl_msgdata *msgdata, + struct hwctrl_to_kernel_msg *to_kernelmsg) +{ + unsigned int result = 0; + struct vdeckm_context *core_ctx = (struct vdeckm_context *)hndl_vxd; + + if (!core_ctx || !to_kernelmsg || !msgdata) + return IMG_ERROR_INVALID_PARAMETERS; + + switch (msgid) { + case HWCTRL_MSGID_BATCH: + result = vdeckm_prepare_batch(core_ctx, &msgdata->batch_msgdata, + &to_kernelmsg->msg_hdr); + break; + + case HWCTRL_MSGID_FRAGMENT: + result = vdeckm_prepare_fragment(core_ctx, &msgdata->fragment_msgdata, + &to_kernelmsg->msg_hdr); + vxd_set_msgflag(VXD_MSG_FLAG_DROP, &to_kernelmsg->flags); + break; + + default: + result = IMG_ERROR_GENERIC_FAILURE; + pr_err("got a message that is not supported by PVDEC"); + break; + } + + if (result == 0) { + /* Set the stream ID for the next message to be sent. */ + to_kernelmsg->km_str_id = msgdata->km_str_id; + to_kernelmsg->msg_size = MEMIO_READ_FIELD(to_kernelmsg->msg_hdr, + FW_DEVA_GENMSG_MSG_SIZE) * + sizeof(unsigned int); + } + + return result; +} + +#ifdef DEBUG_DECODER_DRIVER +static void hwctrl_dump_state(struct vxd_states *prev_state, + struct vxd_states *cur_state, + unsigned char pipe_minus1) +{ + pr_info("Back-End MbX [% 10d]", + prev_state->fw_state.pipe_state[pipe_minus1].be_mb.x); + pr_info("Back-End MbY [% 10d]", + prev_state->fw_state.pipe_state[pipe_minus1].be_mb.y); + pr_info("Front-End MbX [% 10d]", + prev_state->fw_state.pipe_state[pipe_minus1].fe_mb.x); + pr_info("Front-End MbY [% 10d]", + prev_state->fw_state.pipe_state[pipe_minus1].fe_mb.y); + pr_info("VDECFW_CHECKPOINT_BE_PICTURE_COMPLETE [0x%08X]", + cur_state->fw_state.pipe_state[pipe_minus1].acheck_point + [VDECFW_CHECKPOINT_BE_PICTURE_COMPLETE]); + pr_info("VDECFW_CHECKPOINT_BE_1SLICE_DONE [0x%08X]", + cur_state->fw_state.pipe_state[pipe_minus1].acheck_point + [VDECFW_CHECKPOINT_BE_1SLICE_DONE]); + pr_info("VDECFW_CHECKPOINT_BE_PICTURE_STARTED [0x%08X]", + cur_state->fw_state.pipe_state[pipe_minus1].acheck_point + [VDECFW_CHECKPOINT_BE_PICTURE_STARTED]); + pr_info("VDECFW_CHECKPOINT_FE_PICTURE_COMPLETE [0x%08X]", + cur_state->fw_state.pipe_state[pipe_minus1].acheck_point + [VDECFW_CHECKPOINT_FE_PICTURE_COMPLETE]); + pr_info("VDECFW_CHECKPOINT_FE_PARSE_DONE [0x%08X]", + cur_state->fw_state.pipe_state[pipe_minus1].acheck_point + [VDECFW_CHECKPOINT_FE_PARSE_DONE]); + pr_info("VDECFW_CHECKPOINT_FE_1SLICE_DONE [0x%08X]", + cur_state->fw_state.pipe_state[pipe_minus1].acheck_point + [VDECFW_CHECKPOINT_FE_1SLICE_DONE]); + pr_info("VDECFW_CHECKPOINT_ENTDEC_STARTED [0x%08X]", + cur_state->fw_state.pipe_state[pipe_minus1].acheck_point + [VDECFW_CHECKPOINT_ENTDEC_STARTED]); + pr_info("VDECFW_CHECKPOINT_FIRMWARE_SAVED [0x%08X]", + cur_state->fw_state.pipe_state[pipe_minus1].acheck_point + [VDECFW_CHECKPOINT_FIRMWARE_SAVED]); + pr_info("VDECFW_CHECKPOINT_PICMAN_COMPLETE [0x%08X]", + cur_state->fw_state.pipe_state[pipe_minus1].acheck_point + [VDECFW_CHECKPOINT_PICMAN_COMPLETE]); + pr_info("VDECFW_CHECKPOINT_FIRMWARE_READY [0x%08X]", + cur_state->fw_state.pipe_state[pipe_minus1].acheck_point + [VDECFW_CHECKPOINT_FIRMWARE_READY]); + pr_info("VDECFW_CHECKPOINT_PICTURE_STARTED [0x%08X]", + cur_state->fw_state.pipe_state[pipe_minus1].acheck_point + [VDECFW_CHECKPOINT_PICTURE_STARTED]); +} +#endif + +static unsigned int hwctrl_calculate_load(struct bspp_pict_hdr_info *pict_hdr_info) +{ + return (((pict_hdr_info->coded_frame_size.width + 15) / 16) + * ((pict_hdr_info->coded_frame_size.height + 15) / 16)); +} + +static int hwctrl_send_batch_message(struct hwctrl_ctx *hwctx, + struct dec_decpict *decpict, + void *vxd_dec_ctx) +{ + int result; + struct hwctrl_to_kernel_msg to_kernelmsg = {0}; + struct vidio_ddbufinfo *batchmsg_bufinfo = + decpict->batch_msginfo->ddbuf_info; + struct hwctrl_msgdata msg_data; + struct hwctrl_batch_msgdata *batch_msgdata = &msg_data.batch_msgdata; + + memset(&msg_data, 0, sizeof(msg_data)); + + msg_data.km_str_id = GET_STREAM_ID(decpict->transaction_id); + + batch_msgdata->batchmsg_bufinfo = batchmsg_bufinfo; + + batch_msgdata->transaction_id = decpict->transaction_id; + batch_msgdata->pvdec_fwctx = decpict->str_pvdec_fw_ctxbuf; + batch_msgdata->ctrl_alloc_bytes = decpict->ctrl_alloc_bytes; + batch_msgdata->operating_mode = decpict->operating_op; + batch_msgdata->genc_id = decpict->genc_id; + batch_msgdata->mb_load = hwctrl_calculate_load(decpict->pict_hdr_info); + batch_msgdata->size_delimited_mode = + (decpict->pict_hdr_info->parser_mode != VDECFW_SCP_ONLY) ? + (1) : (0); + + result = vdeckm_get_message(hwctx->hndl_vxd, HWCTRL_MSGID_BATCH, + &msg_data, &to_kernelmsg); + if (result != 0) { + pr_err("failed to get decode message\n"); + return result; + } + + pr_debug("[HWCTRL] send batch message\n"); + result = vdeckm_send_message(hwctx->hndl_vxd, &to_kernelmsg, + vxd_dec_ctx); + if (result != 0) + return result; + + vdeckm_return_msg(hwctx->hndl_vxd, &to_kernelmsg); + + return 0; +} + +int hwctrl_process_msg(void *hndl_hwctx, unsigned int msg_flags, unsigned int *msg, + struct dec_decpict **decpict) +{ + int result; + struct hwctrl_ctx *hwctx; + enum vxd_msg_attr msg_attr = VXD_MSG_ATTR_NONE; + struct dec_decpict *pdecpict = NULL; + unsigned int val_first = 0; + unsigned int val_sec = 0; + + if (!hndl_hwctx || !msg || !decpict) { + VDEC_ASSERT(0); + return IMG_ERROR_INVALID_PARAMETERS; + } + + hwctx = (struct hwctrl_ctx *)hndl_hwctx; + + *decpict = NULL; + + pr_debug("[HWCTRL] : process message\n"); + result = vdeckm_process_msg(hwctx->hndl_vxd, msg, &hwctx->pend_pict_list, msg_flags, + &msg_attr, &pdecpict); + if (result != IMG_SUCCESS) + return result; + + /* validate pointers before using them */ + if (!pdecpict || !pdecpict->first_fld_fwmsg || !pdecpict->second_fld_fwmsg) { + VDEC_ASSERT(0); + return -EIO; + } + + val_first = pdecpict->first_fld_fwmsg->pict_attrs.pict_attrs.deverror; + val_sec = pdecpict->second_fld_fwmsg->pict_attrs.pict_attrs.deverror; + + if (val_first || val_sec) + pr_err("device signaled critical error!!!\n"); + + if (msg_attr == VXD_MSG_ATTR_DECODED) { + pdecpict->state = DECODER_PICTURE_STATE_DECODED; + /* + * We have successfully decoded a picture as normally or + * after the replay. + * Mark HW is in good state. + */ + hwctx->is_fatal_state = 0; + } else if (msg_attr == VXD_MSG_ATTR_FATAL) { + struct hwctrl_state state; + unsigned char pipe_minus1 = 0; + + memset(&state, 0, sizeof(state)); + + result = hwctrl_get_core_status(hwctx, &state); + if (result == 0) { + hwctx->is_prev_hw_state_set = 1; + memcpy(&hwctx->prev_state, &state, sizeof(struct hwctrl_state)); + + for (pipe_minus1 = 0; pipe_minus1 < hwctx->num_pipes; + pipe_minus1++) { +#ifdef DEBUG_DECODER_DRIVER + hwctrl_dump_state(&state.core_state, &state.core_state, + pipe_minus1); +#endif + } + } + pdecpict->state = DECODER_PICTURE_STATE_TO_DISCARD; + } + *decpict = pdecpict; + + return 0; +} + +int hwctrl_getcore_cached_status(void *hndl_hwctx, struct hwctrl_state *state) +{ + struct hwctrl_ctx *hwctx = (struct hwctrl_ctx *)hndl_hwctx; + + if (hwctx->is_prev_hw_state_set) + memcpy(state, &hwctx->prev_state, sizeof(struct hwctrl_state)); + else + return IMG_ERROR_UNEXPECTED_STATE; + + return 0; +} + +int hwctrl_get_core_status(void *hndl_hwctx, struct hwctrl_state *state) +{ + struct hwctrl_ctx *hwctx = (struct hwctrl_ctx *)hndl_hwctx; + unsigned int result = IMG_ERROR_GENERIC_FAILURE; + + if (!hwctx->is_fatal_state && state) { + struct vxd_states *pcorestate = NULL; + + pcorestate = &state->core_state; + + memset(pcorestate, 0, sizeof(*(pcorestate))); + + result = vdeckm_get_core_state(hwctx->hndl_vxd, pcorestate); + } + + return result; +} + +int hwctrl_is_on_seq_replay(void *hndl_hwctx) +{ + struct hwctrl_ctx *hwctx = (struct hwctrl_ctx *)hndl_hwctx; + + return hwctx->is_on_seq_replay; +} + +int hwctrl_picture_submitbatch(void *hndl_hwctx, struct dec_decpict *decpict, void *vxd_dec_ctx) +{ + struct hwctrl_ctx *hwctx = (struct hwctrl_ctx *)hndl_hwctx; + + if (hwctx->is_initialised) { + lst_add(&hwctx->pend_pict_list, decpict); + if (!hwctx->is_on_seq_replay) + return hwctrl_send_batch_message(hwctx, decpict, vxd_dec_ctx); + } + + return 0; +} + +int hwctrl_getpicpend_pictlist(void *hndl_hwctx, unsigned int transaction_id, + struct dec_decpict **decpict) +{ + struct hwctrl_ctx *hwctx = (struct hwctrl_ctx *)hndl_hwctx; + struct dec_decpict *dec_pic; + + dec_pic = lst_first(&hwctx->pend_pict_list); + while (dec_pic) { + if (dec_pic->transaction_id == transaction_id) { + *decpict = dec_pic; + break; + } + dec_pic = lst_next(dec_pic); + } + + if (!dec_pic) + return IMG_ERROR_INVALID_ID; + + return 0; +} + +int hwctrl_peekheadpiclist(void *hndl_hwctx, struct dec_decpict **decpict) +{ + struct hwctrl_ctx *hwctx = (struct hwctrl_ctx *)hndl_hwctx; + + if (hwctx) + *decpict = lst_first(&hwctx->pend_pict_list); + + if (*decpict) + return 0; + + return IMG_ERROR_GENERIC_FAILURE; +} + +int hwctrl_getdecodedpicture(void *hndl_hwctx, struct dec_decpict **decpict) +{ + struct hwctrl_ctx *hwctx = (struct hwctrl_ctx *)hndl_hwctx; + + if (hwctx) { + struct dec_decpict *cur_decpict; + /* + * Ensure that this picture is in the list. + */ + cur_decpict = lst_first(&hwctx->pend_pict_list); + while (cur_decpict) { + if (cur_decpict->state == DECODER_PICTURE_STATE_DECODED) { + *decpict = cur_decpict; + return 0; + } + + cur_decpict = lst_next(cur_decpict); + } + } + + return IMG_ERROR_VALUE_OUT_OF_RANGE; +} + +void hwctrl_removefrom_piclist(void *hndl_hwctx, struct dec_decpict *decpict) +{ + struct hwctrl_ctx *hwctx = (struct hwctrl_ctx *)hndl_hwctx; + + if (hwctx) { + struct dec_decpict *cur_decpict; + /* + * Ensure that this picture is in the list. + */ + cur_decpict = lst_first(&hwctx->pend_pict_list); + while (cur_decpict) { + if (cur_decpict == decpict) { + lst_remove(&hwctx->pend_pict_list, decpict); + break; + } + + cur_decpict = lst_next(cur_decpict); + } + } +} + +int hwctrl_getregsoffset(void *hndl_hwctx, struct decoder_regsoffsets *regs_offsets) +{ + struct hwctrl_ctx *hwctx = (struct hwctrl_ctx *)hndl_hwctx; + + return vdeckm_getregsoffsets(hwctx->hndl_vxd, regs_offsets); +} + +static int pvdec_create(struct vxd_dev *vxd, struct vxd_coreprops *core_props, + void **hndl_vdeckm_context) +{ + struct vdeckm_context *corectx; + struct vxd_core_props hndl_core_props; + int result; + int iMapSize, pageSize; + void *phy_addr; + + if (!hndl_vdeckm_context || !core_props) + return IMG_ERROR_INVALID_PARAMETERS; + + /* + * Obtain core context. + */ + corectx = &acore_ctx[0]; + + memset(corectx, 0, sizeof(*corectx)); + + corectx->core_num = 0; + + result = vxd_pvdec_get_props(vxd->dev, vxd->reg_base, &hndl_core_props); + if (result != 0) + return result; + + vxd_get_coreproperties(&hndl_core_props, &corectx->props); + + memcpy(core_props, &corectx->props, sizeof(*core_props)); + + pageSize = PAGE_SIZE; + /* end aligned to page (ceiling), in pages */ + iMapSize = (PVDEC_COMMS_RAM_OFFSET + PVDEC_COMMS_RAM_SIZE + pageSize - 1) / pageSize; + /* subtract start aligned to page (floor), in pages */ + iMapSize -= PVDEC_COMMS_RAM_OFFSET / pageSize; + /* convert to bytes */ + iMapSize *= pageSize; + phy_addr = (void *)(0x4300000); + phy_addr += (PVDEC_COMMS_RAM_OFFSET); + corectx->comms_ram_addr = ioremap((phys_addr_t)phy_addr, iMapSize); + *hndl_vdeckm_context = corectx; + + return 0; +} + +int hwctrl_deinitialise(void *hndl_hwctx) +{ + struct hwctrl_ctx *hwctx = (struct hwctrl_ctx *)hndl_hwctx; + + if (hwctx->is_initialised) { + kfree(hwctx); + hwctx = NULL; + } + + return 0; +} + +int hwctrl_initialise(void *dec_core, void *comp_int_userdata, + const struct vdecdd_dd_devconfig *dd_devconfig, + struct vxd_coreprops *core_props, void **hndl_hwctx) +{ + struct hwctrl_ctx *hwctx = (struct hwctrl_ctx *)*hndl_hwctx; + int result; + + if (!hwctx) { + hwctx = kzalloc(sizeof(*(hwctx)), GFP_KERNEL); + if (!hwctx) + return IMG_ERROR_OUT_OF_MEMORY; + + *hndl_hwctx = hwctx; + } + + if (!hwctx->is_initialised) { + hwctx->hndl_vxd = ((struct dec_core_ctx *)dec_core)->dec_ctx->dev_handle; + result = pvdec_create(hwctx->hndl_vxd, core_props, &hwctx->hndl_vxd); + if (result != 0) + goto error; + + lst_init(&hwctx->pend_pict_list); + + hwctx->devconfig = *dd_devconfig; + hwctx->num_pipes = core_props->num_pixel_pipes; + hwctx->comp_init_userdata = comp_int_userdata; + hwctx->dec_core = dec_core; + hwctx->is_initialised = 1; + hwctx->is_on_seq_replay = 0; + hwctx->is_fatal_state = 0; + } + + return 0; +error: + hwctrl_deinitialise(*hndl_hwctx); + + return result; +} + +static int hwctrl_send_fragment_message(struct hwctrl_ctx *hwctx, + struct dec_pict_fragment *pict_fragment, + struct dec_decpict *decpict, + void *vxd_dec_ctx) +{ + int result; + struct hwctrl_to_kernel_msg to_kernelmsg = {0}; + struct hwctrl_msgdata msg_data; + struct hwctrl_fragment_msgdata *pfragment_msgdata = + &msg_data.fragment_msgdata; + + msg_data.km_str_id = GET_STREAM_ID(decpict->transaction_id); + + pfragment_msgdata->ctrl_alloc_bytes = pict_fragment->ctrl_alloc_bytes; + + pfragment_msgdata->ctrl_alloc_offset = pict_fragment->ctrl_alloc_offset; + + pfragment_msgdata->batchmsg_bufinfo = decpict->batch_msginfo->ddbuf_info; + + result = vdeckm_get_message(hwctx->hndl_vxd, HWCTRL_MSGID_FRAGMENT, &msg_data, + &to_kernelmsg); + if (result != 0) { + pr_err("Failed to get decode message\n"); + return result; + } + + result = vdeckm_send_message(hwctx->hndl_vxd, &to_kernelmsg, vxd_dec_ctx); + if (result != 0) + return result; + + vdeckm_return_msg(hwctx->hndl_vxd, &to_kernelmsg); + + return 0; +} + +int hwctrl_picture_submit_fragment(void *hndl_hwctx, + struct dec_pict_fragment *pict_fragment, + struct dec_decpict *decpict, + void *vxd_dec_ctx) +{ + struct hwctrl_ctx *hwctx = (struct hwctrl_ctx *)hndl_hwctx; + unsigned int result = 0; + + if (hwctx->is_initialised) { + result = hwctrl_send_fragment_message(hwctx, pict_fragment, + decpict, vxd_dec_ctx); + if (result != 0) + pr_err("Failed to send fragment message to firmware !"); + } + + return result; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/hw_control.h b/drivers/media/platform/imagination/vxe-vxd/decoder/hw_control.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/hw_control.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/hw_control.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD DEC Hardware control implementation + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#ifndef _HW_CONTROL_H +#define _HW_CONTROL_H + +#include "bspp.h" +#include "decoder.h" +#include "fw_interface.h" +#include "img_dec_common.h" +#include "img_errors.h" +#include "lst.h" +#include "mem_io.h" +#include "vdecdd_defs.h" +#include "vdecfw_shared.h" +#include "vid_buf.h" +#include "vxd_ext.h" +#include "vxd_props.h" + +/* Size of additional buffers needed for each HEVC picture */ +#ifdef HAS_HEVC + +/* Empirically defined */ +#define MEM_TO_REG_BUF_SIZE 0x2000 + +/* + * Max. no. of slices found in stream db: approx. 2200, + * set MAX_SLICES to 2368 to get buffer size page aligned + */ +#define MAX_SLICES 2368 +#define SLICE_PARAMS_SIZE 64 +#define SLICE_PARAMS_BUF_SIZE (MAX_SLICES * SLICE_PARAMS_SIZE) + +/* + * Size of buffer for "above params" structure, sufficient for stream of width 8192 + * 192 * (8192/64) == 0x6000, see "above_param_size" in TRM + */ +#define ABOVE_PARAMS_BUF_SIZE 0x6000 +#endif + +enum hwctrl_msgid { + HWCTRL_MSGID_BATCH = 0, + HWCTRL_MSGID_FRAGMENT = 1, + CORE_MSGID_MAX, + CORE_MSGID_FORCE32BITS = 0x7FFFFFFFU +}; + +struct hwctrl_to_kernel_msg { + unsigned int msg_size; + unsigned int km_str_id; + unsigned int flags; + unsigned char *msg_hdr; +}; + +struct hwctrl_batch_msgdata { + struct vidio_ddbufinfo *batchmsg_bufinfo; + struct vidio_ddbufinfo *pvdec_fwctx; + unsigned int ctrl_alloc_bytes; + unsigned int operating_mode; + unsigned int transaction_id; + unsigned int tile_cfg; + unsigned int genc_id; + unsigned int mb_load; + unsigned int size_delimited_mode; +}; + +struct hwctrl_fragment_msgdata { + struct vidio_ddbufinfo *batchmsg_bufinfo; + unsigned int ctrl_alloc_offset; + unsigned int ctrl_alloc_bytes; +}; + +struct hwctrl_msgdata { + unsigned int km_str_id; + struct hwctrl_batch_msgdata batch_msgdata; + struct hwctrl_fragment_msgdata fragment_msgdata; +}; + +/* + * This structure contains MSVDX Message information. + */ +struct hwctrl_msgstatus { + unsigned char control_fence_id[VDECFW_MSGID_CONTROL_TYPES]; + unsigned char decode_fence_id[VDECFW_MSGID_DECODE_TYPES]; + unsigned char completion_fence_id[VDECFW_MSGID_COMPLETION_TYPES]; +}; + +/* + * this structure contains the HWCTRL Core state. + */ +struct hwctrl_state { + struct vxd_states core_state; + struct hwctrl_msgstatus fwmsg_status; + struct hwctrl_msgstatus hostmsg_status; +}; + +int hwctrl_picture_submit_fragment(void *hndl_hwctx, + struct dec_pict_fragment *pict_fragment, + struct dec_decpict *decpict, + void *vxd_dec_ctx); + +int hwctrl_process_msg(void *hndl_hwct, unsigned int msg_flags, unsigned int *msg, + struct dec_decpict **decpict); + +int hwctrl_getcore_cached_status(void *hndl_hwctx, struct hwctrl_state *state); + +int hwctrl_get_core_status(void *hndl_hwctx, struct hwctrl_state *state); + +int hwctrl_is_on_seq_replay(void *hndl_hwctx); + +int hwctrl_picture_submitbatch(void *hndl_hwctx, struct dec_decpict *decpict, + void *vxd_dec_ctx); + +int hwctrl_getpicpend_pictlist(void *hndl_hwctx, unsigned int transaction_id, + struct dec_decpict **decpict); + +int hwctrl_peekheadpiclist(void *hndl_hwctx, struct dec_decpict **decpict); + +int hwctrl_getdecodedpicture(void *hndl_hwctx, struct dec_decpict **decpict); + +void hwctrl_removefrom_piclist(void *hndl_hwctx, struct dec_decpict *decpict); + +int hwctrl_getregsoffset(void *hndl_hwctx, + struct decoder_regsoffsets *regs_offsets); + +int hwctrl_initialise(void *dec_core, void *comp_int_userdata, + const struct vdecdd_dd_devconfig *dd_devconfig, + struct vxd_coreprops *core_props, void **hndl_hwctx); + +int hwctrl_deinitialise(void *hndl_hwctx); + +#endif /* _HW_CONTROL_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/img_dec_common.h b/drivers/media/platform/imagination/vxe-vxd/decoder/img_dec_common.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/img_dec_common.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/img_dec_common.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,278 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG DEC common header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#ifndef _IMG_DEC_COMMON_H +#define _IMG_DEC_COMMON_H + +#include + +#define VXD_MAX_PIPES 2 +#define MAX_DST_BUFFERS 32 + +/* Helpers for parsing core properties. Based on HW registers layout. */ +#define VXD_GET_BITS(v, lb, rb, type) \ + ({ \ + type __rb = (rb); \ + (((v) >> (__rb)) & ((1 << ((lb) - __rb + 1)) - 1)); }) +#define VXD_GET_BIT(v, b) (((v) >> (b)) & 1) + +/* Get major core revision. */ +#define VXD_MAJ_REV(props) (VXD_GET_BITS((props).core_rev, 23, 16, unsigned int)) +/* Get minor core revision. */ +#define VXD_MIN_REV(props) (VXD_GET_BITS((props).core_rev, 15, 8, unsigned int)) +/* Get maint core revision. */ +#define VXD_MAINT_REV(props) (VXD_GET_BITS((props).core_rev, 7, 0, unsigned int)) +/* Get number of entropy pipes available (HEVC). */ +#define VXD_NUM_ENT_PIPES(props) ((props).pvdec_core_id & 0xF) +/* Get number of pixel pipes available (other standards). */ +#define VXD_NUM_PIX_PIPES(props) (((props).pvdec_core_id & 0xF0) >> 4) +/* Get number of bits used by external memory interface. */ +#define VXD_EXTRN_ADDR_WIDTH(props) ((((props).mmu_config0 & 0xF0) >> 4) + 32) + +/* Check whether specific standard is supported by the pixel pipe. */ +#define VXD_HAS_MPEG2(props, pipe) VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 0) +#define VXD_HAS_MPEG4(props, pipe) VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 1) +#define VXD_HAS_H264(props, pipe) VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 2) +#define VXD_HAS_VC1(props, pipe) VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 3) +#define VXD_HAS_WMV9(props, pipe) VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 4) +#define VXD_HAS_JPEG(props, pipe) VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 5) +#define VXD_HAS_MPEG4_DATA_PART(props, pipe) \ + VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 6) +#define VXD_HAS_AVS(props, pipe) VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 7) +#define VXD_HAS_REAL(props, pipe) VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 8) +#define VXD_HAS_VP6(props, pipe) VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 9) +#define VXD_HAS_VP8(props, pipe) VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 10) +#define VXD_HAS_SORENSON(props, pipe) \ + VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 11) +#define VXD_HAS_HEVC(props, pipe) VXD_GET_BIT(props.pixel_pipe_cfg[pipe], 22) + +/* Check whether specific feature is supported by the pixel pipe */ + +/* + * Max picture size for HEVC still picture profile is 64k wide and/or 64k + * high. + */ +#define VXD_HAS_HEVC_64K_STILL(props, pipe) \ + (VXD_GET_BIT((props).pixel_misc_cfg[pipe], 24)) + +/* Pixel processing pipe index. */ +#define VXD_PIX_PIPE_ID(props, pipe) \ + (VXD_GET_BITS((props).pixel_misc_cfg[pipe], 18, 16, unsigned int)) + +/* Number of stream supported by the pixel pipe DMAC and shift register. */ +#define VXD_PIX_NUM_STRS(props, pipe) \ + (VXD_GET_BITS((props).pixel_misc_cfg[pipe], 13, 12, unsigned int) + 1) + +/* Is scaling supported. */ +#define VXD_HAS_SCALING(props, pipe) \ + (VXD_GET_BIT((props).pixel_misc_cfg[pipe], 9)) + +/* Is rotation supported. */ +#define VXD_HAS_ROTATION(props, pipe) \ + (VXD_GET_BIT((props).pixel_misc_cfg[pipe], 8)) + +/* Are HEVC range extensions supported. */ +#define VXD_HAS_HEVC_REXT(props, pipe) \ + (VXD_GET_BIT((props).pixel_misc_cfg[pipe], 7)) + +/* Maximum bit depth supported by the pipe. */ +#define VXD_MAX_BIT_DEPTH(props, pipe) \ + (VXD_GET_BITS((props).pixel_misc_cfg[pipe], 6, 4, unsigned int) + 8) + +/* + * Maximum chroma fomar supported by the pipe in HEVC mode. + * 0x1 - 4:2:0 + * 0x2 - 4:2:2 + * 0x3 - 4:4:4 + */ +#define VXD_MAX_HEVC_CHROMA_FMT(props, pipe) \ + (VXD_GET_BITS((props).pixel_misc_cfg[pipe], 3, 2, unsigned int)) + +/* + * Maximum chroma format supported by the pipe in H264 mode. + * 0x1 - 4:2:0 + * 0x2 - 4:2:2 + * 0x3 - 4:4:4 + */ +#define VXD_MAX_H264_CHROMA_FMT(props, pipe) \ + (VXD_GET_BITS((props).pixel_misc_cfg[pipe], 1, 0, unsigned int)) + +/* + * Maximum frame width and height supported in MSVDX pipeline. + */ +#define VXD_MAX_WIDTH_MSVDX(props) \ + (2 << (VXD_GET_BITS((props).pixel_max_frame_cfg, 4, 0, unsigned int))) +#define VXD_MAX_HEIGHT_MSVDX(props) \ + (2 << (VXD_GET_BITS((props).pixel_max_frame_cfg, 12, 8, unsigned int))) + +/* + * Maximum frame width and height supported in PVDEC pipeline. + */ +#define VXD_MAX_WIDTH_PVDEC(props) \ + (2 << (VXD_GET_BITS((props).pixel_max_frame_cfg, 20, 16, unsigned int))) +#define VXD_MAX_HEIGHT_PVDEC(props) \ + (2 << (VXD_GET_BITS((props).pixel_max_frame_cfg, 28, 24, unsigned int))) + +#define PVDEC_COMMS_RAM_OFFSET 0x00002000 +#define PVDEC_COMMS_RAM_SIZE 0x00001000 +#define PVDEC_ENTROPY_OFFSET 0x00003000 +#define PVDEC_ENTROPY_SIZE 0x1FF +#define PVDEC_VEC_BE_OFFSET 0x00005000 +#define PVDEC_VEC_BE_SIZE 0x3FF +#define PVDEC_VEC_BE_CODEC_OFFSET 0x00005400 +#define MSVDX_VEC_OFFSET 0x00006000 +#define MSVDX_VEC_SIZE 0x7FF +#define MSVDX_CMD_OFFSET 0x00007000 + +/* + * Virtual memory heap address ranges for tiled + * and non-tiled buffers. Addresses within each + * range should be assigned to the appropriate + * buffers by the UM driver and mapped into the + * device using the corresponding KM driver ioctl. + */ +#define PVDEC_HEAP_UNTILED_START 0x00400000ul +#define PVDEC_HEAP_UNTILED_SIZE 0x3FC00000ul +#define PVDEC_HEAP_TILE512_START 0x40000000ul +#define PVDEC_HEAP_TILE512_SIZE 0x10000000ul +#define PVDEC_HEAP_TILE1024_START 0x50000000ul +#define PVDEC_HEAP_TILE1024_SIZE 0x20000000ul +#define PVDEC_HEAP_TILE2048_START 0x70000000ul +#define PVDEC_HEAP_TILE2048_SIZE 0x30000000ul +#define PVDEC_HEAP_TILE4096_START 0xA0000000ul +#define PVDEC_HEAP_TILE4096_SIZE 0x30000000ul +#define PVDEC_HEAP_BITSTREAM_START 0xD2000000ul +#define PVDEC_HEAP_BITSTREAM_SIZE 0x0A000000ul +#define PVDEC_HEAP_STREAM_START 0xE4000000ul +#define PVDEC_HEAP_STREAM_SIZE 0x1C000000ul + +/* + * Max size of the message payload, in bytes. There are 7 bits used to encode + * the message size in the firmware interface. + */ +#define VXD_MAX_PAYLOAD_SIZE (127 * sizeof(unsigned int)) +/* Max size of the input message in bytes. */ +#define VXD_MAX_INPUT_SIZE (VXD_MAX_PAYLOAD_SIZE + sizeof(struct vxd_fw_msg)) +/* + * Min size of the input message. Two words needed for message header and + * stream PTD + */ +#define VXD_MIN_INPUT_SIZE 2 +/* + * Offset of the stream PTD within message. This word has to be left null in + * submitted message, driver will fill it in with an appropriate value. + */ +#define VXD_PTD_MSG_OFFSET 1 + +/* Read flags */ +#define VXD_FW_MSG_RD_FLAGS_MASK 0xffff +/* Driver watchdog interrupted processing of the message. */ +#define VXD_FW_MSG_FLAG_DWR 0x1 +/* VXD MMU fault occurred when the message was processed. */ +#define VXD_FW_MSG_FLAG_MMU_FAULT 0x2 +/* Invalid input message, e.g. the message was too large. */ +#define VXD_FW_MSG_FLAG_INV 0x4 +/* I/O error occurred when the message was processed. */ +#define VXD_FW_MSG_FLAG_DEV_ERR 0x8 +/* + * Driver error occurred when the message was processed, e.g. failed to + * allocate memory. + */ +#define VXD_FW_MSG_FLAG_DRV_ERR 0x10 +/* + * Item was canceled, without being fully processed + * i.e. corresponding stream was destroyed. + */ +#define VXD_FW_MSG_FLAG_CANCELED 0x20 +/* Firmware internal error occurred when the message was processed */ +#define VXD_FW_MSG_FLAG_FATAL 0x40 + +/* Write flags */ +#define VXD_FW_MSG_WR_FLAGS_MASK 0xffff0000 +/* Indicates that message shall be dropped after sending it to the firmware. */ +#define VXD_FW_MSG_FLAG_DROP 0x10000 +/* + * Indicates that message shall be exclusively handled by + * the firmware/hardware. Any other pending messages are + * blocked until such message is handled. + */ +#define VXD_FW_MSG_FLAG_EXCL 0x20000 + +#define VXD_MSG_SIZE(msg) (sizeof(struct vxd_fw_msg) + ((msg).payload_size)) + +/* Header included at the beginning of firmware binary */ +struct vxd_fw_hdr { + unsigned int core_size; + unsigned int blob_size; + unsigned int firmware_id; + unsigned int timestamp; +}; + +/* + * struct vxd_dev_fw - Core component will allocate a buffer for firmware. + * This structure holds the information about the firmware + * binary. + * @buf_id: The buffer id allocation + * @hdr: firmware header information + * @fw_size: The size of the fw. Set after successful firmware request. + */ +struct vxd_dev_fw { + int buf_id; + struct vxd_fw_hdr *hdr; + unsigned int fw_size; + unsigned char ready; +}; + +/* + * struct vxd_core_props - contains HW core properties + * @core_rev: Core revision based on register CR_PVDEC_CORE_REV + * @pvdec_core_id: PVDEC Core id based on register CR_PVDEC_CORE_ID + * @mmu_config0: MMU configuration 0 based on register MMU_CONFIG0 + * @mmu_config1: MMU configuration 1 based on register MMU_CONFIG1 + * @mtx_ram_size: size of the MTX RAM based on register CR_PROC_DEBUG + * @pixel_max_frame_cfg: indicates the max frame height and width for + * PVDEC pipeline and MSVDX pipeline based on register + * MAX_FRAME_CONFIG + * @pixel_pipe_cfg: pipe configuration which codecs are supported in a + * Pixel Processing Pipe, based on register + * PIXEL_PIPE_CONFIG + * @pixel_misc_cfg: Additional pipe configuration eg. supported scaling + * or rotation, based on register PIXEL_MISC_CONFIG + * @dbg_fifo_size: contains the depth of the Debug FIFO, based on + * register CR_PROC_DEBUG_FIFO_SIZE + */ +struct vxd_core_props { + unsigned int core_rev; + unsigned int pvdec_core_id; + unsigned int mmu_config0; + unsigned int mmu_config1; + unsigned int mtx_ram_size; + unsigned int pixel_max_frame_cfg; + unsigned int pixel_pipe_cfg[VXD_MAX_PIPES]; + unsigned int pixel_misc_cfg[VXD_MAX_PIPES]; + unsigned int dbg_fifo_size; +}; + +struct vxd_alloc_data { + unsigned int heap_id; /* [IN] Heap ID of allocator */ + unsigned int size; /* [IN] Size of device memory (in bytes) */ + unsigned int attributes; /* [IN] Attributes of buffer */ + unsigned int buf_id; /* [OUT] Generated buffer ID */ +}; + +struct vxd_free_data { + unsigned int buf_id; /* [IN] ID of device buffer to free */ +}; +#endif /* _IMG_DEC_COMMON_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_cmds.h b/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_cmds.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_cmds.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_cmds.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG MSVDX core Registers + * This file contains the MSVDX_CORE_REGS_H Definitions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef _IMG_MSVDX_CMDS_H +#define _IMG_MSVDX_CMDS_H + +#define MSVDX_CMDS_HORIZONTAL_LUMA_COEFFICIENTS_OFFSET (0x0060) +#define MSVDX_CMDS_VERTICAL_LUMA_COEFFICIENTS_OFFSET (0x0070) +/** + * MSVDX_CMDS_HORIZONTAL_CHROMA_COEFFICIENTS_OFFSET - + * MSVDX_CMDS, VERTICAL_LUMA_COEFFICIENTS, VER_LUMA_COEFF_0 + */ +#define MSVDX_CMDS_HORIZONTAL_CHROMA_COEFFICIENTS_OFFSET (0x0080) +/* MSVDX_CMDS, HORIZONTAL_CHROMA_COEFFICIENTS, HOR_CHROMA_COEFF_0 */ +#define MSVDX_CMDS_VERTICAL_CHROMA_COEFFICIENTS_OFFSET (0x0090) +/* MSVDX_CMDS, DISPLAY_PICTURE_SIZE, DISPLAY_PICTURE_HEIGHT */ +#define MSVDX_CMDS_DISPLAY_PICTURE_SIZE_DISPLAY_PICTURE_HEIGHT_LSBMASK (0x00000FFF) +#define MSVDX_CMDS_DISPLAY_PICTURE_SIZE_DISPLAY_PICTURE_HEIGHT_SHIFT (12) +/* MSVDX_CMDS, DISPLAY_PICTURE_SIZE, DISPLAY_PICTURE_WIDTH */ +#define MSVDX_CMDS_DISPLAY_PICTURE_SIZE_DISPLAY_PICTURE_WIDTH_LSBMASK (0x00000FFF) +#define MSVDX_CMDS_DISPLAY_PICTURE_SIZE_DISPLAY_PICTURE_WIDTH_SHIFT (0) +#define MSVDX_CMDS_PVDEC_DISPLAY_PICTURE_SIZE_OFFSET (0x00B0) +#define MSVDX_CMDS_PVDEC_DISPLAY_PICTURE_SIZE_PVDEC_DISPLAY_PICTURE_HEIGHT_MIN1_LSBMASK \ + (0x0000FFFF) +#define MSVDX_CMDS_PVDEC_DISPLAY_PICTURE_SIZE_PVDEC_DISPLAY_PICTURE_HEIGHT_MIN1_SHIFT (16) +/* MSVDX_CMDS, PVDEC_DISPLAY_PICTURE_SIZE, PVDEC_DISPLAY_PICTURE_WIDTH_MIN1 */ +#define MSVDX_CMDS_PVDEC_DISPLAY_PICTURE_SIZE_PVDEC_DISPLAY_PICTURE_WIDTH_MIN1_LSBMASK \ + (0x0000FFFF) +#define MSVDX_CMDS_PVDEC_DISPLAY_PICTURE_SIZE_PVDEC_DISPLAY_PICTURE_WIDTH_MIN1_SHIFT (0) +/* MSVDX_CMDS, CODED_PICTURE_SIZE, CODED_PICTURE_HEIGHT */ +#define MSVDX_CMDS_CODED_PICTURE_SIZE_CODED_PICTURE_HEIGHT_LSBMASK (0x00000FFF) +#define MSVDX_CMDS_CODED_PICTURE_SIZE_CODED_PICTURE_HEIGHT_SHIFT (12) +/* MSVDX_CMDS, CODED_PICTURE_SIZE, CODED_PICTURE_WIDTH */ +#define MSVDX_CMDS_CODED_PICTURE_SIZE_CODED_PICTURE_WIDTH_LSBMASK (0x00000FFF) +#define MSVDX_CMDS_CODED_PICTURE_SIZE_CODED_PICTURE_WIDTH_SHIFT (0) +#define MSVDX_CMDS_PVDEC_CODED_PICTURE_SIZE_OFFSET (0x00B4) +/* MSVDX_CMDS, OPERATING_MODE, USE_EXT_ROW_STRIDE */ +#define MSVDX_CMDS_OPERATING_MODE_USE_EXT_ROW_STRIDE_MASK (0x10000000) +#define MSVDX_CMDS_OPERATING_MODE_USE_EXT_ROW_STRIDE_LSBMASK (0x00000001) +#define MSVDX_CMDS_OPERATING_MODE_USE_EXT_ROW_STRIDE_SHIFT (28) +/* MSVDX_CMDS, OPERATING_MODE, CHROMA_INTERLEAVED */ +#define MSVDX_CMDS_OPERATING_MODE_CHROMA_INTERLEAVED_MASK (0x08000000) +#define MSVDX_CMDS_OPERATING_MODE_CHROMA_INTERLEAVED_LSBMASK (0x00000001) +#define MSVDX_CMDS_OPERATING_MODE_CHROMA_INTERLEAVED_SHIFT (27) +/* MSVDX_CMDS, OPERATING_MODE, ROW_STRIDE */ +#define MSVDX_CMDS_OPERATING_MODE_ROW_STRIDE_MASK (0x07000000) +#define MSVDX_CMDS_OPERATING_MODE_ROW_STRIDE_LSBMASK (0x00000007) +#define MSVDX_CMDS_OPERATING_MODE_ROW_STRIDE_SHIFT (24) +/* MSVDX_CMDS, OPERATING_MODE, CODEC_PROFILE */ +#define MSVDX_CMDS_OPERATING_MODE_CODEC_PROFILE_MASK (0x00300000) +#define MSVDX_CMDS_OPERATING_MODE_CODEC_PROFILE_LSBMASK (0x00000003) +#define MSVDX_CMDS_OPERATING_MODE_CODEC_PROFILE_SHIFT (20) +/* MSVDX_CMDS, OPERATING_MODE, CODEC_MODE */ +#define MSVDX_CMDS_OPERATING_MODE_CODEC_MODE_MASK (0x000F0000) +#define MSVDX_CMDS_OPERATING_MODE_CODEC_MODE_LSBMASK (0x0000000F) +#define MSVDX_CMDS_OPERATING_MODE_CODEC_MODE_SHIFT (16) +/* MSVDX_CMDS, OPERATING_MODE, ASYNC_MODE */ +#define MSVDX_CMDS_OPERATING_MODE_ASYNC_MODE_MASK (0x00006000) +#define MSVDX_CMDS_OPERATING_MODE_ASYNC_MODE_LSBMASK (0x00000003) +#define MSVDX_CMDS_OPERATING_MODE_ASYNC_MODE_SHIFT (13) +/* MSVDX_CMDS, OPERATING_MODE, CHROMA_FORMAT */ +#define MSVDX_CMDS_OPERATING_MODE_CHROMA_FORMAT_MASK (0x00001000) +#define MSVDX_CMDS_OPERATING_MODE_CHROMA_FORMAT_LSBMASK (0x00000001) +#define MSVDX_CMDS_OPERATING_MODE_CHROMA_FORMAT_SHIFT (12) +/* MSVDX_CMDS, OPERATING_MODE, PIC_QUANT */ +#define MSVDX_CMDS_PVDEC_OPERATING_MODE_OFFSET (0x00A0) +/* MSVDX_CMDS, EXT_OP_MODE, BIT_DEPTH_CHROMA_MINUS8 */ +#define MSVDX_CMDS_EXT_OP_MODE_BIT_DEPTH_CHROMA_MINUS8_MASK (0x00003000) +#define MSVDX_CMDS_EXT_OP_MODE_BIT_DEPTH_CHROMA_MINUS8_LSBMASK (0x00000003) +#define MSVDX_CMDS_EXT_OP_MODE_BIT_DEPTH_CHROMA_MINUS8_SHIFT (12) +/* MSVDX_CMDS, EXT_OP_MODE, BIT_DEPTH_LUMA_MINUS8 */ +#define MSVDX_CMDS_EXT_OP_MODE_BIT_DEPTH_LUMA_MINUS8_MASK (0x00000300) +#define MSVDX_CMDS_EXT_OP_MODE_BIT_DEPTH_LUMA_MINUS8_LSBMASK (0x00000003) +#define MSVDX_CMDS_EXT_OP_MODE_BIT_DEPTH_LUMA_MINUS8_SHIFT (8) +/* MSVDX_CMDS, EXT_OP_MODE, MEMORY_PACKING */ +#define MSVDX_CMDS_EXT_OP_MODE_MEMORY_PACKING_MASK (0x00000008) +#define MSVDX_CMDS_EXT_OP_MODE_MEMORY_PACKING_LSBMASK (0x00000001) +#define MSVDX_CMDS_EXT_OP_MODE_MEMORY_PACKING_SHIFT (3) +/* MSVDX_CMDS, EXT_OP_MODE, CHROMA_FORMAT_IDC */ +#define MSVDX_CMDS_EXT_OP_MODE_CHROMA_FORMAT_IDC_MASK (0x00000003) +#define MSVDX_CMDS_EXT_OP_MODE_CHROMA_FORMAT_IDC_LSBMASK (0x00000003) +#define MSVDX_CMDS_EXT_OP_MODE_CHROMA_FORMAT_IDC_SHIFT (0) +#define MSVDX_CMDS_LUMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES_OFFSET (0x000C) +/* + * MSVDX_CMDS, LUMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES, + * LUMA_RECON_BASE_ADDR + */ +#define MSVDX_CMDS_CHROMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES_OFFSET (0x0010) +///* MSVDX_CMDS, AUX_MSB_BUFFER_BASE_ADDRESSES, AUX_MSB_BUFFER_BASE_ADDR */ +#define MSVDX_CMDS_INTRA_BUFFER_BASE_ADDRESS_OFFSET (0x0018) +/* MSVDX_CMDS, INTRA_BUFFER_BASE_ADDRESS, INTRA_BASE_ADDR */ + +#define MSVDX_CMDS_MC_CACHE_CONFIGURATION_OFFSET (0x001C) + +/* MSVDX_CMDS, MC_CACHE_CONFIGURATION, CONFIG_REF_CHROMA_ADJUST */ +#define MSVDX_CMDS_MC_CACHE_CONFIGURATION_CONFIG_REF_CHROMA_ADJUST_MASK (0x01000000) +#define MSVDX_CMDS_MC_CACHE_CONFIGURATION_CONFIG_REF_CHROMA_ADJUST_LSBMASK (0x00000001) +#define MSVDX_CMDS_MC_CACHE_CONFIGURATION_CONFIG_REF_CHROMA_ADJUST_SHIFT (24) +/* MSVDX_CMDS, MC_CACHE_CONFIGURATION, CONFIG_REF_OFFSET */ +#define MSVDX_CMDS_MC_CACHE_CONFIGURATION_CONFIG_REF_OFFSET_MASK (0x00FFF000) +#define MSVDX_CMDS_MC_CACHE_CONFIGURATION_CONFIG_REF_OFFSET_LSBMASK (0x00000FFF) +#define MSVDX_CMDS_MC_CACHE_CONFIGURATION_CONFIG_REF_OFFSET_SHIFT (12) +/* MSVDX_CMDS, MC_CACHE_CONFIGURATION, CONFIG_ROW_OFFSET */ +#define MSVDX_CMDS_MC_CACHE_CONFIGURATION_CONFIG_ROW_OFFSET_MASK (0x0000003F) +#define MSVDX_CMDS_MC_CACHE_CONFIGURATION_CONFIG_ROW_OFFSET_LSBMASK (0x0000003F) +#define MSVDX_CMDS_MC_CACHE_CONFIGURATION_CONFIG_ROW_OFFSET_SHIFT (0) +/* MSVDX_CMDS, H264_WEIGHTED_FACTOR_DENOMINATOR, Y_LOG2_WEIGHT_DENOM */ +#define MSVDX_CMDS_VC1_LUMA_RANGE_MAPPING_BASE_ADDRESS_OFFSET (0x0028) +/* MSVDX_CMDS, VC1_LUMA_RANGE_MAPPING_BASE_ADDRESS, LUMA_RANGE_BASE_ADDR */ +#define MSVDX_CMDS_VC1_CHROMA_RANGE_MAPPING_BASE_ADDRESS_OFFSET (0x002C) +/* MSVDX_CMDS, VC1_RANGE_MAPPING_FLAGS, LUMA_RANGE_MAP */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_OFFSET (0x003C) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION, EXT_ROT_ROW_STRIDE */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_EXT_ROT_ROW_STRIDE_MASK (0xFFC00000) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_EXT_ROT_ROW_STRIDE_LSBMASK \ + (0x000003FF) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_EXT_ROT_ROW_STRIDE_SHIFT (22) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION, PACKED_422_OUTPUT */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_PACKED_422_OUTPUT_MASK (0x00000800) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_PACKED_422_OUTPUT_LSBMASK \ + (0x00000001) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_PACKED_422_OUTPUT_SHIFT (11) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION, USE_AUX_LINE_BUF */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_USE_AUX_LINE_BUF_MASK (0x00000400) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_USE_AUX_LINE_BUF_LSBMASK (0x00000001) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_USE_AUX_LINE_BUF_SHIFT (10) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION, SCALE_INPUT_SIZE_SEL */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_SCALE_INPUT_SIZE_SEL_MASK \ + (0x00000200) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_SCALE_INPUT_SIZE_SEL_LSBMASK \ + (0x00000001) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_SCALE_INPUT_SIZE_SEL_SHIFT (9) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION, USE_EXT_ROT_ROW_STRIDE */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_USE_EXT_ROT_ROW_STRIDE_MASK \ + (0x00000100) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_USE_EXT_ROT_ROW_STRIDE_LSBMASK \ + (0x00000001) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_USE_EXT_ROT_ROW_STRIDE_SHIFT (8) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION, ROTATION_ROW_STRIDE */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_ROTATION_ROW_STRIDE_MASK (0x00000070) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_ROTATION_ROW_STRIDE_LSBMASK \ + (0x00000007) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_ROTATION_ROW_STRIDE_SHIFT (4) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION, ROTATION_MODE */ +#define MSVDX_CMDS_EXTENDED_ROW_STRIDE_OFFSET (0x0040) + +/* MSVDX_CMDS, EXTENDED_ROW_STRIDE, EXT_ROW_STRIDE */ +#define MSVDX_CMDS_EXTENDED_ROW_STRIDE_EXT_ROW_STRIDE_MASK (0x0003FFC0) +#define MSVDX_CMDS_EXTENDED_ROW_STRIDE_EXT_ROW_STRIDE_LSBMASK (0x00000FFF) +#define MSVDX_CMDS_EXTENDED_ROW_STRIDE_EXT_ROW_STRIDE_SHIFT (6) +/* MSVDX_CMDS, EXTENDED_ROW_STRIDE, REF_PIC_MMU_TILED */ +#define MSVDX_CMDS_CHROMA_ROW_STRIDE_OFFSET (0x01AC) +/* MSVDX_CMDS, CHROMA_ROW_STRIDE, ALT_CHROMA_ROW_STRIDE */ +#define MSVDX_CMDS_CHROMA_ROW_STRIDE_ALT_CHROMA_ROW_STRIDE_MASK (0xFFC00000) +#define MSVDX_CMDS_CHROMA_ROW_STRIDE_ALT_CHROMA_ROW_STRIDE_LSBMASK (0x000003FF) +#define MSVDX_CMDS_CHROMA_ROW_STRIDE_ALT_CHROMA_ROW_STRIDE_SHIFT (22) +/* MSVDX_CMDS, CHROMA_ROW_STRIDE, CHROMA_ROW_STRIDE */ +#define MSVDX_CMDS_CHROMA_ROW_STRIDE_CHROMA_ROW_STRIDE_MASK (0x0003FFC0) +#define MSVDX_CMDS_CHROMA_ROW_STRIDE_CHROMA_ROW_STRIDE_LSBMASK (0x00000FFF) +#define MSVDX_CMDS_CHROMA_ROW_STRIDE_CHROMA_ROW_STRIDE_SHIFT (6) +/* MSVDX_CMDS, RPR_PICTURE_SIZE, RPR_PICTURE_WIDTH */ +#define MSVDX_CMDS_SCALED_DISPLAY_SIZE_OFFSET (0x0050) +/* MSVDX_CMDS, SCALED_DISPLAY_SIZE, SCALE_DISPLAY_HEIGHT */ +#define MSVDX_CMDS_SCALED_DISPLAY_SIZE_SCALE_DISPLAY_HEIGHT_MASK (0x00FFF000) +#define MSVDX_CMDS_SCALED_DISPLAY_SIZE_SCALE_DISPLAY_HEIGHT_LSBMASK (0x00000FFF) +#define MSVDX_CMDS_SCALED_DISPLAY_SIZE_SCALE_DISPLAY_HEIGHT_SHIFT (12) +/* MSVDX_CMDS, SCALED_DISPLAY_SIZE, SCALE_DISPLAY_WIDTH */ +#define MSVDX_CMDS_SCALED_DISPLAY_SIZE_SCALE_DISPLAY_WIDTH_MASK (0x00000FFF) +#define MSVDX_CMDS_SCALED_DISPLAY_SIZE_SCALE_DISPLAY_WIDTH_LSBMASK (0x00000FFF) +#define MSVDX_CMDS_SCALED_DISPLAY_SIZE_SCALE_DISPLAY_WIDTH_SHIFT (0) +#define MSVDX_CMDS_PVDEC_SCALED_DISPLAY_SIZE_OFFSET (0x00B8) +/* MSVDX_CMDS, PVDEC_SCALED_DISPLAY_SIZE, PVDEC_SCALE_DISPLAY_HEIGHT */ +#define MSVDX_CMDS_PVDEC_SCALED_DISPLAY_SIZE_PVDEC_SCALE_DISPLAY_HEIGHT_MASK (0xFFFF0000) +#define MSVDX_CMDS_PVDEC_SCALED_DISPLAY_SIZE_PVDEC_SCALE_DISPLAY_HEIGHT_LSBMASK (0x0000FFFF) +#define MSVDX_CMDS_PVDEC_SCALED_DISPLAY_SIZE_PVDEC_SCALE_DISPLAY_HEIGHT_SHIFT (16) +/* MSVDX_CMDS, PVDEC_SCALED_DISPLAY_SIZE, PVDEC_SCALE_DISPLAY_WIDTH */ +#define MSVDX_CMDS_PVDEC_SCALED_DISPLAY_SIZE_PVDEC_SCALE_DISPLAY_WIDTH_MASK (0x0000FFFF) +#define MSVDX_CMDS_PVDEC_SCALED_DISPLAY_SIZE_PVDEC_SCALE_DISPLAY_WIDTH_LSBMASK (0x0000FFFF) +#define MSVDX_CMDS_PVDEC_SCALED_DISPLAY_SIZE_PVDEC_SCALE_DISPLAY_WIDTH_SHIFT (0) +#define MSVDX_CMDS_HORIZONTAL_SCALE_CONTROL_OFFSET (0x0054) +/* MSVDX_CMDS, HORIZONTAL_SCALE_CONTROL, HORIZONTAL_INITIAL_POS */ +#define MSVDX_CMDS_HORIZONTAL_SCALE_CONTROL_HORIZONTAL_INITIAL_POS_MASK (0xFFFF0000) +#define MSVDX_CMDS_HORIZONTAL_SCALE_CONTROL_HORIZONTAL_INITIAL_POS_LSBMASK (0x0000FFFF) +#define MSVDX_CMDS_HORIZONTAL_SCALE_CONTROL_HORIZONTAL_INITIAL_POS_SHIFT (16) +/* MSVDX_CMDS, HORIZONTAL_SCALE_CONTROL, HORIZONTAL_SCALE_PITCH */ +#define MSVDX_CMDS_HORIZONTAL_SCALE_CONTROL_HORIZONTAL_SCALE_PITCH_MASK (0x0000FFFF) +#define MSVDX_CMDS_HORIZONTAL_SCALE_CONTROL_HORIZONTAL_SCALE_PITCH_LSBMASK (0x0000FFFF) +#define MSVDX_CMDS_HORIZONTAL_SCALE_CONTROL_HORIZONTAL_SCALE_PITCH_SHIFT (0) +#define MSVDX_CMDS_VERTICAL_SCALE_CONTROL_OFFSET (0x0058) +/* MSVDX_CMDS, VERTICAL_SCALE_CONTROL, VERTICAL_INITIAL_POS */ +#define MSVDX_CMDS_VERTICAL_SCALE_CONTROL_VERTICAL_INITIAL_POS_MASK (0xFFFF0000) +#define MSVDX_CMDS_VERTICAL_SCALE_CONTROL_VERTICAL_INITIAL_POS_LSBMASK (0x0000FFFF) +#define MSVDX_CMDS_VERTICAL_SCALE_CONTROL_VERTICAL_INITIAL_POS_SHIFT (16) +/* MSVDX_CMDS, VERTICAL_SCALE_CONTROL, VERTICAL_SCALE_PITCH */ +#define MSVDX_CMDS_VERTICAL_SCALE_CONTROL_VERTICAL_SCALE_PITCH_MASK (0x0000FFFF) +#define MSVDX_CMDS_VERTICAL_SCALE_CONTROL_VERTICAL_SCALE_PITCH_LSBMASK (0x0000FFFF) +#define MSVDX_CMDS_VERTICAL_SCALE_CONTROL_VERTICAL_SCALE_PITCH_SHIFT (0) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_OFFSET (0x01B4) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, ALT_BIT_DEPTH_CHROMA_MINUS8 */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_ALT_BIT_DEPTH_CHROMA_MINUS8_MASK (0x00007000) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_ALT_BIT_DEPTH_CHROMA_MINUS8_LSBMASK \ + (0x00000007) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_ALT_BIT_DEPTH_CHROMA_MINUS8_SHIFT (12) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, ALT_BIT_DEPTH_LUMA_MINUS8 */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_ALT_BIT_DEPTH_LUMA_MINUS8_MASK (0x00000700) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_ALT_BIT_DEPTH_LUMA_MINUS8_LSBMASK (0x00000007) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_ALT_BIT_DEPTH_LUMA_MINUS8_SHIFT (8) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, SCALE_LUMA_BIFILTER_HORIZ */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_LUMA_BIFILTER_HORIZ_MASK (0x00000080) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_LUMA_BIFILTER_HORIZ_LSBMASK (0x00000001) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_LUMA_BIFILTER_HORIZ_SHIFT (7) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, SCALE_LUMA_BIFILTER_VERT */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_LUMA_BIFILTER_VERT_MASK (0x00000040) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_LUMA_BIFILTER_VERT_LSBMASK (0x00000001) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_LUMA_BIFILTER_VERT_SHIFT (6) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, SCALE_CHROMA_BIFILTER_HORIZ */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_CHROMA_BIFILTER_HORIZ_MASK (0x00000020) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_CHROMA_BIFILTER_HORIZ_LSBMASK \ + (0x00000001) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_CHROMA_BIFILTER_HORIZ_SHIFT (5) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, SCALE_CHROMA_BIFILTER_VERT */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_CHROMA_BIFILTER_VERT_MASK (0x00000010) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_CHROMA_BIFILTER_VERT_LSBMASK \ + (0x00000001) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_CHROMA_BIFILTER_VERT_SHIFT (4) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, ALT_MEMORY_PACKING */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_ALT_MEMORY_PACKING_MASK (0x00000008) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_ALT_MEMORY_PACKING_LSBMASK (0x00000001) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_ALT_MEMORY_PACKING_SHIFT (3) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, SCALE_CHROMA_RESAMP_ONLY */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_CHROMA_RESAMP_ONLY_MASK (0x00000004) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_CHROMA_RESAMP_ONLY_LSBMASK (0x00000001) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_SCALE_CHROMA_RESAMP_ONLY_SHIFT (2) +/* MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, ALT_OUTPUT_FORMAT */ +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_ALT_OUTPUT_FORMAT_MASK (0x00000003) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_ALT_OUTPUT_FORMAT_LSBMASK (0x00000003) +#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_ALT_OUTPUT_FORMAT_SHIFT (0) +#define MSVDX_CMDS_SCALE_OUTPUT_SIZE_OFFSET (0x01B8) +/* MSVDX_CMDS, SCALE_OUTPUT_SIZE, SCALE_OUTPUT_HEIGHT_MIN1 */ +#define MSVDX_CMDS_SCALE_OUTPUT_SIZE_SCALE_OUTPUT_HEIGHT_MIN1_MASK (0xFFFF0000) +#define MSVDX_CMDS_SCALE_OUTPUT_SIZE_SCALE_OUTPUT_HEIGHT_MIN1_LSBMASK (0x0000FFFF) +#define MSVDX_CMDS_SCALE_OUTPUT_SIZE_SCALE_OUTPUT_HEIGHT_MIN1_SHIFT (16) +/* MSVDX_CMDS, SCALE_OUTPUT_SIZE, SCALE_OUTPUT_WIDTH_MIN1 */ +#define MSVDX_CMDS_SCALE_OUTPUT_SIZE_SCALE_OUTPUT_WIDTH_MIN1_MASK (0x0000FFFF) +#define MSVDX_CMDS_SCALE_OUTPUT_SIZE_SCALE_OUTPUT_WIDTH_MIN1_LSBMASK (0x0000FFFF) +#define MSVDX_CMDS_SCALE_OUTPUT_SIZE_SCALE_OUTPUT_WIDTH_MIN1_SHIFT (0) +#define MSVDX_CMDS_SCALE_HORIZONTAL_CHROMA_OFFSET (0x01BC) +/* MSVDX_CMDS, SCALE_HORIZONTAL_CHROMA, CHROMA_HORIZONTAL_INITIAL */ +#define MSVDX_CMDS_SCALE_HORIZONTAL_CHROMA_CHROMA_HORIZONTAL_INITIAL_MASK (0xFFFF0000) +#define MSVDX_CMDS_SCALE_HORIZONTAL_CHROMA_CHROMA_HORIZONTAL_INITIAL_LSBMASK (0x0000FFFF) +#define MSVDX_CMDS_SCALE_HORIZONTAL_CHROMA_CHROMA_HORIZONTAL_INITIAL_SHIFT (16) +#define MSVDX_CMDS_SCALE_HORIZONTAL_CHROMA_CHROMA_HORIZONTAL_PITCH_MASK (0x0000FFFF) +#define MSVDX_CMDS_SCALE_HORIZONTAL_CHROMA_CHROMA_HORIZONTAL_PITCH_LSBMASK (0x0000FFFF) +#define MSVDX_CMDS_SCALE_HORIZONTAL_CHROMA_CHROMA_HORIZONTAL_PITCH_SHIFT (0) +#define MSVDX_CMDS_SCALE_VERTICAL_CHROMA_OFFSET (0x01C0) +/* MSVDX_CMDS, SCALE_VERTICAL_CHROMA, CHROMA_VERTICAL_INITIAL */ +#define MSVDX_CMDS_SCALE_VERTICAL_CHROMA_CHROMA_VERTICAL_INITIAL_MASK (0xFFFF0000) +#define MSVDX_CMDS_SCALE_VERTICAL_CHROMA_CHROMA_VERTICAL_INITIAL_LSBMASK (0x0000FFFF) +#define MSVDX_CMDS_SCALE_VERTICAL_CHROMA_CHROMA_VERTICAL_INITIAL_SHIFT (16) +/* MSVDX_CMDS, SCALE_VERTICAL_CHROMA, CHROMA_VERTICAL_PITCH */ +#define MSVDX_CMDS_SCALE_VERTICAL_CHROMA_CHROMA_VERTICAL_PITCH_MASK (0x0000FFFF) +#define MSVDX_CMDS_SCALE_VERTICAL_CHROMA_CHROMA_VERTICAL_PITCH_LSBMASK (0x0000FFFF) +#define MSVDX_CMDS_SCALE_VERTICAL_CHROMA_CHROMA_VERTICAL_PITCH_SHIFT (0) +/* MSVDX_CMDS, MULTICORE_OPERATING_MODE, MBLK_ROW_OFFSET */ +#define MSVDX_CMDS_AUX_LINE_BUFFER_BASE_ADDRESS_OFFSET (0x01EC) + +#endif /* _IMG_MSVDX_CMDS_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_core_regs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_core_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_core_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_core_regs.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG MSVDX core Registers + * This file contains the MSVDX_CORE_REGS_H Definitions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef _IMG_MSVDX_CORE_REGS_H +#define _IMG_MSVDX_CORE_REGS_H + +#define MSVDX_CORE_CR_MMU_TILE_NO_ENTRIES (4) +#define MSVDX_CORE_CR_MMU_TILE_EXT_NO_ENTRIES (4) + +#endif /* _IMG_MSVDX_CORE_REGS_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_vdmc_regs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_vdmc_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_vdmc_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_vdmc_regs.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG MSVDX VDMC Registers + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef _IMG_MSVDX_VDMC_REGS_H +#define _IMG_MSVDX_VDMC_REGS_H + +/* MSVDX_VDMC, CR_VDMC_MACROBLOCK_NUMBER, CR_VDMC_MACROBLOCK_X_OFFSET */ +#define MSVDX_VDMC_CR_VDMC_MACROBLOCK_NUMBER_CR_VDMC_MACROBLOCK_X_OFFSET_MASK (0x0000FFFF) +#define MSVDX_VDMC_CR_VDMC_MACROBLOCK_NUMBER_CR_VDMC_MACROBLOCK_X_OFFSET_SHIFT (0) + +/* MSVDX_VDMC, CR_VDMC_MACROBLOCK_NUMBER, CR_VDMC_MACROBLOCK_Y_OFFSET */ +#define MSVDX_VDMC_CR_VDMC_MACROBLOCK_NUMBER_CR_VDMC_MACROBLOCK_Y_OFFSET_MASK (0xFFFF0000) +#define MSVDX_VDMC_CR_VDMC_MACROBLOCK_NUMBER_CR_VDMC_MACROBLOCK_Y_OFFSET_SHIFT (16) + +#endif /* _IMG_MSVDX_VDMC_REGS_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_vec_regs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_vec_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_vec_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/img_msvdx_vec_regs.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG MSVDX VEC Registers + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#if !defined(__MSVDX_VEC_REGS_H__) +#define __MSVDX_VEC_REGS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + /* MSVDX_VEC, CR_VEC_VLR_COMMANDS_NUM, VLR_COMMANDS_STORE_NUMBER_OF_CMDS */ +#define MSVDX_VEC_CR_VEC_VLC_TABLE_ADDR0_OFFSET (0x00EC) + + /* MSVDX_VEC, CR_VEC_VLC_TABLE_ADDR0, VLC_TABLE_ADDR0 */ +#define MSVDX_VEC_CR_VEC_VLC_TABLE_ADDR0_VLC_TABLE_ADDR0_MASK (0x000007FF) + + /* MSVDX_VEC, CR_VEC_VLC_TABLE_ADDR15, VLC_TABLE_ADDR31 */ +#define MSVDX_VEC_CR_VEC_VLC_TABLE_ADDR16_OFFSET (0x01C0) + + /* MSVDX_VEC, CR_VEC_VLC_TABLE_ADDR15, VLC_TABLE_ADDR31 */ +#define MSVDX_VEC_CR_VEC_VLC_TABLE_ADDR16_OFFSET (0x01C0) + + /* MSVDX_VEC, CR_VEC_VLC_TABLE_ADDR18, VLC_TABLE_ADDR37 */ +#define MSVDX_VEC_CR_VEC_VLC_TABLE_INITIAL_WIDTH0_OFFSET (0x012C) + + /* MSVDX_VEC, CR_VEC_VLC_TABLE_ADDR0, VLC_TABLE_ADDR1 */ +#define MSVDX_VEC_CR_VEC_VLC_TABLE_ADDR0_VLC_TABLE_ADDR1_SHIFT (11) + + /* MSVDX_VEC, CR_VEC_VLC_TABLE_INITIAL_WIDTH0, VLC_TABLE_INITIAL_WIDTH0 */ +#define MSVDX_VEC_CR_VEC_VLC_TABLE_INITIAL_WIDTH0_VLC_TABLE_INITIAL_WIDTH0_MASK (0x00000007) + + /* MSVDX_VEC, CR_VEC_VLC_TABLE_INITIAL_WIDTH0, VLC_TABLE_INITIAL_WIDTH1 */ +#define MSVDX_VEC_CR_VEC_VLC_TABLE_INITIAL_WIDTH0_VLC_TABLE_INITIAL_WIDTH1_SHIFT (3) + + /* MSVDX_VEC, CR_VEC_VLC_TABLE_INITIAL_OPCODE0, VLC_TABLE_INITIAL_OPCODE0 */ +#define MSVDX_VEC_CR_VEC_VLC_TABLE_INITIAL_OPCODE0_VLC_TABLE_INITIAL_OPCODE0_MASK \ + (0x00000003) + + /* MSVDX_VEC, CR_VEC_VLC_TABLE_INITIAL_WIDTH3, VLC_TABLE_INITIAL_WIDTH37 */ +#define MSVDX_VEC_CR_VEC_VLC_TABLE_INITIAL_OPCODE0_OFFSET (0x013C) + + /* MSVDX_VEC, CR_VEC_VLC_TABLE_INITIAL_OPCODE0, VLC_TABLE_INITIAL_OPCODE1 */ +#define MSVDX_VEC_CR_VEC_VLC_TABLE_INITIAL_OPCODE0_VLC_TABLE_INITIAL_OPCODE1_SHIFT (2) + +#ifdef __cplusplus +} +#endif + +#endif /* __MSVDX_VEC_REGS_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/img_pixfmts.h b/drivers/media/platform/imagination/vxe-vxd/decoder/img_pixfmts.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/img_pixfmts.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/img_pixfmts.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD DEC SYSDEV and UI Interface header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + */ + +#ifndef __IMG_PIXFMTS_H__ +#define __IMG_PIXFMTS_H__ +/* + * @brief Old pixel format definition + * + * @note These definitions are different in HW documentation(current to HW doc): + * @li PL8 is defined as PL111 + * @li PL12 is sometime used wrongly for monochrome formats instead of PL_Y + */ +enum img_pixfmt { + IMG_PIXFMT_CLUT1 = 0, + IMG_PIXFMT_CLUT2 = 1, + IMG_PIXFMT_CLUT4 = 2, + IMG_PIXFMT_I4A4 = 3, + IMG_PIXFMT_I8A8 = 4, + IMG_PIXFMT_A8I8 = 51, + IMG_PIXFMT_RGB8 = 5, + IMG_PIXFMT_RGB332 = 6, + IMG_PIXFMT_RGB555 = 7, + IMG_PIXFMT_ARGB4444 = 8, + IMG_PIXFMT_ABGR4444 = 57, + IMG_PIXFMT_RGBA4444 = 58, + IMG_PIXFMT_BGRA4444 = 59, + IMG_PIXFMT_ARGB1555 = 9, + IMG_PIXFMT_ABGR1555 = 60, + IMG_PIXFMT_RGBA5551 = 61, + IMG_PIXFMT_BGRA5551 = 62, + IMG_PIXFMT_RGB565 = 10, + IMG_PIXFMT_BGR565 = 63, + IMG_PIXFMT_RGB888 = 11, + IMG_PIXFMT_RSGSBS888 = 68, + IMG_PIXFMT_ARGB8888 = 12, + IMG_PIXFMT_ABGR8888 = 41, + IMG_PIXFMT_BGRA8888 = 42, + IMG_PIXFMT_RGBA8888 = 56, + IMG_PIXFMT_ARGB8332 = 43, + IMG_PIXFMT_ARGB8161616 = 64, + IMG_PIXFMT_ARGB2101010 = 67, + IMG_PIXFMT_UYVY8888 = 13, + IMG_PIXFMT_VYUY8888 = 14, + IMG_PIXFMT_YVYU8888 = 15, + IMG_PIXFMT_YUYV8888 = 16, + IMG_PIXFMT_UYVY10101010 = 17, + IMG_PIXFMT_VYAUYA8888 = 18, + IMG_PIXFMT_YUV101010 = 19, + IMG_PIXFMT_AYUV4444 = 20, + IMG_PIXFMT_YUV888 = 21, + IMG_PIXFMT_AYUV8888 = 22, + IMG_PIXFMT_AYUV2101010 = 23, + IMG_PIXFMT_411PL111YUV8 = 120, + IMG_PIXFMT_411PL12YUV8 = 121, + IMG_PIXFMT_411PL12YVU8 = 24, + IMG_PIXFMT_420PL12YUV8 = 25, + IMG_PIXFMT_420PL12YVU8 = 26, + IMG_PIXFMT_422PL12YUV8 = 27, + IMG_PIXFMT_422PL12YVU8 = 28, + IMG_PIXFMT_420PL8YUV8 = 47, + IMG_PIXFMT_422PL8YUV8 = 48, + IMG_PIXFMT_420PL12YUV8_A8 = 31, + IMG_PIXFMT_422PL12YUV8_A8 = 32, + IMG_PIXFMT_PL12Y8 = 33, + IMG_PIXFMT_PL12YV8 = 35, + IMG_PIXFMT_PL12IMC2 = 36, + IMG_PIXFMT_A4 = 37, + IMG_PIXFMT_A8 = 38, + IMG_PIXFMT_YUV8 = 39, + IMG_PIXFMT_CVBS10 = 40, + IMG_PIXFMT_PL12YV12 = 44, +#if ((!defined(METAG) && !defined(MTXG)) || defined(__linux__)) + IMG_PIXFMT_F16 = 52, + IMG_PIXFMT_F32 = 53, + IMG_PIXFMT_F16F16F16F16 = 65, +#endif + IMG_PIXFMT_L16 = 54, + IMG_PIXFMT_L32 = 55, + IMG_PIXFMT_Y1 = 66, + IMG_PIXFMT_444PL111YUV8 = 69, + IMG_PIXFMT_444PL12YUV8 = 137, + IMG_PIXFMT_444PL12YVU8 = 138, + IMG_PIXFMT_PL12Y10 = 34, + IMG_PIXFMT_PL12Y10_LSB = 96, + IMG_PIXFMT_PL12Y10_MSB = 97, + IMG_PIXFMT_420PL8YUV10 = 49, + IMG_PIXFMT_420PL111YUV10_LSB = 71, + IMG_PIXFMT_420PL111YUV10_MSB = 72, + IMG_PIXFMT_420PL12YUV10 = 29, + IMG_PIXFMT_420PL12YUV10_LSB = 74, + IMG_PIXFMT_420PL12YUV10_MSB = 75, + IMG_PIXFMT_420PL12YVU10 = 45, + IMG_PIXFMT_420PL12YVU10_LSB = 77, + IMG_PIXFMT_420PL12YVU10_MSB = 78, + IMG_PIXFMT_422PL8YUV10 = 50, + IMG_PIXFMT_422PL111YUV10_LSB = 122, + IMG_PIXFMT_422PL111YUV10_MSB = 123, + IMG_PIXFMT_422PL12YUV10 = 30, + IMG_PIXFMT_422PL12YUV10_LSB = 80, + IMG_PIXFMT_422PL12YUV10_MSB = 81, + IMG_PIXFMT_422PL12YVU10 = 46, + IMG_PIXFMT_422PL12YVU10_LSB = 83, + IMG_PIXFMT_422PL12YVU10_MSB = 84, + IMG_PIXFMT_444PL111YUV10 = 85, + IMG_PIXFMT_444PL111YUV10_LSB = 86, + IMG_PIXFMT_444PL111YUV10_MSB = 87, + IMG_PIXFMT_444PL12YUV10 = 139, + IMG_PIXFMT_444PL12YUV10_LSB = 141, + IMG_PIXFMT_444PL12YUV10_MSB = 142, + IMG_PIXFMT_444PL12YVU10 = 140, + IMG_PIXFMT_444PL12YVU10_LSB = 143, + IMG_PIXFMT_444PL12YVU10_MSB = 144, + IMG_PIXFMT_420PL12Y8UV10 = 88, + IMG_PIXFMT_420PL12Y8UV10_LSB = 98, + IMG_PIXFMT_420PL12Y8UV10_MSB = 99, + IMG_PIXFMT_420PL12Y8VU10 = 89, + IMG_PIXFMT_420PL12Y8VU10_LSB = 100, + IMG_PIXFMT_420PL12Y8VU10_MSB = 101, + IMG_PIXFMT_420PL111Y8UV10 = 70, + IMG_PIXFMT_420PL111Y8UV10_LSB = 127, + IMG_PIXFMT_420PL111Y8UV10_MSB = 125, + IMG_PIXFMT_422PL12Y8UV10 = 90, + IMG_PIXFMT_422PL12Y8UV10_LSB = 102, + IMG_PIXFMT_422PL12Y8UV10_MSB = 103, + IMG_PIXFMT_422PL12Y8VU10 = 91, + IMG_PIXFMT_422PL12Y8VU10_LSB = 104, + IMG_PIXFMT_422PL12Y8VU10_MSB = 105, + IMG_PIXFMT_444PL12Y8UV10 = 151, + IMG_PIXFMT_444PL12Y8UV10_LSB = 153, + IMG_PIXFMT_444PL12Y8UV10_MSB = 154, + IMG_PIXFMT_444PL12Y8VU10 = 152, + IMG_PIXFMT_444PL12Y8VU10_LSB = 155, + IMG_PIXFMT_444PL12Y8VU10_MSB = 156, + IMG_PIXFMT_420PL12Y10UV8 = 92, + IMG_PIXFMT_420PL12Y10UV8_LSB = 106, + IMG_PIXFMT_420PL12Y10UV8_MSB = 107, + + IMG_PIXFMT_420PL12Y10VU8 = 93, + IMG_PIXFMT_420PL12Y10VU8_LSB = 108, + IMG_PIXFMT_420PL12Y10VU8_MSB = 109, + + IMG_PIXFMT_420PL111Y10UV8 = 129, + IMG_PIXFMT_420PL111Y10UV8_LSB = 133, + IMG_PIXFMT_420PL111Y10UV8_MSB = 131, + IMG_PIXFMT_422PL12Y10UV8 = 94, + IMG_PIXFMT_422PL12Y10UV8_LSB = 110, + IMG_PIXFMT_422PL12Y10UV8_MSB = 111, + IMG_PIXFMT_422PL12Y10VU8 = 95, + IMG_PIXFMT_422PL12Y10VU8_LSB = 112, + IMG_PIXFMT_422PL12Y10VU8_MSB = 113, + + IMG_PIXFMT_444PL111Y10UV8 = 114, + IMG_PIXFMT_444PL111Y10UV8_LSB = 115, + IMG_PIXFMT_444PL111Y10UV8_MSB = 116, + IMG_PIXFMT_444PL111Y8UV10 = 117, + IMG_PIXFMT_444PL111Y8UV10_LSB = 118, + IMG_PIXFMT_444PL111Y8UV10_MSB = 119, + IMG_PIXFMT_444PL12Y10UV8 = 145, + IMG_PIXFMT_444PL12Y10UV8_LSB = 147, + IMG_PIXFMT_444PL12Y10UV8_MSB = 148, + IMG_PIXFMT_444PL12Y10VU8 = 146, + IMG_PIXFMT_444PL12Y10VU8_LSB = 149, + IMG_PIXFMT_444PL12Y10VU8_MSB = 150, + IMG_PIXFMT_422PL111Y8UV10 = 124, + IMG_PIXFMT_422PL111Y8UV10_MSB = 126, + IMG_PIXFMT_422PL111Y8UV10_LSB = 128, + + IMG_PIXFMT_422PL111Y10UV8 = 130, + IMG_PIXFMT_422PL111Y10UV8_LSB = 134, + IMG_PIXFMT_422PL111Y10UV8_MSB = 132, + IMG_PIXFMT_420PL8YUV12 = 160, + IMG_PIXFMT_422PL8YUV12 = 161, + IMG_PIXFMT_444PL8YUV12 = 162, + IMG_PIXFMT_420PL8YUV14 = 163, + IMG_PIXFMT_422PL8YUV14 = 164, + IMG_PIXFMT_444PL8YUV14 = 165, + IMG_PIXFMT_420PL8YUV16 = 166, + IMG_PIXFMT_422PL8YUV16 = 167, + IMG_PIXFMT_444PL8YUV16 = 168, + IMG_PIXFMT_UNDEFINED = 255, + + IMG_PIXFMT_ARBPLANAR8 = 65536, + IMG_PIXFMT_ARBPLANAR8_LAST = IMG_PIXFMT_ARBPLANAR8 + 0xffff, + IMG_PIXFMT_FORCE32BITS = 0x7FFFFFFFU +}; + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/img_profiles_levels.h b/drivers/media/platform/imagination/vxe-vxd/decoder/img_profiles_levels.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/img_profiles_levels.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/img_profiles_levels.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD DEC SYSDEV and UI Interface header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef __IMG_PROFILES_LEVELS_H +#define __IMG_PROFILES_LEVELS_H + +#include "vdecdd_utils.h" + +/* Minimum level value for h.264 */ +#define H264_LEVEL_MIN (9) +/* Maximum level value for h.264 */ +#define H264_LEVEL_MAX (52) +/* Number of major levels for h.264 (5 + 1 for special levels) */ +#define H264_LEVEL_MAJOR_NUM (6) +/* Number of minor levels for h.264 */ +#define H264_LEVEL_MINOR_NUM (4) +/* Number of major levels for HEVC */ +#define HEVC_LEVEL_MAJOR_NUM (6) +/* Number of minor levels for HEVC */ +#define HEVC_LEVEL_MINOR_NUM (3) + +#endif /*__IMG_PROFILES_LEVELS_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/img_pvdec_core_regs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/img_pvdec_core_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/img_pvdec_core_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/img_pvdec_core_regs.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG PVDEC CORE Registers + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef _IMG_PVDEC_CORE_REGS_H +#define _IMG_PVDEC_CORE_REGS_H + +/* PVDEC_CORE, CR_PVDEC_HOST_INTERRUPT_STATUS, CR_HOST_SYS_WDT */ +#define PVDEC_CORE_CR_PVDEC_HOST_INTERRUPT_STATUS_CR_HOST_SYS_WDT_MASK (0x10000000) + +#define PVDEC_CORE_CR_PVDEC_HOST_INTERRUPT_STATUS_CR_HOST_SYS_WDT_SHIFT (28) + +/* PVDEC_CORE, CR_PVDEC_HOST_INTERRUPT_STATUS, CR_HOST_READ_TIMEOUT_PROC_IRQ */ +#define PVDEC_CORE_CR_PVDEC_HOST_INTERRUPT_STATUS_CR_HOST_READ_TIMEOUT_PROC_IRQ_MASK \ + (0x08000000) + +/* PVDEC_CORE, CR_PVDEC_CORE_REV, CR_PVDEC_MAJOR_REV */ +#define PVDEC_CORE_CR_PVDEC_CORE_REV_CR_PVDEC_MAJOR_REV_MASK (0x00FF0000) +#define PVDEC_CORE_CR_PVDEC_CORE_REV_CR_PVDEC_MAJOR_REV_SHIFT (16) + +/* PVDEC_CORE, CR_PVDEC_CORE_REV, CR_PVDEC_MINOR_REV */ +#define PVDEC_CORE_CR_PVDEC_CORE_REV_CR_PVDEC_MINOR_REV_MASK (0x0000FF00) +#define PVDEC_CORE_CR_PVDEC_CORE_REV_CR_PVDEC_MINOR_REV_SHIFT (8) + +/* PVDEC_CORE, CR_PVDEC_HOST_INTERRUPT_STATUS, CR_HOST_READ_TIMEOUT_PROC_IRQ */ +#define PVDEC_CORE_CR_PVDEC_HOST_INTERRUPT_STATUS_CR_HOST_READ_TIMEOUT_PROC_IRQ_SHIFT (27) + +/* PVDEC_CORE, CR_PVDEC_HOST_INTERRUPT_STATUS, CR_HOST_COMMAND_TIMEOUT_PROC_IRQ */ +#define PVDEC_CORE_CR_PVDEC_HOST_INTERRUPT_STATUS_CR_HOST_COMMAND_TIMEOUT_PROC_IRQ_MASK \ + (0x04000000) +#define PVDEC_CORE_CR_PVDEC_HOST_INTERRUPT_STATUS_CR_HOST_COMMAND_TIMEOUT_PROC_IRQ_SHIFT \ + (26) + +/* PVDEC_CORE, CR_PVDEC_CORE_ID, CR_GROUP_ID */ +#define PVDEC_CORE_CR_PVDEC_CORE_ID_CR_GROUP_ID_MASK (0xFF000000) +#define PVDEC_CORE_CR_PVDEC_CORE_ID_CR_GROUP_ID_SHIFT (24) + +/* PVDEC_CORE, CR_PVDEC_CORE_REV, CR_PVDEC_MAINT_REV */ +#define PVDEC_CORE_CR_PVDEC_CORE_REV_CR_PVDEC_MAINT_REV_MASK (0x000000FF) +#define PVDEC_CORE_CR_PVDEC_CORE_REV_CR_PVDEC_MAINT_REV_SHIFT (0) + +/* PVDEC_CORE, CR_PVDEC_CORE_ID, CR_CORE_ID */ +#define PVDEC_CORE_CR_PVDEC_CORE_ID_CR_CORE_ID_MASK (0x00FF0000) +#define PVDEC_CORE_CR_PVDEC_CORE_ID_CR_CORE_ID_SHIFT (16) + +/* PVDEC_CORE, CR_PVDEC_CORE_ID, CR_PVDEC_CORE_CONFIG */ +#define PVDEC_CORE_CR_PVDEC_CORE_ID_CR_PVDEC_CORE_CONFIG_MASK (0x0000FFFF) +#define PVDEC_CORE_CR_PVDEC_CORE_ID_CR_PVDEC_CORE_CONFIG_SHIFT (0) + +#endif /* _IMG_PVDEC_CORE_REGS_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/img_pvdec_pixel_regs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/img_pvdec_pixel_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/img_pvdec_pixel_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/img_pvdec_pixel_regs.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG PVDEC pixel Registers + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef _IMG_PVDEC_PIXEL_REGS_H +#define _IMG_PVDEC_PIXEL_REGS_H + +/* PVDEC_PIXEL, CR_MAX_FRAME_CONFIG, CR_PVDEC_HOR_MSB */ +#define PVDEC_PIXEL_CR_MAX_FRAME_CONFIG_CR_PVDEC_HOR_MSB_MASK (0x001F0000) + +#define PVDEC_PIXEL_CR_MAX_FRAME_CONFIG_CR_PVDEC_HOR_MSB_SHIFT (16) + +/* PVDEC_PIXEL, CR_MAX_FRAME_CONFIG, CR_PVDEC_VER_MSB */ +#define PVDEC_PIXEL_CR_MAX_FRAME_CONFIG_CR_PVDEC_VER_MSB_MASK (0x1F000000) +#define PVDEC_PIXEL_CR_MAX_FRAME_CONFIG_CR_PVDEC_VER_MSB_SHIFT (24) + +/* PVDEC_PIXEL, CR_MAX_FRAME_CONFIG, CR_MSVDX_HOR_MSB */ +#define PVDEC_PIXEL_CR_MAX_FRAME_CONFIG_CR_MSVDX_HOR_MSB_MASK (0x0000001F) +#define PVDEC_PIXEL_CR_MAX_FRAME_CONFIG_CR_MSVDX_HOR_MSB_SHIFT (0) + +/* PVDEC_PIXEL, CR_MAX_FRAME_CONFIG, CR_MSVDX_VER_MSB */ +#define PVDEC_PIXEL_CR_MAX_FRAME_CONFIG_CR_MSVDX_VER_MSB_MASK (0x00001F00) +#define PVDEC_PIXEL_CR_MAX_FRAME_CONFIG_CR_MSVDX_VER_MSB_SHIFT (8) + +#endif /* _IMG_PVDEC_PIXEL_REGS_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/img_pvdec_test_regs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/img_pvdec_test_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/img_pvdec_test_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/img_pvdec_test_regs.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG PVDEC test Registers + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef _IMG_PVDEC_TEST_REGS_H +#define _IMG_PVDEC_TEST_REGS_H + +/* PVDEC_TEST, RAND_STL_MEM_RDATA_CONFIG, STALL_ENABLE_MEM_RDATA */ +#define PVDEC_TEST_MEM_READ_LATENCY_OFFSET (0x00F0) + +/* PVDEC_TEST, MEM_READ_LATENCY, READ_RESPONSE_RAND_LATENCY */ +#define PVDEC_TEST_MEM_WRITE_RESPONSE_LATENCY_OFFSET (0x00F4) + +/* PVDEC_TEST, MEM_WRITE_RESPONSE_LATENCY, WRITE_RESPONSE_RAND_LATENCY */ +#define PVDEC_TEST_MEM_CTRL_OFFSET (0x00F8) + +/* PVDEC_TEST, RAND_STL_MEM_WDATA_CONFIG, STALL_ENABLE_MEM_WDATA */ +#define PVDEC_TEST_RAND_STL_MEM_WRESP_CONFIG_OFFSET (0x00E8) + +/* PVDEC_TEST, RAND_STL_MEM_WRESP_CONFIG, STALL_ENABLE_MEM_WRESP */ +#define PVDEC_TEST_RAND_STL_MEM_RDATA_CONFIG_OFFSET (0x00EC) + +/* PVDEC_TEST, MEMORY_BUS2_MONITOR_2, BUS2_ADDR */ +#define PVDEC_TEST_RAND_STL_MEM_CMD_CONFIG_OFFSET (0x00E0) + +/* PVDEC_TEST, RAND_STL_MEM_CMD_CONFIG, STALL_ENABLE_MEM_CMD */ +#define PVDEC_TEST_RAND_STL_MEM_WDATA_CONFIG_OFFSET (0x00E4) + +#endif /* _IMG_PVDEC_TEST_REGS_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/img_vdec_fw_msg.h b/drivers/media/platform/imagination/vxe-vxd/decoder/img_vdec_fw_msg.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/img_vdec_fw_msg.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/img_vdec_fw_msg.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG VDEC firmware messages + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef _IMG_VDEC_FW_MSG_H +#define _IMG_VDEC_FW_MSG_H + +#include + +/* FW_DEVA_COMPLETED ERROR_FLAGS */ +#define FW_DEVA_COMPLETED_ERROR_FLAGS_TYPE unsigned short +#define FW_DEVA_COMPLETED_ERROR_FLAGS_MASK (0xFFFF) +#define FW_DEVA_COMPLETED_ERROR_FLAGS_SHIFT (0) +#define FW_DEVA_COMPLETED_ERROR_FLAGS_OFFSET (0x000C) + +/* FW_DEVA_COMPLETED NUM_BEWDTS */ +#define FW_DEVA_COMPLETED_NUM_BEWDTS_TYPE unsigned int +#define FW_DEVA_COMPLETED_NUM_BEWDTS_MASK (0xFFFFFFFF) +#define FW_DEVA_COMPLETED_NUM_BEWDTS_SHIFT (0) +#define FW_DEVA_COMPLETED_NUM_BEWDTS_OFFSET (0x0010) + +/* FW_DEVA_COMPLETED NUM_MBSDROPPED */ +#define FW_DEVA_COMPLETED_NUM_MBSDROPPED_TYPE unsigned int +#define FW_DEVA_COMPLETED_NUM_MBSDROPPED_MASK (0xFFFFFFFF) +#define FW_DEVA_COMPLETED_NUM_MBSDROPPED_SHIFT (0) +#define FW_DEVA_COMPLETED_NUM_MBSDROPPED_OFFSET (0x0014) + +/* FW_DEVA_COMPLETED NUM_MBSRECOVERED */ +#define FW_DEVA_COMPLETED_NUM_MBSRECOVERED_TYPE unsigned int +#define FW_DEVA_COMPLETED_NUM_MBSRECOVERED_MASK (0xFFFFFFFF) +#define FW_DEVA_COMPLETED_NUM_MBSRECOVERED_SHIFT (0) +#define FW_DEVA_COMPLETED_NUM_MBSRECOVERED_OFFSET (0x0018) + +/* FW_DEVA_PANIC ERROR_INT */ +#define FW_DEVA_PANIC_ERROR_INT_TYPE unsigned int +#define FW_DEVA_PANIC_ERROR_INT_MASK (0xFFFFFFFF) +#define FW_DEVA_PANIC_ERROR_INT_SHIFT (0) +#define FW_DEVA_PANIC_ERROR_INT_OFFSET (0x000C) + +/* FW_ASSERT FILE_NAME_HASH */ +#define FW_ASSERT_FILE_NAME_HASH_TYPE unsigned int +#define FW_ASSERT_FILE_NAME_HASH_MASK (0xFFFFFFFF) +#define FW_ASSERT_FILE_NAME_HASH_SHIFT (0) +#define FW_ASSERT_FILE_NAME_HASH_OFFSET (0x0004) + +/* FW_ASSERT FILE_LINE */ +#define FW_ASSERT_FILE_LINE_TYPE unsigned int +#define FW_ASSERT_FILE_LINE_MASK (0xFFFFFFFE) +#define FW_ASSERT_FILE_LINE_SHIFT (1) +#define FW_ASSERT_FILE_LINE_OFFSET (0x0008) + +/* FW_SO TASK_NAME */ +#define FW_SO_TASK_NAME_TYPE unsigned int +#define FW_SO_TASK_NAME_MASK (0xFFFFFFFF) +#define FW_SO_TASK_NAME_SHIFT (0) +#define FW_SO_TASK_NAME_OFFSET (0x0004) + +/* FW_DEVA_GENMSG TRANS_ID */ +#define FW_DEVA_GENMSG_TRANS_ID_TYPE unsigned int +#define FW_DEVA_GENMSG_TRANS_ID_MASK (0xFFFFFFFF) +#define FW_DEVA_GENMSG_TRANS_ID_SHIFT (0) +#define FW_DEVA_GENMSG_TRANS_ID_OFFSET (0x0008) + +/* FW_DEVA_GENMSG MSG_TYPE */ +#define FW_DEVA_GENMSG_MSG_TYPE_TYPE unsigned char +#define FW_DEVA_GENMSG_MSG_TYPE_MASK (0xFF) +#define FW_DEVA_GENMSG_MSG_TYPE_SHIFT (0) +#define FW_DEVA_GENMSG_MSG_TYPE_OFFSET (0x0001) + +/* FW_DEVA_SIGNATURES SIGNATURES */ +#define FW_DEVA_SIGNATURES_SIGNATURES_OFFSET (0x0010) + +/* FW_DEVA_SIGNATURES MSG_SIZE */ +#define FW_DEVA_SIGNATURES_MSG_SIZE_TYPE unsigned char +#define FW_DEVA_SIGNATURES_MSG_SIZE_MASK (0x7F) +#define FW_DEVA_SIGNATURES_MSG_SIZE_SHIFT (0) +#define FW_DEVA_SIGNATURES_MSG_SIZE_OFFSET (0x0000) + +/* FW_DEVA_CONTIGUITY_WARNING BEGIN_MB_NUM */ +#define FW_DEVA_SIGNATURES_SIZE (20) + +/* FW_DEVA_SIGNATURES SIGNATURE_SELECT */ +#define FW_DEVA_SIGNATURES_SIGNATURE_SELECT_TYPE unsigned int +#define FW_DEVA_SIGNATURES_SIGNATURE_SELECT_MASK (0xFFFFFFFF) +#define FW_DEVA_SIGNATURES_SIGNATURE_SELECT_SHIFT (0) +#define FW_DEVA_SIGNATURES_SIGNATURE_SELECT_OFFSET (0x000C) + +/* FW_DEVA_GENMSG TRANS_ID */ +#define FW_DEVA_DECODE_SIZE (52) + +/* FW_DEVA_DECODE CTRL_ALLOC_ADDR */ +#define FW_DEVA_DECODE_CTRL_ALLOC_ADDR_TYPE unsigned int +#define FW_DEVA_DECODE_CTRL_ALLOC_ADDR_MASK (0xFFFFFFFF) +#define FW_DEVA_DECODE_CTRL_ALLOC_ADDR_SHIFT (0) +#define FW_DEVA_DECODE_CTRL_ALLOC_ADDR_OFFSET (0x0010) + +/* FW_DEVA_DECODE BUFFER_SIZE */ +#define FW_DEVA_DECODE_BUFFER_SIZE_TYPE unsigned short +#define FW_DEVA_DECODE_BUFFER_SIZE_MASK (0xFFFF) +#define FW_DEVA_DECODE_BUFFER_SIZE_SHIFT (0) +#define FW_DEVA_DECODE_BUFFER_SIZE_OFFSET (0x000E) + +/* FW_DEVA_DECODE OPERATING_MODE */ +#define FW_DEVA_DECODE_OPERATING_MODE_TYPE unsigned int +#define FW_DEVA_DECODE_OPERATING_MODE_MASK (0xFFFFFFFF) +#define FW_DEVA_DECODE_OPERATING_MODE_OFFSET (0x0018) +#define FW_DEVA_DECODE_OPERATING_MODE_SHIFT (0) + +/* FW_DEVA_DECODE FLAGS */ +#define FW_DEVA_DECODE_FLAGS_TYPE unsigned short +#define FW_DEVA_DECODE_FLAGS_MASK (0xFFFF) +#define FW_DEVA_DECODE_FLAGS_SHIFT (0) +#define FW_DEVA_DECODE_FLAGS_OFFSET (0x000C) + +/* FW_DEVA_DECODE VDEC_FLAGS */ +#define FW_DEVA_DECODE_VDEC_FLAGS_TYPE unsigned char +#define FW_DEVA_DECODE_VDEC_FLAGS_MASK (0xFF) +#define FW_DEVA_DECODE_VDEC_FLAGS_SHIFT (0) +#define FW_DEVA_DECODE_VDEC_FLAGS_OFFSET (0x001E) + +/* FW_DEVA_DECODE GENC_ID */ +#define FW_DEVA_DECODE_GENC_ID_TYPE unsigned int +#define FW_DEVA_DECODE_GENC_ID_MASK (0xFFFFFFFF) +#define FW_DEVA_DECODE_GENC_ID_SHIFT (0) +#define FW_DEVA_DECODE_GENC_ID_OFFSET (0x0028) + +/* FW_DEVA_DECODE MB_LOAD */ +#define FW_DEVA_DECODE_MB_LOAD_TYPE unsigned int +#define FW_DEVA_DECODE_MB_LOAD_MASK (0xFFFFFFFF) +#define FW_DEVA_DECODE_MB_LOAD_OFFSET (0x0030) +#define FW_DEVA_DECODE_MB_LOAD_SHIFT (0) +#define FW_DEVA_DECODE_FRAGMENT_SIZE (16) + +/* FW_DEVA_DECODE STREAMID */ +#define FW_DEVA_DECODE_STREAMID_TYPE unsigned char +#define FW_DEVA_DECODE_STREAMID_MASK (0xFF) +#define FW_DEVA_DECODE_STREAMID_OFFSET (0x001F) +#define FW_DEVA_DECODE_STREAMID_SHIFT (0) + +/* FW_DEVA_DECODE EXT_STATE_BUFFER */ +#define FW_DEVA_DECODE_EXT_STATE_BUFFER_TYPE unsigned int +#define FW_DEVA_DECODE_EXT_STATE_BUFFER_MASK (0xFFFFFFFF) +#define FW_DEVA_DECODE_EXT_STATE_BUFFER_OFFSET (0x0020) +#define FW_DEVA_DECODE_EXT_STATE_BUFFER_SHIFT (0) + +/* FW_DEVA_DECODE MSG_ID */ +#define FW_DEVA_DECODE_MSG_ID_TYPE unsigned short +#define FW_DEVA_DECODE_MSG_ID_MASK (0xFFFF) +#define FW_DEVA_DECODE_MSG_ID_OFFSET (0x0002) +#define FW_DEVA_DECODE_MSG_ID_SHIFT (0) + +/* FW_DEVA_DECODE TRANS_ID */ +#define FW_DEVA_DECODE_TRANS_ID_TYPE unsigned int +#define FW_DEVA_DECODE_TRANS_ID_MASK (0xFFFFFFFF) +#define FW_DEVA_DECODE_TRANS_ID_OFFSET (0x0008) +#define FW_DEVA_DECODE_TRANS_ID_SHIFT (0) + +/* FW_DEVA_DECODE TILE_CFG */ +#define FW_DEVA_DECODE_TILE_CFG_TYPE unsigned int +#define FW_DEVA_DECODE_TILE_CFG_MASK (0xFFFFFFFF) +#define FW_DEVA_DECODE_TILE_CFG_OFFSET (0x0024) +#define FW_DEVA_DECODE_TILE_CFG_SHIFT (0) + +/* FW_DEVA_GENMSG MSG_SIZE */ +#define FW_DEVA_GENMSG_MSG_SIZE_TYPE unsigned char +#define FW_DEVA_GENMSG_MSG_SIZE_MASK (0x7F) +#define FW_DEVA_GENMSG_MSG_SIZE_OFFSET (0x0000) +#define FW_DEVA_GENMSG_MSG_SIZE_SHIFT (0) + +/* FW_DEVA_DECODE_FRAGMENT CTRL_ALLOC_ADDR */ +#define FW_DEVA_DECODE_FRAGMENT_CTRL_ALLOC_ADDR_TYPE unsigned int +#define FW_DEVA_DECODE_FRAGMENT_CTRL_ALLOC_ADDR_MASK (0xFFFFFFFF) +#define FW_DEVA_DECODE_FRAGMENT_CTRL_ALLOC_ADDR_OFFSET (0x000C) +#define FW_DEVA_DECODE_FRAGMENT_CTRL_ALLOC_ADDR_SHIFT (0) + +/* FW_DEVA_DECODE_FRAGMENT BUFFER_SIZE */ +#define FW_DEVA_DECODE_FRAGMENT_BUFFER_SIZE_TYPE unsigned short +#define FW_DEVA_DECODE_FRAGMENT_BUFFER_SIZE_MASK (0xFFFF) +#define FW_DEVA_DECODE_FRAGMENT_BUFFER_SIZE_OFFSET (0x000A) +#define FW_DEVA_DECODE_FRAGMENT_BUFFER_SIZE_SHIFT (0) + +#endif /* _IMG_VDEC_FW_MSG_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/img_video_bus4_mmu_regs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/img_video_bus4_mmu_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/img_video_bus4_mmu_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/img_video_bus4_mmu_regs.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG video bus4 mmu registers + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef _IMG_VIDEO_BUS4_MMU_REGS_H +#define _IMG_VIDEO_BUS4_MMU_REGS_H + +#define IMG_VIDEO_BUS4_MMU_MMU_DIR_BASE_ADDR_OFFSET (0x0020) + +/* IMG_VIDEO_BUS4_MMU, MMU_ADDRESS_CONTROL, MMU_BYPASS */ +#define IMG_VIDEO_BUS4_MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_MASK (0x00000001) +#define IMG_VIDEO_BUS4_MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_SHIFT (0) + +/* IMG_VIDEO_BUS4_MMU, REQUEST_LIMITED_THROUGHPUT, REQUEST_GAP */ +#define IMG_VIDEO_BUS4_MMU_MMU_ADDRESS_CONTROL_OFFSET (0x0070) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, MMU_SOFT_RESET */ +#define IMG_VIDEO_BUS4_MMU_MMU_BANK_INDEX_OFFSET (0x0010) +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL1_MMU_SOFT_RESET_SHIFT (28) + +/* IMG_VIDEO_BUS4_MMU, MMU_TILE_MAX_ADDR, TILE_MAX_ADDR */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL0_OFFSET (0x0000) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONTROL0, MMU_TILING_SCHEME */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL0_MMU_TILING_SCHEME_MASK (0x00000001) +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL0_MMU_TILING_SCHEME_SHIFT (0) + +/* IMG_VIDEO_BUS4_MMU, MMU_TILE_CFG, TILE_STRIDE */ +#define IMG_VIDEO_BUS4_MMU_MMU_TILE_MIN_ADDR_STRIDE (4) +#define IMG_VIDEO_BUS4_MMU_MMU_TILE_MIN_ADDR_OFFSET (0x0050) + +/* IMG_VIDEO_BUS4_MMU, MMU_TILE_MIN_ADDR, TILE_MIN_ADDR */ +#define IMG_VIDEO_BUS4_MMU_MMU_TILE_MAX_ADDR_OFFSET (0x0060) +#define IMG_VIDEO_BUS4_MMU_MMU_TILE_MAX_ADDR_STRIDE (4) + +/* IMG_VIDEO_BUS4_MMU, MMU_STATUS1, MMU_FAULT_RNW */ +#define IMG_VIDEO_BUS4_MMU_MMU_MEM_REQ_OFFSET (0x0090) +#define IMG_VIDEO_BUS4_MMU_MMU_STATUS1_MMU_FAULT_RNW_MASK (0x10000000) +#define IMG_VIDEO_BUS4_MMU_MMU_STATUS1_MMU_FAULT_RNW_SHIFT (28) + +/* IMG_VIDEO_BUS4_MMU, MMU_MEM_REQ, TAG_OUTSTANDING */ +#define IMG_VIDEO_BUS4_MMU_MMU_MEM_REQ_TAG_OUTSTANDING_MASK (0x000003FF) +#define IMG_VIDEO_BUS4_MMU_MMU_MEM_REQ_TAG_OUTSTANDING_SHIFT (0) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONTROL0, USE_TILE_STRIDE_PER_CONTEXT */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL1_OFFSET (0x0008) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, MMU_SOFT_RESET */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL1_MMU_SOFT_RESET_MASK (0x10000000) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, MMU_PAUSE_SET */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL1_MMU_PAUSE_SET_MASK (0x01000000) +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL1_MMU_PAUSE_SET_SHIFT (24) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, MMU_PAUSE_CLEAR */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL1_MMU_PAUSE_CLEAR_MASK (0x02000000) +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL1_MMU_PAUSE_CLEAR_SHIFT (25) + +/* IMG_VIDEO_BUS4_MMU, MMU_ADDRESS_CONTROL, UPPER_ADDRESS_FIXED */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONFIG0_OFFSET (0x0080) + +/* IMG_VIDEO_BUS4_MMU, MMU_MEM_REQ, INT_PROTOCOL_FAULT */ +#define IMG_VIDEO_BUS4_MMU_MMU_MEM_EXT_OUTSTANDING_OFFSET (0x0094) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONFIG0, TAGS_SUPPORTED */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONFIG1_OFFSET (0x0084) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, MMU_INVALDC */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL1_MMU_INVALDC_MASK (0x00000F00) +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL1_MMU_INVALDC_SHIFT (8) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONFIG1, SUPPORT_SECURE */ +#define IMG_VIDEO_BUS4_MMU_MMU_STATUS0_OFFSET (0x0088) + +/* IMG_VIDEO_BUS4_MMU, MMU_STATUS0, MMU_FAULT_ADDR */ +#define IMG_VIDEO_BUS4_MMU_MMU_STATUS1_OFFSET (0x008C) +#define IMG_VIDEO_BUS4_MMU_MMU_STATUS0_MMU_FAULT_ADDR_SHIFT (12) + +/* IMG_VIDEO_BUS4_MMU, MMU_STATUS0, MMU_FAULT_ADDR */ +#define IMG_VIDEO_BUS4_MMU_MMU_STATUS0_MMU_FAULT_ADDR_MASK (0xFFFFF000) + +/* IMG_VIDEO_BUS4_MMU, MMU_STATUS0, MMU_PF_N_RW */ +#define IMG_VIDEO_BUS4_MMU_MMU_STATUS0_MMU_PF_N_RW_MASK (0x00000001) +#define IMG_VIDEO_BUS4_MMU_MMU_STATUS0_MMU_PF_N_RW_SHIFT (0) + +/* IMG_VIDEO_BUS4_MMU, MMU_STATUS1, MMU_FAULT_REQ_ID */ +#define IMG_VIDEO_BUS4_MMU_MMU_STATUS1_MMU_FAULT_REQ_ID_MASK (0x003F0000) +#define IMG_VIDEO_BUS4_MMU_MMU_STATUS1_MMU_FAULT_REQ_ID_SHIFT (16) + +/* IMG_VIDEO_BUS4_MMU, MMU_STATUS0, MMU_SECURE_FAULT */ +#define IMG_VIDEO_BUS4_MMU_MMU_STATUS0_MMU_SECURE_FAULT_MASK (0x00000002) +#define IMG_VIDEO_BUS4_MMU_MMU_STATUS0_MMU_SECURE_FAULT_SHIFT (1) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONFIG1, SUPPORT_STRIDE_PER_CONTEXT */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONFIG1_SUPPORT_STRIDE_PER_CONTEXT_MASK (0x20000000) +#define IMG_VIDEO_BUS4_MMU_MMU_CONFIG1_SUPPORT_STRIDE_PER_CONTEXT_SHIFT (29) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONFIG1, SUPPORT_SECURE */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONFIG1_SUPPORT_SECURE_MASK (0x80000000) +#define IMG_VIDEO_BUS4_MMU_MMU_CONFIG1_SUPPORT_SECURE_SHIFT (31) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONFIG0, EXTENDED_ADDR_RANGE */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONFIG0_EXTENDED_ADDR_RANGE_MASK (0x000000F0) +#define IMG_VIDEO_BUS4_MMU_MMU_CONFIG0_EXTENDED_ADDR_RANGE_SHIFT (4) + +/* IMG_VIDEO_BUS4_MMU, MMU_CONFIG0, GROUP_OVERRIDE_SIZE */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONFIG0_GROUP_OVERRIDE_SIZE_MASK (0x00000700) +#define IMG_VIDEO_BUS4_MMU_MMU_CONFIG0_GROUP_OVERRIDE_SIZE_SHIFT (8) + +#endif /* _IMG_VIDEO_BUS4_MMU_REGS_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/jpegfw_data.h b/drivers/media/platform/imagination/vxe-vxd/decoder/jpegfw_data.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/jpegfw_data.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/jpegfw_data.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Public data structures for the h264 parser firmware module. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#include "jpegfw_data_shared.h" + +#ifndef _JPEGFW_DATA_H_ +#define _JPEGFW_DATA_H_ + +#define JPEG_VDEC_8x8_DCT_SIZE 64 //!< Number of elements in 8x8 DCT +#define JPEG_VDEC_MAX_COMPONENTS 4 //!< Maximum number of component in JPEG +#define JPEG_VDEC_MAX_SETS_HUFFMAN_TABLES 2 //!< Maximum set of huffman table in JPEG +#define JPEG_VDEC_MAX_QUANT_TABLES 4 //!< Maximum set of quantisation table in JPEG +#define JPEG_VDEC_TABLE_CLASS_NUM 2 //!< Maximum set of class of huffman table in JPEG +#define JPEG_VDEC_PLANE_MAX 4 //!< Maximum number of planes + +struct hentry { + unsigned short code; + unsigned char codelen; + unsigned char value; +}; + +/** + * struct vdec_jpeg_huffman_tableinfo - This structure contains JPEG huffmant table + * @bits: number of bits + * @values: codeword value + * + * NOTE: Should only contain JPEG specific information. + * JPEG Huffman Table Information + */ +struct vdec_jpeg_huffman_tableinfo { + /* number of bits */ + unsigned char bits[16]; + /* codeword value */ + unsigned char values[256]; +}; + +/* + * This structure contains JPEG DeQunatisation table + * NOTE: Should only contain JPEG specific information. + * @brief JPEG Dequantisation Table Information + */ +struct vdec_jpeg_de_quant_tableinfo { + /* Qunatisation precision */ + unsigned char precision; + /* Qunatisation Value for 8x8 DCT */ + unsigned short elements[64]; +}; + +/* + * This describes the JPEG parser component "Header data", shown in the + * Firmware Memory Layout diagram. This data is required by the JPEG firmware + * and should be supplied by the Host. + */ +struct jpegfw_header_data { + /* Primary decode buffer base addresses */ + struct vdecfw_image_buffer primary; + /* Reference (output) picture base addresses */ + unsigned int plane_offsets[JPEG_VDEC_PLANE_MAX]; + /* SOS fields count value */ + unsigned char hdr_sos_count; +}; + +/* + * This describes the JPEG parser component "Context data". + * JPEG does not need any data to be saved between pictures, this structure + * is needed only to fit in firmware framework. + */ +struct jpegfw_context_data { + unsigned int dummy; +}; + +#endif /* _JPEGFW_DATA_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/jpegfw_data_shared.h b/drivers/media/platform/imagination/vxe-vxd/decoder/jpegfw_data_shared.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/jpegfw_data_shared.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/jpegfw_data_shared.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Public data structures for the hevc parser firmware module + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + */ +#ifdef USE_SHARING +#endif + +#ifndef _JPEGFW_DATA_H_ +#define _JPEGFW_DATA_H_ + +#include "vdecfw_share.h" +#include "vdecfw_shared.h" + +#define JPEG_VDEC_8x8_DCT_SIZE 64 //!< Number of elements in 8x8 DCT +#define JPEG_VDEC_MAX_COMPONENTS 4 //!< Maximum number of component in JPEG +#define JPEG_VDEC_MAX_SETS_HUFFMAN_TABLES 2 //!< Maximum set of huffman table in JPEG +#define JPEG_VDEC_MAX_QUANT_TABLES 4 //!< Maximum set of quantisation table in JPEG +#define JPEG_VDEC_TABLE_CLASS_NUM 2 //!< Maximum set of class of huffman table in JPEG +#define JPEG_VDEC_PLANE_MAX 4 //!< Maximum number of planes + +struct hentry { + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned short, code); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, codelen); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, value); +}; + +/* + * This structure contains JPEG huffmant table + * NOTE: Should only contain JPEG specific information. + * @brief JPEG Huffman Table Information + */ +struct vdec_jpeg_huffman_tableinfo { + /* number of bits */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, bits[16]); + /* codeword value */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, values[256]); +}; + +/* + * This structure contains JPEG DeQunatisation table + * NOTE: Should only contain JPEG specific information. + * @brief JPEG Dequantisation Table Information + */ +struct vdec_jpeg_de_quant_tableinfo { + /* Qunatisation precision */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, precision); + /* Qunatisation Value for 8x8 DCT */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned short, elements[64]); +}; + +/* + * This describes the JPEG parser component "Header data", shown in the + * Firmware Memory Layout diagram. This data is required by the JPEG firmware + * and should be supplied by the Host. + */ +struct jpegfw_header_data { + /* Primary decode buffer base addresses */ + struct vdecfw_image_buffer primary; + /* Reference (output) picture base addresses */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, + plane_offsets[JPEG_VDEC_PLANE_MAX]); + /* SOS fields count value */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned char, hdr_sos_count); +}; + +/* + * This describes the JPEG parser component "Context data". + * JPEG does not need any data to be saved between pictures, this structure + * is needed only to fit in firmware framework. + */ +struct jpegfw_context_data { + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, dummy); +}; + +#endif /* _JPEGFW_DATA_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/jpeg_secure_parser.c b/drivers/media/platform/imagination/vxe-vxd/decoder/jpeg_secure_parser.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/jpeg_secure_parser.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/jpeg_secure_parser.c 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,645 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * h.264 secure data unit parsing API. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#include +#include +#include +#include + +#include "bspp_int.h" +#include "jpeg_secure_parser.h" +#include "jpegfw_data.h" +#include "swsr.h" + +#define JPEG_MCU_SIZE 8 + +#define JPEG_MAX_COMPONENTS 4 +#define MAX_SETS_HUFFMAN_TABLES 2 +#define MAX_QUANT_TABLES 4 + +#define TABLE_CLASS_DC 0 +#define TABLE_CLASS_AC 1 +#define TABLE_CLASS_NUM 2 + +/* Marker Codes */ +#define CODE_SOF_BASELINE 0xC0 +#define CODE_SOF1 0xC1 +#define CODE_SOF2 0xC2 +#define CODE_SOF3 0xC3 +#define CODE_SOF5 0xC5 +#define CODE_SOF6 0xC6 +#define CODE_SOF7 0xC7 +#define CODE_SOF8 0xC8 +#define CODE_SOF9 0xC9 +#define CODE_SOF10 0xCA +#define CODE_SOF11 0xCB +#define CODE_SOF13 0xCD +#define CODE_SOF14 0xCE +#define CODE_SOF15 0xCF +#define CODE_DHT 0xC4 +#define CODE_RST0 0xD0 +#define CODE_RST1 0xD1 +#define CODE_RST2 0xD2 +#define CODE_RST3 0xD3 +#define CODE_RST4 0xD4 +#define CODE_RST5 0xD5 +#define CODE_RST6 0xD6 +#define CODE_RST7 0xD7 +#define CODE_SOI 0xD8 +#define CODE_EOI 0xD9 +#define CODE_SOS 0xDA +#define CODE_DQT 0xDB +#define CODE_DRI 0xDD +#define CODE_APP0 0xE0 +#define CODE_APP1 0xE1 +#define CODE_APP2 0xE2 +#define CODE_APP3 0xE3 +#define CODE_APP4 0xE4 +#define CODE_APP5 0xE5 +#define CODE_APP6 0xE6 +#define CODE_APP7 0xE7 +#define CODE_APP8 0xE8 +#define CODE_APP9 0xE9 +#define CODE_APP10 0xEA +#define CODE_APP11 0xEB +#define CODE_APP12 0xEC +#define CODE_APP13 0xED +#define CODE_APP14 0xEE +#define CODE_APP15 0xEF +#define CODE_M_DAC 0xCC +#define CODE_COMMENT 0xFE + +enum bspp_exception_handler { + /* BSPP parse exception handler */ + BSPP_EXCEPTION_HANDLER_NONE = 0x00, + /* Jump at exception (external use) */ + BSPP_EXCEPTION_HANDLER_JUMP, + BSPP_EXCEPTION_HANDLER_FORCE32BITS = 0x7FFFFFFFU +}; + +struct components { + unsigned char identifier; + unsigned char horz_factor; + unsigned char vert_factor; + unsigned char quant_table; +}; + +struct jpeg_segment_sof { + unsigned char precision; + unsigned short height; + unsigned short width; + unsigned char component; + struct components components[JPEG_VDEC_MAX_COMPONENTS]; +}; + +struct jpeg_segment_header { + unsigned char type; + unsigned short payload_size; +}; + +/* + * Read bitstream data that may LOOK like SCP + * (but in fact is regular data and should be read as such) + * @return 8bits read from the bitstream + */ +static unsigned char bspp_jpeg_readbyte_asdata(void *swsr_ctx) +{ + if (swsr_check_delim_or_eod(swsr_ctx) == SWSR_FOUND_DELIM) { + swsr_consume_delim(swsr_ctx, SWSR_EMPREVENT_NONE, 8, NULL); + return 0xFF; + } else { + return swsr_read_bits(swsr_ctx, 8); + } +} + +/* + * Read bitstream data that may LOOK like SCP + * (but in fact be regular data should be read as such) + * @return 16bits read from the bitstream + */ +static unsigned short bspp_jpeg_readword_asdata(void *swsr_ctx) +{ + unsigned short byte1 = bspp_jpeg_readbyte_asdata(swsr_ctx); + unsigned short byte2 = bspp_jpeg_readbyte_asdata(swsr_ctx); + + return (byte1 << 8 | byte2); +} + +/* + * Access regular bitstream data that may LOOK like SCP + * (but in fact be regular data) + */ +static void bspp_jpeg_consume_asdata(void *swsr_ctx, int len) +{ + while (len > 0) { + bspp_jpeg_readbyte_asdata(swsr_ctx); + len--; + } +} + +/* + * Parse SOF segment + */ +static enum bspp_error_type bspp_jpeg_segment_parse_sof(void *swsr_ctx, + struct jpeg_segment_sof *sof_header) +{ + unsigned char comp_ind; + + sof_header->precision = swsr_read_bits(swsr_ctx, 8); + if (sof_header->precision != 8) { + pr_warn("Sample precision has invalid value %d\n", + sof_header->precision); + return BSPP_ERROR_INVALID_VALUE; + } + + sof_header->height = bspp_jpeg_readword_asdata(swsr_ctx); + sof_header->width = bspp_jpeg_readword_asdata(swsr_ctx); + if (sof_header->height < JPEG_MCU_SIZE || sof_header->width < JPEG_MCU_SIZE) { + pr_warn("Sample X/Y smaller than macroblock\n"); + return BSPP_ERROR_INVALID_VALUE; + } + sof_header->component = swsr_read_bits(swsr_ctx, 8); + if (sof_header->component > JPEG_MAX_COMPONENTS) { + pr_warn("Number of components (%d) is greater than max allowed\n", + sof_header->component); + return BSPP_ERROR_INVALID_VALUE; + } + /* parse the component */ + for (comp_ind = 0; comp_ind < sof_header->component; comp_ind++) { + sof_header->components[comp_ind].identifier = swsr_read_bits(swsr_ctx, 8); + sof_header->components[comp_ind].horz_factor = swsr_read_bits(swsr_ctx, 4); + sof_header->components[comp_ind].vert_factor = swsr_read_bits(swsr_ctx, 4); + sof_header->components[comp_ind].quant_table = swsr_read_bits(swsr_ctx, 8); + + pr_debug("components[%d]=(identifier=%d; horz_factor=%d; vert_factor=%d; quant_table=%d)", + comp_ind, + sof_header->components[comp_ind].identifier, + sof_header->components[comp_ind].horz_factor, + sof_header->components[comp_ind].vert_factor, + sof_header->components[comp_ind].quant_table); + } + + return BSPP_ERROR_NONE; +} + +/* + * Seeks to delimeter if we're not already on one + */ +static enum swsr_found bspp_jpeg_tryseek_delimeter(void *swsr_ctx) +{ + enum swsr_found was_delim_or_eod = swsr_check_delim_or_eod(swsr_ctx); + + if (was_delim_or_eod != SWSR_FOUND_DELIM) + was_delim_or_eod = swsr_seek_delim_or_eod(swsr_ctx); + + return was_delim_or_eod; +} + +static enum swsr_found bspp_jpeg_tryconsume_delimeters(void *swsr_ctx) +{ + enum swsr_found is_delim_or_eod = swsr_check_delim_or_eod(swsr_ctx); + + while (is_delim_or_eod == SWSR_FOUND_DELIM) { + swsr_consume_delim(swsr_ctx, SWSR_EMPREVENT_NONE, 8, NULL); + is_delim_or_eod = swsr_check_delim_or_eod(swsr_ctx); + } + return is_delim_or_eod; +} + +static enum swsr_found bspp_jpeg_tryseek_and_consume_delimeters(void *swsr_ctx) +{ + enum swsr_found is_delim_or_eod; + + bspp_jpeg_tryseek_delimeter(swsr_ctx); + is_delim_or_eod = bspp_jpeg_tryconsume_delimeters(swsr_ctx); + return is_delim_or_eod; +} + +/* + * Read segment type and size + * @return IMG_TRUE when header is found, + * IMG_FALSE if it has to be called again + */ +static unsigned char bspp_jpeg_segment_read_header(void *swsr_ctx, + struct bspp_unit_data *unit_data, + struct jpeg_segment_header *jpeg_segment_header) +{ + bspp_jpeg_tryconsume_delimeters(swsr_ctx); + jpeg_segment_header->type = swsr_read_bits(swsr_ctx, 8); + + if (jpeg_segment_header->type != 0) + pr_debug("NAL=0x%x\n", jpeg_segment_header->type); + + jpeg_segment_header->payload_size = 0; + + switch (jpeg_segment_header->type) { + case CODE_SOS: + case CODE_DRI: + case CODE_SOF_BASELINE: + case CODE_SOF1: + case CODE_SOF2: + case CODE_SOF3: + case CODE_SOF5: + case CODE_SOF6: + case CODE_SOF7: + case CODE_SOF8: + case CODE_SOF9: + case CODE_SOF10: + case CODE_SOF11: + case CODE_SOF13: + case CODE_SOF14: + case CODE_SOF15: + case CODE_APP0: + case CODE_APP1: + case CODE_APP2: + case CODE_APP3: + case CODE_APP4: + case CODE_APP5: + case CODE_APP6: + case CODE_APP7: + case CODE_APP8: + case CODE_APP9: + case CODE_APP10: + case CODE_APP11: + case CODE_APP12: + case CODE_APP13: + case CODE_APP14: + case CODE_APP15: + case CODE_DHT: + case CODE_DQT: + case CODE_COMMENT: + { + jpeg_segment_header->payload_size = + bspp_jpeg_readword_asdata(swsr_ctx) - 2; + } + break; + case CODE_EOI: + case CODE_SOI: + case CODE_RST0: + case CODE_RST1: + case CODE_RST2: + case CODE_RST3: + case CODE_RST4: + case CODE_RST5: + case CODE_RST6: + case CODE_RST7: + /* + * jpeg_segment_header->payload_size reset to 0 previously, + * so just break. + */ + break; + case 0: + { + /* + * Emulation prevention is OFF which means that 0 after + * 0xff will not be swallowed + * and has to be treated as data + */ + bspp_jpeg_tryseek_and_consume_delimeters(swsr_ctx); + return 0; + } + default: + { + pr_err("BAD NAL=%#x\n", jpeg_segment_header->type); + unit_data->parse_error |= BSPP_ERROR_UNRECOVERABLE; + } + } + + pr_debug("payloadSize=%#x\n", jpeg_segment_header->payload_size); + return 1; +} + +static void bspp_jpeg_calculate_mcus(struct jpeg_segment_sof *data_sof, + unsigned char *alignment_width, + unsigned char *alignment_height) +{ + unsigned char i; + unsigned char max_horz_factor = 0; + unsigned char max_vert_factor = 0; + unsigned short mcu_width = 0; + unsigned short mcu_height = 0; + + /* Determine maximum scale factors */ + for (i = 0; i < data_sof->component; i++) { + unsigned char horz_factor = data_sof->components[i].horz_factor; + unsigned char vert_factor = data_sof->components[i].vert_factor; + + max_horz_factor = horz_factor > max_horz_factor ? horz_factor : max_horz_factor; + max_vert_factor = vert_factor > max_vert_factor ? vert_factor : max_vert_factor; + } + /* + * Alignment we want to have must be: + * - mutliple of VDEC_MB_DIMENSION + * - at least of the size that will fit whole MCUs + */ + *alignment_width = + VDEC_ALIGN_SIZE((8 * max_horz_factor), VDEC_MB_DIMENSION, + unsigned int, unsigned int); + *alignment_height = + VDEC_ALIGN_SIZE((8 * max_vert_factor), VDEC_MB_DIMENSION, + unsigned int, unsigned int); + + /* Calculate dimensions in MCUs */ + mcu_width += (data_sof->width + (8 * max_horz_factor) - 1) / (8 * max_horz_factor); + mcu_height += (data_sof->height + (8 * max_vert_factor) - 1) / (8 * max_vert_factor); + +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s; w=%d; w[MCU]=%d\n", __func__, data_sof->width, mcu_width); + pr_info("%s; h=%d; h[MCU]=%d\n", __func__, data_sof->height, mcu_height); +#endif +} + +static int bspp_jpeg_common_seq_hdr_populate(struct jpeg_segment_sof *sof_header, + struct vdec_comsequ_hdrinfo *com_sequ_hdr_info, + unsigned char alignment_width, + unsigned char alignment_height) +{ + unsigned short i; + int res; + struct img_pixfmt_desc format_desc; + + memset(&format_desc, 0, sizeof(struct img_pixfmt_desc)); + memset(com_sequ_hdr_info, 0, sizeof(*com_sequ_hdr_info)); + + com_sequ_hdr_info->max_frame_size.width = VDEC_ALIGN_SIZE(sof_header->width, + alignment_width, + unsigned int, unsigned int); + com_sequ_hdr_info->max_frame_size.height = VDEC_ALIGN_SIZE(sof_header->height, + alignment_height, unsigned int, + unsigned int); + com_sequ_hdr_info->frame_size.width = sof_header->width; + com_sequ_hdr_info->frame_size.height = sof_header->height; + com_sequ_hdr_info->orig_display_region.width = sof_header->width; + com_sequ_hdr_info->orig_display_region.height = sof_header->height; + + com_sequ_hdr_info->pixel_info.bitdepth_y = 8; + com_sequ_hdr_info->pixel_info.bitdepth_c = 8; + com_sequ_hdr_info->pixel_info.num_planes = sof_header->component; + /* actually we have to set foramt accroding to the following table + * H1 V1 H2 V2 H3 V3 J:a:b h/v + * 1 1 1 1 1 1 4:4:4 1/1 + * 1 2 1 1 1 1 4:4:0 1/2 + * 1 4 1 1 1 1 4:4:1* 1/4 + * 1 4 1 2 1 2 4:4:0 1/2 + * 2 1 1 1 1 1 4:2:2 2/1 + * 2 2 1 1 1 1 4:2:0 2/2 + * 2 2 2 1 2 1 4:4:0 1/2 + * 2 4 1 1 1 1 4:2:1* 2/4 + * 4 1 1 1 1 1 4:1:1 4/1 + * 4 1 2 1 2 1 4:2:2 2/1 + * 4 2 1 1 1 1 4:1:0 4/2 + * 4 4 2 2 2 2 4:2:0 2/2 + */ + if (sof_header->component == (JPEG_MAX_COMPONENTS - 1)) { + com_sequ_hdr_info->pixel_info.chroma_fmt = PIXEL_MULTICHROME; + if ((sof_header->components[1].horz_factor == 1 && + sof_header->components[1].vert_factor == 1) && + (sof_header->components[2].horz_factor == 1 && + sof_header->components[2].vert_factor == 1)) { + if (sof_header->components[0].horz_factor == 1 && + sof_header->components[0].vert_factor == 1) { + com_sequ_hdr_info->pixel_info.chroma_fmt_idc = PIXEL_FORMAT_444; + } else if (sof_header->components[0].horz_factor == 2) { + if (sof_header->components[0].vert_factor == 1) { + com_sequ_hdr_info->pixel_info.chroma_fmt_idc = + PIXEL_FORMAT_422; + } else if (sof_header->components[0].vert_factor == 2) { + com_sequ_hdr_info->pixel_info.chroma_fmt_idc = + PIXEL_FORMAT_420; + } else { + com_sequ_hdr_info->pixel_info.chroma_fmt_idc = + PIXEL_FORMAT_444; + } + } else if ((sof_header->components[0].horz_factor == 4) && + (sof_header->components[0].vert_factor == 1)) { + com_sequ_hdr_info->pixel_info.chroma_fmt_idc = PIXEL_FORMAT_411; + } else { + com_sequ_hdr_info->pixel_info.chroma_fmt_idc = PIXEL_FORMAT_444; + } + } else { + com_sequ_hdr_info->pixel_info.chroma_fmt_idc = PIXEL_FORMAT_444; + } + } else { + com_sequ_hdr_info->pixel_info.chroma_fmt = PIXEL_MONOCHROME; + com_sequ_hdr_info->pixel_info.chroma_fmt_idc = PIXEL_FORMAT_MONO; + } + + for (i = 0; (i < sof_header->component) && (i < IMG_MAX_NUM_PLANES); i++) { + format_desc.planes[i] = 1; + format_desc.h_numer[i] = sof_header->components[i].horz_factor; + format_desc.v_numer[i] = sof_header->components[i].vert_factor; + } + + res = pixel_gen_pixfmt(&com_sequ_hdr_info->pixel_info.pixfmt, &format_desc); + if (res != 0) { + pr_err("Failed to generate pixel format.\n"); + return res; + } + + return 0; +} + +static void bspp_jpeg_pict_hdr_populate(struct jpeg_segment_sof *sof_header, + struct bspp_pict_hdr_info *pict_hdr_info) +{ + memset(pict_hdr_info, 0, sizeof(*pict_hdr_info)); + + pict_hdr_info->intra_coded = 1; + pict_hdr_info->ref = 0; + + pict_hdr_info->coded_frame_size.width = (unsigned int)sof_header->width; + pict_hdr_info->coded_frame_size.height = (unsigned int)sof_header->height; + pict_hdr_info->disp_info.enc_disp_region.width = (unsigned int)sof_header->width; + pict_hdr_info->disp_info.enc_disp_region.height = (unsigned int)sof_header->height; + + pict_hdr_info->pict_aux_data.id = BSPP_INVALID; + pict_hdr_info->second_pict_aux_data.id = BSPP_INVALID; + pict_hdr_info->pict_sgm_data.id = BSPP_INVALID; +} + +static int bspp_jpeg_parse_picture_unit(void *swsr_ctx, + struct bspp_unit_data *unit_data) +{ + /* assume we'll be fine */ + unit_data->parse_error = BSPP_ERROR_NONE; + + while ((unit_data->parse_error == BSPP_ERROR_NONE) && + !(unit_data->slice || unit_data->extracted_all_data)) { + struct jpeg_segment_header segment_header; + /* + * Try hard to read segment header. The only limit we set here is EOD- + * if it happens, we will get an exception, to stop this madness. + */ + while (!bspp_jpeg_segment_read_header(swsr_ctx, unit_data, &segment_header) && + unit_data->parse_error == BSPP_ERROR_NONE) + ; + + switch (segment_header.type) { + case CODE_SOF1: + case CODE_SOF2: + case CODE_SOF3: + case CODE_SOF5: + case CODE_SOF6: + case CODE_SOF8: + case CODE_SOF9: + case CODE_SOF10: + case CODE_SOF11: + case CODE_SOF13: + case CODE_SOF14: + case CODE_SOF15: + { + bspp_jpeg_consume_asdata(swsr_ctx, segment_header.payload_size); + bspp_jpeg_tryseek_delimeter(swsr_ctx); + unit_data->extracted_all_data = 1; + unit_data->slice = 1; + unit_data->parse_error |= BSPP_ERROR_UNSUPPORTED; + return IMG_ERROR_NOT_SUPPORTED; + } + case CODE_SOI: + { + /* + * Reinitialize context at the beginning of each image + */ + } + break; + case CODE_EOI: + { + /* + * Some more frames can be concatenated after SOI, + * but we'll discard it for now + */ + while (bspp_jpeg_tryseek_and_consume_delimeters(swsr_ctx) != SWSR_FOUND_EOD) + ; + unit_data->extracted_all_data = 1; + return 0; + } + case CODE_SOF_BASELINE: + { + int res; + unsigned char alignment_width = 0; + unsigned char alignment_height = 0; + struct jpeg_segment_sof sof_data; + + struct bspp_sequ_hdr_info *sequ_hdr_info = + &unit_data->impl_sequ_hdr_info->sequ_hdr_info; + + memset(&sof_data, 0, sizeof(*&sof_data)); + + /* SOF is the only segment we are interested in- parse it */ + unit_data->parse_error |= bspp_jpeg_segment_parse_sof(swsr_ctx, &sof_data); + /* + * to correctly allocate size for frame we need to have correct MCUs to + * get alignment info + */ + bspp_jpeg_calculate_mcus(&sof_data, &alignment_width, &alignment_height); + + /* fill in headers expected by BSPP framework */ + res = bspp_jpeg_common_seq_hdr_populate(&sof_data, + &sequ_hdr_info->com_sequ_hdr_info, + alignment_width, + alignment_height); + if (res != 0) { + unit_data->parse_error |= BSPP_ERROR_UNRECOVERABLE; + return res; + } + + bspp_jpeg_pict_hdr_populate(&sof_data, unit_data->out.pict_hdr_info); + + /* fill in sequence IDs for header and picture */ + sequ_hdr_info->sequ_hdr_id = BSPP_DEFAULT_SEQUENCE_ID; + unit_data->pict_sequ_hdr_id = BSPP_DEFAULT_SEQUENCE_ID; + + /* reset SOS fields counter value */ + unit_data->out.pict_hdr_info->sos_count = 0; + } + break; + case CODE_SOS: + { + /* increment the SOS fields counter */ + unit_data->out.pict_hdr_info->sos_count++; + + unit_data->slice = 1; + bspp_jpeg_consume_asdata(swsr_ctx, segment_header.payload_size); + return 0; + } + case CODE_DRI: + break; + default: + { +#ifdef DEBUG_DECODER_DRIVER + pr_info("Skipping over 0x%x bytes\n", segment_header.payload_size); +#endif + bspp_jpeg_consume_asdata(swsr_ctx, segment_header.payload_size); + } + break; + } + /* + * After parsing segment we should already be on delimeter. + * Consume it, so header parsing can be started. + */ + bspp_jpeg_tryseek_and_consume_delimeters(swsr_ctx); + } + return 0; +} + +int bspp_jpeg_unit_parser(void *swsr_ctx, struct bspp_unit_data *unit_data) +{ + int retval = 0; + + switch (unit_data->unit_type) { + case BSPP_UNIT_PICTURE: + { + retval = bspp_jpeg_parse_picture_unit(swsr_ctx, unit_data); + unit_data->new_closed_gop = 1; + } + break; + default: + { + unit_data->parse_error = BSPP_ERROR_INVALID_VALUE; + } + break; + } + + return retval; +} + +int bspp_jpeg_setparser_config(enum vdec_bstr_format bstr_format, + struct bspp_vid_std_features *pvidstd_features, + struct bspp_swsr_ctx *pswsr_ctx, + struct bspp_parser_callbacks *pparser_callbacks, + struct bspp_inter_pict_data *pinterpict_data) +{ + /* Set JPEG parser callbacks. */ + pparser_callbacks->parse_unit_cb = bspp_jpeg_unit_parser; + + /* Set JPEG specific features. */ + pvidstd_features->seq_size = sizeof(struct bspp_jpeg_sequ_hdr_info); + pvidstd_features->uses_vps = 0; + pvidstd_features->uses_pps = 0; + + /* Set JPEG specific shift register config. */ + pswsr_ctx->emulation_prevention = SWSR_EMPREVENT_NONE; + pswsr_ctx->sr_config.delim_type = SWSR_DELIM_SCP; + pswsr_ctx->sr_config.delim_length = 8; + pswsr_ctx->sr_config.scp_value = 0xFF; + + return 0; +} + +void bspp_jpeg_determine_unit_type(unsigned char bitstream_unittype, + int disable_mvc, + enum bspp_unit_type *bspp_unittype) +{ + *bspp_unittype = BSPP_UNIT_PICTURE; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/jpeg_secure_parser.h b/drivers/media/platform/imagination/vxe-vxd/decoder/jpeg_secure_parser.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/jpeg_secure_parser.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/jpeg_secure_parser.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * JPEG secure data unit parsing API. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ +#ifndef __JPEGSECUREPARSER_H__ +#define __JPEGSECUREPARSER_H__ + +#include "bspp_int.h" + +/** + * struct bspp_jpeg_sequ_hdr_info - bspp_jpeg_sequ_hdr_info dummu structure + * @dummy: dummy structure + */ +struct bspp_jpeg_sequ_hdr_info { + unsigned int dummy; +}; + +int bspp_jpeg_setparser_config(enum vdec_bstr_format bstr_format, + struct bspp_vid_std_features *pvidstd_features, + struct bspp_swsr_ctx *pswsr_ctx, + struct bspp_parser_callbacks *pparser_callbacks, + struct bspp_inter_pict_data *pinterpict_data); + +void bspp_jpeg_determine_unit_type(unsigned char bitstream_unittype, + int disable_mvc, + enum bspp_unit_type *bspp_unittype); + +#endif /*__JPEGSECUREPARSER_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/mem_io.h b/drivers/media/platform/imagination/vxe-vxd/decoder/mem_io.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/mem_io.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/mem_io.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG PVDEC pixel Registers + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef _MEM_IO_H +#define _MEM_IO_H + +#include + +#include "reg_io2.h" + +#define MEMIO_CHECK_ALIGNMENT(vpmem) \ + IMG_ASSERT((vpmem)) + +#define MEMIO_READ_FIELD(vpmem, field) \ + ((((*((field ## _TYPE *)(((unsigned long)(vpmem)) + field ## _OFFSET))) & \ + field ## _MASK) >> field ## _SHIFT)) + +#define MEMIO_WRITE_FIELD(vpmem, field, value, type) \ + do { \ + type __vpmem = vpmem; \ + MEMIO_CHECK_ALIGNMENT(__vpmem); \ + (*((field ## _TYPE *)(((unsigned long)(__vpmem)) + \ + field ## _OFFSET))) = \ + (field ## _TYPE)(((*((field ## _TYPE *)(((unsigned long)(__vpmem)) + \ + field ## _OFFSET))) & \ + ~(field ## _TYPE)field ## _MASK) | \ + (field ## _TYPE)(((value) << field ## _SHIFT) & \ + field ## _MASK)); \ + } while (0) \ + +#endif /* _MEM_IO_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/mmu_defs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/mmu_defs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/mmu_defs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/mmu_defs.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * V-DEC MMU Definitions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + */ + +#ifndef _VXD_MMU_DEF_H_ +#define _VXD_MMU_DEF_H_ + +/* + * This type defines MMU variant. + */ +enum mmu_etype { + MMU_TYPE_NONE = 0, + MMU_TYPE_32BIT, + MMU_TYPE_36BIT, + MMU_TYPE_40BIT, + MMU_TYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/** + * enum mmu_eheap_id - This type defines the MMU heaps. + * @MMU_HEAP_IMAGE_BUFFERS_UNTILED: Heap for untiled video buffers + * @MMU_HEAP_BITSTREAM_BUFFERS : Heap for bitstream buffers + * @MMU_HEAP_STREAM_BUFFERS : Heap for Stream buffers + * @MMU_HEAP_MAX : Number of heaps + * @MMU_HEAP_FORCE32BITS: MMU_HEAP_FORCE32BITS + */ +enum mmu_eheap_id { + MMU_HEAP_IMAGE_BUFFERS_UNTILED = 0x00, + MMU_HEAP_BITSTREAM_BUFFERS, + MMU_HEAP_STREAM_BUFFERS, + MMU_HEAP_MAX, + MMU_HEAP_FORCE32BITS = 0x7FFFFFFFU +}; + +#endif /* _VXD_MMU_DEFS_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/pixel_api.c b/drivers/media/platform/imagination/vxe-vxd/decoder/pixel_api.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/pixel_api.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/pixel_api.c 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,895 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Pixel processing function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + */ + +#include +#include +#include +#include + +#include "img_errors.h" +#include "img_pixfmts.h" +#include "pixel_api.h" +#include "vdec_defs.h" + +#define NUM_OF_FORMATS 17 +#define PIXNAME(x) /* Pixel name support not enabled */ +#define FACT_SPEC_FORMAT_NUM_PLANES 4 +#define FACT_SPEC_FORMAT_PLANE_UNUSED 0xf +#define FACT_SPEC_FORMAT_PLANE_CODE_BITS 4 +#define FACT_SPEC_FORMAT_PLANE_CODE_MASK 3 +#define FACT_SPEC_FORMAT_MIN_FACT_VAL 1 + +/* + * @brief Pointer to the default format in the asPixelFormats array + * default format is an invalid format + * @note pointer set by initSearch() + * This pointer is also used to know if the arrays were sorted + */ +static struct pixel_pixinfo *def_fmt; + +/* + * @brief Actual array storing the pixel formats information. + */ +static struct pixel_pixinfo pix_fmts[NUM_OF_FORMATS] = { + { + IMG_PIXFMT_420PL12YUV8, + PIXEL_UV_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT8_MP, + PIXEL_FORMAT_420, + 8, + 8, + 2 + }, + + { + IMG_PIXFMT_420PL12YVU8, + PIXEL_VU_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT8_MP, + PIXEL_FORMAT_420, + 8, + 8, + 2 + }, + + { + IMG_PIXFMT_420PL12YUV10, + PIXEL_UV_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT10_MP, + PIXEL_FORMAT_420, + 10, + 10, + 2 + }, + + { + IMG_PIXFMT_420PL12YVU10, + PIXEL_VU_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT10_MP, + PIXEL_FORMAT_420, + 10, + 10, + 2 + }, + + { + IMG_PIXFMT_420PL12YUV10_MSB, + PIXEL_UV_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT10_MSB_MP, + PIXEL_FORMAT_420, + 10, + 10, + 2 + }, + + { + IMG_PIXFMT_420PL12YVU10_MSB, + PIXEL_VU_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT10_MSB_MP, + PIXEL_FORMAT_420, + 10, + 10, + 2 + }, + + { + IMG_PIXFMT_420PL12YUV10_LSB, + PIXEL_UV_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT10_LSB_MP, + PIXEL_FORMAT_420, + 10, + 10, + 2 + }, + + { + IMG_PIXFMT_420PL12YVU10_LSB, + PIXEL_VU_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT10_LSB_MP, + PIXEL_FORMAT_420, + 10, + 10, + 2 + }, + + { + IMG_PIXFMT_422PL12YUV8, + PIXEL_UV_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT8_MP, + PIXEL_FORMAT_422, + 8, + 8, + 2 + }, + + { + IMG_PIXFMT_422PL12YVU8, + PIXEL_VU_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT8_MP, + PIXEL_FORMAT_422, + 8, + 8, + 2 + }, + + { + IMG_PIXFMT_422PL12YUV10, + PIXEL_UV_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT10_MP, + PIXEL_FORMAT_422, + 10, + 10, + 2 + }, + + { + IMG_PIXFMT_422PL12YVU10, + PIXEL_VU_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT10_MP, + PIXEL_FORMAT_422, + 10, + 10, + 2 + }, + + { + IMG_PIXFMT_422PL12YUV10_MSB, + PIXEL_UV_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT10_MSB_MP, + PIXEL_FORMAT_422, + 10, + 10, + 2 + }, + + { + IMG_PIXFMT_422PL12YVU10_MSB, + PIXEL_VU_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT10_MSB_MP, + PIXEL_FORMAT_422, + 10, + 10, + 2 + }, + + { + IMG_PIXFMT_422PL12YUV10_LSB, + PIXEL_UV_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT10_LSB_MP, + PIXEL_FORMAT_422, + 10, + 10, + 2 + }, + + { + IMG_PIXFMT_422PL12YVU10_LSB, + PIXEL_VU_ORDER, + PIXEL_MULTICHROME, + PIXEL_BIT10_LSB_MP, + PIXEL_FORMAT_422, + 10, + 10, + 2 + }, + + { + IMG_PIXFMT_UNDEFINED, + PIXEL_INVALID_CI, + 0, + (enum pixel_mem_packing)0, + PIXEL_FORMAT_INVALID, + 0, + 0, + 0 + } +}; + +static struct pixel_pixinfo_table pixinfo_table[] = { + { + IMG_PIXFMT_420PL12YUV8_A8, + { + PIXNAME(IMG_PIXFMT_420PL12YUV8_A8) + 16, + 16, + 16, + 0, + 16, + TRUE, + TRUE, + 4, + TRUE + } + }, + + { + IMG_PIXFMT_422PL12YUV8_A8, + { + PIXNAME(IMG_PIXFMT_422PL12YUV8_A8) + 16, + 16, + 16, + 0, + 16, + TRUE, + FALSE, + 4, + TRUE + } + }, + + { + IMG_PIXFMT_420PL12YUV8, + { + PIXNAME(IMG_PIXFMT_420PL12YUV8) + 16, + 16, + 16, + 0, + 0, + TRUE, + TRUE, + 4, + FALSE + } + }, + + { + IMG_PIXFMT_420PL12YVU8, + { + PIXNAME(IMG_PIXFMT_420PL12YVU8) + 16, + 16, + 16, + 0, + 0, + TRUE, + TRUE, + 4, + FALSE + } + }, + + { + IMG_PIXFMT_420PL12YUV10, + { + PIXNAME(IMG_PIXFMT_420PL12YUV10) + 12, + 16, + 16, + 0, + 0, + TRUE, + TRUE, + 4, + FALSE + } + }, + + { + IMG_PIXFMT_420PL12YVU10, + { + PIXNAME(IMG_PIXFMT_420PL12YVU10) + 12, + 16, + 16, + 0, + 0, + TRUE, + TRUE, + 4, + FALSE + } + }, + + { + IMG_PIXFMT_420PL12YUV10_MSB, + { + PIXNAME(IMG_PIXFMT_420PL12YUV10_MSB) + 8, + 16, + 16, + 0, + 0, + TRUE, + TRUE, + 4, + FALSE + } + }, + + { + IMG_PIXFMT_420PL12YVU10_MSB, + { + PIXNAME(IMG_PIXFMT_420PL12YVU10_MSB) + 8, + 16, + 16, + 0, + 0, + TRUE, + TRUE, + 4, + FALSE + } + }, + + { + IMG_PIXFMT_422PL12YUV8, + { + PIXNAME(IMG_PIXFMT_422PL12YUV8) + 16, + 16, + 16, + 0, + 0, + TRUE, + FALSE, + 4, + FALSE + } + }, + + { + IMG_PIXFMT_422PL12YVU8, + { + PIXNAME(IMG_PIXFMT_422PL12YVU8) + 16, + 16, + 16, + 0, + 0, + TRUE, + FALSE, + 4, + FALSE + } + }, + + { + IMG_PIXFMT_422PL12YUV10, + { + PIXNAME(IMG_PIXFMT_422PL12YUV10) + 12, + 16, + 16, + 0, + 0, + TRUE, + FALSE, + 4, + FALSE + } + }, + + { + IMG_PIXFMT_422PL12YVU10, + { + PIXNAME(IMG_PIXFMT_422PL12YVU10) + 12, + 16, + 16, + 0, + 0, + TRUE, + FALSE, + 4, + FALSE + } + }, + + { + IMG_PIXFMT_422PL12YUV10_MSB, + { + PIXNAME(IMG_PIXFMT_422PL12YUV10_MSB) + 8, + 16, + 16, + 0, + 0, + TRUE, + FALSE, + 4, + FALSE + } + }, + + { + IMG_PIXFMT_422PL12YVU10_MSB, + { + PIXNAME(IMG_PIXFMT_422PL12YVU10_MSB) + 8, + 16, + 16, + 0, + 0, + TRUE, + FALSE, + 4, + FALSE + } + }, +}; + +static struct pixel_pixinfo_table* +pixel_get_pixelinfo_from_pixfmt(enum img_pixfmt pix_fmt) +{ + unsigned int i; + unsigned char found = FALSE; + struct pixel_pixinfo_table *this_pixinfo_table_entry = NULL; + + for (i = 0; + i < (sizeof(pixinfo_table) / sizeof(struct pixel_pixinfo_table)); + i++) { + if (pix_fmt == pixinfo_table[i].pix_color_fmt) { + /* + * There must only be one entry per pixel colour format + * in the table + */ + VDEC_ASSERT(!found); + found = TRUE; + this_pixinfo_table_entry = &pixinfo_table[i]; + + /* + * We deliberately do NOT break here - scan rest of + * table to ensure there are not duplicate entries + */ + } + } + return this_pixinfo_table_entry; +} + +/* + * @brief Array containing string lookup of pixel format IDC. + * @warning this must be kept in step with PIXEL_FormatIdc. + */ +unsigned char pix_fmt_idc_names[6][16] = { + "Monochrome", + "4:1:1", + "4:2:0", + "4:2:2", + "4:4:4", + "Invalid", +}; + +static int pixel_compare_pixfmts(const void *a, const void *b) +{ + return ((struct pixel_pixinfo *)a)->pixfmt - + ((struct pixel_pixinfo *)b)->pixfmt; +} + +static struct pixel_info* +pixel_get_bufinfo_from_pixfmt(enum img_pixfmt pix_fmt) +{ + struct pixel_pixinfo_table *pixinfo_table_entry = NULL; + struct pixel_info *pix_info = NULL; + + pixinfo_table_entry = pixel_get_pixelinfo_from_pixfmt(pix_fmt); + VDEC_ASSERT(pixinfo_table_entry); + if (pixinfo_table_entry) + pix_info = &pixinfo_table_entry->info; + + return pix_info; +} + +/* + * @brief Search a pixel format based on its attributes rather than its format + * enum. + * @warning use PIXEL_Comparpix_fmts to search by enum + */ +static int pixel_compare_pixinfo(const void *a, const void *b) +{ + int result = 0; + const struct pixel_pixinfo *fmt_a = (struct pixel_pixinfo *)a; + const struct pixel_pixinfo *fmt_b = (struct pixel_pixinfo *)b; + + result = fmt_a->chroma_fmt_idc - fmt_b->chroma_fmt_idc; + if (result != 0) + return result; + + result = fmt_a->mem_pkg - fmt_b->mem_pkg; + if (result != 0) + return result; + + result = fmt_a->chroma_interleave - fmt_b->chroma_interleave; + if (result != 0) + return result; + + result = fmt_a->bitdepth_y - fmt_b->bitdepth_y; + if (result != 0) + return result; + + result = fmt_a->bitdepth_c - fmt_b->bitdepth_c; + if (result != 0) + return result; + + result = fmt_a->num_planes - fmt_b->num_planes; + if (result != 0) + return result; + + return result; +} + +static void pixel_init_search(void) +{ + static unsigned int search_inited; + + search_inited++; + if (search_inited == 1) { + if (!def_fmt) { + int i = 0; + + i = NUM_OF_FORMATS - 1; + while (i >= 0) { + if (IMG_PIXFMT_UNDEFINED == + pix_fmts[i].pixfmt) { + def_fmt = &pix_fmts[i]; + break; + } + } + VDEC_ASSERT(def_fmt); + } + } else { + search_inited--; + } +} + +static struct pixel_pixinfo *pixel_search_fmt(const struct pixel_pixinfo *key, + unsigned char enum_only) +{ + struct pixel_pixinfo *fmt_found = NULL; + int (*compar)(const void *pixfmt1, const void *pixfmt2); + + if (enum_only) + compar = &pixel_compare_pixfmts; + else + compar = &pixel_compare_pixinfo; + + { + unsigned int i; + + for (i = 0; i < NUM_OF_FORMATS; i++) { + if (compar(key, &pix_fmts[i]) == 0) { + fmt_found = &pix_fmts[i]; + break; + } + } + } + return fmt_found; +} + +/* + * @brief Set a pixel format info structure to the default. + * @warning This MODIDIFES the pointer therefore you shouldn't + * call it on pointer you got from the library! + */ +static void pixel_pixinfo_defaults(struct pixel_pixinfo *to_def) +{ + if (!def_fmt) + pixel_init_search(); + + memcpy(to_def, def_fmt, sizeof(struct pixel_pixinfo)); +} + +enum img_pixfmt pixel_get_pixfmt(enum pixel_fmt_idc chroma_fmt_idc, + enum pixel_chroma_interleaved + chroma_interleaved, + enum pixel_mem_packing mem_pkg, + unsigned int bitdepth_y, unsigned int bitdepth_c, + unsigned int num_planes) +{ + unsigned int internal_num_planes = (num_planes == 0 || num_planes > 4) ? 2 : + num_planes; + struct pixel_pixinfo key; + struct pixel_pixinfo *fmt_found = NULL; + + if (chroma_fmt_idc != PIXEL_FORMAT_MONO && + chroma_fmt_idc != PIXEL_FORMAT_411 && + chroma_fmt_idc != PIXEL_FORMAT_420 && + chroma_fmt_idc != PIXEL_FORMAT_422 && + chroma_fmt_idc != PIXEL_FORMAT_444) + return IMG_PIXFMT_UNDEFINED; + + /* valid bit depth 8, 9, 10, or 16/0 for 422 */ + if (bitdepth_y < 8 || bitdepth_y > 10) + return IMG_PIXFMT_UNDEFINED; + + /* valid bit depth 8, 9, 10, or 16/0 for 422 */ + if (bitdepth_c < 8 || bitdepth_c > 10) + return IMG_PIXFMT_UNDEFINED; + + key.pixfmt = IMG_PIXFMT_UNDEFINED; + key.chroma_fmt_idc = chroma_fmt_idc; + key.chroma_interleave = chroma_interleaved; + key.mem_pkg = mem_pkg; + key.bitdepth_y = bitdepth_y; + key.bitdepth_c = bitdepth_c; + key.num_planes = internal_num_planes; + + /* + * 9 and 10 bits formats are handled in the same way, and there is only + * one entry in the PixelFormat table + */ + if (key.bitdepth_y == 9) + key.bitdepth_y = 10; + + /* + * 9 and 10 bits formats are handled in the same way, and there is only + * one entry in the PixelFormat table + */ + if (key.bitdepth_c == 9) + key.bitdepth_c = 10; + + pixel_init_search(); + + /* do not search by format */ + fmt_found = pixel_search_fmt(&key, FALSE); + if (!fmt_found) + return IMG_PIXFMT_UNDEFINED; + + return fmt_found->pixfmt; +} + +static void pixel_get_internal_pixelinfo(struct pixel_pixinfo *pixinfo, + struct pixel_info *pix_bufinfo) +{ + if (pixinfo->bitdepth_y == 8 && pixinfo->bitdepth_c == 8) + pix_bufinfo->pixels_in_bop = 16; + else if (pixinfo->mem_pkg == PIXEL_BIT10_MP) + pix_bufinfo->pixels_in_bop = 12; + else + pix_bufinfo->pixels_in_bop = 8; + + if (pixinfo->bitdepth_y == 8) + pix_bufinfo->ybytes_in_bop = pix_bufinfo->pixels_in_bop; + else + pix_bufinfo->ybytes_in_bop = 16; + + if (pixinfo->chroma_fmt_idc == PIXEL_FORMAT_MONO) { + pix_bufinfo->uvbytes_in_bop = 0; + } else if (pixinfo->bitdepth_c == 8) { + pix_bufinfo->uvbytes_in_bop = pix_bufinfo->pixels_in_bop; + if (pixinfo->chroma_fmt_idc == PIXEL_FORMAT_422 && pixinfo->num_planes == 1) { + pix_bufinfo->uvbytes_in_bop = 0; + pix_bufinfo->pixels_in_bop = 8; + } + } else { + pix_bufinfo->uvbytes_in_bop = 16; + } + + if (pixinfo->chroma_fmt_idc == PIXEL_FORMAT_444) + pix_bufinfo->uvbytes_in_bop *= 2; + + if (pixinfo->chroma_interleave == PIXEL_INVALID_CI) { + pix_bufinfo->uvbytes_in_bop /= 2; + pix_bufinfo->vbytes_in_bop = pix_bufinfo->uvbytes_in_bop; + } else { + pix_bufinfo->vbytes_in_bop = 0; + } + + pix_bufinfo->alphabytes_in_bop = 0; + + if (pixinfo->num_planes == 1) + pix_bufinfo->is_planar = FALSE; + else + pix_bufinfo->is_planar = TRUE; + + if (pixinfo->chroma_fmt_idc == PIXEL_FORMAT_420) + pix_bufinfo->uv_height_halved = TRUE; + else + pix_bufinfo->uv_height_halved = FALSE; + + if (pixinfo->chroma_fmt_idc == PIXEL_FORMAT_444) + pix_bufinfo->uv_stride_ratio_times4 = 8; + else + pix_bufinfo->uv_stride_ratio_times4 = 4; + + if (pixinfo->chroma_interleave == PIXEL_INVALID_CI) + pix_bufinfo->uv_stride_ratio_times4 /= 2; + + pix_bufinfo->has_alpha = FALSE; +} + +static void pixel_yuv_get_descriptor_int(struct pixel_info *pixinfo, + struct img_pixfmt_desc *pix_desc) +{ + pix_desc->bop_denom = pixinfo->pixels_in_bop; + pix_desc->h_denom = (pixinfo->uv_stride_ratio_times4 == 2 || + !pixinfo->is_planar) ? 2 : 1; + pix_desc->v_denom = (pixinfo->uv_height_halved || !pixinfo->is_planar) + ? 2 : 1; + + pix_desc->planes[0] = TRUE; + pix_desc->bop_numer[0] = pixinfo->ybytes_in_bop; + pix_desc->h_numer[0] = pix_desc->h_denom; + pix_desc->v_numer[0] = pix_desc->v_denom; + + pix_desc->planes[1] = pixinfo->is_planar; + pix_desc->bop_numer[1] = pixinfo->uvbytes_in_bop; + pix_desc->h_numer[1] = (pix_desc->h_denom * pixinfo->uv_stride_ratio_times4) / 4; + pix_desc->v_numer[1] = 1; + + pix_desc->planes[2] = (pixinfo->vbytes_in_bop > 0) ? TRUE : FALSE; + pix_desc->bop_numer[2] = pixinfo->vbytes_in_bop; + pix_desc->h_numer[2] = (pixinfo->vbytes_in_bop > 0) ? 1 : 0; + pix_desc->v_numer[2] = (pixinfo->vbytes_in_bop > 0) ? 1 : 0; + + pix_desc->planes[3] = pixinfo->has_alpha; + pix_desc->bop_numer[3] = pixinfo->alphabytes_in_bop; + pix_desc->h_numer[3] = pix_desc->h_denom; + pix_desc->v_numer[3] = pix_desc->v_denom; +} + +int pixel_yuv_get_desc(struct pixel_pixinfo *pix_info, struct img_pixfmt_desc *pix_desc) +{ + struct pixel_info int_pix_info; + + struct pixel_info *int_pix_info_old = NULL; + enum img_pixfmt pix_fmt = pixel_get_pixfmt(pix_info->chroma_fmt_idc, + pix_info->chroma_interleave, + pix_info->mem_pkg, + pix_info->bitdepth_y, + pix_info->bitdepth_c, + pix_info->num_planes); + + /* Validate the output from new function. */ + if (pix_fmt != IMG_PIXFMT_UNDEFINED) + int_pix_info_old = pixel_get_bufinfo_from_pixfmt(pix_fmt); + + pixel_get_internal_pixelinfo(pix_info, &int_pix_info); + + if (int_pix_info_old) { + VDEC_ASSERT(int_pix_info_old->has_alpha == + int_pix_info.has_alpha); + VDEC_ASSERT(int_pix_info_old->is_planar == + int_pix_info.is_planar); + VDEC_ASSERT(int_pix_info_old->uv_height_halved == + int_pix_info.uv_height_halved); + VDEC_ASSERT(int_pix_info_old->alphabytes_in_bop == + int_pix_info.alphabytes_in_bop); + VDEC_ASSERT(int_pix_info_old->pixels_in_bop == + int_pix_info.pixels_in_bop); + VDEC_ASSERT(int_pix_info_old->uvbytes_in_bop == + int_pix_info.uvbytes_in_bop); + VDEC_ASSERT(int_pix_info_old->uv_stride_ratio_times4 == + int_pix_info.uv_stride_ratio_times4); + VDEC_ASSERT(int_pix_info_old->vbytes_in_bop == + int_pix_info.vbytes_in_bop); + VDEC_ASSERT(int_pix_info_old->ybytes_in_bop == + int_pix_info.ybytes_in_bop); + } + + pixel_yuv_get_descriptor_int(&int_pix_info, pix_desc); + + return IMG_SUCCESS; +} + +struct pixel_pixinfo *pixel_get_pixinfo(const enum img_pixfmt pix_fmt) +{ + struct pixel_pixinfo key; + struct pixel_pixinfo *fmt_found = NULL; + + pixel_init_search(); + pixel_pixinfo_defaults(&key); + key.pixfmt = pix_fmt; + + fmt_found = pixel_search_fmt(&key, TRUE); + if (!fmt_found) + return def_fmt; + return fmt_found; +} + +int pixel_get_fmt_desc(enum img_pixfmt pix_fmt, struct img_pixfmt_desc *pix_desc) +{ + if (pix_fmt >= IMG_PIXFMT_ARBPLANAR8 && pix_fmt <= IMG_PIXFMT_ARBPLANAR8_LAST) { + unsigned int i; + unsigned short spec; + + pix_desc->bop_denom = 1; + pix_desc->h_denom = 1; + pix_desc->v_denom = 1; + + spec = (pix_fmt - IMG_PIXFMT_ARBPLANAR8) & 0xffff; + for (i = 0; i < FACT_SPEC_FORMAT_NUM_PLANES; i++) { + unsigned char code = (spec >> FACT_SPEC_FORMAT_PLANE_CODE_BITS * + (FACT_SPEC_FORMAT_NUM_PLANES - 1 - i)) & 0xf; + pix_desc->bop_numer[i] = 1; + pix_desc->h_numer[i] = ((code >> 2) & FACT_SPEC_FORMAT_PLANE_CODE_MASK) + + FACT_SPEC_FORMAT_MIN_FACT_VAL; + pix_desc->v_numer[i] = (code & FACT_SPEC_FORMAT_PLANE_CODE_MASK) + + FACT_SPEC_FORMAT_MIN_FACT_VAL; + if (i == 0 || code != FACT_SPEC_FORMAT_PLANE_UNUSED) { + pix_desc->planes[i] = TRUE; + + pix_desc->h_denom = + pix_desc->h_denom > pix_desc->h_numer[i] ? + pix_desc->h_denom : pix_desc->h_numer[i]; + + pix_desc->v_denom = + pix_desc->v_denom > pix_desc->v_numer[i] ? + pix_desc->v_denom : pix_desc->v_numer[i]; + } else { + pix_desc->planes[i] = FALSE; + } + } + } else { + struct pixel_info *info = + pixel_get_bufinfo_from_pixfmt(pix_fmt); + if (!info) { + VDEC_ASSERT(0); + return -EINVAL; + } + + pixel_yuv_get_descriptor_int(info, pix_desc); + } + + return IMG_SUCCESS; +} + +int pixel_gen_pixfmt(enum img_pixfmt *pix_fmt, struct img_pixfmt_desc *pix_desc) +{ + unsigned short spec = 0, i; + unsigned char code; + + for (i = 0; i < FACT_SPEC_FORMAT_NUM_PLANES; i++) { + if (pix_desc->planes[i] != 1) { + code = FACT_SPEC_FORMAT_PLANE_UNUSED; + } else { + code = (((pix_desc->h_numer[i] - FACT_SPEC_FORMAT_MIN_FACT_VAL) & + FACT_SPEC_FORMAT_PLANE_CODE_MASK) << 2) | + ((pix_desc->v_numer[i] - FACT_SPEC_FORMAT_MIN_FACT_VAL) & + FACT_SPEC_FORMAT_PLANE_CODE_MASK); + } + spec |= (code << FACT_SPEC_FORMAT_PLANE_CODE_BITS * + (FACT_SPEC_FORMAT_NUM_PLANES - 1 - i)); + } + + *pix_fmt = (enum img_pixfmt)(IMG_PIXFMT_ARBPLANAR8 | spec); + + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/pixel_api.h b/drivers/media/platform/imagination/vxe-vxd/decoder/pixel_api.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/pixel_api.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/pixel_api.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Pixel processing functions header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + */ + +#ifndef __PIXEL_API_H__ +#define __PIXEL_API_H__ + +#include + +#include "img_errors.h" +#include "img_pixfmts.h" + +#define PIXEL_MULTICHROME TRUE +#define PIXEL_MONOCHROME FALSE +#define IMG_MAX_NUM_PLANES 4 +#define PIXEL_INVALID_BDC 8 + +extern unsigned char pix_fmt_idc_names[6][16]; + +struct img_pixfmt_desc { + unsigned char planes[IMG_MAX_NUM_PLANES]; + unsigned int bop_denom; + unsigned int bop_numer[IMG_MAX_NUM_PLANES]; + unsigned int h_denom; + unsigned int v_denom; + unsigned int h_numer[IMG_MAX_NUM_PLANES]; + unsigned int v_numer[IMG_MAX_NUM_PLANES]; +}; + +/* + * @brief This type defines memory chroma interleaved order + */ +enum pixel_chroma_interleaved { + PIXEL_INVALID_CI = 0, + PIXEL_UV_ORDER = 1, + PIXEL_VU_ORDER = 2, + PIXEL_YAYB_ORDER = 4, + PIXEL_AYBY_ORDER = 8, + PIXEL_ORDER_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * @brief This macro translates enum pixel_chroma_interleaved values into + * value that can be used to write HW registers directly. + */ +#define PIXEL_GET_HW_CHROMA_INTERLEAVED(value) \ + ((value) & PIXEL_VU_ORDER ? TRUE : FALSE) + +/* + * @brief This type defines memory packing types + */ +enum pixel_mem_packing { + PIXEL_BIT8_MP = 0, + PIXEL_BIT10_MSB_MP = 1, + PIXEL_BIT10_LSB_MP = 2, + PIXEL_BIT10_MP = 3, + PIXEL_DEFAULT_MP = 0xff, + PIXEL_DEFAULT_FORCE32BITS = 0x7FFFFFFFU +}; + +static inline unsigned char pixel_get_hw_memory_packing(enum pixel_mem_packing value) +{ + return value == PIXEL_BIT8_MP ? FALSE : + value == PIXEL_BIT10_MSB_MP ? FALSE : + value == PIXEL_BIT10_LSB_MP ? FALSE : + value == PIXEL_BIT10_MP ? TRUE : FALSE; +} + +/* + * @brief This type defines chroma formats + */ +enum pixel_fmt_idc { + PIXEL_FORMAT_MONO = 0, + PIXEL_FORMAT_411 = 1, + PIXEL_FORMAT_420 = 2, + PIXEL_FORMAT_422 = 3, + PIXEL_FORMAT_444 = 4, + PIXEL_FORMAT_INVALID = 0xFF, + PIXEL_FORMAT_FORCE32BITS = 0x7FFFFFFFU +}; + +static inline int pixel_get_hw_chroma_format_idc(enum pixel_fmt_idc value) +{ + return value == PIXEL_FORMAT_MONO ? 0 : + value == PIXEL_FORMAT_420 ? 1 : + value == PIXEL_FORMAT_422 ? 2 : + value == PIXEL_FORMAT_444 ? 3 : + PIXEL_FORMAT_INVALID; +} + +/* + * @brief This structure contains information about the pixel formats + */ +struct pixel_pixinfo { + enum img_pixfmt pixfmt; + enum pixel_chroma_interleaved chroma_interleave; + unsigned char chroma_fmt; + enum pixel_mem_packing mem_pkg; + enum pixel_fmt_idc chroma_fmt_idc; + unsigned int bitdepth_y; + unsigned int bitdepth_c; + unsigned int num_planes; +}; + +/* + * @brief This type defines the image in memory + */ +struct pixel_info { + unsigned int pixels_in_bop; + unsigned int ybytes_in_bop; + unsigned int uvbytes_in_bop; + unsigned int vbytes_in_bop; + unsigned int alphabytes_in_bop; + unsigned char is_planar; + unsigned char uv_height_halved; + unsigned int uv_stride_ratio_times4; + unsigned char has_alpha; +}; + +struct pixel_pixinfo_table { + enum img_pixfmt pix_color_fmt; + struct pixel_info info; +}; + +struct pixel_pixinfo *pixel_get_pixinfo(const enum img_pixfmt pixfmt); + +enum img_pixfmt pixel_get_pixfmt(enum pixel_fmt_idc chroma_fmt_idc, + enum pixel_chroma_interleaved + chroma_interleaved, + enum pixel_mem_packing mem_packing, + unsigned int bitdepth_y, unsigned int bitdepth_c, + unsigned int num_planes); + +int pixel_yuv_get_desc(struct pixel_pixinfo *pix_info, + struct img_pixfmt_desc *desc); + +int pixel_get_fmt_desc(enum img_pixfmt pixfmt, + struct img_pixfmt_desc *fmt_desc); + +int pixel_gen_pixfmt(enum img_pixfmt *pix_fmt, struct img_pixfmt_desc *pix_desc); + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/pvdec_entropy_regs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/pvdec_entropy_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/pvdec_entropy_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/pvdec_entropy_regs.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD DEC Common low level core interface component + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef __PVDEC_ENTROPY_REGS_H__ +#define __PVDEC_ENTROPY_REGS_H__ + +/* + * PVDEC_ENTROPY, CR_ENTROPY_SHIFTREG_CONTROL, SR_SW_RESET + */ +#define PVDEC_ENTROPY_CR_GENC_BUFFER_SIZE_OFFSET (0x0100) + +/* + * PVDEC_ENTROPY, CR_GENC_BUFFER_SIZE, GENC_BUFFER_SIZE + */ +#define PVDEC_ENTROPY_CR_GENC_BUFFER_BASE_ADDRESS_OFFSET (0x0110) + +/* + * PVDEC_ENTROPY, CR_ENTROPY_SLICE_PARAMETER_SIZE, SLICE_PARAMETER_SIZE + */ +#define PVDEC_ENTROPY_CR_GENC_FRAGMENT_BASE_ADDRESS_OFFSET (0x0098) + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/pvdec_int.h b/drivers/media/platform/imagination/vxe-vxd/decoder/pvdec_int.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/pvdec_int.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/pvdec_int.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Low-level PVDEC interface component. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ +#ifndef __PVDEC_INT_H__ +#define __PVDEC_INT_H__ + +#include "hw_control.h" +#include "vxd_ext.h" +#include "vxd_props.h" + +/* How many VLC IDX addresses fits in single address register */ +#define PVDECIO_VLC_IDX_ADDR_PARTS 2 + +/* How many VLC IDX initial fits in single width register */ +#define PVDECIO_VLC_IDX_WIDTH_PARTS 10 + +/* How many VLC IDX initial opcodes fits in single opcode register */ +#define PVDECIO_VLC_IDX_OPCODE_PARTS 16 + +/* + * Length (shift) of VLC IDX opcode field. We're taking [0][1] here, as it + * corresponds to shift of one element + */ +#define PVDECIO_VLC_IDX_ADDR_ID 2 + +/* + * Mask for VLC IDX address field. We're taking [0][0] here, as it corresponds + * to unshifted mask + */ +#define PVDECIO_VLC_IDX_ADDR_MASK MSVDX_VEC_CR_VEC_VLC_TABLE_ADDR0_VLC_TABLE_ADDR0_MASK + +/* + * Length (shift) of VLC IDX address field. We're taking [0][1] here, as it + * corresponds to shift of one element + */ +#define PVDECIO_VLC_IDX_ADDR_SHIFT MSVDX_VEC_CR_VEC_VLC_TABLE_ADDR0_VLC_TABLE_ADDR1_SHIFT +#define PVDECIO_VLC_IDX_WIDTH_ID 1 + +/* + * Mask for VLC IDX width field. We're taking [0][0] here, as it corresponds + * to unshifted mask + */ +#define PVDECIO_VLC_IDX_WIDTH_MASK \ + MSVDX_VEC_CR_VEC_VLC_TABLE_INITIAL_WIDTH0_VLC_TABLE_INITIAL_WIDTH0_MASK + +/* + * Length (shift) of VLC IDX width field. We're taking [0][1] here, as it + * corresponds to shift of one element + */ +#define PVDECIO_VLC_IDX_WIDTH_SHIFT \ + MSVDX_VEC_CR_VEC_VLC_TABLE_INITIAL_WIDTH0_VLC_TABLE_INITIAL_WIDTH1_SHIFT + +#define PVDECIO_VLC_IDX_OPCODE_ID 0 + +/* + * Length (shift) of VLC IDX opcode field. We're taking [0][1] here, as it + * corresponds to shift of one element + */ +#define PVDECIO_VLC_IDX_OPCODE_SHIFT \ + MSVDX_VEC_CR_VEC_VLC_TABLE_INITIAL_OPCODE0_VLC_TABLE_INITIAL_OPCODE1_SHIFT + +/* This comes from DEVA PVDEC FW */ +#define CTRL_ALLOC_MAX_SEGMENT_SIZE 1024 + +/* + * Mask for VLC IDX opcode field. We're taking [0][0] here, as it corresponds + * to unshifted mask + */ +#define PVDECIO_VLC_IDX_OPCODE_MASK \ + MSVDX_VEC_CR_VEC_VLC_TABLE_INITIAL_OPCODE0_VLC_TABLE_INITIAL_OPCODE0_MASK + +#endif /* __PVDEC_INT_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/pvdec_vec_be_regs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/pvdec_vec_be_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/pvdec_vec_be_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/pvdec_vec_be_regs.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD DEC Common low level core interface component + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef __PVDEC_VEC_BE_REGS_H__ +#define __PVDEC_VEC_BE_REGS_H__ + +#define PVDEC_VEC_BE_CR_GENC_BUFFER_SIZE_OFFSET (0x0040) + +/* + * PVDEC_VEC_BE, CR_GENC_BUFFER_SIZE, GENC_BUFFER_SIZE + */ +#define PVDEC_VEC_BE_CR_GENC_BUFFER_BASE_ADDRESS_OFFSET (0x0050) + +/* + * PVDEC_VEC_BE, CR_MEM_TO_REG_CONTROL, MEM_TO_REG_NUM_PAIRS + */ +#define PVDEC_VEC_BE_CR_GENC_FRAGMENT_BASE_ADDRESS_OFFSET (0x0030) + +/* + * PVDEC_VEC_BE, CR_GENC_CONTEXT1, GENC_CONTEXT1_1 + */ +#define PVDEC_VEC_BE_CR_ABOVE_PARAM_BASE_ADDRESS_OFFSET (0x00C0) + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/reg_io2.h b/drivers/media/platform/imagination/vxe-vxd/decoder/reg_io2.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/reg_io2.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/reg_io2.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG MSVDX core Registers + * This file contains the MSVDX_CORE_REGS_H Definitions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef REG_IO2_H_ +#define REG_IO2_H_ + +#define IMG_ASSERT(expected) \ + ((void)((expected) || \ + (pr_err("Assertion failed: %s, file %s, line %d\n", \ + #expected, __FILE__, __LINE__), dump_stack(), 0))) + +/* This macro is used to extract a field from a register. */ +#define REGIO_READ_FIELD(regval, group, reg, field) \ + (((regval) & group ## _ ## reg ## _ ## field ## _MASK) >> \ + group ## _ ## reg ## _ ## field ## _SHIFT) + +#if (defined WIN32 || defined __linux__) && !defined NO_REGIO_CHECK_FIELD_VALUE +/* + * Only provide register field range checking for Windows and + * Linux builds + * Simple range check that ensures that if bits outside the valid field + * range are set, that the provided value is at least consistent with a + * negative value (i.e.: all top bits are set to 1). + * Cannot perform more comprehensive testing without knowing + * whether field + * should be interpreted as signed or unsigned. + */ +#define REGIO_CHECK_VALUE_FITS_WITHIN_FIELD(group, reg, field, value, type) \ + { \ + type __value = 0; \ + unsigned int temp = 0; \ + __value = value; \ + temp = (unsigned int)(__value); \ + if (temp > group ## _ ## reg ## _ ## field ## _LSBMASK) { \ + IMG_ASSERT((((unsigned int)__value) & \ + (unsigned int)~(group ## _ ## reg ## _ ## field ## _LSBMASK)) == \ + (unsigned int)~(group ## _ ## reg ## _ ## field ## _LSBMASK)); \ + } \ + } +#else +#define REGIO_CHECK_VALUE_FITS_WITHIN_FIELD(group, reg, field, value, type) +#endif + +/* This macro is used to update the value of a field in a register. */ +#define REGIO_WRITE_FIELD(regval, group, reg, field, value, reg_type, val_type) \ + { \ + reg_type __regval = regval; \ + val_type __value = value; \ + REGIO_CHECK_VALUE_FITS_WITHIN_FIELD(group, reg, field, __value, val_type); \ + (regval) = \ + ((__regval) & ~(group ## _ ## reg ## _ ## field ## _MASK)) | \ + (((unsigned int)(__value) << (group ## _ ## reg ## _ ## field ## _SHIFT)) & \ + (group ## _ ## reg ## _ ## field ## _MASK)); \ + } + +/* This macro is used to update the value of a field in a register. */ +#define REGIO_WRITE_FIELD_LITE(regval, group, reg, field, value, type) \ +{ \ + type __value = value; \ + REGIO_CHECK_VALUE_FITS_WITHIN_FIELD(group, reg, field, __value, type); \ + (regval) |= ((unsigned int)(__value) << (group ## _ ## reg ## _ ## field ## _SHIFT)); \ +} + +#endif /* REG_IO2_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/scaler_setup.h b/drivers/media/platform/imagination/vxe-vxd/decoder/scaler_setup.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/scaler_setup.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/scaler_setup.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD DEC constants calculation and scalling coefficients + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + */ + +#ifndef _SCALER_SETUP_H +#define _SCALER_SETUP_H + +#define LOWP 11 +#define HIGHP 14 + +#define FIXED(a, digits) ((int)((a) * (1 << (digits)))) + +struct scaler_params { + unsigned int vert_pitch; + unsigned int vert_startpos; + unsigned int vert_pitch_chroma; + unsigned int vert_startpos_chroma; + unsigned int horz_pitch; + unsigned int horz_startpos; + unsigned int horz_pitch_chroma; + unsigned int horz_startpos_chroma; + unsigned char fixed_point_shift; +}; + +struct scaler_filter { + unsigned char bhoriz_bilinear; + unsigned char bvert_bilinear; +}; + +struct scaler_pitch { + int horiz_luma; + int vert_luma; + int horiz_chroma; + int vert_chroma; +}; + +struct scaler_config { + enum vdec_vid_std vidstd; + const struct vxd_coreprops *coreprops; + struct pixel_pixinfo *in_pixel_info; + const struct pixel_pixinfo *out_pixel_info; + unsigned char bfield_coded; + unsigned char bseparate_chroma_planes; + unsigned int recon_width; + unsigned int recon_height; + unsigned int mb_width; + unsigned int mb_height; + unsigned int scale_width; + unsigned int scale_height; +}; + +#endif /* _SCALER_SETUP_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/swsr.c b/drivers/media/platform/imagination/vxe-vxd/decoder/swsr.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/swsr.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/swsr.c 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,1657 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Software Shift Register Access fucntions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * Re-written for upstreming + * Prashanth Kumar Amai + * Sidraya Jayagond + */ + +#include +#include +#include +#include + +#include "swsr.h" +#include "vdec_defs.h" + +#define NBIT_8BYTE_MASK(n) ((1ULL << (n)) - 1) + +/* Input FIFO length (in bytes). */ +#define SWSR_INPUT_FIFO_LENGTH 8 + +/* Output FIFO length (in bits). */ +#define SWSR_OUTPUT_FIFO_LENGTH 64 + +#define SWSR_NALTYPE_LENGTH 8 + +#define SWSR_MAX_SYNTAX_LENGTH 32 + +#define SWSR_ASSERT(expected) ({WARN_ON(!(expected)); 0; }) + +struct swsr_buffer { + void **lst_link; + /* Pointer to bitstream data. */ + unsigned char *data; + /* Number of bytes of bitstream */ + unsigned long long num_bytes; + /* Index (in bytes) to next data within the buffer */ + unsigned long long byte_offset; + /* Number of bytes read from input FIFO */ + unsigned long long num_bytes_read; +}; + +struct swsr_input { + /* Bitstream data (byte-based and pre emu prev) - left aligned. */ + unsigned long long fifo; + /* Number of *bytes* in Input FIFO */ + unsigned int num_bytes; + struct swsr_config config; + /* Emulation prevention mode used to process data in Input FIFO */ + enum swsr_emprevent emprevent; + /* Number of bytes in emulation prevention sequence */ + unsigned int emprev_seq_len; + /* Size of bitstream declared at initialisation */ + unsigned long long bitstream_size; + /* + * Number of bytes required from input buffer before checking + * next emulation prevention sequence. + */ + unsigned int bytes_for_next_sequ; + /* Byte count read from size delimiter */ + unsigned long long byte_count; + unsigned long long bytes_read_since_delim; + /* Cumulative offset (in bytes) into input buffer data */ + unsigned long long bitstream_offset; + /* Bitstream delimiter found (see #SWSR_delim_type) */ + unsigned char delim_found; + /* + * No More Valid Data before next delimiter. + * Set only for SWSR_EMPREVENT_00000300. + */ + unsigned char no_moredata; + /* Pointer to current input buffer in the context of Input FIFO */ + struct swsr_buffer *buf; + /* Start offset within buffer of current delimited unit */ + long delimited_unit_start_offset; + /* Size of current delimited unit (if already calculated) */ + unsigned int delimited_unit_size; + /* Current bit offset within the current delimited unit */ + unsigned int delimunit_bitofst; +}; + +struct swsr_output { + /* + * Bitstream data (post emulation prevention removal + * delimiter checking) - left aligned. + */ + unsigned long long fifo; + /* Number of *bits* in Output FIFO */ + unsigned int num_bits; + unsigned long long totalbits_consumed; +}; + +struct swsr_buffer_ctx { + /* + * Callback function to notify event and provide/request data. + * See #SWSR_eCbEvent for event types and description + * of CB argument usage. + */ + swsr_callback_fxn cb_fxn; + /* Caller supplied pointer for callback */ + void *cb_param; + /* List of buffers */ + struct lst_t free_buffer_list; + /* + * List of buffers (#SWSR_sBufferCtx) whose data reside + * in the Input/Output FIFOs. + */ + struct lst_t used_buffer_list; +}; + +struct swsr_context { + /* IMG_TRUE if the context is initialised */ + unsigned char initialised; + /* A pointer to an exception handler */ + swsr_except_handler_fxn exception_handler_fxn; + /* Caller supplied pointer */ + void *pexception_param; + /* Last recorded exception */ + enum swsr_exception exception; + /* Buffer context data */ + struct swsr_buffer_ctx buffer_ctx; + /* Context of shift register input. */ + struct swsr_input input; + /* Context of shift register output */ + struct swsr_output output; +}; + +static unsigned long long left_aligned_nbit_8byte_mask(unsigned int mask, unsigned int nbits) +{ + return (((unsigned long long)mask << (64 - nbits)) | + (unsigned long long)NBIT_8BYTE_MASK(64 - nbits)); +} + +/* + * buffer has been exhausted and there is still more bytes declared in bitstream + */ +static int swsr_extractbyte(struct swsr_context *ctx, unsigned char *byte_ext) +{ + struct swsr_input *input; + struct swsr_buffer_ctx *buf_ctx; + unsigned char byte = 0; + unsigned long long cur_byte_offset; + unsigned int result = 0; + + if (!ctx || !byte_ext) + return IMG_ERROR_FATAL; + + input = &ctx->input; + buf_ctx = &ctx->buffer_ctx; + + cur_byte_offset = input->bitstream_offset; + + if (input->buf && input->buf->byte_offset < input->buf->num_bytes) { + input->bitstream_offset++; + byte = input->buf->data[input->buf->byte_offset++]; + } else if (input->bitstream_offset < input->bitstream_size) { + struct swsr_buffer *buffer; + + buffer = lst_removehead(&buf_ctx->free_buffer_list); + if (!buffer) + return IMG_ERROR_FATAL; + + buffer->num_bytes_read = 0; + buffer->byte_offset = 0; + + buf_ctx->cb_fxn(SWSR_EVENT_INPUT_BUFFER_START, + buf_ctx->cb_param, 0, + &buffer->data, &buffer->num_bytes); + SWSR_ASSERT(buffer->data && buffer->num_bytes > 0); + + if (buffer->data && buffer->num_bytes > 0) { + input->buf = buffer; + + /* Add input buffer to output buffer list. */ + lst_add(&buf_ctx->used_buffer_list, input->buf); + + input->bitstream_offset++; + byte = input->buf->data[input->buf->byte_offset++]; + } + } + + { + struct swsr_buffer *buffer = input->buf; + + if (!buffer) + buffer = lst_first(&buf_ctx->used_buffer_list); + + if (!buffer || buffer->num_bytes_read > buffer->num_bytes) { + input->delimited_unit_start_offset = -1; + input->delimited_unit_size = 0; + } + } + /* If the bitstream offset hasn't increased we failed to read a byte. */ + if (cur_byte_offset == input->bitstream_offset) { + input->buf = NULL; + result = IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + } + + *byte_ext = byte; + + return result; +} + +static unsigned char swsr_checkfor_delimiter(struct swsr_context *ctx) +{ + struct swsr_input *input; + unsigned char delim_found = 0; + + input = &ctx->input; + + /* Check for delimiter. */ + if (input->config.delim_type == SWSR_DELIM_SCP) { + unsigned int shift = (SWSR_INPUT_FIFO_LENGTH * 8) + - input->config.delim_length; + unsigned long long sequ = input->fifo >> shift; + + /* + * Check if the SCP value is matched outside of + * emulation prevention data. + */ + if (sequ == input->config.scp_value && input->bytes_for_next_sequ == 0) + delim_found = 1; + + } else if (input->config.delim_type == SWSR_DELIM_SIZE) { + delim_found = (input->bytes_read_since_delim >= input->byte_count) ? 1 : 0; + } + + return delim_found; +} + +static int swsr_increment_cur_bufoffset(struct swsr_context *ctx) +{ + struct swsr_buffer_ctx *buf_ctx; + struct swsr_buffer *cur_buf; + + buf_ctx = &ctx->buffer_ctx; + + /* Update the number of bytes read from input FIFO for current buffer */ + cur_buf = lst_first(&buf_ctx->used_buffer_list); + if (cur_buf->num_bytes_read >= cur_buf->num_bytes) { + /* Mark current bitstream buffer as fully consumed */ + cur_buf->num_bytes_read = cur_buf->num_bytes; + + /* Notify the application that the old buffer is exhausted. */ + buf_ctx->cb_fxn(SWSR_EVENT_OUTPUT_BUFFER_END, + buf_ctx->cb_param, 0, + NULL, NULL); + + /* + * Discard the buffer whose data was at the head of + * the input FIFO. + */ + cur_buf = lst_removehead(&buf_ctx->used_buffer_list); + /* Add the buffer container to free list. */ + lst_add(&buf_ctx->free_buffer_list, cur_buf); + + /* + * Since the byte that we read was actually from the next + * buffer increment it's counter. + */ + cur_buf = lst_first(&buf_ctx->used_buffer_list); + cur_buf->num_bytes_read++; + } else { + cur_buf->num_bytes_read++; + } + + return 0; +} + +static enum swsr_found swsr_readbyte_from_inputfifo(struct swsr_context *ctx, + unsigned char *byte) +{ + struct swsr_input *input; + enum swsr_found found = SWSR_FOUND_NONE; + unsigned int result = 0; + + input = &ctx->input; + + input->delim_found |= swsr_checkfor_delimiter(ctx); + + /* + * Refill the input FIFO before checking for emulation prevention etc. + * The only exception is when there are no more bytes left to extract + * from input buffer. + */ + while (input->num_bytes < SWSR_INPUT_FIFO_LENGTH && result == 0) { + unsigned char byte; + + result = swsr_extractbyte(ctx, &byte); + if (result == 0) { + input->fifo |= ((unsigned long long)byte << + ((SWSR_INPUT_FIFO_LENGTH - 1 - input->num_bytes) * 8)); + input->num_bytes += 1; + } + } + + if (input->num_bytes == 0) { + found = SWSR_FOUND_EOD; + } else if (!input->delim_found) { + /* + * Check for emulation prevention when enabled and enough + * bytes are remaining in input FIFO. + */ + if (input->emprevent != SWSR_EMPREVENT_NONE && + /* + * Ensure you have enough bytes to check for emulation + * prevention. + */ + input->num_bytes >= input->emprev_seq_len && + (input->config.delim_type != SWSR_DELIM_SIZE || + /* + * Ensure that you don't remove emu bytes beyond current + * delimited unit. + */ + ((input->bytes_read_since_delim + input->emprev_seq_len) < + input->byte_count)) && input->bytes_for_next_sequ == 0) { + unsigned char emprev_removed = 0; + unsigned int shift = (SWSR_INPUT_FIFO_LENGTH - input->emprev_seq_len) * 8; + unsigned long long sequ = input->fifo >> shift; + + if (input->emprevent == SWSR_EMPREVENT_00000300) { + if ((sequ & 0xffffff00) == 0x00000300) { + if ((sequ & 0x000000ff) > 0x03) + pr_err("Invalid start code emulation preventionbytes found\n"); + + /* + * Instead of trying to remove the emulation prevention + * byte from the middle of the FIFO simply make it zero + * and drop the next byte from the FIFO which will + * also be zero. + */ + input->fifo &= left_aligned_nbit_8byte_mask + (0xffff00ff, + input->emprev_seq_len * 8); + input->fifo <<= 8; + + emprev_removed = 1; + } else if ((sequ & 0xffffffff) == 0x00000000 || + (sequ & 0xffffffff) == 0x00000001) { + input->no_moredata = 1; + } + } else if (input->emprevent == SWSR_EMPREVENT_ff00) { + if (sequ == 0xff00) { + /* Remove the zero byte. */ + input->fifo <<= 8; + input->fifo |= (0xff00ULL << shift); + emprev_removed = 1; + } + } else if (input->emprevent == SWSR_EMPREVENT_000002) { + /* + * Remove the emulation prevention bytes + * if we find 22 consecutive 0 bits + * (from a byte-aligned position?!) + */ + if (sequ == 0x000002) { + /* + * Appear to "remove" the 0x02 byte by clearing + * it and then dropping the top (zero) byte. + */ + input->fifo &= left_aligned_nbit_8byte_mask + (0xffff00, + input->emprev_seq_len * 8); + input->fifo <<= 8; + emprev_removed = 1; + } + } + + if (emprev_removed) { + input->num_bytes--; + input->bytes_read_since_delim++; + + /* Increment the buffer offset for the + * byte that has been removed. + */ + swsr_increment_cur_bufoffset(ctx); + + /* + * Signal that two more new bytes in the emulation + * prevention sequence are required before another match + * can be made. + */ + input->bytes_for_next_sequ = input->emprev_seq_len - 2; + } + } + + if (input->bytes_for_next_sequ > 0) + input->bytes_for_next_sequ--; + + /* return the first bytes from read data */ + *byte = (unsigned char)(input->fifo >> ((SWSR_INPUT_FIFO_LENGTH - 1) * 8)); + input->fifo <<= 8; + + input->num_bytes--; + input->bytes_read_since_delim++; + + /* Increment the buffer offset for byte that has been read. */ + swsr_increment_cur_bufoffset(ctx); + + found = SWSR_FOUND_DATA; + } else { + found = SWSR_FOUND_DELIM; + } + + return found; +} + +static enum swsr_found swsr_consumebyte_from_inputfifo + (struct swsr_context *ctx, unsigned char *byte) +{ + enum swsr_found found; + + found = swsr_readbyte_from_inputfifo(ctx, byte); + + if (found == SWSR_FOUND_DATA) { + /* Only whole bytes can be read from Input FIFO. */ + ctx->output.totalbits_consumed += 8; + ctx->input.delimunit_bitofst += 8; + } + + return found; +} + +static int swsr_fill_outputfifo(struct swsr_context *ctx) +{ + unsigned char byte; + enum swsr_found found = SWSR_FOUND_DATA; + + /* Fill output FIFO with whole bytes up to (but not over) max length */ + while (ctx->output.num_bits <= (SWSR_OUTPUT_FIFO_LENGTH - 8) && found == SWSR_FOUND_DATA) { + found = swsr_readbyte_from_inputfifo(ctx, &byte); + if (found == SWSR_FOUND_DATA) { + ctx->output.fifo |= ((unsigned long long)byte << + (SWSR_OUTPUT_FIFO_LENGTH - 8 - ctx->output.num_bits)); + ctx->output.num_bits += 8; + } + } + + return 0; +} + +static unsigned int swsr_getbits_from_outputfifo(struct swsr_context *ctx, + unsigned int numbits, + unsigned char bconsume) +{ + unsigned int bitsread; + + /* + * Fetch more bits from the input FIFO if the output FIFO + * doesn't have enough bits to satisfy the request on its own. + */ + if (numbits > ctx->output.num_bits) + swsr_fill_outputfifo(ctx); + + /* Ensure that are now enough bits in the output FIFO. */ + if (numbits > ctx->output.num_bits) { + /* Tried to access into an SCP or other delimiter. */ + if (ctx->input.delim_found) { + ctx->exception = SWSR_EXCEPT_ACCESS_INTO_SCP; + } else { + /* + * Data has been exhausted if after extracting bits + * there are still not enough bits in the internal + * storage to fulfil the number requested. + */ + ctx->exception = SWSR_EXCEPT_ACCESS_BEYOND_EOD; + } + + ctx->exception_handler_fxn(ctx->exception, ctx->pexception_param); + + /* Return zero if the bits couldn't be obtained */ + bitsread = 0; + } else { + unsigned int shift; + + /* Extract all the bits from the output FIFO */ + shift = (SWSR_OUTPUT_FIFO_LENGTH - numbits); + bitsread = (unsigned int)(ctx->output.fifo >> shift); + + if (bconsume) { + /* Update output FIFO. */ + ctx->output.fifo <<= numbits; + ctx->output.num_bits -= numbits; + } + } + + if (bconsume && ctx->exception == SWSR_EXCEPT_NO_EXCEPTION) { + ctx->output.totalbits_consumed += numbits; + ctx->input.delimunit_bitofst += numbits; + } + + /* Return the bits */ + return bitsread; +} + +int swsr_read_signed_expgoulomb(void *ctx_hndl) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + unsigned int exp_goulomb; + unsigned char unsign; + + /* Validate input arguments. */ + if (!ctx) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + /* Read unsigned value then convert to signed value */ + exp_goulomb = swsr_read_unsigned_expgoulomb(ctx); + + unsign = exp_goulomb & 1; + exp_goulomb >>= 1; + exp_goulomb = (unsign) ? exp_goulomb + 1 : -(int)exp_goulomb; + + if (ctx->exception != SWSR_EXCEPT_NO_EXCEPTION) + ctx->exception_handler_fxn(ctx->exception, ctx->pexception_param); + + /* Return the signed value */ + return exp_goulomb; +} + +static unsigned int swsr_readunsigned_expgoulomb(struct swsr_context *ctx) +{ + unsigned int numbits = 0; + unsigned int bitpeeked; + unsigned int bitread; + unsigned int setbits; + unsigned int expgoulomb; + + /* Loop until we have found a non-zero nibble or reached 31 0-bits */ + /* first read is 3 bits only to prevent an illegal 32-bit peek */ + numbits = 1; + do { + bitpeeked = swsr_peekbits(ctx, numbits); + /* Check for non-zero nibble */ + if (bitpeeked != 0) + break; + + numbits++; + + } while (numbits < 32); + + /* Correct the number of leading zero bits */ + numbits--; + + if (bitpeeked) { + /* read leading zeros and 1-bit */ + bitread = swsr_read_bits(ctx, numbits + 1); + if (bitread != 1) + ctx->exception = SWSR_EXCEPT_EXPGOULOMB_ERROR; + } else { + /* + * read 31 zero bits - special case to deal with 31 or 32 + * leading zeros + */ + bitread = swsr_read_bits(ctx, 31); + if (bitread != 0) + ctx->exception = SWSR_EXCEPT_EXPGOULOMB_ERROR; + + /* + * next 3 bits make either 31 0-bit code:'1xx', + * or 32 0-bit code:'010' + */ + /* + * only valid 32 0-bit code is:'0..010..0' + * and results in 0xffffffff + */ + bitpeeked = swsr_peekbits(ctx, 3); + + if (ctx->exception == SWSR_EXCEPT_NO_EXCEPTION) { + if (0x4 & bitpeeked) { + bitread = swsr_read_bits(ctx, 1); + numbits = 31; + } else { + if (bitpeeked != 2) + ctx->exception = SWSR_EXCEPT_EXPGOULOMB_ERROR; + + bitread = swsr_read_bits(ctx, 3); + bitread = swsr_read_bits(ctx, 31); + if (bitread != 0) + ctx->exception = SWSR_EXCEPT_EXPGOULOMB_ERROR; + + return 0xffffffff; + } + } else { + /* encountered an exception while reading code */ + /* just return a valid value */ + return 0; + } + } + + /* read data bits */ + bitread = 0; + if (numbits) + bitread = swsr_read_bits(ctx, numbits); + + /* convert exp-goulomb to value */ + setbits = (1 << numbits) - 1; + expgoulomb = setbits + bitread; + /* Return the value */ + return expgoulomb; +} + +unsigned int swsr_read_unsigned_expgoulomb(void *ctx_hndl) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + unsigned int value; + + /* Validate input arguments. */ + if (!ctx) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + value = swsr_readunsigned_expgoulomb(ctx); + + if (ctx->exception != SWSR_EXCEPT_NO_EXCEPTION) + ctx->exception_handler_fxn(ctx->exception, ctx->pexception_param); + + return value; +} + +enum swsr_exception swsr_check_exception(void *ctx_hndl) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + enum swsr_exception exception; + + /* Validate input arguments. */ + if (!ctx) { + pr_err("Invalid arguments to function: %s\n", __func__); + return (enum swsr_exception)IMG_ERROR_INVALID_PARAMETERS; + } + + exception = ctx->exception; + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return (enum swsr_exception)IMG_ERROR_NOT_INITIALISED; + } + + ctx->exception = SWSR_EXCEPT_NO_EXCEPTION; + return exception; +} + +int swsr_check_more_rbsp_data(void *ctx_hndl, unsigned char *more_rbsp_data) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + + int rembitsinbyte; + unsigned char currentbyte; + int numof_aligned_rembits; + unsigned long long rest_alignedbytes; + unsigned char moredata = 0; + + /* Validate input arguments. */ + if (!ctx) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + if (ctx->input.emprevent != SWSR_EMPREVENT_00000300) { + pr_err("SWSR cannot determine More RBSP data for a stream without SWSR_EMPREVENT_00000300: %s\n", + __func__); + return IMG_ERROR_OPERATION_PROHIBITED; + } + + /* + * Always fill the output FIFO to ensure the no_moredata flag is set + * when there are enough remaining bytes + */ + + swsr_fill_outputfifo(ctx); + + if (ctx->output.num_bits != 0) { + /* Calculate the number of bits in the MS byte */ + rembitsinbyte = (ctx->output.num_bits & 0x7); + if (rembitsinbyte == 0) + rembitsinbyte = 8; + + numof_aligned_rembits = (ctx->output.num_bits - rembitsinbyte); + + /* Peek the value of last byte. */ + currentbyte = swsr_peekbits(ctx, rembitsinbyte); + rest_alignedbytes = (ctx->output.fifo >> + (64 - ctx->output.num_bits)) & + ((1ULL << numof_aligned_rembits) - 1); + + if ((currentbyte == (1 << (rembitsinbyte - 1))) && + (numof_aligned_rembits == 0 || (rest_alignedbytes == 0 && + ((((((unsigned int)numof_aligned_rembits >> 3)) < + ctx->input.emprev_seq_len) && + ctx->input.num_bytes == 0) || ctx->input.no_moredata)))) + moredata = 0; + else + moredata = 1; + } + + *more_rbsp_data = moredata; + + return 0; +} + +unsigned int swsr_read_onebit(void *ctx_hndl) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + unsigned int bitread; + + /* Validate input arguments. */ + if (!ctx_hndl) { + VDEC_ASSERT(0); + return -EIO; + } + + ctx = (struct swsr_context *)ctx_hndl; + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + /* Optimize with inline code (specific version of call below). */ + bitread = swsr_read_bits(ctx, 1); + + return bitread; +} + +unsigned int swsr_read_bits(void *ctx_hndl, unsigned int no_bits) +{ + struct swsr_context *ctx; + + /* Validate input arguments. */ + if (!ctx_hndl) { + VDEC_ASSERT(0); + return -EIO; + } + + ctx = (struct swsr_context *)ctx_hndl; + + /* Validate input arguments. */ + if (!ctx->initialised) { + pr_err("%s: Invalid SWSR context\n", __func__); + ctx->exception = SWSR_EXCEPT_INVALID_CONTEXT; + ctx->exception_handler_fxn(ctx->exception, ctx->pexception_param); + + return 0; + } + + if (no_bits > SWSR_MAX_SYNTAX_LENGTH) { + pr_err("Maximum symbol length exceeded\n"); + ctx->exception = SWSR_EXCEPT_WRONG_CODEWORD_ERROR; + ctx->exception_handler_fxn(ctx->exception, ctx->pexception_param); + + return 0; + } + + return swsr_getbits_from_outputfifo(ctx, no_bits, 1); +} + +int swsr_read_signedbits(void *ctx_hndl, unsigned int no_bits) +{ + struct swsr_context *ctx; + int outbits = 0; + + /* Validate input arguments. */ + if (!ctx_hndl) { + VDEC_ASSERT(0); + return -EIO; + } + + ctx = (struct swsr_context *)ctx_hndl; + + /* Check if the context has been initialized. */ + if (!ctx->initialised) { + pr_err("%s: Invalid SWSR context\n", __func__); + ctx->exception = SWSR_EXCEPT_INVALID_CONTEXT; + ctx->exception_handler_fxn(ctx->exception, ctx->pexception_param); + + return 0; + } + + if ((no_bits + 1) > SWSR_MAX_SYNTAX_LENGTH) { + pr_err("Maximum symbol length exceeded\n"); + ctx->exception = SWSR_EXCEPT_WRONG_CODEWORD_ERROR; + ctx->exception_handler_fxn(ctx->exception, ctx->pexception_param); + + return 0; + } + outbits = swsr_getbits_from_outputfifo(ctx, no_bits, 1); + + return (swsr_getbits_from_outputfifo(ctx, 1, 1)) ? -outbits : outbits; +} + +unsigned int swsr_peekbits(void *ctx_hndl, unsigned int no_bits) +{ + struct swsr_context *ctx; + + /* validate input parameters */ + if (!ctx_hndl) { + VDEC_ASSERT(0); + return -EIO; + } + + ctx = (struct swsr_context *)ctx_hndl; + + /* Validate input arguments. */ + if (!ctx->initialised) { + pr_err("%s: Invalid SWSR context\n", __func__); + ctx->exception = SWSR_EXCEPT_INVALID_CONTEXT; + ctx->exception_handler_fxn(ctx->exception, ctx->pexception_param); + + return 0; + } + + if (no_bits > SWSR_MAX_SYNTAX_LENGTH) { + pr_err("Maximum symbol length exceeded\n"); + ctx->exception = SWSR_EXCEPT_WRONG_CODEWORD_ERROR; + ctx->exception_handler_fxn(ctx->exception, ctx->pexception_param); + + return 0; + } + + return swsr_getbits_from_outputfifo(ctx, no_bits, 0); +} + +int swsr_byte_align(void *ctx_hndl) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + unsigned int numbits; + + /* Validate input arguments. */ + if (!ctx) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + numbits = (ctx->output.num_bits & 0x7); + /* Read the required number of bits if not already byte-aligned. */ + if (numbits != 0) + swsr_read_bits(ctx, numbits); + + SWSR_ASSERT((ctx->output.num_bits & 0x7) == 0); + + return 0; +} + +int swsr_get_total_bitsconsumed(void *ctx_hndl, unsigned long long *total_bitsconsumed) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + + /* Validate input arguments. */ + if (!ctx || !total_bitsconsumed) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + *total_bitsconsumed = ctx->output.totalbits_consumed; + + return 0; +} + +int swsr_get_byte_offset_curbuf(void *ctx_hndl, unsigned long long *byte_offset) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + struct swsr_buffer *outbuf; + + /* Validate input arguments. */ + if (!ctx || !byte_offset) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + if (ctx->output.num_bits != 0) { + pr_err("SWSR output FIFO not empty. First seek to next delimiter: %s\n", + __func__); + return IMG_ERROR_OPERATION_PROHIBITED; + } + + outbuf = lst_first(&ctx->buffer_ctx.used_buffer_list); + if (outbuf) + *byte_offset = outbuf->num_bytes_read; + else + return IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + + return 0; +} + +static int swsr_update_emprevent(enum swsr_emprevent emprevent, + struct swsr_context *ctx) +{ + struct swsr_input *input; + + input = &ctx->input; + + input->emprevent = emprevent; + switch (input->emprevent) { + case SWSR_EMPREVENT_00000300: + input->emprev_seq_len = 4; + break; + + case SWSR_EMPREVENT_ff00: + input->emprev_seq_len = 2; + break; + + case SWSR_EMPREVENT_000002: + input->emprev_seq_len = 3; + break; + + default: + input->emprev_seq_len = 0; + break; + } + + return 0; +} + +int swsr_consume_delim(void *ctx_hndl, enum swsr_emprevent emprevent, + unsigned int size_delim_length, unsigned long long *byte_count) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + struct swsr_input *input; + unsigned long long delimiter = 0; + + /* Validate input arguments. */ + if (!ctx || emprevent >= SWSR_EMPREVENT_MAX || + (ctx->input.config.delim_type == SWSR_DELIM_SIZE && + size_delim_length > SWSR_MAX_DELIM_LENGTH)) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + if (ctx->input.config.delim_type == SWSR_DELIM_SIZE && + size_delim_length == 0 && !byte_count) { + pr_err("Byte count value must be provided when size delimiter is zero length: %s\n", + __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + input = &ctx->input; + + /* + * Ensure that the input is at a delimiter since emulation prevention + * removal will not have spanned into this next unit. + * This allows emulation prevention detection modes to be changed. + * Now check for delimiter. + */ + input->delim_found = swsr_checkfor_delimiter(ctx); + + if (!input->delim_found) + return IMG_ERROR_UNEXPECTED_STATE; + + /* Output bitstream FIFOs should be empty. */ + /* NOTE: flush output queue using seek function. */ + SWSR_ASSERT(ctx->output.num_bits == 0); + + /* Only update the delimiter length for size delimiters. */ + if (input->config.delim_type == SWSR_DELIM_SIZE) + input->config.delim_length = size_delim_length; + + /* Update the emulation prevention detection/removal scheme */ + swsr_update_emprevent(emprevent, ctx); + + /* + * Peek at the NAL type and return in callback only + * when delimiter is in bitstream. + */ + if (input->config.delim_length) { + unsigned int shift; + unsigned char naltype; + + /* + * Peek at the next 8-bits after the delimiter that + * resides in internal FIFO. + */ + shift = SWSR_OUTPUT_FIFO_LENGTH - + (input->config.delim_length + SWSR_NALTYPE_LENGTH); + naltype = (input->fifo >> shift) & NBIT_8BYTE_MASK(SWSR_NALTYPE_LENGTH); + + /* + * Notify caller of NAL type so that bitstream segmentation + * can take place before the delimiter is consumed + */ + ctx->buffer_ctx.cb_fxn(SWSR_EVENT_DELIMITER_NAL_TYPE, ctx->buffer_ctx.cb_param, + naltype, NULL, NULL); + } + + /* + * Clear the delimiter found flag and reset bytes read to allow + * reading of data from input FIFO. + */ + input->delim_found = 0; + + if (input->config.delim_length != 0) { + unsigned long long scpvalue = input->config.scp_value; + unsigned int i; + unsigned char byte = 0; + + /* + * Ensure that delimiter is not detected while delimiter + * is read. + */ + if (input->config.delim_type == SWSR_DELIM_SIZE) { + input->bytes_read_since_delim = 0; + input->byte_count = (input->config.delim_length + 7) / 8; + } else if (input->config.delim_type == SWSR_DELIM_SCP) { + input->config.scp_value = 0xdeadbeefdeadbeefUL; + } + + /* + * Fill output FIFO only with bytes at least partially + * used for delimiter. + */ + for (i = 0; i < ((input->config.delim_length + 7) / 8); i++) { + swsr_readbyte_from_inputfifo(ctx, &byte); + + ctx->output.fifo |= ((unsigned long long)byte << + (SWSR_OUTPUT_FIFO_LENGTH - 8 - ctx->output.num_bits)); + ctx->output.num_bits += 8; + } + + /* + * Read delimiter from output FIFO leaving any remaining + * non-byte-aligned bits behind. + */ + delimiter = swsr_getbits_from_outputfifo(ctx, input->config.delim_length, 1); + + /* Restore SCP value. */ + if (input->config.delim_type == SWSR_DELIM_SCP) + input->config.scp_value = scpvalue; + } else { + /* + * For size delimited bitstreams without a delimiter use + * the byte count provided. + */ + SWSR_ASSERT(*byte_count > 0); + delimiter = *byte_count; + SWSR_ASSERT(input->config.delim_type == SWSR_DELIM_SIZE); + } + + if (input->config.delim_type == SWSR_DELIM_SCP) + SWSR_ASSERT((delimiter & NBIT_8BYTE_MASK(input->config.delim_length)) == + input->config.scp_value); + else if (input->config.delim_type == SWSR_DELIM_SIZE) { + input->byte_count = delimiter; + + /* Return byte count if argument provided. */ + if (byte_count) + *byte_count = input->byte_count; + } + + input->bytes_read_since_delim = 0; + { + struct swsr_buffer *buffer = input->buf; + + if (!buffer) + buffer = lst_first(&ctx->buffer_ctx.used_buffer_list); + if (buffer) + input->delimited_unit_start_offset = (long)buffer->num_bytes_read; + else + input->delimited_unit_start_offset = 0; + } + input->delimited_unit_size = 0; + input->delimunit_bitofst = 0; + + input->no_moredata = 0; + + return 0; +} + +enum swsr_found swsr_seek_delim_or_eod(void *ctx_hndl) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + enum swsr_found found = SWSR_FOUND_DATA; + unsigned char byte; + + /* Validate input arguments. */ + if (!ctx) { + pr_err("Invalid arguments to function: %s\n", __func__); + return (enum swsr_found)IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return (enum swsr_found)IMG_ERROR_NOT_INITIALISED; + } + + /* Read the residual contents of the output FIFO */ + swsr_byte_align(ctx); + while (ctx->output.num_bits > 0) { + SWSR_ASSERT((ctx->output.num_bits & 0x7) == 0); + swsr_read_bits(ctx, 8); + } + SWSR_ASSERT(ctx->output.num_bits == 0); + if (ctx->input.config.delim_type == SWSR_DELIM_SCP) { + struct swsr_input *input = &ctx->input; + struct swsr_output *output = &ctx->output; + + while (found == SWSR_FOUND_DATA) { + unsigned char *offset; + unsigned int delimlength_inbytes; + unsigned char *startoffset; + unsigned long long mask; + unsigned long long scp; + unsigned char scpfirstbyte; + + /* + * ensure that all the data in the input FIFO comes + * from the current buffer + */ + if (input->buf && input->buf->byte_offset <= input->num_bytes) { + found = swsr_consumebyte_from_inputfifo(ctx, &byte); + continue; + } + + /* consume remaining bytes from the FIFO */ + if (!input->buf) { + found = swsr_consumebyte_from_inputfifo(ctx, &byte); + continue; + } + + delimlength_inbytes = (input->config.delim_length + 7) / 8; + + /* + * Make the mask and the scp value byte aligned to + * speed up things + */ + mask = ((1UL << input->config.delim_length) - 1) << + (8 * delimlength_inbytes - input->config.delim_length); + scp = input->config.scp_value << + (8 * delimlength_inbytes - input->config.delim_length); + scpfirstbyte = (scp >> 8 * (delimlength_inbytes - 1)) & 0xFF; + + /* rollback the input FIFO */ + input->buf->byte_offset -= input->num_bytes; + input->buf->num_bytes_read -= input->num_bytes; + input->bitstream_offset -= input->num_bytes; + input->num_bytes = 0; + input->fifo = 0; + + startoffset = input->buf->data + input->buf->byte_offset; + + while (found == SWSR_FOUND_DATA) { + offset = memchr(input->buf->data + input->buf->byte_offset, + scpfirstbyte, + input->buf->num_bytes - + (input->buf->byte_offset + delimlength_inbytes - + 1)); + + if (offset) { + unsigned int i; + + /* + * load bytes that might be SCP into + * the FIFO + */ + for (i = 0; i < delimlength_inbytes; i++) { + input->fifo <<= 8; + input->fifo |= offset[i]; + } + + input->buf->byte_offset = offset - input->buf->data; + + if ((input->fifo & mask) == scp) { + unsigned long long bytesread = offset + - startoffset; + + /* + * Scp found, fill the rest of + * the FIFO + */ + for (i = delimlength_inbytes; + i < SWSR_INPUT_FIFO_LENGTH && + input->buf->byte_offset + i < + input->buf->num_bytes; + i++) { + input->fifo <<= 8; + input->fifo |= offset[i]; + } + + input->fifo <<= (SWSR_INPUT_FIFO_LENGTH - i) * 8; + + input->bytes_for_next_sequ = 0; + input->num_bytes = i; + + input->buf->byte_offset += i; + + input->buf->num_bytes_read = offset - + input->buf->data; + input->bitstream_offset += bytesread + i; + + output->totalbits_consumed += bytesread * 8; + + input->delimunit_bitofst += bytesread * 8; + + output->num_bits = 0; + output->fifo = 0; + + SWSR_ASSERT(swsr_checkfor_delimiter(ctx)); + + found = SWSR_FOUND_DELIM; + } else { + input->buf->byte_offset++; + } + } else { + /* End of the current buffer */ + unsigned int bytesread = input->buf->num_bytes - + (startoffset - input->buf->data); + unsigned int i; + + /* update offsets */ + input->bitstream_offset += bytesread; + output->totalbits_consumed += bytesread * 8; + input->delimunit_bitofst += bytesread * 8; + + input->buf->byte_offset = input->buf->num_bytes; + input->buf->num_bytes_read = input->buf->num_bytes - + (delimlength_inbytes - 1); + + /* load remaining bytes to FIFO */ + offset = input->buf->data + + input->buf->num_bytes - + (delimlength_inbytes - 1); + for (i = 0; i < delimlength_inbytes - 1; + i++) { + input->fifo <<= 8; + input->fifo |= offset[i]; + } + + input->fifo <<= (SWSR_INPUT_FIFO_LENGTH - i) * 8; + + input->bytes_for_next_sequ = 0; + input->num_bytes = delimlength_inbytes - 1; + + output->num_bits = 0; + output->fifo = 0; + + /* + * Consume a few bytes from the next + * byte to check if there is scp on + * buffers boundary + */ + for (i = 0; + i < delimlength_inbytes && found == SWSR_FOUND_DATA; + i++) { + found = swsr_consumebyte_from_inputfifo(ctx, &byte); + SWSR_ASSERT(found != SWSR_FOUND_NONE); + } + + break; + } + } + } + } else { + /* + * Extract data from input FIFO until data is not found either + * because we have run out or a SCP has been detected. + */ + while (found == SWSR_FOUND_DATA) { + found = swsr_consumebyte_from_inputfifo(ctx, &byte); + SWSR_ASSERT(found != SWSR_FOUND_NONE); + } + } + + /* + * When the end of data has been reached there should be no + * more data in the input FIFO. + */ + if (found == SWSR_FOUND_EOD) + SWSR_ASSERT(ctx->input.num_bytes == 0); + + SWSR_ASSERT(found != SWSR_FOUND_DATA); + return found; +} + +enum swsr_found swsr_check_delim_or_eod(void *ctx_hndl) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + enum swsr_found found = SWSR_FOUND_DATA; + + /* Validate input arguments. */ + if (!ctx) { + pr_err("Invalid arguments to function: %s\n", __func__); + + return (enum swsr_found)IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + + return (enum swsr_found)IMG_ERROR_NOT_INITIALISED; + } + + /* + * End of data when all FIFOs are empty and there is nothing left to + * read from the input buffers. + */ + if (ctx->output.num_bits == 0 && ctx->input.num_bytes == 0 && + ctx->input.bitstream_offset >= ctx->input.bitstream_size) + found = SWSR_FOUND_EOD; + else if (ctx->output.num_bits == 0 && swsr_checkfor_delimiter(ctx)) { + /* + * Output queue is empty and delimiter is at the head of + * input queue. + */ + found = SWSR_FOUND_DELIM; + } + + return found; +} + +int swsr_start_bitstream(void *ctx_hndl, const struct swsr_config *config, + unsigned long long bitstream_size, enum swsr_emprevent emprevent) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + struct swsr_buffer *buffer; + unsigned int result; + + /* Validate input arguments. */ + if (!ctx || !config || config->delim_type >= SWSR_DELIM_MAX || + config->delim_length > SWSR_MAX_DELIM_LENGTH || + config->scp_value > NBIT_8BYTE_MASK(config->delim_length) || + emprevent >= SWSR_EMPREVENT_MAX) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + /* Move all used buffers into free list */ + buffer = lst_removehead(&ctx->buffer_ctx.used_buffer_list); + while (buffer) { + lst_add(&ctx->buffer_ctx.free_buffer_list, buffer); + buffer = lst_removehead(&ctx->buffer_ctx.used_buffer_list); + } + + /* Clear all the shift-register state (except config) */ + memset(&ctx->input, 0, sizeof(ctx->input)); + memset(&ctx->output, 0, sizeof(ctx->output)); + + /* Update input FIFO configuration */ + ctx->input.bitstream_size = bitstream_size; + ctx->input.config = *config; + result = swsr_update_emprevent(emprevent, ctx); + SWSR_ASSERT(result == 0); + + /* + * Signal delimiter found to ensure that no data is read out of + * input FIFO + * while fetching the first bitstream data into input FIFO. + */ + ctx->input.delim_found = 1; + result = swsr_fill_outputfifo(ctx); + SWSR_ASSERT(result == 0); + + /* Now check for delimiter. */ + ctx->input.delim_found = swsr_checkfor_delimiter(ctx); + + return 0; +} + +int swsr_deinitialise(void *ctx_hndl) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + struct swsr_buffer *buffer; + + /* Validate input arguments. */ + if (!ctx) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + /* Free all used buffer containers */ + buffer = lst_removehead(&ctx->buffer_ctx.used_buffer_list); + while (buffer) { + kfree(buffer); + buffer = lst_removehead(&ctx->buffer_ctx.used_buffer_list); + } + + /* Free all free buffer containers. */ + buffer = lst_removehead(&ctx->buffer_ctx.free_buffer_list); + while (buffer) { + kfree(buffer); + buffer = lst_removehead(&ctx->buffer_ctx.free_buffer_list); + } + + ctx->initialised = 0; + kfree(ctx); + + return 0; +} + +int swsr_initialise(swsr_except_handler_fxn exception_handler_fxn, + void *exception_cbparam, swsr_callback_fxn callback_fxn, + void *cb_param, void **ctx_hndl) +{ + struct swsr_context *ctx; + struct swsr_buffer *buffer; + unsigned int i; + unsigned int result; + + /* Validate input arguments. */ + if (!exception_handler_fxn || !exception_cbparam || !callback_fxn || + !cb_param || !ctx_hndl) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Allocate and initialise shift-register context */ + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + VDEC_ASSERT(0); + return -EINVAL; + } + + /* Setup shift-register context */ + ctx->exception_handler_fxn = exception_handler_fxn; + ctx->pexception_param = exception_cbparam; + + ctx->buffer_ctx.cb_fxn = callback_fxn; + ctx->buffer_ctx.cb_param = cb_param; + + /* + * Allocate a new buffer container for each byte in internal storage. + * This is the theoretical maximum number of buffers in the SWSR at + * any one time. + */ + for (i = 0; i < SWSR_INPUT_FIFO_LENGTH + (SWSR_OUTPUT_FIFO_LENGTH / 8); + i++) { + /* Allocate a buffer container */ + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + SWSR_ASSERT(buffer); + if (!buffer) { + result = IMG_ERROR_OUT_OF_MEMORY; + goto error; + } + + /* Add container to free list */ + lst_add(&ctx->buffer_ctx.free_buffer_list, buffer); + } + + SWSR_ASSERT(SWSR_MAX_SYNTAX_LENGTH <= (sizeof(unsigned int) * 8)); + + ctx->initialised = 1; + *ctx_hndl = ctx; + + return 0; +error: + buffer = lst_removehead(&ctx->buffer_ctx.free_buffer_list); + while (buffer) { + kfree(buffer); + buffer = lst_removehead(&ctx->buffer_ctx.free_buffer_list); + } + kfree(ctx); + + return result; +} + +static unsigned char swsr_israwdata_extraction_supported(struct swsr_context *ctx) +{ + /* + * For now only h.264/HEVC like 0x000001 SCP delimited + * bistreams are supported. + */ + if (ctx->input.config.delim_type == SWSR_DELIM_SCP && + ctx->input.config.delim_length == (3 * 8) && + ctx->input.config.scp_value == 0x000001) + return 1; + + return 0; +} + +static int swsr_getcurrent_delimited_unitsize(struct swsr_context *ctx, unsigned int *size) +{ + struct swsr_buffer *buf; + + buf = ctx->input.buf; + if (!buf) + buf = lst_first(&ctx->buffer_ctx.used_buffer_list); + + if (buf && ctx->input.delimited_unit_start_offset >= 0 && + ctx->input.delimited_unit_start_offset < buf->num_bytes) { + unsigned long long bufptr = + (unsigned long long)ctx->input.delimited_unit_start_offset; + unsigned int zeros = 0; + + /* Scan the current buffer for the next SCP. */ + while (1) { + /* Look for two consecutive 0 bytes. */ + while ((bufptr < buf->num_bytes) && (zeros < 2)) { + if (buf->data[bufptr++] == 0) + zeros++; + else + zeros = 0; + } + /* + * If we're not at the end of the buffer already and + * the next byte is 1, we've got it. + */ + /* + * If we're at the end of the buffer, just assume + * we've got it too + * as we do not support buffer spanning units. + */ + if (bufptr < buf->num_bytes && buf->data[bufptr] == 1) { + break; + } else if (bufptr == buf->num_bytes) { + zeros = 0; + break; + } + /* + * Finally just decrease the number of 0s found + * already and go on scanning. + */ + else + zeros = 1; + } + /* Calculate the unit size. */ + ctx->input.delimited_unit_size = (unsigned int)(bufptr - + (unsigned long long)ctx->input.delimited_unit_start_offset) - zeros; + *size = ctx->input.delimited_unit_size; + } else { + return IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + } + + return 0; +} + +int swsr_get_current_delimited_unitsize(void *ctx_hndl, unsigned int *size) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + + /* Validate input arguments. */ + if (!ctx || !size) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + if (!swsr_israwdata_extraction_supported(ctx)) + return IMG_ERROR_NOT_SUPPORTED; + + return swsr_getcurrent_delimited_unitsize(ctx, size); +} + +int swsr_get_current_delimited_unit(void *ctx_hndl, unsigned char *data, unsigned int *size) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + struct swsr_buffer *buf; + unsigned int copysize; + + /* Validate input arguments. */ + if (!ctx || !data || !size || *size == 0) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + if (!swsr_israwdata_extraction_supported(ctx)) + return IMG_ERROR_NOT_SUPPORTED; + + buf = ctx->input.buf; + if (!buf) + buf = lst_first(&ctx->buffer_ctx.used_buffer_list); + + if (buf && ctx->input.delimited_unit_start_offset >= 0) { + if (ctx->input.delimited_unit_size == 0) + swsr_getcurrent_delimited_unitsize(ctx, ©size); + + if (ctx->input.delimited_unit_size < *size) + *size = ctx->input.delimited_unit_size; + + memcpy(data, buf->data + ctx->input.delimited_unit_start_offset, *size); + } else { + return IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + } + + return 0; +} + +int swsr_get_current_delimited_unit_bit_offset(void *ctx_hndl, unsigned int *bit_offset) +{ + struct swsr_context *ctx = (struct swsr_context *)ctx_hndl; + + /* Validate input arguments. */ + if (!ctx || !bit_offset) { + pr_err("Invalid arguments to function: %s\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!ctx->initialised) { + pr_err("SWSR not yet initialised: %s\n", __func__); + return IMG_ERROR_NOT_INITIALISED; + } + + if (!swsr_israwdata_extraction_supported(ctx)) + return IMG_ERROR_NOT_SUPPORTED; + + if (ctx->input.delimited_unit_start_offset >= 0) + *bit_offset = ctx->input.delimunit_bitofst; + + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/swsr.h b/drivers/media/platform/imagination/vxe-vxd/decoder/swsr.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/swsr.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/swsr.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,278 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Software Shift Register Access fucntions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstreming + * Prashanth Kumar Amai + * Sidraya Jayagond + */ +#ifndef _SWSR_H +#define _SWSR_H + +#include + +#include "img_errors.h" +#include "lst.h" + +#define SWSR_MAX_DELIM_LENGTH (8 * 8) + +enum swsr_exception { + SWSR_EXCEPT_NO_EXCEPTION = 0x00, + SWSR_EXCEPT_ENCAPULATION_ERROR1, + SWSR_EXCEPT_ENCAPULATION_ERROR2, + SWSR_EXCEPT_ACCESS_INTO_SCP, + SWSR_EXCEPT_ACCESS_BEYOND_EOD, + SWSR_EXCEPT_EXPGOULOMB_ERROR, + SWSR_EXCEPT_WRONG_CODEWORD_ERROR, + SWSR_EXCEPT_NO_SCP, + SWSR_EXCEPT_INVALID_CONTEXT, + SWSR_EXCEPT_FORCE32BITS = 0x7FFFFFFFU +}; + +enum swsr_cbevent { + SWSR_EVENT_INPUT_BUFFER_START = 0, + SWSR_EVENT_OUTPUT_BUFFER_END, + SWSR_EVENT_DELIMITER_NAL_TYPE, + SWSR_EVENT_FORCE32BITS = 0x7FFFFFFFU +}; + +enum swsr_found { + SWSR_FOUND_NONE = 0, + SWSR_FOUND_EOD, + SWSR_FOUND_DELIM, + SWSR_FOUND_DATA, + SWSR_FOUND_FORCE32BITS = 0x7FFFFFFFU +}; + +enum swsr_delim_type { + SWSR_DELIM_NONE = 0, + SWSR_DELIM_SCP, + SWSR_DELIM_SIZE, + SWSR_DELIM_MAX, + SWSR_DELIM_FORCE32BITS = 0x7FFFFFFFU +}; + +enum swsr_emprevent { + SWSR_EMPREVENT_NONE = 0x00, + SWSR_EMPREVENT_00000300, + SWSR_EMPREVENT_ff00, + SWSR_EMPREVENT_000002, + SWSR_EMPREVENT_MAX, + SWSR_EMPREVENT_FORCE32BITS = 0x7FFFFFFFU +}; + +struct swsr_config { + enum swsr_delim_type delim_type; + unsigned int delim_length; + unsigned long long scp_value; +}; + +/* + * This is the function prototype for the caller supplier exception handler. + * + * NOTE: The internally recorded exception is reset to #SWSR_EXCEPT_NO_EXCEPTION + * on return from SWSR_CheckException() or a call to the caller supplied + * exception handler see #SWSR_pfnExceptHandler. + * + * NOTE: By defining an exception handler the caller can handle Shift Register + * errors as they occur - for example, using a structure exception mechanism + * such as setjmp/longjmp. + */ +typedef void (*swsr_except_handler_fxn)(enum swsr_exception exception, + void *callback_param); + +/* + * This is the function prototype for the caller supplier to retrieve the data + * from the application + */ +typedef void (*swsr_callback_fxn)(enum swsr_cbevent event, + void *priv_data, + unsigned char nal_type, unsigned char **data_buffer, + unsigned long long *data_size); + +int swsr_get_total_bitsconsumed(void *context, unsigned long long *total_bitsconsumed); + +/* + * This function is used to return the offset into the current bitstream buffer + * on the shift-register output FIFO. Call after #SWSR_SeekDelimOrEOD to + * determine the offset of an delimiter. + */ +int swsr_get_byte_offset_curbuf(void *context, unsigned long long *byte_offset); + +/* + * This function is used to read a signed Exp-Goulomb value from the Shift + * Register. + * + * NOTE: If this function is used to attempt to read into a Start-Code-Prefix + * or beyond the End-Of-Data then and exception is generated which can be + * handled by the caller supplied exception handler see + * #SWSR_pfnExceptionHandler. If no exception handler has been supplied (or the + * exception handler returns) then the exception is recorded and can be obtained + * using SWSR_CheckException(). In this event the function returns 0. + */ +int swsr_read_signed_expgoulomb(void *context); + +/* + * This function is used to read a unsigned Exp-Goulomb value from the Shift + * Register. + * + * NOTE: If this function is used to attempt to read into a Start-Code-Prefix + * or beyond the End-Of-Data then and exception is generated which can be + * handled by the caller supplied exception handler see + * #SWSR_pfnExceptionHandler. If no exception handler has been supplied (or the + * exception handler returns) then the exception is recorded and can be obtained + * using SWSR_CheckException(). In this event the function returns 0. + */ +unsigned int swsr_read_unsigned_expgoulomb(void *context); + +/* + * This function is used to check for exceptions. + * + * NOTE: The internally recorded exception is reset to #SWSR_EXCEPT_NO_EXCEPTION + * on return from SWSR_CheckException() or a call to the caller supplied + * exception handler see #SWSR_pfnExceptionHandler. + */ +enum swsr_exception swsr_check_exception(void *context); + +/* + * This function is used to check for bitstream data with + * SWSR_EMPREVENT_00000300 whether more RBSP data is present. + */ +int swsr_check_more_rbsp_data(void *context, unsigned char *more_rbsp_data); + +/* + * This function is used to read a single bit from the Shift Register. + * + * NOTE: If this function is used to attempt to read into a Start-Code-Prefix + * or beyond the End-Of-Data then and exception is generated which can be + * handled by the caller supplied exception handler see + * #SWSR_pfnExceptionHandler. If no exception handler has been supplied (or the + * exception handler returns) then the exception is recorded and can be obtained + * using SWSR_CheckException(). In this event the function returns 0. + */ +unsigned int swsr_read_onebit(void *context); + +/* + * This function is used to consume a number of bits from the Shift Register. + * + * NOTE: If this function is used to attempt to read into a Start-Code-Prefix + * or beyond the End-Of-Data then and exception is generated which can be + * handled by the caller supplied exception handler see + * #SWSR_pfnExceptionHandler. If no exception handler has been supplied (or the + * exception handler returns) then the exception is recorded and can be obtained + * using SWSR_CheckException(). In this event the function returns 0. + */ +unsigned int swsr_read_bits(void *context, unsigned int no_bits); + +int swsr_read_signedbits(void *context, unsigned int no_bits); + +/* + * This function is used to peek at number of bits from the Shift Register. The + * bits are not consumed. + * + * NOTE: If this function is used to attempt to read into a Start-Code-Prefix + * or beyond the End-Of-Data then and exception is generated which can be + * handled by the caller supplied exception handler see + * #SWSR_pfnExceptionHandler. If no exception handler has been supplied (or + * the exception handler returns) then the exception is recorded and can be + * obtained using SWSR_CheckException(). In this event the function returns 0. + */ +unsigned int swsr_peekbits(void *context, unsigned int no_bits); + +/* + * Makes the shift-register output byte-aligned by consuming the remainder of + * the current partially read byte. + */ +int swsr_byte_align(void *context); + +/* + * Consume the next delimiter whose length should be specified if delimiter type + * is #SWSR_DELIM_SIZE. The emulation prevention detection/removal scheme can + * also be specified for this and subsequent units. + * + * Consumes the unit delimiter from the bitstream buffer. The delimiter type + * depends upon the bitstream format. + */ +int swsr_consume_delim(void *context, + enum swsr_emprevent emprevent, + unsigned int size_delim_length, + unsigned long long *byte_count); + +/* + * Seek for the next delimiter or end of bitstream data if no delimiter is + * found. + */ +enum swsr_found swsr_seek_delim_or_eod(void *context); + +/* + * Check if shift-register is at a delimiter or end of data. + */ +enum swsr_found swsr_check_delim_or_eod(void *context); + +/* + * This function automatically fetches the first bitstream buffer (using + * callback with event type #SWSR_EVENT_INPUT_BUFFER_START) before returning. + */ +int swsr_start_bitstream(void *context, + const struct swsr_config *pconfig, + unsigned long long bitstream_size, + enum swsr_emprevent emprevent); + +/* + * This function is used to de-initialise the Shift Register. + */ +int swsr_deinitialise(void *context); + +/* + * This function is used to initialise the Shift Register. + * + * NOTE: If no exception handler is provided (pfnExceptionHandler == IMG_NULL) + * then the caller must check for exceptions using the function + * SWSR_CheckException(). + * + * NOTE: If pui8RbduBuffer is IMG_NULL then the bit stream is not encapsulated + * so the Shift Register needn't perform and de-encapsulation. However, + * if this is not IMG_NULL then, from time to time, the Shift Register APIs + * will de-encapsulate portions of the bit stream into this intermediate buffer + * - the larger the buffer the less frequent the de-encapsulation function + * needs to be called. + */ +int swsr_initialise(swsr_except_handler_fxn exception_handler_fxn, + void *exception_cbparam, + swsr_callback_fxn callback_fxn, + void *cb_param, + void **context); + +/* + * This function is used to return the size in bytes of the delimited unit + * that's currently being processed. + * + * NOTE: This size includes all the emulation prevention bytes present + * in the delimited unit. + */ +int swsr_get_current_delimited_unitsize(void *context, unsigned int *size); + +/* + * This function is used to copy the delimited unit that's currently being + * processed to the provided buffer. + * + * NOTE: This delimited unit includes all the emulation prevention bytes present + * in it. + */ +int swsr_get_current_delimited_unit(void *context, unsigned char *data, unsigned int *size); + +/* + * This function is used to return the bit offset the shift register is at + * in processing the current delimited unit. + * + * NOTE: This offset does not count emulation prevention bytes. + */ +int swsr_get_current_delimited_unit_bit_offset(void *context, unsigned int *bit_offset); + +#endif /* _SWSR_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/translation_api.c b/drivers/media/platform/imagination/vxe-vxd/decoder/translation_api.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/translation_api.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/translation_api.c 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,1725 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VDECDD translation APIs. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +/* As of now we are defining HAS_H264 */ +#define HAS_H264 +#define VDEC_USE_PVDEC + +#include +#include +#include +#include +#include + +#include "fw_interface.h" +#ifdef HAS_H264 +#include "h264fw_data.h" +#endif /* HAS_H264 */ +#include "hw_control.h" +#include "img_errors.h" +#include "img_msvdx_cmds.h" +#include "img_msvdx_vec_regs.h" +#ifdef VDEC_USE_PVDEC +#include "pvdec_int.h" +#include "img_pvdec_core_regs.h" +#endif +#include "img_video_bus4_mmu_regs.h" +#include "lst.h" +#include "reg_io2.h" +#include "rman_api.h" +#include "translation_api.h" +#include "vdecdd_defs.h" +#include "vdecdd_utils.h" +#include "vdecfw_share.h" +#include "vxd_int.h" +#include "vxd_props.h" + +#ifdef HAS_HEVC +#include "hevcfw_data.h" +#include "pvdec_entropy_regs.h" +#include "pvdec_vec_be_regs.h" +#endif + +#ifdef HAS_JPEG +#include "jpegfw_data.h" +#endif /* HAS_JPEG */ + +#define NO_VALUE 0 + +/* + * Discontinuity in layout of VEC_VLC_TABLE* registers. + * Address of VEC_VLC_TABLE_ADDR16 does not immediately follow + * VEC_VLC_TABLE_ADDR15, see TRM. + */ +#define VEC_VLC_TABLE_ADDR_PT1_SIZE 16 /* in 32-bit words */ +#define VEC_VLC_TABLE_ADDR_DISCONT (VEC_VLC_TABLE_ADDR_PT1_SIZE * \ + PVDECIO_VLC_IDX_ADDR_PARTS) + +/* + * now it can be done by VXD_GetCodecMode + * Imply standard from OperatingMode. + * As of now only H264 supported through the file. + */ +#define CODEC_MODE_JPEG 0x0 +#define CODEC_MODE_H264 0x1 +#define CODEC_MODE_REAL8 0x8 +#define CODEC_MODE_REAL9 0x9 + +/* + * This enum defines values of ENTDEC_BE_MODE field of VEC_ENTDEC_BE_CONTROL + * register and ENTDEC_FE_MODE field of VEC_ENTDEC_FE_CONTROL register. + */ +enum decode_mode { + /* JPEG */ + VDEC_ENTDEC_MODE_JPEG = 0x0, + /* H264 (MPEG4/AVC) */ + VDEC_ENTDEC_MODE_H264 = 0x1, + VDEC_ENTDEC_MODE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This has all that it needs to translate a Stream Unit for a picture into a + * transaction. + */ +static int translation_set_buffer(struct vdecdd_ddpict_buf *picbuf, + struct vdecfw_image_buffer *image_buffer) +{ + unsigned int i; + + for (i = 0; i < VDEC_PLANE_MAX; i++) { + image_buffer->byte_offset[i] = + (unsigned int)GET_HOST_ADDR(&picbuf->pict_buf->ddbuf_info) + + picbuf->rend_info.plane_info[i].offset; + pr_debug("%s image_buffer->byte_offset[%d] = 0x%x\n", + __func__, i, image_buffer->byte_offset[i]); + } + return IMG_SUCCESS; +} + +#ifdef HAS_HEVC +/* + * @Function translation_hevc_header + */ +static int translation_hevc_header(struct vdecdd_picture *picture, + struct dec_decpict *dec_pict, + struct hevcfw_headerdata *header_data) +{ + translation_set_buffer(dec_pict->recon_pict, &header_data->primary); + + if (dec_pict->alt_pict) + translation_set_buffer(dec_pict->alt_pict, &header_data->alternate); + + VDEC_ASSERT(picture); + VDEC_ASSERT(picture->pict_res_int); + VDEC_ASSERT(picture->pict_res_int->mb_param_buf); + header_data->temporal_outaddr = (unsigned int)GET_HOST_ADDR + (&picture->pict_res_int->mb_param_buf->ddbuf_info); + + return IMG_SUCCESS; +} +#endif + +#ifdef HAS_H264 +static int translation_h264header(struct vdecdd_picture *pspicture, + struct dec_decpict *dec_pict, + struct h264fw_header_data *psheaderdata, + struct vdec_str_configdata *psstrconfigdata) +{ + psheaderdata->two_pass_flag = dec_pict->pict_hdr_info->discontinuous_mbs; + psheaderdata->disable_mvc = psstrconfigdata->disable_mvc; + + /* + * As of now commenting the mb params base address as we are not using, + * if needed in future please un comment and make the allocation for + * pict_res_int. + */ + /* Obtain the MB parameter address from the stream unit. */ + if (pspicture->pict_res_int->mb_param_buf) { + psheaderdata->mbparams_base_address = + (unsigned int)GET_HOST_ADDR(&pspicture->pict_res_int->mb_param_buf->ddbuf_info); + psheaderdata->mbparams_size_per_plane = + pspicture->pict_res_int->mb_param_buf->ddbuf_info.buf_size / 3; + } else { + psheaderdata->mbparams_base_address = 0; + psheaderdata->mbparams_size_per_plane = 0; + } + psheaderdata->slicegroupmap_base_address = + (unsigned int)GET_HOST_ADDR(&dec_pict->cur_pict_dec_res->h264_sgm_buf); + + translation_set_buffer(dec_pict->recon_pict, &psheaderdata->primary); + + if (dec_pict->alt_pict) + translation_set_buffer(dec_pict->alt_pict, &psheaderdata->alternate); + + /* Signal whether we have PPS for the second field. */ + if (pspicture->dec_pict_aux_info.second_pps_id == BSPP_INVALID) + psheaderdata->second_pps = 0; + else + psheaderdata->second_pps = 1; + + return IMG_SUCCESS; +} +#endif /* HAS_H264 */ + +#ifdef HAS_JPEG + +static int translation_jpegheader(const struct bspp_sequ_hdr_info *seq, + const struct dec_decpict *dec_pict, + const struct bspp_pict_hdr_info *pict_hdrinfo, + struct jpegfw_header_data *header_data) +{ + unsigned int i; + + /* Output picture planes addresses */ + for (i = 0; i < seq->com_sequ_hdr_info.pixel_info.num_planes; i++) { + header_data->plane_offsets[i] = + (unsigned int)GET_HOST_ADDR(&dec_pict->recon_pict->pict_buf->ddbuf_info) + + dec_pict->recon_pict->rend_info.plane_info[i].offset; + } + + /* copy the expected SOS fields number */ + header_data->hdr_sos_count = pict_hdrinfo->sos_count; + + translation_set_buffer(dec_pict->recon_pict, &header_data->primary); + + return IMG_SUCCESS; +} +#endif /* HAS_JPEG */ +/* + * This function translates host video standard enum (VDEC_eVidStd) into + * firmware video standard enum (VDECFW_eCodecType); + */ +static int translation_get_codec(enum vdec_vid_std evidstd, + enum vdecfw_codectype *pecodec) +{ + enum vdecfw_codectype ecodec = VDEC_CODEC_NONE; + unsigned int result = IMG_ERROR_NOT_SUPPORTED; + + /* Translate from video standard to firmware codec. */ + switch (evidstd) { + #ifdef HAS_H264 + case VDEC_STD_H264: + ecodec = VDECFW_CODEC_H264; + result = IMG_SUCCESS; + break; + #endif /* HAS_H264 */ +#ifdef HAS_HEVC + case VDEC_STD_HEVC: + ecodec = VDECFW_CODEC_HEVC; + result = IMG_SUCCESS; + break; +#endif /* HAS_HEVC */ +#ifdef HAS_JPEG + case VDEC_STD_JPEG: + ecodec = VDECFW_CODEC_JPEG; + result = IMG_SUCCESS; + break; +#endif + default: + result = IMG_ERROR_NOT_SUPPORTED; + break; + } + *pecodec = ecodec; + return result; +} + +/* + * This function is used to obtain buffer for sequence header. + */ +static int translation_get_seqhdr(struct vdecdd_str_unit *psstrunit, + struct dec_decpict *psdecpict, + unsigned int *puipseqaddr) +{ + /* + * ending Sequence info only if its a First Pic of Sequence, or a Start + * of Closed GOP + */ + if (psstrunit->pict_hdr_info->first_pic_of_sequence || psstrunit->closed_gop) { + struct vdecdd_ddbuf_mapinfo *ddbuf_map_info; + /* Get access to map info context */ + int result = rman_get_resource(psstrunit->seq_hdr_info->bufmap_id, + VDECDD_BUFMAP_TYPE_ID, + (void **)&ddbuf_map_info, NULL); + VDEC_ASSERT(result == IMG_SUCCESS); + if (result != IMG_SUCCESS) + return result; + + *puipseqaddr = GET_HOST_ADDR_OFFSET(&ddbuf_map_info->ddbuf_info, + psstrunit->seq_hdr_info->buf_offset); + } else { + *puipseqaddr = 0; + } + return IMG_SUCCESS; +} + +/* + * This function is used to obtain buffer for picture parameter set. + */ +static int translation_get_ppshdr(struct vdecdd_str_unit *psstrunit, + struct dec_decpict *psdecpict, + unsigned int *puipppsaddr) +{ + if (psstrunit->pict_hdr_info->pict_aux_data.id != BSPP_INVALID) { + struct vdecdd_ddbuf_mapinfo *ddbuf_map_info; + int result; + + VDEC_ASSERT(psstrunit->pict_hdr_info->pict_aux_data.pic_data); + /* Get access to map info context */ + result = rman_get_resource(psstrunit->pict_hdr_info->pict_aux_data.bufmap_id, + VDECDD_BUFMAP_TYPE_ID, + (void **)&ddbuf_map_info, NULL); + VDEC_ASSERT(result == IMG_SUCCESS); + + if (result != IMG_SUCCESS) + return result; + *puipppsaddr = + GET_HOST_ADDR_OFFSET(&ddbuf_map_info->ddbuf_info, + psstrunit->pict_hdr_info->pict_aux_data.buf_offset); + } else { + *puipppsaddr = 0; + } + return IMG_SUCCESS; +} + +/* + * This function is used to obtain buffer for second picture parameter set. + */ +static int translation_getsecond_ppshdr(struct vdecdd_str_unit *psstrunit, + unsigned int *puisecond_ppshdr) +{ + if (psstrunit->pict_hdr_info->second_pict_aux_data.id != + BSPP_INVALID) { + struct vdecdd_ddbuf_mapinfo *ddbuf_map_info; + int result; + void *pic_data = + psstrunit->pict_hdr_info->second_pict_aux_data.pic_data; + + VDEC_ASSERT(pic_data); + result = rman_get_resource(psstrunit->pict_hdr_info->second_pict_aux_data.bufmap_id, + VDECDD_BUFMAP_TYPE_ID, + (void **)&ddbuf_map_info, NULL); + VDEC_ASSERT(result == IMG_SUCCESS); + + if (result != IMG_SUCCESS) + return result; + + *puisecond_ppshdr = + GET_HOST_ADDR_OFFSET + (&ddbuf_map_info->ddbuf_info, + psstrunit->pict_hdr_info->second_pict_aux_data.buf_offset); + } else { + *puisecond_ppshdr = 0; + } + return IMG_SUCCESS; +} + +/* + * Returns address from which FW should download its shared context. + */ +static unsigned int translation_getctx_loadaddr(struct dec_decpict *psdecpict) +{ + if (psdecpict->prev_pict_dec_res) + return GET_HOST_ADDR(&psdecpict->prev_pict_dec_res->fw_ctx_buf); + + /* + * No previous context exists, using current context leads to + * problems on replay so just say to FW to use clean one. + * This is NULL as integer to avoid pointer size warnings due + * to type casting. + */ + return 0; +} + +static void translation_setup_std_header + (struct vdec_str_configdata *str_configdata, + struct dec_decpict *dec_pict, + struct vdecdd_str_unit *str_unit, unsigned int *psr_hdrsize, + struct vdecdd_picture *picture, unsigned int *picture_cmds, + enum vdecfw_parsermode *parser_mode) +{ + switch (str_configdata->vid_std) { +#ifdef HAS_H264 + case VDEC_STD_H264: + { + struct h264fw_header_data *header_data = + (struct h264fw_header_data *) + dec_pict->hdr_info->ddbuf_info->cpu_virt; + *parser_mode = str_unit->pict_hdr_info->parser_mode; + + if (str_unit->pict_hdr_info->parser_mode != + VDECFW_SCP_ONLY) { + pr_warn("VDECFW_SCP_ONLY mode supported in PVDEC FW\n"); + } + /* Reset header data. */ + memset(header_data, 0, sizeof(*(header_data))); + + /* Prepare active parameter sets. */ + translation_h264header(picture, dec_pict, header_data, str_configdata); + + /* Setup header size in the transaction. */ + *psr_hdrsize = sizeof(struct h264fw_header_data); + break; + } +#endif /* HAS_H264 */ + +#ifdef HAS_HEVC + case VDEC_STD_HEVC: + { + struct hevcfw_headerdata *header_data = + (struct hevcfw_headerdata *)dec_pict->hdr_info->ddbuf_info->cpu_virt; + *parser_mode = str_unit->pict_hdr_info->parser_mode; + + /* Reset header data. */ + memset(header_data, 0, sizeof(*header_data)); + + /* Prepare active parameter sets. */ + translation_hevc_header(picture, dec_pict, header_data); + + /* Setup header size in the transaction. */ + *psr_hdrsize = sizeof(struct hevcfw_headerdata); + break; + } +#endif +#ifdef HAS_JPEG + case VDEC_STD_JPEG: + { + struct jpegfw_header_data *header_data = + (struct jpegfw_header_data *)dec_pict->hdr_info->ddbuf_info->cpu_virt; + const struct bspp_sequ_hdr_info *seq = str_unit->seq_hdr_info; + const struct bspp_pict_hdr_info *pict_hdr_info = str_unit->pict_hdr_info; + + /* Reset header data. */ + memset(header_data, 0, sizeof(*(header_data))); + + /* Prepare active parameter sets. */ + translation_jpegheader(seq, dec_pict, pict_hdr_info, header_data); + + /* Setup header size in the transaction. */ + *psr_hdrsize = sizeof(struct jpegfw_header_data); + break; + } +#endif + default: + VDEC_ASSERT(NULL == "Unknown standard!"); + *psr_hdrsize = 0; + break; + } +} + +#define VDEC_INITIAL_DEVA_DMA_CMD_SIZE 3 +#define VDEC_SINLGE_DEVA_DMA_CMD_SIZE 2 + +#ifdef VDEC_USE_PVDEC +/* + * Creates DEVA bitstream segments command and saves is to control allocation + * buffer. + */ +static int translation_pvdec_adddma_transfers + (struct lst_t *decpic_seglist, unsigned int **dma_cmdbuf, + int cmd_bufsize, struct dec_decpict *psdecpict, int eop) +{ + /* + * DEVA's bitstream DMA command is made out of chunks with following + * layout ('+' sign is used to mark actual words in command): + * + * + Bitstream HDR, type unsigned int, consists of: + * - command id (CMD_BITSTREAM_SEGMENTS), + * - number of segments in this chunk, + * - optional CMD_BITSTREAM_SEGMENTS_MORE_FOLLOW_MASK + * + * + Bitstream total size, type unsigned int, + * represents size of all segments in all chunks + * + * Segments of following type (can repeat up to + * CMD_BITSTREAM_SEGMENTS_MINUS1_MASK + 1 times) + * + * + Bitstream segment address, type unsigned int + * + * + Bitstream segment size, type unsigned int + * + * Subsequent chunks are present when + * CMD_BITSTREAM_SEGMENTS_MORE_FOLLOW_MASK flag is set in Bitstream HDR. + */ + struct dec_decpict_seg *dec_picseg = (struct dec_decpict_seg *)lst_first(decpic_seglist); + unsigned int *cmd = *dma_cmdbuf; + unsigned int *dma_hdr = cmd; + unsigned int segcount = 0; + unsigned int bitstream_size = 0; + + /* + * Two words for DMA command header (setup later as we need to find out + * count of BS segments). + */ + cmd += CMD_BITSTREAM_HDR_DW_SIZE; + cmd_bufsize -= CMD_BITSTREAM_HDR_DW_SIZE; + if (cmd_bufsize < 0) { + pr_err("Buffer for DMA command too small.\n"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!dec_picseg) { + /* No segments to be send to FW: preparing fake one */ + cmd_bufsize -= VDEC_SINLGE_DEVA_DMA_CMD_SIZE; + if (cmd_bufsize < 0) { + pr_err("Buffer for DMA command too small.\n"); + return IMG_ERROR_INVALID_PARAMETERS; + } + segcount++; + + /* zeroing bitstream size and bitstream offset */ + *(cmd++) = 0; + *(cmd++) = 0; + } + + /* Loop through all bitstream segments */ + while (dec_picseg) { + if (dec_picseg->bstr_seg && (dec_picseg->bstr_seg->bstr_seg_flag + & VDECDD_BSSEG_SKIP) == 0) { + unsigned int result; + struct vdecdd_ddbuf_mapinfo *ddbuf_map_info; + + segcount++; + /* Two words for each added bitstream segment */ + cmd_bufsize -= VDEC_SINLGE_DEVA_DMA_CMD_SIZE; + if (cmd_bufsize < 0) { + pr_err("Buffer for DMA command too small.\n"); + return IMG_ERROR_INVALID_PARAMETERS; + } + /* Insert SCP/SC if needed */ + if (dec_picseg->bstr_seg->bstr_seg_flag & + VDECDD_BSSEG_INSERTSCP) { + unsigned int startcode_length = + psdecpict->start_code_bufinfo->buf_size; + + if (dec_picseg->bstr_seg->bstr_seg_flag & + VDECDD_BSSEG_INSERT_STARTCODE) { + unsigned char *start_code = + psdecpict->start_code_bufinfo->cpu_virt; + start_code[startcode_length - 1] = + dec_picseg->bstr_seg->start_code_suffix; + } else { + startcode_length -= 1; + } + + segcount++; + *(cmd++) = startcode_length; + bitstream_size += startcode_length; + + *(cmd++) = psdecpict->start_code_bufinfo->dev_virt; + + if (((segcount % + (CMD_BITSTREAM_SEGMENTS_MINUS1_MASK + 1)) == 0)) + /* + * we have reached max number of + * bitstream segments for current + * command make pui32Cmd point to next + * BS command + */ + cmd += CMD_BITSTREAM_HDR_DW_SIZE; + } + /* Get access to map info context */ + result = rman_get_resource(dec_picseg->bstr_seg->bufmap_id, + VDECDD_BUFMAP_TYPE_ID, + (void **)&ddbuf_map_info, NULL); + VDEC_ASSERT(result == IMG_SUCCESS); + if (result != IMG_SUCCESS) + return result; + + *(cmd++) = (dec_picseg->bstr_seg->data_size); + bitstream_size += dec_picseg->bstr_seg->data_size; + + *(cmd++) = ddbuf_map_info->ddbuf_info.dev_virt + + dec_picseg->bstr_seg->data_byte_offset; + + if (((segcount % + (CMD_BITSTREAM_SEGMENTS_MINUS1_MASK + 1)) == 0) && + (lst_next(dec_picseg))) + /* + * we have reached max number of bitstream + * segments for current command make pui32Cmd + * point to next BS command + */ + cmd += CMD_BITSTREAM_HDR_DW_SIZE; + } + dec_picseg = lst_next(dec_picseg); + } + + if (segcount > CMD_BITSTREAM_SEGMENTS_MAX_NUM) { + pr_err("Too many bitstream segments to transfer.\n"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + while (segcount > (CMD_BITSTREAM_SEGMENTS_MINUS1_MASK + 1)) { + *dma_hdr++ = CMD_BITSTREAM_SEGMENTS | + CMD_BITSTREAM_SEGMENTS_MORE_FOLLOW_MASK | + CMD_BITSTREAM_SEGMENTS_MINUS1_MASK; + *dma_hdr++ = bitstream_size; + /* + * make pui32DmaHdr point to next chunk by skipping bitstream + * Segments + */ + dma_hdr += (2 * (CMD_BITSTREAM_SEGMENTS_MINUS1_MASK + 1)); + segcount -= (CMD_BITSTREAM_SEGMENTS_MINUS1_MASK + 1); + } + *dma_hdr = eop ? CMD_BITSTREAM_EOP_MASK : 0; + *dma_hdr++ |= CMD_BITSTREAM_SEGMENTS | (segcount - 1); + *dma_hdr = bitstream_size; + + /* + * Let caller know where we finished. Pointer to location one word after + * end of our command buffer + */ + *dma_cmdbuf = cmd; + return IMG_SUCCESS; +} + +/* + * Creates DEVA control allocation buffer header. + */ +static void translation_pvdec_ctrl_setuphdr + (struct ctrl_alloc_header *ctrlalloc_hdr, + unsigned int *pic_cmds) +{ + ctrlalloc_hdr->cmd_additional_params = CMD_CTRL_ALLOC_HEADER; + ctrlalloc_hdr->ext_opmode = pic_cmds[VDECFW_CMD_EXT_OP_MODE]; + ctrlalloc_hdr->chroma_strides = + pic_cmds[VDECFW_CMD_CHROMA_ROW_STRIDE]; + ctrlalloc_hdr->alt_output_addr[0] = + pic_cmds[VDECFW_CMD_LUMA_ALTERNATIVE_PICTURE_BASE_ADDRESS]; + ctrlalloc_hdr->alt_output_addr[1] = + pic_cmds[VDECFW_CMD_CHROMA_ALTERNATIVE_PICTURE_BASE_ADDRESS]; + ctrlalloc_hdr->alt_output_flags = + pic_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_PICTURE_ROTATION]; +} + +/* + * Creates DEVA VLC DMA command and saves is to control allocation buffer. + */ +static int translation_pvdecsetup_vlcdma + (struct vidio_ddbufinfo *vlctables_bufinfo, + unsigned int **dmacmd_buf, unsigned int cmdbuf_size) +{ + unsigned int cmd_dma; + unsigned int *cmd = *dmacmd_buf; + + /* Check if VLC tables fit in one DMA transfer */ + if (vlctables_bufinfo->buf_size > CMD_DMA_DMA_SIZE_MASK) { + pr_err("VLC tables won't fit into one DMA transfer!\n"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Check if we have enough space in control allocation buffer. */ + if (cmdbuf_size < VDEC_SINLGE_DEVA_DMA_CMD_SIZE) { + pr_err("Buffer for DMA command too small.\n"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Construct DMA command */ + cmd_dma = CMD_DMA | CMD_DMA_TYPE_VLC_TABLE | + vlctables_bufinfo->buf_size; + + /* Add command to control allocation */ + *cmd++ = cmd_dma; + *cmd++ = vlctables_bufinfo->dev_virt; + + /* + * Let caller know where we finished. Pointer to location one word after + * end of our command buffer + */ + *dmacmd_buf = cmd; + return IMG_SUCCESS; +} + +/* + * Creates DEVA commands for configuring VLC tables and saves them into + * control allocation buffer. + */ +static int translation_pvdecsetup_vlctables + (unsigned short vlc_index_data[][3], unsigned int num_tables, + unsigned int **ctrl_allocbuf, unsigned int ctrl_allocsize, + unsigned int msvdx_vecoffset) +{ + unsigned int i; + unsigned int word_count; + unsigned int reg_val; + unsigned int *ctrl_allochdr; + + unsigned int *ctrl_alloc = *ctrl_allocbuf; + + /* Calculate the number of words needed for VLC control allocations. */ + /* + * 3 words for control allocation headers (we are writing 3 chunks: + * addresses, widths, opcodes) + */ + unsigned int req_elems = 3 + + (ALIGN(num_tables, PVDECIO_VLC_IDX_WIDTH_PARTS) / + PVDECIO_VLC_IDX_WIDTH_PARTS) + + (ALIGN(num_tables, PVDECIO_VLC_IDX_ADDR_PARTS) / + PVDECIO_VLC_IDX_ADDR_PARTS) + + (ALIGN(num_tables, PVDECIO_VLC_IDX_OPCODE_PARTS) / + PVDECIO_VLC_IDX_OPCODE_PARTS); + + /* + * Addresses chunk has to be split in two, if number of tables exceeds + * VEC_VLC_TABLE_ADDR_DISCONT (see layout of VEC_VLC_TABLE_ADDR* + * registers in TRM) + */ + if (num_tables > VEC_VLC_TABLE_ADDR_DISCONT) + /* We need additional control allocation header */ + req_elems += 1; + + if (ctrl_allocsize < req_elems) { + pr_err("Buffer for VLC IDX commands too small.\n"); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* + * Write VLC IDX addresses. Chunks for VEC_VLC_TABLE_ADDR[0-15] and + * VEC_VLC_TABLE_ADDR[16-18] registers. + */ + ctrl_allochdr = ctrl_alloc++; + *ctrl_allochdr = CMD_REGISTER_BLOCK | CMD_REGISTER_BLOCK_FLAG_VLC_DATA | + (MSVDX_VEC_CR_VEC_VLC_TABLE_ADDR0_OFFSET + msvdx_vecoffset); + /* Reset the word count. */ + word_count = 0; + + /* Process VLC index table. */ + i = 0; + reg_val = 0; + while (i < num_tables) { + VDEC_ASSERT((vlc_index_data[i][PVDECIO_VLC_IDX_ADDR_ID] & + ~PVDECIO_VLC_IDX_ADDR_MASK) == 0); + /* Pack the addresses into a word. */ + reg_val |= ((vlc_index_data[i][PVDECIO_VLC_IDX_ADDR_ID] & + PVDECIO_VLC_IDX_ADDR_MASK) << + ((i % PVDECIO_VLC_IDX_ADDR_PARTS) * + PVDECIO_VLC_IDX_ADDR_SHIFT)); + + /* If we reached the end of VEC_VLC_TABLE_ADDR[0-15] area... */ + if (i == VEC_VLC_TABLE_ADDR_DISCONT) { + /* + * Finalize command header for VEC_VLC_TABLE_ADDR[0-15] + * register chunk. + */ + *ctrl_allochdr |= word_count << 16; + /* + * Reserve and preset command header for + * VEC_VLC_TABLE_ADDR[16-18] register chunk. + */ + ctrl_allochdr = ctrl_alloc++; + *ctrl_allochdr = CMD_REGISTER_BLOCK | + CMD_REGISTER_BLOCK_FLAG_VLC_DATA | + (MSVDX_VEC_CR_VEC_VLC_TABLE_ADDR16_OFFSET + + msvdx_vecoffset); + /* Reset the word count. */ + word_count = 0; + } + + /* + * If all the addresses are packed in this word or that's the + * last iteration + */ + if (((i % PVDECIO_VLC_IDX_ADDR_PARTS) == + (PVDECIO_VLC_IDX_ADDR_PARTS - 1)) || + (i == (num_tables - 1))) { + /* + * Add VLC table address to this chunk and increase + * words count. + */ + *ctrl_alloc++ = reg_val; + word_count++; + /* Reset address value. */ + reg_val = 0; + } + + i++; + } + + /* + * Finalize the current command header for VEC_VLC_TABLE_ADDR register + * chunk. + */ + *ctrl_allochdr |= word_count << 16; + + /* + * Start new commands chunk for VEC_VLC_TABLE_INITIAL_WIDTH[0-3] + * registers. + */ + + /* + * Reserve and preset command header for + * VEC_VLC_TABLE_INITIAL_WIDTH[0-3] register chunk. + */ + ctrl_allochdr = ctrl_alloc++; + *ctrl_allochdr = CMD_REGISTER_BLOCK | CMD_REGISTER_BLOCK_FLAG_VLC_DATA | + (MSVDX_VEC_CR_VEC_VLC_TABLE_INITIAL_WIDTH0_OFFSET + + msvdx_vecoffset); + /* Reset the word count. */ + word_count = 0; + + /* Process VLC index table. */ + i = 0; + reg_val = 0; + + while (i < num_tables) { + VDEC_ASSERT((vlc_index_data[i][PVDECIO_VLC_IDX_WIDTH_ID] & + ~PVDECIO_VLC_IDX_WIDTH_MASK) == 0); + /* Pack the widths into a word. */ + reg_val |= ((vlc_index_data[i][PVDECIO_VLC_IDX_WIDTH_ID] & + PVDECIO_VLC_IDX_WIDTH_MASK) << + (i % PVDECIO_VLC_IDX_WIDTH_PARTS) * + PVDECIO_VLC_IDX_WIDTH_SHIFT); + + /* + * If all the widths are packed in this word or that's the last + * iteration. + */ + if (((i % PVDECIO_VLC_IDX_WIDTH_PARTS) == + (PVDECIO_VLC_IDX_WIDTH_PARTS - 1)) || + (i == (num_tables - 1))) { + /* + * Add VLC table width to this chunk and increase words + * count. + */ + *ctrl_alloc++ = reg_val; + word_count++; + /* Reset width value. */ + reg_val = 0; + } + i++; + } + + /* + * Finalize command header for VEC_VLC_TABLE_INITIAL_WIDTH[0-3] register + * chunk. + */ + *ctrl_allochdr |= word_count << 16; + + /* + * Start new commands chunk for VEC_VLC_TABLE_INITIAL_OPCODE[0-2] + * registers. + * Reserve and preset command header for + * VEC_VLC_TABLE_INITIAL_OPCODE[0-2] register chunk + */ + ctrl_allochdr = ctrl_alloc++; + *ctrl_allochdr = CMD_REGISTER_BLOCK | CMD_REGISTER_BLOCK_FLAG_VLC_DATA | + (MSVDX_VEC_CR_VEC_VLC_TABLE_INITIAL_OPCODE0_OFFSET + + msvdx_vecoffset); + /* Reset the word count. */ + word_count = 0; + + /* Process VLC index table. */ + i = 0; + reg_val = 0; + + while (i < num_tables) { + VDEC_ASSERT((vlc_index_data[i][PVDECIO_VLC_IDX_OPCODE_ID] & + ~PVDECIO_VLC_IDX_OPCODE_MASK) == 0); + /* Pack the opcodes into a word. */ + reg_val |= ((vlc_index_data[i][PVDECIO_VLC_IDX_OPCODE_ID] & + PVDECIO_VLC_IDX_OPCODE_MASK) << + (i % PVDECIO_VLC_IDX_OPCODE_PARTS) * + PVDECIO_VLC_IDX_OPCODE_SHIFT); + + /* + * If all the opcodes are packed in this word or that's the last + * iteration. + */ + if (((i % PVDECIO_VLC_IDX_OPCODE_PARTS) == + (PVDECIO_VLC_IDX_OPCODE_PARTS - 1)) || + (i == (num_tables - 1))) { + /* + * Add VLC table opcodes to this chunk and increase + * words count. + */ + *ctrl_alloc++ = reg_val; + word_count++; + /* Reset width value. */ + reg_val = 0; + } + i++; + } + + /* + * Finalize command header for VEC_VLC_TABLE_INITIAL_OPCODE[0-2] + * register chunk. + */ + *ctrl_allochdr |= word_count << 16; + + /* Update caller with current location of control allocation pointer */ + *ctrl_allocbuf = ctrl_alloc; + return IMG_SUCCESS; +} + +/* + * fills in a rendec command chunk in the command buffer. + */ +static void fill_rendec_chunk(int num, ...) +{ + va_list valist; + unsigned int i, j = 0; + unsigned int chunk_word_count = 0; + unsigned int used_word_count = 0; + int aux_array_size = 0; + unsigned int *pic_cmds; + unsigned int **ctrl_allocbuf; + unsigned int ctrl_allocsize; + unsigned int vdmc_cmd_offset; + unsigned int offset; + unsigned int *buf; + /* 5 is the fixed arguments passed to fill_rendec_chunk function */ + enum vdecfw_picture_cmds *aux_array = kmalloc((sizeof(unsigned int) * + (num - 5)), GFP_KERNEL); + if (!aux_array) + return; + + /* initialize valist for num number of arguments */ + va_start(valist, num); + + pic_cmds = va_arg(valist, unsigned int *); + ctrl_allocbuf = va_arg(valist, unsigned int **); + ctrl_allocsize = va_arg(valist, unsigned int); + vdmc_cmd_offset = va_arg(valist, unsigned int); + offset = va_arg(valist, unsigned int); + buf = *ctrl_allocbuf; + + aux_array_size = (sizeof(unsigned int) * (num - 5)); + /* + * access all the arguments assigned to valist, we have already + * read till 5 + */ + for (i = 6, j = 0; i <= num; i++, j++) + aux_array[j] = (enum vdecfw_picture_cmds)va_arg(valist, int); + + /* clean memory reserved for valist */ + va_end(valist); + chunk_word_count = aux_array_size / + sizeof(enum vdecfw_picture_cmds); + if ((chunk_word_count + 1) > (ctrl_allocsize - used_word_count)) { + kfree(aux_array); + return; + } + if ((chunk_word_count & ~(CMD_RENDEC_WORD_COUNT_MASK >> + CMD_RENDEC_WORD_COUNT_SHIFT)) != 0) { + kfree(aux_array); + return; + } + used_word_count += chunk_word_count + 1; + *buf++ = CMD_RENDEC_BLOCK | (chunk_word_count << 16) | + (vdmc_cmd_offset + offset); + + for (i = 0; i < chunk_word_count; i++) + *buf++ = pic_cmds[aux_array[i]]; + + *ctrl_allocbuf = buf; + /* free the memory */ + kfree(aux_array); +} + +/* + * Creates DEVA commands for configuring rendec and writes them into control + * allocation buffer. + */ +static void translation_pvdec_setup_commands(unsigned int *pic_cmds, + unsigned int **ctrl_allocbuf, + unsigned int ctrl_allocsize, + unsigned int vdmc_cmd_offset) +{ + unsigned int codec_mode; + + codec_mode = REGIO_READ_FIELD(pic_cmds[VDECFW_CMD_OPERATING_MODE], + MSVDX_CMDS, OPERATING_MODE, CODEC_MODE); + + if (codec_mode != CODEC_MODE_H264) + /* chunk with cache settings at 0x01C */ + /* + * here first argument 6 says there are 6 number of arguments + * being passed to fill_rendec_chunk function. + */ + fill_rendec_chunk(6, pic_cmds, ctrl_allocbuf, ctrl_allocsize, + vdmc_cmd_offset, + MSVDX_CMDS_MC_CACHE_CONFIGURATION_OFFSET, + VDECFW_CMD_MC_CACHE_CONFIGURATION); + + /* chunk with extended row stride at 0x03C */ + /* + * here first argument 6 says there are 6 number of arguments + * being passed to fill_rendec_chunk function. + */ + fill_rendec_chunk(6, pic_cmds, ctrl_allocbuf, ctrl_allocsize, + vdmc_cmd_offset, + MSVDX_CMDS_EXTENDED_ROW_STRIDE_OFFSET, + VDECFW_CMD_EXTENDED_ROW_STRIDE); + + /* chunk with alternative output control at 0x1B4 */ + /* + * here first argument 6 says there are 6 number of arguments + * being passed to fill_rendec_chunk function. + */ + fill_rendec_chunk(6, pic_cmds, ctrl_allocbuf, ctrl_allocsize, + vdmc_cmd_offset, + MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_OFFSET, + VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL); + + /* scaling chunks */ + if (pic_cmds[VDECFW_CMD_SCALED_DISPLAY_SIZE]) { + if (codec_mode != CODEC_MODE_REAL8 && codec_mode != CODEC_MODE_REAL9) { + /* + * chunk with scale display size, scale H/V control at + * 0x0050 + */ + /* + * here first argument 8 says there are 8 number of + * arguments being passed to fill_rendec_chunk function. + */ + fill_rendec_chunk(8, pic_cmds, ctrl_allocbuf, + ctrl_allocsize, vdmc_cmd_offset, + MSVDX_CMDS_SCALED_DISPLAY_SIZE_OFFSET, + VDECFW_CMD_SCALED_DISPLAY_SIZE, + VDECFW_CMD_HORIZONTAL_SCALE_CONTROL, + VDECFW_CMD_VERTICAL_SCALE_CONTROL); + + /* chunk with luma/chorma H/V coeffs at 0x0060 */ + /* + * here first argument 21 says there are 21 number of + * arguments being passed to fill_rendec_chunk function. + */ + fill_rendec_chunk(21, pic_cmds, ctrl_allocbuf, + ctrl_allocsize, vdmc_cmd_offset, + MSVDX_CMDS_HORIZONTAL_LUMA_COEFFICIENTS_OFFSET, + VDECFW_CMD_HORIZONTAL_LUMA_COEFFICIENTS_0, + VDECFW_CMD_HORIZONTAL_LUMA_COEFFICIENTS_1, + VDECFW_CMD_HORIZONTAL_LUMA_COEFFICIENTS_2, + VDECFW_CMD_HORIZONTAL_LUMA_COEFFICIENTS_3, + VDECFW_CMD_VERTICAL_LUMA_COEFFICIENTS_0, + VDECFW_CMD_VERTICAL_LUMA_COEFFICIENTS_1, + VDECFW_CMD_VERTICAL_LUMA_COEFFICIENTS_2, + VDECFW_CMD_VERTICAL_LUMA_COEFFICIENTS_3, + VDECFW_CMD_HORIZONTAL_CHROMA_COEFFICIENTS_0, + VDECFW_CMD_HORIZONTAL_CHROMA_COEFFICIENTS_1, + VDECFW_CMD_HORIZONTAL_CHROMA_COEFFICIENTS_2, + VDECFW_CMD_HORIZONTAL_CHROMA_COEFFICIENTS_3, + VDECFW_CMD_VERTICAL_CHROMA_COEFFICIENTS_0, + VDECFW_CMD_VERTICAL_CHROMA_COEFFICIENTS_1, + VDECFW_CMD_VERTICAL_CHROMA_COEFFICIENTS_2, + VDECFW_CMD_VERTICAL_CHROMA_COEFFICIENTS_3); + + /* + * chunk with scale output size, scale H/V chroma at + * 0x01B8 + */ + /* + * here first argument 8 says there are 8 number of + * arguments being passed to fill_rendec_chunk function. + */ + fill_rendec_chunk(8, pic_cmds, ctrl_allocbuf, + ctrl_allocsize, vdmc_cmd_offset, + MSVDX_CMDS_SCALE_OUTPUT_SIZE_OFFSET, + VDECFW_CMD_SCALE_OUTPUT_SIZE, + VDECFW_CMD_SCALE_HORIZONTAL_CHROMA, + VDECFW_CMD_SCALE_VERTICAL_CHROMA); + } + } +} + +#ifdef HAS_HEVC +/* + * @Function translation_pvdec_setup_pvdec_commands + */ +static int translation_pvdec_setup_pvdec_commands(struct vdecdd_picture *picture, + struct dec_decpict *dec_pict, + struct vdecdd_str_unit *str_unit, + struct decoder_regsoffsets *regs_offsets, + unsigned int **ctrl_allocbuf, + unsigned int ctrl_alloc_size, + unsigned int *mem_to_reg_host_part, + unsigned int *pict_cmds) +{ + const unsigned int genc_buf_cnt = 4; + /* We have two chunks: for GENC buffers addresses and sizes*/ + const unsigned int genc_conf_items = 2; + const unsigned int pipe = 0xf << 16; /* Instruct H/W to write to current pipe */ + /* We need to configure address and size of each GENC buffer */ + const unsigned int genc_words_cnt = genc_buf_cnt * genc_conf_items; + struct vdecdd_ddbuf_mapinfo **genc_buffers = + picture->pict_res_int->seq_resint->genc_buffers; + unsigned int memto_reg_used; /* in bytes */ + unsigned int i; + unsigned int *ctrl_alloc = *ctrl_allocbuf; + unsigned int *mem_to_reg = (unsigned int *)dec_pict->pvdec_info->ddbuf_info->cpu_virt; + unsigned int reg = 0; + + if (ctrl_alloc_size < genc_words_cnt + genc_conf_items) { + pr_err("Buffer for GENC config too small."); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Insert command header for GENC buffers sizes */ + *ctrl_alloc++ = CMD_REGISTER_BLOCK | (genc_buf_cnt << 16) | + (PVDEC_ENTROPY_CR_GENC_BUFFER_SIZE_OFFSET + regs_offsets->entropy_offset); + for (i = 0; i < genc_buf_cnt; i++) + *ctrl_alloc++ = genc_buffers[i]->ddbuf_info.buf_size; + + /* Insert command header for GENC buffers addresses */ + *ctrl_alloc++ = CMD_REGISTER_BLOCK | (genc_buf_cnt << 16) | + (PVDEC_ENTROPY_CR_GENC_BUFFER_BASE_ADDRESS_OFFSET + regs_offsets->entropy_offset); + for (i = 0; i < genc_buf_cnt; i++) + *ctrl_alloc++ = genc_buffers[i]->ddbuf_info.dev_virt; + + /* Insert GENC fragment buffer address */ + *ctrl_alloc++ = CMD_REGISTER_BLOCK | (1 << 16) | + (PVDEC_ENTROPY_CR_GENC_FRAGMENT_BASE_ADDRESS_OFFSET + regs_offsets->entropy_offset); + *ctrl_alloc++ = picture->pict_res_int->genc_fragment_buf->ddbuf_info.dev_virt; + + /* Return current location in control allocation buffer to caller */ + *ctrl_allocbuf = ctrl_alloc; + + reg = 0; + REGIO_WRITE_FIELD_LITE + (reg, + MSVDX_CMDS, PVDEC_DISPLAY_PICTURE_SIZE, PVDEC_DISPLAY_PICTURE_WIDTH_MIN1, + str_unit->pict_hdr_info->coded_frame_size.width - 1, unsigned int); + REGIO_WRITE_FIELD_LITE + (reg, + MSVDX_CMDS, PVDEC_DISPLAY_PICTURE_SIZE, PVDEC_DISPLAY_PICTURE_HEIGHT_MIN1, + str_unit->pict_hdr_info->coded_frame_size.height - 1, unsigned int); + + /* + * Pvdec operating mode needs to be submitted before any other commands. + * This will be set in FW. Make sure it's the first command in Mem2Reg buffer. + */ + VDEC_ASSERT((unsigned int *)dec_pict->pvdec_info->ddbuf_info->cpu_virt == mem_to_reg); + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_PVDEC_OPERATING_MODE_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = 0x0; /* has to be updated in the F/W */ + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_MC_CACHE_CONFIGURATION_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = 0x0; /* has to be updated in the F/W */ + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_PVDEC_DISPLAY_PICTURE_SIZE_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = reg; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_PVDEC_CODED_PICTURE_SIZE_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = reg; + + /* scaling configuration */ + if (pict_cmds[VDECFW_CMD_SCALED_DISPLAY_SIZE]) { + *mem_to_reg++ = pipe | + (MSVDX_CMDS_PVDEC_SCALED_DISPLAY_SIZE_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_SCALED_DISPLAY_SIZE]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_HORIZONTAL_SCALE_CONTROL_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_HORIZONTAL_SCALE_CONTROL]; + *mem_to_reg++ = pipe | + (MSVDX_CMDS_VERTICAL_SCALE_CONTROL_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_VERTICAL_SCALE_CONTROL]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_SCALE_OUTPUT_SIZE_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_SCALE_OUTPUT_SIZE]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_SCALE_HORIZONTAL_CHROMA_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_SCALE_HORIZONTAL_CHROMA]; + *mem_to_reg++ = pipe | + (MSVDX_CMDS_SCALE_VERTICAL_CHROMA_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_SCALE_VERTICAL_CHROMA]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_HORIZONTAL_LUMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_HORIZONTAL_LUMA_COEFFICIENTS_0]; + *mem_to_reg++ = pipe | + (4 + MSVDX_CMDS_HORIZONTAL_LUMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_HORIZONTAL_LUMA_COEFFICIENTS_1]; + *mem_to_reg++ = pipe | + (8 + MSVDX_CMDS_HORIZONTAL_LUMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_HORIZONTAL_LUMA_COEFFICIENTS_2]; + *mem_to_reg++ = pipe | + (12 + MSVDX_CMDS_HORIZONTAL_LUMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_HORIZONTAL_LUMA_COEFFICIENTS_3]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_VERTICAL_LUMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_VERTICAL_LUMA_COEFFICIENTS_0]; + *mem_to_reg++ = pipe | + (4 + MSVDX_CMDS_VERTICAL_LUMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_VERTICAL_LUMA_COEFFICIENTS_1]; + *mem_to_reg++ = pipe | + (8 + MSVDX_CMDS_VERTICAL_LUMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_VERTICAL_LUMA_COEFFICIENTS_2]; + *mem_to_reg++ = pipe | + (12 + MSVDX_CMDS_VERTICAL_LUMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_VERTICAL_LUMA_COEFFICIENTS_3]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_HORIZONTAL_CHROMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_HORIZONTAL_CHROMA_COEFFICIENTS_0]; + *mem_to_reg++ = pipe | + (4 + MSVDX_CMDS_HORIZONTAL_CHROMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_HORIZONTAL_CHROMA_COEFFICIENTS_1]; + *mem_to_reg++ = pipe | + (8 + MSVDX_CMDS_HORIZONTAL_CHROMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_HORIZONTAL_CHROMA_COEFFICIENTS_2]; + *mem_to_reg++ = pipe | + (12 + MSVDX_CMDS_HORIZONTAL_CHROMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_HORIZONTAL_CHROMA_COEFFICIENTS_3]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_VERTICAL_CHROMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_VERTICAL_CHROMA_COEFFICIENTS_0]; + *mem_to_reg++ = pipe | + (4 + MSVDX_CMDS_VERTICAL_CHROMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_VERTICAL_CHROMA_COEFFICIENTS_1]; + *mem_to_reg++ = pipe | + (8 + MSVDX_CMDS_VERTICAL_CHROMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_VERTICAL_CHROMA_COEFFICIENTS_2]; + *mem_to_reg++ = pipe | + (12 + MSVDX_CMDS_VERTICAL_CHROMA_COEFFICIENTS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_VERTICAL_CHROMA_COEFFICIENTS_3]; + } + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_EXTENDED_ROW_STRIDE_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_EXTENDED_ROW_STRIDE]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_ALTERNATIVE_OUTPUT_CONTROL_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_PICTURE_ROTATION]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_CHROMA_ROW_STRIDE_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_CHROMA_ROW_STRIDE]; + + /* Setup MEM_TO_REG buffer */ + for (i = 0; i < genc_buf_cnt; i++) { + *mem_to_reg++ = pipe | (PVDEC_VEC_BE_CR_GENC_BUFFER_SIZE_OFFSET + + regs_offsets->vec_be_regs_offset + i * sizeof(unsigned int)); + *mem_to_reg++ = genc_buffers[i]->ddbuf_info.buf_size; + *mem_to_reg++ = pipe | (PVDEC_VEC_BE_CR_GENC_BUFFER_BASE_ADDRESS_OFFSET + + regs_offsets->vec_be_regs_offset + i * sizeof(unsigned int)); + *mem_to_reg++ = genc_buffers[i]->ddbuf_info.dev_virt; + } + + *mem_to_reg++ = pipe | + (PVDEC_VEC_BE_CR_GENC_FRAGMENT_BASE_ADDRESS_OFFSET + + regs_offsets->vec_be_regs_offset); + *mem_to_reg++ = picture->pict_res_int->genc_fragment_buf->ddbuf_info.dev_virt; + + *mem_to_reg++ = pipe | + (PVDEC_VEC_BE_CR_ABOVE_PARAM_BASE_ADDRESS_OFFSET + + regs_offsets->vec_be_regs_offset); + + *mem_to_reg++ = dec_pict->pvdec_info->ddbuf_info->dev_virt + + MEM_TO_REG_BUF_SIZE + SLICE_PARAMS_BUF_SIZE; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_LUMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_LUMA_RECONSTRUCTED_PICTURE_BASE_ADDRESS]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_CHROMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_CHROMA_RECONSTRUCTED_PICTURE_BASE_ADDRESS]; + + /* alternative picture configuration */ + if (dec_pict->alt_pict) { + *mem_to_reg++ = pipe | + (MSVDX_CMDS_VC1_LUMA_RANGE_MAPPING_BASE_ADDRESS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_LUMA_ALTERNATIVE_PICTURE_BASE_ADDRESS]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_VC1_CHROMA_RANGE_MAPPING_BASE_ADDRESS_OFFSET + + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_CHROMA_ALTERNATIVE_PICTURE_BASE_ADDRESS]; + } + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_AUX_LINE_BUFFER_BASE_ADDRESS_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_AUX_LINE_BUFFER_BASE_ADDRESS]; + + *mem_to_reg++ = pipe | + (MSVDX_CMDS_INTRA_BUFFER_BASE_ADDRESS_OFFSET + regs_offsets->vdmc_cmd_offset); + *mem_to_reg++ = pict_cmds[VDECFW_CMD_INTRA_BUFFER_BASE_ADDRESS]; + + /* Make sure we fit in buffer */ + memto_reg_used = (unsigned long)mem_to_reg - + (unsigned long)dec_pict->pvdec_info->ddbuf_info->cpu_virt; + + VDEC_ASSERT(memto_reg_used < MEM_TO_REG_BUF_SIZE); + + *mem_to_reg_host_part = memto_reg_used / sizeof(unsigned int); + + return IMG_SUCCESS; +} +#endif + +/* + * Creates DEVA commands for configuring rendec and writes them into control + * allocation buffer. + */ +static int translation_pvdecsetup_vdecext + (struct vdec_ext_cmd *vdec_ext, + struct dec_decpict *dec_pict, unsigned int *pic_cmds, + struct vdecdd_str_unit *str_unit, enum vdec_vid_std vid_std, + enum vdecfw_parsermode parser_mode) +{ + int result; + unsigned int trans_id = dec_pict->transaction_id; + + VDEC_ASSERT(dec_pict->recon_pict); + + vdec_ext->cmd = CMD_VDEC_EXT; + vdec_ext->trans_id = trans_id; + + result = translation_get_seqhdr(str_unit, dec_pict, &vdec_ext->seq_addr); + VDEC_ASSERT(result == IMG_SUCCESS); + if (result != IMG_SUCCESS) + return result; + + result = translation_get_ppshdr(str_unit, dec_pict, &vdec_ext->pps_addr); + VDEC_ASSERT(result == IMG_SUCCESS); + if (result != IMG_SUCCESS) + return result; + + result = translation_getsecond_ppshdr(str_unit, &vdec_ext->pps_2addr); + if (result != IMG_SUCCESS) + return result; + + vdec_ext->hdr_addr = GET_HOST_ADDR(dec_pict->hdr_info->ddbuf_info); + + vdec_ext->ctx_load_addr = translation_getctx_loadaddr(dec_pict); + vdec_ext->ctx_save_addr = GET_HOST_ADDR(&dec_pict->cur_pict_dec_res->fw_ctx_buf); + vdec_ext->buf_ctrl_addr = GET_HOST_ADDR(&dec_pict->pict_ref_res->fw_ctrlbuf); + if (dec_pict->prev_pict_dec_res) { + /* + * Copy the previous firmware context to the current one in case + * picture management fails in firmware. + */ + memcpy(dec_pict->cur_pict_dec_res->fw_ctx_buf.cpu_virt, + dec_pict->prev_pict_dec_res->fw_ctx_buf.cpu_virt, + dec_pict->prev_pict_dec_res->fw_ctx_buf.buf_size); + } + + vdec_ext->last_luma_recon = + pic_cmds[VDECFW_CMD_LUMA_RECONSTRUCTED_PICTURE_BASE_ADDRESS]; + vdec_ext->last_chroma_recon = + pic_cmds[VDECFW_CMD_CHROMA_RECONSTRUCTED_PICTURE_BASE_ADDRESS]; + + vdec_ext->luma_err_base = + pic_cmds[VDECFW_CMD_LUMA_ERROR_PICTURE_BASE_ADDRESS]; + vdec_ext->chroma_err_base = + pic_cmds[VDECFW_CMD_CHROMA_ERROR_PICTURE_BASE_ADDRESS]; + + vdec_ext->scaled_display_size = + pic_cmds[VDECFW_CMD_SCALED_DISPLAY_SIZE]; + vdec_ext->horz_scale_control = + pic_cmds[VDECFW_CMD_HORIZONTAL_SCALE_CONTROL]; + vdec_ext->vert_scale_control = + pic_cmds[VDECFW_CMD_VERTICAL_SCALE_CONTROL]; + vdec_ext->scale_output_size = pic_cmds[VDECFW_CMD_SCALE_OUTPUT_SIZE]; + + vdec_ext->intra_buf_base_addr = + pic_cmds[VDECFW_CMD_INTRA_BUFFER_BASE_ADDRESS]; + vdec_ext->intra_buf_size_per_pipe = + pic_cmds[VDECFW_CMD_INTRA_BUFFER_SIZE_PER_PIPE]; + vdec_ext->intra_buf_size_per_plane = + pic_cmds[VDECFW_CMD_INTRA_BUFFER_PLANE_SIZE]; + vdec_ext->aux_line_buffer_base_addr = + pic_cmds[VDECFW_CMD_AUX_LINE_BUFFER_BASE_ADDRESS]; + vdec_ext->aux_line_buf_size_per_pipe = + pic_cmds[VDECFW_CMD_AUX_LINE_BUFFER_SIZE_PER_PIPE]; + vdec_ext->alt_output_pict_rotation = + pic_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_PICTURE_ROTATION]; + vdec_ext->chroma2reconstructed_addr = + pic_cmds[VDECFW_CMD_CHROMA2_RECONSTRUCTED_PICTURE_BASE_ADDRESS]; + vdec_ext->luma_alt_addr = + pic_cmds[VDECFW_CMD_LUMA_ALTERNATIVE_PICTURE_BASE_ADDRESS]; + vdec_ext->chroma_alt_addr = + pic_cmds[VDECFW_CMD_CHROMA_ALTERNATIVE_PICTURE_BASE_ADDRESS]; + vdec_ext->chroma2alt_addr = + pic_cmds[VDECFW_CMD_CHROMA2_ALTERNATIVE_PICTURE_BASE_ADDRESS]; + + if (vid_std == VDEC_STD_VC1) { + struct vidio_ddbufinfo *vlc_idx_tables_bufinfo = + dec_pict->vlc_idx_tables_bufinfo; + struct vidio_ddbufinfo *vlc_tables_bufinfo = + dec_pict->vlc_tables_bufinfo; + + vdec_ext->vlc_idx_table_size = vlc_idx_tables_bufinfo->buf_size; + vdec_ext->vlc_idx_table_addr = vlc_idx_tables_bufinfo->buf_size; + vdec_ext->vlc_tables_size = vlc_tables_bufinfo->buf_size; + vdec_ext->vlc_tables_size = vlc_tables_bufinfo->buf_size; + } else { + vdec_ext->vlc_idx_table_size = 0; + vdec_ext->vlc_idx_table_addr = 0; + vdec_ext->vlc_tables_size = 0; + vdec_ext->vlc_tables_size = 0; + } + + vdec_ext->display_picture_size = pic_cmds[VDECFW_CMD_DISPLAY_PICTURE]; + vdec_ext->parser_mode = parser_mode; + + /* miscellaneous flags */ + vdec_ext->is_chromainterleaved = + REGIO_READ_FIELD(pic_cmds[VDECFW_CMD_OPERATING_MODE], MSVDX_CMDS, OPERATING_MODE, + CHROMA_INTERLEAVED); + vdec_ext->is_discontinuousmbs = + dec_pict->pict_hdr_info->discontinuous_mbs; + +#ifdef HAS_HEVC + if (dec_pict->pvdec_info) { + vdec_ext->mem_to_reg_addr = dec_pict->pvdec_info->ddbuf_info->dev_virt; + vdec_ext->slice_params_addr = dec_pict->pvdec_info->ddbuf_info->dev_virt + + MEM_TO_REG_BUF_SIZE; + vdec_ext->slice_params_size = SLICE_PARAMS_BUF_SIZE; + } + if (vid_std == VDEC_STD_HEVC) { + struct vdecdd_picture *picture = (struct vdecdd_picture *)str_unit->dd_pict_data; + + VDEC_ASSERT(picture); + /* 10-bit packed output format indicator */ + vdec_ext->is_packedformat = picture->op_config.pixel_info.mem_pkg == + PIXEL_BIT10_MP ? 1 : 0; + } +#endif + return IMG_SUCCESS; +} + +/* + * NOTE : + * translation_configure_tiling is not supported as of now. + */ +int translation_ctrl_alloc_prepare(struct vdec_str_configdata *pstr_config_data, + struct vdecdd_str_unit *str_unit, + struct dec_decpict *dec_pict, + const struct vxd_coreprops *core_props, + struct decoder_regsoffsets *regs_offset) +{ + int result; + unsigned int *cmd_buf; + unsigned int hdr_size = 0; + unsigned int pict_cmds[VDECFW_CMD_MAX]; + enum vdecfw_codectype codec; + struct vxd_buffers buffers; + struct vdec_ext_cmd *vdec_ext; + enum vdecfw_parsermode parser_mode = VDECFW_SCP_ONLY; + struct vidio_ddbufinfo *batch_msgbuf_info = + dec_pict->batch_msginfo->ddbuf_info; + struct lst_t *decpic_seg_list = &dec_pict->dec_pict_seg_list; + unsigned int memto_reg_host_part = 0; + + unsigned long ctrl_alloc = (unsigned long)batch_msgbuf_info->cpu_virt; + unsigned long ctrl_alloc_end = ctrl_alloc + batch_msgbuf_info->buf_size; + + struct vdecdd_picture *picture = + (struct vdecdd_picture *)str_unit->dd_pict_data; + + memset(pict_cmds, 0, sizeof(pict_cmds)); + memset(&buffers, 0, sizeof(buffers)); + + VDEC_ASSERT(batch_msgbuf_info->buf_size >= CTRL_ALLOC_MAX_SEGMENT_SIZE); + memset(batch_msgbuf_info->cpu_virt, 0, batch_msgbuf_info->buf_size); + + /* Construct transaction based on new picture. */ + VDEC_ASSERT(str_unit->str_unit_type == VDECDD_STRUNIT_PICTURE_START); + + /* Obtain picture data. */ + picture = (struct vdecdd_picture *)str_unit->dd_pict_data; + dec_pict->recon_pict = &picture->disp_pict_buf; + + result = translation_get_codec(pstr_config_data->vid_std, &codec); + if (result != IMG_SUCCESS) + return result; + + translation_setup_std_header(pstr_config_data, dec_pict, str_unit, &hdr_size, picture, + pict_cmds, &parser_mode); + + buffers.recon_pict = dec_pict->recon_pict; + buffers.alt_pict = dec_pict->alt_pict; + +#ifdef HAS_HEVC + /* Set pipe offsets to device buffers */ + if (pstr_config_data->vid_std == VDEC_STD_HEVC) { + /* FW in multipipe requires this buffers to be allocated per stream */ + if (picture->pict_res_int && picture->pict_res_int->seq_resint && + picture->pict_res_int->seq_resint->intra_buffer && + picture->pict_res_int->seq_resint->aux_buffer) { + buffers.intra_bufinfo = + &picture->pict_res_int->seq_resint->intra_buffer->ddbuf_info; + buffers.auxline_bufinfo = + &picture->pict_res_int->seq_resint->aux_buffer->ddbuf_info; + } + } else { + buffers.intra_bufinfo = dec_pict->intra_bufinfo; + buffers.auxline_bufinfo = dec_pict->auxline_bufinfo; + } + + if (buffers.intra_bufinfo) + buffers.intra_bufsize_per_pipe = buffers.intra_bufinfo->buf_size / + core_props->num_pixel_pipes; + if (buffers.auxline_bufinfo) + buffers.auxline_bufsize_per_pipe = buffers.auxline_bufinfo->buf_size / + core_props->num_pixel_pipes; +#endif + +#ifdef ERROR_CONCEALMENT + if (picture->pict_res_int && picture->pict_res_int->seq_resint) + if (picture->pict_res_int->seq_resint->err_pict_buf) + buffers.err_pict_bufinfo = + &picture->pict_res_int->seq_resint->err_pict_buf->ddbuf_info; +#endif + + /* + * Prepare Reconstructed Picture Configuration + * Note: we are obtaining values of registers prepared basing on header + * files generated from MSVDX *dev files. + * That's allowed, as layout of registers: MSVDX_CMDS_OPERATING_MODE, + * MSVDX_CMDS_EXTENDED_ROW_STRIDE, + * MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION, + * MSVDX_CMDS_CHROMA_ROW_STRIDE is the same for both MSVDX and PVDEC. + */ + vxd_set_reconpictcmds(str_unit, pstr_config_data, &picture->op_config, core_props, + &buffers, pict_cmds); + + /* Alternative Picture Configuration */ + if (dec_pict->alt_pict) { + dec_pict->twopass = picture->op_config.force_oold; + buffers.btwopass = dec_pict->twopass; + /* + * Alternative Picture Configuration + * Note: we are obtaining values of registers prepared basing + * on header files generated from MSVDX *dev files. + * That's allowed, as layout of registers: + * MSVDX_CMDS_OPERATING_MODE, MSVDX_CMDS_EXTENDED_ROW_STRIDE, + * MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION, + * MSVDX_CMDS_CHROMA_ROW_STRIDE is the same for both MSVDX and + * PVDEC. + */ + /* + * Configure second buffer for out-of-loop processing + * (e.g. scaling etc.). + */ + vxd_set_altpictcmds(str_unit, pstr_config_data, &picture->op_config, core_props, + &buffers, pict_cmds); + } + + /* + * Setup initial simple bitstream configuration to be used by parser + * task + */ + cmd_buf = (unsigned int *)ctrl_alloc; + result = translation_pvdec_adddma_transfers + (decpic_seg_list, &cmd_buf, + (ctrl_alloc_end - (unsigned long)cmd_buf) / sizeof(unsigned int), + dec_pict, str_unit->eop); + if (result != IMG_SUCCESS) + return result; + + if ((unsigned long)(cmd_buf + (sizeof(struct ctrl_alloc_header) + + sizeof(struct vdec_ext_cmd)) / sizeof(unsigned int)) >= + ctrl_alloc_end) + return IMG_ERROR_INVALID_PARAMETERS; + + /* + * Setup regular control allocation message. Start with control + * allocation header + */ + translation_pvdec_ctrl_setuphdr((struct ctrl_alloc_header *)cmd_buf, pict_cmds); + /* Setup additional params for VP8 */ + cmd_buf += sizeof(struct ctrl_alloc_header) / sizeof(unsigned int); + + /* Reserve space for VDEC extension command and fill it */ + vdec_ext = (struct vdec_ext_cmd *)cmd_buf; + cmd_buf += sizeof(struct vdec_ext_cmd) / sizeof(unsigned int); + + result = translation_pvdecsetup_vdecext(vdec_ext, dec_pict, pict_cmds, + str_unit, + pstr_config_data->vid_std, + parser_mode); + if (result != IMG_SUCCESS) + return result; + + vdec_ext->hdr_size = hdr_size; + + /* Add VLC tables to control allocation, skip when VC1 */ + if (pstr_config_data->vid_std != VDEC_STD_VC1 && + dec_pict->vlc_idx_tables_bufinfo && + dec_pict->vlc_idx_tables_bufinfo->cpu_virt) { + unsigned short *vlc_idx_tables = (unsigned short *) + dec_pict->vlc_idx_tables_bufinfo->cpu_virt; + /* + * Get count of elements in VLC idx table. Each element is made + * of 3 IMG_UINT16, see e.g. mpeg2_idx.c + */ + unsigned int vlc_idx_count = + dec_pict->vlc_idx_tables_bufinfo->buf_size / + (3 * sizeof(unsigned short)); + + /* Add command to DMA VLC */ + result = translation_pvdecsetup_vlcdma + (dec_pict->vlc_tables_bufinfo, &cmd_buf, + (ctrl_alloc_end - (unsigned long)cmd_buf) / sizeof(unsigned int)); + + if (result != IMG_SUCCESS) + return result; + + /* Add command to configure VLC tables */ + result = translation_pvdecsetup_vlctables + ((unsigned short (*)[3])vlc_idx_tables, vlc_idx_count, &cmd_buf, + (ctrl_alloc_end - (unsigned long)cmd_buf) / sizeof(unsigned int), + regs_offset->vec_offset); + + if (result != IMG_SUCCESS) + return result; + } + + /* Setup commands for standards other than HEVC */ + if (pstr_config_data->vid_std != VDEC_STD_HEVC) { + translation_pvdec_setup_commands + (pict_cmds, &cmd_buf, + (ctrl_alloc_end - (unsigned long)cmd_buf) / sizeof(unsigned int), + regs_offset->vdmc_cmd_offset); + } + + /* Setup commands for HEVC */ + vdec_ext->mem_to_reg_size = 0; + +#ifdef HAS_HEVC + if (pstr_config_data->vid_std == VDEC_STD_HEVC) { + result = translation_pvdec_setup_pvdec_commands + (picture, dec_pict, str_unit, + regs_offset, &cmd_buf, + (ctrl_alloc_end - (unsigned long)cmd_buf) / sizeof(unsigned int), + &memto_reg_host_part, pict_cmds); + if (result != IMG_SUCCESS) { + pr_err("Failed to setup VDMC & VDEB firmware commands."); + return result; + } + + /* Set size of MemToReg buffer in VDEC extension command */ + VDEC_ASSERT(MEM_TO_REG_BUF_SIZE < + (MEM2REG_SIZE_BUF_TOTAL_MASK >> MEM2REG_SIZE_BUF_TOTAL_SHIFT)); + VDEC_ASSERT(memto_reg_host_part < + (MEM2REG_SIZE_HOST_PART_MASK >> MEM2REG_SIZE_HOST_PART_SHIFT)); + + vdec_ext->mem_to_reg_size = (MEM_TO_REG_BUF_SIZE << MEM2REG_SIZE_BUF_TOTAL_SHIFT) | + (memto_reg_host_part << MEM2REG_SIZE_HOST_PART_SHIFT); + + dec_pict->genc_id = picture->pict_res_int->seq_resint->genc_buf_id; + dec_pict->genc_bufs = picture->pict_res_int->seq_resint->genc_buffers; + } +#endif + /* Finally mark end of commands */ + *(cmd_buf++) = CMD_COMPLETION; + + /* Print message for debugging */ + { + int i; + + for (i = 0; i < ((unsigned long)cmd_buf - ctrl_alloc) / sizeof(unsigned int); i++) + pr_debug("ctrl_alloc_buf[%d] == %08x\n", i, + ((unsigned int *)ctrl_alloc)[i]); + } + /* Transfer control allocation command to device memory */ + dec_pict->ctrl_alloc_bytes = ((unsigned long)cmd_buf - ctrl_alloc); + dec_pict->ctrl_alloc_offset = dec_pict->ctrl_alloc_bytes; + dec_pict->operating_op = pict_cmds[VDECFW_CMD_OPERATING_MODE]; + + /* + * NOTE : Nothing related to tiling will be used. + * result = translation_ConfigureTiling(psStrUnit, psDecPict, + * psCoreProps); + */ + + return result; +}; + +int translation_fragment_prepare(struct dec_decpict *dec_pict, + struct lst_t *decpic_seg_list, int eop, + struct dec_pict_fragment *pict_fragement) +{ + int result; + unsigned int *cmd_buf; + struct vidio_ddbufinfo *batchmsg_bufinfo; + unsigned long ctrl_alloc; + unsigned long ctrl_alloc_end; + + if (!dec_pict || !dec_pict->batch_msginfo || + !decpic_seg_list || !pict_fragement) + return IMG_ERROR_INVALID_PARAMETERS; + + batchmsg_bufinfo = dec_pict->batch_msginfo->ddbuf_info; + + ctrl_alloc = (unsigned long)batchmsg_bufinfo->cpu_virt + + dec_pict->ctrl_alloc_offset; + ctrl_alloc_end = (unsigned long)batchmsg_bufinfo->cpu_virt + + batchmsg_bufinfo->buf_size; + + /* + * Setup initial simple bitstream configuration to be used by parser + * task + */ + cmd_buf = (unsigned int *)ctrl_alloc; + result = translation_pvdec_adddma_transfers + (decpic_seg_list, &cmd_buf, + (ctrl_alloc_end - (unsigned long)cmd_buf) / sizeof(unsigned int), + dec_pict, eop); + + if (result != IMG_SUCCESS) + return result; + + /* Finally mark end of commands */ + *(cmd_buf++) = CMD_COMPLETION; + + /* Transfer control allocation command to device memory */ + pict_fragement->ctrl_alloc_offset = dec_pict->ctrl_alloc_offset; + pict_fragement->ctrl_alloc_bytes = + ((unsigned long)cmd_buf - ctrl_alloc); + + dec_pict->ctrl_alloc_offset += pict_fragement->ctrl_alloc_bytes; + + return result; +}; +#endif /* VDEC_USE_PVDEC */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/translation_api.h b/drivers/media/platform/imagination/vxe-vxd/decoder/translation_api.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/translation_api.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/translation_api.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VDECDD translation API's. + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ +#ifndef __TRANSLATION_API_H__ +#define __TRANSLATION_API_H__ + +#include "decoder.h" +#include "hw_control.h" +#include "vdecdd_defs.h" +#include "vdec_defs.h" +#include "vxd_props.h" + +/* + * This function submits a stream unit for translation + * into a control allocation buffer used in PVDEC operation. + */ +int translation_ctrl_alloc_prepare + (struct vdec_str_configdata *psstr_config_data, + struct vdecdd_str_unit *psstrunit, + struct dec_decpict *psdecpict, + const struct vxd_coreprops *core_props, + struct decoder_regsoffsets *regs_offset); + +/* + * TRANSLATION_FragmentPrepare. + */ +int translation_fragment_prepare(struct dec_decpict *psdecpict, + struct lst_t *decpic_seg_list, int eop, + struct dec_pict_fragment *pict_fragement); + +#endif /* __TRANSLATION_API_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vdecdd_defs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vdecdd_defs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vdecdd_defs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vdecdd_defs.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,446 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD Decoder device driver header definitions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + * Prashanth Kumar Amai + * + * Re-written for upstream + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#include +#include +#include +#include + +#include "img_profiles_levels.h" +#include "pixel_api.h" +#include "vdecdd_utils.h" + +/* + * Tests if chroma offset (immediately after size of luma) is exactly + * aligned to buffer alignment constraint. + */ +static inline unsigned char is_packedbuf_chroma_aligned(unsigned int offset, + unsigned int color_plane, + unsigned int align) +{ + return(color_plane != VDEC_PLANE_VIDEO_Y ? TRUE : + (offset == ALIGN(offset, align) ? TRUE : FALSE)); +} + +/* + * < h.264 MaxDpbMbs values per profile (see Table A-1 of Rec. ITU-T H.264 + * (03/2010)). + * NOTE: Level 1b will be treated as 1.1 in case of Baseline, + * Constrained Baseline, Main, and Extended profiles as the value of the + * constraint_set3_flag is not available in #VDEC_sComSequHdrInfo structure. + */ +static unsigned int h264_max_dpb_mbs[H264_LEVEL_MAJOR_NUM][H264_LEVEL_MINOR_NUM] = { + /* level: n/a n/a n/a 1.0b */ + { 396, 396, 396, 396 }, + /* level: 1.0 1.1 1.2 1.3 */ + { 396, 900, 2376, 2376 }, + /* level: 2.0 2.1 2.2 n/a */ + { 2376, 4752, 8100, 8100 }, + /* level: 3.0 3.1 3.2 n/a */ + { 8100, 18000, 20480, 20480}, + /* level: 4.0 4.1 4.2 n/a */ + { 32768, 32768, 34816, 34816}, + /* level: 5.0 5.1 5.2 n/a */ + { 110400, 184320, 184320, 184320} +}; + +typedef int (*fn_ref_pic_get_max_num)(const struct vdec_comsequ_hdrinfo + *comseq_hdrinfo, unsigned int *max_ref_pic_num); + +void vdecddutils_buf_vxd_adjust_size(unsigned int *buf_size) +{ + /* Align the buffer size to VXD page size. */ + *buf_size = ALIGN(*buf_size, VDEC_VXD_BUF_ALIGNMENT); +} + +static int vdecddutils_ref_pic_h264_get_maxnum + (const struct vdec_comsequ_hdrinfo *comseq_hdrinfo, + unsigned int *max_ref_pic_num) +{ + unsigned int pic_width_mb; + unsigned int pic_height_mb; + unsigned int lvl_major = 0; + unsigned int lvl_minor = 0; + + /* Pre-validate level. */ + if (comseq_hdrinfo->codec_level < H264_LEVEL_MIN || + comseq_hdrinfo->codec_level > H264_LEVEL_MAX) { + pr_warn("Wrong H264 level value: %u", + comseq_hdrinfo->codec_level); + } + + if (comseq_hdrinfo->max_reorder_picts) { + *max_ref_pic_num = comseq_hdrinfo->max_reorder_picts; + } else { + /* Calculate level major and minor. */ + lvl_major = comseq_hdrinfo->codec_level / 10; + lvl_minor = comseq_hdrinfo->codec_level % 10; + + /* Calculate picture sizes in MBs. */ + pic_width_mb = (comseq_hdrinfo->max_frame_size.width + + (VDEC_MB_DIMENSION - 1)) / VDEC_MB_DIMENSION; + pic_height_mb = (comseq_hdrinfo->max_frame_size.height + + (VDEC_MB_DIMENSION - 1)) / VDEC_MB_DIMENSION; + + /* Validate lvl_minor */ + if (lvl_minor > 3) { + pr_warn("Wrong H264 lvl_minor level value: %u, overriding with 3", + lvl_minor); + lvl_minor = 3; + } + /* Validate lvl_major */ + if (lvl_major > 5) { + pr_warn("Wrong H264 lvl_major level value: %u, overriding with 5", + lvl_major); + lvl_major = 5; + } + + /* + * Calculate the maximum number of reference pictures + * required based on level. + */ + *max_ref_pic_num = h264_max_dpb_mbs[lvl_major][lvl_minor] / + (pic_width_mb * pic_height_mb); + if (*max_ref_pic_num > 16) + *max_ref_pic_num = 16; + } + + /* Return success. */ + return IMG_SUCCESS; +} + +#ifdef HAS_HEVC +/* + * @Function vdecddutils_ref_pic_hevc_get_maxnum + */ +int vdecddutils_ref_pic_hevc_get_maxnum(const struct vdec_comsequ_hdrinfo *comseq_hdrinfo, + unsigned int *max_ref_picnum) +{ + static const unsigned int HEVC_LEVEL_IDC_MIN = 30; + static const unsigned int HEVC_LEVEL_IDC_MAX = 186; + + static const unsigned int + max_luma_ps_list[HEVC_LEVEL_MAJOR_NUM][HEVC_LEVEL_MINOR_NUM] = { + /* level: 1.0 1.1 1.2 */ + { 36864, 0, 0, }, + /* level: 2.0 2.1 2.2 */ + { 122880, 245760, 0, }, + /* level: 3.0 3.1 3.2 */ + { 552960, 983040, 0, }, + /* level: 4.0 4.1 4.2 */ + { 2228224, 2228224, 0, }, + /* level: 5.0 5.1 5.2 */ + { 8912896, 8912896, 8912896, }, + /* level: 6.0 6.1 6.2 */ + { 35651584, 35651584, 35651584, } + }; + + /* ITU-T H.265 04/2013 A.4.1 */ + + const unsigned int max_dpb_picbuf = 6; + + /* this is rounded to whole Ctbs */ + unsigned int pic_size_in_samples_Y = comseq_hdrinfo->frame_size.height * + comseq_hdrinfo->frame_size.width; + + signed char level_maj, level_min; + unsigned int max_luma_ps; + + /* some error resilience */ + if (comseq_hdrinfo->codec_level > HEVC_LEVEL_IDC_MAX || + comseq_hdrinfo->codec_level < HEVC_LEVEL_IDC_MIN) { + pr_warn("HEVC Codec level out of range: %u, falling back to %u", + comseq_hdrinfo->codec_level, + comseq_hdrinfo->min_pict_buf_num); + + *max_ref_picnum = comseq_hdrinfo->min_pict_buf_num; + return IMG_SUCCESS; + } + + level_maj = comseq_hdrinfo->codec_level / 30; + level_min = (comseq_hdrinfo->codec_level % 30) / 3; + + if (level_maj > 0 && level_maj <= HEVC_LEVEL_MAJOR_NUM && + level_min >= 0 && level_min < HEVC_LEVEL_MINOR_NUM) { + max_luma_ps = max_luma_ps_list[level_maj - 1][level_min]; + } else { + pr_err("%s: Invalid parameters\n", __func__); + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (max_luma_ps == 0) { + pr_err("Wrong HEVC level value: %u.%u (general_level_idc: %u)", + level_maj, level_min, comseq_hdrinfo->codec_level); + + return IMG_ERROR_VALUE_OUT_OF_RANGE; + } + + if (max_luma_ps < pic_size_in_samples_Y) + pr_warn("HEVC PicSizeInSamplesY too large for level (%u > %u)", + pic_size_in_samples_Y, max_luma_ps); + + if (pic_size_in_samples_Y <= (max_luma_ps >> 2)) + *max_ref_picnum = vdec_size_min(4 * max_dpb_picbuf, 16); + else if (pic_size_in_samples_Y <= (max_luma_ps >> 1)) + *max_ref_picnum = vdec_size_min(2 * max_dpb_picbuf, 16); + else if (pic_size_in_samples_Y <= ((3 * max_luma_ps) >> 2)) + *max_ref_picnum = vdec_size_min((4 * max_dpb_picbuf) / 3, 16); + else + *max_ref_picnum = max_dpb_picbuf; + + /* Return success. */ + return IMG_SUCCESS; +} +#endif + +#ifdef HAS_JPEG +static int vdecddutils_ref_pic_jpeg_get_maxnum(const struct vdec_comsequ_hdrinfo *comseq_hdrinfo, + unsigned int *max_ref_picnum) +{ + /* No reference frames for JPEG. */ + *max_ref_picnum = 0; + + /* Return success. */ + return IMG_SUCCESS; +} +#endif + +/* + * The array of pointers to functions calculating the maximum number + * of reference pictures required for each supported video standard. + * NOTE: The table is indexed by #VDEC_eVidStd enum values. + */ +static fn_ref_pic_get_max_num ref_pic_get_maxnum[VDEC_STD_MAX - 1] = { + NULL, + NULL, + NULL, + vdecddutils_ref_pic_h264_get_maxnum, + NULL, + NULL, + NULL, +#ifdef HAS_JPEG + vdecddutils_ref_pic_jpeg_get_maxnum, +#else + NULL, +#endif + NULL, + NULL, + NULL, +#ifdef HAS_HEVC + vdecddutils_ref_pic_hevc_get_maxnum +#else + NULL +#endif +}; + +int +vdecddutils_ref_pict_get_maxnum(const struct vdec_str_configdata *str_cfg_data, + const struct vdec_comsequ_hdrinfo *comseq_hdr_info, + unsigned int *num_picts) +{ + int ret = IMG_SUCCESS; + + /* Validate input params. */ + if (str_cfg_data->vid_std == VDEC_STD_UNDEFINED || str_cfg_data->vid_std >= VDEC_STD_MAX) + return IMG_ERROR_VALUE_OUT_OF_RANGE; + + /* Call the function related to the provided video standard. */ + ret = ref_pic_get_maxnum[str_cfg_data->vid_std - 1](comseq_hdr_info, + num_picts); + if (ret != IMG_SUCCESS) + pr_warn("[USERSID=0x%08X] Failed to get number of reference pictures", + str_cfg_data->user_str_id); + + /* + * For non-conformant stream use the + * max(*pui32NumPicts,comseq_hdrinfo->ui32MinPicBufNum) + */ + if (*num_picts < comseq_hdr_info->min_pict_buf_num) + *num_picts = comseq_hdr_info->min_pict_buf_num; + + /* + * Increase for MVC: mvcScaleFactor = 2 (H.10.2) and additional pictures + * for a StoreInterViewOnlyRef case (C.4.5.2) + */ + if (comseq_hdr_info->num_views > 1) { + *num_picts *= 2; + *num_picts += comseq_hdr_info->num_views - 1; + } + + return ret; +} + +static void vdecddutils_update_rend_pictsize(struct vdec_pict_size pict_size, + struct vdec_pict_size *rend_pict_size) +{ + if (rend_pict_size->width == 0) { + rend_pict_size->width = pict_size.width; + } else { + /* Take the smallest resolution supported by all the planes */ + rend_pict_size->width = (pict_size.width < + rend_pict_size->width) ? + pict_size.width : + rend_pict_size->width; + } + if (rend_pict_size->height == 0) { + rend_pict_size->height = pict_size.height; + } else { + /* Take the smallest resolution supported by all the planes. */ + rend_pict_size->height = (pict_size.height < + rend_pict_size->height) ? + pict_size.height : + rend_pict_size->height; + } +} + +int vdecddutils_convert_buffer_config(const struct vdec_str_configdata *str_cfg_data, + const struct vdec_pict_bufconfig *pict_bufcfg, + struct vdec_pict_rendinfo *pict_rend_info) +{ + const struct pixel_pixinfo *pix_info; + struct img_pixfmt_desc pixfmt; + unsigned int i; + unsigned int total_vert_samples = 0; + unsigned int vert_samples[IMG_MAX_NUM_PLANES]; + unsigned int plane_size = 0; + unsigned int plane_offset = 0; + struct vdec_pict_size pict_size; + + /* Validate inputs. */ + VDEC_ASSERT(str_cfg_data); + VDEC_ASSERT(pict_bufcfg); + VDEC_ASSERT(pict_rend_info); + + /* Reset picture buffer allocation data. */ + memset(pict_rend_info, 0x0, sizeof(*pict_rend_info)); + + pr_debug("%s picture buffer pixel_fmt = %d\n", __func__, pict_bufcfg->pixel_fmt); + /* Get pixel format info for regular pixel formats... */ + if (pict_bufcfg->pixel_fmt < IMG_PIXFMT_ARBPLANAR8) { + pix_info = pixel_get_pixinfo(pict_bufcfg->pixel_fmt); + pixel_yuv_get_desc((struct pixel_pixinfo *)pix_info, &pixfmt); + } else { + pixel_get_fmt_desc(pict_bufcfg->pixel_fmt, &pixfmt); + } + + /* + * Construct the render region information from the picture + * buffer configuration. + */ + for (i = 0; i < IMG_MAX_NUM_PLANES; i++) { + if (pixfmt.planes[i]) { + unsigned int plane_align = VDEC_VXD_PICTBUF_ALIGNMENT; + + /* + * Determine the offset (in bytes) to this plane. + * This is zero for the first (luma) plane and at the + * end of the previous plane for all subsequent planes. + */ + plane_offset = plane_offset + plane_size; + + /* + * Calculate the minimum number of vertical samples + * for this plane. + */ + vert_samples[i] = + ((pict_bufcfg->coded_height + + pixfmt.v_denom - 1) / pixfmt.v_denom) * + pixfmt.v_numer[i]; + + /* + * Calculate the mimimum plane size from the stride and + * decode picture height. Packed buffers have the luma + * and chroma exactly adjacent and consequently the + * chroma plane offset is equal to this plane size. + */ + plane_size = pict_bufcfg->stride[i] * vert_samples[i]; + plane_size = ALIGN(plane_size, plane_align); + + if (!pict_bufcfg->packed && pict_bufcfg->chroma_offset[i]) { + unsigned int max_plane_size; + + max_plane_size = + pict_bufcfg->chroma_offset[i] - plane_offset; + + if (plane_size > max_plane_size) { + pr_err("Chroma offset [%d bytes] is not large enough to fit minimum plane data [%d bytes] at offset [%d]", + pict_bufcfg->chroma_offset[i], + plane_size, plane_offset); + return IMG_ERROR_INVALID_PARAMETERS; + } + + plane_size = max_plane_size; + + vert_samples[i] = plane_size / + pict_bufcfg->stride[i]; + } else { + if (pict_bufcfg->chroma_offset[i] && (plane_offset + plane_size) != + pict_bufcfg->chroma_offset[i]) { + pr_err("Chroma offset specified [%d bytes] should match that required for plane size calculated from stride and height [%d bytes]", + pict_bufcfg->chroma_offset[i], + plane_offset + plane_size); + return IMG_ERROR_INVALID_PARAMETERS; + } + } + + pict_rend_info->plane_info[i].offset = plane_offset; + pict_rend_info->plane_info[i].stride = + pict_bufcfg->stride[i]; + pict_rend_info->plane_info[i].size = plane_size; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("VDECDDUTILS_ConvertBufferConfig() plane %d stride %u size %u offset %u", + i, pict_rend_info->plane_info[i].stride, + pict_rend_info->plane_info[i].size, + pict_rend_info->plane_info[i].offset); +#endif + + pict_rend_info->rendered_size += + pict_rend_info->plane_info[i].size; + + total_vert_samples += vert_samples[i]; + + /* Calculate the render region maximum picture size. */ + pict_size.width = (pict_rend_info->plane_info[i].stride * + pixfmt.bop_denom) / pixfmt.bop_numer[i]; + pict_size.height = (vert_samples[i] * pixfmt.v_denom) / pixfmt.v_numer[i]; + vdecddutils_update_rend_pictsize(pict_size, + &pict_rend_info->rend_pict_size); + } + } +#ifdef DEBUG_DECODER_DRIVER + pr_info("VDECDDUTILS_ConvertBufferConfig() total required %u (inc. alignment for addressing/tiling) vs. buffer %u", + pict_rend_info->rendered_size, pict_bufcfg->buf_size); +#endif + + /* Ensure that the buffer size is large enough to hold the data */ + if (pict_bufcfg->buf_size < pict_rend_info->rendered_size) { + pr_err("Buffer size [%d bytes] should be at least as large as rendered data (inc. any enforced gap between planes) [%d bytes]", + pict_bufcfg->buf_size, + pict_rend_info->rendered_size); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Whole buffer should be marked as rendered region */ + pict_rend_info->rendered_size = pict_bufcfg->buf_size; + /* Use the actual stride alignment */ + pict_rend_info->stride_alignment = pict_bufcfg->stride_alignment; + + return IMG_SUCCESS; +} + +static unsigned char vdecddutils_is_secondary_op_required(const struct vdec_comsequ_hdrinfo + *comseq_hdr_info, + const struct vdec_str_opconfig + *op_cfg) +{ + unsigned char result = TRUE; + + if (!op_cfg->force_oold && + !comseq_hdr_info->post_processing && + comseq_hdr_info->pixel_info.chroma_fmt_idc == + op_cfg->pixel_info.chroma_fmt_idc && + comseq_hdr_info->pixel_info.bitdepth_y == + op_cfg->pixel_info.bitdepth_y && + comseq_hdr_info->pixel_info.bitdepth_c == + op_cfg->pixel_info.bitdepth_c) + /* + * The secondary output is not required (if we have it we will + * not use it for transformation (e.g. scaling. rotating or + * up/down-sampling). + */ + result = FALSE; + + return result; +} + +int vdecddutils_get_minrequired_numpicts(const struct vdec_str_configdata *str_cfg_data, + const struct vdec_comsequ_hdrinfo *comseq_hdr_info, + const struct vdec_str_opconfig *op_cfg, + unsigned int *num_picts) +{ + int ret; + unsigned int max_held_picnum; + + /* If any operation requiring internal buffers is to be applied... */ + if (vdecddutils_is_secondary_op_required(comseq_hdr_info, op_cfg)) { + /* + * Reference picture buffers will be allocated internally, + * but there may be a number of picture buffers to which + * out-of-display-order pictures will be decoded. These + * buffers need to be allocated externally, so there's a + * need to calculate the number of out-of-(display)-order + * pictures required for the provided video standard. + */ + ret = vdecddutils_ref_pict_get_maxnum(str_cfg_data, comseq_hdr_info, + &max_held_picnum); + if (ret != IMG_SUCCESS) + return ret; + } else { + /* + * All the reference picture buffers have to be allocated + * externally, so there's a need to calculate the number of + * reference picture buffers required for the provided video + * standard. + */ + ret = vdecddutils_ref_pict_get_maxnum(str_cfg_data, comseq_hdr_info, + &max_held_picnum); + if (ret != IMG_SUCCESS) + return ret; + } + + /* + * Calculate the number of picture buffers required as the maximum + * number of picture buffers to be held onto by the driver plus the + * current picture buffer. + */ + *num_picts = max_held_picnum + + (comseq_hdr_info->interlaced_frames ? 2 : 1); + + return IMG_SUCCESS; +} + +static void vdecddutils_get_codedsize(const struct vdec_pict_rend_config *pict_rend_cfg, + struct vdec_pict_size *decoded_pict_size) +{ + decoded_pict_size->width = pict_rend_cfg->coded_pict_size.width; + decoded_pict_size->height = pict_rend_cfg->coded_pict_size.height; +} + +static unsigned char vdecddutils_is_packed(const struct vdec_pict_rendinfo *pict_rend_info, + const struct vdec_pict_rend_config *pict_rend_cfg) +{ + unsigned char packed = TRUE; + unsigned int pict_buf_align; + + /* Validate inputs. */ + VDEC_ASSERT(pict_rend_info); + VDEC_ASSERT(pict_rend_cfg); + + pict_buf_align = VDEC_VXD_PICTBUF_ALIGNMENT; + + if (pict_rend_info->plane_info[VDEC_PLANE_VIDEO_Y].size != + pict_rend_info->plane_info[VDEC_PLANE_VIDEO_UV].offset) { + /* Planes that are not adjacent cannot be packed */ + packed = FALSE; + } else if (!is_packedbuf_chroma_aligned(pict_rend_info->plane_info + [VDEC_PLANE_VIDEO_UV].offset, + VDEC_PLANE_VIDEO_Y, + pict_buf_align)) { + /* Chroma plane must be aligned for packed buffers. */ + VDEC_ASSERT(pict_rend_info->plane_info[VDEC_PLANE_VIDEO_Y].size == + pict_rend_info->plane_info[VDEC_PLANE_VIDEO_UV].offset); + packed = FALSE; + } + + return packed; +} + +static int vdecddutils_get_stride + (const struct vdec_str_configdata *str_cfg_data, + const struct vdec_pict_rend_config *pict_rend_cfg, + unsigned int vert_samples, unsigned int *h_stride, + enum vdec_color_planes color_planes) +{ + unsigned int hw_h_stride = *h_stride; + + /* + * If extended strides are to be used or indexed strides failed, + * make extended stride alignment. + */ + hw_h_stride = ALIGN(hw_h_stride, + pict_rend_cfg->stride_alignment > 0 ? + pict_rend_cfg->stride_alignment : + VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT); + + /* A zero-value indicates unsupported stride */ + if (hw_h_stride == 0) + /* No valid stride found */ + return IMG_ERROR_NOT_SUPPORTED; + + *h_stride = hw_h_stride; + + return IMG_SUCCESS; +} + +static int vdecddutils_get_render_info(const struct vdec_str_configdata *str_cfg_data, + const struct vdec_pict_rend_config *pict_rend_cfg, + const struct pixel_pixinfo *pix_info, + struct vdec_pict_rendinfo *pict_rend_info) +{ + unsigned int i; + struct img_pixfmt_desc pixfmt; + struct vdec_pict_size coded_pict_size; + unsigned char single_stride = FALSE; + unsigned int vert_sample[IMG_MAX_NUM_PLANES] = {0}; + unsigned int total_vert_samples; + unsigned int largest_stride; + unsigned int result; + + /* Reset the output structure. */ + memset(pict_rend_info, 0, sizeof(*pict_rend_info)); + + /* Ensure that the coded sizes are in whole macroblocks. */ + if ((pict_rend_cfg->coded_pict_size.width & + (VDEC_MB_DIMENSION - 1)) != 0 || + (pict_rend_cfg->coded_pict_size.height & + (VDEC_MB_DIMENSION - 1)) != 0) { + pr_err("Invalid render configuration coded picture size [%d x %d]. It should be a whole number of MBs in each dimension", + pict_rend_cfg->coded_pict_size.width, + pict_rend_cfg->coded_pict_size.height); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Check if the stride alignment is multiple of default. */ + if ((pict_rend_cfg->stride_alignment & + (VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT - 1)) != 0) { + pr_err("Invalid stride alignment %d used. It should be multiple of %d.", + pict_rend_cfg->stride_alignment, + VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT); + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Get pixel format info for regular pixel formats... */ + if (pix_info->pixfmt < IMG_PIXFMT_ARBPLANAR8) + pixel_yuv_get_desc((struct pixel_pixinfo *)pix_info, &pixfmt); + else + pixel_get_fmt_desc(pix_info->pixfmt, &pixfmt); + + /* Get the coded size for the appropriate orientation */ + vdecddutils_get_codedsize(pict_rend_cfg, &coded_pict_size); + + /* + * Calculate the hardware (inc. constraints) strides and + * number of vertical samples for each plane. + */ + total_vert_samples = 0; + largest_stride = 0; + for (i = 0; i < IMG_MAX_NUM_PLANES; i++) { + if (pixfmt.planes[i]) { + unsigned int h_stride; + + /* Horizontal stride must be for a multiple of BOPs. */ + h_stride = ((coded_pict_size.width + + pixfmt.bop_denom - 1) / + pixfmt.bop_denom) * pixfmt.bop_numer[i]; + + /* + * Vertical only has to satisfy whole pixel of + * samples. + */ + vert_sample[i] = ((coded_pict_size.height + + pixfmt.v_denom - 1) / + pixfmt.v_denom) * pixfmt.v_numer[i]; + + /* + * Obtain a horizontal stride supported by the hardware + * (inc. constraints). + */ + result = vdecddutils_get_stride(str_cfg_data, pict_rend_cfg, vert_sample[i], + &h_stride, (enum vdec_color_planes)i); + if (result != IMG_SUCCESS) { + VDEC_ASSERT(0); + pr_err("No valid VXD stride found for picture with decoded dimensions [%d x %d] and min stride [%d]", + coded_pict_size.width, coded_pict_size.height, h_stride); + return result; + } + + pict_rend_info->plane_info[i].stride = h_stride; + if (i == VDEC_PLANE_VIDEO_UV && (str_cfg_data->vid_std == VDEC_STD_H264 || + str_cfg_data->vid_std == VDEC_STD_HEVC)) { + struct pixel_pixinfo *info = + pixel_get_pixinfo(pix_info->pixfmt); + VDEC_ASSERT(PIXEL_FORMAT_INVALID != + info->chroma_fmt_idc); + } + + total_vert_samples += vert_sample[i]; + if (h_stride > largest_stride) + largest_stride = h_stride; + } + } + pict_rend_info->stride_alignment = + pict_rend_cfg->stride_alignment > 0 ? + pict_rend_cfg->stride_alignment : + VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT; + + if (pict_rend_cfg->packed) + single_stride = TRUE; + +#ifdef HAS_JPEG + /* JPEG hardware uses a single (luma) stride for all planes. */ + if (str_cfg_data->vid_std == VDEC_STD_JPEG) { + single_stride = true; + + /* Luma should be largest for this to be used for all planes. */ + VDEC_ASSERT(largest_stride == + pict_rend_info->plane_info[VDEC_PLANE_VIDEO_Y].stride); + } +#endif + + /* Calculate plane sizes. */ + for (i = 0; i < IMG_MAX_NUM_PLANES; i++) { + if (pixfmt.planes[i]) { + struct vdec_pict_size pict_size; + unsigned int vert_samples = vert_sample[i]; + unsigned int plane_align = VDEC_VXD_PICTBUF_ALIGNMENT; + + if (single_stride) + pict_rend_info->plane_info[i].stride = + largest_stride; + + pict_rend_info->plane_info[i].size = + pict_rend_info->plane_info[i].stride * + vert_samples; + pict_rend_info->plane_info[i].size = + ALIGN(pict_rend_info->plane_info[i].size, plane_align); + /* + * Ensure that the total buffer rendered size is + * rounded-up to the picture buffer alignment so that + * this plane (within this single buffer) can be + * correctly addressed by the hardware at this byte + * offset. + */ + if (i == 1 && pict_rend_cfg->packed) + /* + * Packed buffers must have chroma plane + * already aligned since this was factored + * into the stride/size calculation. + */ + VDEC_ASSERT(pict_rend_info->rendered_size == + ALIGN(pict_rend_info->rendered_size, plane_align)); + + pict_rend_info->plane_info[i].offset = pict_rend_info->rendered_size; + + /* Update the total buffer size (inc. this plane). */ + pict_rend_info->rendered_size += + pict_rend_info->plane_info[i].size; + + /* + * Update the maximum render picture size supported + * by all planes of this buffer. + */ + pict_size.width = (pict_rend_info->plane_info[i].stride * + pixfmt.bop_denom) / pixfmt.bop_numer[i]; + + pict_size.height = (vert_sample[i] * pixfmt.v_denom) / pixfmt.v_numer[i]; + + vdecddutils_update_rend_pictsize(pict_size, + &pict_rend_info->rend_pict_size); + +#ifdef DEBUG_DECODER_DRIVER + pr_info("vdecddutils_GetRenderInfo() plane %d stride %u size %u offset %u", + i, pict_rend_info->plane_info[i].stride, + pict_rend_info->plane_info[i].size, + pict_rend_info->plane_info[i].offset); +#endif + } + } + +#ifdef DEBUG_DECODER_DRIVER + pr_info("vdecddutils_GetRenderInfo() total %u (inc. alignment for addressing/tiling)", + pict_rend_info->rendered_size); +#endif + + return IMG_SUCCESS; +} + +int vdecddutils_pictbuf_getconfig(const struct vdec_str_configdata *str_cfg_data, + const struct vdec_pict_rend_config *pict_rend_cfg, + const struct vdec_str_opconfig *str_opcfg, + struct vdec_pict_bufconfig *pict_bufcfg) +{ + struct vdec_pict_rendinfo disp_pict_rendinfo; + struct vdec_pict_size coded_pict_size; + unsigned int ret, i; + unsigned int size0, size1; + + /* Validate inputs. */ + VDEC_ASSERT(str_cfg_data); + VDEC_ASSERT(pict_rend_cfg); + VDEC_ASSERT(str_opcfg); + VDEC_ASSERT(pict_bufcfg); + + /* Clear the picture buffer config before populating */ + memset(pict_bufcfg, 0, sizeof(struct vdec_pict_bufconfig)); + + /* Determine the rounded-up coded sizes (compatible with hardware) */ + ret = vdecddutils_get_render_info(str_cfg_data, + pict_rend_cfg, + &str_opcfg->pixel_info, + &disp_pict_rendinfo); + if (ret != IMG_SUCCESS) + return ret; + + /* Get the coded size for the appropriate orientation */ + vdecddutils_get_codedsize(pict_rend_cfg, &coded_pict_size); + + pict_bufcfg->coded_width = coded_pict_size.width; + pict_bufcfg->coded_height = coded_pict_size.height; + + /* + * Use the luma stride for all planes in buffer. + * Additional chroma stride may be needed for other pixel formats. + */ + for (i = 0; i < VDEC_PLANE_MAX; i++) + pict_bufcfg->stride[i] = disp_pict_rendinfo.plane_info[i].stride; + + /* + * Pixel information is taken from that + * specified for display. + */ + pict_bufcfg->pixel_fmt = str_opcfg->pixel_info.pixfmt; + pr_debug("picture buffer pixel_fmt = %d\n", pict_bufcfg->pixel_fmt); + + /* Tiling scheme is taken from render configuration */ + pict_bufcfg->byte_interleave = pict_rend_cfg->byte_interleave; + pr_debug("picture buffer byte_interleave = %d\n", pict_bufcfg->byte_interleave); + /* Stride alignment */ + pict_bufcfg->stride_alignment = pict_rend_cfg->stride_alignment > 0 ? + pict_rend_cfg->stride_alignment : VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT; + + pr_debug("picture buffer stride_alignment = %d\n", pict_bufcfg->stride_alignment); + /* Chroma offset taken as calculated for render configuration. */ + pict_bufcfg->chroma_offset[0] = disp_pict_rendinfo.plane_info[VDEC_PLANE_VIDEO_UV].offset; + pict_bufcfg->chroma_offset[1] = disp_pict_rendinfo.plane_info[VDEC_PLANE_VIDEO_V].offset; + + if (pict_rend_cfg->packed && str_opcfg->pixel_info.num_planes > 1) { + pict_bufcfg->packed = vdecddutils_is_packed(&disp_pict_rendinfo, pict_rend_cfg); + if (!pict_bufcfg->packed) { + /* Report if unable to meet request to pack. */ + pr_err("Request for packed buffer could not be met"); + return IMG_ERROR_NOT_SUPPORTED; + } + + size0 = ALIGN(pict_bufcfg->chroma_offset[0], VDEC_VXD_PICTBUF_ALIGNMENT); + size1 = ALIGN(pict_bufcfg->chroma_offset[1], VDEC_VXD_PICTBUF_ALIGNMENT); + + if (pict_bufcfg->chroma_offset[0] != size0 || + pict_bufcfg->chroma_offset[1] != size1) { + pr_err("Chroma plane could not be located on a %d byte boundary (investigate stride calculations)", + VDEC_VXD_PICTBUF_ALIGNMENT); + return IMG_ERROR_NOT_SUPPORTED; + } + } else { + pict_bufcfg->packed = FALSE; + } + + pict_bufcfg->buf_size = disp_pict_rendinfo.rendered_size; + + /* Return success */ + return IMG_SUCCESS; +} + +int vdecddutils_get_display_region(const struct vdec_pict_size *coded_size, + const struct vdec_rect *orig_disp_region, + struct vdec_rect *disp_region) +{ + int ret = IMG_SUCCESS; + + /* Validate inputs. */ + VDEC_ASSERT(coded_size); + VDEC_ASSERT(orig_disp_region); + VDEC_ASSERT(disp_region); + if (!coded_size || !orig_disp_region || !disp_region) + return IMG_ERROR_INVALID_PARAMETERS; + + /* + * In the simplest case the display region is the same as + * that defined in the bitstream. + */ + *disp_region = *orig_disp_region; + + if (orig_disp_region->height == 0 || orig_disp_region->width == 0 || + coded_size->height == 0 || coded_size->width == 0) { + pr_err("Invalid params to calculate display region:"); + pr_err("Display Size: [%d,%d]", orig_disp_region->width, orig_disp_region->height); + pr_err("Coded Size : [%d,%d]", coded_size->width, coded_size->height); + return IMG_ERROR_INVALID_PARAMETERS; + } + + return ret; +} + +int vdecddutils_pictbuf_getinfo(const struct vdec_str_configdata *str_cfg_data, + const struct vdec_pict_rend_config *pict_rend_cfg, + const struct vdec_str_opconfig *str_op_cfg, + struct vdec_pict_rendinfo *pict_rend_info) +{ + unsigned int ret; + + /* Validate inputs. */ + VDEC_ASSERT(str_cfg_data); + VDEC_ASSERT(pict_rend_cfg); + VDEC_ASSERT(str_op_cfg); + VDEC_ASSERT(pict_rend_info); + + ret = vdecddutils_get_render_info(str_cfg_data, pict_rend_cfg, + &str_op_cfg->pixel_info, + pict_rend_info); + VDEC_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + return IMG_SUCCESS; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vdecdd_utils.c b/drivers/media/platform/imagination/vxe-vxd/decoder/vdecdd_utils.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vdecdd_utils.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vdecdd_utils.c 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VXD Decoder device driver utility functions implementation + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#include +#include +#include +#include + +#include "bspp.h" +#include "vdecdd_utils.h" + +/* + * @Function VDECDDUTILS_FreeStrUnit + */ +int vdecddutils_free_strunit(struct vdecdd_str_unit *str_unit) +{ + struct bspp_bitstr_seg *bstr_seg; + + /* Loop over bit stream segments */ + bstr_seg = (struct bspp_bitstr_seg *)lst_removehead(&str_unit->bstr_seg_list); + while (bstr_seg) { + /* Free segment. */ + kfree(bstr_seg); + + /* Get next segment. */ + bstr_seg = (struct bspp_bitstr_seg *)lst_removehead(&str_unit->bstr_seg_list); + } + + /* Free the sequence header */ + if (str_unit->seq_hdr_info) { + str_unit->seq_hdr_info->ref_count--; + if (str_unit->seq_hdr_info->ref_count == 0) { + kfree(str_unit->seq_hdr_info); + str_unit->seq_hdr_info = NULL; + } + } + + /* Free the picture header... */ + if (str_unit->pict_hdr_info) { + kfree(str_unit->pict_hdr_info->pict_sgm_data.pic_data); + str_unit->pict_hdr_info->pict_sgm_data.pic_data = NULL; + + kfree(str_unit->pict_hdr_info); + str_unit->pict_hdr_info = NULL; + } + + /* Free stream unit. */ + kfree(str_unit); + str_unit = NULL; + + /* Return success */ + return IMG_SUCCESS; +} + +/* + * @Function: VDECDDUTILS_CreateStrUnit + * @Description: this function allocate a structure for a complete data unit + */ +int vdecddutils_create_strunit(struct vdecdd_str_unit **str_unit_handle, + struct lst_t *bs_list) +{ + struct vdecdd_str_unit *str_unit; + struct bspp_bitstr_seg *bstr_seg; + + str_unit = kzalloc(sizeof(*str_unit), GFP_KERNEL); + VDEC_ASSERT(str_unit); + if (!str_unit) + return IMG_ERROR_OUT_OF_MEMORY; + + if (bs_list) { + /* copy BS list to this list */ + lst_init(&str_unit->bstr_seg_list); + for (bstr_seg = lst_first(bs_list); bstr_seg; + bstr_seg = lst_first(bs_list)) { + bstr_seg = lst_removehead(bs_list); + lst_add(&str_unit->bstr_seg_list, bstr_seg); + } + } + + *str_unit_handle = str_unit; + + return IMG_SUCCESS; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vdecdd_utils.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vdecdd_utils.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vdecdd_utils.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vdecdd_utils.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD Decoder device driver utility header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstream + * Sidraya Jayagond + */ + +#ifndef __VDECDD_UTILS_H__ +#define __VDECDD_UTILS_H__ + +#include "img_errors.h" +#include "vdecdd_defs.h" + +/* The picture buffer alignment (in bytes) for VXD. */ +#define VDEC_VXD_PICTBUF_ALIGNMENT (64) +/* The buffer alignment (in bytes) for VXD. */ +#define VDEC_VXD_BUF_ALIGNMENT (4096) +/* The extended stride alignment for VXD. */ +#define VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT (64) +/* Macroblock dimension (width and height) in pixels. */ +#define VDEC_MB_DIMENSION (16) + +static inline unsigned int vdec_size_min(unsigned int a, unsigned int b) +{ + return a <= b ? a : b; +} + +static inline unsigned char vdec_size_lt(struct vdec_pict_size sa, struct vdec_pict_size sb) +{ + return (sa.width < sb.width && sa.height <= sb.height) || + (sa.width <= sb.width && sa.height < sb.height); +} + +static inline unsigned char vdec_size_ge(struct vdec_pict_size sa, struct vdec_pict_size sb) +{ + return sa.width >= sb.width && sa.height >= sb.height; +} + +static inline unsigned char vdec_size_ne(struct vdec_pict_size sa, struct vdec_pict_size sb) +{ + return sa.width != sb.width || sa.height != sb.height; +} + +static inline unsigned char vdec_size_nz(struct vdec_pict_size sa) +{ + return sa.width != 0 && sa.height != 0; +} + +int vdecddutils_free_strunit(struct vdecdd_str_unit *str_unit); + +int vdecddutils_create_strunit(struct vdecdd_str_unit **str_unit_handle, + struct lst_t *bs_list); + +int vdecddutils_ref_pict_get_maxnum(const struct vdec_str_configdata *str_cfg_data, + const struct vdec_comsequ_hdrinfo *comseq_hdr_info, + unsigned int *num_picts); + +int vdecddutils_get_minrequired_numpicts(const struct vdec_str_configdata *str_cfg_data, + const struct vdec_comsequ_hdrinfo *comseq_hdr_info, + const struct vdec_str_opconfig *op_cfg, + unsigned int *num_picts); + +int vdecddutils_pictbuf_getconfig(const struct vdec_str_configdata *str_cfg_data, + const struct vdec_pict_rend_config *pict_rend_cfg, + const struct vdec_str_opconfig *str_opcfg, + struct vdec_pict_bufconfig *pict_bufcfg); + +int vdecddutils_pictbuf_getinfo(const struct vdec_str_configdata *str_cfg_data, + const struct vdec_pict_rend_config *pict_rend_cfg, + const struct vdec_str_opconfig *str_opcfg, + struct vdec_pict_rendinfo *pict_rend_info); + +int vdecddutils_convert_buffer_config(const struct vdec_str_configdata *str_cfg_data, + const struct vdec_pict_bufconfig *pict_bufcfg, + struct vdec_pict_rendinfo *pict_rend_info); + +int vdecddutils_get_display_region(const struct vdec_pict_size *coded_size, + const struct vdec_rect *orig_disp_region, + struct vdec_rect *disp_region); + +void vdecddutils_buf_vxd_adjust_size(unsigned int *buf_size); + +int vdecddutils_ref_pic_hevc_get_maxnum(const struct vdec_comsequ_hdrinfo *comseq_hdrinfo, + unsigned int *max_ref_picnum); + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vdec_defs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vdec_defs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vdec_defs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vdec_defs.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,555 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD Decoder common header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef __VDEC_DEFS_H__ +#define __VDEC_DEFS_H__ + +#include "img_mem.h" +#include "img_pixfmts.h" +#ifdef HAS_JPEG +#include "jpegfw_data.h" +#endif +#include "pixel_api.h" +#include "vdecfw_shared.h" + +#define VDEC_MAX_PANSCAN_WINDOWS 4 +#define VDEC_MB_DIMENSION (16) + +#define MAX_PICS_IN_SYSTEM (8) +#define SEQUENCE_SLOTS (8) +#define PPS_SLOTS (8) +/* Only for HEVC */ +#define VPS_SLOTS (16) +#define MAX_VPSS (MAX_PICS_IN_SYSTEM + VPS_SLOTS) +#define MAX_SEQUENCES (MAX_PICS_IN_SYSTEM + SEQUENCE_SLOTS) +#define MAX_PPSS (MAX_PICS_IN_SYSTEM + PPS_SLOTS) + +#define VDEC_H264_MAXIMUMVALUEOFCPB_CNT 32 +#define VDEC_H264_MVC_MAX_VIEWS (H264FW_MAX_NUM_VIEWS) + +#define VDEC_ASSERT(expected) ({ WARN_ON(!(expected)); 0; }) + +#define VDEC_ALIGN_SIZE(_val, _alignment, val_type, align_type) \ + ({ \ + val_type val = _val; \ + align_type alignment = _alignment; \ + (((val) + (alignment) - 1) & ~((alignment) - 1)); }) + +/* + * This type defines the video standard. + * @brief VDEC Video Standards + */ +enum vdec_vid_std { + VDEC_STD_UNDEFINED = 0, + VDEC_STD_MPEG2, + VDEC_STD_MPEG4, + VDEC_STD_H263, + VDEC_STD_H264, + VDEC_STD_VC1, + VDEC_STD_AVS, + VDEC_STD_REAL, + VDEC_STD_JPEG, + VDEC_STD_VP6, + VDEC_STD_VP8, + VDEC_STD_SORENSON, + VDEC_STD_HEVC, + VDEC_STD_MAX, + VDEC_STD_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This type defines the bitstream format. Should be done at the + * start of decoding. + * @brief VDEC Bitstream Format + */ +enum vdec_bstr_format { + VDEC_BSTRFORMAT_UNDEFINED = 0, + VDEC_BSTRFORMAT_ELEMENTARY, + VDEC_BSTRFORMAT_DEMUX_BYTESTREAM, + VDEC_BSTRFORMAT_DEMUX_SIZEDELIMITED, + VDEC_BSTRFORMAT_MAX, + VDEC_BSTRFORMAT_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This type defines the Type of payload. Could change with every buffer. + * @brief VDEC Bitstream Element Type + */ +enum vdec_bstr_element_type { + VDEC_BSTRELEMENT_UNDEFINED = 0, + VDEC_BSTRELEMENT_UNSPECIFIED, + VDEC_BSTRELEMENT_CODEC_CONFIG, + VDEC_BSTRELEMENT_PICTURE_DATA, + VDEC_BSTRELEMENT_MAX, + VDEC_BSTRELEMENT_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This structure contains the stream configuration details. + * @brief VDEC Stream Configuration Information + */ +struct vdec_str_configdata { + enum vdec_vid_std vid_std; + enum vdec_bstr_format bstr_format; + unsigned int user_str_id; + unsigned char update_yuv; + unsigned char bandwidth_efficient; + unsigned char disable_mvc; + unsigned char full_scan; + unsigned char immediate_decode; + unsigned char intra_frame_closed_gop; + + /* + * constrain the amount of DPB's allowed + * a value of 0 means let the firmware determine + */ + unsigned int max_dec_frame_buffering; +}; + +/* + * This type defines the buffer type categories. + * @brief Buffer Types + */ +enum vdec_buf_type { + VDEC_BUFTYPE_BITSTREAM, + VDEC_BUFTYPE_PICTURE, + VDEC_BUFTYPE_ALL, + VDEC_BUFTYPE_MAX, + VDEC_BUFTYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This structure contains information related to a picture plane. + * @brief Picture Plane Information + */ +struct vdec_plane_info { + unsigned int offset; + unsigned int stride; + unsigned int size; +}; + +/* + * This structure describes the VDEC picture dimensions. + * @brief VDEC Picture Size + */ +struct vdec_pict_size { + unsigned int width; + unsigned int height; +}; + +/* + * This enumeration defines the colour plane indices. + * @brief Colour Plane Indices + */ +enum vdec_color_planes { + VDEC_PLANE_VIDEO_Y = 0, + VDEC_PLANE_VIDEO_YUV = 0, + VDEC_PLANE_VIDEO_U = 1, + VDEC_PLANE_VIDEO_UV = 1, + VDEC_PLANE_VIDEO_V = 2, + VDEC_PLANE_VIDEO_A = 3, + VDEC_PLANE_LIGHT_R = 0, + VDEC_PLANE_LIGHT_G = 1, + VDEC_PLANE_LIGHT_B = 2, + VDEC_PLANE_INK_C = 0, + VDEC_PLANE_INK_M = 1, + VDEC_PLANE_INK_Y = 2, + VDEC_PLANE_INK_K = 3, + VDEC_PLANE_MAX = 4, + VDEC_PLANE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This structure describes the rendered region of a picture buffer (i.e. where + * the image data is written. + * @brief Picture Buffer Render Information + */ +struct vdec_pict_rendinfo { + unsigned int rendered_size; + struct vdec_plane_info plane_info[VDEC_PLANE_MAX]; + unsigned int stride_alignment; + struct vdec_pict_size rend_pict_size; +}; + +/* + * This structure contains information required to configure the picture + * buffers + * @brief Picture Buffer Configuration + */ +struct vdec_pict_bufconfig { + unsigned int coded_width; + unsigned int coded_height; + enum img_pixfmt pixel_fmt; + unsigned int stride[IMG_MAX_NUM_PLANES]; + unsigned int stride_alignment; + unsigned char byte_interleave; + unsigned int buf_size; + unsigned char packed; + unsigned int chroma_offset[IMG_MAX_NUM_PLANES]; + unsigned int plane_size[IMG_MAX_NUM_PLANES]; +}; + +/* + * This structure describes the VDEC Display Rectangle. + * @brief VDEC Display Rectangle + */ +struct vdec_rect { + unsigned int top_offset; + unsigned int left_offset; + unsigned int width; + unsigned int height; +}; + +/* + * This structure contains the Color Space Description that may be present + * in SequenceDisplayExtn(MPEG2), VUI parameters(H264), Visual Object(MPEG4) + * for the application to use. + * @brief Stream Color Space Properties + */ +struct vdec_color_space_desc { + unsigned char is_present; + unsigned char color_primaries; + unsigned char transfer_characteristics; + unsigned char matrix_coefficients; +}; + +/* + * This structure contains common (standard agnostic) sequence header + * information, which is required for image buffer allocation and display. + * @brief Sequence Header Information (common) + */ +struct vdec_comsequ_hdrinfo { + unsigned int codec_profile; + unsigned int codec_level; + unsigned int bitrate; + long frame_rate; + unsigned int frame_rate_num; + unsigned int frame_rate_den; + unsigned int aspect_ratio_num; + unsigned int aspect_ratio_den; + unsigned char interlaced_frames; + struct pixel_pixinfo pixel_info; + struct vdec_pict_size max_frame_size; + unsigned int max_ref_frame_num; + struct vdec_pict_size frame_size; + unsigned char field_codec_mblocks; + unsigned int min_pict_buf_num; + unsigned char picture_reordering; + unsigned char post_processing; + struct vdec_rect orig_display_region; + struct vdec_rect raw_display_region; + unsigned int num_views; + unsigned int max_reorder_picts; + unsigned char separate_chroma_planes; + unsigned char not_dpb_flush; + struct vdec_color_space_desc color_space_info; +}; + +/* + * This structure contains the standard specific codec configuration + * @brief Codec configuration + */ +struct vdec_codec_config { + unsigned int default_height; + unsigned int default_width; +}; + +/* + * This structure describes the decoded picture attributes (relative to the + * encoded, where necessary, e.g. rotation angle). + * @brief Stream Output Configuration + */ +struct vdec_str_opconfig { + struct pixel_pixinfo pixel_info; + unsigned char force_oold; +}; + +/* + * This type defines the "play" mode. + * @brief Play Mode + */ +enum vdec_play_mode { + VDEC_PLAYMODE_PARSE_ONLY, + VDEC_PLAYMODE_NORMAL_DECODE, + VDEC_PLAYMODE_MAX, + VDEC_PLAYMODE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This type defines the bitstream processing error info. + * @brief Bitstream Processing Error Info + */ +struct vdec_bstr_err_info { + unsigned int sequence_err; + unsigned int picture_err; + unsigned int other_err; +}; + +/* + * This structure describes the VDEC Pan Scan Window. + * @brief VDEC Pan Scan Window + */ +struct vdec_window { + unsigned int ui32topoffset; + unsigned int ui32leftoffset; + unsigned int ui32width; + unsigned int ui32height; +}; + +/* + * This structure contains the VDEC picture display properties. + * @brief VDEC Picture Display Properties + */ +struct vdec_pict_disp_info { + struct vdec_rect enc_disp_region; + struct vdec_rect disp_region; + struct vdec_rect raw_disp_region; + unsigned char top_fld_first; + unsigned char out_top_fld_first; + unsigned int max_frm_repeat; + unsigned int repeat_first_fld; + unsigned int num_pan_scan_windows; + struct vdec_window pan_scan_windows[VDEC_MAX_PANSCAN_WINDOWS]; +}; + +/* + * This structure contains VXD hardware signatures. + * @brief VXD Hardware signatures + */ +struct vdec_pict_hwcrc { + unsigned char first_fld_rcvd; + unsigned int crc_vdmc_pix_recon; + unsigned int vdeb_sysmem_wrdata; +}; + +struct vdec_features { + unsigned char valid; + unsigned char mpeg2; + unsigned char mpeg4; + unsigned char h264; + unsigned char vc1; + unsigned char avs; + unsigned char real; + unsigned char jpeg; + unsigned char vp6; + unsigned char vp8; + unsigned char hevc; + unsigned char hd; + unsigned char rotation; + unsigned char scaling; + unsigned char scaling_oold; + unsigned char scaling_extnd_strides; +}; + +/* + * This type defines the auxiliary info for picture queued for decoding. + * @brief Auxiliary Decoding Picture Info + */ +struct vdec_dec_pict_auxinfo { + unsigned int seq_hdr_id; + unsigned int pps_id; + unsigned int second_pps_id; + unsigned char not_decoded; +}; + +/* + * This type defines the decoded picture state. + * @brief Decoded Picture State + */ +enum vdec_pict_state { + VDEC_PICT_STATE_NOT_DECODED, + VDEC_PICT_STATE_DECODED, + VDEC_PICT_STATE_TERMINATED, + VDEC_PICT_STATE_MAX, + VDEC_PICT_STATE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This type defines the container for various picture tags. + * @brief Picture Tag Container + */ +struct vdec_pict_tag_container { + enum img_buffer_type pict_type; + unsigned long long pict_tag_param; + unsigned long long sideband_info; + struct vdec_pict_hwcrc pict_hwcrc; +}; + +/* + * This structure describes raw bitstream data chunk. + * @brief Raw Bitstream Data Chunk + */ +struct vdec_raw_bstr_data { + unsigned int size; + unsigned int bit_offset; + unsigned char *data; + struct vdec_raw_bstr_data *next; +}; + +/* + * This type defines the supplementary picture data. + * @brief Supplementary Picture Data + */ +struct vdec_pict_supl_data { + struct vdec_raw_bstr_data *raw_vui_data; + struct vdec_raw_bstr_data *raw_sei_list_first_fld; + struct vdec_raw_bstr_data *raw_sei_list_second_fld; + union { + struct h264_pict_supl_data { + unsigned char nal_ref_idc; + unsigned short frame_num; + } data; + }; +}; + +/* + * This structure contains decoded picture information for display. + * @brief Decoded Picture Information + */ +struct vdec_dec_pict_info { + enum vdec_pict_state pict_state; + enum img_buffer_type buf_type; + unsigned char interlaced_flds; + unsigned int err_flags; + unsigned int err_level; + struct vdec_pict_tag_container first_fld_tag_container; + struct vdec_pict_tag_container second_fld_tag_container; + struct vdec_str_opconfig op_config; + struct vdec_pict_rendinfo rend_info; + struct vdec_pict_disp_info disp_info; + unsigned int last_in_seq; + unsigned int decode_id; + unsigned int id_for_hwcrc_chk; + unsigned short view_id; + unsigned int timestamp; + struct vdec_pict_supl_data pict_supl_data; +}; + +struct vdec_pict_rend_config { + struct vdec_pict_size coded_pict_size; + unsigned char packed; + unsigned char byte_interleave; + unsigned int stride_alignment; +}; + +/* + * This structure contains unsupported feature flags. + * @brief Unsupported Feature Flags + */ +struct vdec_unsupp_flags { + unsigned int str_cfg; + unsigned int str_opcfg; + unsigned int op_bufcfg; + unsigned int seq_hdr; + unsigned int pict_hdr; +}; + +/* + * This type defines the error , error in parsing, error in decoding etc. + * @brief VDEC parsing/decoding error Information + */ +enum vdec_error_type { + VDEC_ERROR_NONE = (0), + VDEC_ERROR_SR_ERROR = (1 << 0), + VDEC_ERROR_FEHW_TIMEOUT = (1 << 1), + VDEC_ERROR_FEHW_DECODE = (1 << 2), + VDEC_ERROR_BEHW_TIMEOUT = (1 << 3), + VDEC_ERROR_SERVICE_TIMER_EXPIRY = (1 << 4), + VDEC_ERROR_MISSING_REFERENCES = (1 << 5), + VDEC_ERROR_MMU_FAULT = (1 << 6), + VDEC_ERROR_DEVICE = (1 << 7), + VDEC_ERROR_CORRUPTED_REFERENCE = (1 << 8), + VDEC_ERROR_MMCO = (1 << 9), + VDEC_ERROR_MBS_DROPPED = (1 << 10), + VDEC_ERROR_MAX = (1 << 11), + VDEC_ERROR_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This structure contains information relating to a buffer. + * @brief Buffer Information + */ +struct vdec_buf_info { + void *cpu_linear_addr; + unsigned int buf_id; + struct vdec_pict_bufconfig pictbuf_cfg; + int fd; + /* The following are fields used internally within VDEC... */ + unsigned int buf_size; + enum sys_emem_attrib mem_attrib; + void *buf_alloc_handle; + void *buf_map_handle; + unsigned long dma_addr; +}; + +#ifdef HAS_JPEG +/* + * This structure contains JPEG sequence header information. + * NOTE: Should only contain JPEG specific information. + * @brief JPEG sequence header Information + */ +struct vdec_jpeg_sequ_hdr_info { + /* total component in jpeg */ + unsigned char num_component; + /* precision */ + unsigned char precision; +}; + +/* + * This structure contains JPEG start of frame segment header + * NOTE: Should only contain JPEG specific information. + * @brief JPEG SOF header Information + */ +struct vdec_jpeg_sof_component_hdr { + /* component identifier. */ + unsigned char identifier; + /* Horizontal scaling. */ + unsigned char horz_factor; + /* Verticale scaling */ + unsigned char vert_factor; + /* Qunatisation tables . */ + unsigned char quant_table; +}; + +/* + * This structure contains JPEG start of scan segment header + * NOTE: Should only contain JPEG specific information. + * @brief JPEG SOS header Information + */ +struct vdec_jpeg_sos_component_hdr { + /* component identifier. */ + unsigned char component_index; + /* Huffman DC tables. */ + unsigned char dc_table; + /* Huffman AC table .*/ + unsigned char ac_table; +}; + +struct vdec_jpeg_pict_hdr_info { + /* Start of frame component header */ + struct vdec_jpeg_sof_component_hdr sof_comp[JPEG_VDEC_MAX_COMPONENTS]; + /* Start of Scan component header */ + struct vdec_jpeg_sos_component_hdr sos_comp[JPEG_VDEC_MAX_COMPONENTS]; + /* Huffman tables */ + struct vdec_jpeg_huffman_tableinfo huff_tables[JPEG_VDEC_TABLE_CLASS_NUM] + [JPEG_VDEC_MAX_SETS_HUFFMAN_TABLES]; + /* Quantization tables */ + struct vdec_jpeg_de_quant_tableinfo quant_tables[JPEG_VDEC_MAX_QUANT_TABLES]; + /* Number of MCU in the restart interval */ + unsigned short interval; + unsigned int test; +}; +#endif + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vdecfw_shared.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vdecfw_shared.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vdecfw_shared.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vdecfw_shared.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,893 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Public data structures and enums for the firmware + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifdef USE_SHARING +#endif + +#ifndef _VDECFW_H_ +#define _VDECFW_H_ + +#include "img_msvdx_core_regs.h" +#include "vdecfw_share.h" + +/* brief This type defines the buffer type */ +enum img_buffer_type { + IMG_BUFFERTYPE_FRAME = 0, + IMG_BUFFERTYPE_FIELD_TOP, + IMG_BUFFERTYPE_FIELD_BOTTOM, + IMG_BUFFERTYPE_PAIR, + IMG_BUFFERTYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* Number of scaling coefficients */ +#define VDECFW_NUM_SCALE_COEFFS 4 + +/* + * maximum number of pictures handled by the firmware + * for H.264 (largest requirement): 32 for 4 view MVC + */ +#define VDECFW_MAX_NUM_PICTURES 32 +#define VDECFW_MAX_NUM_VIEWS 4 +#define EMERALD_CORE 6 + +/* + * maximum number of colocated pictures handled by + * firmware in FWBSP mode + */ +#define VDECFWBSP_MAX_NUM_COL_PICS 16 + +/* Maximum number of colour planes. */ +#define VDECFW_PLANE_MAX 4 + +#define VDECFW_NON_EXISTING_PICTURE_TID (0xffffffff) + +#define NO_VALUE 0 + +/* Indicates whether a cyclic sequence number (x) has reached another (y). */ +#define HAS_X_REACHED_Y(x, y, range, type) \ + ({ \ + type __x = x; \ + type __y = y; \ + type __range = range; \ + (((((__x) - (__y) + (__range)) % (__range)) <= \ + (((__y) - (__x) + (__range)) % (__range))) ? TRUE : FALSE); }) + +/* Indicates whether a cyclic sequence number (x) has passed another (y). */ +#define HAS_X_PASSED_Y(x, y, range, type) \ + ({ \ + type __x = x; \ + type __y = y; \ + type __range = range; \ + (((((__x) - (__y) + (__range)) % (__range)) < \ + (((__y) - (__x) + (__range)) % (__range))) ? TRUE : FALSE); }) + +#define FWIF_BIT_MASK(num) ((1 << (num)) - 1) + +/* + * Number of bits in transaction ID used to represent picture number in stream. + */ +#define FWIF_NUMBITS_STREAM_PICTURE_ID 16 +/* Number of bits in transaction ID used to represent picture number in core. */ +#define FWIF_NUMBITS_CORE_PICTURE_ID 4 +/* Number of bits in transaction ID used to represent stream id. */ +#define FWIF_NUMBITS_STREAM_ID 8 +/* Number of bits in transaction ID used to represent core id. */ +#define FWIF_NUMBITS_CORE_ID 4 + +/* Offset in transaction ID to picture number in stream. */ +#define FWIF_OFFSET_STREAM_PICTURE_ID 0 +/* Offset in transaction ID to picture number in core. */ +#define FWIF_OFFSET_CORE_PICTURE_ID \ + (FWIF_OFFSET_STREAM_PICTURE_ID + FWIF_NUMBITS_STREAM_PICTURE_ID) +/* Offset in transaction ID to stream id. */ +#define FWIF_OFFSET_STREAM_ID \ + (FWIF_OFFSET_CORE_PICTURE_ID + FWIF_NUMBITS_CORE_PICTURE_ID) +/* Offset in transaction ID to core id. */ +#define FWIF_OFFSET_CORE_ID \ + (FWIF_OFFSET_STREAM_ID + FWIF_NUMBITS_STREAM_ID) + +/* Picture id (stream) from transaction id. */ +#define GET_STREAM_PICTURE_ID(transaction_id) \ + ((transaction_id) & FWIF_BIT_MASK(FWIF_NUMBITS_STREAM_PICTURE_ID)) +/* Picture id (core) from transaction id. */ +#define GET_CORE_PICTURE_ID(transaction_id) \ + (((transaction_id) >> FWIF_OFFSET_CORE_PICTURE_ID) & \ + FWIF_BIT_MASK(FWIF_NUMBITS_CORE_PICTURE_ID)) +/* Stream id from transaction id. */ +#define GET_STREAM_ID(transaction_id) \ + (((transaction_id) >> FWIF_OFFSET_STREAM_ID) & \ + FWIF_BIT_MASK(FWIF_NUMBITS_STREAM_ID)) +/* Core id from transaction id. */ +#define GET_CORE_ID(transaction_id) \ + (((transaction_id) >> FWIF_OFFSET_CORE_ID) & \ + FWIF_BIT_MASK(FWIF_NUMBITS_CORE_ID)) + +/* Picture id (stream) for transaction id. */ +#define SET_STREAM_PICTURE_ID(str_pic_id) \ + (((str_pic_id) & FWIF_BIT_MASK(FWIF_NUMBITS_STREAM_PICTURE_ID)) << \ + FWIF_OFFSET_STREAM_PICTURE_ID) +/* Picture id (core) for transaction id. */ +#define SET_CORE_PICTURE_ID(core_pic_id) \ + (((core_pic_id) % (1 << FWIF_NUMBITS_CORE_PICTURE_ID)) << \ + FWIF_OFFSET_CORE_PICTURE_ID) +/* Stream id for transaction id. */ +#define SET_STREAM_ID(stream_id) \ + (((stream_id) & FWIF_BIT_MASK(FWIF_NUMBITS_STREAM_ID)) << \ + FWIF_OFFSET_STREAM_ID) +/* Core id for transaction id. */ +#define SET_CORE_ID(core_id) \ + (((core_id) & FWIF_BIT_MASK(FWIF_NUMBITS_CORE_ID)) << \ + FWIF_OFFSET_CORE_ID) +/* flag checking */ +#define FLAG_MASK(_flagname_) ((1 << _flagname_ ## _SHIFT)) +#define FLAG_IS_SET(_flagsword_, _flagname_) \ + (((_flagsword_) & FLAG_MASK(_flagname_)) ? TRUE : FALSE) + +/* This type defines the parser component types */ +enum vdecfw_codectype { + VDECFW_CODEC_H264 = 0, /* H.264, AVC, MVC */ + VDECFW_CODEC_MPEG4, /* MPEG4, H.263, DivX, Sorenson */ + VDECFW_CODEC_VP8, /* VP8 */ + + VDECFW_CODEC_VC1, /* VC1 (includes WMV9) */ + VDECFW_CODEC_MPEG2, /* MPEG2 */ + + VDECFW_CODEC_JPEG, /* JPEG */ + + VDECFW_CODEC_VP6, /* VP6 */ + VDECFW_CODEC_AVS, /* AVS */ + VDECFW_CODEC_RV, /* RV30, RV40 */ + + VDECFW_CODEC_HEVC, /* HEVC/H265 */ + + VDECFW_CODEC_VP9, /* VP9 */ + + VDECFW_CODEC_MAX, /* End Marker */ + + VDEC_CODEC_NONE = -1, /* No codec */ + VDEC_CODEC_FORCE32BITS = 0x7FFFFFFFU +}; + +/* This type defines the FW parser mode - SCP, size delimited, etc. */ +enum vdecfw_parsermode { + /* Every NAL is expected to have SCP */ + VDECFW_SCP_ONLY = 0, + /* Every NAL is expect to be size delimited with field size 4 */ + VDECFW_SIZE_DELIMITED_4_ONLY, + /* Every NAL is expect to be size delimited with field size 2 */ + VDECFW_SIZE_DELIMITED_2_ONLY, + /* Every NAL is expect to be size delimited with field size 1 */ + VDECFW_SIZE_DELIMITED_1_ONLY, + /* Size of NAL is provided in the picture header */ + VDECFW_SIZE_SIDEBAND, + /* Unit is a skipped picture with no data to process */ + VDECFW_SKIPPED_PICTURE, + VDECFW_SKIPPED_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This enum defines values of ENTDEC_BE_MODE field of VEC_ENTDEC_BE_CONTROL + * register and ENTDEC_FE_MODE field of VEC_ENTDEC_FE_CONTROL register. + */ +enum vdecfw_msvdxentdecmode { + /* JPEG */ + VDECFW_ENTDEC_MODE_JPEG = 0x0, + /* H264 (MPEG4/AVC) */ + VDECFW_ENTDEC_MODE_H264 = 0x1, + /* VC1 */ + VDECFW_ENTDEC_MODE_VC1 = 0x2, + /* MPEG2 */ + VDECFW_ENTDEC_MODE_MPEG2 = 0x3, + /* MPEG4 */ + VDECFW_ENTDEC_MODE_MPEG4 = 0x4, + /* AVS */ + VDECFW_ENTDEC_MODE_AVS = 0x5, + /* WMV9 */ + VDECFW_ENTDEC_MODE_WMV9 = 0x6, + /* MPEG1 */ + VDECFW_ENTDEC_MODE_MPEG1 = 0x7, + /* RealVideo8, with ENTDEC_[BE|FE]_EXTENDED_MODE bit set */ + VDECFW_ENTDEC_MODE_EXT_REAL8 = 0x0, + /* RealVideo9, with ENTDEC_[BE|FE]_EXTENDED_MODE bit set */ + VDECFW_ENTDEC_MODE_EXT_REAL9 = 0x1, + /* VP6, with ENTDEC_[BE|FE]_EXTENDED_MODE bit set */ + VDECFW_ENTDEC_MODE_EXT_VP6 = 0x2, + /* VP8, with ENTDEC_[BE|FE]_EXTENDED_MODE bit set */ + VDECFW_ENTDEC_MODE_EXT_VP8 = 0x3, + /* SVC, with ENTDEC_[BE|FE]_EXTENDED_MODE bit set */ + VDECFW_ENTDEC_MODE_EXT_SVC = 0x4, + VDECFW_ENTDEC_MODE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This describes the Firmware Parser checkpoints in VEC Local RAM. + * Each checkpoint is updated with the TransactionID of the picture as it passes + * that point in its decode. Together they describe the current position of + * pictures in the VXD/Firmware pipeline. + * + * Numbers indicate point in the "VDEC Firmware Component Timing" diagram. + */ +enum vdecfw_progresscheckpoint { + /* Decode message has been read */ + VDECFW_CHECKPOINT_PICTURE_STARTED = 1, + /* Firmware has been loaded and bitstream DMA started */ + VDECFW_CHECKPOINT_FIRMWARE_READY = 2, + /* Picture management operations have completed */ + VDECFW_CHECKPOINT_PICMAN_COMPLETE = 3, + /* Firmware context for this picture has been saved */ + VDECFW_CHECKPOINT_FIRMWARE_SAVED = 4, + /* + * 1st Picture/Slice header has been read, + * registers written and Entdec started + */ + VDECFW_CHECKPOINT_ENTDEC_STARTED = 5, + /* 1st Slice has been completed by Entdec */ + VDECFW_CHECKPOINT_FE_1SLICE_DONE = 6, + /* Parsing of picture has completed on FE */ + VDECFW_CHECKPOINT_FE_PARSE_DONE = 7, + /* Picture end code has been read and picture closed */ + VDECFW_CHECKPOINT_FE_PICTURE_COMPLETE = 8, + /* Picture has started decoding on VXD Backend */ + VDECFW_CHECKPOINT_BE_PICTURE_STARTED = 9, + /* 1st Slice has completed on VXD Backend */ + VDECFW_CHECKPOINT_BE_1SLICE_DONE = 10, + /* Picture decode has completed and done message sent to the Host */ + VDECFW_CHECKPOINT_BE_PICTURE_COMPLETE = 11, +#ifndef FW_STACK_USAGE_TRACKING + /* General purpose check point 1 */ + VDECFW_CHECKPOINT_AUX1 = 12, + /* General purpose check point 2 */ + VDECFW_CHECKPOINT_AUX2 = 13, + /* General purpose check point 3 */ + VDECFW_CHECKPOINT_AUX3 = 14, + /* General purpose check point 4 */ + VDECFW_CHECKPOINT_AUX4 = 15, +#endif /* ndef FW_STACK_USAGE_TRACKING */ + VDECFW_CHECKPOINT_MAX, + /* + * Indicate which checkpoints mark the start and end of each + * group (FW, FE and BE). + * The start and end values should be updated if new checkpoints are + * added before the current start or after the current end of any group. + */ + VDECFW_CHECKPOINT_FW_START = VDECFW_CHECKPOINT_PICTURE_STARTED, + VDECFW_CHECKPOINT_FW_END = VDECFW_CHECKPOINT_FIRMWARE_SAVED, + VDECFW_CHECKPOINT_FE_START = VDECFW_CHECKPOINT_ENTDEC_STARTED, + VDECFW_CHECKPOINT_FE_END = VDECFW_CHECKPOINT_FE_PICTURE_COMPLETE, + VDECFW_CHECKPOINT_BE_START = VDECFW_CHECKPOINT_BE_PICTURE_STARTED, + VDECFW_CHECKPOINT_BE_END = VDECFW_CHECKPOINT_BE_PICTURE_COMPLETE, + VDECFW_CHECKPOINT_FORCE32BITS = 0x7FFFFFFFU +}; + +/* Number of auxiliary firmware checkpoints. */ +#define VDECFW_CHECKPOINT_AUX_COUNT 4 +/* This describes the action currently being done by the Firmware. */ +enum vdecfw_firmwareaction { + VDECFW_FWACT_IDLE = 1, /* Firmware is currently doing nothing */ + VDECFW_FWACT_BASE_LOADING_PSR, /* Loading parser context */ + VDECFW_FWACT_BASE_SAVING_PSR, /* Saving parser context */ + VDECFW_FWACT_BASE_LOADING_BEMOD, /* Loading Backend module */ + VDECFW_FWACT_BASE_LOADING_FEMOD, /* Loading Frontend module */ + VDECFW_FWACT_PARSER_SLICE, /* Parser active: parsing slice */ + VDECFW_FWACT_PARSER_PM, /* Parser active: picture management */ + VDECFE_FWACT_BEMOD_ACTIVE, /* Backend module active */ + VDECFE_FWACT_FEMOD_ACTIVE, /* Frontend module active */ + VDECFW_FWACT_MAX, + VDECFW_FWACT_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This describes the FE_ERR flags word in the VDECFW_MSGID_PIC_DECODED message + */ +enum vdecfw_msgflagdecodedfeerror { + /* Front-end hardware watchdog timeout (FE_WDT_CM0) */ + VDECFW_MSGFLAG_DECODED_FEERROR_HWWDT_SHIFT = 0, + /* Front-end entdec error (VEC_ERROR_DETECTED_ENTDEC) */ + VDECFW_MSGFLAG_DECODED_FEERROR_ENTDECERROR_SHIFT, + /* Shift-register error (VEC_ERROR_DETECTED_SR) */ + VDECFW_MSGFLAG_DECODED_FEERROR_SRERROR_SHIFT, + /* For cases when B frame comes after I without P. */ + VDECFW_MSGFLAG_DECODED_MISSING_REFERENCES_SHIFT, + /* MMCO operation failed. */ + VDECFW_MSGFLAG_DECODED_MMCO_ERROR_SHIFT, + /* Back-end WDT timeout */ + VDECFW_MSGFLAG_DECODED_BEERROR_HWWDT_SHIFT, + /* Some macroblocks were dropped */ + VDECFW_MSGFLAG_DECODED_MBS_DROPPED_ERROR_SHIFT, + VDECFW_MSGFLAG_DECODED_FEERROR_MAX, + VDECFW_MSGFLAG_DECODED_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This type defines the IDs of the messages used to communicate with the + * Firmware. + * + * The Firmware has 3 message buffers, each buffer uses a different set of IDs. + * The buffers are: + * Host -> FW -Control messages(High Priority: processed in interrupt context) + * Host -> FW -Decode commands and associated information + * (Normal Priority: processed in baseloop) + * FW -> Host -Completion message + */ +enum vdecfw_message_id { + /* Control Messages */ + /* + * Host -> FW Padding message + * Sent to optionally pad the message buffer + */ + VDECFW_MSGID_BASE_PADDING = 0x01, + /* + * Host -> FW Initialisation message Initialisation should be + * sent *immediately* after loading the base component + * ie. while the FW is idle + */ + VDECFW_MSGID_FIRMWARE_INIT, + /* + * Host -> FW Configuration message + * Configuration should be setup after loading the base component + * and before decoding the next picture ie. while the FW is idle + */ + VDECFW_MSGID_FIRMWARE_CONFIG, + /* + * Host -> FW Control message + * Firmware control command to have immediate affect + * eg. Stop stream, return CRCs, return Performance Data + */ + VDECFW_MSGID_FIRMWARE_CONTROL, + VDECFW_MSGID_CONTROL_MAX, + /* Decode Commands */ + /* + * Host -> FW Padding message + * Sent to optionally pad the message buffer + */ + VDECFW_MSGID_PSR_PADDING = 0x40, + /* + * Host -> FW Decode message + * Describes the picture to decode + */ + VDECFW_MSGID_DECODE_PICTURE, + /* + * Host -> FW Bitstream buffer information + * Information describing a bitstream buffer to DMA to VXD + */ + VDECFW_MSGID_BITSTREAM_BUFFER, + /* + * Host -> FW Fence message + * Generate an interrupt when this is read, + * FenceID should be written to a location in VLR + */ + VDECFW_MSGID_FENCE, + /* + * Host -> FW Batch message + * Contains a pointer to a host memory buffer + * containing a batch of decode command FW messages + */ + VDECFW_MSGID_BATCH, + VDECFW_MSGID_DECODE_MAX, + /* Completion Messages */ + /* + * FW -> Host Padding message + * Sent to optionally pad the message buffer + */ + VDECFW_MSGID_BE_PADDING = 0x80, + /* + * FW -> Host Decoded Picture message + * Notification of decoded picture including errors recorded + */ + VDECFW_MSGID_PIC_DECODED, + /* + * FW -> Host CRC message + * Optionally sent with Decoded Picture message, contains VXD CRCs + */ + VDECFW_MSGID_PIC_CRCS, + /* + * FW -> Host Performance message + * Optional timestamps at the decode checkpoints and other information + * about the image to assist in measuring performance + */ + VDECFW_MSGID_PIC_PERFORMANCE, + /* FW -> Host POST calculation test message */ + VDECFW_MSGID_PIC_POST_RESP, + VDECFW_MSGID_COMPLETION_MAX, + VDECFW_MSGID_FORCE32BITS = 0x7FFFFFFFU +}; + +#define VDECFW_MSGID_CONTROL_TYPES \ + (VDECFW_MSGID_CONTROL_MAX - VDECFW_MSGID_BASE_PADDING) +#define VDECFW_MSGID_DECODE_TYPES \ + (VDECFW_MSGID_DECODE_MAX - VDECFW_MSGID_PSR_PADDING) +#define VDECFW_MSGID_COMPLETION_TYPES \ + (VDECFW_MSGID_COMPLETION_MAX - VDECFW_MSGID_BE_PADDING) + +/* This describes the layout of PVDEC Firmware state indicators in Comms RAM. */ + +/* Maximum number of PVDEC decoding pipes per core supported. */ +#define VDECFW_MAX_DP 3 + +struct vdecfw_pvdecpipestate { + /* TransactionID at each checkpoint */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, check_point[VDECFW_CHECKPOINT_MAX]); + /* VDECFW_eFirmwareAction (UINT32 used to guarantee size) */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, firmware_action); + /* Number of FE Slices processed for the last picture in FE */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, fe_slices); + /* Number of BE Slices processed for the last picture in BE */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, be_slices); + /* + * Number of FE Slices being detected as erroed for the last picture + * in FE + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, fe_errored_slices); + /* + * Number of BE Slices being detected as erroed for the last picture + * in BE + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, be_errored_slices); + /* Number of BE macroblocks dropped for the last picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, be_mbs_dropped); + /* Number of BE macroblocks recovered for the last picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, be_mbs_recovered); + /* Number of FE macroblocks processed for the last picture in FE */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, last_fe_mb_xy); + /* Number of BE macroblocks processed for the last picture in BE */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, last_be_mb_xy); + /* VDECFW_eCodecType - Codec currently loaded */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, curr_codec); + /* TRUE if this pipe is available for processing */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, pipe_present); +}; + +#ifdef FW_STACK_USAGE_TRACKING +/* Stack usage info array size. */ +#define VDECFW_STACK_INFO_SIZE (VDECFW_MAX_DP * VDECFW_CHECKPOINT_AUX_COUNT) +#endif /* FW_STACK_USAGE_TRACKING */ +struct vdecfw_pvdecfirmwarestate { + /* + * Indicates generic progress taken by firmware + * (must be the first item) + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, fwstep); + /* Pipe state array. */ + struct vdecfw_pvdecpipestate pipestate[VDECFW_MAX_DP]; +#ifdef FW_STACK_USAGE_TRACKING + /* Stack usage info array. */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, unsigned int, + stackinfo[VDECFW_STACK_INFO_SIZE]); +#endif /* FW_STACK_USAGE_TRACKING */ +}; + +/* + * This describes the flags word in the aui8DisplayFlags + * in VDECFW_sBufferControl + */ +enum vdecfw_bufflagdisplay { + /* TID has been flushed with a "no display" indication */ + VDECFW_BUFFLAG_DISPLAY_NODISPLAY_SHIFT = 0, + /* TID contains an unpaired field */ + VDECFW_BUFFLAG_DISPLAY_SINGLE_FIELD_SHIFT = 1, + /* TID contains field coded picture(s) - single field or pair */ + VDECFW_BUFFLAG_DISPLAY_FIELD_CODED_SHIFT = 2, + /* if TID contains a single field, this defines which field that is */ + VDECFW_BUFFLAG_DISPLAY_BOTTOM_FIELD_SHIFT = 3, + /* if TID contains a frame with two interlaced fields */ + VDECFW_BUFFLAG_DISPLAY_INTERLACED_FIELDS_SHIFT = 4, + /* End marker */ + VDECFW_BUFFLAG_DISPLAY_MAX = 8, + VDECFW_BUFFLAG_DISPLAY_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This describes the flags in the ui8PictMgmtFlags field in + * VDECFW_sBufferControl + */ +enum vdecfw_picmgmflags { + /* Picture management for this picture successfully executed */ + VDECFW_PICMGMTFLAG_PICTURE_EXECUTED_SHIFT = 0, + /* + * Picture management for the first field of this picture + * successfully executed + */ + VDECFW_PICMGMTFLAG_1ST_FIELD_EXECUTED_SHIFT = 0, + /* + * Picture management for the second field of this picture + * successfully executed + */ + VDECFW_PICMGMTFLAG_2ND_FIELD_EXECUTED_SHIFT = 1, + VDECFW_PICMGMTFLAG_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Macro for checking if picture management was successfully executed for + * field coded picture + */ +#define VDECFW_PICMGMT_FIELD_CODED_PICTURE_EXECUTED(_flagsword_) \ + ((FLAG_IS_SET(buf_control->picmgmt_flags, \ + VDECFW_PICMGMTFLAG_1ST_FIELD_EXECUTED) && \ + FLAG_IS_SET(buf_control->picmgmt_flags, \ + VDECFW_PICMGMTFLAG_2ND_FIELD_EXECUTED)) ? \ + TRUE : FALSE) +/* This describes the REAL related data for the current picture. */ +struct vdecfw_real_data { + /* Picture width */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, width); + /* Picture height */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, height); + /* Scaled Picture Width */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, scaled_width); + /* Scaled Picture Height */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, scaled_height); + /* Timestamp parsed in the firmware */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, timestamp); +}; + +/* This describes the HEVC related data for the current picture. */ +struct vdecfw_hevcdata { + /* POC */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, int, pic_order_count); +}; + +/* + * This describes the buffer control structure that is used by the firmware to + * signal to the Host to control the display and release of buffers. + */ +struct vdecfw_buffer_control { + /* + * List of TransactionIDs indicating buffers ready to display, + * in display order + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, display_list[VDECFW_MAX_NUM_PICTURES]); + /* + * List of TransactionIDs indicating buffers that are no longer + * required for reference + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, + release_list[VDECFW_MAX_NUM_PICTURES + + VDECFW_MAX_NUM_VIEWS]); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, + display_view_ids[VDECFW_MAX_NUM_PICTURES]); + /* List of flags for each TID in the DisplayList */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, display_flags[VDECFW_MAX_NUM_PICTURES]); + /* Number of TransactionIDs in aui32DisplayList */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, display_list_length); + /* Number of TransactionIDs in aui32ReleaseList */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, release_list_length); + union { + struct vdecfw_real_data real_data; + struct vdecfw_hevcdata hevc_data; + }; + /* + * Refers to the picture decoded with the current transaction ID + * (not affected by merge with field of previous transaction ID) + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + enum img_buffer_type, dec_pict_type); + /* Set if the current field is a pair to the previous field */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, second_field_of_pair); + /* + * Set if for a pair we decoded first the top field or + * if we have only top field + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, top_field_first); + /* Top field is first to be displayed */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, out_top_field_first); + /* Picture management flags for this picture */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, picmgmt_flags); + /* + * List of TransactionIDs indicating buffers used as references + * when decoding current picture + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, ref_list[VDECFW_MAX_NUM_PICTURES]); +}; + +/* + * This describes an image buffer for one picture supplied to + * the firmware by the host + */ +struct vdecfw_image_buffer { + /* Virtual Address of each plane */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, byte_offset[VDECFW_PLANE_MAX]); +}; + +/* This type defines the picture commands that are prepared for the firmware. */ +enum vdecfw_picture_cmds { + /* Reconstructed buffer */ + /* DISPLAY_PICTURE_SIZE */ + VDECFW_CMD_DISPLAY_PICTURE, + /* CODED_PICTURE_SIZE */ + VDECFW_CMD_CODED_PICTURE, + /* OPERATING_MODE */ + VDECFW_CMD_OPERATING_MODE, + /* LUMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES */ + VDECFW_CMD_LUMA_RECONSTRUCTED_PICTURE_BASE_ADDRESS, + /* CHROMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES */ + VDECFW_CMD_CHROMA_RECONSTRUCTED_PICTURE_BASE_ADDRESS, + /* CHROMA2_RECONSTRUCTED_PICTURE_BASE_ADDRESSES */ + VDECFW_CMD_CHROMA2_RECONSTRUCTED_PICTURE_BASE_ADDRESS, + /* VC1_LUMA_RANGE_MAPPING_BASE_ADDRESS */ + VDECFW_CMD_LUMA_ALTERNATIVE_PICTURE_BASE_ADDRESS, + /* VC1_CHROMA_RANGE_MAPPING_BASE_ADDRESS */ + VDECFW_CMD_CHROMA_ALTERNATIVE_PICTURE_BASE_ADDRESS, + /* CHROMA2_ALTERNATIVE_PICTURE_BASE_ADDRESS */ + VDECFW_CMD_CHROMA2_ALTERNATIVE_PICTURE_BASE_ADDRESS, + /* LUMA_ERROR_PICTURE_BASE_ADDRESSES */ + VDECFW_CMD_LUMA_ERROR_PICTURE_BASE_ADDRESS, + /* CHROMA_ERROR_PICTURE_BASE_ADDRESSES */ + VDECFW_CMD_CHROMA_ERROR_PICTURE_BASE_ADDRESS, + /* AUX_MSB_BUFFER_BASE_ADDRESSES (VC-1 only) */ + VDECFW_CMD_AUX_MSB_BUFFER, + /* INTRA_BUFFER_BASE_ADDRESS (various) */ + VDECFW_CMD_INTRA_BUFFER_BASE_ADDRESS, + /* AUX_LINE_BUFFER_BASE_ADDRESS */ + VDECFW_CMD_AUX_LINE_BUFFER_BASE_ADDRESS, + /* MBFLAGS_BUFFER_BASE_ADDRESSES (VP8 only) */ + VDECFW_CMD_MBFLAGS_BUFFER_BASE_ADDRESS, + /* FIRST_PARTITION_BASE_ADDRESSES (VP8 only) */ + VDECFW_CMD_FIRST_PARTITION_BUFFER_BASE_ADDRESS, + /* CURRENT_PICTURE_BUFFER_BASE_ADDRESSES (VP8 only) */ + VDECFW_CMD_CURRENT_PICTURE_BUFFER_BASE_ADDRESS, + /* SEGMENTID_BUFFER_BASE_ADDRESSES (VP8 only) */ + VDECFW_CMD_SEGMENTID_BASE_ADDRESS, + /* EXT_OP_MODE (H.264 only) */ + VDECFW_CMD_EXT_OP_MODE, + /* MC_CACHE_CONFIGURATION */ + VDECFW_CMD_MC_CACHE_CONFIGURATION, + /* Alternative output buffer (rotation etc.) */ + /* ALTERNATIVE_OUTPUT_PICTURE_ROTATION */ + VDECFW_CMD_ALTERNATIVE_OUTPUT_PICTURE_ROTATION, + /* EXTENDED_ROW_STRIDE */ + VDECFW_CMD_EXTENDED_ROW_STRIDE, + /* CHROMA_ROW_STRIDE (H.264 only) */ + VDECFW_CMD_CHROMA_ROW_STRIDE, + /* ALTERNATIVE_OUTPUT_CONTROL */ + VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL, + /* RPR specific commands */ + /* RPR_AX_INITIAL */ + VDECFW_CMD_RPR_AX_INITIAL, + /* RPR_AX_INCREMENT */ + VDECFW_CMD_RPR_AX_INCREMENT, + /* RPR_AY_INITIAL */ + VDECFW_CMD_RPR_AY_INITIAL, + /* RPR_AY_INCREMENT */ + VDECFW_CMD_RPR_AY_INCREMENT, + /* RPR_PICTURE_SIZE */ + VDECFW_CMD_RPR_PICTURE_SIZE, + /* Scaling specific params */ + /* SCALED_DISPLAY_SIZE */ + VDECFW_CMD_SCALED_DISPLAY_SIZE, + /* HORIZONTAL_SCALE_CONTROL */ + VDECFW_CMD_HORIZONTAL_SCALE_CONTROL, + /* SCALE_HORIZONTAL_CHROMA (H.264 only) */ + VDECFW_CMD_SCALE_HORIZONTAL_CHROMA, + /* VERTICAL_SCALE_CONTROL */ + VDECFW_CMD_VERTICAL_SCALE_CONTROL, + /* SCALE_VERTICAL_CHROMA (H.264 only) */ + VDECFW_CMD_SCALE_VERTICAL_CHROMA, + /* HORIZONTAL_LUMA_COEFFICIENTS_0 */ + VDECFW_CMD_HORIZONTAL_LUMA_COEFFICIENTS_0, + /* HORIZONTAL_LUMA_COEFFICIENTS_1 */ + VDECFW_CMD_HORIZONTAL_LUMA_COEFFICIENTS_1, + /* HORIZONTAL_LUMA_COEFFICIENTS_2 */ + VDECFW_CMD_HORIZONTAL_LUMA_COEFFICIENTS_2, + /* HORIZONTAL_LUMA_COEFFICIENTS_3 */ + VDECFW_CMD_HORIZONTAL_LUMA_COEFFICIENTS_3, + /* VERTICAL_LUMA_COEFFICIENTS_0 */ + VDECFW_CMD_VERTICAL_LUMA_COEFFICIENTS_0, + /* VERTICAL_LUMA_COEFFICIENTS_1 */ + VDECFW_CMD_VERTICAL_LUMA_COEFFICIENTS_1, + /* VERTICAL_LUMA_COEFFICIENTS_2 */ + VDECFW_CMD_VERTICAL_LUMA_COEFFICIENTS_2, + /* VERTICAL_LUMA_COEFFICIENTS_3 */ + VDECFW_CMD_VERTICAL_LUMA_COEFFICIENTS_3, + /* HORIZONTAL_CHROMA_COEFFICIENTS_0 */ + VDECFW_CMD_HORIZONTAL_CHROMA_COEFFICIENTS_0, + /* HORIZONTAL_CHROMA_COEFFICIENTS_1 */ + VDECFW_CMD_HORIZONTAL_CHROMA_COEFFICIENTS_1, + /* HORIZONTAL_CHROMA_COEFFICIENTS_2 */ + VDECFW_CMD_HORIZONTAL_CHROMA_COEFFICIENTS_2, + /* HORIZONTAL_CHROMA_COEFFICIENTS_3 */ + VDECFW_CMD_HORIZONTAL_CHROMA_COEFFICIENTS_3, + /* VERTICAL_CHROMA_COEFFICIENTS_0 */ + VDECFW_CMD_VERTICAL_CHROMA_COEFFICIENTS_0, + /* VERTICAL_CHROMA_COEFFICIENTS_1 */ + VDECFW_CMD_VERTICAL_CHROMA_COEFFICIENTS_1, + /* VERTICAL_CHROMA_COEFFICIENTS_2 */ + VDECFW_CMD_VERTICAL_CHROMA_COEFFICIENTS_2, + /* VERTICAL_CHROMA_COEFFICIENTS_3 */ + VDECFW_CMD_VERTICAL_CHROMA_COEFFICIENTS_3, + /* SCALE_OUTPUT_SIZE */ + VDECFW_CMD_SCALE_OUTPUT_SIZE, + /* VDECFW_CMD_INTRA_BUFFER_PLANE_SIZE */ + VDECFW_CMD_INTRA_BUFFER_PLANE_SIZE, + /* VDECFW_CMD_INTRA_BUFFER_SIZE_PER_PIPE */ + VDECFW_CMD_INTRA_BUFFER_SIZE_PER_PIPE, + /* VDECFW_CMD_AUX_LINE_BUFFER_SIZE_PER_PIPE */ + VDECFW_CMD_AUX_LINE_BUFFER_SIZE_PER_PIPE, + VDECFW_SLICE_X_MB_OFFSET, + VDECFW_SLICE_Y_MB_OFFSET, + VDECFW_SLICE_TYPE, + VDECFW_CMD_MAX, + VDECFW_CMD_FORCE32BITS = 0x7FFFFFFFU +}; + +/* Size of relocation data attached to VDECFW_sTransaction message in words */ +#define VDECFW_RELOC_SIZE 125 + +/* This structure defines the MMU Tile configuration. */ +struct vdecfw_mmu_tile_config { + /* MMU_CONTROL2 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned char, tilig_scheme); + /* MMU_TILE */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, + mmu_tiling[MSVDX_CORE_CR_MMU_TILE_NO_ENTRIES]); + /* MMU_TILE_EXT */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, + mmu_tiling_ext[MSVDX_CORE_CR_MMU_TILE_EXT_NO_ENTRIES]); +}; + +/* + * This structure contains the transaction attributes to be given to the + * firmware + * @brief Transaction Attributes + */ +struct vdecfw_transaction { + /* Unique identifier for the picture (driver-wide). */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, transation_id); + /* Codec */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + enum vdecfw_codectype, codec); + /* + * Flag to indicate that the stream needs to ge handled + * in secure memory (if available) + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + int, secure_stream); + /* Unique identifier for the current stream */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, stream_id); + /* Dictates to the FW parser how the NALs are delimited */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + enum vdecfw_parsermode, parser_mode); + /* Address from which to load the parser context data. */ + IMG_ALIGN_FIELD(VDECFW_SHARE_PTR_ALIGNMENT, + unsigned int, ctx_load_addr); + /* + * Address to save the parser state data including the updated + * "parser context data". + */ + IMG_ALIGN_FIELD(VDECFW_SHARE_PTR_ALIGNMENT, + unsigned int, ctx_save_addr); + /* Size of the parser context data in bytes. */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, ctx_size); + /* Address to save the "buffer control" data. */ + IMG_ALIGN_FIELD(VDECFW_SHARE_PTR_ALIGNMENT, + unsigned int, ctrl_save_addr); + /* Size of the buffer control data in bytes. */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, ctrl_size); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, pict_cmds[VDECFW_CMD_MAX]); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, pic_width_inmbs); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, pic_height_inmbs); + + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, mbparams_base_addr); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, mbparams_size_per_plane); + /* Address of VLC table data. */ + IMG_ALIGN_FIELD(VDECFW_SHARE_PTR_ALIGNMENT, + unsigned int, vlc_tables_addr); + /* Size of the VLC table data in bytes. */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, vlc_tables_size); + /* Address of VLC index table data. */ + IMG_ALIGN_FIELD(VDECFW_SHARE_PTR_ALIGNMENT, + unsigned int, vlc_index_table_addr); + /* Size of the VLC index table data in bytes. */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, vlc_index_table_size); + /* Address of parser picture header. */ + IMG_ALIGN_FIELD(VDECFW_SHARE_PTR_ALIGNMENT, + unsigned int, psr_hdr_addr); + /* Size of the parser picture header in bytes. */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, psr_hdr_size); + /* Address of Sequence Info in the Host (secure) */ + IMG_ALIGN_FIELD(VDECFW_SHARE_PTR_ALIGNMENT, + unsigned int, sequence_info_source); + /* Address of PPS Info in the Host (secure) */ + IMG_ALIGN_FIELD(VDECFW_SHARE_PTR_ALIGNMENT, + unsigned int, pps_info_source); + /* Address of Second PPS Info in the Host (secure) */ + IMG_ALIGN_FIELD(VDECFW_SHARE_PTR_ALIGNMENT, + unsigned int, second_pps_info_source); + /* MMU Tile config comes down with each transaction. */ + struct vdecfw_mmu_tile_config mmu_tile_config; +}; + +/* + * This structure contains the info for extracting a subset of VLC tables + * indexed inside the index table. + * aui32VlcTablesOffset is the offset to the first table inside the index table + * aui32VlcConsecutiveTables indicates the consecutive number of entries (from + * aui32VlcTablesOffset to aui32VlcTablesOffset+aui32VlcConsecutiveTables) + * which will be copied. + */ +struct vdecfw_vlc_table_info { + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, vlc_table_offset); + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned short, vlc_consecutive_tables); +}; + +/* This structure defines the RENDEC buffer configuration. */ +struct vdecfw_rendec_config { + /* VEC_RENDEC_CONTROL0 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, regvec_rendec_control0); + /* VEC_RENDEC_CONTROL1 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, regvec_rendec_control1); + /* VEC_RENDEC_BASE_ADDR0 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, rendec_buffer_baseaddr0); + /* VEC_RENDEC_BASE_ADDR1 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, rendec_buffer_baseaddr1); + /* VEC_RENDEC_BUFFER_SIZE */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, regvec_rendec_buffer_size); + /* VEC_RENDEC_CONTEXT0 - VEC_RENDEC_CONTEXT5 */ + IMG_ALIGN_FIELD(VDECFW_SHARE_DEFAULT_ALIGNMENT, + unsigned int, rendec_initial_ctx[6]); +}; + +#endif /* _VDECFW_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vdecfw_share.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vdecfw_share.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vdecfw_share.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vdecfw_share.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD DEC SYSDEV and UI Interface header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ +#ifndef _VDECFW_SHARE_H_ +#define _VDECFW_SHARE_H_ + +/* + * This macro sets alignment for a field structure. + * Parameters : + * a - alignment value + * t - field type + * n - field name + */ +#define IMG_ALIGN_FIELD(a, t, n) t n __aligned(a) + +/* END of vdecfw_share_macros.h */ + +/* + * Field alignments in shared data structures + */ +/* Default field alignment */ +#define VDECFW_SHARE_DEFAULT_ALIGNMENT 4 +/* Pointer field alignment */ +#define VDECFW_SHARE_PTR_ALIGNMENT 4 + +#endif /* _VDECFW_SHARE_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vdec_mmu_wrapper.c b/drivers/media/platform/imagination/vxe-vxd/decoder/vdec_mmu_wrapper.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vdec_mmu_wrapper.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vdec_mmu_wrapper.c 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,829 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VDEC MMU Functions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Sidraya Jayagond + */ + +#include "img_dec_common.h" +#include "lst.h" +#include "talmmu_api.h" +#include "vdec_defs.h" +#include "vdec_mmu_wrapper.h" +#include "vxd_dec.h" + +#define GUARD_BAND 0x1000 + +struct mmuheap { + unsigned char *name; + enum mmu_eheap_id heap_id; + enum talmmu_heap_type heap_type; + unsigned int start_offset; + unsigned int size; + unsigned char *mem_space; + unsigned char use_guard_band; + unsigned char image_buffers; +}; + +static const struct mmuheap mmu_heaps[MMU_HEAP_MAX] = { + { "Image untiled", MMU_HEAP_IMAGE_BUFFERS_UNTILED, + TALMMU_HEAP_PERCONTEXT, PVDEC_HEAP_UNTILED_START, + PVDEC_HEAP_UNTILED_SIZE, "MEMBE", 1, 1 }, + + { "Bitstream", MMU_HEAP_BITSTREAM_BUFFERS, + TALMMU_HEAP_PERCONTEXT, PVDEC_HEAP_BITSTREAM_START, + PVDEC_HEAP_BITSTREAM_SIZE, "MEMDMAC_02", 1, 0 }, + + { "Stream", MMU_HEAP_STREAM_BUFFERS, + TALMMU_HEAP_PERCONTEXT, PVDEC_HEAP_STREAM_START, + PVDEC_HEAP_STREAM_SIZE, "MEM", 1, 0 }, +}; + +/* + * @Heap ID + * @Heap type + * @Heap flags + * @Memory space name + * @Start address (virtual) + * @Size of heap, in bytes + */ +static struct talmmu_heap_info heap_info = { + MMU_HEAP_IMAGE_BUFFERS_UNTILED, + TALMMU_HEAP_PERCONTEXT, + TALMMU_HEAPFLAGS_NONE, + "MEMBE", + 0, + 0, +}; + +/* + * This structure contains the device context. + * @brief VDECDD MMU Device Context + * @devmem_template_hndl: Handle for MMU template. + * @devmem_ctx_hndl: Handle for MMU context. + * @str_list: List of streams. + */ +struct mmu_dev_context { + void *devmem_template_hndl; + void *devmem_ctx_hndl; + struct lst_t str_list; + unsigned int ctx_id; + unsigned int next_ctx_id; +}; + +/* + * This structure contains the stream context. + * @brief VDECDD MMU Stream Context + * @LST_LINK: List link (allows the structure to be part of a MeOS list). + * @devmem_ctx_hndl: Handle for MMU context. + * @dev_ctx: Pointer to device context. + * @ctx_id: MMU context Id. + * km_str_id: Stream ID used in communication with new KM interface + */ +struct mmu_str_context { + void **link; + void *devmem_ctx_hndl; + struct mmu_dev_context *dev_ctx; + unsigned int ctx_id; + void *ptd_memspace_hndl; + unsigned int int_reg_num; + unsigned int km_str_id; + struct vxd_dec_ctx *vxd_dec_context; +}; + +static unsigned int set_attributes(enum sys_emem_attrib mem_attrib) +{ + unsigned int attrib = 0; + + if (mem_attrib & SYS_MEMATTRIB_CACHED) + attrib |= MEM_ATTR_CACHED; + + if (mem_attrib & SYS_MEMATTRIB_UNCACHED) + attrib |= MEM_ATTR_UNCACHED; + + if (mem_attrib & SYS_MEMATTRIB_WRITECOMBINE) + attrib |= MEM_ATTR_WRITECOMBINE; + + if (mem_attrib & SYS_MEMATTRIB_SECURE) + attrib |= MEM_ATTR_SECURE; + + return attrib; +} + +/* + * @Function mmu_dev_mem_context_create + */ +static int mmu_devmem_context_create(struct mmu_dev_context *dev_ctx, void **mmu_ctx_hndl) +{ + int result; + void *devmem_heap_hndl; + union talmmu_heap_options heap_opt1; + unsigned int i; + unsigned char use_guardband; + enum talmmu_heap_option_id heap_option_id; + + dev_ctx->next_ctx_id++; + + /* Create a context from the template */ + result = talmmu_devmem_ctx_create(dev_ctx->devmem_template_hndl, dev_ctx->next_ctx_id, + mmu_ctx_hndl); + if (result != IMG_SUCCESS) + return result; + + /* Apply options to heaps. */ + heap_opt1.guardband_opt.guardband = GUARD_BAND; + + for (i = 0; i < MMU_HEAP_MAX; i++) { + result = talmmu_get_heap_handle(mmu_heaps[i].heap_id, *mmu_ctx_hndl, + &devmem_heap_hndl); + if (result != IMG_SUCCESS) + return result; + + use_guardband = mmu_heaps[i].use_guard_band; + heap_option_id = TALMMU_HEAP_OPT_ADD_GUARD_BAND; + if (use_guardband) + talmmu_devmem_heap_options(devmem_heap_hndl, heap_option_id, heap_opt1); + } + + return IMG_SUCCESS; +} + +/* + * @Function mmu_device_create + */ +int mmu_device_create(enum mmu_etype mmu_type_arg, + unsigned int ptd_alignment, + void **mmudev_handle) +{ + int result = IMG_SUCCESS; + enum talmmu_mmu_type talmmu_type = + TALMMU_MMUTYPE_4K_PAGES_32BIT_ADDR; + unsigned int i; + struct mmu_dev_context *dev_ctx; + struct talmmu_devmem_info dev_mem_info; + + /* Set the TAL MMU type. */ + switch (mmu_type_arg) { + case MMU_TYPE_32BIT: + talmmu_type = TALMMU_MMUTYPE_4K_PAGES_32BIT_ADDR; + break; + + case MMU_TYPE_36BIT: + talmmu_type = TALMMU_MMUTYPE_4K_PAGES_36BIT_ADDR; + break; + + case MMU_TYPE_40BIT: + talmmu_type = TALMMU_MMUTYPE_4K_PAGES_40BIT_ADDR; + break; + + default: + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Allocate a device context structure */ + dev_ctx = kzalloc(sizeof(*dev_ctx), GFP_KERNEL); + if (!dev_ctx) + return IMG_ERROR_OUT_OF_MEMORY; + + /* Initialise stream list. */ + lst_init(&dev_ctx->str_list); + + /* Initialise TALMMU. */ + result = talmmu_init(); + if (result != IMG_SUCCESS) + goto error_tal_init; + + dev_mem_info.device_id = 0; + dev_mem_info.mmu_type = talmmu_type; + dev_mem_info.dev_flags = TALMMU_DEVFLAGS_NONE; + dev_mem_info.pagedir_memspace_name = "MEM"; + dev_mem_info.pagetable_memspace_name = NULL; + dev_mem_info.page_size = DEV_MMU_PAGE_SIZE; + dev_mem_info.ptd_alignment = ptd_alignment; + + result = talmmu_devmem_template_create(&dev_mem_info, &dev_ctx->devmem_template_hndl); + if (result != IMG_SUCCESS) + goto error_tal_template; + + /* Add heaps to template */ + for (i = 0; i < MMU_HEAP_MAX; i++) { + heap_info.heap_id = mmu_heaps[i].heap_id; + heap_info.heap_type = mmu_heaps[i].heap_type; + heap_info.memspace_name = mmu_heaps[i].name; + heap_info.size = mmu_heaps[i].size; + heap_info.basedev_virtaddr = mmu_heaps[i].start_offset; + + result = talmmu_devmem_heap_add(dev_ctx->devmem_template_hndl, &heap_info); + if (result != IMG_SUCCESS) + goto error_tal_heap; + } + + /* Create the device context. */ + result = mmu_devmem_context_create(dev_ctx, &dev_ctx->devmem_ctx_hndl); + if (result != IMG_SUCCESS) + goto error_mmu_context; + + dev_ctx->ctx_id = dev_ctx->next_ctx_id; + + /* Return the device context. */ + *mmudev_handle = dev_ctx; + + return IMG_SUCCESS; + + /* Roll back in case of errors. */ +error_mmu_context: +error_tal_heap: + talmmu_devmem_template_destroy(dev_ctx->devmem_template_hndl); +error_tal_template: + talmmu_deinit(); +error_tal_init: + kfree(dev_ctx); + return result; +} + +/* + * @Function mmu_device_destroy + */ +int mmu_device_destroy(void *mmudev_handle) +{ + struct mmu_dev_context *dev_ctx = mmudev_handle; + unsigned int result; + struct mmu_str_context *str_ctx; + + /* Validate inputs. */ + if (!mmudev_handle) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Destroy all streams associated with the device. */ + str_ctx = lst_first(&dev_ctx->str_list); + while (str_ctx) { + result = mmu_stream_destroy(str_ctx); + if (result != IMG_SUCCESS) + return result; + /* See if there are more streams. */ + str_ctx = lst_first(&dev_ctx->str_list); + } + + /* Destroy the device context */ + result = talmmu_devmem_ctx_destroy(dev_ctx->devmem_ctx_hndl); + if (result != IMG_SUCCESS) + return result; + + /* Destroy the template. */ + result = talmmu_devmem_template_destroy(dev_ctx->devmem_template_hndl); + if (result != IMG_SUCCESS) + return result; + + talmmu_deinit(); + + kfree(dev_ctx); + return IMG_SUCCESS; +} + +/* + * @Function mmu_stream_create + * @Description + * This function is used to create and initialise the MMU stream context. + * @Input mmudev_handle : The MMU device handle. + * @Input km_str_id : Stream Id used in communication with KM driver. + * @Output mmu_str_hndl : A pointer used to return the MMU stream + * handle. + * @Return IMG_SUCCESS or an error code. + */ +int mmu_stream_create(void *mmudev_handle, + unsigned int km_str_id, + void *vxd_dec_ctx_arg, + void **mmu_str_hndl) +{ + struct mmu_dev_context *dev_ctx = mmudev_handle; + struct mmu_str_context *str_ctx; + int res; + + /* Validate inputs. */ + if (!mmudev_handle) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Allocate a stream context structure */ + str_ctx = kzalloc(sizeof(*str_ctx), GFP_KERNEL); + if (!str_ctx) + return IMG_ERROR_OUT_OF_MEMORY; + + str_ctx->km_str_id = km_str_id; + str_ctx->dev_ctx = dev_ctx; + str_ctx->int_reg_num = 32; + str_ctx->vxd_dec_context = (struct vxd_dec_ctx *)vxd_dec_ctx_arg; + + /* Create a stream context. */ + res = mmu_devmem_context_create(dev_ctx, &str_ctx->devmem_ctx_hndl); + if (res != IMG_SUCCESS) { + kfree(str_ctx); + return res; + } + + str_ctx->ctx_id = dev_ctx->next_ctx_id; + + /* Add stream to list. */ + lst_add(&dev_ctx->str_list, str_ctx); + + *mmu_str_hndl = str_ctx; + + return IMG_SUCCESS; +} + +/* + * @Function mmu_stream_destroy + * @Description + * This function is used to create and initialise the MMU stream context. + * NOTE: Destroy automatically frees and memory allocated using + * mmu_stream_malloc(). + * @Input mmu_str_hndl : The MMU stream handle. + * @Return IMG_SUCCESS or an error code. + */ +int mmu_stream_destroy(void *mmu_str_hndl) +{ + struct mmu_str_context *str_ctx = mmu_str_hndl; + int res; + + /* Validate inputs. */ + if (!mmu_str_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + /* remove stream to list. */ + lst_remove(&str_ctx->dev_ctx->str_list, str_ctx); + + /* Destroy the device context */ + res = talmmu_devmem_ctx_destroy(str_ctx->devmem_ctx_hndl); + if (res != IMG_SUCCESS) + return res; + + kfree(str_ctx); + + return IMG_SUCCESS; +} + +/* + * @Function mmu_malloc + */ +static int mmu_alloc(void *devmem_ctx_hndl, + struct vxd_dec_ctx *vxd_dec_ctx_arg, + enum mmu_eheap_id heap_id, + unsigned int mem_heap_id, + enum sys_emem_attrib mem_attrib, + unsigned int size, + unsigned int alignment, + struct vidio_ddbufinfo *ddbuf_info) +{ + int result; + void *devmem_heap_hndl; + struct vxd_free_data free_data; + struct vxd_dec_ctx *ctx; + struct vxd_dev *vxd; + struct vxd_alloc_data alloc_data; + unsigned int flags; + + if (!devmem_ctx_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Set buffer size. */ + ddbuf_info->buf_size = size; + + /* Round size up to next multiple of physical pages */ + if ((size % HOST_MMU_PAGE_SIZE) != 0) + size = ((size / HOST_MMU_PAGE_SIZE) + 1) * HOST_MMU_PAGE_SIZE; + + /* Allocate memory */ + ctx = vxd_dec_ctx_arg; + vxd = ctx->dev; + + alloc_data.heap_id = mem_heap_id; + alloc_data.size = ddbuf_info->buf_size; + + alloc_data.attributes = set_attributes(mem_attrib); + + result = img_mem_alloc(vxd->dev, ctx->mem_ctx, alloc_data.heap_id, alloc_data.size, + (enum mem_attr)alloc_data.attributes, + (int *)&ddbuf_info->buff_id); + if (result != IMG_SUCCESS) + goto error_alloc; + + ddbuf_info->is_internal = 1; + + if (mem_attrib & SYS_MEMATTRIB_SECURE) { + ddbuf_info->cpu_virt = NULL; + } else { + /* Map the buffer to CPU */ + result = img_mem_map_km(ctx->mem_ctx, ddbuf_info->buff_id); + if (result) { + dev_err(vxd->dev, "%s: failed to map buf to cpu!(%d)\n", __func__, result); + goto error_get_heap_handle; + } + ddbuf_info->cpu_virt = img_mem_get_kptr(ctx->mem_ctx, ddbuf_info->buff_id); + } + + /* Get heap handle */ + result = talmmu_get_heap_handle(heap_id, devmem_ctx_hndl, &devmem_heap_hndl); + if (result != IMG_SUCCESS) + goto error_get_heap_handle; + + /* Allocate device "virtual" memory. */ + result = talmmu_devmem_addr_alloc(devmem_ctx_hndl, devmem_heap_hndl, size, alignment, + &ddbuf_info->hndl_memory); + if (result != IMG_SUCCESS) + goto error_mem_map_ext_mem; + + /* Get the device virtual address. */ + result = talmmu_get_dev_virt_addr(ddbuf_info->hndl_memory, &ddbuf_info->dev_virt); + if (result != IMG_SUCCESS) + goto error_get_dev_virt_addr; + + flags = VXD_MAP_FLAG_NONE; + + if (mem_attrib & SYS_MEMATTRIB_CORE_READ_ONLY) + flags |= VXD_MAP_FLAG_READ_ONLY; + + if (mem_attrib & SYS_MEMATTRIB_CORE_WRITE_ONLY) + flags |= VXD_MAP_FLAG_WRITE_ONLY; + + result = vxd_map_buffer(vxd, ctx, ddbuf_info->kmstr_id, ddbuf_info->buff_id, + ddbuf_info->dev_virt, + flags); + + if (result != IMG_SUCCESS) + goto error_map_dev; + + return IMG_SUCCESS; + +error_map_dev: +error_get_dev_virt_addr: + talmmu_devmem_addr_free(ddbuf_info->hndl_memory); + ddbuf_info->hndl_memory = NULL; +error_mem_map_ext_mem: +error_get_heap_handle: + free_data.buf_id = ddbuf_info->buff_id; + img_mem_free(ctx->mem_ctx, free_data.buf_id); +error_alloc: + return result; +} + +/* + * @Function mmu_stream_malloc + */ +int mmu_stream_alloc(void *mmu_str_hndl, + enum mmu_eheap_id heap_id, + unsigned int mem_heap_id, + enum sys_emem_attrib mem_attrib, + unsigned int size, + unsigned int alignment, + struct vidio_ddbufinfo *ddbuf_info) +{ + struct mmu_str_context *str_ctx = + (struct mmu_str_context *)mmu_str_hndl; + int result; + + /* Validate inputs. */ + if (!mmu_str_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Check if device level heap. */ + switch (heap_id) { + case MMU_HEAP_IMAGE_BUFFERS_UNTILED: + case MMU_HEAP_BITSTREAM_BUFFERS: + case MMU_HEAP_STREAM_BUFFERS: + break; + + default: + return IMG_ERROR_INVALID_PARAMETERS; + } + + ddbuf_info->kmstr_id = str_ctx->km_str_id; + + /* Allocate device memory. */ + result = mmu_alloc(str_ctx->devmem_ctx_hndl, str_ctx->vxd_dec_context, heap_id, mem_heap_id, + mem_attrib, size, alignment, ddbuf_info); + if (result != IMG_SUCCESS) + return result; + + return IMG_SUCCESS; +} + +/* + * @Function mmu_stream_map_ext_sg + */ +int mmu_stream_map_ext_sg(void *mmu_str_hndl, + enum mmu_eheap_id heap_id, + void *sgt, + unsigned int size, + unsigned int alignment, + enum sys_emem_attrib mem_attrib, + void *cpu_linear_addr, + struct vidio_ddbufinfo *ddbuf_info, + unsigned int *buff_id) +{ + struct mmu_str_context *str_ctx = + (struct mmu_str_context *)mmu_str_hndl; + int result; + void *devmem_heap_hndl; + unsigned int flags; + + struct vxd_dec_ctx *ctx = str_ctx->vxd_dec_context; + struct vxd_dev *vxd = ctx->dev; + + /* Validate inputs. */ + if (!mmu_str_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Check if device level heap. */ + switch (heap_id) { + case MMU_HEAP_IMAGE_BUFFERS_UNTILED: + case MMU_HEAP_BITSTREAM_BUFFERS: + case MMU_HEAP_STREAM_BUFFERS: + break; + + default: + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!str_ctx->devmem_ctx_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Set buffer size. */ + ddbuf_info->buf_size = size; + + /* Round size up to next multiple of physical pages */ + if ((size % HOST_MMU_PAGE_SIZE) != 0) + size = ((size / HOST_MMU_PAGE_SIZE) + 1) * HOST_MMU_PAGE_SIZE; + + result = img_mem_import(vxd->dev, ctx->mem_ctx, ddbuf_info->buf_size, + (enum mem_attr)set_attributes(mem_attrib), + (int *)buff_id); + if (result != IMG_SUCCESS) + return result; + + if (mem_attrib & SYS_MEMATTRIB_SECURE) + ddbuf_info->cpu_virt = NULL; + + ddbuf_info->buff_id = *buff_id; + ddbuf_info->is_internal = 0; + + ddbuf_info->kmstr_id = str_ctx->km_str_id; + + /* Set buffer size. */ + ddbuf_info->buf_size = size; + + /* Ensure the address of the buffer is at least page aligned. */ + ddbuf_info->cpu_virt = cpu_linear_addr; + + /* Get heap handle */ + result = talmmu_get_heap_handle(heap_id, str_ctx->devmem_ctx_hndl, &devmem_heap_hndl); + if (result != IMG_SUCCESS) + return result; + + /* Allocate device "virtual" memory. */ + result = talmmu_devmem_addr_alloc(str_ctx->devmem_ctx_hndl, devmem_heap_hndl, size, + alignment, + &ddbuf_info->hndl_memory); + if (result != IMG_SUCCESS) + return result; + + /* Get the device virtual address. */ + result = talmmu_get_dev_virt_addr(ddbuf_info->hndl_memory, &ddbuf_info->dev_virt); + if (result != IMG_SUCCESS) + goto error_get_dev_virt_addr; + + /* Map memory to the device */ + flags = VXD_MAP_FLAG_NONE; + + if (mem_attrib & SYS_MEMATTRIB_CORE_READ_ONLY) + flags |= VXD_MAP_FLAG_READ_ONLY; + + if (mem_attrib & SYS_MEMATTRIB_CORE_WRITE_ONLY) + flags |= VXD_MAP_FLAG_WRITE_ONLY; + + result = vxd_map_buffer_sg(vxd, ctx, ddbuf_info->kmstr_id, ddbuf_info->buff_id, sgt, + ddbuf_info->dev_virt, + flags); + + if (result != IMG_SUCCESS) + goto error_map_dev; + + return IMG_SUCCESS; + +error_map_dev: +error_get_dev_virt_addr: + talmmu_devmem_addr_free(ddbuf_info->hndl_memory); + ddbuf_info->hndl_memory = NULL; + return result; +} + +/* + * @Function mmu_stream_map_ext + */ +int mmu_stream_map_ext(void *mmu_str_hndl, + enum mmu_eheap_id heap_id, + unsigned int buff_id, + unsigned int size, + unsigned int alignment, + enum sys_emem_attrib mem_attrib, + void *cpu_linear_addr, + struct vidio_ddbufinfo *ddbuf_info) +{ + struct mmu_str_context *str_ctx = + (struct mmu_str_context *)mmu_str_hndl; + int result; + void *devmem_heap_hndl; + struct vxd_dec_ctx *ctx; + struct vxd_dev *vxd; + unsigned int flags; + + /* Validate inputs. */ + if (!mmu_str_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Check if device level heap. */ + switch (heap_id) { + case MMU_HEAP_IMAGE_BUFFERS_UNTILED: + case MMU_HEAP_BITSTREAM_BUFFERS: + case MMU_HEAP_STREAM_BUFFERS: + break; + + default: + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Round size up to next multiple of physical pages */ + if ((size % HOST_MMU_PAGE_SIZE) != 0) + size = ((size / HOST_MMU_PAGE_SIZE) + 1) * HOST_MMU_PAGE_SIZE; + + ddbuf_info->buff_id = buff_id; + ddbuf_info->is_internal = 0; + + ddbuf_info->kmstr_id = str_ctx->km_str_id; + + /* Set buffer size. */ + ddbuf_info->buf_size = size; + + /* Ensure the address of the buffer is at least page aligned. */ + ddbuf_info->cpu_virt = cpu_linear_addr; + + /* Get heap handle */ + result = talmmu_get_heap_handle(heap_id, str_ctx->devmem_ctx_hndl, &devmem_heap_hndl); + if (result != IMG_SUCCESS) + return result; + + /* Allocate device "virtual" memory. */ + result = talmmu_devmem_addr_alloc(str_ctx->devmem_ctx_hndl, devmem_heap_hndl, size, + alignment, + &ddbuf_info->hndl_memory); + if (result != IMG_SUCCESS) + return result; + + /* Get the device virtual address. */ + result = talmmu_get_dev_virt_addr(ddbuf_info->hndl_memory, &ddbuf_info->dev_virt); + if (result != IMG_SUCCESS) + return result; + + /* + * Map device memory (allocated from outside VDEC) + * into the stream PTD. + */ + ctx = str_ctx->vxd_dec_context; + vxd = ctx->dev; + + flags = VXD_MAP_FLAG_NONE; + + if (mem_attrib & SYS_MEMATTRIB_CORE_READ_ONLY) + flags |= VXD_MAP_FLAG_READ_ONLY; + + if (mem_attrib & SYS_MEMATTRIB_CORE_WRITE_ONLY) + flags |= VXD_MAP_FLAG_WRITE_ONLY; + + result = vxd_map_buffer(vxd, ctx, ddbuf_info->kmstr_id, ddbuf_info->buff_id, + ddbuf_info->dev_virt, + flags); + if (result != IMG_SUCCESS) + return result; + + return IMG_SUCCESS; +} + +/* + * @Function mmu_free_mem + */ +int mmu_free_mem(void *mmustr_hndl, struct vidio_ddbufinfo *ddbuf_info) +{ + int tmp_result; + int result = IMG_SUCCESS; + struct vxd_dec_ctx *ctx; + struct vxd_dev *vxd; + + struct mmu_str_context *str_ctx = + (struct mmu_str_context *)mmustr_hndl; + + /* Validate inputs. */ + if (!ddbuf_info) + return IMG_ERROR_INVALID_PARAMETERS; + + if (!str_ctx) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Unmap the memory mapped to the device */ + ctx = str_ctx->vxd_dec_context; + vxd = ctx->dev; + + tmp_result = vxd_unmap_buffer(vxd, ctx, ddbuf_info->kmstr_id, ddbuf_info->buff_id); + if (tmp_result != IMG_SUCCESS) + result = tmp_result; + + /* + * Unmapping the memory mapped to the device - done + * Free the memory. + */ + tmp_result = talmmu_devmem_addr_free(ddbuf_info->hndl_memory); + if (tmp_result != IMG_SUCCESS) + result = tmp_result; + + if (ddbuf_info->is_internal) { + struct vxd_free_data free_data = { ddbuf_info->buff_id }; + + img_mem_free(ctx->mem_ctx, free_data.buf_id); + } + + return result; +} + +/* + * @Function mmu_free_mem + */ +int mmu_free_mem_sg(void *mmustr_hndl, struct vidio_ddbufinfo *ddbuf_info) +{ + int tmp_result; + int result = IMG_SUCCESS; + struct vxd_dec_ctx *ctx; + struct vxd_dev *vxd; + struct vxd_free_data free_data; + + struct mmu_str_context *str_ctx = + (struct mmu_str_context *)mmustr_hndl; + + /* Validate inputs. */ + if (!ddbuf_info) + return IMG_ERROR_INVALID_PARAMETERS; + + if (!str_ctx) + return IMG_ERROR_INVALID_PARAMETERS; + + free_data.buf_id = ddbuf_info->buff_id; + /* Unmap the memory mapped to the device */ + ctx = str_ctx->vxd_dec_context; + vxd = ctx->dev; + + tmp_result = vxd_unmap_buffer(vxd, ctx, ddbuf_info->kmstr_id, ddbuf_info->buff_id); + if (tmp_result != IMG_SUCCESS) + result = tmp_result; + + /* + * Unmapping the memory mapped to the device - done + * Free the memory. + */ + tmp_result = talmmu_devmem_addr_free(ddbuf_info->hndl_memory); + if (tmp_result != IMG_SUCCESS) + result = tmp_result; + + /* + * for external mem manager buffers, just cleanup the idr list and + * buffer objects + */ + img_mem_free_bufid(ctx->mem_ctx, free_data.buf_id); + + return result; +} + +/* + * @Function MMU_GetHeap + */ +int mmu_get_heap(unsigned int image_stride, enum mmu_eheap_id *heap_id) +{ + unsigned int i; + unsigned char found = FALSE; + + for (i = 0; i < MMU_HEAP_MAX; i++) { + if (mmu_heaps[i].image_buffers) { + *heap_id = mmu_heaps[i].heap_id; + found = TRUE; + break; + } + } + + VDEC_ASSERT(found); + if (!found) + return IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + + return IMG_SUCCESS; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vdec_mmu_wrapper.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vdec_mmu_wrapper.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vdec_mmu_wrapper.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vdec_mmu_wrapper.h 2024-07-07 20:37:34.656306609 -0400 @@ -0,0 +1,174 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VDEC MMU Functions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lakshmi Sankar + * + * Re-written for upstream + * Sidraya Jayagond + */ + +#include +#include +#include +#include + +#include "img_errors.h" +#include "img_mem.h" +#include "lst.h" +#include "mmu_defs.h" +#include "vid_buf.h" + +#ifndef _VXD_MMU_H_ +#define _VXD_MMU_H_ + +/* Page size of the device MMU */ +#define DEV_MMU_PAGE_SIZE (0x1000) +/* Page alignment of the device MMU */ +#define DEV_MMU_PAGE_ALIGNMENT (0x1000) + +#define HOST_MMU_PAGE_SIZE PAGE_SIZE + +/* + * @Function mmu_stream_get_ptd_handle + * @Description + * This function is used to obtain the stream PTD (Page Table Directory)handle + * @Input mmu_str_handle : MMU stream handle. + * @Output str_ptd : Pointer to stream PTD handle. + * @Return IMG_SUCCESS or an error code. + */ +int mmu_stream_get_ptd_handle(void *mmu_str_handle, void **str_ptd); + +/* + * @Function mmu_device_create + * @Description + * This function is used to create and initialise the MMU device context. + * @Input mmu_type : MMU type. + * @Input ptd_alignment : Alignment of Page Table directory. + * @Output mmudev_hndl : A pointer used to return the + * MMU device handle. + * @Return IMG_SUCCESS or an error code. + */ +int mmu_device_create(enum mmu_etype mmu_type, + unsigned int ptd_alignment, + void **mmudev_hndl); + +/* + * @Function mmu_device_destroy + * @Description + * This function is used to create and initialise the MMU device context. + * NOTE: Destroy device automatically destroys any streams and frees and + * memory allocated using MMU_StreamMalloc(). + * @Input mmudev_hndl : The MMU device handle. + * @Return IMG_SUCCESS or an error code. + */ +int mmu_device_destroy(void *mmudev_hndl); + +/* + * @Function mmu_stream_create + * @Description + * This function is used to create and initialise the MMU stream context. + * @Input mmudev_hndl : The MMU device handle. + * @Input km_str_id : Stream Id used in communication with KM driver. + * @Output mmustr_hndl : A pointer used to return the MMU stream handle. + * @Return IMG_SUCCESS or an error code. + */ +int mmu_stream_create(void *mmudev_hndl, unsigned int km_str_id, void *vxd_dec_ctx, + void **mmustr_hndl); + +/** + * mmu_stream_destroy - This function is used to create and initialise the MMU stream context. + * @mmustr_hndl : The MMU stream handle. + * Return IMG_SUCCESS or an error code. + * + * NOTE: Destroy automatically frees and memory allocated using + * mmu_stream_malloc(). + */ +int mmu_stream_destroy(void *mmustr_hndl); + +/* + * @Function mmu_stream_alloc + * @Description + * This function is used to allocate stream memory. + * @Input mmustr_hndl : The MMU stream handle. + * @Input heap_id : The MMU heap Id. + * @Input mem_heap_id : Memory heap id + * @Input mem_attrib : Memory attributes + * @Input size : The size, in bytes, to be allocated. + * @Input alignment : The required byte alignment + * (1, 2, 4, 8, 16 etc). + * @Output ddbuf_info : A pointer to a #vidio_ddbufinfo structure + * used to return the buffer info. + * @Return IMG_SUCCESS or an error code. + */ +int mmu_stream_alloc(void *mmustr_hndl, + enum mmu_eheap_id heap_id, + unsigned int mem_heap_id, + enum sys_emem_attrib mem_attrib, + unsigned int size, + unsigned int alignment, + struct vidio_ddbufinfo *ddbuf_info); + +/* + * @Function mmu_stream_map_ext + * @Description + * This function is used to malloc device memory (virtual memory), but mapping + * this to memory that has already been allocated (externally). + * NOTE: Memory can be freed using MMU_Free(). However, this does not + * free the memory provided by the caller via pvCpuLinearAddr. + * @Input mmustr_hndl : The MMU stream handle. + * @Input heap_id : The heap Id. + * @Input buff_id : The buffer Id. + * @Input size : The size, in bytes, to be allocated. + * @Input alignment : The required byte alignment (1, 2, 4, 8, 16 etc). + * @Input mem_attrib : Memory attributes + * @Input cpu_linear_addr : CPU linear address of the memory + * to be allocated for the device. + * @Output ddbuf_info : A pointer to a #vidio_ddbufinfo structure + * used to return the buffer info. + * @Return IMG_SUCCESS or an error code. + */ +int mmu_stream_map_ext(void *mmustr_hndl, + enum mmu_eheap_id heap_id, + unsigned int buff_id, + unsigned int size, + unsigned int alignment, + enum sys_emem_attrib mem_attrib, + void *cpu_linear_addr, + struct vidio_ddbufinfo *ddbuf_info); + +int mmu_stream_map_ext_sg(void *mmustr_hndl, + enum mmu_eheap_id heap_id, + void *sgt, + unsigned int size, + unsigned int alignment, + enum sys_emem_attrib mem_attrib, + void *cpu_linear_addr, + struct vidio_ddbufinfo *ddbuf_info, + unsigned int *buff_id); + +/* + * @Function mmu_free_mem + * @Description + * This function is used to free device memory. + * @Input ps_dd_buf_info : A pointer to a #vidio_ddbufinfo structure. + * @Return IMG_SUCCESS or an error code. + */ +int mmu_free_mem(void *mmustr_hndl, struct vidio_ddbufinfo *ddbuf_info); + +/* + * @Function mmu_free_mem + * @Description + * This function is used to free device memory. + * @Input ps_dd_buf_info : A pointer to a #vidio_ddbufinfo structure. + * @Return IMG_SUCCESS or an error code. + */ +int mmu_free_mem_sg(void *mmustr_hndl, struct vidio_ddbufinfo *ddbuf_info); + +int mmu_get_heap(unsigned int image_stride, enum mmu_eheap_id *heap_id); + +#endif /* _VXD_MMU_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_core.c b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_core.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_core.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_core.c 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,1689 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMG DEC VXD Core component function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "img_dec_common.h" +#include "vxd_pvdec_priv.h" +#include "img_errors.h" + +#define VXD_RENDEC_SIZE (5 * 1024 * 1024) + +#define VXD_MSG_CNT_SHIFT 8 +#define VXD_MSG_CNT_MASK 0xff00 +#define VXD_MAX_MSG_CNT ((1 << VXD_MSG_CNT_SHIFT) - 1) +#define VXD_MSG_STR_MASK 0xff +#define VXD_INVALID_ID (-1) + +#define MAP_FIRMWARE_TO_STREAM 1 + +/* Has to be used with VXD->mutex acquired! */ +#define VXD_GEN_MSG_ID(VXD, STR_ID, MSG_ID, vxd_type, str_type) \ + do { \ + vxd_type __VXD = VXD; \ + str_type __STR_ID = STR_ID; \ + WARN_ON((__STR_ID) > VXD_MSG_STR_MASK); \ + (__VXD)->msg_cnt = (__VXD)->msg_cnt + 1 % (VXD_MAX_MSG_CNT); \ + (MSG_ID) = ((__VXD)->msg_cnt << VXD_MSG_CNT_SHIFT) | \ + ((__STR_ID) & VXD_MSG_STR_MASK); \ + } while (0) + +/* Have to be used with VXD->mutex acquired! */ +#define VXD_RET_MSG_ID(VXD) ((VXD)->msg_cnt--) + +#define VXD_MSG_ID_GET_STR_ID(MSG_ID) \ + ((MSG_ID) & VXD_MSG_STR_MASK) + +#define VXD_MSG_ID_GET_CNT(MSG_ID) \ + (((MSG_ID) & VXD_MSG_CNT_MASK) >> VXD_MSG_CNT_SHIFT) + +static const unsigned char *drv_fw_name = "pvdec_full_bin.fw"; + +/* Driver context */ +static struct { + /* Available memory heaps. List of */ + struct list_head heaps; + /* heap id for all internal allocations (rendec, firmware) */ + int internal_heap_id; + + /* Memory Management context for driver */ + struct mem_ctx *mem_ctx; + + /* List of associated */ + struct list_head devices; + + /* Virtual addresses of shared buffers, common for all streams. */ + struct { + unsigned int fw_addr; /* Firmware blob */ + unsigned int rendec_addr; /* Rendec buffer */ + } virt_space; + + int initialised; +} vxd_drv; + +/* + * struct vxd_heap - node for heaps list + * @id: heap id + * @list: Entry in + */ +struct vxd_heap { + int id; + struct list_head list; +}; + +static void img_mmu_callback(enum mmu_callback_type callback_type, + int buff_id, void *data) +{ + struct vxd_dev *vxd = data; + + if (!vxd) + return; + + if (callback_type == MMU_CALLBACK_MAP) + return; + + if (vxd->hw_on) + vxd_pvdec_mmu_flush(vxd->dev, vxd->reg_base); +} + +static int vxd_is_apm_required(struct vxd_dev *vxd) +{ + return vxd->hw_on; +} + +/* + * Power on the HW. + * Call with vxd->mutex acquired. + */ +static int vxd_make_hw_on_locked(struct vxd_dev *vxd, unsigned int fw_ptd) +{ + unsigned int fw_size; + struct vxd_fw_hdr *fw_hdr; + struct vxd_ena_params ena_params; + int ret; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s:%d\n", __func__, __LINE__); +#endif + if (vxd->hw_on) + return 0; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: enabling HW\n", __func__); +#endif + + fw_size = vxd->firmware.fw_size; + fw_hdr = vxd->firmware.hdr; + if (!fw_size || !fw_hdr) { + dev_err(vxd->dev, "%s: firmware missing!\n", __func__); + return -ENOENT; + } + + memset(&ena_params, 0, sizeof(struct vxd_ena_params)); + + ena_params.fw_buf_size = fw_size - sizeof(struct vxd_fw_hdr); + ena_params.fw_buf_virt_addr = vxd_drv.virt_space.fw_addr; + ena_params.ptd = fw_ptd; + ena_params.boot_poll.msleep_cycles = 50; + ena_params.crc = 0; + ena_params.rendec_addr = vxd_drv.virt_space.rendec_addr; + ena_params.rendec_size = (VXD_NUM_PIX_PIPES(vxd->props) * + VXD_RENDEC_SIZE) / 4096u; + + ena_params.secure = 0; + ena_params.wait_dbg_fifo = 0; + ena_params.mem_staller.data = NULL; + ena_params.mem_staller.size = 0; + + ret = vxd_pvdec_ena(vxd->dev, vxd->reg_base, &ena_params, + fw_hdr, &vxd->freq_khz); + /* + * Ignore the return code, proceed as usual, it will be returned anyway. + * The HW is turned on, so we can perform post mortem analysis, + * and collect the fw logs when available. + */ + + vxd->hw_on = 1; + + return ret; +} + +/* + * Power off the HW. + * Call with vxd->mutex acquired. + */ +static void vxd_make_hw_off_locked(struct vxd_dev *vxd, unsigned char suspending) +{ + int ret; + + if (!vxd->hw_on) + return; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s:%d\n", __func__, __LINE__); +#endif + + ret = vxd_pvdec_dis(vxd->dev, vxd->reg_base); + vxd->hw_on = 0; + if (ret) + dev_err(vxd->dev, "%s: failed to power off the VXD!\n", __func__); +} + +/* + * Moves all valid items from the queue of items being currently processed to + * the pending queue. + * Call with vxd->mutex locked + */ +static void vxd_rewind_msgs_locked(struct vxd_dev *vxd) +{ + struct vxd_item *item, *tmp; + + if (list_empty(&vxd->msgs)) + return; + + list_for_each_entry_safe(item, tmp, &vxd->msgs, list) + list_move(&item->list, &vxd->pend); +} + +static void vxd_report_item_locked(struct vxd_dev *vxd, + struct vxd_item *item, + unsigned int flags) +{ + struct vxd_stream *stream; + + __list_del_entry(&item->list); + stream = idr_find(vxd->streams, item->stream_id); + if (!stream) { + /* + * Failed to find associated stream. Probably it was + * already destroyed -- drop the item + */ +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: drop item %p [0x%x]\n", __func__, item, item->msg_id); +#endif + kfree(item); + } else { + item->msg.out_flags |= flags; + list_add_tail(&item->list, &stream->ctx->items_done); +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: waking %p\n", __func__, stream->ctx); + + dev_info(vxd->dev, "%s: signaling worker for %p\n", __func__, stream->ctx); +#endif + schedule_work(stream->ctx->work); + } +} + +/* + * Rewind all items to the pending queue and report those to listener. + * Postpone the reset. + * Call with vxd->mutex acquired. + */ +static void vxd_emrg_reset_locked(struct vxd_dev *vxd, unsigned int flags) +{ + cancel_delayed_work(vxd->dwork); + + vxd->emergency = 1; + +#ifdef ERROR_RECOVERY_SIMULATION + if (disable_fw_irq_value != 0) { + /* + * Previously we have disabled IRQ, now enable it. This + * condition will occur only when the firmware non responsiveness + * will be detected on vxd_worker thread. Once we reproduce the + * issue we will enable the IRQ so that the code flow continues. + */ + enable_irq(g_module_irq); + } +#endif + + /* + * If the firmware sends more than one reply per item, it's possible + * that corresponding item was already removed from vxd-msgs, but the + * HW was still processing it and MMU page fault could happen and + * trigger execution of this function. So make sure that vxd->msgs + * is not empty before rewinding items. + */ + if (!list_empty(&vxd->msgs)) + /* Move all valid items to the pending queue */ + vxd_rewind_msgs_locked(vxd); + + { + struct vxd_item *item, *tmp; + + list_for_each_entry_safe(item, tmp, &vxd->pend, list) { + /* + * Exclusive items that were on the pending list + * must be reported as canceled + */ + if ((item->msg.out_flags & VXD_FW_MSG_FLAG_EXCL) && !item->msg_id) + item->msg.out_flags |= VXD_FW_MSG_FLAG_CANCELED; + + vxd_report_item_locked(vxd, item, flags); + } + } +} + +static void vxd_handle_io_error_locked(struct vxd_dev *vxd) +{ + struct vxd_item *item, *tmp; + unsigned int pend_flags = !vxd->hw_on ? VXD_FW_MSG_FLAG_DEV_ERR : + VXD_FW_MSG_FLAG_CANCELED; + + list_for_each_entry_safe(item, tmp, &vxd->msgs, list) + vxd_report_item_locked(vxd, item, VXD_FW_MSG_FLAG_DEV_ERR); + + list_for_each_entry_safe(item, tmp, &vxd->pend, list) + vxd_report_item_locked(vxd, item, pend_flags); +} + +static void vxd_sched_worker_locked(struct vxd_dev *vxd, unsigned int delay_ms) +{ + unsigned long long work_at = jiffies + msecs_to_jiffies(delay_ms); + int ret; + + /* + * Try to queue the work. + * This may be also called from the worker context, + * so we need to re-arm anyway in case of error + */ + ret = schedule_delayed_work(vxd->dwork, work_at - jiffies); + if (ret) { + /* Work is already in the queue */ + /* + * Check if new requested time is "before" + * the last "time" we scheduled this work at, + * if not, do nothing, the worker will do + * recalculation for APM/DWR afterwards + */ + if (time_before((unsigned long)work_at, (unsigned long)vxd->work_sched_at)) { + /* + * Canceling & rescheduling might be problematic, + * so just modify it, when needed + */ + ret = mod_delayed_work(system_wq, vxd->dwork, work_at - jiffies); + if (!ret) + dev_err(vxd->dev, "%s: failed to modify work!\n", __func__); + /* + * Record the 'time' this work + * has been rescheduled at + */ + vxd->work_sched_at = work_at; + } + } else { + /* Record the 'time' this work has been scheduled at */ + vxd->work_sched_at = work_at; + } +} + +static void vxd_monitor_locked(struct vxd_dev *vxd) +{ + /* HW is dead, not much sense in rescheduling */ + if (vxd->hw_dead) + return; + + /* + * We are not processing anything, but pending list is not empty + * probably the message fifo is full, so retrigger the worker. + */ + if (!list_empty(&vxd->pend) && list_empty(&vxd->msgs)) + vxd_sched_worker_locked(vxd, 1); + + if (list_empty(&vxd->pend) && list_empty(&vxd->msgs) && vxd_is_apm_required(vxd)) { +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: scheduling APM work (%d ms)!\n", __func__, vxd->hw_pm_delay); +#endif + /* + * No items to process and no items being processed - + * disable the HW + */ + vxd->pm_start = jiffies; + vxd_sched_worker_locked(vxd, vxd->hw_pm_delay); + return; + } + + if (vxd->hw_dwr_period > 0 && !list_empty(&vxd->msgs)) { +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: scheduling DWR work (%d ms)!\n", + __func__, vxd->hw_dwr_period); +#endif + vxd->dwr_start = jiffies; + vxd_sched_worker_locked(vxd, vxd->hw_dwr_period); + } +} + +/* + * Take first item from pending list and submit it to the hardware. + * Has to be called with vxd->mutex locked. + */ +static int vxd_sched_single_locked(struct vxd_dev *vxd) +{ + struct vxd_item *item = NULL; + unsigned long msg_size; + int ret; + + item = list_first_entry(&vxd->pend, struct vxd_item, list); + + msg_size = item->msg.payload_size / sizeof(unsigned int); + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: checking msg_size: %zu, item: %p\n", __func__, msg_size, item); +#endif + + /* + * In case of exclusive item check if hw/fw is + * currently processing anything. + * If so we need to wait until items are returned back. + */ + if ((item->msg.out_flags & VXD_FW_MSG_FLAG_EXCL) && !list_empty(&vxd->msgs) && + /* + * We can move forward if message + * is about to be dropped. + */ + !(item->msg.out_flags & VXD_FW_MSG_FLAG_DROP)) + + ret = -EBUSY; + else + /* + * Check if there's enough space + * in comms RAM to submit the message. + */ + ret = vxd_pvdec_msg_fit(vxd->dev, vxd->reg_base, msg_size); + + if (ret == 0) { + unsigned short msg_id; + + VXD_GEN_MSG_ID(vxd, item->stream_id, msg_id, struct vxd_dev*, unsigned int); + + /* submit the message to the hardware */ + ret = vxd_pvdec_send_msg(vxd->dev, vxd->reg_base, + (unsigned int *)item->msg.payload, msg_size, + msg_id, vxd); + if (ret) { + dev_err(vxd->dev, "%s: failed to send msg!\n", __func__); + VXD_RET_MSG_ID(vxd); + } else { + if (item->msg.out_flags & VXD_FW_MSG_FLAG_DROP) { + __list_del_entry(&item->list); + kfree(item); +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: drop msg 0x%x! (user requested)\n", + __func__, msg_id); +#endif + } else { + item->msg_id = msg_id; +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, + "%s: moving item %p, id 0x%x to msgs\n", + __func__, item, item->msg_id); +#endif + list_move(&item->list, &vxd->msgs); + } + + vxd_monitor_locked(vxd); + } + + } else if (ret == -EINVAL) { + dev_warn(vxd->dev, "%s: invalid msg!\n", __func__); + vxd_report_item_locked(vxd, item, VXD_FW_MSG_FLAG_INV); + /* + * HW is ok, the message was invalid, so don't return an + * error + */ + ret = 0; + } else if (ret == -EBUSY) { + /* + * Not enough space. Message is already in the pending queue, + * so it will be submitted once we've got space. Delayed work + * might have been canceled (if we are currently processing + * threaded irq), so make sure that DWR will trigger if it's + * enabled. + */ + vxd_monitor_locked(vxd); + } else { + dev_err(vxd->dev, "%s: failed to check space for msg!\n", __func__); + } + + return ret; +} + +/* + * Take items from pending list and submit them to the hardware, if space is + * available in the ring buffer. + * Call with vxd->mutex locked + */ +static void vxd_schedule_locked(struct vxd_dev *vxd) +{ + unsigned char emergency = vxd->emergency; + int ret; + + /* if HW is dead, inform the UM and skip */ + if (vxd->hw_dead) { + vxd_handle_io_error_locked(vxd); + return; + } + + if (!vxd->hw_on && !list_empty(&vxd->msgs)) + dev_err(vxd->dev, "%s: msgs not empty when the HW is off!\n", __func__); + + if (list_empty(&vxd->pend)) { + vxd_monitor_locked(vxd); + return; + } + + /* + * If the emergency routine was fired, the hw was left ON,so the UM + * could do the post mortem analysis before submitting the next items. + * Now we can switch off the hardware. + */ + if (emergency) { + vxd->emergency = 0; + vxd_make_hw_off_locked(vxd, FALSE); + usleep_range(1000, 2000); + } + + /* Try to schedule */ + ret = 0; + while (!list_empty(&vxd->pend) && ret == 0) { + struct vxd_item *item; + struct vxd_stream *stream; + + item = list_first_entry(&vxd->pend, struct vxd_item, list); + stream = idr_find(vxd->streams, item->stream_id); + + ret = vxd_make_hw_on_locked(vxd, stream->ptd); + if (ret) { + dev_err(vxd->dev, "%s: failed to start HW!\n", __func__); + vxd->hw_dead = 1; + vxd_handle_io_error_locked(vxd); + return; + } + + ret = vxd_sched_single_locked(vxd); + } + + if (ret != 0 && ret != -EBUSY) { + dev_err(vxd->dev, "%s: failed to schedule, emrg: %d!\n", __func__, emergency); + if (emergency) { + /* + * Failed to schedule in the emergency mode -- + * there's no hope. Power off the HW, mark all + * items as failed and return them. + */ + vxd_handle_io_error_locked(vxd); + return; + } + /* Let worker try to handle it */ + vxd_sched_worker_locked(vxd, 0); + } +} + +static void stream_worker(void *work) +{ + struct vxd_dec_ctx *ctx = NULL; + struct vxd_dev *vxd = NULL; + struct vxd_item *item; + + work = get_work_buff(work, FALSE); + ctx = container_of(work, struct vxd_dec_ctx, work); + vxd = ctx->dev; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: got work for ctx %p\n", __func__, ctx); +#endif + + mutex_lock_nested(ctx->mutex, SUBCLASS_VXD_CORE); + /* don't let this run while device_run is still executing */ + mutex_lock(ctx->mutex2); + + while (!list_empty(&ctx->items_done)) { + item = list_first_entry(&ctx->items_done, struct vxd_item, list); + + item->msg.out_flags &= VXD_FW_MSG_RD_FLAGS_MASK; + +#ifdef DEBUG_DECODER_DRIVER + dev_info(vxd->dev, "%s: item: %p, payload_size: %d, flags: 0x%x\n", + __func__, item, item->msg.payload_size, + item->msg.out_flags); +#endif + + if (ctx->cb) + ctx->cb(ctx->res_str_id, item->msg.payload, + item->msg.payload_size, item->msg.out_flags); + + __list_del_entry(&item->list); + kfree(item); + } + mutex_unlock(ctx->mutex); + mutex_unlock(ctx->mutex2); +} + +int vxd_create_ctx(struct vxd_dev *vxd, struct vxd_dec_ctx *ctx) +{ + int ret = 0; + unsigned int fw_load_retries = 2 * 1000; + + while (!vxd->firmware.ready) { + usleep_range(1000, 2000); + fw_load_retries--; + } + if (vxd->firmware.buf_id == 0) { + dev_err(vxd->dev, "%s: request fw not yet done!\n", __func__); + return -EAGAIN; + } + + /* Create memory management context for HW buffers */ + ret = img_mem_create_ctx(&ctx->mem_ctx); + if (ret) { + dev_err(vxd->dev, "%s: failed to create mem context (err:%d)!\n", __func__, ret); + return ret; + } + + ret = img_mmu_ctx_create(vxd->dev, vxd->mmu_config_addr_width, + ctx->mem_ctx, vxd_drv.internal_heap_id, + img_mmu_callback, vxd, &ctx->mmu_ctx); + if (ret) { + dev_err(vxd->dev, "%s:%d: failed to create mmu ctx\n", __func__, __LINE__); + ret = -EPERM; + goto out_destroy_ctx; + } + + ret = img_mmu_map(ctx->mmu_ctx, vxd->mem_ctx, vxd->firmware.buf_id, + vxd_drv.virt_space.fw_addr, + VXD_MMU_PTD_FLAG_READ_ONLY); + if (ret) { + dev_err(vxd->dev, "%s:%d: failed to map firmware buffer\n", __func__, __LINE__); + ret = -EPERM; + goto out_destroy_mmu_ctx; + } + + ret = img_mmu_map(ctx->mmu_ctx, vxd->mem_ctx, vxd->rendec_buf_id, + vxd_drv.virt_space.rendec_addr, + VXD_MMU_PTD_FLAG_NONE); + if (ret) { + dev_err(vxd->dev, "%s:%d: failed to map rendec buffer\n", __func__, __LINE__); + ret = -EPERM; + goto out_unmap_fw; + } + + ret = img_mmu_get_ptd(ctx->mmu_ctx, &ctx->ptd); + if (ret) { + dev_err(vxd->dev, "%s:%d: failed to get PTD\n", __func__, __LINE__); + ret = -EPERM; + goto out_unmap_rendec; + } + + /* load fw - turned Hw on */ + ret = vxd_make_hw_on_locked(vxd, ctx->ptd); + if (ret) { + dev_err(vxd->dev, "%s:%d: failed to start HW\n", __func__, __LINE__); + ret = -EPERM; + vxd->hw_on = FALSE; + goto out_unmap_rendec; + } + + init_work(&ctx->work, stream_worker, HWA_DECODER); + if (!ctx->work) { + ret = ENOMEM; + goto out_unmap_rendec; + } + + vxd->fw_refcnt++; + + return ret; + +out_unmap_rendec: + img_mmu_unmap(ctx->mmu_ctx, vxd->mem_ctx, vxd->rendec_buf_id); +out_unmap_fw: + img_mmu_unmap(ctx->mmu_ctx, vxd->mem_ctx, vxd->firmware.buf_id); + +out_destroy_mmu_ctx: + img_mmu_ctx_destroy(ctx->mmu_ctx); +out_destroy_ctx: + img_mem_destroy_ctx(ctx->mem_ctx); + return ret; +} + +void vxd_destroy_ctx(struct vxd_dev *vxd, struct vxd_dec_ctx *ctx) +{ + vxd->fw_refcnt--; + + flush_work(ctx->work); + + img_mmu_unmap(ctx->mmu_ctx, vxd->mem_ctx, vxd->rendec_buf_id); + + img_mmu_unmap(ctx->mmu_ctx, vxd->mem_ctx, vxd->firmware.buf_id); + + img_mmu_ctx_destroy(ctx->mmu_ctx); + + img_mem_destroy_ctx(ctx->mem_ctx); + + if (vxd->fw_refcnt == 0) { +#ifdef DEBUG_DECODER_DRIVER + dev_info(vxd->dev, "FW: put %s\n", drv_fw_name); +#endif + /* Poke the monitor to finally switch off the hw, when needed */ + vxd_monitor_locked(vxd); + } +} + +/* Top half */ +irqreturn_t vxd_handle_irq(void *dev) +{ + struct vxd_dev *vxd = ((const struct device *)dev)->driver_data; + struct vxd_hw_state *hw_state = &vxd->state.hw_state; + int ret; + + if (!vxd) + return IRQ_NONE; + + ret = vxd_pvdec_clear_int(vxd->reg_base, &hw_state->irq_status); + + if (!hw_state->irq_status || ret == IRQ_NONE) + dev_warn(dev, "Got spurious interrupt!\n"); + + return (irqreturn_t)ret; +} + +static void vxd_drop_msg_locked(const struct vxd_dev *vxd) +{ + int ret; + + ret = vxd_pvdec_recv_msg(vxd->dev, vxd->reg_base, NULL, 0, (struct vxd_dev *)vxd); + if (ret) + dev_warn(vxd->dev, "%s: failed to receive msg!\n", __func__); +} + +#ifdef DEBUG_DECODER_DRIVER +static void vxd_dbg_dump_msg(const void *dev, const unsigned char *func, + const unsigned int *payload, + unsigned long msg_size) +{ + unsigned int i; + + for (i = 0; i < msg_size; i++) + dev_dbg(dev, "%s: msg %d: 0x%08x\n", func, i, payload[i]); +} +#endif + +static struct vxd_item *vxd_get_orphaned_item_locked(struct vxd_dev *vxd, + unsigned short msg_id, + unsigned long msg_size) +{ + struct vxd_stream *stream; + struct vxd_item *item; + unsigned short str_id = VXD_MSG_ID_GET_STR_ID(msg_id); + + /* Try to find associated stream */ + stream = idr_find(vxd->streams, str_id); + if (!stream) { + /* Failed to find associated stream. */ +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: failed to find str_id: %u\n", __func__, str_id); +#endif + return NULL; + } + + item = kzalloc(sizeof(*item) + (msg_size * sizeof(unsigned int)), GFP_KERNEL); + if (!item) + return NULL; + + item->msg.out_flags = 0; + item->stream_id = str_id; + item->msg.payload_size = msg_size * sizeof(unsigned int); + if (vxd_pvdec_recv_msg(vxd->dev, vxd->reg_base, item->msg.payload, msg_size, vxd)) { + dev_err(vxd->dev, "%s: failed to receive msg from VXD!\n", __func__); + item->msg.out_flags |= VXD_FW_MSG_FLAG_DEV_ERR; + } +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: item: %p str_id: %u\n", __func__, item, str_id); +#endif + /* + * Need to put this item on the vxd->msgs list. + * It will be removed after. + */ + list_add_tail(&item->list, &vxd->msgs); + +#ifdef DEBUG_DECODER_DRIVER + vxd_dbg_dump_msg(vxd->dev, __func__, item->msg.payload, msg_size); +#endif + + return item; +} + +/* + * Fetch and process a single message from the MTX->host ring buffer. + * parameter is used to indicate if there are more messages pending. + * parameter indicates if there is some serious situation detected. + * Has to be called with vxd->mutex locked. + */ +static void vxd_handle_single_msg_locked(struct vxd_dev *vxd, + unsigned char *no_more, + unsigned char *fatal) +{ + int ret; + unsigned short msg_id, str_id; + unsigned long msg_size; /* size in dwords */ + struct vxd_item *item = NULL, *tmp, *it; + struct vxd_stream *stream; + void *dev = vxd->dev; + unsigned char not_last_msg; + + /* get the message size and id */ + ret = vxd_pvdec_pend_msg_info(dev, vxd->reg_base, &msg_size, &msg_id, + ¬_last_msg); + if (ret) { + dev_err(dev, "%s: failed to get pending msg size!\n", __func__); + *no_more = TRUE; /* worker will HW failure */ + return; + } + + if (msg_size == 0) { + *no_more = TRUE; + return; + } + *no_more = FALSE; + + str_id = VXD_MSG_ID_GET_STR_ID(msg_id); +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: [msg] size: %zu, cnt: %u, str_id: %u, id: 0x%x\n", + __func__, msg_size, VXD_MSG_ID_GET_CNT(msg_id), + str_id, msg_id); + dev_dbg(dev, "%s: [msg] not last: %u\n", __func__, not_last_msg); +#endif + + cancel_delayed_work(vxd->dwork); + + /* Find associated item */ + list_for_each_entry_safe_reverse(it, tmp, &vxd->msgs, list) { +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: checking item %p [0x%x] [des: %d]\n", + __func__, it, it->msg_id, it->destroy); +#endif + if (it->msg_id == msg_id) { + item = it; + break; + } + } + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: found item %p [destroy: %d]\n", + __func__, item, item ? item->destroy : VXD_INVALID_ID); +#endif + + /* Find associated stream */ + stream = idr_find(vxd->streams, str_id); + /* + * Check for firmware condition in case + * when unexpected item is received. + */ + if (!item && !stream && vxd_pvdec_check_fw_status(dev, vxd->reg_base)) { + struct vxd_item *orphan; + /* + * Lets forward the fatal info to listeners first, relaying + * on the head of the msg queue. + */ + /* TODO: forward fatal info to all attached processes */ + item = list_entry(vxd->msgs.prev, struct vxd_item, list); + orphan = vxd_get_orphaned_item_locked(vxd, item->msg_id, msg_size); + if (!orphan) { + dev_warn(dev, "%s: drop msg 0x%x! (no orphan)\n", __func__, item->msg_id); + vxd_drop_msg_locked(vxd); + } + + *fatal = TRUE; + return; + } + + if ((item && item->destroy) || !stream) { + /* + * Item was marked for destruction or we failed to find + * associated stream. Probably it was already destroyed -- + * just ignore the message. + */ + if (item) { + __list_del_entry(&item->list); + kfree(item); + item = NULL; + } + dev_warn(dev, "%s: drop msg 0x%x! (no owner)\n", __func__, msg_id); + vxd_drop_msg_locked(vxd); + return; + } + + /* Remove item from vxd->msgs list */ + if (item && item->msg_id == msg_id && !not_last_msg) + __list_del_entry(&item->list); + + /* + * If there's no such item on a list, or the one + * found is too small to fit the output, or it's not supposed to be + * released, allocate a new one. + */ + if (!item || (msg_size * sizeof(unsigned int) > item->msg.payload_size) || not_last_msg) { + struct vxd_item *new_item; + + new_item = kzalloc(sizeof(*new_item) + + (msg_size * sizeof(unsigned int)), GFP_KERNEL); + if (item) { + if (!new_item) { + /* + * Failed to allocate new item. Mark item as + * errored and continue best effort, provide + * only part of the message to the userspace + */ + dev_err(dev, "%s: failed to alloc new item!\n", __func__); + msg_size = item->msg.payload_size / sizeof(unsigned int); + item->msg.out_flags |= VXD_FW_MSG_FLAG_DRV_ERR; + } else { + *new_item = *item; + /* + * Do not free the old item if subsequent + * messages are expected (it also wasn't + * removed from the vxd->msgs list, so we are + * not losing a pointer here). + */ + if (!not_last_msg) + kfree(item); + item = new_item; + } + } else { + if (!new_item) { + /* + * We have no place to put the message, we have + * to drop it + */ + dev_err(dev, "%s: drop msg 0x%08x! (no mem)\n", __func__, msg_id); + vxd_drop_msg_locked(vxd); + return; + } + /* + * There was no corresponding item on the + * list and we've allocated + * a new one. Initialize it + */ + new_item->msg.out_flags = 0; + new_item->stream_id = str_id; + item = new_item; + } + } + ret = vxd_pvdec_recv_msg(dev, vxd->reg_base, item->msg.payload, msg_size, vxd); + if (ret) { + dev_err(dev, "%s: failed to receive msg from VXD!\n", __func__); + item->msg.out_flags |= VXD_FW_MSG_FLAG_DEV_ERR; + } + item->msg.payload_size = msg_size * sizeof(unsigned int); + +#ifdef DEBUG_DECODER_DRIVER + vxd_dbg_dump_msg(dev, __func__, item->msg.payload, msg_size); + + dev_dbg(dev, "%s: adding to done list, item: %p, msg_size: %zu\n", + __func__, item, msg_size); +#endif + list_add_tail(&item->list, &stream->ctx->items_done); + +#ifdef DEBUG_DECODER_DRIVER + dev_info(dev, "%s: signaling worker for %p\n", __func__, stream->ctx); +#endif + schedule_work(stream->ctx->work); +} + +/* Bottom half */ +irqreturn_t vxd_handle_thread_irq(void *dev) +{ + unsigned char no_more = FALSE; + unsigned char fatal = FALSE; + struct vxd_dev *vxd = ((const struct device *)dev)->driver_data; + struct vxd_hw_state *hw_state = &vxd->state.hw_state; + irqreturn_t ret = IRQ_HANDLED; + + if (!vxd) + return IRQ_NONE; + + mutex_lock(vxd->mutex); + + /* Spurious interrupt? */ + if (unlikely(!vxd->hw_on || vxd->hw_dead)) { + ret = IRQ_NONE; + goto out_unlock; + } + + /* Check for critical exception - only MMU faults for now */ + if (vxd_pvdec_check_irq(dev, vxd->reg_base, hw_state->irq_status) < 0) { +#ifdef DEBUG_DECODER_DRIVER + dev_info(vxd->dev, "device MMU fault: resetting!!!\n"); +#endif + vxd_emrg_reset_locked(vxd, VXD_FW_MSG_FLAG_MMU_FAULT); + goto out_unlock; + } + + /* + * Single interrupt can correspond to multiple messages, handle them + * all. + */ + while (!no_more) + vxd_handle_single_msg_locked(vxd, &no_more, &fatal); + + if (fatal) { +#ifdef DEBUG_DECODER_DRIVER + dev_info(vxd->dev, "fw fatal condition: resetting!!!\n"); +#endif + /* Try to recover ... */ + vxd_emrg_reset_locked(vxd, VXD_FW_MSG_FLAG_FATAL); + } else { + /* Try to submit items to the HW */ + vxd_schedule_locked(vxd); + } + +out_unlock: + hw_state->irq_status = 0; + mutex_unlock(vxd->mutex); + + return ret; +} + +static void vxd_worker(void *work) +{ + struct vxd_dev *vxd = NULL; + struct vxd_hw_state state = { 0 }; + struct vxd_item *item_tail; + + work = get_delayed_work_buff(work, FALSE); + vxd = container_of(work, struct vxd_dev, dwork); + mutex_lock(vxd->mutex); + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: jif: %lu, pm: %llu dwr: %llu\n", __func__, + jiffies, vxd->pm_start, vxd->dwr_start); +#endif + + /* + * Disable the hardware if it has been idle for vxd->hw_pm_delay + * milliseconds. Or simply leave the function without doing anything + * if the HW is not supposed to be turned off. + */ + if (list_empty(&vxd->pend) && list_empty(&vxd->msgs)) { + if (vxd_is_apm_required(vxd)) { + unsigned long long dst = vxd->pm_start + + msecs_to_jiffies(vxd->hw_pm_delay); + + if (time_is_before_eq_jiffies((unsigned long)dst)) { +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: pm, power off\n", __func__); +#endif + vxd_make_hw_off_locked(vxd, FALSE); + } else { + unsigned long long targ = dst - jiffies; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: pm, reschedule: %llu\n", __func__, targ); +#endif + vxd_sched_worker_locked(vxd, jiffies_to_msecs(targ)); + } + } + goto out_unlock; + } + + /* + * We are not processing anything, but pending list is not empty (if it + * was, we would enter above. This can happen upon + * specific conditions, when input message occupies almost whole + * host->MTX ring buffer and is followed by large padding message. + */ + if (list_empty(&vxd->msgs)) { + vxd_schedule_locked(vxd); + goto out_unlock; + } + + /* Skip emergency reset if it's disabled. */ + if (vxd->hw_dwr_period <= 0) { +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: skip watchdog\n", __func__); +#endif + goto out_unlock; + } else { + /* Recalculate DWR when needed */ + unsigned long long dst = vxd->dwr_start + + msecs_to_jiffies(vxd->hw_dwr_period); + + if (time_is_after_jiffies((unsigned long)dst)) { + unsigned long long targ = dst - jiffies; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: dwr, reschedule: %llu\n", __func__, targ); +#endif + vxd_sched_worker_locked(vxd, jiffies_to_msecs(targ)); + goto out_unlock; + } + } + + /* Get ID of the oldest item being processed by the HW */ + item_tail = list_entry(vxd->msgs.prev, struct vxd_item, list); + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: tail_item: %p, id: 0x%x\n", __func__, item_tail, + item_tail->msg_id); +#endif + + /* Get HW and firmware state */ + vxd_pvdec_get_state(vxd->dev, vxd->reg_base, VXD_NUM_PIX_PIPES(vxd->props), &state); + + if (vxd->state.msg_id_tail == item_tail->msg_id && + !memcmp(&state, &vxd->state.hw_state, + sizeof(struct vxd_hw_state))) { + vxd->state.msg_id_tail = 0; + memset(&vxd->state.hw_state, 0, sizeof(vxd->state.hw_state)); + dev_err(vxd->dev, "device DWR(%ums) expired: resetting!!!\n", + vxd->hw_dwr_period); + vxd_emrg_reset_locked(vxd, VXD_FW_MSG_FLAG_DWR); + } else { + /* Record current state */ + vxd->state.msg_id_tail = item_tail->msg_id; + vxd->state.hw_state = state; + + /* Submit items to the HW, if space is available. */ + vxd_schedule_locked(vxd); + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: scheduling DWR work (%d ms)!\n", + __func__, vxd->hw_dwr_period); +#endif + vxd_sched_worker_locked(vxd, vxd->hw_dwr_period); + } + +out_unlock: + mutex_unlock(vxd->mutex); +} + +/* + * Lazy initialization of main driver context (when first core is probed -- we + * need heap configuration from sysdev to allocate firmware buffers. + */ +int vxd_init(void *dev, struct vxd_dev *vxd, + const struct heap_config heap_configs[], int heaps) +{ + int ret, i; + + INIT_LIST_HEAD(&vxd_drv.heaps); + vxd_drv.internal_heap_id = VXD_INVALID_ID; + + vxd_drv.mem_ctx = NULL; + + INIT_LIST_HEAD(&vxd_drv.devices); + + vxd_drv.virt_space.fw_addr = 0x42000; + vxd_drv.virt_space.rendec_addr = 0xe0000000; + + vxd_drv.initialised = 0; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: vxd drv init, params:\n", __func__); +#endif + + /* Initialise memory management component */ + for (i = 0; i < heaps; i++) { + struct vxd_heap *heap; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: adding heap of type %d\n", + __func__, heap_configs[i].type); +#endif + + heap = kzalloc(sizeof(*heap), GFP_KERNEL); + if (!heap) { + ret = -ENOMEM; + goto heap_add_failed; + } + + ret = img_mem_add_heap(&heap_configs[i], &heap->id); + if (ret < 0) { + dev_err(dev, "%s: failed to init heap (type %d)!\n", + __func__, heap_configs[i].type); + kfree(heap); + goto heap_add_failed; + } + list_add(&heap->list, &vxd_drv.heaps); + + /* Implicitly, first heap is used for internal allocations */ + if (vxd_drv.internal_heap_id < 0) { + vxd_drv.internal_heap_id = heap->id; +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: using heap %d for internal alloc\n", + __func__, vxd_drv.internal_heap_id); +#endif + } + } + + /* Do not proceed if internal heap not defined */ + if (vxd_drv.internal_heap_id < 0) { + dev_err(dev, "%s: failed to locate heap for internal alloc\n", __func__); + ret = -EINVAL; + /* Loop registered heaps just for sanity */ + goto heap_add_failed; + } + + /* Create memory management context for HW buffers */ + ret = img_mem_create_ctx(&vxd_drv.mem_ctx); + if (ret) { + dev_err(dev, "%s: failed to create mem context (err:%d)!\n", __func__, ret); + goto create_mem_context_failed; + } + + vxd->mem_ctx = vxd_drv.mem_ctx; + + /* Allocate rendec buffer */ + ret = img_mem_alloc(dev, vxd_drv.mem_ctx, vxd_drv.internal_heap_id, + VXD_RENDEC_SIZE * VXD_NUM_PIX_PIPES(vxd->props), + (enum mem_attr)0, &vxd->rendec_buf_id); + if (ret) { + dev_err(dev, "%s: alloc rendec buffer failed (err:%d)!\n", __func__, ret); + goto create_mem_context_failed; + } + + init_delayed_work(&vxd->dwork, vxd_worker, HWA_DECODER); + if (!vxd->dwork) { + ret = ENOMEM; + goto create_mem_context_failed; + } + + vxd_drv.initialised = 1; +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: vxd drv init done\n", __func__); +#endif + return 0; + +create_mem_context_failed: +heap_add_failed: + while (!list_empty(&vxd_drv.heaps)) { + struct vxd_heap *heap; + + heap = list_first_entry(&vxd_drv.heaps, struct vxd_heap, list); + __list_del_entry(&heap->list); + img_mem_del_heap(heap->id); + kfree(heap); + } + vxd_drv.internal_heap_id = VXD_INVALID_ID; + return ret; +} + +/* + * Get internal_heap_id + * TODO: Only error checking is if < 0, so if the stored value is < 0, then + * just passing the value to caller still conveys error. + * Caller must error check. + */ +int vxd_g_internal_heap_id(void) +{ + return vxd_drv.internal_heap_id; +} + +void vxd_deinit(struct vxd_dev *vxd) +{ + cancel_delayed_work_sync(vxd->dwork); + vxd_make_hw_off_locked(vxd, FALSE); + + /* Destroy memory management context */ + if (vxd_drv.mem_ctx) { + /* Deallocate rendec buffer */ + img_mem_free(vxd_drv.mem_ctx, vxd->rendec_buf_id); + + img_mem_destroy_ctx(vxd_drv.mem_ctx); + vxd_drv.mem_ctx = NULL; + } + + /* Deinitialize memory management component */ + while (!list_empty(&vxd_drv.heaps)) { + struct vxd_heap *heap; + + heap = list_first_entry(&vxd_drv.heaps, struct vxd_heap, list); + __list_del_entry(&heap->list); + img_mem_del_heap(heap->id); + kfree(heap); + } + + vxd_drv.internal_heap_id = VXD_INVALID_ID; + vxd_drv.mem_ctx = NULL; + vxd_drv.virt_space.fw_addr = 0x0; + vxd_drv.virt_space.rendec_addr = 0x0; + vxd_drv.initialised = 0; + +#ifdef ERROR_RECOVERY_SIMULATION + /* free the kernel object created to debug */ + kobject_put(vxd_dec_kobject); +#endif +} + +static void vxd_fw_loaded(const struct firmware *fw, void *context) +{ + struct vxd_dev *vxd = context; + unsigned long bin_size; + int buf_id; + struct vxd_fw_hdr *hdr; + void *buf_kptr; + int ret; + unsigned long size = 0; + const unsigned char *data = NULL; + + if (!fw) { + dev_err(vxd->dev, "Firmware binary is not present\n"); + vxd->no_fw = 1; + return; + } + + size = fw->size; + data = fw->data; + +#ifdef DEBUG_DECODER_DRIVER + dev_info(vxd->dev, "FW: acquired %s size %zu\n", drv_fw_name, size); +#endif + + /* Sanity verification of the firmware */ + if (size < sizeof(struct vxd_fw_hdr)) { + dev_err(vxd->dev, "%s: firmware file too small!\n", __func__); + goto out; + } + + bin_size = size - sizeof(struct vxd_fw_hdr); + ret = img_mem_alloc(vxd->dev, vxd_drv.mem_ctx, vxd_drv.internal_heap_id, + bin_size, (enum mem_attr)0, &buf_id); + if (ret) { + dev_err(vxd->dev, "%s: failed to alloc fw buffer (err:%d)!\n", __func__, ret); + goto out; + } + + hdr = kzalloc(sizeof(*hdr), GFP_KERNEL); + if (!hdr) + goto out_release_buf; + + /* Store firmware header in vxd context */ + memcpy(hdr, data, sizeof(struct vxd_fw_hdr)); + +#ifdef DEBUG_DECODER_DRIVER + dev_info(vxd->dev, "FW: info cs: %u, bs: %u, id: 0x%08x, ts: %u\n", + hdr->core_size, hdr->blob_size, + hdr->firmware_id, hdr->timestamp); +#endif + + /* Check if header is consistent */ + if (hdr->core_size > bin_size || hdr->blob_size > bin_size) { + dev_err(vxd->dev, "%s: got invalid firmware!\n", __func__); + goto out_release_hdr; + } + + /* Map the firmware buffer to CPU */ + ret = img_mem_map_km(vxd_drv.mem_ctx, buf_id); + if (ret) { + dev_err(vxd->dev, "%s: failed to map FW buf to cpu! (%d)\n", __func__, ret); + goto out_release_hdr; + } + + /* Copy firmware to device buffer */ + buf_kptr = img_mem_get_kptr(vxd_drv.mem_ctx, buf_id); + memcpy(buf_kptr, data + sizeof(struct vxd_fw_hdr), size - sizeof(struct vxd_fw_hdr)); +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: FW: copied to buffer %d kptr 0x%p\n", __func__, buf_id, buf_kptr); +#endif + + img_mem_sync_cpu_to_device(vxd_drv.mem_ctx, buf_id); + + vxd->firmware.fw_size = size; + vxd->firmware.buf_id = buf_id; + vxd->firmware.hdr = hdr; + vxd->firmware.ready = TRUE; + + release_firmware(fw); + complete_all(vxd->firmware_loading_complete); + pr_debug("Firmware loaded successfully ..!!\n"); + return; + +out_release_hdr: + kfree(hdr); +out_release_buf: + img_mem_free(vxd_drv.mem_ctx, buf_id); +out: + release_firmware(fw); + complete_all(vxd->firmware_loading_complete); + kfree(vxd->firmware_loading_complete); + vxd->firmware_loading_complete = NULL; +} + +/* + * Takes the firmware from the file system and allocates a buffer + */ +int vxd_prepare_fw(struct vxd_dev *vxd) +{ + int ret; + + /* Fetch firmware from the file system */ + struct completion **firmware_loading_complete = + (struct completion **)&vxd->firmware_loading_complete; + + *firmware_loading_complete = kmalloc(sizeof(*firmware_loading_complete), GFP_KERNEL); + if (!(*firmware_loading_complete)) { + pr_err("Memory allocation failed for init_completion\n"); + return -ENOMEM; + } + init_completion(*firmware_loading_complete); + + if (!vxd->firmware_loading_complete) + return -ENOMEM; + + vxd->firmware.ready = FALSE; + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, + drv_fw_name, vxd->dev, GFP_KERNEL, vxd, + vxd_fw_loaded); + if (ret < 0) { + dev_err(vxd->dev, "request_firmware_nowait err: %d\n", ret); + complete_all(vxd->firmware_loading_complete); + kfree(vxd->firmware_loading_complete); + vxd->firmware_loading_complete = NULL; + } + + return ret; +} + +/* + * Cleans firmware resources + */ +void vxd_clean_fw_resources(struct vxd_dev *vxd) +{ +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s:%d\n", __func__, __LINE__); +#endif + + wait_for_completion(vxd->firmware_loading_complete); + kfree(vxd->firmware_loading_complete); + vxd->firmware_loading_complete = NULL; + + if (vxd->firmware.fw_size) { + img_mem_free(vxd_drv.mem_ctx, vxd->firmware.buf_id); + kfree(vxd->firmware.hdr); + vxd->firmware.hdr = NULL; +#ifdef DEBUG_DECODER_DRIVER + dev_info(vxd->dev, "FW: released %s\n", drv_fw_name); +#endif + vxd->firmware.buf_id = VXD_INVALID_ID; + } +} + +/* + * Submit a message to the VXD. + * is used to verify that requested stream id (item->stream_id) is valid + * for this ctx + */ +int vxd_send_msg(struct vxd_dec_ctx *ctx, struct vxd_fw_msg *msg) +{ + struct vxd_dev *vxd = ctx->dev; + unsigned long msg_size; + struct vxd_item *item; + struct vxd_stream *stream; + int ret; + + if (msg->payload_size < VXD_MIN_INPUT_SIZE) + return -EINVAL; + + if (msg->payload_size % sizeof(unsigned int)) { + dev_err(vxd->dev, "msg size not aligned! (%u)\n", + msg->payload_size); + return -EINVAL; + } + + msg_size = VXD_MSG_SIZE(*msg); + + if (msg_size > VXD_MAX_INPUT_SIZE) + return -EINVAL; + + /* Verify that the gap was left for stream PTD */ + if (msg->payload[VXD_PTD_MSG_OFFSET] != 0) { + dev_err(vxd->dev, "%s: PTD gap missing!\n", __func__); + return -EINVAL; + } + + ret = mutex_lock_interruptible_nested(ctx->mutex, SUBCLASS_VXD_CORE); + if (ret) + return ret; + + stream = idr_find(vxd->streams, ctx->stream.id); + if (!stream) { + dev_warn(vxd->dev, "%s: invalid stream id requested! (%u)\n", + __func__, ctx->stream.id); + + ret = -EINVAL; + goto out_unlock; + } + + item = kmalloc(sizeof(*item) + msg->payload_size, GFP_KERNEL); + if (!item) { + ret = -ENOMEM; + goto out_unlock; + } + + memcpy(&item->msg, msg, msg_size); + + msg->out_flags &= VXD_FW_MSG_WR_FLAGS_MASK; + item->stream_id = ctx->stream.id; + item->msg_id = 0; + item->msg.out_flags = msg->out_flags; + item->destroy = 0; + + /* + * Inject the stream PTD into the message. It was already verified that + * there is enough space. + */ + item->msg.payload[VXD_PTD_MSG_OFFSET] = stream->ptd; + + list_add_tail(&item->list, &vxd->pend); +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, + "%s: added item %p to pend, ptd: 0x%x, str: %u flags: 0x%x\n", + __func__, item, stream->ptd, stream->id, item->msg.out_flags); +#endif + + mutex_lock(vxd->mutex); + vxd_schedule_locked(vxd); + mutex_unlock(vxd->mutex); + +out_unlock: + mutex_unlock(ctx->mutex); + + return ret; +} + +int vxd_suspend_dev(void *dev) +{ + struct vxd_dev *vxd = platform_get_drvdata(to_platform_device(dev)); + + mutex_lock(vxd->mutex); +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: taking a nap!\n", __func__); +#endif + + /* Cancel the worker first */ + cancel_delayed_work(vxd->dwork); + + /* Forcing hardware disable */ + vxd_make_hw_off_locked(vxd, TRUE); + + /* Move all valid items to the pending queue */ + vxd_rewind_msgs_locked(vxd); + + mutex_unlock(vxd->mutex); + + return 0; +} + +int vxd_resume_dev(void *dev) +{ + struct vxd_dev *vxd = platform_get_drvdata(to_platform_device(dev)); + int ret = 0; + + mutex_lock(vxd->mutex); +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: waking up!\n", __func__); +#endif + + mutex_unlock(vxd->mutex); + + return ret; +} + +int vxd_map_buffer_sg(struct vxd_dev *vxd, struct vxd_dec_ctx *ctx, + unsigned int str_id, + unsigned int buff_id, + void *sgt, unsigned int virt_addr, + unsigned int map_flags) +{ + struct vxd_stream *stream; + unsigned int flags = VXD_MMU_PTD_FLAG_NONE; + int ret; + + ret = mutex_lock_interruptible_nested(ctx->mutex, SUBCLASS_VXD_CORE); + if (ret) + return ret; + + stream = idr_find(vxd->streams, str_id); + if (!stream) { + dev_err(vxd->dev, "%s: stream %d not found!\n", __func__, str_id); + ret = -EINVAL; + goto out_unlock; + } + + if ((map_flags & (VXD_MAP_FLAG_READ_ONLY | VXD_MAP_FLAG_WRITE_ONLY)) + == (VXD_MAP_FLAG_READ_ONLY | VXD_MAP_FLAG_WRITE_ONLY)) { + dev_err(vxd->dev, "%s: Bogus mapping flags 0x%x!\n", __func__, + map_flags); + ret = -EINVAL; + goto out_unlock; + } + + /* Convert permission flags to internal definitions */ + if (map_flags & VXD_MAP_FLAG_READ_ONLY) + flags |= VXD_MMU_PTD_FLAG_READ_ONLY; + + if (map_flags & VXD_MAP_FLAG_WRITE_ONLY) + flags |= VXD_MMU_PTD_FLAG_WRITE_ONLY; + + ret = img_mmu_map_sg(stream->mmu_ctx, ctx->mem_ctx, buff_id, sgt, virt_addr, flags); + if (ret) { + dev_err(vxd->dev, "%s: map failed!\n", __func__); + goto out_unlock; + } + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, + "%s: mapped buf %u to 0x%08x, str_id: %u flags: 0x%x\n", + __func__, buff_id, virt_addr, str_id, flags); +#endif + +out_unlock: + mutex_unlock(ctx->mutex); + return ret; +} + +int vxd_map_buffer(struct vxd_dev *vxd, struct vxd_dec_ctx *ctx, unsigned int str_id, + unsigned int buff_id, + unsigned int virt_addr, + unsigned int map_flags) +{ + struct vxd_stream *stream; + unsigned int flags = VXD_MMU_PTD_FLAG_NONE; + int ret; + + ret = mutex_lock_interruptible_nested(ctx->mutex, SUBCLASS_VXD_CORE); + if (ret) + return ret; + + stream = idr_find(vxd->streams, str_id); + if (!stream) { + dev_err(vxd->dev, "%s: stream %d not found!\n", __func__, str_id); + ret = -EINVAL; + goto out_unlock; + } + + if ((map_flags & (VXD_MAP_FLAG_READ_ONLY | VXD_MAP_FLAG_WRITE_ONLY)) + == (VXD_MAP_FLAG_READ_ONLY | VXD_MAP_FLAG_WRITE_ONLY)) { + dev_err(vxd->dev, "%s: Bogus mapping flags 0x%x!\n", __func__, map_flags); + ret = -EINVAL; + goto out_unlock; + } + + /* Convert permission flags to internal definitions */ + if (map_flags & VXD_MAP_FLAG_READ_ONLY) + flags |= VXD_MMU_PTD_FLAG_READ_ONLY; + + if (map_flags & VXD_MAP_FLAG_WRITE_ONLY) + flags |= VXD_MMU_PTD_FLAG_WRITE_ONLY; + + ret = img_mmu_map(stream->mmu_ctx, ctx->mem_ctx, buff_id, virt_addr, flags); + if (ret) { + dev_err(vxd->dev, "%s: map failed!\n", __func__); + goto out_unlock; + } + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, + "%s: mapped buf %u to 0x%08x, str_id: %u flags: 0x%x\n", + __func__, buff_id, virt_addr, str_id, flags); +#endif + +out_unlock: + mutex_unlock(ctx->mutex); + return ret; +} + +int vxd_unmap_buffer(struct vxd_dev *vxd, struct vxd_dec_ctx *ctx, + unsigned int str_id, unsigned int buff_id) +{ + struct vxd_stream *stream; + int ret; + + ret = mutex_lock_interruptible_nested(ctx->mutex, SUBCLASS_VXD_CORE); + if (ret) + return ret; + + stream = idr_find(vxd->streams, str_id); + if (!stream) { + dev_err(vxd->dev, "%s: stream %d not found!\n", __func__, str_id); + ret = -EINVAL; + goto out_unlock; + } + + ret = img_mmu_unmap(stream->mmu_ctx, ctx->mem_ctx, buff_id); + if (ret) { + dev_err(vxd->dev, "%s: map failed!\n", __func__); + goto out_unlock; + } + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(vxd->dev, "%s: unmapped buf %u str_id: %u\n", __func__, buff_id, str_id); +#endif + +out_unlock: mutex_unlock(ctx->mutex); + return ret; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_dec.c b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_dec.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_dec.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_dec.c 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMG DEC SYSDEV and UI Interface function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#include +#include +#include +#include + +#include "core.h" +#include "h264fw_data.h" +#include "hevcfw_data.h" +#include "img_dec_common.h" +#include "vxd_pvdec_priv.h" + +unsigned int get_nbuffers(enum vdec_vid_std std, int w, int h, + unsigned int max_num_ref_frames) +{ + unsigned int nbuffers; + + switch (std) { + case VDEC_STD_H264: + /* + * Request number of buffers from header bspp information + * using formula N + Display Lag + * Parser is passing (2*N) + */ + if (max_num_ref_frames == 0) { + nbuffers = DISPLAY_LAG + min(MAX_CAPBUFS_H264, + (184320 / ((w / 16) * (h / 16)))); + } else { + nbuffers = max_num_ref_frames + DISPLAY_LAG; + } + break; + case VDEC_STD_HEVC: + if (max_num_ref_frames == 0) { + if ((w * h) <= (HEVC_MAX_LUMA_PS >> 2)) + nbuffers = 16; + else if ((w * h) <= (HEVC_MAX_LUMA_PS >> 1)) + nbuffers = 12; + else if ((w * h) <= ((3 * HEVC_MAX_LUMA_PS) >> 2)) + nbuffers = 8; + else + nbuffers = 6; + nbuffers += DISPLAY_LAG; + } else { + nbuffers = max_num_ref_frames + DISPLAY_LAG; + } + break; +#ifdef HAS_JPEG + case VDEC_STD_JPEG: + /* + * Request number of output buffers based on h264 spec + * + display delay + */ + nbuffers = DISPLAY_LAG + min(MAX_CAPBUFS_H264, + (184320 / ((w / 16) * (h / 16)))); + break; +#endif + default: + nbuffers = 0; + } + + return nbuffers; +} + +int vxd_dec_alloc_bspp_resource(struct vxd_dec_ctx *ctx, enum vdec_vid_std vid_std) +{ + struct vxd_dev *vxd_dev = ctx->dev; + struct device *dev = vxd_dev->v4l2_dev.dev; + struct vdec_buf_info buf_info; + struct bspp_ddbuf_array_info *fw_sequ = ctx->fw_sequ; + struct bspp_ddbuf_array_info *fw_pps = ctx->fw_pps; + int attributes = 0, heap_id = 0, size = 0; + int i, ret = 0; + + attributes = SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE | + SYS_MEMATTRIB_INTERNAL | SYS_MEMATTRIB_CPU_WRITE; + heap_id = vxd_g_internal_heap_id(); + + size = vid_std == VDEC_STD_HEVC ? + sizeof(struct hevcfw_sequence_ps) : sizeof(struct h264fw_sequence_ps); + +#ifdef HAS_JPEG + if (vid_std == VDEC_STD_JPEG) + size = sizeof(struct vdec_jpeg_sequ_hdr_info); +#endif + + for (i = 0; i < MAX_SEQUENCES; i++) { + ret = img_mem_alloc(vxd_dev->dev, ctx->mem_ctx, heap_id, + size, (enum mem_attr)attributes, + (int *)&fw_sequ[i].ddbuf_info.buf_id); + if (ret) { + dev_err(dev, "Couldn't allocate sequ buffer %d\n", i); + return -ENOMEM; + } + ret = img_mem_map_km(ctx->mem_ctx, fw_sequ[i].ddbuf_info.buf_id); + if (ret) { + dev_err(dev, "Couldn't map sequ buffer %d\n", i); + return -ENOMEM; + } + fw_sequ[i].ddbuf_info.cpu_virt_addr = img_mem_get_kptr + (ctx->mem_ctx, + fw_sequ[i].ddbuf_info.buf_id); + fw_sequ[i].buf_offset = 0; + fw_sequ[i].buf_element_size = size; + fw_sequ[i].ddbuf_info.buf_size = size; + fw_sequ[i].ddbuf_info.mem_attrib = (enum sys_emem_attrib)attributes; + memset(fw_sequ[i].ddbuf_info.cpu_virt_addr, 0, size); + + buf_info.cpu_linear_addr = + fw_sequ[i].ddbuf_info.cpu_virt_addr; + buf_info.buf_size = size; + buf_info.fd = -1; + buf_info.buf_id = fw_sequ[i].ddbuf_info.buf_id; + buf_info.mem_attrib = + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE | + SYS_MEMATTRIB_INPUT | SYS_MEMATTRIB_CPU_WRITE); + + ret = core_stream_map_buf(ctx->res_str_id, VDEC_BUFTYPE_BITSTREAM, &buf_info, + &fw_sequ[i].ddbuf_info.bufmap_id); + if (ret) { + dev_err(dev, "sps core_stream_map_buf failed\n"); + return ret; + } + } + +#ifdef HAS_JPEG + if (vid_std == VDEC_STD_JPEG) + return 0; +#endif + + size = vid_std == VDEC_STD_HEVC ? + sizeof(struct hevcfw_picture_ps) : sizeof(struct h264fw_picture_ps); + + for (i = 0; i < MAX_PPSS; i++) { + ret = img_mem_alloc(vxd_dev->dev, ctx->mem_ctx, heap_id, size, + (enum mem_attr)attributes, + (int *)&fw_pps[i].ddbuf_info.buf_id); + if (ret) { + dev_err(dev, "Couldn't allocate sequ buffer %d\n", i); + return -ENOMEM; + } + ret = img_mem_map_km(ctx->mem_ctx, fw_pps[i].ddbuf_info.buf_id); + if (ret) { + dev_err(dev, "Couldn't map sequ buffer %d\n", i); + return -ENOMEM; + } + fw_pps[i].ddbuf_info.cpu_virt_addr = img_mem_get_kptr(ctx->mem_ctx, + fw_pps[i].ddbuf_info.buf_id); + fw_pps[i].buf_offset = 0; + fw_pps[i].buf_element_size = size; + fw_pps[i].ddbuf_info.buf_size = size; + fw_pps[i].ddbuf_info.mem_attrib = (enum sys_emem_attrib)attributes; + memset(fw_pps[i].ddbuf_info.cpu_virt_addr, 0, size); + + buf_info.cpu_linear_addr = + fw_pps[i].ddbuf_info.cpu_virt_addr; + buf_info.buf_size = size; + buf_info.fd = -1; + buf_info.buf_id = fw_pps[i].ddbuf_info.buf_id; + buf_info.mem_attrib = + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE | + SYS_MEMATTRIB_INPUT | SYS_MEMATTRIB_CPU_WRITE); + + ret = core_stream_map_buf(ctx->res_str_id, VDEC_BUFTYPE_BITSTREAM, &buf_info, + &fw_pps[i].ddbuf_info.bufmap_id); + if (ret) { + dev_err(dev, "pps core_stream_map_buf failed\n"); + return ret; + } + } + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_dec.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_dec.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_dec.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_dec.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,512 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * IMG DEC SYSDEV and UI Interface header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#ifndef _VXD_DEC_H +#define _VXD_DEC_H + +#include +#include +#include +#include +#include +#include + +#include "bspp.h" +#include "img_dec_common.h" +#include "img_mem_man.h" +#include "img_pixfmts.h" +#include "pixel_api.h" +#include "vdecdd_defs.h" +#include "vdec_defs.h" +#include "work_queue.h" + +#define VXD_MIN_STREAM_ID 1 +#define VXD_MAX_STREAMS_PER_DEV 254 +#define VXD_MAX_STREAM_ID (VXD_MIN_STREAM_ID + VXD_MAX_STREAMS_PER_DEV) + +#define CODEC_NONE -1 +#define CODEC_H264_DEC 0 +#define CODEC_MPEG4_DEC 1 +#define CODEC_VP8_DEC 2 +#define CODEC_VC1_DEC 3 +#define CODEC_MPEG2_DEC 4 +#define CODEC_JPEG_DEC 5 +#define CODEC_VP9_DEC 6 +#define CODEC_HEVC_DEC 7 + +#define MAX_SEGMENTS 6 +#define HW_ALIGN 64 + +#define MAX_BUF_TRACE 30 + +#define MAX_CAPBUFS_H264 16 +#define DISPLAY_LAG 3 +#define HEVC_MAX_LUMA_PS 35651584 + +#define MAX_PLANES 3 + +enum { + Q_DATA_SRC = 0, + Q_DATA_DST = 1, + Q_DATA_FORCE32BITS = 0x7FFFFFFFU +}; + +enum { + IMG_DEC_FMT_TYPE_CAPTURE = 0x01, + IMG_DEC_FMT_TYPE_OUTPUT = 0x10, + IMG_DEC_FMT_TYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +enum vxd_map_flags { + VXD_MAP_FLAG_NONE = 0x0, + VXD_MAP_FLAG_READ_ONLY = 0x1, + VXD_MAP_FLAG_WRITE_ONLY = 0x2, + VXD_MAP_FLAG_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * struct vxd_fw_msg - This structure holds the information about the message + * exchanged in read/write between Kernel and firmware. + * + * @out_flags: indicating the type of message + * @payload_size: size of payload in bytes + * @payload: data which is send to firmware + */ +struct vxd_fw_msg { + unsigned int out_flags; + unsigned int payload_size; + unsigned int payload[0]; +}; + +/* HW state */ +struct vxd_hw_state { + unsigned int fw_counter; + unsigned int fe_status[VXD_MAX_PIPES]; + unsigned int be_status[VXD_MAX_PIPES]; + unsigned int dmac_status[VXD_MAX_PIPES][2]; /* Cover DMA chan 2/3*/ + unsigned int irq_status; +}; + +/* + * struct vxd_state - contains VXD HW state + * + * @hw_state: HW state + * @msg_id_tail: msg id of the oldest item being processed + */ +struct vxd_state { + struct vxd_hw_state hw_state; + unsigned short msg_id_tail; +}; + +/* + * struct vxd_dec_fmt - contains info for each of the supported video format + * + * @fourcc: V4L2 pixel format FCC identifier + * @num_planes: number of planes required for luma and chroma + * @type: CAPTURE or OUTPUT + * @std: VDEC video standard + * @pixfmt: IMG pixel format + * @interleave: Chroma interleave order + * @idc: Chroma format + * @size_num: Numberator used to calculate image size + * @size_den: Denominator used to calculate image size + * @bytes_pp: Bytes per pixel for this format + */ +struct vxd_dec_fmt { + unsigned int fourcc; + unsigned int num_planes; + unsigned char type; + enum vdec_vid_std std; + enum img_pixfmt pixfmt; + enum pixel_chroma_interleaved interleave; + enum pixel_fmt_idc idc; + int size_num; + int size_den; + int bytes_pp; +}; + +/* + * struct vxd_item - contains information about the item sent to fw + * + * @list: item to be linked list to items_done, msgs, or pend. + * @stream_id: stream id + * @msg_id: message id + * @destroy: item belongs to the stream which is destroyed + * @msg: contains msg between kernel and fw + */ +struct vxd_item { + struct list_head list; + unsigned int stream_id; + unsigned int msg_id; + struct { + unsigned destroy : 1; + }; + struct vxd_fw_msg msg; +}; + +enum vxd_cb_type { + VXD_CB_STRUNIT_PROCESSED, + VXD_CB_SPS_RELEASE, + VXD_CB_PPS_RELEASE, + VXD_CB_PICT_DECODED, + VXD_CB_PICT_DISPLAY, + VXD_CB_PICT_RELEASE, + VXD_CB_PICT_END, + VXD_CB_STR_END, + VXD_CB_ERROR_FATAL, + VXD_CB_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * vxd_cb - Return a resource to vxd + * + * @ctx: the vxd stream context + * @type: the type of message + * @buf_map_id: the buf_map_id of the resource being returned + */ +typedef void (*vxd_cb)(void *ctx, enum vxd_cb_type type, unsigned int buf_map_id, + unsigned int error_code); + +/* + * struct vxd_return - contains information about items returning from core + * + * @type: Type of item being returned + * @buf_map_id: mmu mapped id of buffer being returned + */ +struct vxd_return { + void *work; + struct vxd_dec_ctx *ctx; + enum vxd_cb_type type; + unsigned int buf_map_id; +}; + +/* + * struct vxd_dec_q_data - contains queue data information + * + * @fmt: format info + * @width: frame width + * @height: frame height + * @bytesperline: bytes per line in memory + * @size_image: image size in memory + */ +struct vxd_dec_q_data { + struct vxd_dec_fmt *fmt; + unsigned int width; + unsigned int height; + unsigned int bytesperline[MAX_PLANES]; + unsigned int size_image[MAX_PLANES]; +}; + +/* + * struct time_prof - contains time taken by decoding information + * + * @id: id info + * @start_time: start time + * @end_time: end time + */ +struct time_prof { + unsigned int id; + long long start_time; + long long end_time; +}; + +/* + * struct vxd_dev - The struct containing decoder driver internal parameters. + * + * @v4l2_dev: main struct of V4L2 device drivers + * @dev: platform device driver + * @vfd_dec: video device structure to create and manage the V4L2 device node. + * @plat_dev: linux platform device + * @struct v4l2_m2m_dev: mem2mem device + * @mutex: mutex to protect certain ongoing operation. + * @module_irq: a threaded request IRQ for the device + * @reg_base: base address of the IMG VXD hw registers + * @props: contains HW properties + * @mmu_config_addr_width: indicates the number of extended address bits + * (above 32) that the external memory interface + * uses, based on EXTENDED_ADDR_RANGE field of + * MMU_CONFIG0 + * @rendec_buf_id: buffer id for rendec buffer allocation + * @firmware: firmware information based on vxd_dev_fw structure + * @firmware_loading_complete: loading completion + * @no_fw: Just to check if firmware is present in /lib + * @fw_refcnt: firmware reference counter + * @hw_on: indication if hw is on or off + * @hw_dead: indication if hw is dead + * @lock: basic primitive for locking through spinlock + * @state: internal state handling of vxd state + * @msgs: linked list of msgs with vxd_item + * @pend: linked list of pending msgs to be sent to fw + * @msg_cnt: counter of messages submitted to VXD. Wraps every VXD_MSG_ID_MASK + * @freq_khz: Core clock frequency measured during boot of firmware + * @streams: unique id for the stream + * @mem_ctx: memory management context for HW buffers + * @dwork: use for Power Management and Watchdog + * @work_sched_at: the time of the last work has been scheduled at + * @emergency: indicates if emergency condition occurred + * @dbgfs_ctx: pointer to debug FS context. + * @hw_pm_delay: delay before performaing PM + * @hw_dwr_period: period for checking for dwr + * @pm_start: time, in jiffies, when core become idle + * @dwr_start: time, in jiffies, when dwr has been started + */ +struct vxd_dev { + struct v4l2_device v4l2_dev; + void *dev; + struct video_device *vfd_dec; + struct platform_device *plat_dev; + struct v4l2_m2m_dev *m2m_dev; + struct mutex *mutex; /* Per device mutex */ + struct mutex *mutex_queue; /* Mutex for ioctl synchronization on queue */ + int module_irq; + void __iomem *reg_base; + struct vxd_core_props props; + unsigned int mmu_config_addr_width; + int rendec_buf_id; + struct vxd_dev_fw firmware; + void *firmware_loading_complete; + unsigned char no_fw; + unsigned char fw_refcnt; + unsigned int hw_on; + unsigned int hw_dead; + void *lock; /* basic device level spinlock */ + struct vxd_state state; + struct list_head msgs; + struct list_head pend; + int msg_cnt; + unsigned int freq_khz; + struct idr *streams; + struct mem_ctx *mem_ctx; + void *dwork; + unsigned long long work_sched_at; + unsigned int emergency; + void *dbgfs_ctx; + unsigned int hw_pm_delay; + unsigned int hw_dwr_period; + unsigned long long pm_start; + unsigned long long dwr_start; + struct time_prof time_fw[MAX_BUF_TRACE]; + struct time_prof time_drv[MAX_BUF_TRACE]; + + /* The variables defined below are used in RTOS only. */ + /* This variable holds queue handler */ + void *vxd_worker_queue_handle; + void *vxd_worker_queue_sem_handle; +}; + +/* + * struct vxd_stream - holds stream-related info + * + * @ctx: associated vxd_dec_ctx + * @mmu_ctx: MMU context for this stream + * @ptd: ptd for the stream + * @id: unique stream id + */ +struct vxd_stream { + struct vxd_dec_ctx *ctx; + struct mmu_ctx *mmu_ctx; + unsigned int ptd; + unsigned int id; +}; + + +/* + * struct vxd_buffer - holds per buffer info. + * @buffer: the vb2_v4l2_buffer + * @list: list head for gathering in linked list + * @mapped: is this buffer mapped yet + * @reuse: is the buffer ready for reuse + * @buf_map_id: the mapped buffer id + * @buf_info: the buffer info for submitting to map + * @bstr_info: the buffer info for submitting to bspp + * @seq_unit: the str_unit for submitting sps + * @seq_unit: the str_unit for submitting pps and segments + * @seq_unit: the str_unit for submitting picture_end + */ +struct vxd_buffer { + struct v4l2_m2m_buffer buffer; + struct list_head list; + unsigned char mapped; + unsigned char reuse; + unsigned int buf_map_id; + struct vxd_mapping *mapping; + struct vdec_buf_info buf_info; + struct bspp_ddbuf_info bstr_info; + struct vdecdd_str_unit seq_unit; + struct vdecdd_str_unit pic_unit; + struct vdecdd_str_unit end_unit; + struct bspp_preparsed_data preparsed_data; +}; + +struct vxd_mapping { + struct list_head list; + unsigned int buf_map_id; + unsigned char reuse; + unsigned long dma_addr; + struct vxd_buffer *buf; /* point to the mapped buffer */ +}; + +typedef void (*decode_cb)(int res_str_id, unsigned int *msg, unsigned int msg_size, + unsigned int msg_flags); + +/* + * struct vxd_dec_ctx - holds per stream data. Each playback has its own + * vxd_dec_ctx + * + * @fh: V4L2 file handler + * @dev: pointer to the device main information. + * @ctrl_hdl_dec: v4l2 custom control command for video decoder + * @mem_ctx: mem context for this stream + * @mmu_ctx: MMU context for this stream + * @ptd: page table information + * @items_done: linked list of items is ready + * @width: frame width + * @height: frame height + * @width_orig: original frame width (before padding) + * @height_orig: original frame height (before padding) + * @q_data: Queue data information of src[0] and dst[1] + * @stream: stream-related info + * @work: work queue for message handling + * @return_queue: list of resources returned from core + * @out_buffers: list of all output buffers + * @cap_buffers: list of all capture buffers except those in reuse_queue + * @cap_mappings: list of all capture buffers mapped to HW + * @reuse_queue: list of capture buffers waiting for core to signal reuse + * @res_str_id: Core stream id + * @stream_created: Core stream is created + * @stream_configured: Core stream is configured + * @opconfig_pending: Core opconfig is pending stream_create + * @src_streaming: V4L2 src stream is streaming + * @dst_streaming: V4L2 dst stream is streaming + * @core_streaming: core is streaming + * @aborting: signal job abort on next irq + * @str_opcfg: core output config + * @pict_bufcfg: core picture buffer config + * @bspp_context: BSPP Stream context handle + * @seg_list: list of bspp_bitstr_seg for submitting to BSPP + * @fw_sequ: BSPP sps resource + * @fw_pps: BSPP pps resource + * @cb: registered callback for incoming messages + * @mutex: mutex to protect context specific state machine + */ +struct vxd_dec_ctx { + struct v4l2_fh fh; + struct vxd_dev *dev; + struct mem_ctx *mem_ctx; + struct mmu_ctx *mmu_ctx; + unsigned int ptd; + struct list_head items_done; + unsigned int width; + unsigned int height; + unsigned int width_orig; + unsigned int height_orig; + struct vxd_dec_q_data q_data[2]; + struct vxd_stream stream; + void *work; + struct list_head return_queue; + struct list_head out_buffers; + struct list_head cap_buffers; + struct list_head cap_mappings; + struct list_head reuse_queue; + unsigned int res_str_id; + unsigned char stream_created; + unsigned char stream_configured; + unsigned char opconfig_pending; + unsigned char src_streaming; + unsigned char dst_streaming; + unsigned char core_streaming; + unsigned char aborting; + unsigned char eos; + unsigned char stop_initiated; + unsigned char flag_last; + unsigned char num_decoding; + unsigned int max_num_ref_frames; + unsigned int cap_seq; /* sequence number for capture port */ + unsigned int out_seq; /* sequence number for output port */ + struct vdec_str_opconfig str_opcfg; + struct vdec_pict_bufconfig pict_bufcfg; + + struct vdec_comsequ_hdrinfo comseq_hdr_info; + struct vdec_str_configdata strcfgdata; + struct vdecdd_dddev_context *dev_ctx; + + struct v4l2_ctrl_handler v4l2_ctrl_hdl; + + /* The following are parameters from V4L2 extra-controls */ + + /* + * used by the IMG firmware to constrain DPB's utilized + * a value of 0 indicates to let the firmware decide + */ + unsigned int max_dec_frame_buffering; + int override_spec_dpb_buffers; + int img_extra_decode_buffers; + unsigned int display_pipeline_size; + + void *bspp_context; + struct bspp_bitstr_seg bstr_segments[MAX_SEGMENTS]; + struct lst_t seg_list; + struct bspp_ddbuf_array_info fw_sequ[MAX_SEQUENCES]; + struct bspp_ddbuf_array_info fw_pps[MAX_PPSS]; + decode_cb cb; + struct mutex *mutex; /* Per stream mutex */ + struct mutex *mutex2; /* used as a sequencing mutex, so device_run runs to completion */ + + /* The below variable used only in Rtos */ + void *mm_return_resource; /* Place holder for CB to application */ + void *stream_worker_queue_handle; + void *stream_worker_queue_sem_handle; + // lock is used to synchronize the stream worker and process function + void *lock; + /* "sem_eos" this semaphore variable used to wait until all frame decoded */ + void *sem_eos; +}; + +irqreturn_t vxd_handle_irq(void *dev); +irqreturn_t vxd_handle_thread_irq(void *dev); +int vxd_init(void *dev, struct vxd_dev *vxd, const struct heap_config heap_configs[], int heaps); +int vxd_g_internal_heap_id(void); +void vxd_deinit(struct vxd_dev *vxd); +int vxd_prepare_fw(struct vxd_dev *vxd); +void vxd_clean_fw_resources(struct vxd_dev *vxd); +int vxd_send_msg(struct vxd_dec_ctx *ctx, struct vxd_fw_msg *msg); +int vxd_suspend_dev(void *dev); +int vxd_resume_dev(void *dev); + +int vxd_create_ctx(struct vxd_dev *vxd, struct vxd_dec_ctx *ctx); +void vxd_destroy_ctx(struct vxd_dev *vxd, struct vxd_dec_ctx *ctx); + +int vxd_map_buffer_sg(struct vxd_dev *vxd, struct vxd_dec_ctx *ctx, + unsigned int str_id, unsigned int buff_id, + void *sgt, unsigned int virt_addr, + unsigned int map_flags); +int vxd_map_buffer(struct vxd_dev *vxd, struct vxd_dec_ctx *ctx, unsigned int str_id, + unsigned int buff_id, unsigned int virt_addr, unsigned int map_flags); +int vxd_unmap_buffer(struct vxd_dev *vxd, struct vxd_dec_ctx *ctx, + unsigned int str_id, unsigned int buff_id); + +unsigned int get_nbuffers(enum vdec_vid_std std, int w, int h, unsigned int max_num_ref_frames); + +int vxd_dec_alloc_bspp_resource(struct vxd_dec_ctx *ctx, enum vdec_vid_std vid_std); + +#ifdef ERROR_RECOVERY_SIMULATION +/* sysfs read write functions */ +ssize_t vxd_sysfs_show(struct kobject *vxd_dec_kobject, + struct kobj_attribute *attr, char *buf); + +ssize_t vxd_sysfs_store(struct kobject *vxd_dec_kobject, + struct kobj_attribute *attr, const char *buf, unsigned long count); +#endif +#endif /* _VXD_DEC_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_ext.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_ext.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_ext.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_ext.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD DEC Low-level device interface component + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + */ + +#ifndef _VXD_EXT_H +#define _VXD_EXT_H + +#define VLR_COMPLETION_COMMS_AREA_SIZE 476 + +/* Word Size of buffer used to pass messages between LISR and HISR */ +#define VXD_SIZE_MSG_BUFFER (1 * 1024) + +/* This structure describes macroblock coordinates. */ +struct vxd_mb_coords { + unsigned int x; + unsigned int y; +}; + +/* This structure contains firmware and decoding pipe state information. */ +struct vxd_pipestate { + unsigned char is_pipe_present; + unsigned char cur_codec; + unsigned int acheck_point[VDECFW_CHECKPOINT_MAX]; + unsigned int firmware_action; + unsigned int fe_slices; + unsigned int be_slices; + unsigned int fe_errored_slices; + unsigned int be_errored_slices; + unsigned int be_mbs_dropped; + unsigned int be_mbs_recovered; + struct vxd_mb_coords fe_mb; + struct vxd_mb_coords be_mb; +}; + +/* This structure contains firmware and decoder core state information. */ +struct vxd_firmware_state { + unsigned int fw_step; + struct vxd_pipestate pipe_state[VDECFW_MAX_DP]; +}; + +/* This structure contains the video decoder device state. */ +struct vxd_states { + struct vxd_firmware_state fw_state; +}; + +struct vxd_pict_attrs { + unsigned int dwrfired; + unsigned int mmufault; + unsigned int deverror; +}; + +/* This type defines the message attributes. */ +enum vxd_msg_attr { + VXD_MSG_ATTR_NONE = 0, + VXD_MSG_ATTR_DECODED = 1, + VXD_MSG_ATTR_FATAL = 2, + VXD_MSG_ATTR_CANCELED = 3, + VXD_MSG_ATTR_FORCE32BITS = 0x7FFFFFFFU +}; + +enum vxd_msg_flag { + VXD_MSG_FLAG_DROP = 0, + VXD_MSG_FLAG_EXCL = 1, + VXD_MSG_FLAG_FORCE32BITS = 0x7FFFFFFFU +}; + +#endif /* VXD_EXT_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_int.c b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_int.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_int.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_int.c 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,1137 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VXD DEC Common low level core interface component + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#include +#include +#include +#include +#include + +#include "bspp.h" +#include "fw_interface.h" +#include "h264fw_data.h" +#include "img_errors.h" +#include "img_dec_common.h" +#include "img_pvdec_core_regs.h" +#include "img_pvdec_pixel_regs.h" +#include "img_pvdec_test_regs.h" +#include "img_vdec_fw_msg.h" +#include "img_video_bus4_mmu_regs.h" +#include "img_msvdx_core_regs.h" +#include "img_msvdx_cmds.h" +#include "reg_io2.h" +#include "scaler_setup.h" +#include "vdecdd_defs.h" +#include "vdecdd_utils.h" +#include "vdecfw_shared.h" +#include "vdec_defs.h" +#include "vxd_ext.h" +#include "vxd_int.h" +#include "vxd_props.h" + +#define MSVDX_CACHE_REF_OFFSET_V100 (72L) +#define MSVDX_CACHE_ROW_OFFSET_V100 (4L) + +#define MSVDX_CACHE_REF_OFFSET_V550 (144L) +#define MSVDX_CACHE_ROW_OFFSET_V550 (8L) + +#define GET_BITS(v, lb, n) (((v) >> (lb)) & ((1 << (n)) - 1)) +#define IS_PVDEC_PIPELINE(std) ((std) == VDEC_STD_HEVC ? 1 : 0) + +static int amsvdx_codecmode[VDEC_STD_MAX] = { + /* Invalid */ + -1, + /* MPEG2 */ + 3, + /* MPEG4 */ + 4, + /* H263 */ + 4, + /* H264 */ + 1, + /* VC1 */ + 2, + /* AVS */ + 5, + /* RealVideo (8) */ + 8, + /* JPEG */ + 0, + /* On2 VP6 */ + 10, + /* On2 VP8 */ + 11, + /* Invalid */ +#ifdef HAS_VP9 + /* On2 VP9 */ + 13, +#endif + /* Sorenson */ + 4, + /* HEVC */ + 12, +}; + +struct msvdx_scaler_coeff_cmds { + unsigned int acmd_horizluma_coeff[VDECFW_NUM_SCALE_COEFFS]; + unsigned int acmd_vertluma_coeff[VDECFW_NUM_SCALE_COEFFS]; + unsigned int acmd_horizchroma_coeff[VDECFW_NUM_SCALE_COEFFS]; + unsigned int acmd_vertchroma_coeff[VDECFW_NUM_SCALE_COEFFS]; +}; + +static struct vxd_vidstd_props astd_props[] = { + { VDEC_STD_MPEG2, CORE_REVISION(7, 0, 0), 64, 16, 4096, 4096, 0, 8, 8, + PIXEL_FORMAT_420 }, + { VDEC_STD_MPEG4, CORE_REVISION(7, 0, 0), 64, 16, 4096, 4096, 0, 8, 8, + PIXEL_FORMAT_420 }, + { VDEC_STD_H263, CORE_REVISION(7, 0, 0), 64, 16, 4096, 4096, 0, 8, 8, + PIXEL_FORMAT_420 }, + { VDEC_STD_H264, CORE_REVISION(7, 0, 0), 64, 16, 4096, 4096, 0x10000, 8, + 8, PIXEL_FORMAT_420 }, + { VDEC_STD_VC1, CORE_REVISION(7, 0, 0), 80, 16, 4096, 4096, 0, 8, 8, + PIXEL_FORMAT_420 }, + { VDEC_STD_AVS, CORE_REVISION(7, 0, 0), 64, 16, 4096, 4096, 0, 8, 8, + PIXEL_FORMAT_420 }, + { VDEC_STD_REAL, CORE_REVISION(7, 0, 0), 64, 16, 4096, 4096, 0, 8, 8, + PIXEL_FORMAT_420 }, + { VDEC_STD_JPEG, CORE_REVISION(7, 0, 0), 64, 16, 32768, 32768, 0, 8, 8, + PIXEL_FORMAT_444 }, + { VDEC_STD_VP6, CORE_REVISION(7, 0, 0), 64, 16, 4096, 4096, 0, 8, 8, + PIXEL_FORMAT_420 }, + { VDEC_STD_VP8, CORE_REVISION(7, 0, 0), 64, 16, 4096, 4096, 0, 8, 8, + PIXEL_FORMAT_420 }, + { VDEC_STD_SORENSON, CORE_REVISION(7, 0, 0), 64, 16, 4096, 4096, 0, 8, + 8, PIXEL_FORMAT_420 }, + { VDEC_STD_HEVC, CORE_REVISION(7, 0, 0), 64, 16, 8192, 8192, 0, 8, 8, + PIXEL_FORMAT_420 }, +}; + +enum vdec_msvdx_async_mode { + VDEC_MSVDX_ASYNC_NORMAL, + VDEC_MSVDX_ASYNC_VDMC, + VDEC_MSVDX_ASYNC_VDEB, + VDEC_MSVDX_ASYNC_FORCE32BITS = 0x7FFFFFFFU +}; + +/* MSVDX row strides for video buffers. */ +static const unsigned int amsvdx_64byte_row_stride[] = { + 384, 768, 1280, 1920, 512, 1024, 2048, 4096 +}; + +/* MSVDX row strides for jpeg buffers. */ +static const unsigned int amsvdx_jpeg_row_stride[] = { + 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768 +}; + +/* VXD Core major revision. */ +static unsigned int maj_rev; +/* VXD Core minor revision. */ +static unsigned int min_rev; +/* VXD Core maintenance revision. */ +static unsigned int maint_rev; + +static int get_stride_code(enum vdec_vid_std vidstd, unsigned int row_stride) +{ + unsigned int i; + + if (vidstd == VDEC_STD_JPEG) { + for (i = 0; i < (sizeof(amsvdx_jpeg_row_stride) / + sizeof(amsvdx_jpeg_row_stride[0])); i++) { + if (amsvdx_jpeg_row_stride[i] == row_stride) + return i; + } + } else { + for (i = 0; i < (sizeof(amsvdx_64byte_row_stride) / + sizeof(amsvdx_64byte_row_stride[0])); i++) { + if (amsvdx_64byte_row_stride[i] == row_stride) + return i; + } + } + + return -1; +} + +/* Obtains the hardware defined video profile. */ +static unsigned int vxd_getprofile(enum vdec_vid_std vidstd, unsigned int std_profile) +{ + unsigned int profile = 0; + + switch (vidstd) { + case VDEC_STD_H264: + switch (std_profile) { + case H264_PROFILE_BASELINE: + profile = 0; + break; + + /* + * Extended may be attempted as Baseline or + * Main depending on the constraint_set_flags + */ + case H264_PROFILE_EXTENDED: + case H264_PROFILE_MAIN: + profile = 1; + break; + + case H264_PROFILE_HIGH: + case H264_PROFILE_HIGH444: + case H264_PROFILE_HIGH422: + case H264_PROFILE_HIGH10: + case H264_PROFILE_CAVLC444: + case H264_PROFILE_MVC_HIGH: + case H264_PROFILE_MVC_STEREO: + profile = 2; + break; + default: + profile = 2; + break; + } + break; + + default: + profile = 0; + break; + } + + return profile; +} + +static int vxd_getcoreproperties(struct vxd_coreprops *coreprops, + unsigned int corerev, + unsigned int pvdec_coreid, unsigned int mmu_config0, + unsigned int mmu_config1, unsigned int *pixel_pipecfg, + unsigned int *pixel_misccfg, unsigned int max_framecfg) +{ + unsigned int group_id; + unsigned int core_id; + unsigned int core_config; + unsigned int extended_address_range; + unsigned char group_size = 0; + unsigned char pipe_minus1 = 0; + unsigned int max_h264_hw_chromaformat = 0; + unsigned int max_hevc_hw_chromaformat = 0; + unsigned int max_bitdepth_luma = 0; + unsigned int i; + + struct pvdec_core_rev core_rev; + + if (!coreprops || !pixel_pipecfg || !pixel_misccfg) + return IMG_ERROR_INVALID_PARAMETERS; + + /* PVDEC Core Revision Information */ + core_rev.maj_rev = REGIO_READ_FIELD(corerev, PVDEC_CORE, CR_PVDEC_CORE_REV, + CR_PVDEC_MAJOR_REV); + core_rev.min_rev = REGIO_READ_FIELD(corerev, PVDEC_CORE, CR_PVDEC_CORE_REV, + CR_PVDEC_MINOR_REV); + core_rev.maint_rev = REGIO_READ_FIELD(corerev, PVDEC_CORE, CR_PVDEC_CORE_REV, + CR_PVDEC_MAINT_REV); + + /* core id */ + group_id = REGIO_READ_FIELD(pvdec_coreid, PVDEC_CORE, CR_PVDEC_CORE_ID, CR_GROUP_ID); + core_id = REGIO_READ_FIELD(pvdec_coreid, PVDEC_CORE, CR_PVDEC_CORE_ID, CR_CORE_ID); + + /* Ensure that the core is IMG Video Decoder (PVDEC). */ + if (group_id != 3 || core_id != 3) + return IMG_ERROR_DEVICE_NOT_FOUND; + + core_config = REGIO_READ_FIELD(pvdec_coreid, PVDEC_CORE, + CR_PVDEC_CORE_ID, CR_PVDEC_CORE_CONFIG); + + memset(coreprops, 0, sizeof(*(coreprops))); + + /* Construct core version name. */ + snprintf(coreprops->aversion, VER_STR_LEN, "%d.%d.%d", + core_rev.maj_rev, core_rev.min_rev, core_rev.maint_rev); + + coreprops->mmu_support_stride_per_context = + REGIO_READ_FIELD(mmu_config1, IMG_VIDEO_BUS4_MMU, + MMU_CONFIG1, + SUPPORT_STRIDE_PER_CONTEXT) == 1 ? 1 : 0; + + coreprops->mmu_support_secure = REGIO_READ_FIELD(mmu_config1, IMG_VIDEO_BUS4_MMU, + MMU_CONFIG1, SUPPORT_SECURE) == 1 ? 1 : 0; + + extended_address_range = REGIO_READ_FIELD(mmu_config0, IMG_VIDEO_BUS4_MMU, + MMU_CONFIG0, EXTENDED_ADDR_RANGE); + + switch (extended_address_range) { + case 0: + coreprops->mmu_type = MMU_TYPE_32BIT; + break; + case 4: + coreprops->mmu_type = MMU_TYPE_36BIT; + break; + case 8: + coreprops->mmu_type = MMU_TYPE_40BIT; + break; + default: + return IMG_ERROR_NOT_SUPPORTED; + } + + group_size += REGIO_READ_FIELD(mmu_config0, IMG_VIDEO_BUS4_MMU, + MMU_CONFIG0, GROUP_OVERRIDE_SIZE); + + coreprops->num_entropy_pipes = core_config & 0xF; + coreprops->num_pixel_pipes = core_config >> 4 & 0xF; +#ifdef DEBUG_DECODER_DRIVER + pr_info("PVDEC revision %08x detected, id %08x.\n", corerev, core_id); + pr_info("Found %d entropy pipe(s), %d pixel pipe(s), %d group size", + coreprops->num_entropy_pipes, coreprops->num_pixel_pipes, + group_size); +#endif + + /* Set global rev info variables used by macros */ + maj_rev = core_rev.maj_rev; + min_rev = core_rev.min_rev; + maint_rev = core_rev.maint_rev; + + /* Default settings */ + for (i = 0; i < ARRAY_SIZE(astd_props); i++) { + struct vxd_vidstd_props *pvidstd_props = + &coreprops->vidstd_props[astd_props[i].vidstd]; + /* + * Update video standard properties if the core is beyond + * specified version and the properties are for newer cores + * than the previous. + */ + if (FROM_REV(MAJOR_REVISION((int)astd_props[i].core_rev), + MINOR_REVISION((int)astd_props[i].core_rev), + MAINT_REVISION((int)astd_props[i].core_rev), int) && + astd_props[i].core_rev >= pvidstd_props->core_rev) { + *pvidstd_props = astd_props[i]; + + if (pvidstd_props->vidstd != VDEC_STD_JPEG && + (FROM_REV(8, 0, 0, int)) && (pvidstd_props->vidstd == + VDEC_STD_HEVC ? 1 : 0)) { + /* + * override default values with values + * specified in HW (register does not + * exist in previous cores) + */ + pvidstd_props->max_width = + 2 << REGIO_READ_FIELD(max_framecfg, + PVDEC_PIXEL, + CR_MAX_FRAME_CONFIG, + CR_PVDEC_HOR_MSB); + + pvidstd_props->max_height = + 2 << REGIO_READ_FIELD(max_framecfg, + PVDEC_PIXEL, + CR_MAX_FRAME_CONFIG, + CR_PVDEC_VER_MSB); + } else if (pvidstd_props->vidstd != VDEC_STD_JPEG && + (FROM_REV(8, 0, 0, int))) { + pvidstd_props->max_width = + 2 << REGIO_READ_FIELD(max_framecfg, + PVDEC_PIXEL, + CR_MAX_FRAME_CONFIG, + CR_MSVDX_HOR_MSB); + + pvidstd_props->max_height = + 2 << REGIO_READ_FIELD(max_framecfg, + PVDEC_PIXEL, + CR_MAX_FRAME_CONFIG, + CR_MSVDX_VER_MSB); + } + } + } + + /* Populate the core properties. */ + if (GET_BITS(core_config, 11, 1)) + coreprops->hd_support = 1; + + for (pipe_minus1 = 0; pipe_minus1 < coreprops->num_pixel_pipes; + pipe_minus1++) { + unsigned int current_bitdepth = + GET_BITS(pixel_misccfg[pipe_minus1], 4, 3) + 8; + unsigned int current_h264_hw_chromaformat = + GET_BITS(pixel_misccfg[pipe_minus1], 0, 2); + unsigned int current_hevc_hw_chromaformat = + GET_BITS(pixel_misccfg[pipe_minus1], 2, 2); +#ifdef DEBUG_DECODER_DRIVER + pr_info("cur_bitdepth: %d cur_h264_hw_chromaformat: %d", + current_bitdepth, current_h264_hw_chromaformat); + pr_info("cur_hevc_hw_chromaformat: %d pipe_minus1: %d\n", + current_hevc_hw_chromaformat, pipe_minus1); +#endif + + if (GET_BITS(pixel_misccfg[pipe_minus1], 8, 1)) + coreprops->rotation_support[pipe_minus1] = 1; + + if (GET_BITS(pixel_misccfg[pipe_minus1], 9, 1)) + coreprops->scaling_support[pipe_minus1] = 1; + + coreprops->num_streams[pipe_minus1] = + GET_BITS(pixel_misccfg[pipe_minus1], 12, 2) + 1; + + /* Video standards. */ + coreprops->mpeg2[pipe_minus1] = + GET_BITS(pixel_pipecfg[pipe_minus1], 0, 1) ? 1 : 0; + coreprops->mpeg4[pipe_minus1] = + GET_BITS(pixel_pipecfg[pipe_minus1], 1, 1) ? 1 : 0; + coreprops->h264[pipe_minus1] = + GET_BITS(pixel_pipecfg[pipe_minus1], 2, 1) ? 1 : 0; + coreprops->vc1[pipe_minus1] = + GET_BITS(pixel_pipecfg[pipe_minus1], 3, 1) ? 1 : 0; + coreprops->jpeg[pipe_minus1] = + GET_BITS(pixel_pipecfg[pipe_minus1], 5, 1) ? 1 : 0; + coreprops->avs[pipe_minus1] = + GET_BITS(pixel_pipecfg[pipe_minus1], 7, 1) ? 1 : 0; + coreprops->real[pipe_minus1] = + GET_BITS(pixel_pipecfg[pipe_minus1], 8, 1) ? 1 : 0; + coreprops->vp6[pipe_minus1] = + GET_BITS(pixel_pipecfg[pipe_minus1], 9, 1) ? 1 : 0; + coreprops->vp8[pipe_minus1] = + GET_BITS(pixel_pipecfg[pipe_minus1], 10, 1) ? 1 : 0; + coreprops->hevc[pipe_minus1] = + GET_BITS(pixel_pipecfg[pipe_minus1], 22, 1) ? 1 : 0; + + max_bitdepth_luma = (max_bitdepth_luma > current_bitdepth ? + max_bitdepth_luma : current_bitdepth); + max_h264_hw_chromaformat = (max_h264_hw_chromaformat > + current_h264_hw_chromaformat ? max_h264_hw_chromaformat + : current_h264_hw_chromaformat); + max_hevc_hw_chromaformat = (max_hevc_hw_chromaformat > + current_hevc_hw_chromaformat ? max_hevc_hw_chromaformat + : current_hevc_hw_chromaformat); + } + + /* Override default bit-depth with value signalled explicitly by core. */ + coreprops->vidstd_props[0].max_luma_bitdepth = max_bitdepth_luma; + coreprops->vidstd_props[0].max_chroma_bitdepth = + coreprops->vidstd_props[0].max_luma_bitdepth; + + for (i = 1; i < VDEC_STD_MAX; i++) { + coreprops->vidstd_props[i].max_luma_bitdepth = + coreprops->vidstd_props[0].max_luma_bitdepth; + coreprops->vidstd_props[i].max_chroma_bitdepth = + coreprops->vidstd_props[0].max_chroma_bitdepth; + } + + switch (max_h264_hw_chromaformat) { + case 1: + coreprops->vidstd_props[VDEC_STD_H264].max_chroma_format = + PIXEL_FORMAT_420; + break; + + case 2: + coreprops->vidstd_props[VDEC_STD_H264].max_chroma_format = + PIXEL_FORMAT_422; + break; + + case 3: + coreprops->vidstd_props[VDEC_STD_H264].max_chroma_format = + PIXEL_FORMAT_444; + break; + + default: + break; + } + + switch (max_hevc_hw_chromaformat) { + case 1: + coreprops->vidstd_props[VDEC_STD_HEVC].max_chroma_format = + PIXEL_FORMAT_420; + break; + + case 2: + coreprops->vidstd_props[VDEC_STD_HEVC].max_chroma_format = + PIXEL_FORMAT_422; + break; + + case 3: + coreprops->vidstd_props[VDEC_STD_HEVC].max_chroma_format = + PIXEL_FORMAT_444; + break; + + default: + break; + } + + return 0; +} + +static unsigned char vxd_is_supported_byatleast_onepipe(const unsigned char *features, + unsigned int num_pipes) +{ + unsigned int i; + + VDEC_ASSERT(features); + VDEC_ASSERT(num_pipes <= VDEC_MAX_PIXEL_PIPES); + + for (i = 0; i < num_pipes; i++) { + if (features[i]) + return 1; + } + + return 0; +} + +void vxd_set_reconpictcmds(const struct vdecdd_str_unit *str_unit, + const struct vdec_str_configdata *str_configdata, + const struct vdec_str_opconfig *output_config, + const struct vxd_coreprops *coreprops, + const struct vxd_buffers *buffers, + unsigned int *pict_cmds) +{ + struct pixel_pixinfo *pixel_info; + unsigned int row_stride_code; + unsigned char benable_auxline_buf = 1; + + unsigned int coded_height; + unsigned int coded_width; + unsigned int disp_height; + unsigned int disp_width; + unsigned int profile; + unsigned char plane; + unsigned int y_stride; + unsigned int uv_stride; + unsigned int v_stride; + unsigned int cache_ref_offset; + unsigned int cache_row_offset; + + if (str_configdata->vid_std == VDEC_STD_JPEG) { + disp_height = 0; + disp_width = 0; + coded_height = 0; + coded_width = 0; + } else { + coded_height = ALIGN(str_unit->pict_hdr_info->coded_frame_size.height, + (str_unit->pict_hdr_info->field) ? + 2 * VDEC_MB_DIMENSION : VDEC_MB_DIMENSION); + /* Hardware field is coded size - 1 */ + coded_height -= 1; + + coded_width = ALIGN(str_unit->pict_hdr_info->coded_frame_size.width, + VDEC_MB_DIMENSION); + /* Hardware field is coded size - 1 */ + coded_width -= 1; + + disp_height = str_unit->pict_hdr_info->disp_info.enc_disp_region.height + + str_unit->pict_hdr_info->disp_info.enc_disp_region.left_offset - 1; + disp_width = str_unit->pict_hdr_info->disp_info.enc_disp_region.width + + str_unit->pict_hdr_info->disp_info.enc_disp_region.top_offset - 1; + } + /* + * Display picture size (DISPLAY_PICTURE) + * The display to be written is not the actual video size to be + * displayed but a number that has to differ from the coded pixel size + * by less than 1MB (coded_size-display_size <= 0x0F). Because H264 can + * have a different display size, we need to check and write + * the coded_size again in the display_size register if this condition + * is not fulfilled. + */ + if (str_configdata->vid_std != VDEC_STD_VC1 && ((coded_height - disp_height) > 0x0F)) { + REGIO_WRITE_FIELD_LITE(pict_cmds[VDECFW_CMD_DISPLAY_PICTURE], + MSVDX_CMDS, DISPLAY_PICTURE_SIZE, + DISPLAY_PICTURE_HEIGHT, + coded_height, unsigned int); + } else { + REGIO_WRITE_FIELD_LITE(pict_cmds[VDECFW_CMD_DISPLAY_PICTURE], + MSVDX_CMDS, DISPLAY_PICTURE_SIZE, + DISPLAY_PICTURE_HEIGHT, + disp_height, unsigned int); + } + + if (((coded_width - disp_width) > 0x0F)) { + REGIO_WRITE_FIELD_LITE(pict_cmds[VDECFW_CMD_DISPLAY_PICTURE], + MSVDX_CMDS, DISPLAY_PICTURE_SIZE, + DISPLAY_PICTURE_WIDTH, + coded_width, unsigned int); + } else { + REGIO_WRITE_FIELD_LITE(pict_cmds[VDECFW_CMD_DISPLAY_PICTURE], + MSVDX_CMDS, DISPLAY_PICTURE_SIZE, + DISPLAY_PICTURE_WIDTH, + disp_width, unsigned int); + } + + REGIO_WRITE_FIELD_LITE(pict_cmds[VDECFW_CMD_CODED_PICTURE], + MSVDX_CMDS, CODED_PICTURE_SIZE, + CODED_PICTURE_HEIGHT, + coded_height, unsigned int); + REGIO_WRITE_FIELD_LITE(pict_cmds[VDECFW_CMD_CODED_PICTURE], + MSVDX_CMDS, CODED_PICTURE_SIZE, + CODED_PICTURE_WIDTH, + coded_width, unsigned int); + + /* + * For standards where dpb_diff != 1 and chroma format != 420 + * cache_ref_offset has to be calculated in the F/W. + */ + if (str_configdata->vid_std != VDEC_STD_HEVC && str_configdata->vid_std != VDEC_STD_H264) { + unsigned int log2_size, cache_size, luma_size; + unsigned char is_hevc_supported, is_hevc444_supported = 0; + + is_hevc_supported = + vxd_is_supported_byatleast_onepipe(coreprops->hevc, + coreprops->num_pixel_pipes); + + if (is_hevc_supported) { + is_hevc444_supported = + coreprops->vidstd_props[VDEC_STD_HEVC].max_chroma_format == + PIXEL_FORMAT_444 ? 1 : 0; + } + + log2_size = 9 + (is_hevc_supported ? 1 : 0) + (is_hevc444_supported ? 1 : 0); + cache_size = 3 << log2_size; + luma_size = (cache_size * 2) / 3; + cache_ref_offset = (luma_size * 15) / 32; + cache_ref_offset = (cache_ref_offset + 7) & (~7); + cache_row_offset = 0x0C; + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_MC_CACHE_CONFIGURATION], + MSVDX_CMDS, MC_CACHE_CONFIGURATION, + CONFIG_REF_CHROMA_ADJUST, 1, + unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_MC_CACHE_CONFIGURATION], + MSVDX_CMDS, MC_CACHE_CONFIGURATION, + CONFIG_REF_OFFSET, cache_ref_offset, + unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_MC_CACHE_CONFIGURATION], + MSVDX_CMDS, MC_CACHE_CONFIGURATION, + CONFIG_ROW_OFFSET, cache_row_offset, + unsigned int, unsigned int); + } + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_OPERATING_MODE], + MSVDX_CMDS, OPERATING_MODE, CODEC_MODE, + amsvdx_codecmode[str_configdata->vid_std], + unsigned int, unsigned int); + + profile = str_unit->seq_hdr_info->com_sequ_hdr_info.codec_profile; + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_OPERATING_MODE], + MSVDX_CMDS, OPERATING_MODE, CODEC_PROFILE, + vxd_getprofile(str_configdata->vid_std, profile), + unsigned int, unsigned int); + + plane = str_unit->seq_hdr_info->com_sequ_hdr_info.separate_chroma_planes; + pixel_info = &str_unit->seq_hdr_info->com_sequ_hdr_info.pixel_info; + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_OPERATING_MODE], + MSVDX_CMDS, OPERATING_MODE, CHROMA_FORMAT, plane ? + 0 : pixel_info->chroma_fmt, unsigned int, int); + + if (str_configdata->vid_std != VDEC_STD_JPEG) { + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_EXT_OP_MODE], + MSVDX_CMDS, EXT_OP_MODE, CHROMA_FORMAT_IDC, plane ? + 0 : pixel_get_hw_chroma_format_idc + (pixel_info->chroma_fmt_idc), + unsigned int, int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_EXT_OP_MODE], + MSVDX_CMDS, EXT_OP_MODE, MEMORY_PACKING, + output_config->pixel_info.mem_pkg == + PIXEL_BIT10_MP ? 1 : 0, unsigned int, int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_EXT_OP_MODE], + MSVDX_CMDS, EXT_OP_MODE, BIT_DEPTH_LUMA_MINUS8, + pixel_info->bitdepth_y - 8, + unsigned int, unsigned int); + + if (pixel_info->chroma_fmt_idc == PIXEL_FORMAT_MONO) { + /* + * For monochrome streams use the same bit depth for + * chroma and luma. + */ + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_EXT_OP_MODE], + MSVDX_CMDS, EXT_OP_MODE, + BIT_DEPTH_CHROMA_MINUS8, + pixel_info->bitdepth_y - 8, + unsigned int, unsigned int); + } else { + /* + * For normal streams use the appropriate bit depth for chroma. + */ + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_EXT_OP_MODE], MSVDX_CMDS, + EXT_OP_MODE, BIT_DEPTH_CHROMA_MINUS8, + pixel_info->bitdepth_c - 8, + unsigned int, unsigned int); + } + } else { + pict_cmds[VDECFW_CMD_EXT_OP_MODE] = 0; + } + + if (str_configdata->vid_std != VDEC_STD_JPEG) { + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_OPERATING_MODE], MSVDX_CMDS, + OPERATING_MODE, CHROMA_INTERLEAVED, + PIXEL_GET_HW_CHROMA_INTERLEAVED + (output_config->pixel_info.chroma_interleave), + unsigned int, int); + } + + if (str_configdata->vid_std == VDEC_STD_JPEG) { + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_OPERATING_MODE], + MSVDX_CMDS, OPERATING_MODE, ASYNC_MODE, + VDEC_MSVDX_ASYNC_VDMC, + unsigned int, unsigned int); + } + + if (str_configdata->vid_std == VDEC_STD_H264) { + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_OPERATING_MODE], MSVDX_CMDS, + OPERATING_MODE, ASYNC_MODE, + str_unit->pict_hdr_info->discontinuous_mbs ? + VDEC_MSVDX_ASYNC_VDMC : VDEC_MSVDX_ASYNC_NORMAL, + unsigned int, int); + } + + y_stride = buffers->recon_pict->rend_info.plane_info[VDEC_PLANE_VIDEO_Y].stride; + uv_stride = buffers->recon_pict->rend_info.plane_info[VDEC_PLANE_VIDEO_UV].stride; + v_stride = buffers->recon_pict->rend_info.plane_info[VDEC_PLANE_VIDEO_V].stride; + + if (((y_stride % (VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT)) == 0) && + ((uv_stride % (VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT)) == 0) && + ((v_stride % (VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT)) == 0)) { + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_OPERATING_MODE], + MSVDX_CMDS, OPERATING_MODE, + USE_EXT_ROW_STRIDE, 1, unsigned int, int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_EXTENDED_ROW_STRIDE], + MSVDX_CMDS, EXTENDED_ROW_STRIDE, + EXT_ROW_STRIDE, y_stride >> 6, unsigned int, unsigned int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_CHROMA_ROW_STRIDE], + MSVDX_CMDS, CHROMA_ROW_STRIDE, + CHROMA_ROW_STRIDE, uv_stride >> 6, unsigned int, unsigned int); + } else { + row_stride_code = get_stride_code(str_configdata->vid_std, y_stride); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_OPERATING_MODE], + MSVDX_CMDS, OPERATING_MODE, ROW_STRIDE, + row_stride_code & 0x7, unsigned int, unsigned int); + + if (str_configdata->vid_std == VDEC_STD_JPEG) { + /* + * Use the unused chroma interleaved flag + * to hold MSB of row stride code + */ + IMG_ASSERT(row_stride_code < 16); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_OPERATING_MODE], + MSVDX_CMDS, OPERATING_MODE, + CHROMA_INTERLEAVED, + row_stride_code >> 3, unsigned int, unsigned int); + } else { + IMG_ASSERT(row_stride_code < 8); + } + } + pict_cmds[VDECFW_CMD_LUMA_RECONSTRUCTED_PICTURE_BASE_ADDRESS] = + (unsigned int)GET_HOST_ADDR(&buffers->recon_pict->pict_buf->ddbuf_info) + + buffers->recon_pict->rend_info.plane_info[0].offset; + + pict_cmds[VDECFW_CMD_CHROMA_RECONSTRUCTED_PICTURE_BASE_ADDRESS] = + (unsigned int)GET_HOST_ADDR(&buffers->recon_pict->pict_buf->ddbuf_info) + + buffers->recon_pict->rend_info.plane_info[1].offset; + + pict_cmds[VDECFW_CMD_CHROMA2_RECONSTRUCTED_PICTURE_BASE_ADDRESS] = + (unsigned int)GET_HOST_ADDR(&buffers->recon_pict->pict_buf->ddbuf_info) + + buffers->recon_pict->rend_info.plane_info[2].offset; + + pict_cmds[VDECFW_CMD_LUMA_ERROR_PICTURE_BASE_ADDRESS] = 0; + pict_cmds[VDECFW_CMD_CHROMA_ERROR_PICTURE_BASE_ADDRESS] = 0; + +#ifdef ERROR_CONCEALMENT + /* update error concealment frame info if available */ + if (buffers->err_pict_bufinfo) { + pict_cmds[VDECFW_CMD_LUMA_ERROR_PICTURE_BASE_ADDRESS] = + (unsigned int)GET_HOST_ADDR(buffers->err_pict_bufinfo) + + buffers->recon_pict->rend_info.plane_info[0].offset; + + pict_cmds[VDECFW_CMD_CHROMA_ERROR_PICTURE_BASE_ADDRESS] = + (unsigned int)GET_HOST_ADDR(buffers->err_pict_bufinfo) + + buffers->recon_pict->rend_info.plane_info[1].offset; + } +#endif + + pict_cmds[VDECFW_CMD_INTRA_BUFFER_BASE_ADDRESS] = + (unsigned int)GET_HOST_ADDR(buffers->intra_bufinfo); + pict_cmds[VDECFW_CMD_INTRA_BUFFER_PLANE_SIZE] = + buffers->intra_bufsize_per_pipe / 3; + pict_cmds[VDECFW_CMD_INTRA_BUFFER_SIZE_PER_PIPE] = + buffers->intra_bufsize_per_pipe; + pict_cmds[VDECFW_CMD_AUX_LINE_BUFFER_BASE_ADDRESS] = + (unsigned int)GET_HOST_ADDR(buffers->auxline_bufinfo); + pict_cmds[VDECFW_CMD_AUX_LINE_BUFFER_SIZE_PER_PIPE] = + buffers->auxline_bufsize_per_pipe; + + /* + * for pvdec we need to set this registers even if we don't + * use alternative output + */ + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + ALT_BIT_DEPTH_CHROMA_MINUS8, + output_config->pixel_info.bitdepth_c - 8, unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + ALT_BIT_DEPTH_LUMA_MINUS8, + output_config->pixel_info.bitdepth_y - 8, unsigned int, unsigned int); + + /* + * this is causing corruption in RV40 and VC1 streams with + * scaling/rotation enabled on Coral, so setting to 0 + */ + benable_auxline_buf = benable_auxline_buf && + (str_configdata->vid_std != VDEC_STD_REAL) && + (str_configdata->vid_std != VDEC_STD_VC1); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_PICTURE_ROTATION], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION, + USE_AUX_LINE_BUF, benable_auxline_buf ? 1 : 0, unsigned int, int); +} + +void vxd_set_altpictcmds(const struct vdecdd_str_unit *str_unit, + const struct vdec_str_configdata *str_configdata, + const struct vdec_str_opconfig *output_config, + const struct vxd_coreprops *coreprops, + const struct vxd_buffers *buffers, + unsigned int *pict_cmds) +{ + unsigned int row_stride_code; + unsigned int y_stride; + unsigned int uv_stride; + unsigned int v_stride; + + y_stride = buffers->alt_pict->rend_info.plane_info[VDEC_PLANE_VIDEO_Y].stride; + uv_stride = buffers->alt_pict->rend_info.plane_info[VDEC_PLANE_VIDEO_UV].stride; + v_stride = buffers->alt_pict->rend_info.plane_info[VDEC_PLANE_VIDEO_V].stride; + + if (((y_stride % (VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT)) == 0) && + ((uv_stride % (VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT)) == 0) && + ((v_stride % (VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT)) == 0)) { + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_PICTURE_ROTATION], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION, + USE_EXT_ROT_ROW_STRIDE, 1, unsigned int, int); + + /* 64-byte (min) aligned luma stride value. */ + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_PICTURE_ROTATION], + MSVDX_CMDS, + ALTERNATIVE_OUTPUT_PICTURE_ROTATION, + EXT_ROT_ROW_STRIDE, y_stride >> 6, + unsigned int, unsigned int); + + /* 64-byte (min) aligned chroma stride value. */ + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_CHROMA_ROW_STRIDE], + MSVDX_CMDS, CHROMA_ROW_STRIDE, + ALT_CHROMA_ROW_STRIDE, uv_stride >> 6, + unsigned int, unsigned int); + } else { + /* + * Obtain the code for buffer stride + * (must be less than 8, i.e. not JPEG strides) + */ + row_stride_code = + get_stride_code(str_configdata->vid_std, y_stride); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_PICTURE_ROTATION], + MSVDX_CMDS, + ALTERNATIVE_OUTPUT_PICTURE_ROTATION, + ROTATION_ROW_STRIDE, row_stride_code & 0x7, + unsigned int, unsigned int); + } + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_PICTURE_ROTATION], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION, + SCALE_INPUT_SIZE_SEL, + ((output_config->pixel_info.chroma_fmt_idc != + str_unit->seq_hdr_info->com_sequ_hdr_info.pixel_info.chroma_fmt_idc)) ? + 1 : 0, unsigned int, int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_PICTURE_ROTATION], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION, + PACKED_422_OUTPUT, + (output_config->pixel_info.chroma_fmt_idc == + PIXEL_FORMAT_422 && + output_config->pixel_info.num_planes == 1) ? 1 : 0, + unsigned int, int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + ALT_OUTPUT_FORMAT, + str_unit->seq_hdr_info->com_sequ_hdr_info.separate_chroma_planes ? + 0 : pixel_get_hw_chroma_format_idc + (output_config->pixel_info.chroma_fmt_idc), + unsigned int, int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + ALT_BIT_DEPTH_CHROMA_MINUS8, + output_config->pixel_info.bitdepth_c - 8, + unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + ALT_BIT_DEPTH_LUMA_MINUS8, + output_config->pixel_info.bitdepth_y - 8, + unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + ALT_MEMORY_PACKING, + (output_config->pixel_info.mem_pkg == + PIXEL_BIT10_MP) ? 1 : 0, unsigned int, int); + + pict_cmds[VDECFW_CMD_LUMA_ALTERNATIVE_PICTURE_BASE_ADDRESS] = + (unsigned int)GET_HOST_ADDR(&buffers->alt_pict->pict_buf->ddbuf_info) + + buffers->alt_pict->rend_info.plane_info[0].offset; + + pict_cmds[VDECFW_CMD_CHROMA_ALTERNATIVE_PICTURE_BASE_ADDRESS] = + (unsigned int)GET_HOST_ADDR(&buffers->alt_pict->pict_buf->ddbuf_info) + + buffers->alt_pict->rend_info.plane_info[1].offset; + + pict_cmds[VDECFW_CMD_CHROMA2_ALTERNATIVE_PICTURE_BASE_ADDRESS] = + (unsigned int)GET_HOST_ADDR(&buffers->alt_pict->pict_buf->ddbuf_info) + + buffers->alt_pict->rend_info.plane_info[2].offset; +} + +int vxd_getscalercmds(const struct scaler_config *scaler_config, + const struct scaler_pitch *pitch, + const struct scaler_filter *filter, + const struct pixel_pixinfo *out_loop_pixel_info, + struct scaler_params *params, + unsigned int *pict_cmds) +{ + const struct vxd_coreprops *coreprops = scaler_config->coreprops; + /* + * Indirectly detect decoder core type (if HEVC is supported, it has + * to be PVDEC core) and decide if to force luma re-sampling. + */ + unsigned char bforce_luma_resampling = coreprops->hevc[0]; + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + ALT_OUTPUT_FORMAT, + scaler_config->bseparate_chroma_planes ? 0 : + pixel_get_hw_chroma_format_idc(out_loop_pixel_info->chroma_fmt_idc), + unsigned int, int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + SCALE_CHROMA_RESAMP_ONLY, bforce_luma_resampling ? 0 : + (pitch->horiz_luma == FIXED(1, HIGHP)) && + (pitch->vert_luma == FIXED(1, HIGHP)), unsigned int, int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, ALT_MEMORY_PACKING, + pixel_get_hw_memory_packing(out_loop_pixel_info->mem_pkg), + unsigned int, int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + ALT_BIT_DEPTH_LUMA_MINUS8, + out_loop_pixel_info->bitdepth_y - 8, + unsigned int, unsigned int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + ALT_BIT_DEPTH_CHROMA_MINUS8, + out_loop_pixel_info->bitdepth_c - 8, + unsigned int, unsigned int); + + /* Scale luma bifilter is always 0 for now */ + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + SCALE_LUMA_BIFILTER_HORIZ, + 0, unsigned int, int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + SCALE_LUMA_BIFILTER_VERT, + 0, unsigned int, int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + SCALE_CHROMA_BIFILTER_HORIZ, + filter->bhoriz_bilinear ? 1 : 0, + unsigned int, int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_ALTERNATIVE_OUTPUT_CONTROL], + MSVDX_CMDS, ALTERNATIVE_OUTPUT_CONTROL, + SCALE_CHROMA_BIFILTER_VERT, + filter->bvert_bilinear ? 1 : 0, unsigned int, int); + + /* for cores 7.x.x and more, precision 3.13 */ + params->fixed_point_shift = 13; + + /* Calculate the fixed-point versions for use by the hardware. */ + params->vert_pitch = (int)((pitch->vert_luma + + (1 << (HIGHP - params->fixed_point_shift - 1))) >> + (HIGHP - params->fixed_point_shift)); + params->vert_startpos = params->vert_pitch >> 1; + params->vert_pitch_chroma = (int)((pitch->vert_chroma + + (1 << (HIGHP - params->fixed_point_shift - 1))) >> + (HIGHP - params->fixed_point_shift)); + params->vert_startpos_chroma = params->vert_pitch_chroma >> 1; + params->horz_pitch = (int)(pitch->horiz_luma >> + (HIGHP - params->fixed_point_shift)); + params->horz_startpos = params->horz_pitch >> 1; + params->horz_pitch_chroma = (int)(pitch->horiz_chroma >> + (HIGHP - params->fixed_point_shift)); + params->horz_startpos_chroma = params->horz_pitch_chroma >> 1; + +#ifdef HAS_HEVC + if (scaler_config->vidstd == VDEC_STD_HEVC) { + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_SCALED_DISPLAY_SIZE], + MSVDX_CMDS, PVDEC_SCALED_DISPLAY_SIZE, + PVDEC_SCALE_DISPLAY_WIDTH, + scaler_config->recon_width - 1, + unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_SCALED_DISPLAY_SIZE], + MSVDX_CMDS, PVDEC_SCALED_DISPLAY_SIZE, + PVDEC_SCALE_DISPLAY_HEIGHT, + scaler_config->recon_height - 1, + unsigned int, unsigned int); + } else { + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_SCALED_DISPLAY_SIZE], + MSVDX_CMDS, SCALED_DISPLAY_SIZE, + SCALE_DISPLAY_WIDTH, + scaler_config->recon_width - 1, + unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_SCALED_DISPLAY_SIZE], + MSVDX_CMDS, SCALED_DISPLAY_SIZE, + SCALE_DISPLAY_HEIGHT, + scaler_config->recon_height - 1, + unsigned int, unsigned int); + } +#else + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_SCALED_DISPLAY_SIZE], + MSVDX_CMDS, SCALED_DISPLAY_SIZE, + SCALE_DISPLAY_WIDTH, + scaler_config->recon_width - 1, + unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_SCALED_DISPLAY_SIZE], + MSVDX_CMDS, SCALED_DISPLAY_SIZE, SCALE_DISPLAY_HEIGHT, + scaler_config->recon_height - 1, + unsigned int, unsigned int); +#endif + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_SCALE_OUTPUT_SIZE], + MSVDX_CMDS, SCALE_OUTPUT_SIZE, + SCALE_OUTPUT_WIDTH_MIN1, + scaler_config->scale_width - 1, + unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_SCALE_OUTPUT_SIZE], + MSVDX_CMDS, SCALE_OUTPUT_SIZE, + SCALE_OUTPUT_HEIGHT_MIN1, + scaler_config->scale_height - 1, + unsigned int, unsigned int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_HORIZONTAL_SCALE_CONTROL], + MSVDX_CMDS, HORIZONTAL_SCALE_CONTROL, + HORIZONTAL_SCALE_PITCH, params->horz_pitch, + unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_HORIZONTAL_SCALE_CONTROL], + MSVDX_CMDS, HORIZONTAL_SCALE_CONTROL, + HORIZONTAL_INITIAL_POS, params->horz_startpos, + unsigned int, unsigned int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_SCALE_HORIZONTAL_CHROMA], + MSVDX_CMDS, SCALE_HORIZONTAL_CHROMA, + CHROMA_HORIZONTAL_PITCH, params->horz_pitch_chroma, + unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_SCALE_HORIZONTAL_CHROMA], + MSVDX_CMDS, SCALE_HORIZONTAL_CHROMA, + CHROMA_HORIZONTAL_INITIAL, + params->horz_startpos_chroma, + unsigned int, unsigned int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_VERTICAL_SCALE_CONTROL], + MSVDX_CMDS, VERTICAL_SCALE_CONTROL, + VERTICAL_SCALE_PITCH, params->vert_pitch, + unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_VERTICAL_SCALE_CONTROL], + MSVDX_CMDS, VERTICAL_SCALE_CONTROL, + VERTICAL_INITIAL_POS, params->vert_startpos, + unsigned int, unsigned int); + + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_SCALE_VERTICAL_CHROMA], + MSVDX_CMDS, SCALE_VERTICAL_CHROMA, + CHROMA_VERTICAL_PITCH, params->vert_pitch_chroma, + unsigned int, unsigned int); + REGIO_WRITE_FIELD(pict_cmds[VDECFW_CMD_SCALE_VERTICAL_CHROMA], + MSVDX_CMDS, SCALE_VERTICAL_CHROMA, + CHROMA_VERTICAL_INITIAL, + params->vert_startpos_chroma, + unsigned int, unsigned int); + return 0; +} + +unsigned int vxd_get_codedpicsize(unsigned short width_min1, unsigned short height_min1) +{ + unsigned int reg = 0; + + REGIO_WRITE_FIELD_LITE(reg, MSVDX_CMDS, CODED_PICTURE_SIZE, + CODED_PICTURE_WIDTH, width_min1, + unsigned short); + REGIO_WRITE_FIELD_LITE(reg, MSVDX_CMDS, CODED_PICTURE_SIZE, + CODED_PICTURE_HEIGHT, height_min1, + unsigned short); + + return reg; +} + +unsigned char vxd_get_codedmode(enum vdec_vid_std vidstd) +{ + return (unsigned char)amsvdx_codecmode[vidstd]; +} + +void vxd_get_coreproperties(void *hndl_coreproperties, + struct vxd_coreprops *vxd_coreprops) +{ + struct vxd_core_props *props = + (struct vxd_core_props *)hndl_coreproperties; + + vxd_getcoreproperties(vxd_coreprops, props->core_rev, + props->pvdec_core_id, + props->mmu_config0, + props->mmu_config1, + props->pixel_pipe_cfg, + props->pixel_misc_cfg, + props->pixel_max_frame_cfg); +} + +int vxd_get_pictattrs(unsigned int flags, struct vxd_pict_attrs *pict_attrs) +{ + if (flags & (VXD_FW_MSG_FLAG_DWR | VXD_FW_MSG_FLAG_FATAL)) + pict_attrs->dwrfired = 1; + if (flags & VXD_FW_MSG_FLAG_MMU_FAULT) + pict_attrs->mmufault = 1; + if (flags & VXD_FW_MSG_FLAG_DEV_ERR) + pict_attrs->deverror = 1; + + return 0; +} + +int vxd_get_msgerrattr(unsigned int flags, enum vxd_msg_attr *msg_attr) +{ + if ((flags & ~VXD_FW_MSG_FLAG_CANCELED)) + *msg_attr = VXD_MSG_ATTR_FATAL; + else if ((flags & VXD_FW_MSG_FLAG_CANCELED)) + *msg_attr = VXD_MSG_ATTR_CANCELED; + else + *msg_attr = VXD_MSG_ATTR_NONE; + + return 0; +} + +int vxd_set_msgflag(enum vxd_msg_flag input_flag, unsigned int *flags) +{ + switch (input_flag) { + case VXD_MSG_FLAG_DROP: + *flags |= VXD_FW_MSG_FLAG_DROP; + break; + case VXD_MSG_FLAG_EXCL: + *flags |= VXD_FW_MSG_FLAG_EXCL; + break; + default: + return IMG_ERROR_FATAL; + } + + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_int.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_int.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_int.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_int.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD DEC Common low level core interface component + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ +#ifndef _VXD_INT_H +#define _VXD_INT_H + +#include "fw_interface.h" +#include "scaler_setup.h" +#include "vdecdd_defs.h" +#include "vdecfw_shared.h" +#include "vdec_defs.h" +#include "vxd_ext.h" +#include "vxd_props.h" + +/* + * Size of buffer used for batching messages + */ +#define BATCH_MSG_BUFFER_SIZE (8 * 4096) + +#define INTRA_BUF_SIZE (1024 * 32) +#define AUX_LINE_BUFFER_SIZE (512 * 1024) + +#define MAX_PICTURE_WIDTH (4096) +#define MAX_PICTURE_HEIGHT (4096) + +/* + * this macro returns the host address of device buffer. + */ +#define GET_HOST_ADDR(buf) ((buf)->dev_virt) + +#define GET_HOST_ADDR_OFFSET(buf, offset) (((buf)->dev_virt) + (offset)) + +/* + * The extended stride alignment for VXD. + */ +#define VDEC_VXD_EXT_STRIDE_ALIGNMENT_DEFAULT (64) + +struct vxd_buffers { + struct vdecdd_ddpict_buf *recon_pict; + struct vdecdd_ddpict_buf *alt_pict; + struct vidio_ddbufinfo *intra_bufinfo; + struct vidio_ddbufinfo *auxline_bufinfo; + struct vidio_ddbufinfo *err_pict_bufinfo; + unsigned int intra_bufsize_per_pipe; + unsigned int auxline_bufsize_per_pipe; + struct vidio_ddbufinfo *msb_bufinfo; + unsigned char btwopass; +}; + +struct pvdec_core_rev { + unsigned int maj_rev; + unsigned int min_rev; + unsigned int maint_rev; + unsigned int int_rev; +}; + +/* + * this has all that it needs to translate a Stream Unit for a picture + * into a transaction. + */ +void vxd_set_altpictcmds(const struct vdecdd_str_unit *str_unit, + const struct vdec_str_configdata *str_configdata, + const struct vdec_str_opconfig *output_config, + const struct vxd_coreprops *coreprops, + const struct vxd_buffers *buffers, + unsigned int *pict_cmds); + +/* + * this has all that it needs to translate a Stream Unit for + * a picture into a transaction. + */ +void vxd_set_reconpictcmds(const struct vdecdd_str_unit *str_unit, + const struct vdec_str_configdata *str_configdata, + const struct vdec_str_opconfig *output_config, + const struct vxd_coreprops *coreprops, + const struct vxd_buffers *buffers, + unsigned int *pict_cmds); + +int vxd_getscalercmds(const struct scaler_config *scaler_config, + const struct scaler_pitch *pitch, + const struct scaler_filter *filter, + const struct pixel_pixinfo *out_loop_pixel_info, + struct scaler_params *params, + unsigned int *pict_cmds); + +/* + * this creates value of MSVDX_CMDS_CODED_PICTURE_SIZE register. + */ +unsigned int vxd_get_codedpicsize(unsigned short width_min1, unsigned short height_min1); + +/* + * return HW codec mode based on video standard. + */ +unsigned char vxd_get_codedmode(enum vdec_vid_std vidstd); + +/* + * translates core properties to the form of the struct vxd_coreprops struct. + */ +void vxd_get_coreproperties(void *hndl_coreproperties, + struct vxd_coreprops *vxd_coreprops); + +/* + * translates picture attributes to the form of the VXD_sPictAttrs struct. + */ +int vxd_get_pictattrs(unsigned int flags, struct vxd_pict_attrs *pict_attrs); + +/* + * translates message attributes to the form of the VXD_eMsgAttr struct. + */ +int vxd_get_msgerrattr(unsigned int flags, enum vxd_msg_attr *msg_attr); + +/* + * sets a message flag. + */ +int vxd_set_msgflag(enum vxd_msg_flag input_flag, unsigned int *flags); + +#endif /* _VXD_INT_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_mmu_defs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_mmu_defs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_mmu_defs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_mmu_defs.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * V-DEC MMU Definitions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + */ + +#ifndef _VXD_MMU_DEF_H_ +#define _VXD_MMU_DEF_H_ + +/* + * This type defines the MMU heaps. + * @0: Heap for untiled video buffers + * @1: Heap for bitstream buffers + * @2: Heap for Stream buffers + * @3: Number of heaps + */ +enum mmu_eheap_id { + MMU_HEAP_IMAGE_BUFFERS_UNTILED = 0x00, + MMU_HEAP_BITSTREAM_BUFFERS, + MMU_HEAP_STREAM_BUFFERS, + MMU_HEAP_MAX, + MMU_HEAP_FORCE32BITS = 0x7FFFFFFFU +}; + +#endif /* _VXD_MMU_DEFS_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_props.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_props.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_props.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_props.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Low-level VXD interface component + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + */ + +#ifndef _VXD_PROPS_H +#define _VXD_PROPS_H + +#include "vdec_defs.h" +#include "imgmmu.h" + +#define VDEC_MAX_PIXEL_PIPES 2 + +#define VXD_MAX_CORES 1 +#define VER_STR_LEN 64 + +#define CORE_REVISION(maj, min, maint) \ + ((((maj) & 0xff) << 16) | (((min) & 0xff) << 8) | (((maint) & 0xff))) +#define MAJOR_REVISION(rev) (((rev) >> 16) & 0xff) +#define MINOR_REVISION(rev) (((rev) >> 8) & 0xff) +#define MAINT_REVISION(rev) ((rev) & 0xff) + +#define FROM_REV(maj, min, maint, type) \ + ({ \ + type __maj = maj; \ + type __min = min; \ + (((maj_rev) > (__maj)) || \ + (((maj_rev) == (__maj)) && ((min_rev) > (__min))) || \ + (((maj_rev) == (__maj)) && ((min_rev) == (__min)) && \ + ((int)(maint_rev) >= (maint)))); }) + +struct vxd_vidstd_props { + enum vdec_vid_std vidstd; + unsigned int core_rev; + unsigned int min_width; + unsigned int min_height; + unsigned int max_width; + unsigned int max_height; + unsigned int max_macroblocks; + unsigned int max_luma_bitdepth; + unsigned int max_chroma_bitdepth; + enum pixel_fmt_idc max_chroma_format; +}; + +struct vxd_coreprops { + unsigned char aversion[VER_STR_LEN]; + unsigned char mpeg2[VDEC_MAX_PIXEL_PIPES]; + unsigned char mpeg4[VDEC_MAX_PIXEL_PIPES]; + unsigned char h264[VDEC_MAX_PIXEL_PIPES]; + unsigned char vc1[VDEC_MAX_PIXEL_PIPES]; + unsigned char avs[VDEC_MAX_PIXEL_PIPES]; + unsigned char real[VDEC_MAX_PIXEL_PIPES]; + unsigned char jpeg[VDEC_MAX_PIXEL_PIPES]; + unsigned char vp6[VDEC_MAX_PIXEL_PIPES]; + unsigned char vp8[VDEC_MAX_PIXEL_PIPES]; + unsigned char hevc[VDEC_MAX_PIXEL_PIPES]; + unsigned char rotation_support[VDEC_MAX_PIXEL_PIPES]; + unsigned char scaling_support[VDEC_MAX_PIXEL_PIPES]; + unsigned char hd_support; + unsigned int num_streams[VDEC_MAX_PIXEL_PIPES]; + unsigned int num_entropy_pipes; + unsigned int num_pixel_pipes; + struct vxd_vidstd_props vidstd_props[VDEC_STD_MAX]; + enum mmu_etype mmu_type; + unsigned char mmu_support_stride_per_context; + unsigned char mmu_support_secure; + /* Range extensions supported by hw -> used only by hevc */ + unsigned char hevc_range_ext[VDEC_MAX_PIXEL_PIPES]; +}; + +#endif /* _VXD_PROPS_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_pvdec.c b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_pvdec.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_pvdec.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_pvdec.c 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,1745 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMG DEC PVDEC function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "img_dec_common.h" +#include "img_pvdec_test_regs.h" +#include "img_video_bus4_mmu_regs.h" +#include "vxd_pvdec_priv.h" +#include "vxd_pvdec_regs.h" + +#ifdef PVDEC_SINGLETHREADED_IO +static DEFINE_SPINLOCK(pvdec_irq_lock); +static ulong pvdec_irq_flags; +#endif + +static const ulong vxd_plat_poll_udelay = 100; + +/* This function will return reminder and quotient */ +static inline unsigned int do_divide(unsigned long long *n, unsigned int base) +{ + unsigned int remainder = *n % base; + *n = *n / base; + return remainder; +} + +/* + * Reads PROC_DEBUG register and provides number of MTX RAM banks + * and their size + */ +static int pvdec_get_mtx_ram_info(void __iomem *reg_base, int *bank_cnt, + unsigned long *bank_size, + unsigned long *last_bank_size) +{ + unsigned int ram_bank_count, reg; + + reg = VXD_RD_REG(reg_base, PVDEC_CORE, PROC_DEBUG); + ram_bank_count = VXD_RD_REG_FIELD(reg, PVDEC_CORE, PROC_DEBUG, MTX_RAM_BANKS); + if (!ram_bank_count) + return -EIO; + + if (bank_cnt) + *bank_cnt = ram_bank_count; + + if (bank_size) { + unsigned int ram_bank_size = VXD_RD_REG_FIELD(reg, PVDEC_CORE, + PROC_DEBUG, MTX_RAM_BANK_SIZE); + *bank_size = 1 << (ram_bank_size + 2); + } + + if (last_bank_size) { + unsigned int last_bank = VXD_RD_REG_FIELD(reg, PVDEC_CORE, PROC_DEBUG, + MTX_LAST_RAM_BANK_SIZE); + unsigned char new_representation = VXD_RD_REG_FIELD(reg, + PVDEC_CORE, PROC_DEBUG, MTX_RAM_NEW_REPRESENTATION); + if (new_representation) { + *last_bank_size = 1024 * last_bank; + } else { + *last_bank_size = 1 << (last_bank + 2); + if (bank_cnt && last_bank == 13 && *bank_cnt == 4) { + /* + * VXD hardware ambiguity: + * old cores confuse 120k and 128k + * So assume worst case. + */ + *last_bank_size -= 0x2000; + } + } + } + + return 0; +} + +/* Provides size of MTX RAM in bytes */ +static int pvdec_get_mtx_ram_size(void __iomem *reg_base, unsigned int *ram_size) +{ + int bank_cnt, ret; + unsigned long bank_size, last_bank_size; + + ret = pvdec_get_mtx_ram_info(reg_base, &bank_cnt, &bank_size, &last_bank_size); + if (ret) + return ret; + + *ram_size = (bank_cnt - 1) * bank_size + last_bank_size; + + return 0; +} + +/* Poll for single register-based transfer to/from MTX to complete */ +static unsigned int pvdec_wait_mtx_reg_access(void __iomem *reg_base, unsigned int *mtx_fault) +{ + unsigned int pvdec_timeout = PVDEC_TIMEOUT_COUNTER, reg; + + do { + /* Check MTX is OK */ + reg = VXD_RD_REG(reg_base, MTX_CORE, MTX_FAULT0); + if (reg != 0) { + *mtx_fault = reg; + return -EIO; + } + + pvdec_timeout--; + reg = VXD_RD_REG(reg_base, MTX_CORE, MTX_REG_READ_WRITE_REQUEST); + } while ((VXD_RD_REG_FIELD(reg, MTX_CORE, + MTX_REG_READ_WRITE_REQUEST, + MTX_DREADY) == 0) && + (pvdec_timeout != 0)); + + if (pvdec_timeout == 0) + return -EIO; + + return 0; +} + +static void pvdec_mtx_status_dump(void __iomem *reg_base, unsigned int *status) +{ + unsigned int reg; + + pr_debug("%s: *** dumping status ***\n", __func__); + +#define READ_MTX_REG(_NAME_) \ + do { \ + unsigned int val; \ + VXD_WR_REG(reg_base, MTX_CORE, \ + MTX_REG_READ_WRITE_REQUEST, reg); \ + if (pvdec_wait_mtx_reg_access(reg_base, ®)) { \ + pr_debug("%s: " \ + "MTX REG RD fault: 0x%08x\n", __func__, reg); \ + break; \ + } \ + val = VXD_RD_REG(reg_base, MTX_CORE, MTX_REG_READ_WRITE_DATA); \ + if (status) \ + *status++ = val; \ + pr_debug("%s: " _NAME_ ": 0x%08x\n", __func__, val); \ + } while (0) + + reg = 0; + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, /* Read */ + MTX_REG_READ_WRITE_REQUEST, MTX_RNW, 1); + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, /* PC or PCX */ + MTX_REG_READ_WRITE_REQUEST, MTX_USPECIFIER, 5); + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, /* PC */ + MTX_REG_READ_WRITE_REQUEST, MTX_RSPECIFIER, 0); + READ_MTX_REG("MTX PC"); + + reg = 0; + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, /* Read */ + MTX_REG_READ_WRITE_REQUEST, MTX_RNW, 1); + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, /* PC or PCX */ + MTX_REG_READ_WRITE_REQUEST, MTX_USPECIFIER, 5); + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, /* PCX */ + MTX_REG_READ_WRITE_REQUEST, MTX_RSPECIFIER, 1); + READ_MTX_REG("MTX PCX"); + + reg = 0; + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, /* Read */ + MTX_REG_READ_WRITE_REQUEST, MTX_RNW, 1); + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, /* A0StP */ + MTX_REG_READ_WRITE_REQUEST, MTX_USPECIFIER, 3); + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, + MTX_REG_READ_WRITE_REQUEST, MTX_RSPECIFIER, 0); + READ_MTX_REG("MTX A0STP"); + + reg = 0; + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, /* Read */ + MTX_REG_READ_WRITE_REQUEST, MTX_RNW, 1); + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, /* A0FrP */ + MTX_REG_READ_WRITE_REQUEST, MTX_USPECIFIER, 3); + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, MTX_REG_READ_WRITE_REQUEST, MTX_RSPECIFIER, 1); + READ_MTX_REG("MTX A0FRP"); +#undef PRINT_MTX_REG + + pr_debug("%s: *** status dump done ***\n", __func__); +} + +static void pvdec_prep_fw_upload(const void *dev, + void __iomem *reg_base, + struct vxd_ena_params *ena_params, + unsigned char dma_channel) +{ + unsigned int fw_vxd_virt_addr = ena_params->fw_buf_virt_addr; + unsigned int vxd_ptd_addr = ena_params->ptd; + unsigned int reg = 0; + int i; + unsigned int flags = PVDEC_FWFLAG_FORCE_FS_FLOW | + PVDEC_FWFLAG_DISABLE_GENC_FLUSHING | + PVDEC_FWFLAG_DISABLE_AUTONOMOUS_RESET | + PVDEC_FWFLAG_DISABLE_IDLE_GPIO | + PVDEC_FWFLAG_ENABLE_ERROR_CONCEALMENT; + + if (ena_params->secure) + flags |= PVDEC_FWFLAG_BIG_TO_HOST_BUFFER; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: fw_virt: 0x%x, ptd: 0x%x, dma ch: %u, flags: 0x%x\n", + __func__, fw_vxd_virt_addr, vxd_ptd_addr, dma_channel, flags); +#endif + + /* Reset MTX */ + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, MTX_SOFT_RESET, MTX_RESET, 1); + VXD_WR_REG(reg_base, MTX_CORE, MTX_SOFT_RESET, reg); + /* + * NOTE: The MTX reset bit is WRITE ONLY, so we cannot + * check the reset procedure has finished, thus BEWARE to put + * any MTX_CORE* access just after this line + */ + + /* Clear COMMS RAM header */ + for (i = 0; i < PVDEC_FW_COMMS_HDR_SIZE; i++) + VXD_WR_REG_ABS(reg_base, VLR_OFFSET + i * sizeof(unsigned int), 0); + + VXD_WR_REG_ABS(reg_base, VLR_OFFSET + PVDEC_FW_FLAGS_OFFSET, flags); + /* Do not wait for debug FIFO flag - set it only when requested */ + VXD_WR_REG_ABS(reg_base, VLR_OFFSET + PVDEC_FW_SIGNATURE_OFFSET, + !ena_params->wait_dbg_fifo); + + /* + * Clear the bypass bits and enable extended addressing in MMU. + * Firmware depends on this configuration, so we have to set it, + * even if firmware is being uploaded via registers. + */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_ADDRESS_CONTROL, UPPER_ADDR_FIXED, 0); + reg = VXD_WR_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_ADDRESS_CONTROL, MMU_ENA_EXT_ADDR, 1); + reg = VXD_WR_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_ADDRESS_CONTROL, MMU_BYPASS, 0); + VXD_WR_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_ADDRESS_CONTROL, reg); + + /* + * Buffer device virtual address. + * This is an address of a firmware blob, firmware reads this base + * address from DMAC_SETUP register and uses to load the modules, so it + * has to be set even when uploading the FW via registers. + */ + VXD_WR_RPT_REG(reg_base, DMAC, DMAC_SETUP, fw_vxd_virt_addr, dma_channel); + + /* + * Set base address of PTD. Same as before, has to be configured even + * when uploading the firmware via regs, FW uses it to execute DMA + * before switching to stream MMU context. + */ + VXD_WR_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_DIR_BASE_ADDR, vxd_ptd_addr); + + /* Configure MMU bank index - Use bank 0 */ + VXD_WR_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_BANK_INDEX, 0); + + /* Set the MTX timer divider register */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, MTX_SYSC_TIMERDIV, TIMER_EN, 1); + /* + * Setting max freq - divide by 1 for better measurement accuracy + * during fw upload stage + */ + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, MTX_SYSC_TIMERDIV, TIMER_DIV, 0); + VXD_WR_REG(reg_base, MTX_CORE, MTX_SYSC_TIMERDIV, reg); +} + +static int pvdec_check_fw_sig(void __iomem *reg_base) +{ + unsigned int fw_sig = VXD_RD_REG_ABS(reg_base, VLR_OFFSET + + PVDEC_FW_SIGNATURE_OFFSET); + + if (fw_sig != PVDEC_FW_READY_SIG) + return -EIO; + + return 0; +} + +static void pvdec_kick_mtx(void __iomem *reg_base) +{ + unsigned int reg = 0; + + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, MTX_KICKI, MTX_KICKI, 1); + VXD_WR_REG(reg_base, MTX_CORE, MTX_KICKI, reg); +} + +static int pvdec_write_vlr(void __iomem *reg_base, const unsigned int *buf, + unsigned long size_dwrds, int off_dwrds) +{ + unsigned int i; + + if (((off_dwrds + size_dwrds) * sizeof(unsigned int)) > VLR_SIZE) + return -EINVAL; + + for (i = 0; i < size_dwrds; i++) { + int off = (off_dwrds + i) * sizeof(unsigned int); + + VXD_WR_REG_ABS(reg_base, (VLR_OFFSET + off), *buf); + buf++; + } + + return 0; +} + +static int pvdec_poll_fw_boot(void __iomem *reg_base, struct vxd_boot_poll_params *poll_params) +{ + unsigned int i; + + for (i = 0; i < 25; i++) { + if (!pvdec_check_fw_sig(reg_base)) + return 0; + usleep_range(100, 110); + } + for (i = 0; i < poll_params->msleep_cycles; i++) { + if (!pvdec_check_fw_sig(reg_base)) + return 0; + msleep(100); + } + return -EIO; +} + +static int pvdec_read_vlr(void __iomem *reg_base, unsigned int *buf, + unsigned long size_dwrds, int off_dwrds) +{ + unsigned int i; + + if (((off_dwrds + size_dwrds) * sizeof(unsigned int)) > VLR_SIZE) + return -EINVAL; + + for (i = 0; i < size_dwrds; i++) { + int off = (off_dwrds + i) * sizeof(unsigned int); + *buf++ = VXD_RD_REG_ABS(reg_base, (VLR_OFFSET + off)); + } + + return 0; +} + +/* Get configuration of a ring buffer used to send messages to the MTX */ +static int pvdec_get_to_mtx_cfg(void __iomem *reg_base, unsigned long *size, int *off, + unsigned int *wr_idx, unsigned int *rd_idx) +{ + unsigned int to_mtx_cfg; + int to_mtx_off, ret; + + ret = pvdec_check_fw_sig(reg_base); + if (ret) + return ret; + + to_mtx_cfg = VXD_RD_REG_ABS(reg_base, VLR_OFFSET + PVDEC_FW_TO_MTX_BUF_CONF_OFFSET); + + *size = PVDEC_FW_COM_BUF_SIZE(to_mtx_cfg); + to_mtx_off = PVDEC_FW_COM_BUF_OFF(to_mtx_cfg); + + if (to_mtx_off % 4) + return -EIO; + + to_mtx_off /= sizeof(unsigned int); + *off = to_mtx_off; + + *wr_idx = VXD_RD_REG_ABS(reg_base, VLR_OFFSET + PVDEC_FW_TO_MTX_WR_IDX_OFFSET); + *rd_idx = VXD_RD_REG_ABS(reg_base, VLR_OFFSET + PVDEC_FW_TO_MTX_RD_IDX_OFFSET); + + if ((*rd_idx >= *size) || (*wr_idx >= *size)) + return -EIO; + + return 0; +} + +/* Submit a padding message to the host->MTX ring buffer */ +static int pvdec_send_pad_msg(void __iomem *reg_base) +{ + int ret, pad_size, to_mtx_off; /* offset in dwords */ + unsigned int wr_idx, rd_idx; /* indicies in dwords */ + unsigned long pad_msg_size = 1, to_mtx_size; /* size in dwords */ + const unsigned long max_msg_size = VXD_MAX_PAYLOAD_SIZE / sizeof(unsigned int); + unsigned int pad_msg; + + ret = pvdec_get_to_mtx_cfg(reg_base, &to_mtx_size, &to_mtx_off, &wr_idx, &rd_idx); + if (ret) + return ret; + + pad_size = to_mtx_size - wr_idx; /* size in dwords */ + + if (pad_size <= 0) { + VXD_WR_REG_ABS(reg_base, VLR_OFFSET + PVDEC_FW_TO_MTX_WR_IDX_OFFSET, 0); + return 0; + } + + while (pad_size > 0) { + int cur_pad_size = pad_size > max_msg_size ? + max_msg_size : pad_size; + + pad_msg = 0; + pad_msg = VXD_WR_REG_FIELD(pad_msg, PVDEC_FW, DEVA_GENMSG, MSG_SIZE, cur_pad_size); + pad_msg = VXD_WR_REG_FIELD(pad_msg, PVDEC_FW, DEVA_GENMSG, + MSG_TYPE, PVDEC_FW_MSG_TYPE_PADDING); + + ret = pvdec_write_vlr(reg_base, &pad_msg, pad_msg_size, to_mtx_off + wr_idx); + if (ret) + return ret; + + wr_idx += cur_pad_size; + + VXD_WR_REG_ABS(reg_base, VLR_OFFSET + PVDEC_FW_TO_MTX_WR_IDX_OFFSET, wr_idx); + + pad_size -= cur_pad_size; + + pvdec_kick_mtx(reg_base); + } + + wr_idx = 0; + VXD_WR_REG_ABS(reg_base, VLR_OFFSET + PVDEC_FW_TO_MTX_WR_IDX_OFFSET, wr_idx); + + return 0; +} + +/* + * Check if there is enough space in comms RAM to submit a + * dwords long message. Submit a padding message if necessary and requested. + * + * Returns 0 if there is space for a message. + * Returns -EINVAL when msg is too big or empty. + * Returns -EIO when there was a problem accessing the HW. + * Returns -EBUSY when there is not ennough space. + */ +static int pvdec_check_comms_space(void __iomem *reg_base, unsigned long msg_size, + unsigned char send_padding) +{ + int ret, to_mtx_off; /* offset in dwords */ + unsigned int wr_idx, rd_idx; /* indicies in dwords */ + unsigned long to_mtx_size; /* size in dwords */ + + ret = pvdec_get_to_mtx_cfg(reg_base, &to_mtx_size, &to_mtx_off, &wr_idx, &rd_idx); + if (ret) + return ret; + + /* Enormous or empty message, won't fit */ + if (msg_size >= to_mtx_size || !msg_size) + return -EINVAL; + + /* Buffer does not wrap */ + if (wr_idx >= rd_idx) { + /* Is there enough space to put the message? */ + if (wr_idx + msg_size < to_mtx_size) + return 0; + + if (!send_padding) + return -EBUSY; + + /* Check if it's ok to send a padding message */ + if (rd_idx == 0) + return -EBUSY; + + /* Send a padding message */ + ret = pvdec_send_pad_msg(reg_base); + if (ret) + return ret; + + /* + * And check if there's enough space at the beginning + * of a buffer + */ + if (msg_size >= rd_idx) + return -EBUSY; /* Not enough space at the beginning */ + + } else { /* Buffer wraps */ + if (wr_idx + msg_size >= rd_idx) + return -EBUSY; /* Not enough space! */ + } + + return 0; +} + +/* Get configuration of a ring buffer used to receive messages from the MTX */ +static int pvdec_get_to_host_cfg(void __iomem *reg_base, unsigned long *size, int *off, + unsigned int *wr_idx, unsigned int *rd_idx) +{ + unsigned int to_host_cfg; + int to_host_off, ret; + + ret = pvdec_check_fw_sig(reg_base); + if (ret) + return ret; + + to_host_cfg = VXD_RD_REG_ABS(reg_base, VLR_OFFSET + PVDEC_FW_TO_HOST_BUF_CONF_OFFSET); + + *size = PVDEC_FW_COM_BUF_SIZE(to_host_cfg); + to_host_off = PVDEC_FW_COM_BUF_OFF(to_host_cfg); + + if (to_host_off % 4) + return -EIO; + + to_host_off /= sizeof(unsigned int); + *off = to_host_off; + + *wr_idx = VXD_RD_REG_ABS(reg_base, VLR_OFFSET + PVDEC_FW_TO_HOST_WR_IDX_OFFSET); + *rd_idx = VXD_RD_REG_ABS(reg_base, VLR_OFFSET + PVDEC_FW_TO_HOST_RD_IDX_OFFSET); + + if ((*rd_idx >= *size) || (*wr_idx >= *size)) + return -EIO; + + return 0; +} + +static void pvdec_select_pipe(void __iomem *reg_base, unsigned char pipe) +{ + unsigned int reg = 0; + + reg = VXD_WR_REG_FIELD(reg, PVDEC_CORE, PVDEC_HOST_PIPE_SELECT, PIPE_SEL, pipe); + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_HOST_PIPE_SELECT, reg); +} + +static void pvdec_pre_boot_setup(const void *dev, + void __iomem *reg_base, + struct vxd_ena_params *ena_params) +{ + /* Memory staller pre boot settings */ + if (ena_params->mem_staller.data) { + unsigned char size = ena_params->mem_staller.size; + + if (size == PVDEC_CORE_MEMSTALLER_ELEMENTS) { + unsigned int *data = ena_params->mem_staller.data; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: Setting up memory staller", __func__); +#endif + /* + * Data structure represents PVDEC_TEST memory staller + * registers according to TRM 5.25 section + */ + VXD_WR_REG(reg_base, PVDEC_TEST, MEM_READ_LATENCY, data[0]); + VXD_WR_REG(reg_base, PVDEC_TEST, MEM_WRITE_RESPONSE_LATENCY, data[1]); + VXD_WR_REG(reg_base, PVDEC_TEST, MEM_CTRL, data[2]); + VXD_WR_REG(reg_base, PVDEC_TEST, RAND_STL_MEM_CMD_CONFIG, data[3]); + VXD_WR_REG(reg_base, PVDEC_TEST, RAND_STL_MEM_WDATA_CONFIG, data[4]); + VXD_WR_REG(reg_base, PVDEC_TEST, RAND_STL_MEM_WRESP_CONFIG, data[5]); + VXD_WR_REG(reg_base, PVDEC_TEST, RAND_STL_MEM_RDATA_CONFIG, data[6]); + } else { + dev_warn(dev, "%s: Wrong layout of mem staller config (%u)!", + __func__, size); + } + } +} + +static void pvdec_post_boot_setup(const void *dev, + void __iomem *reg_base, + unsigned int freq_khz) +{ + int reg; + + /* + * Configure VXD MMU to use video tiles (256x16) and unique + * strides per context as default. There is currently no + * override mechanism. + */ + reg = VXD_RD_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_CONTROL0); + reg = VXD_WR_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_CONTROL0, + MMU_TILING_SCHEME, 0); + reg = VXD_WR_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_CONTROL0, + USE_TILE_STRIDE_PER_CTX, 1); + VXD_WR_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_CONTROL0, reg); + + /* + * Setup VXD MMU with the tile heap device virtual address + * ranges. + */ + VXD_WR_RPT_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_TILE_MIN_ADDR, + PVDEC_HEAP_TILE512_START, 0); + VXD_WR_RPT_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_TILE_MAX_ADDR, + PVDEC_HEAP_TILE512_START + PVDEC_HEAP_TILE512_SIZE - 1, 0); + VXD_WR_RPT_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_TILE_MIN_ADDR, + PVDEC_HEAP_TILE1024_START, 1); + VXD_WR_RPT_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_TILE_MAX_ADDR, + PVDEC_HEAP_TILE1024_START + PVDEC_HEAP_TILE1024_SIZE - 1, 1); + VXD_WR_RPT_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_TILE_MIN_ADDR, + PVDEC_HEAP_TILE2048_START, 2); + VXD_WR_RPT_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_TILE_MAX_ADDR, + PVDEC_HEAP_TILE2048_START + PVDEC_HEAP_TILE2048_SIZE - 1, 2); + VXD_WR_RPT_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_TILE_MIN_ADDR, + PVDEC_HEAP_TILE4096_START, 3); + VXD_WR_RPT_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_TILE_MAX_ADDR, + PVDEC_HEAP_TILE4096_START + PVDEC_HEAP_TILE4096_SIZE - 1, 3); + + /* Disable timer */ + VXD_WR_REG(reg_base, MTX_CORE, MTX_SYSC_TIMERDIV, 0); + + reg = 0; + if (freq_khz) + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, MTX_SYSC_TIMERDIV, TIMER_DIV, + PVDEC_CALC_TIMER_DIV(freq_khz / 1000)); + else + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, MTX_SYSC_TIMERDIV, + TIMER_DIV, PVDEC_CLK_MHZ_DEFAULT - 1); + + /* Enable the MTX timer with final settings */ + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, MTX_SYSC_TIMERDIV, TIMER_EN, 1); + VXD_WR_REG(reg_base, MTX_CORE, MTX_SYSC_TIMERDIV, reg); +} + +static void pvdec_clock_measure(void __iomem *reg_base, + struct timespec64 *start_time, + unsigned int *start_ticks) +{ + local_irq_disable(); + ktime_get_real_ts64(start_time); + *start_ticks = VXD_RD_REG(reg_base, MTX_CORE, MTX_SYSC_TXTIMER); + local_irq_enable(); +} + +static int pvdec_clock_calculate(const void *dev, + void __iomem *reg_base, + struct timespec64 *start_time, + unsigned int start_ticks, + unsigned int *freq_khz) +{ + struct timespec64 end_time, dif_time; + long long span_nsec = 0; + unsigned int stop_ticks, tot_ticks; + + local_irq_disable(); + ktime_get_real_ts64(&end_time); + + stop_ticks = VXD_RD_REG(reg_base, MTX_CORE, MTX_SYSC_TXTIMER); + local_irq_enable(); + + *(struct timespec64 *)(&dif_time) = timespec64_sub(*((struct timespec64 *)(&end_time)), + *((struct timespec64 *)(&start_time))); + + span_nsec = timespec64_to_ns((const struct timespec64 *)&dif_time); + + /* Sanity check for mtx timer */ + if (!stop_ticks || stop_ticks < start_ticks) { + dev_err(dev, "%s: invalid ticks (0x%x -> 0x%x)\n", + __func__, start_ticks, stop_ticks); + return -EIO; + } + tot_ticks = stop_ticks - start_ticks; + + if (span_nsec) { + unsigned long long res = (unsigned long long)tot_ticks * 1000000UL; + + do_divide(&res, span_nsec); + *freq_khz = (unsigned int)res; + if (*freq_khz < 1000) + *freq_khz = 1000; /* 1MHz */ + } else { + dev_err(dev, "%s: generic failure!\n", __func__); + *freq_khz = 0; + return -ERANGE; + } + + return 0; +} + +static int pvdec_wait_dma_done(const void *dev, + void __iomem *reg_base, + unsigned long size, + unsigned char dma_channel) +{ + unsigned int reg, timeout = PVDEC_TIMEOUT_COUNTER, prev_count, count = size; + + do { + usleep_range(300, 310); + prev_count = count; + reg = VXD_RD_RPT_REG(reg_base, DMAC, DMAC_COUNT, dma_channel); + count = VXD_RD_REG_FIELD(reg, DMAC, DMAC_COUNT, CNT); + /* Check for dma progress */ + if (count == prev_count) { + /* There could be a bus lag, protect against that */ + timeout--; + if (timeout == 0) { + dev_err(dev, "%s FW DMA failed! (0x%x)\n", __func__, count); + return -EIO; + } + } else { + /* Reset timeout counter */ + timeout = PVDEC_TIMEOUT_COUNTER; + } + } while (count > 0); + + return 0; +} + +static int pvdec_start_fw_dma(const void *dev, + void __iomem *reg_base, + unsigned char dma_channel, + unsigned long fw_buf_size, + unsigned int *freq_khz) +{ + unsigned int reg = 0; + int ret = 0; + + fw_buf_size = fw_buf_size / sizeof(unsigned int); +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: dma FW upload, fw_buf_size: %zu (dwords)\n", __func__, fw_buf_size); +#endif + + pvdec_select_pipe(reg_base, 1); + + reg = VXD_RD_REG(reg_base, PVDEC_PIXEL, PIXEL_MAN_CLK_ENA); + reg = VXD_WR_REG_FIELD(reg, PVDEC_PIXEL, PIXEL_MAN_CLK_ENA, PIXEL_DMAC_MAN_CLK_ENA, 1); + reg = VXD_WR_REG_FIELD(reg, PVDEC_PIXEL, PIXEL_MAN_CLK_ENA, PIXEL_REG_MAN_CLK_ENA, 1); + VXD_WR_REG(reg_base, PVDEC_PIXEL, PIXEL_MAN_CLK_ENA, reg); + + /* + * Setup MTX to receive DMA + * DMA transfers to/from the MTX have to be 32-bit aligned and + * in multiples of 32 bits + */ + VXD_WR_REG(reg_base, MTX_CORE, MTX_SYSC_CDMAA, 0); /* MTX: 0x80900000 */ + + reg = 0; + /* Burst size in multiples of 64 bits (allowed values are 2 or 4) */ + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, MTX_SYSC_CDMAC, BURSTSIZE, 0); + /* 0 - write to MTX memory */ + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, MTX_SYSC_CDMAC, RNW, 0); + /* Begin transfer */ + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, MTX_SYSC_CDMAC, ENABLE, 1); + /* Transfer size */ + reg = VXD_WR_REG_FIELD(reg, MTX_CORE, MTX_SYSC_CDMAC, LENGTH, + ((fw_buf_size + 7) & (~7)) + 8); + VXD_WR_REG(reg_base, MTX_CORE, MTX_SYSC_CDMAC, reg); + + /* Boot MTX once transfer is done */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, PVDEC_CORE, PROC_DMAC_CONTROL, + BOOT_ON_DMA_CH0, 1); + VXD_WR_REG(reg_base, PVDEC_CORE, PROC_DMAC_CONTROL, reg); + + /* Toggle channel 0 usage between MTX and other PVDEC peripherals */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, PVDEC_PIXEL, PIXEL_CONTROL_0, + DMAC_CH_SEL_FOR_MTX, 0); + VXD_WR_REG(reg_base, PVDEC_PIXEL, PIXEL_CONTROL_0, reg); + + /* Reset DMA channel first */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, SRST, 1); + VXD_WR_RPT_REG(reg_base, DMAC, DMAC_COUNT, reg, dma_channel); + + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, LIST_EN, 0); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, CNT, 0); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, EN, 0); + VXD_WR_RPT_REG(reg_base, DMAC, DMAC_COUNT, reg, dma_channel); + + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, SRST, 0); + VXD_WR_RPT_REG(reg_base, DMAC, DMAC_COUNT, reg, dma_channel); + + /* + * Setup a Simple DMA for Ch0 + * Specify the holdover period to use for the channel + */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_PER_HOLD, PER_HOLD, 7); + VXD_WR_RPT_REG(reg_base, DMAC, DMAC_PER_HOLD, reg, dma_channel); + + /* Clear the DMAC Stats */ + VXD_WR_RPT_REG(reg_base, DMAC, DMAC_IRQ_STAT, 0, dma_channel); + + reg = 0; + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_PERIPH_ADDR, ADDR, + MTX_CORE_MTX_SYSC_CDMAT_OFFSET); + VXD_WR_RPT_REG(reg_base, DMAC, DMAC_PERIPH_ADDR, reg, dma_channel); + + /* Clear peripheral register address */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_PERIPH, ACC_DEL, 0); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_PERIPH, INCR, DMAC_INCR_OFF); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_PERIPH, BURST, DMAC_BURST_1); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_PERIPH, EXT_BURST, DMAC_EXT_BURST_0); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_PERIPH, EXT_SA, 0); + VXD_WR_RPT_REG(reg_base, DMAC, DMAC_PERIPH, reg, dma_channel); + + /* + * Now start the transfer by setting the list enable bit in + * the count register + */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, TRANSFER_IEN, 1); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, PW, DMAC_PWIDTH_32_BIT); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, DIR, DMAC_MEM_TO_VXD); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, PI, DMAC_INCR_ON); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, LIST_FIN_CTL, 0); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, LIST_EN, 0); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, ENABLE_2D_MODE, 0); + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, CNT, fw_buf_size); + VXD_WR_RPT_REG(reg_base, DMAC, DMAC_COUNT, reg, dma_channel); + + reg = VXD_WR_REG_FIELD(reg, DMAC, DMAC_COUNT, EN, 1); + VXD_WR_RPT_REG(reg_base, DMAC, DMAC_COUNT, reg, dma_channel); + + /* NOTE: The MTX timer starts once DMA boot is triggered */ + { + struct timespec64 host_time; + unsigned int mtx_time; + + pvdec_clock_measure(reg_base, &host_time, &mtx_time); + + ret = pvdec_wait_dma_done(dev, reg_base, fw_buf_size, dma_channel); + if (!ret) { + if (pvdec_clock_calculate(dev, reg_base, &host_time, mtx_time, + freq_khz) < 0) + dev_dbg(dev, "%s: measure info not available!\n", __func__); + } + } + + return ret; +} + +static int pvdec_set_clocks(void __iomem *reg_base, unsigned int req_clocks) +{ + unsigned int clocks = 0, reg; + unsigned int pvdec_timeout; + + /* Turn on core clocks only */ + clocks = VXD_WR_REG_FIELD(clocks, PVDEC_CORE, PVDEC_MAN_CLK_ENA, + PVDEC_REG_MAN_CLK_ENA, 1); + clocks = VXD_WR_REG_FIELD(clocks, PVDEC_CORE, PVDEC_MAN_CLK_ENA, CORE_MAN_CLK_ENA, 1); + + /* Wait until core clocks set */ + pvdec_timeout = PVDEC_TIMEOUT_COUNTER; + do { + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_MAN_CLK_ENA, clocks); + udelay(vxd_plat_poll_udelay); + reg = VXD_RD_REG(reg_base, PVDEC_CORE, PVDEC_MAN_CLK_ENA); + pvdec_timeout--; + } while (reg != clocks && pvdec_timeout != 0); + + if (pvdec_timeout == 0) + return -EIO; + + /* Write requested clocks */ + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_MAN_CLK_ENA, req_clocks); + + return 0; +} + +static int pvdec_enable_clocks(void __iomem *reg_base) +{ + unsigned int clocks = 0; + + clocks = VXD_WR_REG_FIELD(clocks, PVDEC_CORE, PVDEC_MAN_CLK_ENA, + PVDEC_REG_MAN_CLK_ENA, 1); + clocks = VXD_WR_REG_FIELD(clocks, PVDEC_CORE, PVDEC_MAN_CLK_ENA, + CORE_MAN_CLK_ENA, 1); + clocks = VXD_WR_REG_FIELD(clocks, PVDEC_CORE, PVDEC_MAN_CLK_ENA, + MEM_MAN_CLK_ENA, 1); + clocks = VXD_WR_REG_FIELD(clocks, PVDEC_CORE, PVDEC_MAN_CLK_ENA, + PROC_MAN_CLK_ENA, 1); + clocks = VXD_WR_REG_FIELD(clocks, PVDEC_CORE, PVDEC_MAN_CLK_ENA, + PIXEL_PROC_MAN_CLK_ENA, 1); + + return pvdec_set_clocks(reg_base, clocks); +} + +static int pvdec_disable_clocks(void __iomem *reg_base) +{ + return pvdec_set_clocks(reg_base, 0); +} + +static void pvdec_ena_mtx_int(void __iomem *reg_base) +{ + unsigned int reg = VXD_RD_REG(reg_base, PVDEC_CORE, PVDEC_HOST_INT_ENA); + + reg = VXD_WR_REG_FIELD(reg, PVDEC_CORE, PVDEC_INT_STAT, HOST_PROC_IRQ, 1); + reg = VXD_WR_REG_FIELD(reg, PVDEC_CORE, PVDEC_INT_STAT, HOST_MMU_FAULT_IRQ, 1); + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_HOST_INT_ENA, reg); +} + +static void pvdec_check_mmu_requests(void __iomem *reg_base, + unsigned int mmu_checks, + unsigned int max_attempts) +{ + unsigned int reg, i, checks = 0; + + for (i = 0; i < max_attempts; i++) { + reg = VXD_RD_REG(reg_base, + IMG_VIDEO_BUS4_MMU, MMU_MEM_REQ); + reg = VXD_RD_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_MEM_REQ, TAG_OUTSTANDING); + if (reg) { + udelay(vxd_plat_poll_udelay); + continue; + } + + /* Read READ_WORDS_OUTSTANDING */ + reg = VXD_RD_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_MEM_EXT_OUTSTANDING); + reg = VXD_RD_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_MEM_EXT_OUTSTANDING, + READ_WORDS); + if (!reg) { + checks++; + if (checks == mmu_checks) + break; + } else { /* Reset the counter and continue */ + checks = 0; + } + } + + if (checks != mmu_checks) + pr_warn("Checking for MMU outstanding requests failed!\n"); +} + +static int pvdec_reset(void __iomem *reg_base, unsigned char skip_pipe_clocks) +{ + unsigned int reg = 0; + unsigned char pipe, num_ent_pipes, num_pix_pipes; + unsigned int core_id, pvdec_timeout; + + core_id = VXD_RD_REG(reg_base, PVDEC_CORE, PVDEC_CORE_ID); + + num_ent_pipes = VXD_RD_REG_FIELD(core_id, PVDEC_CORE, PVDEC_CORE_ID, ENT_PIPES); + num_pix_pipes = VXD_RD_REG_FIELD(core_id, PVDEC_CORE, PVDEC_CORE_ID, PIX_PIPES); + + if (num_pix_pipes == 0 || num_pix_pipes > VXD_MAX_PIPES) + return -EINVAL; + + /* Clear interrupt enabled flag */ + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_HOST_INT_ENA, 0); + + /* Clear any pending interrupt flags */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, PVDEC_CORE, PVDEC_INT_CLEAR, IRQ_CLEAR, 0xFFFF); + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_INT_CLEAR, reg); + + /* Turn all clocks on - don't touch reserved bits! */ + pvdec_set_clocks(reg_base, 0xFFFF0113); + + if (!skip_pipe_clocks) { + for (pipe = 1; pipe <= num_pix_pipes; pipe++) { + pvdec_select_pipe(reg_base, pipe); + /* Turn all available clocks on - skip reserved bits! */ + VXD_WR_REG(reg_base, PVDEC_PIXEL, PIXEL_MAN_CLK_ENA, 0xFFBF0FFF); + } + + for (pipe = 1; pipe <= num_ent_pipes; pipe++) { + pvdec_select_pipe(reg_base, pipe); + /* Turn all available clocks on - skip reserved bits! */ + VXD_WR_REG(reg_base, PVDEC_ENTROPY, ENTROPY_MAN_CLK_ENA, 0x5); + } + } + + /* 1st MMU outstanding requests check */ + pvdec_check_mmu_requests(reg_base, 1000, 2000); + + /* Make sure MMU is not under reset MMU_SOFT_RESET -> 0 */ + pvdec_timeout = PVDEC_TIMEOUT_COUNTER; + do { + reg = VXD_RD_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1); + reg = VXD_RD_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, MMU_SOFT_RESET); + udelay(vxd_plat_poll_udelay); + pvdec_timeout--; + } while (reg != 0 && pvdec_timeout != 0); + + if (pvdec_timeout == 0) { + pr_err("Waiting for MMU soft reset(1) timed out!\n"); + pvdec_mtx_status_dump(reg_base, NULL); + } + + /* Write 1 to MMU_PAUSE_SET */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, MMU_PAUSE_SET, 1); + VXD_WR_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, reg); + + /* 2nd MMU outstanding requests check */ + pvdec_check_mmu_requests(reg_base, 100, 1000); + + /* Issue software reset for all but MMU/core */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, PVDEC_CORE, PVDEC_SOFT_RST, PVDEC_PIXEL_PROC_SOFT_RST, 0xFF); + reg = VXD_WR_REG_FIELD(reg, PVDEC_CORE, PVDEC_SOFT_RST, PVDEC_ENTROPY_SOFT_RST, 0xFF); + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_SOFT_RST, reg); + + VXD_RD_REG(reg_base, PVDEC_CORE, PVDEC_SOFT_RST); + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_SOFT_RST, 0); + + /* Write 1 to MMU_PAUSE_CLEAR in MMU_CONTROL1 reg */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, MMU_PAUSE_CLEAR, 1); + VXD_WR_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, reg); + + /* Confirm MMU_PAUSE_SET is cleared */ + pvdec_timeout = PVDEC_TIMEOUT_COUNTER; + do { + reg = VXD_RD_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1); + reg = VXD_RD_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, MMU_PAUSE_SET); + udelay(vxd_plat_poll_udelay); + pvdec_timeout--; + } while (reg != 0 && pvdec_timeout != 0); + + if (pvdec_timeout == 0) { + pr_err("Waiting for MMU pause clear timed out!\n"); + pvdec_mtx_status_dump(reg_base, NULL); + return -EIO; + } + + /* Issue software reset for MMU */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, MMU_SOFT_RESET, 1); + VXD_WR_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, reg); + + /* Wait until MMU_SOFT_RESET -> 0 */ + pvdec_timeout = PVDEC_TIMEOUT_COUNTER; + do { + reg = VXD_RD_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1); + reg = VXD_RD_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, MMU_SOFT_RESET); + udelay(vxd_plat_poll_udelay); + pvdec_timeout--; + } while (reg != 0 && pvdec_timeout != 0); + + if (pvdec_timeout == 0) { + pr_err("Waiting for MMU soft reset(2) timed out!\n"); + pvdec_mtx_status_dump(reg_base, NULL); + } + + /* Issue software reset for entire PVDEC */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, PVDEC_CORE, PVDEC_SOFT_RST, PVDEC_SOFT_RST, 0x1); + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_SOFT_RST, reg); + + /* Waiting for reset bit to be cleared */ + pvdec_timeout = PVDEC_TIMEOUT_COUNTER; + do { + reg = VXD_RD_REG(reg_base, PVDEC_CORE, PVDEC_SOFT_RST); + reg = VXD_RD_REG_FIELD(reg, PVDEC_CORE, PVDEC_SOFT_RST, PVDEC_SOFT_RST); + udelay(vxd_plat_poll_udelay); + pvdec_timeout--; + } while (reg != 0 && pvdec_timeout != 0); + + if (pvdec_timeout == 0) { + pr_err("Waiting for PVDEC soft reset timed out!\n"); + pvdec_mtx_status_dump(reg_base, NULL); + return -EIO; + } + + /* Clear interrupt enabled flag */ + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_HOST_INT_ENA, 0); + + /* Clear any pending interrupt flags */ + reg = 0; + reg = VXD_WR_REG_FIELD(reg, PVDEC_CORE, PVDEC_INT_CLEAR, IRQ_CLEAR, 0xFFFF); + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_INT_CLEAR, reg); + return 0; +} + +static int pvdec_get_properties(void __iomem *reg_base, + struct vxd_core_props *props) +{ + unsigned int major, minor, maint, group_id, core_id; + unsigned char num_pix_pipes, pipe; + + if (!props) + return -EINVAL; + + /* PVDEC Core Revision Information */ + props->core_rev = VXD_RD_REG(reg_base, PVDEC_CORE, PVDEC_CORE_REV); + major = VXD_RD_REG_FIELD(props->core_rev, PVDEC_CORE, PVDEC_CORE_REV, PVDEC_MAJOR_REV); + minor = VXD_RD_REG_FIELD(props->core_rev, PVDEC_CORE, PVDEC_CORE_REV, PVDEC_MINOR_REV); + maint = VXD_RD_REG_FIELD(props->core_rev, PVDEC_CORE, PVDEC_CORE_REV, PVDEC_MAINT_REV); + + /* Core ID */ + props->pvdec_core_id = VXD_RD_REG(reg_base, PVDEC_CORE, PVDEC_CORE_ID); + group_id = VXD_RD_REG_FIELD(props->pvdec_core_id, PVDEC_CORE, PVDEC_CORE_ID, GROUP_ID); + core_id = VXD_RD_REG_FIELD(props->pvdec_core_id, PVDEC_CORE, PVDEC_CORE_ID, CORE_ID); + + /* Ensure that the core is IMG Video Decoder (PVDEC). */ + if (group_id != 3 || core_id != 3) { + pr_err("Wrong core revision %d.%d.%d !!!\n", major, minor, maint); + return -EIO; + } + + props->mmu_config0 = VXD_RD_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_CONFIG0); + props->mmu_config1 = VXD_RD_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_CONFIG1); + + num_pix_pipes = VXD_NUM_PIX_PIPES(*props); + + if (unlikely(num_pix_pipes > VXD_MAX_PIPES)) { + pr_warn("Too many pipes detected!\n"); + num_pix_pipes = VXD_MAX_PIPES; + } + + for (pipe = 1; pipe <= num_pix_pipes; ++pipe) { + pvdec_select_pipe(reg_base, pipe); + if (pipe < VXD_MAX_PIPES) { + props->pixel_pipe_cfg[pipe - 1] = + VXD_RD_REG(reg_base, PVDEC_PIXEL, PIXEL_PIPE_CONFIG); + props->pixel_misc_cfg[pipe - 1] = + VXD_RD_REG(reg_base, PVDEC_PIXEL, PIXEL_MISC_CONFIG); + /* + * Detect pipe access problems. + * Pipe config shall always indicate + * a non zero value (at least one standard supported)! + */ + if (!props->pixel_pipe_cfg[pipe - 1]) + pr_warn("Pipe config info is wrong!\n"); + } + } + + pvdec_select_pipe(reg_base, 1); + props->pixel_max_frame_cfg = VXD_RD_REG(reg_base, PVDEC_PIXEL, MAX_FRAME_CONFIG); + + { + unsigned int fifo_ctrl = VXD_RD_REG(reg_base, PVDEC_CORE, PROC_DBG_FIFO_CTRL0); + + props->dbg_fifo_size = VXD_RD_REG_FIELD(fifo_ctrl, + PVDEC_CORE, + PROC_DBG_FIFO_CTRL0, + PROC_DBG_FIFO_SIZE); + } + + return 0; +} + +int vxd_pvdec_init(const void *dev, void __iomem *reg_base) +{ + int ret; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: trying to reset VXD, reg base: %p\n", __func__, reg_base); +#endif + + ret = pvdec_enable_clocks(reg_base); + if (ret) { + dev_err(dev, "%s: failed to enable clocks!\n", __func__); + return ret; + } + + ret = pvdec_reset(reg_base, FALSE); + if (ret) { + dev_err(dev, "%s: VXD reset failed!\n", __func__); + return ret; + } + + pvdec_ena_mtx_int(reg_base); + + return 0; +} + +/* Send dwords long message */ +int vxd_pvdec_send_msg(const void *dev, + void __iomem *reg_base, + unsigned int *msg, + unsigned long msg_size, + unsigned short msg_id, + struct vxd_dev *ctx) +{ + int ret, to_mtx_off; /* offset in dwords */ + unsigned int wr_idx, rd_idx; /* indicies in dwords */ + unsigned long to_mtx_size; /* size in dwords */ + unsigned int msg_wrd; + struct timespec64 time; + static int cnt; + + ktime_get_real_ts64(&time); + + ctx->time_fw[cnt].start_time = timespec64_to_ns((const struct timespec64 *)&time); + ctx->time_fw[cnt].id = msg_id; + cnt++; + + if (cnt >= ARRAY_SIZE(ctx->time_fw)) + cnt = 0; + + ret = pvdec_get_to_mtx_cfg(reg_base, &to_mtx_size, &to_mtx_off, &wr_idx, &rd_idx); + if (ret) { + dev_err(dev, "%s: failed to obtain mtx ring buffer config!\n", __func__); + return ret; + } + + /* populate the size and id fields in the message header */ + msg_wrd = VXD_RD_MSG_WRD(msg, PVDEC_FW, DEVA_GENMSG); + msg_wrd = VXD_WR_REG_FIELD(msg_wrd, PVDEC_FW, DEVA_GENMSG, MSG_SIZE, msg_size); + msg_wrd = VXD_WR_REG_FIELD(msg_wrd, PVDEC_FW, DEVA_GENMSG, MSG_ID, msg_id); + VXD_WR_MSG_WRD(msg, PVDEC_FW, DEVA_GENMSG, msg_wrd); + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: [msg out] size: %zu, id: 0x%x, type: 0x%x\n", __func__, msg_size, msg_id, + VXD_RD_REG_FIELD(msg_wrd, PVDEC_FW, DEVA_GENMSG, MSG_TYPE)); + dev_dbg(dev, "%s: to_mtx: (%zu @ %d), wr_idx: %d, rd_idx: %d\n", + __func__, to_mtx_size, to_mtx_off, wr_idx, rd_idx); +#endif + + ret = pvdec_check_comms_space(reg_base, msg_size, FALSE); + if (ret) { + dev_err(dev, "%s: invalid message or not enough space (%d)!\n", __func__, ret); + return ret; + } + + ret = pvdec_write_vlr(reg_base, msg, msg_size, to_mtx_off + wr_idx); + if (ret) { + dev_err(dev, "%s: failed to write msg to vlr!\n", __func__); + return ret; + } + + wr_idx += msg_size; + if (wr_idx == to_mtx_size) + wr_idx = 0; + VXD_WR_REG_ABS(reg_base, VLR_OFFSET + + PVDEC_FW_TO_MTX_WR_IDX_OFFSET, wr_idx); + + pvdec_kick_mtx(reg_base); + + return 0; +} + +/* Fetch size (in dwords) of message pending from MTX */ +int vxd_pvdec_pend_msg_info(const void *dev, void __iomem *reg_base, + unsigned long *size, + unsigned short *msg_id, + unsigned char *not_last_msg) +{ + int ret, to_host_off; /* offset in dwords */ + unsigned int wr_idx, rd_idx; /* indicies in dwords */ + unsigned long to_host_size; /* size in dwords */ + unsigned int val = 0; + + ret = pvdec_get_to_host_cfg(reg_base, &to_host_size, &to_host_off, &wr_idx, &rd_idx); + if (ret) { + dev_err(dev, "%s: failed to obtain host ring buffer config!\n", __func__); + return ret; + } + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: to host: (%zu @ %d), wr: %u, rd: %u\n", __func__, + to_host_size, to_host_off, wr_idx, rd_idx); +#endif + + if (wr_idx == rd_idx) { + *size = 0; + *msg_id = 0; + return 0; + } + + ret = pvdec_read_vlr(reg_base, &val, 1, to_host_off + rd_idx); + if (ret) { + dev_err(dev, "%s: failed to read first word!\n", __func__); + return ret; + } + + *size = VXD_RD_REG_FIELD(val, PVDEC_FW, DEVA_GENMSG, MSG_SIZE); + *msg_id = VXD_RD_REG_FIELD(val, PVDEC_FW, DEVA_GENMSG, MSG_ID); + *not_last_msg = VXD_RD_REG_FIELD(val, PVDEC_FW, DEVA_GENMSG, NOT_LAST_MSG); + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: [msg in] rd_idx: %d, size: %zu, id: 0x%04x, type: 0x%x\n", + __func__, rd_idx, *size, *msg_id, + VXD_RD_REG_FIELD(val, PVDEC_FW, DEVA_GENMSG, MSG_TYPE)); +#endif + + return 0; +} + +/* + * Receive message from the MTX and place it in a dwords long + * buffer. If the provided buffer is too small to hold the message, only part + * of it will be placed in a buffer, but the ring buffer read index will be + * moved so that message is no longer available. + */ +int vxd_pvdec_recv_msg(const void *dev, void __iomem *reg_base, + unsigned int *buf, + unsigned long buf_size, + struct vxd_dev *vxd) +{ + int ret, to_host_off; /* offset in dwords */ + unsigned int wr_idx, rd_idx; /* indicies in dwords */ + unsigned long to_host_size, msg_size, to_read; /* sizes in dwords */ + unsigned int val = 0; + struct timespec64 time; + unsigned short msg_id; + int loop; + + ret = pvdec_get_to_host_cfg(reg_base, &to_host_size, + &to_host_off, &wr_idx, &rd_idx); + if (ret) { + dev_err(dev, "%s: failed to obtain host ring buffer config!\n", __func__); + return ret; + } + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: to host: (%zu @ %d), wr: %u, rd: %u\n", __func__, + to_host_size, to_host_off, wr_idx, rd_idx); +#endif + + /* Obtain the message size */ + ret = pvdec_read_vlr(reg_base, &val, 1, to_host_off + rd_idx); + if (ret) { + dev_err(dev, "%s: failed to read first word!\n", __func__); + return ret; + } + msg_size = VXD_RD_REG_FIELD(val, PVDEC_FW, DEVA_GENMSG, MSG_SIZE); + + to_read = (msg_size > buf_size) ? buf_size : msg_size; + + /* Does the message wrap? */ + if (to_read + rd_idx > to_host_size) { + unsigned long chunk_size = to_host_size - rd_idx; + + ret = pvdec_read_vlr(reg_base, buf, chunk_size, to_host_off + rd_idx); + if (ret) { + dev_err(dev, "%s: failed to read chunk before wrap!\n", __func__); + return ret; + } + to_read -= chunk_size; + buf += chunk_size; + rd_idx = 0; + msg_size -= chunk_size; + } + + /* + * If the message wrapped, read the second chunk. + * If it didn't, read first and only chunk + */ + ret = pvdec_read_vlr(reg_base, buf, to_read, to_host_off + rd_idx); + if (ret) { + dev_err(dev, "%s: failed to read message from vlr!\n", __func__); + return ret; + } + + /* Update read index in the ring buffer */ + rd_idx = (rd_idx + msg_size) % to_host_size; + VXD_WR_REG_ABS(reg_base, VLR_OFFSET + + PVDEC_FW_TO_HOST_RD_IDX_OFFSET, rd_idx); + + msg_id = VXD_RD_REG_FIELD(val, PVDEC_FW, DEVA_GENMSG, MSG_ID); + + ktime_get_real_ts64(&time); + for (loop = 0; loop < ARRAY_SIZE(vxd->time_fw); loop++) { + if (vxd->time_fw[loop].id == msg_id) { + vxd->time_fw[loop].end_time = + timespec64_to_ns((const struct timespec64 *)&time); +#ifdef DEBUG_DECODER_DRIVER + dev_info(dev, "fw decode time is %llu us for msg_id x%0x\n", + div_s64(vxd->time_fw[loop].end_time - + vxd->time_fw[loop].start_time, 1000), msg_id); +#endif + break; + } + } + + if (loop == ARRAY_SIZE(vxd->time_fw)) + dev_err(dev, "fw decode time for msg_id x%0x is not measured\n", msg_id); + + return 0; +} + +int vxd_pvdec_check_fw_status(const void *dev, void __iomem *reg_base) +{ + int ret; + unsigned int val = 0; + + /* Obtain current fw status */ + ret = pvdec_read_vlr(reg_base, &val, 1, PVDEC_FW_STATUS_OFFSET); + if (ret) { + dev_err(dev, "%s: failed to read fw status!\n", __func__); + return ret; + } + + /* Check for fatal condition */ + if (val == PVDEC_FW_STATUS_PANIC || val == PVDEC_FW_STATUS_ASSERT || + val == PVDEC_FW_STATUS_SO) + return -1; + + return 0; +} + +static int pvdec_send_init_msg(const void *dev, + void __iomem *reg_base, + struct vxd_ena_params *ena_params) +{ + unsigned short msg_id = 0; + unsigned int msg[PVDEC_FW_DEVA_INIT_MSG_WRDS] = { 0 }, msg_wrd = 0; + struct vxd_dev *vxd; + int ret; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: rendec: %d@0x%x, crc: 0x%x\n", __func__, + ena_params->rendec_size, ena_params->rendec_addr, ena_params->crc); +#endif + + vxd = kzalloc(sizeof(*vxd), GFP_KERNEL); + if (!vxd) + return -1; + + /* message type */ + msg_wrd = VXD_WR_REG_FIELD(msg_wrd, PVDEC_FW, DEVA_GENMSG, MSG_TYPE, + PVDEC_FW_MSG_TYPE_INIT); + VXD_WR_MSG_WRD(msg, PVDEC_FW, DEVA_GENMSG, msg_wrd); + + /* rendec address */ + VXD_WR_MSG_WRD(msg, PVDEC_FW_DEVA_INIT, RENDEC_ADDR0, ena_params->rendec_addr); + + /* rendec size */ + msg_wrd = 0; + msg_wrd = VXD_WR_REG_FIELD(msg_wrd, PVDEC_FW, DEVA_INIT, RENDEC_SIZE0, + ena_params->rendec_size); + VXD_WR_MSG_WRD(msg, PVDEC_FW_DEVA_INIT, RENDEC_SIZE0, msg_wrd); + + /* HEVC configuration */ + msg_wrd = 0; + msg_wrd = VXD_WR_REG_FIELD(msg_wrd, PVDEC_FW, DEVA_INIT, + HEVC_CFG_MAX_H_FOR_PIPE_WAIT, 0xFFFF); + VXD_WR_MSG_WRD(msg, PVDEC_FW_DEVA_INIT, HEVC_CFG, msg_wrd); + + /* signature select */ + VXD_WR_MSG_WRD(msg, PVDEC_FW_DEVA_INIT, SIG_SELECT, ena_params->crc); + + /* partial frame notification timer divider */ + msg_wrd = 0; + msg_wrd = VXD_WR_REG_FIELD(msg_wrd, PVDEC_FW, DEVA_INIT, PFNT_DIV, PVDEC_PFNT_DIV); + VXD_WR_MSG_WRD(msg, PVDEC_FW_DEVA_INIT, PFNT_DIV, msg_wrd); + + /* firmware watchdog timeout value */ + msg_wrd = VXD_WR_REG_FIELD(msg_wrd, PVDEC_FW, DEVA_INIT, FWWDT_MS, ena_params->fwwdt_ms); + VXD_WR_MSG_WRD(msg, PVDEC_FW_DEVA_INIT, FWWDT_MS, msg_wrd); + + ret = vxd_pvdec_send_msg(dev, reg_base, msg, ARRAY_SIZE(msg), msg_id, vxd); + kfree(vxd); + + return ret; +} + +int vxd_pvdec_ena(const void *dev, void __iomem *reg_base, + struct vxd_ena_params *ena_params, + struct vxd_fw_hdr *fw_hdr, + unsigned int *freq_khz) +{ + int ret; + unsigned int mtx_ram_size = 0; + unsigned char dma_channel = 0; + + ret = vxd_pvdec_init(dev, reg_base); + if (ret) { + dev_err(dev, "%s: PVDEC init failed!\n", __func__); + return ret; + } + + ret = pvdec_get_mtx_ram_size(reg_base, &mtx_ram_size); + if (ret) { + dev_err(dev, "%s: failed to get MTX RAM size!\n", __func__); + return ret; + } + + if (mtx_ram_size < fw_hdr->core_size) { + dev_err(dev, "%s: FW larger than MTX RAM size (%u < %d)!\n", + __func__, mtx_ram_size, fw_hdr->core_size); + return -EINVAL; + } + + /* Apply pre boot settings - if any */ + pvdec_pre_boot_setup(dev, reg_base, ena_params); + + pvdec_prep_fw_upload(dev, reg_base, ena_params, dma_channel); + + ret = pvdec_start_fw_dma(dev, reg_base, dma_channel, fw_hdr->core_size, freq_khz); + + if (ret) { + dev_err(dev, "%s: failed to load FW! (%d)", __func__, ret); + pvdec_mtx_status_dump(reg_base, NULL); + return ret; + } + + /* Apply final settings - if any */ + pvdec_post_boot_setup(dev, reg_base, *freq_khz); + + ret = pvdec_poll_fw_boot(reg_base, &ena_params->boot_poll); + if (ret) { + dev_err(dev, "%s: FW failed to boot! (%d)!\n", __func__, ret); + return ret; + } + + ret = pvdec_send_init_msg(dev, reg_base, ena_params); + if (ret) { + dev_err(dev, "%s: failed to send init message! (%d)!\n", __func__, ret); + return ret; + } + + return 0; +} + +int vxd_pvdec_dis(const void *dev, void __iomem *reg_base) +{ + int ret = pvdec_enable_clocks(reg_base); + + if (ret) { + dev_err(dev, "%s: failed to enable clocks! (%d)\n", __func__, ret); + return ret; + } + + ret = pvdec_reset(reg_base, TRUE); + if (ret) { + dev_err(dev, "%s: VXD reset failed! (%d)\n", __func__, ret); + return ret; + } + + ret = pvdec_disable_clocks(reg_base); + if (ret) { + dev_err(dev, "%s: VXD disable clocks failed! (%d)\n", __func__, ret); + return ret; + } + + return 0; +} + +/* + * Invalidate VXD's MMU cache. + */ +int vxd_pvdec_mmu_flush(const void *dev, void __iomem *reg_base) +{ + unsigned int reg = VXD_RD_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1); + + if (reg == PVDEC_INVALID_HW_STATE) { + dev_err(dev, "%s: invalid HW state!\n", __func__); + return -EIO; + } + + reg = VXD_WR_REG_FIELD(reg, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, MMU_INVALDC, 0xF); + VXD_WR_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_CONTROL1, reg); + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: device MMU cache invalidated!\n", __func__); +#endif + + return 0; +} + +irqreturn_t vxd_pvdec_clear_int(void __iomem *reg_base, unsigned int *irq_status) +{ + irqreturn_t ret = IRQ_NONE; + unsigned int enabled; + unsigned int status = VXD_RD_REG(reg_base, PVDEC_CORE, PVDEC_INT_STAT); + + enabled = VXD_RD_REG(reg_base, PVDEC_CORE, PVDEC_HOST_INT_ENA); + + status &= enabled; + /* Store the last irq status */ + *irq_status |= status; + + if (status & (PVDEC_CORE_PVDEC_INT_STAT_HOST_MMU_FAULT_IRQ_MASK | + PVDEC_CORE_PVDEC_INT_STAT_HOST_PROC_IRQ_MASK)) + ret = IRQ_WAKE_THREAD; + + /* Disable MMU interrupts - clearing is not enough */ + if (status & PVDEC_CORE_PVDEC_INT_STAT_HOST_MMU_FAULT_IRQ_MASK) { + enabled &= ~PVDEC_CORE_PVDEC_INT_STAT_HOST_MMU_FAULT_IRQ_MASK; + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_HOST_INT_ENA, enabled); + } + + VXD_WR_REG(reg_base, PVDEC_CORE, PVDEC_INT_CLEAR, status); + + return ret; +} + +/* + * Check if there's enough space in comms RAM to submit dwords long + * message. This function also submits a padding message if it will be + * necessary for this particular message. + * + * return 0 if there is enough space, + * return -EBUSY if there is not enough space, + * return another fault code in case of an error. + */ +int vxd_pvdec_msg_fit(const void *dev, void __iomem *reg_base, unsigned long msg_size) +{ + int ret = pvdec_check_comms_space(reg_base, msg_size, TRUE); + + /* + * In specific environment, when to_mtx buffer is small, and messages + * the userspace is submitting are large (e.g. FWBSP flow), it's + * possible that firmware will consume the padding message sent by + * vxd_pvdec_msg_fit() immediately. Retry the check. + */ + if (ret == -EBUSY) { + unsigned int flags = VXD_RD_REG_ABS(reg_base, + VLR_OFFSET + PVDEC_FW_FLAGS_OFFSET) | + PVDEC_FWFLAG_FAKE_COMPLETION; + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "comms space full, asking fw to send empty msg when space is available"); +#endif + + VXD_WR_REG_ABS(reg_base, VLR_OFFSET + PVDEC_FW_FLAGS_OFFSET, flags); + ret = pvdec_check_comms_space(reg_base, msg_size, FALSE); + } + + return ret; +} + +void vxd_pvdec_get_state(const void *dev, void __iomem *reg_base, + unsigned int num_pipes, + struct vxd_hw_state *state) +{ + unsigned char pipe; +#ifdef DEBUG_DECODER_DRIVER + unsigned int state_cfg = VXD_RD_REG_ABS(reg_base, (VLR_OFFSET + + PVDEC_FW_STATE_BUF_CFG_OFFSET)); + + unsigned short state_size = PVDEC_FW_COM_BUF_SIZE(state_cfg); + unsigned short state_off = PVDEC_FW_COM_BUF_OFF(state_cfg); + + /* + * The generic fw progress counter + * is the first element in the fw state + */ + dev_dbg(dev, "%s: state off: 0x%x, size: 0x%x\n", __func__, state_off, state_size); + state->fw_counter = VXD_RD_REG_ABS(reg_base, (VLR_OFFSET + state_off)); + dev_dbg(dev, "%s: fw_counter: 0x%x\n", __func__, state->fw_counter); +#endif + + /* We just combine the macroblocks being processed by the HW */ + for (pipe = 0; pipe < num_pipes; pipe++) { + unsigned int p_off = VXD_GET_PIPE_OFF(num_pipes, pipe + 1); + unsigned int reg_val; + + /* Front-end */ + unsigned int reg_off = VXD_GET_REG_OFF(PVDEC_ENTROPY, ENTROPY_LAST_MB); + + state->fe_status[pipe] = VXD_RD_REG_ABS(reg_base, reg_off + p_off); + + reg_off = VXD_GET_REG_OFF(MSVDX_VEC, VEC_ENTDEC_INFORMATION); + state->fe_status[pipe] |= VXD_RD_REG_ABS(reg_base, reg_off + p_off); + + /* Back-end */ + reg_off = VXD_GET_REG_OFF(PVDEC_VEC_BE, VEC_BE_STATUS); + state->be_status[pipe] = VXD_RD_REG_ABS(reg_base, reg_off + p_off); + reg_off = VXD_GET_REG_OFF(MSVDX_VDMC, VDMC_MACROBLOCK_NUMBER); + state->be_status[pipe] |= VXD_RD_REG_ABS(reg_base, reg_off + p_off); + + /* + * Take DMAC channels 2/3 into consideration to cover + * parser progress on SR1/2 + */ + reg_off = VXD_GET_RPT_REG_OFF(DMAC, DMAC_COUNT, 2); + reg_val = VXD_RD_REG_ABS(reg_base, reg_off + p_off); + state->dmac_status[pipe][0] = VXD_RD_REG_FIELD(reg_val, DMAC, DMAC_COUNT, CNT); + reg_off = VXD_GET_RPT_REG_OFF(DMAC, DMAC_COUNT, 3); + reg_val = VXD_RD_REG_ABS(reg_base, reg_off + p_off); + state->dmac_status[pipe][1] = VXD_RD_REG_FIELD(reg_val, DMAC, DMAC_COUNT, CNT); + } +} + +/* + * Check for the source of the last interrupt. + * + * return 0 if nothing serious happened, + * return -EFAULT if there was a critical interrupt detected. + */ +int vxd_pvdec_check_irq(const void *dev, void __iomem *reg_base, unsigned int irq_status) +{ + if (irq_status & PVDEC_CORE_PVDEC_INT_STAT_HOST_MMU_FAULT_IRQ_MASK) { + unsigned int status0 = + VXD_RD_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_STATUS0); + unsigned int status1 = + VXD_RD_REG(reg_base, IMG_VIDEO_BUS4_MMU, MMU_STATUS1); + + unsigned int addr = VXD_RD_REG_FIELD(status0, IMG_VIDEO_BUS4_MMU, + MMU_STATUS0, MMU_FAULT_ADDR) << 12; + unsigned char reason = VXD_RD_REG_FIELD(status0, IMG_VIDEO_BUS4_MMU, + MMU_STATUS0, MMU_PF_N_RW); + unsigned char requestor = VXD_RD_REG_FIELD(status1, IMG_VIDEO_BUS4_MMU, + MMU_STATUS1, MMU_FAULT_REQ_ID); + unsigned char type = VXD_RD_REG_FIELD(status1, IMG_VIDEO_BUS4_MMU, + MMU_STATUS1, MMU_FAULT_RNW); + unsigned char secure = VXD_RD_REG_FIELD(status0, IMG_VIDEO_BUS4_MMU, + MMU_STATUS0, MMU_SECURE_FAULT); + +#ifdef DEBUG_DECODER_DRIVER + dev_dbg(dev, "%s: MMU Page Fault s0:%08x s1:%08x", __func__, status0, status1); +#endif + + dev_err(dev, "%s: MMU %s fault from %s while %s @ 0x%08X", __func__, + (reason) ? "Page" : "Protection", + (requestor & (0x1)) ? "dmac" : + (requestor & (0x2)) ? "vec" : + (requestor & (0x4)) ? "vdmc" : + (requestor & (0x8)) ? "vdeb" : "unknown source", + (type) ? "reading" : "writing", addr); + + if (secure) + dev_err(dev, "%s: MMU security policy violation detected!", __func__); + + return -EFAULT; + } + + return 0; +} + +/* + * This functions enables the clocks, fetches the core properties, stores them + * in the structure and DISABLES the clocks. Do not call when hardware + * is busy! + */ +int vxd_pvdec_get_props(const void *dev, void __iomem *reg_base, struct vxd_core_props *props) +{ +#ifdef DEBUG_DECODER_DRIVER + unsigned char num_pix_pipes, pipe; +#endif + int ret = pvdec_enable_clocks(reg_base); + + if (ret) { + dev_err(dev, "%s: failed to enable clocks!\n", __func__); + return ret; + } + + ret = pvdec_get_mtx_ram_size(reg_base, &props->mtx_ram_size); + if (ret) { + dev_err(dev, "%s: failed to get MTX ram size!\n", __func__); + return ret; + } + + ret = pvdec_get_properties(reg_base, props); + if (ret) { + dev_err(dev, "%s: failed to get VXD props!\n", __func__); + return ret; + } + + if (pvdec_disable_clocks(reg_base)) + dev_err(dev, "%s: failed to disable clocks!\n", __func__); + +#ifdef DEBUG_DECODER_DRIVER + num_pix_pipes = VXD_NUM_PIX_PIPES(*props); + + /* Warning already raised in pvdec_get_properties() */ + if (unlikely(num_pix_pipes > VXD_MAX_PIPES)) + num_pix_pipes = VXD_MAX_PIPES; + dev_dbg(dev, "%s: core_rev: 0x%08x\n", __func__, props->core_rev); + dev_dbg(dev, "%s: pvdec_core_id: 0x%08x\n", __func__, props->pvdec_core_id); + dev_dbg(dev, "%s: mmu_config0: 0x%08x\n", __func__, props->mmu_config0); + dev_dbg(dev, "%s: mmu_config1: 0x%08x\n", __func__, props->mmu_config1); + dev_dbg(dev, "%s: mtx_ram_size: %u\n", __func__, props->mtx_ram_size); + dev_dbg(dev, "%s: pix max frame: 0x%08x\n", __func__, props->pixel_max_frame_cfg); + + for (pipe = 1; pipe <= num_pix_pipes; ++pipe) + dev_dbg(dev, "%s: pipe %u, 0x%08x, misc 0x%08x\n", + __func__, pipe, props->pixel_pipe_cfg[pipe - 1], + props->pixel_misc_cfg[pipe - 1]); + dev_dbg(dev, "%s: dbg fifo size: %u\n", __func__, props->dbg_fifo_size); +#endif + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_pvdec_priv.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_pvdec_priv.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_pvdec_priv.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_pvdec_priv.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD PVDEC Private header file + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Amit Makani + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#ifndef _VXD_PVDEC_PRIV_H +#define _VXD_PVDEC_PRIV_H +#include + +#include "img_dec_common.h" +#include "vxd_pvdec_regs.h" +#include "vxd_dec.h" + +#ifdef ERROR_RECOVERY_SIMULATION +/* kernel object used to debug. Declared in v4l2_int.c */ +extern struct kobject *vxd_dec_kobject; +extern int disable_fw_irq_value; +extern int g_module_irq; +#endif + +struct vxd_boot_poll_params { + unsigned int msleep_cycles; +}; + +struct vxd_ena_params { + struct vxd_boot_poll_params boot_poll; + + unsigned long fw_buf_size; + unsigned int fw_buf_virt_addr; + /* + * VXD's MMU virtual address of a firmware + * buffer. + */ + unsigned int ptd; /* Shifted physical address of PTD */ + + /* Required for firmware upload via registers. */ + struct { + const unsigned char *buf; /* Firmware blob buffer */ + + } regs_data; + + struct { + unsigned secure : 1; /* Secure flow indicator. */ + unsigned wait_dbg_fifo : 1; /* + * Indicates that fw shall use + * blocking mode when putting logs + * into debug fifo + */ + }; + + /* Structure containing memory staller configuration */ + struct { + unsigned int *data; /* Configuration data array */ + unsigned char size; /* Configuration size in dwords */ + + } mem_staller; + + unsigned int fwwdt_ms; /* Firmware software watchdog timeout value */ + + unsigned int crc; /* HW signatures to be enabled by firmware */ + unsigned int rendec_addr; /* VXD's virtual address of a rendec buffer */ + unsigned short rendec_size; /* Size of a rendec buffer in 4K pages */ +}; + +int vxd_pvdec_init(const void *dev, void __iomem *reg_base); + +int vxd_pvdec_ena(const void *dev, void __iomem *reg_base, + struct vxd_ena_params *ena_params, struct vxd_fw_hdr *hdr, + unsigned int *freq_khz); + +int vxd_pvdec_dis(const void *dev, void __iomem *reg_base); + +int vxd_pvdec_mmu_flush(const void *dev, void __iomem *reg_base); + +int vxd_pvdec_send_msg(const void *dev, void __iomem *reg_base, + unsigned int *msg, unsigned long msg_size, unsigned short msg_id, + struct vxd_dev *ctx); + +int vxd_pvdec_pend_msg_info(const void *dev, void __iomem *reg_base, + unsigned long *size, unsigned short *msg_id, + unsigned char *not_last_msg); + +int vxd_pvdec_recv_msg(const void *dev, void __iomem *reg_base, + unsigned int *buf, unsigned long buf_size, struct vxd_dev *ctx); + +int vxd_pvdec_check_fw_status(const void *dev, void __iomem *reg_base); + +unsigned long vxd_pvdec_peek_mtx_fifo(const void *dev, + void __iomem *reg_base); + +unsigned long vxd_pvdec_read_mtx_fifo(const void *dev, void __iomem *reg_base, + unsigned int *buf, unsigned long size); + +irqreturn_t vxd_pvdec_clear_int(void __iomem *reg_base, unsigned int *irq_status); + +int vxd_pvdec_check_irq(const void *dev, void __iomem *reg_base, + unsigned int irq_status); + +int vxd_pvdec_msg_fit(const void *dev, void __iomem *reg_base, + unsigned long msg_size); + +void vxd_pvdec_get_state(const void *dev, void __iomem *reg_base, + unsigned int num_pipes, struct vxd_hw_state *state); + +int vxd_pvdec_get_props(const void *dev, void __iomem *reg_base, + struct vxd_core_props *props); + +unsigned long vxd_pvdec_get_dbg_fifo_size(void __iomem *reg_base); + +int vxd_pvdec_dump_mtx_ram(const void *dev, void __iomem *reg_base, + unsigned int addr, unsigned int count, unsigned int *buf); + +int vxd_pvdec_dump_mtx_status(const void *dev, void __iomem *reg_base, + unsigned int *array, unsigned int array_size); + +#endif /* _VXD_PVDEC_PRIV_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_pvdec_regs.h b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_pvdec_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_pvdec_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_pvdec_regs.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,779 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VXD PVDEC registers header file + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * + * Re-written for upstreamimg + * Sidraya Jayagond + * Prashanth Kumar Amai + */ + +#ifndef VXD_PVDEC_REGS_H +#define VXD_PVDEC_REGS_H + +/* ************************* VXD-specific values *************************** */ +/* 0x10 for code, 0x18 for data. */ +#define PVDEC_MTX_CORE_MEM 0x18 +/* Iteration time out counter for MTX I/0. */ +#define PVDEC_TIMEOUT_COUNTER 1000 +/* Partial frame notification timer divider. */ +#define PVDEC_PFNT_DIV 0 +/* Value returned by register reads when HW enters invalid state (FPGA) */ +#define PVDEC_INVALID_HW_STATE 0x000dead1 + +/* Default core clock for pvdec */ +#define PVDEC_CLK_MHZ_DEFAULT 200 + +/* Offsets of registers groups within VXD. */ +#define PVDEC_PROC_OFFSET 0x0000 +/* 0x34c: Skip DMA registers when running against CSIM (vritual platform) */ +#define PVDEC_PROC_SIZE 0x34C /* 0x3FF */ + +#define PVDEC_CORE_OFFSET 0x0400 +#define PVDEC_CORE_SIZE 0x3FF + +#define MTX_CORE_OFFSET PVDEC_PROC_OFFSET +#define MTX_CORE_SIZE PVDEC_PROC_SIZE + +#define VIDEO_BUS4_MMU_OFFSET 0x1000 +#define VIDEO_BUS4_MMU_SIZE 0x1FF + +#define IMG_VIDEO_BUS4_MMU_OFFSET VIDEO_BUS4_MMU_OFFSET +#define IMG_VIDEO_BUS4_MMU_SIZE VIDEO_BUS4_MMU_SIZE + +#define VLR_OFFSET 0x2000 +#define VLR_SIZE 0x1000 + +/* PVDEC_ENTROPY defined in uapi/vxd_pvdec.h */ + +#define PVDEC_PIXEL_OFFSET 0x4000 +#define PVDEC_PIXEL_SIZE 0x1FF + +/* PVDEC_VEC_BE defined in uapi/vxd_pvdec.h */ + +/* MSVDX_VEC defined in uapi/vxd_pvdec.h */ + +#define MSVDX_VDMC_OFFSET 0x6800 +#define MSVDX_VDMC_SIZE 0x7F + +#define DMAC_OFFSET 0x6A00 +#define DMAC_SIZE 0x1FF + +#define PVDEC_TEST_OFFSET 0xFF00 +#define PVDEC_TEST_SIZE 0xFF + +/* *********************** firmware specific values ************************* */ + +/* layout of COMMS RAM */ + +#define PVDEC_FW_COMMS_HDR_SIZE 0x38 + +#define PVDEC_FW_STATUS_OFFSET 0x00 +#define PVDEC_FW_TASK_STATUS_OFFSET 0x04 +#define PVDEC_FW_ID_OFFSET 0x08 +#define PVDEC_FW_MTXPC_OFFSET 0x0c +#define PVDEC_FW_MSG_COUNTER_OFFSET 0x10 +#define PVDEC_FW_SIGNATURE_OFFSET 0x14 +#define PVDEC_FW_TO_HOST_BUF_CONF_OFFSET 0x18 +#define PVDEC_FW_TO_HOST_RD_IDX_OFFSET 0x1c +#define PVDEC_FW_TO_HOST_WR_IDX_OFFSET 0x20 +#define PVDEC_FW_TO_MTX_BUF_CONF_OFFSET 0x24 +#define PVDEC_FW_TO_MTX_RD_IDX_OFFSET 0x28 +#define PVDEC_FW_FLAGS_OFFSET 0x2c +#define PVDEC_FW_TO_MTX_WR_IDX_OFFSET 0x30 +#define PVDEC_FW_STATE_BUF_CFG_OFFSET 0x34 + +/* firmware status */ + +#define PVDEC_FW_STATUS_PANIC 0x2 +#define PVDEC_FW_STATUS_ASSERT 0x3 +#define PVDEC_FW_STATUS_SO 0x8 + +/* firmware flags */ + +#define PVDEC_FWFLAG_BIG_TO_HOST_BUFFER 0x00000002 +#define PVDEC_FWFLAG_FORCE_FS_FLOW 0x00000004 +#define PVDEC_FWFLAG_DISABLE_WATCHDOGS 0x00000008 +#define PVDEC_FWFLAG_DISABLE_AUTONOMOUS_RESET 0x00000040 +#define PVDEC_FWFLAG_DISABLE_IDLE_GPIO 0x00002000 +#define PVDEC_FWFLAG_ENABLE_ERROR_CONCEALMENT 0x00100000 +#define PVDEC_FWFLAG_DISABLE_GENC_FLUSHING 0x00800000 +#define PVDEC_FWFLAG_FAKE_COMPLETION 0x20000000 +#define PVDEC_FWFLAG_DISABLE_COREWDT_TIMERS 0x01000000 + +/* firmware message header */ + +#define PVDEC_FW_DEVA_GENMSG_OFFSET 0 + +#define PVDEC_FW_DEVA_GENMSG_MSG_ID_MASK 0xFFFF0000 +#define PVDEC_FW_DEVA_GENMSG_MSG_ID_SHIFT 16 + +#define PVDEC_FW_DEVA_GENMSG_MSG_TYPE_MASK 0xFF00 +#define PVDEC_FW_DEVA_GENMSG_MSG_TYPE_SHIFT 8 + +#define PVDEC_FW_DEVA_GENMSG_NOT_LAST_MSG_MASK 0x80 +#define PVDEC_FW_DEVA_GENMSG_NOT_LAST_MSG_SHIFT 7 + +#define PVDEC_FW_DEVA_GENMSG_MSG_SIZE_MASK 0x7F +#define PVDEC_FW_DEVA_GENMSG_MSG_SIZE_SHIFT 0 + +/* firmware init message */ + +#define PVDEC_FW_DEVA_INIT_MSG_WRDS 9 + +#define PVDEC_FW_DEVA_INIT_RENDEC_ADDR0_OFFSET 0xC + +#define PVDEC_FW_DEVA_INIT_RENDEC_SIZE0_OFFSET 0x10 +#define PVDEC_FW_DEVA_INIT_RENDEC_SIZE0_MASK 0xFFFF +#define PVDEC_FW_DEVA_INIT_RENDEC_SIZE0_SHIFT 0 + +#define PVDEC_FW_DEVA_INIT_HEVC_CFG_OFFSET 0x14 +#define PVDEC_FW_DEVA_INIT_HEVC_CFG_MAX_H_FOR_PIPE_WAIT_MASK 0xFFFF0000 +#define PVDEC_FW_DEVA_INIT_HEVC_CFG_MAX_H_FOR_PIPE_WAIT_SHIFT 16 +#define PVDEC_FW_DEVA_INIT_HEVC_CFG_MIN_H_FOR_DUAL_PIPE_MASK 0xFFFF +#define PVDEC_FW_DEVA_INIT_HEVC_CFG_MIN_H_FOR_DUAL_PIPE_SHIFT 0 + +#define PVDEC_FW_DEVA_INIT_SIG_SELECT_OFFSET 0x18 + +#define PVDEC_FW_DEVA_INIT_DBG_DELAYS_OFFSET 0x1C + +#define PVDEC_FW_DEVA_INIT_PFNT_DIV_OFFSET 0x20 +#define PVDEC_FW_DEVA_INIT_PFNT_DIV_MASK 0xFFFF0000 +#define PVDEC_FW_DEVA_INIT_PFNT_DIV_SHIFT 16 + +#define PVDEC_FW_DEVA_INIT_FWWDT_MS_OFFSET 0x20 +#define PVDEC_FW_DEVA_INIT_FWWDT_MS_MASK 0xFFFF +#define PVDEC_FW_DEVA_INIT_FWWDT_MS_SHIFT 0 + +/* firmware message types */ +#define PVDEC_FW_MSG_TYPE_PADDING 0 +#define PVDEC_FW_MSG_TYPE_INIT 0x80 + +/* miscellaneous */ + +#define PVDEC_FW_READY_SIG 0xa5a5a5a5 + +#define PVDEC_FW_COM_BUF_SIZE(cfg) ((cfg) & 0x0000ffff) +#define PVDEC_FW_COM_BUF_OFF(cfg) (((cfg) & 0xffff0000) >> 16) + +/* + * Timer divider calculation macro. + * NOTE: The Timer divider is only 8bit field + * so we set it for 2MHz timer base to cover wider + * range of core frequencies on real platforms (freq > 255MHz) + */ +#define PVDEC_CALC_TIMER_DIV(val) (((val) - 1) / 2) + +#define MTX_CORE_STATUS_ELEMENTS 4 + +#define PVDEC_CORE_MEMSTALLER_ELEMENTS 7 + +/* ********************** PVDEC_CORE registers group ************************ */ + +/* register PVDEC_SOFT_RESET */ +#define PVDEC_CORE_PVDEC_SOFT_RST_OFFSET 0x0000 + +#define PVDEC_CORE_PVDEC_SOFT_RST_PVDEC_PIXEL_PROC_SOFT_RST_MASK 0xFF000000 +#define PVDEC_CORE_PVDEC_SOFT_RST_PVDEC_PIXEL_PROC_SOFT_RST_SHIFT 24 + +#define PVDEC_CORE_PVDEC_SOFT_RST_PVDEC_ENTROPY_SOFT_RST_MASK 0x00FF0000 +#define PVDEC_CORE_PVDEC_SOFT_RST_PVDEC_ENTROPY_SOFT_RST_SHIFT 16 + +#define PVDEC_CORE_PVDEC_SOFT_RST_PVDEC_MMU_SOFT_RST_MASK 0x00000002 +#define PVDEC_CORE_PVDEC_SOFT_RST_PVDEC_MMU_SOFT_RST_SHIFT 1 + +#define PVDEC_CORE_PVDEC_SOFT_RST_PVDEC_SOFT_RST_MASK 0x00000001 +#define PVDEC_CORE_PVDEC_SOFT_RST_PVDEC_SOFT_RST_SHIFT 0 + +/* register PVDEC_HOST_INTERRUPT_STATUS */ +#define PVDEC_CORE_PVDEC_INT_STAT_OFFSET 0x0010 + +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_SYS_WDT_MASK 0x10000000 +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_SYS_WDT_SHIFT 28 + +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_READ_TIMEOUT_PROC_IRQ_MASK 0x08000000 +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_READ_TIMEOUT_PROC_IRQ_SHIFT 27 + +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_COMMAND_TIMEOUT_PROC_IRQ_MASK 0x04000000 +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_COMMAND_TIMEOUT_PROC_IRQ_SHIFT 26 + +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_READ_TIMEOUT_HOST_IRQ_MASK 0x02000000 +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_READ_TIMEOUT_HOST_IRQ_SHIFT 25 + +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_COMMAND_TIMEOUT_HOST_IRQ_MASK 0x01000000 +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_COMMAND_TIMEOUT_HOST_IRQ_SHIFT 24 + +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_PROC_GPIO_IRQ_MASK 0x00200000 +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_PROC_GPIO_IRQ_SHIFT 21 + +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_PROC_IRQ_MASK 0x00100000 +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_PROC_IRQ_SHIFT 20 + +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_MMU_FAULT_IRQ_MASK 0x00010000 +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_MMU_FAULT_IRQ_SHIFT 16 + +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_PIXEL_PROCESSING_IRQ_MASK 0x0000FF00 +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_PIXEL_PROCESSING_IRQ_SHIFT 8 + +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_ENTROPY_PIPE_IRQ_MASK 0x000000FF +#define PVDEC_CORE_PVDEC_INT_STAT_HOST_ENTROPY_PIPE_IRQ_SHIFT 0 + +/* register PVDEC_INTERRUPT_CLEAR */ +#define PVDEC_CORE_PVDEC_INT_CLEAR_OFFSET 0x0014 + +#define PVDEC_CORE_PVDEC_INT_CLEAR_IRQ_CLEAR_MASK 0xFFFF0000 +#define PVDEC_CORE_PVDEC_INT_CLEAR_IRQ_CLEAR_SHIFT 16 + +/* register PVDEC_HOST_INTERRUPT_ENABLE */ +#define PVDEC_CORE_PVDEC_HOST_INT_ENA_OFFSET 0x0018 + +#define PVDEC_CORE_PVDEC_HOST_INT_ENA_HOST_IRQ_ENABLE_MASK 0xFFFF0000 +#define PVDEC_CORE_PVDEC_HOST_INT_ENA_HOST_IRQ_ENABLE_SHIFT 16 + +/* Register PVDEC_MAN_CLK_ENABLE */ +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_OFFSET 0x0040 + +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_PIXEL_PROC_MAN_CLK_ENA_MASK 0xFF000000 +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_PIXEL_PROC_MAN_CLK_ENA_SHIFT 24 + +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_ENTROPY_PIPE_MAN_CLK_ENA_MASK 0x00FF0000 +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_ENTROPY_PIPE_MAN_CLK_ENA_SHIFT 16 + +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_MEM_MAN_CLK_ENA_MASK 0x00000100 +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_MEM_MAN_CLK_ENA_SHIFT 8 + +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_PVDEC_REG_MAN_CLK_ENA_MASK 0x00000010 +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_PVDEC_REG_MAN_CLK_ENA_SHIFT 4 + +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_PROC_MAN_CLK_ENA_MASK 0x00000002 +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_PROC_MAN_CLK_ENA_SHIFT 1 + +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_CORE_MAN_CLK_ENA_MASK 0x00000001 +#define PVDEC_CORE_PVDEC_MAN_CLK_ENA_CORE_MAN_CLK_ENA_SHIFT 0 + +/* register PVDEC_HOST_PIPE_SELECT */ +#define PVDEC_CORE_PVDEC_HOST_PIPE_SELECT_OFFSET 0x0060 + +#define PVDEC_CORE_PVDEC_HOST_PIPE_SELECT_PIPE_SEL_MASK 0x0000000F +#define PVDEC_CORE_PVDEC_HOST_PIPE_SELECT_PIPE_SEL_SHIFT 0 + +/* register PROC_DEBUG */ +#define PVDEC_CORE_PROC_DEBUG_OFFSET 0x0100 + +#define PVDEC_CORE_PROC_DEBUG_MTX_LAST_RAM_BANK_SIZE_MASK 0xFF000000 +#define PVDEC_CORE_PROC_DEBUG_MTX_LAST_RAM_BANK_SIZE_SHIFT 24 + +#define PVDEC_CORE_PROC_DEBUG_MTX_RAM_BANK_SIZE_MASK 0x000F0000 +#define PVDEC_CORE_PROC_DEBUG_MTX_RAM_BANK_SIZE_SHIFT 16 + +#define PVDEC_CORE_PROC_DEBUG_MTX_RAM_BANKS_MASK 0x00000F00 +#define PVDEC_CORE_PROC_DEBUG_MTX_RAM_BANKS_SHIFT 8 + +#define PVDEC_CORE_PROC_DEBUG_MTX_RAM_NEW_REPRESENTATION_MASK 0x00000080 +#define PVDEC_CORE_PROC_DEBUG_MTX_RAM_NEW_REPRESENTATION_SHIFT 7 + +#define PVDEC_CORE_PROC_DEBUG_PROC_DBG_GPIO_OUT_MASK 0x00000018 +#define PVDEC_CORE_PROC_DEBUG_PROC_DBG_GPIO_OUT_SHIFT 3 + +#define PVDEC_CORE_PROC_DEBUG_PROC_DBG_IS_SLAVE_MASK 0x00000004 +#define PVDEC_CORE_PROC_DEBUG_PROC_DBG_IS_SLAVE_SHIFT 2 + +#define PVDEC_CORE_PROC_DEBUG_PROC_DBG_GPIO_IN_MASK 0x00000003 +#define PVDEC_CORE_PROC_DEBUG_PROC_DBG_GPIO_IN_SHIFT 0 + +/* register PROC_DMAC_CONTROL */ +#define PVDEC_CORE_PROC_DMAC_CONTROL_OFFSET 0x0104 + +#define PVDEC_CORE_PROC_DMAC_CONTROL_BOOT_ON_DMA_CH0_MASK 0x80000000 +#define PVDEC_CORE_PROC_DMAC_CONTROL_BOOT_ON_DMA_CH0_SHIFT 31 + +/* register PROC_DEBUG_FIFO */ +#define PVDEC_CORE_PROC_DBG_FIFO_OFFSET 0x0108 + +#define PVDEC_CORE_PROC_DBG_FIFO_PROC_DBG_FIFO_MASK 0xFFFFFFFF +#define PVDEC_CORE_PROC_DBG_FIFO_PROC_DBG_FIFO_SHIFT 0 + +/* register PROC_DEBUG_FIFO_CTRL_0 */ +#define PVDEC_CORE_PROC_DBG_FIFO_CTRL0_OFFSET 0x010C + +#define PVDEC_CORE_PROC_DBG_FIFO_CTRL0_PROC_DBG_FIFO_COUNT_MASK 0xFFFF0000 +#define PVDEC_CORE_PROC_DBG_FIFO_CTRL0_PROC_DBG_FIFO_COUNT_SHIFT 16 + +#define PVDEC_CORE_PROC_DBG_FIFO_CTRL0_PROC_DBG_FIFO_SIZE_MASK 0x0000FFFF +#define PVDEC_CORE_PROC_DBG_FIFO_CTRL0_PROC_DBG_FIFO_SIZE_SHIFT 0 + +/* register PVDEC_CORE_ID */ +#define PVDEC_CORE_PVDEC_CORE_ID_OFFSET 0x0230 + +#define PVDEC_CORE_PVDEC_CORE_ID_GROUP_ID_MASK 0xFF000000 +#define PVDEC_CORE_PVDEC_CORE_ID_GROUP_ID_SHIFT 24 + +#define PVDEC_CORE_PVDEC_CORE_ID_CORE_ID_MASK 0x00FF0000 +#define PVDEC_CORE_PVDEC_CORE_ID_CORE_ID_SHIFT 16 + +#define PVDEC_CORE_PVDEC_CORE_ID_PVDEC_CORE_CONFIG_MASK 0x0000FFFF +#define PVDEC_CORE_PVDEC_CORE_ID_PVDEC_CORE_CONFIG_SHIFT 0 + +#define PVDEC_CORE_PVDEC_CORE_ID_ENT_PIPES_MASK 0x0000000F +#define PVDEC_CORE_PVDEC_CORE_ID_ENT_PIPES_SHIFT 0 + +#define PVDEC_CORE_PVDEC_CORE_ID_PIX_PIPES_MASK 0x000000F0 +#define PVDEC_CORE_PVDEC_CORE_ID_PIX_PIPES_SHIFT 4 + +/* register PVDEC_CORE_REV */ +#define PVDEC_CORE_PVDEC_CORE_REV_OFFSET 0x0240 + +#define PVDEC_CORE_PVDEC_CORE_REV_PVDEC_DESIGNER_MASK 0xFF000000 +#define PVDEC_CORE_PVDEC_CORE_REV_PVDEC_DESIGNER_SHIFT 24 + +#define PVDEC_CORE_PVDEC_CORE_REV_PVDEC_MAJOR_REV_MASK 0x00FF0000 +#define PVDEC_CORE_PVDEC_CORE_REV_PVDEC_MAJOR_REV_SHIFT 16 + +#define PVDEC_CORE_PVDEC_CORE_REV_PVDEC_MINOR_REV_MASK 0x0000FF00 +#define PVDEC_CORE_PVDEC_CORE_REV_PVDEC_MINOR_REV_SHIFT 8 + +#define PVDEC_CORE_PVDEC_CORE_REV_PVDEC_MAINT_REV_MASK 0x000000FF +#define PVDEC_CORE_PVDEC_CORE_REV_PVDEC_MAINT_REV_SHIFT 0 + +/* *********************** MTX_CORE registers group ************************* */ + +/* register MTX_ENABLE */ +#define MTX_CORE_MTX_ENABLE_OFFSET 0x0000 + +/* register MTX_SYSC_TXTIMER. Note: it's not defined in PVDEC TRM. */ +#define MTX_CORE_MTX_SYSC_TXTIMER_OFFSET 0x0010 + +/* register MTX_KICKI */ +#define MTX_CORE_MTX_KICKI_OFFSET 0x0088 + +#define MTX_CORE_MTX_KICKI_MTX_KICKI_MASK 0x0000FFFF +#define MTX_CORE_MTX_KICKI_MTX_KICKI_SHIFT 0 + +/* register MTX_FAULT0 */ +#define MTX_CORE_MTX_FAULT0_OFFSET 0x0090 + +/* register MTX_REGISTER_READ_WRITE_DATA */ +#define MTX_CORE_MTX_REG_READ_WRITE_DATA_OFFSET 0x00F8 + +/* register MTX_REGISTER_READ_WRITE_REQUEST */ +#define MTX_CORE_MTX_REG_READ_WRITE_REQUEST_OFFSET 0x00FC + +#define MTX_CORE_MTX_REG_READ_WRITE_REQUEST_MTX_DREADY_MASK 0x80000000 +#define MTX_CORE_MTX_REG_READ_WRITE_REQUEST_MTX_DREADY_SHIFT 31 + +#define MTX_CORE_MTX_REG_READ_WRITE_REQUEST_MTX_RNW_MASK 0x00010000 +#define MTX_CORE_MTX_REG_READ_WRITE_REQUEST_MTX_RNW_SHIFT 16 + +#define MTX_CORE_MTX_REG_READ_WRITE_REQUEST_MTX_RSPECIFIER_MASK 0x00000070 +#define MTX_CORE_MTX_REG_READ_WRITE_REQUEST_MTX_RSPECIFIER_SHIFT 4 + +#define MTX_CORE_MTX_REG_READ_WRITE_REQUEST_MTX_USPECIFIER_MASK 0x0000000F +#define MTX_CORE_MTX_REG_READ_WRITE_REQUEST_MTX_USPECIFIER_SHIFT 0 + +/* register MTX_RAM_ACCESS_DATA_EXCHANGE */ +#define MTX_CORE_MTX_RAM_ACCESS_DATA_EXCHANGE_OFFSET 0x0100 + +/* register MTX_RAM_ACCESS_DATA_TRANSFER */ +#define MTX_CORE_MTX_RAM_ACCESS_DATA_TRANSFER_OFFSET 0x0104 + +/* register MTX_RAM_ACCESS_CONTROL */ +#define MTX_CORE_MTX_RAM_ACCESS_CONTROL_OFFSET 0x0108 + +#define MTX_CORE_MTX_RAM_ACCESS_CONTROL_MTX_MCMID_MASK 0x0FF00000 +#define MTX_CORE_MTX_RAM_ACCESS_CONTROL_MTX_MCMID_SHIFT 20 + +#define MTX_CORE_MTX_RAM_ACCESS_CONTROL_MTX_MCM_ADDR_MASK 0x000FFFFC +#define MTX_CORE_MTX_RAM_ACCESS_CONTROL_MTX_MCM_ADDR_SHIFT 2 + +#define MTX_CORE_MTX_RAM_ACCESS_CONTROL_MTX_MCMAI_MASK 0x00000002 +#define MTX_CORE_MTX_RAM_ACCESS_CONTROL_MTX_MCMAI_SHIFT 1 + +#define MTX_CORE_MTX_RAM_ACCESS_CONTROL_MTX_MCMR_MASK 0x00000001 +#define MTX_CORE_MTX_RAM_ACCESS_CONTROL_MTX_MCMR_SHIFT 0 + +/* register MTX_RAM_ACCESS_STATUS */ +#define MTX_CORE_MTX_RAM_ACCESS_STATUS_OFFSET 0x010C + +#define MTX_CORE_MTX_RAM_ACCESS_STATUS_MTX_MTX_MCM_STAT_MASK 0x00000001 +#define MTX_CORE_MTX_RAM_ACCESS_STATUS_MTX_MTX_MCM_STAT_SHIFT 0 + +/* register MTX_SOFT_RESET */ +#define MTX_CORE_MTX_SOFT_RESET_OFFSET 0x0200 + +#define MTX_CORE_MTX_SOFT_RESET_MTX_RESET_MASK 0x00000001 +#define MTX_CORE_MTX_SOFT_RESET_MTX_RESET_SHIFT 0 + +/* register MTX_SYSC_TIMERDIV */ +#define MTX_CORE_MTX_SYSC_TIMERDIV_OFFSET 0x0208 + +#define MTX_CORE_MTX_SYSC_TIMERDIV_TIMER_EN_MASK 0x00010000 +#define MTX_CORE_MTX_SYSC_TIMERDIV_TIMER_EN_SHIFT 16 + +#define MTX_CORE_MTX_SYSC_TIMERDIV_TIMER_DIV_MASK 0x000000FF +#define MTX_CORE_MTX_SYSC_TIMERDIV_TIMER_DIV_SHIFT 0 + +/* register MTX_SYSC_CDMAA */ +#define MTX_CORE_MTX_SYSC_CDMAA_OFFSET 0x0344 + +#define MTX_CORE_MTX_SYSC_CDMAA_CDMAA_ADDRESS_MASK 0x03FFFFFC +#define MTX_CORE_MTX_SYSC_CDMAA_CDMAA_ADDRESS_SHIFT 2 + +/* register MTX_SYSC_CDMAC */ +#define MTX_CORE_MTX_SYSC_CDMAC_OFFSET 0x0340 + +#define MTX_CORE_MTX_SYSC_CDMAC_BURSTSIZE_MASK 0x07000000 +#define MTX_CORE_MTX_SYSC_CDMAC_BURSTSIZE_SHIFT 24 + +#define MTX_CORE_MTX_SYSC_CDMAC_RNW_MASK 0x00020000 +#define MTX_CORE_MTX_SYSC_CDMAC_RNW_SHIFT 17 + +#define MTX_CORE_MTX_SYSC_CDMAC_ENABLE_MASK 0x00010000 +#define MTX_CORE_MTX_SYSC_CDMAC_ENABLE_SHIFT 16 + +#define MTX_CORE_MTX_SYSC_CDMAC_LENGTH_MASK 0x0000FFFF +#define MTX_CORE_MTX_SYSC_CDMAC_LENGTH_SHIFT 0 + +/* register MTX_SYSC_CDMAT */ +#define MTX_CORE_MTX_SYSC_CDMAT_OFFSET 0x0350 + +/* ****************** IMG_VIDEO_BUS4_MMU registers group ******************** */ + +/* register MMU_CONTROL0_ */ +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL0_USE_TILE_STRIDE_PER_CTX_MASK 0x00010000 +#define IMG_VIDEO_BUS4_MMU_MMU_CONTROL0_USE_TILE_STRIDE_PER_CTX_SHIFT 16 + +#define IMG_VIDEO_BUS4_MMU_MMU_ADDRESS_CONTROL_MMU_ENA_EXT_ADDR_MASK 0x00000010 +#define IMG_VIDEO_BUS4_MMU_MMU_ADDRESS_CONTROL_MMU_ENA_EXT_ADDR_SHIFT 4 + +#define IMG_VIDEO_BUS4_MMU_MMU_ADDRESS_CONTROL_UPPER_ADDR_FIXED_MASK 0x00FF0000 +#define IMG_VIDEO_BUS4_MMU_MMU_ADDRESS_CONTROL_UPPER_ADDR_FIXED_SHIFT 16 + +#define IMG_VIDEO_BUS4_MMU_MMU_MEM_EXT_OUTSTANDING_READ_WORDS_MASK 0x0000FFFF +#define IMG_VIDEO_BUS4_MMU_MMU_MEM_EXT_OUTSTANDING_READ_WORDS_SHIFT 0 + +/* *************************** MMU-related values ************************** */ + +/* MMU page size */ + +enum { + VXD_MMU_SOFT_PAGE_SIZE_PAGE_64K = 0x4, + VXD_MMU_SOFT_PAGE_SIZE_PAGE_16K = 0x2, + VXD_MMU_SOFT_PAGE_SIZE_PAGE_4K = 0x0, + VXD_MMU_SOFT_PAGE_SIZE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* MMU PTD entry flags */ +enum { + VXD_MMU_PTD_FLAG_NONE = 0x0, + VXD_MMU_PTD_FLAG_VALID = 0x1, + VXD_MMU_PTD_FLAG_WRITE_ONLY = 0x2, + VXD_MMU_PTD_FLAG_READ_ONLY = 0x4, + VXD_MMU_PTD_FLAG_CACHE_COHERENCY = 0x8, + VXD_MMU_PTD_FLAG_FORCE32BITS = 0x7FFFFFFFU +}; + +/* ********************* PVDEC_PIXEL registers group *********************** */ + +/* register PVDEC_PIXEL_PIXEL_CONTROL_0 */ +#define PVDEC_PIXEL_PIXEL_CONTROL_0_OFFSET 0x0004 + +#define PVDEC_PIXEL_PIXEL_CONTROL_0_DMAC_CH_SEL_FOR_MTX_MASK 0x0000000E +#define PVDEC_PIXEL_PIXEL_CONTROL_0_DMAC_CH_SEL_FOR_MTX_SHIFT 1 + +#define PVDEC_PIXEL_PIXEL_CONTROL_0_PROC_DMAC_CH0_SEL_MASK 0x00000001 +#define PVDEC_PIXEL_PIXEL_CONTROL_0_PROC_DMAC_CH0_SEL_SHIFT 0 + +/* register PVDEC_PIXEL_MAN_CLK_ENABLE */ +#define PVDEC_PIXEL_PIXEL_MAN_CLK_ENA_OFFSET 0x0020 + +#define PVDEC_PIXEL_PIXEL_MAN_CLK_ENA_PIXEL_REG_MAN_CLK_ENA_MASK 0x00020000 +#define PVDEC_PIXEL_PIXEL_MAN_CLK_ENA_PIXEL_REG_MAN_CLK_ENA_SHIFT 17 + +#define PVDEC_PIXEL_PIXEL_MAN_CLK_ENA_PIXEL_DMAC_MAN_CLK_ENA_MASK 0x00010000 +#define PVDEC_PIXEL_PIXEL_MAN_CLK_ENA_PIXEL_DMAC_MAN_CLK_ENA_SHIFT 16 + +/* register PIXEL_PIPE_CONFIG */ +#define PVDEC_PIXEL_PIXEL_PIPE_CONFIG_OFFSET 0x00C0 + +/* register PIXEL_MISC_CONFIG */ +#define PVDEC_PIXEL_PIXEL_MISC_CONFIG_OFFSET 0x00C4 + +/* register MAX_FRAME_CONFIG */ +#define PVDEC_PIXEL_MAX_FRAME_CONFIG_OFFSET 0x00C8 + +/* ********************* PVDEC_ENTROPY registers group ********************* */ + +/* Register PVDEC_ENTROPY_MAN_CLK_ENABLE */ +#define PVDEC_ENTROPY_ENTROPY_MAN_CLK_ENA_OFFSET 0x0020 + +/* Register PVDEC_ENTROPY_LAST_LAST_MB */ +#define PVDEC_ENTROPY_ENTROPY_LAST_MB_OFFSET 0x00BC + +/* ********************* PVDEC_VEC_BE registers group ********************** */ + +/* Register PVDEC_VEC_BE_VEC_BE_STATUS */ +#define PVDEC_VEC_BE_VEC_BE_STATUS_OFFSET 0x0018 + +/* ********************* MSVDX_VEC registers group ************************* */ + +/* Register MSVDX_VEC_VEC_ENTDEC_INFORMATION */ +#define MSVDX_VEC_VEC_ENTDEC_INFORMATION_OFFSET 0x00AC + +/* ********************* MSVDX_VDMC registers group ************************ */ + +/* Register MSVDX_VDMC_VDMC_MACROBLOCK_NUMBER */ +#define MSVDX_VDMC_VDMC_MACROBLOCK_NUMBER_OFFSET 0x0048 + +/* ************************** DMAC registers group ************************* */ + +/* register DMAC_SETUP */ +#define DMAC_DMAC_SETUP_OFFSET 0x0000 +#define DMAC_DMAC_SETUP_STRIDE 32 +#define DMAC_DMAC_SETUP_NO_ENTRIES 6 + +/* register DMAC_COUNT */ +#define DMAC_DMAC_COUNT_OFFSET 0x0004 +#define DMAC_DMAC_COUNT_STRIDE 32 +#define DMAC_DMAC_COUNT_NO_ENTRIES 6 + +#define DMAC_DMAC_COUNT_LIST_IEN_MASK 0x80000000 +#define DMAC_DMAC_COUNT_LIST_IEN_SHIFT 31 + +#define DMAC_DMAC_COUNT_BSWAP_MASK 0x40000000 +#define DMAC_DMAC_COUNT_BSWAP_SHIFT 30 + +#define DMAC_DMAC_COUNT_TRANSFER_IEN_MASK 0x20000000 +#define DMAC_DMAC_COUNT_TRANSFER_IEN_SHIFT 29 + +#define DMAC_DMAC_COUNT_PW_MASK 0x18000000 +#define DMAC_DMAC_COUNT_PW_SHIFT 27 + +#define DMAC_DMAC_COUNT_DIR_MASK 0x04000000 +#define DMAC_DMAC_COUNT_DIR_SHIFT 26 + +#define DMAC_DMAC_COUNT_PI_MASK 0x03000000 +#define DMAC_DMAC_COUNT_PI_SHIFT 24 + +#define DMAC_DMAC_COUNT_LIST_FIN_CTL_MASK 0x00400000 +#define DMAC_DMAC_COUNT_LIST_FIN_CTL_SHIFT 22 + +#define DMAC_DMAC_COUNT_DREQ_MASK 0x00100000 +#define DMAC_DMAC_COUNT_DREQ_SHIFT 20 + +#define DMAC_DMAC_COUNT_SRST_MASK 0x00080000 +#define DMAC_DMAC_COUNT_SRST_SHIFT 19 + +#define DMAC_DMAC_COUNT_LIST_EN_MASK 0x00040000 +#define DMAC_DMAC_COUNT_LIST_EN_SHIFT 18 + +#define DMAC_DMAC_COUNT_ENABLE_2D_MODE_MASK 0x00020000 +#define DMAC_DMAC_COUNT_ENABLE_2D_MODE_SHIFT 17 + +#define DMAC_DMAC_COUNT_EN_MASK 0x00010000 +#define DMAC_DMAC_COUNT_EN_SHIFT 16 + +#define DMAC_DMAC_COUNT_CNT_MASK 0x0000FFFF +#define DMAC_DMAC_COUNT_CNT_SHIFT 0 + +/* register DMAC_PERIPH */ +#define DMAC_DMAC_PERIPH_OFFSET 0x0008 +#define DMAC_DMAC_PERIPH_STRIDE 32 +#define DMAC_DMAC_PERIPH_NO_ENTRIES 6 + +#define DMAC_DMAC_PERIPH_ACC_DEL_MASK 0xE0000000 +#define DMAC_DMAC_PERIPH_ACC_DEL_SHIFT 29 + +#define DMAC_DMAC_PERIPH_INCR_MASK 0x08000000 +#define DMAC_DMAC_PERIPH_INCR_SHIFT 27 + +#define DMAC_DMAC_PERIPH_BURST_MASK 0x07000000 +#define DMAC_DMAC_PERIPH_BURST_SHIFT 24 + +#define DMAC_DMAC_PERIPH_EXT_BURST_MASK 0x000F0000 +#define DMAC_DMAC_PERIPH_EXT_BURST_SHIFT 16 + +#define DMAC_DMAC_PERIPH_EXT_SA_MASK 0x0000000F +#define DMAC_DMAC_PERIPH_EXT_SA_SHIFT 0 + +/* register DMAC_IRQ_STAT */ +#define DMAC_DMAC_IRQ_STAT_OFFSET 0x000C +#define DMAC_DMAC_IRQ_STAT_STRIDE 32 +#define DMAC_DMAC_IRQ_STAT_NO_ENTRIES 6 + +/* register DMAC_PERIPHERAL_ADDR */ +#define DMAC_DMAC_PERIPH_ADDR_OFFSET 0x0014 +#define DMAC_DMAC_PERIPH_ADDR_STRIDE 32 +#define DMAC_DMAC_PERIPH_ADDR_NO_ENTRIES 6 + +#define DMAC_DMAC_PERIPH_ADDR_ADDR_MASK 0x007FFFFF +#define DMAC_DMAC_PERIPH_ADDR_ADDR_SHIFT 0 + +/* register DMAC_PER_HOLD */ +#define DMAC_DMAC_PER_HOLD_OFFSET 0x0018 +#define DMAC_DMAC_PER_HOLD_STRIDE 32 +#define DMAC_DMAC_PER_HOLD_NO_ENTRIES 6 + +#define DMAC_DMAC_PER_HOLD_PER_HOLD_MASK 0x0000001F +#define DMAC_DMAC_PER_HOLD_PER_HOLD_SHIFT 0 + +#define DMAC_DMAC_SOFT_RESET_OFFSET 0x00C0 + +/* ************************** DMAC-related values *************************** */ + +/* + * This type defines whether the peripheral address is static or + * auto-incremented. (see the TRM "Transfer Sequence Linked-list - INCR") + */ +enum { + DMAC_INCR_OFF = 0, /* No action, no increment. */ + DMAC_INCR_ON = 1, /* Generate address increment. */ + DMAC_INCR_FORCE32BITS = 0x7FFFFFFFU +}; + +/* Burst size settings (see the TRM "Transfer Sequence Linked-list - BURST"). */ +enum { + DMAC_BURST_0 = 0x0, /* burst size of 0 */ + DMAC_BURST_1 = 0x1, /* burst size of 1 */ + DMAC_BURST_2 = 0x2, /* burst size of 2 */ + DMAC_BURST_3 = 0x3, /* burst size of 3 */ + DMAC_BURST_4 = 0x4, /* burst size of 4 */ + DMAC_BURST_5 = 0x5, /* burst size of 5 */ + DMAC_BURST_6 = 0x6, /* burst size of 6 */ + DMAC_BURST_7 = 0x7, /* burst size of 7 */ + DMAC_BURST_8 = 0x8, /* burst size of 8 */ + DMAC_BURST_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Extended burst size settings (see TRM "Transfer Sequence Linked-list - + * EXT_BURST"). + */ +enum { + DMAC_EXT_BURST_0 = 0x0, /* no extension */ + DMAC_EXT_BURST_1 = 0x1, /* extension of 8 */ + DMAC_EXT_BURST_2 = 0x2, /* extension of 16 */ + DMAC_EXT_BURST_3 = 0x3, /* extension of 24 */ + DMAC_EXT_BURST_4 = 0x4, /* extension of 32 */ + DMAC_EXT_BURST_5 = 0x5, /* extension of 40 */ + DMAC_EXT_BURST_6 = 0x6, /* extension of 48 */ + DMAC_EXT_BURST_7 = 0x7, /* extension of 56 */ + DMAC_EXT_BURST_8 = 0x8, /* extension of 64 */ + DMAC_EXT_BURST_9 = 0x9, /* extension of 72 */ + DMAC_EXT_BURST_10 = 0xa, /* extension of 80 */ + DMAC_EXT_BURST_11 = 0xb, /* extension of 88 */ + DMAC_EXT_BURST_12 = 0xc, /* extension of 96 */ + DMAC_EXT_BURST_13 = 0xd, /* extension of 104 */ + DMAC_EXT_BURST_14 = 0xe, /* extension of 112 */ + DMAC_EXT_BURST_15 = 0xf, /* extension of 120 */ + DMAC_EXT_BURST_FORCE32BITS = 0x7FFFFFFFU +}; + +/* Transfer direction. */ +enum { + DMAC_MEM_TO_VXD = 0x0, + DMAC_VXD_TO_MEM = 0x1, + DMAC_VXD_TO_FORCE32BITS = 0x7FFFFFFFU +}; + +/* How much to increment the peripheral address. */ +enum { + DMAC_PI_1 = 0x2, /* increment by 1 */ + DMAC_PI_2 = 0x1, /* increment by 2 */ + DMAC_PI_4 = 0x0, /* increment by 4 */ + DMAC_PI_FORCE32BITS = 0x7FFFFFFFU +}; + +/* Peripheral width settings (see TRM "Transfer Sequence Linked-list - PW"). */ +enum { + DMAC_PWIDTH_32_BIT = 0x0, /* Peripheral width 32-bit. */ + DMAC_PWIDTH_16_BIT = 0x1, /* Peripheral width 16-bit. */ + DMAC_PWIDTH_8_BIT = 0x2, /* Peripheral width 8-bit. */ + DMAC_PWIDTH_FORCE32BITS = 0x7FFFFFFFU +}; + +/* ******************************* macros ********************************** */ + +#ifdef PVDEC_SINGLETHREADED_IO +/* Write to the register */ +#define VXD_WR_REG_ABS(base, addr, val) \ + ({ spin_lock_irqsave(&pvdec_irq_lock, pvdec_irq_flags); \ + iowrite32((val), (addr) + (base)); \ + spin_unlock_irqrestore(&pvdec_irq_lock, (unsigned long)pvdec_irq_flags); }) + +/* Read the register */ +#define VXD_RD_REG_ABS(base, addr) \ + ({ unsigned int reg; \ + spin_lock_irqsave(&pvdec_irq_lock, pvdec_irq_flags); \ + reg = ioread32((addr) + (base)); \ + spin_unlock_irqrestore(&pvdec_irq_lock, (unsigned long)pvdec_irq_flags); \ + reg; }) +#else /* ndef PVDEC_SINGLETHREADED_IO */ + +/* Write to the register */ +#define VXD_WR_REG_ABS(base, addr, val) \ + (iowrite32((val), (addr) + (base))) + +/* Read the register */ +#define VXD_RD_REG_ABS(base, addr) \ + (ioread32((addr) + (base))) + +#endif + +/* Get offset of a register */ +#define VXD_GET_REG_OFF(group, reg) \ + (group ## _OFFSET + group ## _ ## reg ## _OFFSET) + +/* Get offset of a repated register */ +#define VXD_GET_RPT_REG_OFF(group, reg, index) \ + (VXD_GET_REG_OFF(group, reg) + ((index) * group ## _ ## reg ## _STRIDE)) + +/* Extract field from a register */ +#define VXD_RD_REG_FIELD(val, group, reg, field) \ + (((val) & group ## _ ## reg ## _ ## field ## _MASK) >> \ + group ## _ ## reg ## _ ## field ## _SHIFT) + +/* Shift provided value by number of bits relevant to register specification */ +#define VXD_ENC_REG_FIELD(group, reg, field, val) \ + ((unsigned int)(val) << (group ## _ ## reg ## _ ## field ## _SHIFT)) + +/* Update the field in a register */ +#define VXD_WR_REG_FIELD(reg_val, group, reg, field, val) \ + (((reg_val) & ~(group ## _ ## reg ## _ ## field ## _MASK)) | \ + (VXD_ENC_REG_FIELD(group, reg, field, val) & \ + (group ## _ ## reg ## _ ## field ## _MASK))) + +/* Write to a register */ +#define VXD_WR_REG(base, group, reg, val) \ + VXD_WR_REG_ABS(base, VXD_GET_REG_OFF(group, reg), val) + +/* Write to a repeated register */ +#define VXD_WR_RPT_REG(base, group, reg, val, index) \ + VXD_WR_REG_ABS(base, VXD_GET_RPT_REG_OFF(group, reg, index), val) + +/* Read a register */ +#define VXD_RD_REG(base, group, reg) \ + VXD_RD_REG_ABS(base, VXD_GET_REG_OFF(group, reg)) + +/* Read a repeated register */ +#define VXD_RD_RPT_REG(base, group, reg, index) \ + VXD_RD_REG_ABS(base, VXD_GET_RPT_REG_OFF(group, reg, index)) + +/* Insert word into the message buffer */ +#define VXD_WR_MSG_WRD(buf, msg_type, wrd, val) \ + (((unsigned int *)buf)[(msg_type ## _ ## wrd ## _OFFSET) / sizeof(unsigned int)] = \ + val) + +/* Get a word from the message buffer */ +#define VXD_RD_MSG_WRD(buf, msg_type, wrd) \ + (((unsigned int *)buf)[(msg_type ## _ ## wrd ## _OFFSET) / sizeof(unsigned int)]) + +/* Get offset for pipe register */ +#define VXD_GET_PIPE_OFF(num_pipes, pipe) \ + ((num_pipes) > 1 ? ((pipe) << 16) : 0) + +#endif /* VXD_PVDEC_REGS_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_v4l2.c b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_v4l2.c --- a/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_v4l2.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/decoder/vxd_v4l2.c 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,2428 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMG DEC V4L2 Interface function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Angela Stegmaier + * David Huang + * + * Re-written for upstreaming + * Prashanth Kumar Amai + * Sidraya Jayagond + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ERROR_RECOVERY_SIMULATION +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CAPTURE_CONTIG_ALLOC +#include +#endif + +#include "core.h" +#include "h264fw_data.h" +#include "hevcfw_data.h" +#include "img_dec_common.h" +#include "vxd_pvdec_priv.h" +#include "vxd_dec.h" +#include "img_errors.h" +#include "vdecdd_utils.h" + +#define VXD_DEC_SPIN_LOCK_NAME "vxd-dec" +#define IMG_VXD_DEC_MODULE_NAME "vxd-dec" + +#define V4L2_CID_VXD_SET_DEC_BUFS (V4L2_CID_USER_BASE + 0x1001) +#define V4L2_CID_VXD_SET_DISP_BUFS (V4L2_CID_USER_BASE + 0x1002) +#define V4L2_CID_VXD_SET_IMG_BUFS (V4L2_CID_USER_BASE + 0x1003) +#define V4L2_CID_VXD_SET_SPEC_BUFS (V4L2_CID_USER_BASE + 0x1004) + +#ifdef ERROR_RECOVERY_SIMULATION +/* This code should be execute only in debug flag */ +/* + * vxd decoder kernel object to create sysfs to debug error recovery and firmware + * watchdog timer. This kernel object will create a directory under /sys/kernel, + * containing two files fw_error_value and disable_fw_irq. + */ +struct kobject *vxd_dec_kobject; + +/* fw_error_value is the variable used to handle fw_error_attr */ +int fw_error_value = VDEC_ERROR_MAX; + +/* irq for the module, stored globally so can be accessed from sysfs */ +int g_module_irq; + +/* + * fw_error_attr. Application can set the value of this attribute, based on the + * firmware error that needs to be reproduced. + */ +struct kobj_attribute fw_error_attr = + __ATTR(fw_error_value, 0660, vxd_sysfs_show, vxd_sysfs_store); + +/* disable_fw_irq_value is variable to handle disable_fw_irq_attr */ +int disable_fw_irq_value; + +/* + * disable_fw_irq_attr. Application can set the value of this attribute. 1 to + * disable irq. 0 to enable irq. + */ +struct kobj_attribute disable_fw_irq_attr = + __ATTR(disable_fw_irq_value, 0660, vxd_sysfs_show, vxd_sysfs_store); + +/* + * Group attribute so that we can create and destroy all of them at once. + */ +struct attribute *attrs[] = { + &fw_error_attr.attr, + &disable_fw_irq_attr.attr, + NULL, /* Terminate list of attributes with NULL */ +}; + +/* + * An unnamed attribute group will put all of the attributes directly in + * the kobject directory. If we specify a name, a sub directory will be + * created for the attributes with the directory being the name of the + * attribute group + */ +struct attribute_group attr_group = { + .attrs = attrs, +}; + +#endif + +static struct heap_config vxd_dec_heap_configs[] = { + { + .type = MEM_HEAP_TYPE_UNIFIED, + .options.unified = { + .gfp_type = __GFP_DMA32 | __GFP_ZERO, + }, + .to_dev_addr = NULL, + }, +}; + +static inline struct vxd_dec_ctx *vxd_ctrl_to_ctx(struct v4l2_ctrl *vctrl) +{ + return container_of(vctrl->handler, struct vxd_dec_ctx, v4l2_ctrl_hdl); +} + +static int vxd_dec_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vxd_dec_ctx *ctx = vxd_ctrl_to_ctx(ctrl); + + pr_debug("%s: name: %s | value: %d\n", + __func__, ctrl->name, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_VXD_SET_DEC_BUFS: + ctx->max_dec_frame_buffering = ctrl->val; + break; + case V4L2_CID_VXD_SET_SPEC_BUFS: + ctx->override_spec_dpb_buffers = ctrl->val; + break; + case V4L2_CID_VXD_SET_IMG_BUFS: + ctx->img_extra_decode_buffers = ctrl->val; + break; + case V4L2_CID_VXD_SET_DISP_BUFS: + ctx->display_pipeline_size = ctrl->val; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops vxd_dec_ctrl_ops = { + .s_ctrl = vxd_dec_s_ctrl, +}; + +static const struct v4l2_ctrl_config vxd_max_dec_frame_buffering = { + .ops = &vxd_dec_ctrl_ops, + .id = V4L2_CID_VXD_SET_DEC_BUFS, + .name = "max_dec_frame_buffering", + .type = V4L2_CTRL_TYPE_INTEGER, + .def = 0, + .min = 0, + .max = 16, + .step = 1, + .flags = 0, +}; + +static const struct v4l2_ctrl_config vxd_img_extra_decode_buffers = { + .ops = &vxd_dec_ctrl_ops, + .id = V4L2_CID_VXD_SET_IMG_BUFS, + .name = "img_extra_decode_buffers", + .type = V4L2_CTRL_TYPE_INTEGER, + .def = -1, + .min = -1, + .max = 3, + .step = 1, + .flags = 0, +}; + +static const struct v4l2_ctrl_config vxd_display_pipeline_size = { + .ops = &vxd_dec_ctrl_ops, + .id = V4L2_CID_VXD_SET_DISP_BUFS, + .name = "display_pipeline_size", + .type = V4L2_CTRL_TYPE_INTEGER, + .def = DISPLAY_LAG, + .min = 0, + .max = 6, + .step = 1, + .flags = 0, +}; + +static const struct v4l2_ctrl_config vxd_override_spec_dpb_buffers = { + .ops = &vxd_dec_ctrl_ops, + .id = V4L2_CID_VXD_SET_SPEC_BUFS, + .name = "override_spec_dpb_buffers", + .type = V4L2_CTRL_TYPE_INTEGER, + .def = -1, + .min = -1, + .max = 16, + .step = 1, + .flags = 0, +}; + +static struct vxd_dec_fmt vxd_dec_formats[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .num_planes = 1, + .type = IMG_DEC_FMT_TYPE_CAPTURE, + .std = VDEC_STD_UNDEFINED, + .pixfmt = IMG_PIXFMT_420PL12YUV8, + .interleave = PIXEL_UV_ORDER, + .idc = PIXEL_FORMAT_420, + .size_num = 3, + .size_den = 2, + .bytes_pp = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV16, + .num_planes = 1, + .type = IMG_DEC_FMT_TYPE_CAPTURE, + .std = VDEC_STD_UNDEFINED, + .pixfmt = IMG_PIXFMT_422PL12YUV8, + .interleave = PIXEL_UV_ORDER, + .idc = PIXEL_FORMAT_422, + .size_num = 2, + .size_den = 1, + .bytes_pp = 1, + }, + { + .fourcc = V4L2_PIX_FMT_TI1210, + .num_planes = 1, + .type = IMG_DEC_FMT_TYPE_CAPTURE, + .std = VDEC_STD_UNDEFINED, + .pixfmt = IMG_PIXFMT_420PL12YUV10_MSB, + .interleave = PIXEL_UV_ORDER, + .idc = PIXEL_FORMAT_420, + .size_num = 3, + .size_den = 2, + .bytes_pp = 2, + }, + { + .fourcc = V4L2_PIX_FMT_TI1610, + .num_planes = 1, + .type = IMG_DEC_FMT_TYPE_CAPTURE, + .std = VDEC_STD_UNDEFINED, + .pixfmt = IMG_PIXFMT_422PL12YUV10_MSB, + .interleave = PIXEL_UV_ORDER, + .idc = PIXEL_FORMAT_422, + .size_num = 2, + .size_den = 1, + .bytes_pp = 2, + }, + { + .fourcc = V4L2_PIX_FMT_H264, + .num_planes = 1, + .type = IMG_DEC_FMT_TYPE_OUTPUT, + .std = VDEC_STD_H264, + .pixfmt = IMG_PIXFMT_UNDEFINED, + .interleave = PIXEL_INVALID_CI, + .idc = PIXEL_FORMAT_INVALID, + .size_num = 1, + .size_den = 1, + .bytes_pp = 1, + }, + { + .fourcc = V4L2_PIX_FMT_HEVC, + .num_planes = 1, + .type = IMG_DEC_FMT_TYPE_OUTPUT, + .std = VDEC_STD_HEVC, + .pixfmt = IMG_PIXFMT_UNDEFINED, + .interleave = PIXEL_INVALID_CI, + .idc = PIXEL_FORMAT_INVALID, + .size_num = 1, + .size_den = 1, + .bytes_pp = 1, + }, + { + .fourcc = V4L2_PIX_FMT_MJPEG, + .num_planes = 1, + .type = IMG_DEC_FMT_TYPE_OUTPUT, + .std = VDEC_STD_JPEG, + .pixfmt = IMG_PIXFMT_UNDEFINED, + .interleave = PIXEL_INVALID_CI, + .idc = PIXEL_FORMAT_INVALID, + .size_num = 1, + .size_den = 1, + .bytes_pp = 1, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420M, + .num_planes = 3, + .type = IMG_DEC_FMT_TYPE_CAPTURE, + .std = VDEC_STD_UNDEFINED, + .pixfmt = 86031, + .interleave = PIXEL_UV_ORDER, + .idc = PIXEL_FORMAT_420, + .size_num = 2, + .size_den = 1, + .bytes_pp = 1, + }, + { + .fourcc = V4L2_PIX_FMT_YUV422M, + .num_planes = 3, + .type = IMG_DEC_FMT_TYPE_CAPTURE, + .std = VDEC_STD_UNDEFINED, + .pixfmt = 81935, + .interleave = PIXEL_UV_ORDER, + .idc = PIXEL_FORMAT_422, + .size_num = 3, + .size_den = 1, + .bytes_pp = 1, + }, +}; + +#ifdef ERROR_RECOVERY_SIMULATION +ssize_t vxd_sysfs_show(struct kobject *vxd_dec_kobject, + struct kobj_attribute *attr, char *buf) + +{ + int var = 0; + + if (strcmp(attr->attr.name, "fw_error_value") == 0) + var = fw_error_value; + + else + var = disable_fw_irq_value; + + return sprintf(buf, "%d\n", var); +} + +ssize_t vxd_sysfs_store(struct kobject *vxd_dec_kobject, + struct kobj_attribute *attr, + const char *buf, unsigned long count) +{ + int var = 0, rv = 0; + + rv = sscanf(buf, "%du", &var); + + if (strcmp(attr->attr.name, "fw_error_value") == 0) { + fw_error_value = var; + } else { + disable_fw_irq_value = var; + /* + * if disable_fw_irq_value is not zero, disable the irq to reproduce + * firmware non responsiveness in vxd_worker. + */ + if (disable_fw_irq_value != 0) { + /* just ignore the irq */ + disable_irq(g_module_irq); + } + } + return sprintf((char *)buf, "%d\n", var); +} +#endif + +static struct vxd_dec_ctx *file2ctx(struct file *file) +{ + return container_of(file->private_data, struct vxd_dec_ctx, fh); +} + +static irqreturn_t soft_thread_irq(int irq, void *dev_id) +{ + struct platform_device *pdev = (struct platform_device *)dev_id; + + if (!pdev) + return IRQ_NONE; + + return vxd_handle_thread_irq(&pdev->dev); +} + +static irqreturn_t hard_isrcb(int irq, void *dev_id) +{ + struct platform_device *pdev = (struct platform_device *)dev_id; + + if (!pdev) + return IRQ_NONE; + + return vxd_handle_irq(&pdev->dev); +} + +static struct vxd_mapping *find_mapping(unsigned int buf_map_id, struct list_head *head) +{ + struct list_head *list; + struct vxd_mapping *mapping = NULL; + + list_for_each(list, head) { + mapping = list_entry(list, struct vxd_mapping, list); + if (!mapping) + continue; + if (mapping->buf_map_id == buf_map_id) + break; + mapping = NULL; + } + return mapping; +} + +static struct vxd_buffer *find_buffer(unsigned int buf_map_id, struct list_head *head) +{ + struct list_head *list; + struct vxd_buffer *buf = NULL; + + list_for_each(list, head) { + buf = list_entry(list, struct vxd_buffer, list); + if (!buf) + continue; + if (buf->buf_map_id == buf_map_id) + break; + buf = NULL; + } + return buf; +} + +static void return_worker(void *work) +{ + struct vxd_dec_ctx *ctx; + struct vxd_return *res; + struct device *dev; + struct timespec64 time; + int loop; + + work = get_work_buff(work, TRUE); + + res = container_of(work, struct vxd_return, work); + ctx = res->ctx; + dev = ctx->dev->dev; + switch (res->type) { + case VXD_CB_PICT_DECODED: + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); + ktime_get_real_ts64(&time); + for (loop = 0; loop < ARRAY_SIZE(ctx->dev->time_drv); loop++) { + if (ctx->dev->time_drv[loop].id == res->buf_map_id) { + ctx->dev->time_drv[loop].end_time = + timespec64_to_ns(&time); +#ifdef DEBUG_DECODER_DRIVER + dev_info(dev, "picture buf decode time is %llu us for buf_map_id 0x%x\n", + div_s64(ctx->dev->time_drv[loop].end_time - + ctx->dev->time_drv[loop].start_time, 1000), + res->buf_map_id); +#endif + break; + } + } + + if (loop == ARRAY_SIZE(ctx->dev->time_drv)) + dev_err(dev, "picture buf decode for buf_map_id x%0x is not measured\n", + res->buf_map_id); + break; + + default: + break; + } + kfree(res->work); + kfree(res); +} + +#ifdef ERROR_RECOVERY_SIMULATION +static void vxd_error_recovery(struct vxd_dec_ctx *ctx) +{ + int ret = -1; + + /* + * In the previous frame decoding fatal error has been detected + * so we need to reload the firmware to make it alive. + */ + pr_debug("Reloading the firmware because of previous error\n"); + vxd_clean_fw_resources(ctx->dev); + ret = vxd_prepare_fw(ctx->dev); + if (ret) + pr_err("Reloading the firmware failed!!"); +} +#endif /* ERROR_RECOVERY_SIMULATION */ + +static struct vxd_dec_q_data *get_q_data(struct vxd_dec_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return &ctx->q_data[Q_DATA_SRC]; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + return &ctx->q_data[Q_DATA_DST]; + default: + return NULL; + } + return NULL; +} + +static void vxd_return_resource(void *ctx_handle, enum vxd_cb_type type, + unsigned int buf_map_id, unsigned int err_flags) +{ + struct vxd_return *res; + struct vxd_buffer *buf = NULL; + struct vb2_v4l2_buffer *vb; + struct vxd_mapping *mapping = NULL; + struct vxd_dec_ctx *ctx = (struct vxd_dec_ctx *)ctx_handle; + struct v4l2_event event = {}; + struct device *dev = ctx->dev->dev; + int i; + struct vxd_dec_q_data *q_data; + + switch (type) { + case VXD_CB_STRUNIT_PROCESSED: + + buf = find_buffer(buf_map_id, &ctx->out_buffers); + if (!buf) { + dev_err(dev, "Could not locate buf_map_id=0x%x in OUTPUT buffers list\n", + buf_map_id); + break; + } + buf->buffer.vb.field = V4L2_FIELD_NONE; + + q_data = get_q_data(ctx, buf->buffer.vb.vb2_buf.vb2_queue->type); + if (!q_data) + return; + + for (i = 0; i < q_data->fmt->num_planes; i++) + vb2_set_plane_payload(&buf->buffer.vb.vb2_buf, i, + ctx->pict_bufcfg.plane_size[i]); + + v4l2_m2m_buf_done(&buf->buffer.vb, VB2_BUF_STATE_DONE); + break; + case VXD_CB_SPS_RELEASE: + break; + case VXD_CB_PPS_RELEASE: + break; + case VXD_CB_PICT_DECODED: + res = kzalloc(sizeof(*res), GFP_KERNEL); + if (!res) + return; + res->ctx = ctx; + res->type = type; + res->buf_map_id = buf_map_id; + + init_work(&res->work, return_worker, HWA_DECODER); + if (!res->work) + return; + + /* this is done because the v4l2 spec says can't call m2m_done from */ + /* device_run, this callback could come from device_run */ + schedule_work(res->work); + + break; + case VXD_CB_PICT_DISPLAY: + buf = find_buffer(buf_map_id, &ctx->cap_buffers); + if (!buf) { + dev_err(dev, "Could not locate buf_map_id=0x%x in CAPTURE buffers list\n", + buf_map_id); + break; + } + buf->mapping->reuse = FALSE; + buf->buffer.vb.field = V4L2_FIELD_NONE; + + q_data = get_q_data(ctx, buf->buffer.vb.vb2_buf.vb2_queue->type); + if (!q_data) + return; + + for (i = 0; i < q_data->fmt->num_planes; i++) + vb2_set_plane_payload(&buf->buffer.vb.vb2_buf, i, + ctx->pict_bufcfg.plane_size[i]); + + /* + * for fatal errors we will use the FATAL callback + * however this will signal to v4l2 that this frame + * has a (potentially concealled) error + */ + if (err_flags) + v4l2_m2m_buf_done(&buf->buffer.vb, VB2_BUF_STATE_ERROR); + else + v4l2_m2m_buf_done(&buf->buffer.vb, VB2_BUF_STATE_DONE); + + break; + case VXD_CB_PICT_RELEASE: + buf = find_buffer(buf_map_id, &ctx->reuse_queue); + if (buf) { + buf->mapping->reuse = TRUE; + list_move_tail(&buf->list, &ctx->cap_buffers); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, &buf->buffer.vb); + break; + } + mapping = find_mapping(buf_map_id, &ctx->cap_mappings); + if (!mapping) { + dev_err(dev, "Could not locate buf_map_id=0x%x in CAPTURE buffers list\n", + buf_map_id); + break; + } + mapping->reuse = TRUE; + + break; + case VXD_CB_PICT_END: + break; + case VXD_CB_STR_END: + event.type = V4L2_EVENT_EOS; + v4l2_event_queue_fh(&ctx->fh, &event); + if (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) > 0) { + vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + vb->flags |= V4L2_BUF_FLAG_LAST; + + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!q_data) + break; + + for (i = 0; i < q_data->fmt->num_planes; i++) + vb2_set_plane_payload(&vb->vb2_buf, i, 0); + + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE); + } else { + ctx->flag_last = TRUE; + } + break; + case VXD_CB_ERROR_FATAL: + /* + * There has been FW error, so we need to reload the firmware. + */ +#ifdef ERROR_RECOVERY_SIMULATION + vxd_error_recovery(ctx); +#endif + + if (ctx->dev->emergency) + ctx->eos = TRUE; + /* + * Just send zero size buffer to v4l2 application, + * informing the error condition. + */ + if (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) > 0) { + vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + vb->flags |= V4L2_BUF_FLAG_LAST; + + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!q_data) + break; + + // terminal error, set planes to zero size and tell v4l2 layer + for (i = 0; i < q_data->fmt->num_planes; i++) + vb2_set_plane_payload(&vb->vb2_buf, i, 0); + + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); + } else { + ctx->flag_last = TRUE; + } + break; + default: + break; + } +} + +static int vxd_dec_submit_opconfig(struct vxd_dec_ctx *ctx) +{ + int ret = 0; + + if (ctx->stream_created) { + ret = core_stream_set_output_config(ctx->res_str_id, + &ctx->str_opcfg, + &ctx->pict_bufcfg); + if (ret) { + dev_err(ctx->dev->dev, "core_stream_set_output_config failed\n"); + ctx->opconfig_pending = TRUE; + return ret; + } + ctx->opconfig_pending = FALSE; + ctx->stream_configured = TRUE; + } else { + ctx->opconfig_pending = TRUE; + } + return ret; +} + +static int vxd_dec_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vxd_dec_ctx *ctx = vb2_get_drv_priv(vq); + struct vxd_dec_q_data *q_data; + struct vxd_dec_q_data *src_q_data; + int i; + unsigned int hw_nbuffers = 0; + + q_data = get_q_data(ctx, vq->type); + if (!q_data) + return -EINVAL; + + if (*nplanes) { + /* This is being called from CREATEBUFS, perform validation */ + if (*nplanes != q_data->fmt->num_planes) + return -EINVAL; + + for (i = 0; i < *nplanes; i++) { + if (sizes[i] != q_data->size_image[i]) + return -EINVAL; + } + + return 0; + } + + *nplanes = q_data->fmt->num_planes; + + if (!V4L2_TYPE_IS_OUTPUT(vq->type)) { + src_q_data = &ctx->q_data[Q_DATA_SRC]; + if (src_q_data) { + if (src_q_data->fmt->std == VDEC_STD_H264) { + if (ctx->override_spec_dpb_buffers == -1) + vdecddutils_get_minrequired_numpicts( + &ctx->strcfgdata, + &ctx->comseq_hdr_info, + &ctx->str_opcfg, &hw_nbuffers); + else + hw_nbuffers = + ctx->override_spec_dpb_buffers; + + /* + * IMG Spec says need: + * vdecddutils_get_minrequired_numpicts() + * + ((num_cores * slots_per_core) - 1) + * + display_pipeline_length + */ + if (ctx->img_extra_decode_buffers == -1) + hw_nbuffers += + (CORE_NUM_DECODE_SLOTS * + ((struct dec_ctx *)ctx->dev_ctx->dec_context)->num_pipes) - + 1; + else + hw_nbuffers += + ctx->img_extra_decode_buffers; + + hw_nbuffers += ctx->display_pipeline_size; + + pr_debug( + "DPB allocation algorithm has requested %d buffers\n", + hw_nbuffers); + } else { + hw_nbuffers = get_nbuffers(src_q_data->fmt->std, + q_data->width, + q_data->height, + ctx->max_num_ref_frames); + } + } + } + + *nbuffers = max(*nbuffers, hw_nbuffers); + + pr_debug("telling the framework to allocate %d buffers\n", *nbuffers); + + for (i = 0; i < *nplanes; i++) + sizes[i] = q_data->size_image[i]; + + return 0; +} + +static int vxd_dec_buf_prepare(struct vb2_buffer *vb) +{ + struct vxd_dec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct device *dev = ctx->dev->dev; + struct vxd_dec_q_data *q_data; + void *sgt; +#ifdef CAPTURE_CONTIG_ALLOC + struct page *new_page; +#else + void *sgl; +#endif + struct sg_table *sgt_new; + void *sgl_new; + int pages; + int nents = 0; + int size = 0; + int plane, num_planes, ret = 0; + unsigned long dma_addr; + struct vxd_mapping *mapping; + struct list_head *list; + struct vxd_buffer *buf = + container_of(vb, struct vxd_buffer, buffer.vb.vb2_buf); + + q_data = get_q_data(ctx, vb->vb2_queue->type); + if (!q_data) + return -EINVAL; + + num_planes = q_data->fmt->num_planes; + + for (plane = 0; plane < num_planes; plane++) { + if (vb2_plane_size(vb, plane) < q_data->size_image[plane]) { + dev_err(dev, "data will not fit into plane (%lu < %lu)\n", + vb2_plane_size(vb, plane), + (long)q_data->size_image[plane]); + return -EINVAL; + } + } + + if (buf->mapped && !V4L2_TYPE_IS_OUTPUT(vb->type)) { +#ifdef CAPTURE_CONTIG_ALLOC + dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); +#else + sgt = vb2_dma_sg_plane_desc(vb, 0); + if (!sgt) + return -EFAULT; + + dma_addr = sg_phys(img_mmu_get_sgl(sgt)); +#endif + if (buf->buf_info.dma_addr != dma_addr) { + list_for_each(list, &ctx->cap_mappings) { + mapping = list_entry(list, struct vxd_mapping, list); + if (dma_addr == mapping->dma_addr) + break; + + mapping = NULL; + } + if (mapping) { + /* skip the mapping, buf update buf_map_id */ + buf->buf_info.dma_addr = mapping->dma_addr; + buf->buf_map_id = mapping->buf_map_id; + buf->buf_info.cpu_linear_addr = vb2_plane_vaddr(vb, 0); + buf->mapping = mapping; + return 0; + } + } else { + return 0; + } + } else if (buf->mapped) { + return 0; + } + + buf->buf_info.cpu_linear_addr = vb2_plane_vaddr(vb, 0); + buf->buf_info.buf_size = vb2_plane_size(vb, 0); + buf->buf_info.fd = -1; + sgt = vb2_dma_sg_plane_desc(vb, 0); + if (!sgt) { + dev_err(dev, "Could not get sg_table from plane 0\n"); + return -EINVAL; + } + + if (V4L2_TYPE_IS_OUTPUT(vb->type)) { + buf->buf_info.dma_addr = sg_phys(img_mmu_get_sgl(sgt)); + ret = core_stream_map_buf_sg(ctx->res_str_id, + VDEC_BUFTYPE_BITSTREAM, + &buf->buf_info, sgt, + &buf->buf_map_id); + if (ret) { + dev_err(dev, "OUTPUT core_stream_map_buf_sg failed\n"); + return ret; + } + + buf->bstr_info.buf_size = q_data->size_image[0]; + buf->bstr_info.cpu_virt_addr = buf->buf_info.cpu_linear_addr; + buf->bstr_info.mem_attrib = + SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE | + SYS_MEMATTRIB_INPUT | SYS_MEMATTRIB_CPU_WRITE; + buf->bstr_info.bufmap_id = buf->buf_map_id; + lst_init(&buf->seq_unit.bstr_seg_list); + lst_init(&buf->pic_unit.bstr_seg_list); + lst_init(&buf->end_unit.bstr_seg_list); + + list_add_tail(&buf->list, &ctx->out_buffers); + } else { +#ifdef CAPTURE_CONTIG_ALLOC + buf->buf_info.dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); +#else + buf->buf_info.dma_addr = sg_phys(img_mmu_get_sgl(sgt)); +#endif + /* Create a single sgt from the plane(s) */ + sgt_new = kmalloc(sizeof(*sgt_new), GFP_KERNEL); + if (!sgt_new) + return -EINVAL; + + for (plane = 0; plane < num_planes; plane++) { + size += ALIGN(vb2_plane_size(vb, plane), PAGE_SIZE); + sgt = vb2_dma_sg_plane_desc(vb, plane); + if (!sgt) { + dev_err(dev, "Could not get sg_table from plane %d\n", plane); + kfree(sgt_new); + return -EINVAL; + } +#ifdef CAPTURE_CONTIG_ALLOC + nents += 1; +#else + nents += sg_nents(img_mmu_get_sgl(sgt)); +#endif + } + buf->buf_info.buf_size = size; + + pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; + ret = sg_alloc_table(sgt_new, nents, GFP_KERNEL); + if (ret) { + kfree(sgt_new); + return -EINVAL; + } + sgl_new = img_mmu_get_sgl(sgt_new); + + for (plane = 0; plane < num_planes; plane++) { + sgt = vb2_dma_sg_plane_desc(vb, plane); + if (!sgt) { + dev_err(dev, "Could not get sg_table from plane %d\n", plane); + sg_free_table(sgt_new); + kfree(sgt_new); + return -EINVAL; + } +#ifdef CAPTURE_CONTIG_ALLOC + new_page = phys_to_page(vb2_dma_contig_plane_dma_addr(vb, plane)); + sg_set_page(sgl_new, new_page, ALIGN(vb2_plane_size(vb, plane), + PAGE_SIZE), 0); + sgl_new = sg_next(sgl_new); +#else + sgl = img_mmu_get_sgl(sgt); + + while (sgl) { + sg_set_page(sgl_new, sg_page(sgl), img_mmu_get_sgl_length(sgl), 0); + sgl = sg_next(sgl); + sgl_new = sg_next(sgl_new); + } +#endif + } + + buf->buf_info.pictbuf_cfg = ctx->pict_bufcfg; + ret = core_stream_map_buf_sg(ctx->res_str_id, + VDEC_BUFTYPE_PICTURE, + &buf->buf_info, sgt_new, + &buf->buf_map_id); + sg_free_table(sgt_new); + kfree(sgt_new); + if (ret) { + dev_err(dev, "CAPTURE core_stream_map_buf_sg failed\n"); + return ret; + } + if (buf->mapped == FALSE) + list_add_tail(&buf->list, &ctx->cap_buffers); + + /* Add this to the mappings */ + mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); + + mapping->reuse = TRUE; + mapping->dma_addr = buf->buf_info.dma_addr; + mapping->buf_map_id = buf->buf_map_id; + list_add_tail(&mapping->list, &ctx->cap_mappings); + buf->mapping = mapping; + mapping->buf = buf; + } + buf->mapped = TRUE; + + return 0; +} + +static void vxd_dec_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vxd_dec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vxd_buffer *buf = + container_of(vb, struct vxd_buffer, buffer.vb.vb2_buf); + struct vxd_dec_q_data *q_data; + int i; + + if (V4L2_TYPE_IS_OUTPUT(vb->type)) { + vbuf->sequence = ctx->out_seq++; + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + } else { + vbuf->sequence = ctx->cap_seq++; + mutex_lock_nested(ctx->mutex, SUBCLASS_VXD_V4L2); + if (buf->mapping->reuse) { + mutex_unlock(ctx->mutex); + if (ctx->flag_last) { + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + vbuf->flags |= V4L2_BUF_FLAG_LAST; + + for (i = 0; i < q_data->fmt->num_planes; i++) + vb2_set_plane_payload(&vbuf->vb2_buf, i, 0); + + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); + } else { + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + } + } else { + list_move_tail(&buf->list, &ctx->reuse_queue); + mutex_unlock(ctx->mutex); + } + } +} + +static void vxd_dec_return_all_buffers(struct vxd_dec_ctx *ctx, + struct vb2_queue *q, + enum vb2_buffer_state state) +{ + struct vb2_v4l2_buffer *vb; + unsigned long flags; + + for (;;) { + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + if (!vb) + break; + + spin_lock_irqsave(ctx->dev->lock, flags); + v4l2_m2m_buf_done(vb, state); + spin_unlock_irqrestore(ctx->dev->lock, (unsigned long)flags); + } +} + +static int vxd_dec_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + int ret = 0; + struct vxd_dec_ctx *ctx = vb2_get_drv_priv(vq); + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + ctx->src_streaming = TRUE; + else + ctx->dst_streaming = TRUE; + + if (ctx->dst_streaming && ctx->src_streaming && !ctx->core_streaming) { + if (!ctx->stream_configured) { + vxd_dec_return_all_buffers(ctx, vq, VB2_BUF_STATE_ERROR); + return -EINVAL; + } + ctx->eos = FALSE; + ctx->stop_initiated = FALSE; + ctx->flag_last = FALSE; + ret = core_stream_play(ctx->res_str_id); + if (ret) { + vxd_dec_return_all_buffers(ctx, vq, VB2_BUF_STATE_ERROR); + return ret; + } + ctx->core_streaming = TRUE; + ctx->aborting = 0; + } + + return 0; +} + +static void vxd_dec_stop_streaming(struct vb2_queue *vq) +{ + struct vxd_dec_ctx *ctx = vb2_get_drv_priv(vq); + struct list_head *list; + struct list_head *temp; + struct vxd_buffer *buf = NULL; + struct vxd_mapping *mapping = NULL; + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + ctx->src_streaming = FALSE; + else + ctx->dst_streaming = FALSE; + + if (!ctx->stream_created) { + vxd_dec_return_all_buffers(ctx, vq, VB2_BUF_STATE_ERROR); + return; + } + + if (ctx->core_streaming) { + core_stream_stop(ctx->res_str_id); + ctx->core_streaming = FALSE; + + core_stream_flush(ctx->res_str_id, TRUE); + } + /* unmap all the output and capture plane buffers */ + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { + list_for_each(list, &ctx->out_buffers) { + buf = list_entry(list, struct vxd_buffer, list); + core_stream_unmap_buf_sg(buf->buf_map_id); + buf->mapped = FALSE; + __list_del_entry(&buf->list); + } + } else { + list_for_each_safe(list, temp, &ctx->reuse_queue) { + buf = list_entry(list, struct vxd_buffer, list); + list_move_tail(&buf->list, &ctx->cap_buffers); + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, &buf->buffer.vb); + } + + list_for_each(list, &ctx->cap_buffers) { + buf = list_entry(list, struct vxd_buffer, list); + __list_del_entry(&buf->list); + } + + list_for_each(list, &ctx->cap_mappings) { + mapping = list_entry(list, struct vxd_mapping, list); + core_stream_unmap_buf_sg(mapping->buf_map_id); + mapping->buf->mapped = FALSE; + __list_del_entry(&mapping->list); + } + } + + ctx->flag_last = FALSE; + vxd_dec_return_all_buffers(ctx, vq, VB2_BUF_STATE_ERROR); +} + +static const struct vb2_ops vxd_dec_video_ops = { + .queue_setup = vxd_dec_queue_setup, + .buf_prepare = vxd_dec_buf_prepare, + .buf_queue = vxd_dec_buf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = vxd_dec_start_streaming, + .stop_streaming = vxd_dec_stop_streaming, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + struct vxd_dec_ctx *ctx = priv; + struct vxd_dev *vxd = ctx->dev; + int ret = 0; + + /* src_vq */ + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct vxd_buffer); + src_vq->ops = &vxd_dec_video_ops; + src_vq->mem_ops = &vb2_dma_sg_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = vxd->mutex_queue; + src_vq->dev = vxd->v4l2_dev.dev; + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + /* dst_vq */ + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct vxd_buffer); + dst_vq->ops = &vxd_dec_video_ops; +#ifdef CAPTURE_CONTIG_ALLOC + dst_vq->mem_ops = &vb2_dma_contig_memops; +#else + dst_vq->mem_ops = &vb2_dma_sg_memops; +#endif + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = vxd->mutex_queue; + dst_vq->dev = vxd->v4l2_dev.dev; + ret = vb2_queue_init(dst_vq); + if (ret) { + vb2_queue_release(src_vq); + return ret; + } + + return ret; +} + +static int vxd_dec_open(struct file *file) +{ + struct vxd_dev *vxd = video_drvdata(file); + struct vxd_dec_ctx *ctx; + struct vxd_dec_q_data *s_q_data; + struct v4l2_ctrl_handler *v4l2_ctrl_hdl; + + int i, ret = 0; + + dev_dbg(vxd->dev, "%s:%d vxd %p\n", __func__, __LINE__, vxd); + + if (vxd->no_fw) { + dev_err(vxd->dev, "Error!! fw binary is not present"); + return -1; + } + + mutex_lock_nested(vxd->mutex, SUBCLASS_BASE); + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + mutex_unlock(vxd->mutex); + return -ENOMEM; + } + ctx->dev = vxd; + + v4l2_ctrl_hdl = &ctx->v4l2_ctrl_hdl; + + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + + s_q_data = &ctx->q_data[Q_DATA_SRC]; + s_q_data->fmt = &vxd_dec_formats[0]; + s_q_data->width = 1920; + s_q_data->height = 1080; + for (i = 0; i < s_q_data->fmt->num_planes; i++) { + s_q_data->bytesperline[i] = s_q_data->width; + s_q_data->size_image[i] = s_q_data->bytesperline[i] * s_q_data->height; + } + + ctx->q_data[Q_DATA_DST] = *s_q_data; + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vxd->m2m_dev, ctx, &queue_init); + if (IS_ERR_VALUE((unsigned long)ctx->fh.m2m_ctx)) { + ret = (long)(ctx->fh.m2m_ctx); + goto exit; + } + + v4l2_fh_add(&ctx->fh); + + v4l2_ctrl_handler_init(v4l2_ctrl_hdl, 6); + v4l2_ctrl_new_custom(v4l2_ctrl_hdl, &vxd_max_dec_frame_buffering, NULL); + v4l2_ctrl_new_custom(v4l2_ctrl_hdl, &vxd_override_spec_dpb_buffers, NULL); + v4l2_ctrl_new_custom(v4l2_ctrl_hdl, &vxd_img_extra_decode_buffers, NULL); + v4l2_ctrl_new_custom(v4l2_ctrl_hdl, &vxd_display_pipeline_size, NULL); + if (ctx->v4l2_ctrl_hdl.error) { + dev_err(vxd->dev, "failed to create custom controls\n"); + ret = -ENODEV; + goto exit; + } + + ctx->fh.ctrl_handler = &ctx->v4l2_ctrl_hdl; + v4l2_ctrl_handler_setup(&ctx->v4l2_ctrl_hdl); + + ret = idr_alloc_cyclic(vxd->streams, &ctx->stream, VXD_MIN_STREAM_ID, VXD_MAX_STREAM_ID, + GFP_KERNEL); + if (ret < VXD_MIN_STREAM_ID || ret > VXD_MAX_STREAM_ID) { + dev_err(vxd->dev, "%s: stream id creation failed!\n", + __func__); + ret = -EFAULT; + goto exit; + } + + ctx->stream.id = ret; + ctx->stream.ctx = ctx; + + ctx->stream_created = FALSE; + ctx->stream_configured = FALSE; + ctx->src_streaming = FALSE; + ctx->dst_streaming = FALSE; + ctx->core_streaming = FALSE; + ctx->eos = FALSE; + ctx->stop_initiated = FALSE; + ctx->flag_last = FALSE; + + lst_init(&ctx->seg_list); + for (i = 0; i < MAX_SEGMENTS; i++) + lst_add(&ctx->seg_list, &ctx->bstr_segments[i]); + + if (vxd_create_ctx(vxd, ctx)) + goto out_idr_remove; + + ctx->stream.mmu_ctx = ctx->mmu_ctx; + ctx->stream.ptd = ctx->ptd; + + ctx->mutex = kzalloc(sizeof(*ctx->mutex), GFP_KERNEL); + if (!ctx->mutex) { + ret = -ENOMEM; + goto out_idr_remove; + } + mutex_init(ctx->mutex); + + ctx->mutex2 = kzalloc(sizeof(*ctx->mutex), GFP_KERNEL); + if (!ctx->mutex2) { + ret = -ENOMEM; + goto out_idr_remove; + } + mutex_init(ctx->mutex2); + + INIT_LIST_HEAD(&ctx->items_done); + INIT_LIST_HEAD(&ctx->reuse_queue); + INIT_LIST_HEAD(&ctx->return_queue); + INIT_LIST_HEAD(&ctx->out_buffers); + INIT_LIST_HEAD(&ctx->cap_buffers); + INIT_LIST_HEAD(&ctx->cap_mappings); + + mutex_unlock(vxd->mutex); + + return 0; + +out_idr_remove: + idr_remove(vxd->streams, ctx->stream.id); + +exit: + v4l2_fh_exit(&ctx->fh); + get_work_buff(ctx->work, TRUE); + kfree(ctx->work); + kfree(ctx); + mutex_unlock(vxd->mutex); + return ret; +} + +static int vxd_dec_release(struct file *file) +{ + struct vxd_dev *vxd = video_drvdata(file); + struct vxd_dec_ctx *ctx = file2ctx(file); + struct bspp_ddbuf_array_info *fw_sequ = ctx->fw_sequ; + struct bspp_ddbuf_array_info *fw_pps = ctx->fw_pps; + int i, ret = 0; + struct vxd_dec_q_data *s_q_data; + struct list_head *list; + struct list_head *temp; + struct vxd_buffer *buf = NULL; + struct vxd_mapping *mapping = NULL; + + s_q_data = &ctx->q_data[Q_DATA_SRC]; + if (ctx->core_streaming) { + core_stream_stop(ctx->res_str_id); + ctx->core_streaming = FALSE; + + core_stream_flush(ctx->res_str_id, TRUE); + } + + list_for_each(list, &ctx->out_buffers) { + buf = list_entry(list, struct vxd_buffer, list); + core_stream_unmap_buf_sg(buf->buf_map_id); + buf->mapped = FALSE; + __list_del_entry(&buf->list); + } + + list_for_each(list, &ctx->cap_buffers) { + buf = list_entry(list, struct vxd_buffer, list); + __list_del_entry(&buf->list); + } + + list_for_each_safe(list, temp, &ctx->reuse_queue) { + buf = list_entry(list, struct vxd_buffer, list); + core_stream_unmap_buf_sg(buf->buf_map_id); + buf->mapped = FALSE; + __list_del_entry(&buf->list); + } + + list_for_each(list, &ctx->cap_mappings) { + mapping = list_entry(list, struct vxd_mapping, list); + core_stream_unmap_buf_sg(mapping->buf_map_id); + __list_del_entry(&mapping->list); + } + if (ctx->stream_created) { + bspp_stream_destroy(ctx->bspp_context); + + for (i = 0; i < MAX_SEQUENCES; i++) { + core_stream_unmap_buf(fw_sequ[i].ddbuf_info.bufmap_id); + img_mem_free(ctx->mem_ctx, fw_sequ[i].ddbuf_info.buf_id); + } + + if (s_q_data->fmt->std != VDEC_STD_JPEG) { + for (i = 0; i < MAX_PPSS; i++) { + core_stream_unmap_buf(fw_pps[i].ddbuf_info.bufmap_id); + img_mem_free(ctx->mem_ctx, fw_pps[i].ddbuf_info.buf_id); + } + } + core_stream_destroy(ctx->res_str_id); + ctx->stream_created = FALSE; + } + + mutex_lock_nested(vxd->mutex, SUBCLASS_BASE); + + vxd_destroy_ctx(vxd, ctx); + + idr_remove(vxd->streams, ctx->stream.id); + + v4l2_fh_del(&ctx->fh); + + v4l2_fh_exit(&ctx->fh); + + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + + mutex_destroy(ctx->mutex); + kfree(ctx->mutex); + ctx->mutex = NULL; + + get_work_buff(ctx->work, TRUE); + kfree(ctx->work); + kfree(ctx); + + mutex_unlock(vxd->mutex); + + return ret; +} + +static int vxd_dec_querycap(struct file *file, void *priv, struct v4l2_capability *cap) +{ + strncpy(cap->driver, IMG_VXD_DEC_MODULE_NAME, sizeof(cap->driver) - 1); + strncpy(cap->card, IMG_VXD_DEC_MODULE_NAME, sizeof(cap->card) - 1); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", IMG_VXD_DEC_MODULE_NAME); + cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int __enum_fmt(struct v4l2_fmtdesc *f, unsigned int type) +{ + int i, index; + struct vxd_dec_fmt *fmt = NULL; + index = 0; + for (i = 0; i < ARRAY_SIZE(vxd_dec_formats); ++i) { + if (vxd_dec_formats[i].type & type) { + if (index == f->index) { + fmt = &vxd_dec_formats[i]; + break; + } + index++; + } + } + + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->fourcc; + return 0; +} + +static int vxd_dec_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) +{ + if (V4L2_TYPE_IS_OUTPUT(f->type)) + return __enum_fmt(f, IMG_DEC_FMT_TYPE_OUTPUT); + + return __enum_fmt(f, IMG_DEC_FMT_TYPE_CAPTURE); +} + +static struct vxd_dec_fmt *find_format(struct v4l2_format *f, unsigned int type) +{ + int i; + for (i = 0; i < ARRAY_SIZE(vxd_dec_formats); ++i) { + if (vxd_dec_formats[i].fourcc == f->fmt.pix_mp.pixelformat && + vxd_dec_formats[i].type == type) + return &vxd_dec_formats[i]; + } + return NULL; +} + +static unsigned int get_sizeimage(int w, int h, struct vxd_dec_fmt *fmt, int plane) +{ + switch (fmt->fourcc) { + case V4L2_PIX_FMT_YUV420M: + return ((plane == 0) ? (w * h) : (w * h / 2)); + case V4L2_PIX_FMT_YUV422M: + return (w * h); + default: + return (w * h * fmt->size_num / fmt->size_den); + } + + return 0; +} + +static unsigned int get_stride(int w, struct vxd_dec_fmt *fmt) +{ + return (ALIGN(w, HW_ALIGN) * fmt->bytes_pp); +} + +/* + * @ Function vxd_get_header_info + * Run bspp stream submit and preparse once before device_run + * To retrieve header information + */ +static int vxd_get_header_info(void *priv) +{ + struct vxd_dec_ctx *ctx = priv; + struct vxd_dev *vxd_dev = ctx->dev; + struct device *dev = vxd_dev->v4l2_dev.dev; + struct vb2_v4l2_buffer *src_vb; + struct vxd_buffer *src_vxdb; + struct vxd_buffer *dst_vxdb; + struct bspp_preparsed_data *preparsed_data; + unsigned int data_size; + int ret; + + /* + * Checking for queued buffer. + * If no next buffer present, do not get information from header. + * Else, get header information and store for later use. + */ + src_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + if (!src_vb) { + dev_warn(dev, "get_header_info Next src buffer is null\n"); + return IMG_ERROR_INVALID_PARAMETERS; + } + mutex_lock_nested(ctx->mutex, SUBCLASS_VXD_V4L2); + + src_vxdb = container_of(src_vb, struct vxd_buffer, buffer.vb); + /* Setting dst_vxdb to arbitrary value (using src_vb) for now */ + dst_vxdb = container_of(src_vb, struct vxd_buffer, buffer.vb); + + preparsed_data = &dst_vxdb->preparsed_data; + + data_size = vb2_get_plane_payload(&src_vxdb->buffer.vb.vb2_buf, 0); + + ret = bspp_stream_submit_buffer(ctx->bspp_context, + &src_vxdb->bstr_info, + src_vxdb->buf_map_id, + data_size, NULL, + VDEC_BSTRELEMENT_UNSPECIFIED); + if (ret) { + dev_err(dev, "get_header_info bspp_stream_submit_buffer failed %d\n", ret); + return ret; + } + mutex_unlock(ctx->mutex); + + ret = bspp_stream_preparse_buffers(ctx->bspp_context, NULL, 0, + &ctx->seg_list, + preparsed_data, ctx->eos); + if (ret) { + dev_err(dev, "get_header_info bspp_stream_preparse_buffers failed %d\n", ret); + return ret; + } + + if (preparsed_data->sequ_hdr_info.com_sequ_hdr_info.max_frame_size.height && + preparsed_data->sequ_hdr_info.com_sequ_hdr_info.max_ref_frame_num) { + ctx->height = preparsed_data->sequ_hdr_info.com_sequ_hdr_info.max_frame_size.height; + ctx->max_num_ref_frames = + preparsed_data->sequ_hdr_info.com_sequ_hdr_info.max_ref_frame_num; + + /* save off the sequence header to the context structure */ + memcpy(&ctx->comseq_hdr_info, &(preparsed_data->sequ_hdr_info.com_sequ_hdr_info), + sizeof(struct vdec_comsequ_hdrinfo)); + } else { + dev_err(dev, "get_header_info preparsed data is null %d\n", ret); + return ret; + } + + return 0; +} + +static int vxd_dec_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct vxd_dec_ctx *ctx = file2ctx(file); + struct vxd_dec_q_data *q_data; + struct vxd_dev *vxd_dev = ctx->dev; + unsigned int i = 0; + int ret = 0; + + q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->pixelformat = q_data->fmt->fourcc; + pix_mp->num_planes = q_data->fmt->num_planes; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + /* The buffer contains compressed image. */ + pix_mp->width = ctx->width; + pix_mp->height = ctx->height; + pix_mp->plane_fmt[0].bytesperline = 0; + pix_mp->plane_fmt[0].sizeimage = q_data->size_image[0]; + } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + /* The buffer contains decoded YUV image. */ + pix_mp->width = ctx->width; + pix_mp->height = ctx->height; + for (i = 0; i < q_data->fmt->num_planes; i++) { + pix_mp->plane_fmt[i].bytesperline = get_stride(pix_mp->width, q_data->fmt); + pix_mp->plane_fmt[i].sizeimage = get_sizeimage + (pix_mp->plane_fmt[i].bytesperline, + ctx->height, q_data->fmt, i); + } + } else { + dev_err(vxd_dev->v4l2_dev.dev, "Wrong V4L2_format type\n"); + return -EINVAL; + } + + return ret; +} + +static int vxd_dec_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct vxd_dec_ctx *ctx = file2ctx(file); + struct vxd_dev *vxd_dev = ctx->dev; + struct vxd_dec_fmt *fmt; + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt; + unsigned int i = 0; + int ret = 0; + + pix_mp->width = ALIGN(pix_mp->width, HW_ALIGN); + pix_mp->height = ALIGN(pix_mp->height, HW_ALIGN); + + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + fmt = find_format(f, IMG_DEC_FMT_TYPE_OUTPUT); + if (!fmt) { + dev_err(vxd_dev->v4l2_dev.dev, "Unsupported format for source.\n"); + return -EINVAL; + } + /* + * Allocation for NV12 input frame size: + */ + plane_fmt[0].sizeimage = (ALIGN(pix_mp->width, HW_ALIGN) * + ALIGN(pix_mp->height, HW_ALIGN) * 3)/2; + } else { + fmt = find_format(f, IMG_DEC_FMT_TYPE_CAPTURE); + if (!fmt) { + dev_err(vxd_dev->v4l2_dev.dev, "Unsupported format for dest.\n"); + return -EINVAL; + } + for (i = 0; i < fmt->num_planes; i++) { + plane_fmt[i].bytesperline = get_stride(pix_mp->width, fmt); + plane_fmt[i].sizeimage = get_sizeimage(pix_mp->width, + pix_mp->height, fmt, i); + } + pix_mp->num_planes = fmt->num_planes; + pix_mp->flags = 0; + } + + if (pix_mp->field == V4L2_FIELD_ANY) + pix_mp->field = V4L2_FIELD_NONE; + + return ret; +} + +static int vxd_dec_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp; + struct vxd_dec_ctx *ctx = file2ctx(file); + struct vxd_dev *vxd_dev = ctx->dev; + struct device *dev = vxd_dev->v4l2_dev.dev; + struct vxd_dec_q_data *q_data; + struct vb2_queue *vq; + struct vxd_dec_fmt *fmt; + + int ret = 0; + unsigned char i = 0, j = 0; + + pix_mp = &f->fmt.pix_mp; + + if (!V4L2_TYPE_IS_OUTPUT(f->type)) { + int res = vxd_get_header_info(ctx); + + if (res == 0) + pix_mp->height = ctx->height; + } else { + ctx->width_orig = pix_mp->width; + ctx->height_orig = pix_mp->height; + } + + ret = vxd_dec_try_fmt(file, priv, f); + if (ret) + return ret; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + if (vb2_is_busy(vq)) { + dev_err(dev, "Queue is busy\n"); + return -EBUSY; + } + + q_data = get_q_data(ctx, f->type); + + if (!q_data) + return -EINVAL; + + ctx->width = pix_mp->width; + ctx->height = pix_mp->height; + + q_data->width = pix_mp->width; + q_data->height = pix_mp->height; + + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + q_data->fmt = find_format(f, IMG_DEC_FMT_TYPE_OUTPUT); + q_data->size_image[0] = pix_mp->plane_fmt[0].sizeimage; + + if (!ctx->stream_created) { + ctx->strcfgdata.vid_std = q_data->fmt->std; + + if (ctx->strcfgdata.vid_std == VDEC_STD_UNDEFINED) { + dev_err(dev, "Invalid input format\n"); + return -EINVAL; + } + ctx->strcfgdata.bstr_format = VDEC_BSTRFORMAT_ELEMENTARY; + ctx->strcfgdata.user_str_id = ctx->stream.id; + ctx->strcfgdata.update_yuv = FALSE; + ctx->strcfgdata.bandwidth_efficient = FALSE; + ctx->strcfgdata.disable_mvc = FALSE; + ctx->strcfgdata.full_scan = FALSE; + ctx->strcfgdata.immediate_decode = TRUE; + ctx->strcfgdata.intra_frame_closed_gop = TRUE; + + ctx->strcfgdata.max_dec_frame_buffering = ctx->max_dec_frame_buffering; + + ret = core_stream_create(ctx, &ctx->strcfgdata, &ctx->res_str_id); + if (ret) { + dev_err(dev, "Core stream create failed\n"); + return -EINVAL; + } + ctx->stream_created = TRUE; + if (ctx->opconfig_pending) { + ret = vxd_dec_submit_opconfig(ctx); + if (ret) { + dev_err(dev, "Output config failed\n"); + return -EINVAL; + } + } + + vxd_dec_alloc_bspp_resource(ctx, ctx->strcfgdata.vid_std); + ret = bspp_stream_create(&ctx->strcfgdata, + &ctx->bspp_context, + ctx->fw_sequ, + ctx->fw_pps); + if (ret) { + dev_err(dev, "BSPP stream create failed %d\n", ret); + return ret; + } + } else if (q_data->fmt != + find_format(f, IMG_DEC_FMT_TYPE_OUTPUT)) { + dev_err(dev, "Input format already set\n"); + return -EBUSY; + } + } else { + fmt = find_format(f, IMG_DEC_FMT_TYPE_CAPTURE); + for (i = 0; i < pix_mp->num_planes; i++) { + pix_mp->plane_fmt[i].sizeimage = + get_sizeimage(ctx->width_orig, + ctx->height_orig, fmt, i); + } + q_data->fmt = fmt; + for (i = 0; i < q_data->fmt->num_planes; i++) { + q_data->size_image[i] = + get_sizeimage(get_stride(pix_mp->width, q_data->fmt), + ctx->height, q_data->fmt, i); + } + + ctx->str_opcfg.pixel_info.pixfmt = q_data->fmt->pixfmt; + ctx->str_opcfg.pixel_info.chroma_interleave = q_data->fmt->interleave; + ctx->str_opcfg.pixel_info.chroma_fmt = TRUE; + ctx->str_opcfg.pixel_info.chroma_fmt_idc = q_data->fmt->idc; + + if (q_data->fmt->pixfmt == IMG_PIXFMT_420PL12YUV10_MSB || + q_data->fmt->pixfmt == IMG_PIXFMT_422PL12YUV10_MSB) { + ctx->str_opcfg.pixel_info.mem_pkg = PIXEL_BIT10_MSB_MP; + ctx->str_opcfg.pixel_info.bitdepth_y = 10; + ctx->str_opcfg.pixel_info.bitdepth_c = 10; + } else { + ctx->str_opcfg.pixel_info.mem_pkg = PIXEL_BIT8_MP; + ctx->str_opcfg.pixel_info.bitdepth_y = 8; + ctx->str_opcfg.pixel_info.bitdepth_c = 8; + } + + ctx->str_opcfg.force_oold = FALSE; + + ctx->pict_bufcfg.coded_width = pix_mp->width; + ctx->pict_bufcfg.coded_height = pix_mp->height; + ctx->pict_bufcfg.pixel_fmt = q_data->fmt->pixfmt; + for (i = 0; i < pix_mp->num_planes; i++) { + q_data->bytesperline[i] = get_stride(q_data->width, q_data->fmt); + if (q_data->bytesperline[i] < + pix_mp->plane_fmt[0].bytesperline) + q_data->bytesperline[i] = + ALIGN(pix_mp->plane_fmt[0].bytesperline, HW_ALIGN); + pix_mp->plane_fmt[0].bytesperline = + q_data->bytesperline[i]; + ctx->pict_bufcfg.stride[i] = q_data->bytesperline[i]; + } + for (j = i; j < IMG_MAX_NUM_PLANES; j++) { + if ((i - 1) < 0) + i++; + ctx->pict_bufcfg.stride[j] = + q_data->bytesperline[i - 1]; + } + ctx->pict_bufcfg.stride_alignment = HW_ALIGN; + ctx->pict_bufcfg.byte_interleave = FALSE; + for (i = 0; i < pix_mp->num_planes; i++) { + unsigned int plane_size = + get_sizeimage(ctx->pict_bufcfg.stride[i], + ctx->pict_bufcfg.coded_height, + q_data->fmt, i); + ctx->pict_bufcfg.buf_size += ALIGN(plane_size, PAGE_SIZE); + ctx->pict_bufcfg.plane_size[i] = plane_size; + } + if (q_data->fmt->pixfmt == 86031 || + q_data->fmt->pixfmt == 81935) { + /* Handle the v4l2 multi-planar formats */ + ctx->str_opcfg.pixel_info.num_planes = 3; + ctx->pict_bufcfg.packed = FALSE; + for (i = 0; i < pix_mp->num_planes; i++) { + ctx->pict_bufcfg.chroma_offset[i] = + ALIGN(pix_mp->plane_fmt[i].sizeimage, PAGE_SIZE); + ctx->pict_bufcfg.chroma_offset[i] += + (i ? ctx->pict_bufcfg.chroma_offset[i - 1] : 0); + } + } else { + /* IMG Decoders support only multi-planar formats */ + ctx->str_opcfg.pixel_info.num_planes = 2; + ctx->pict_bufcfg.packed = TRUE; + ctx->pict_bufcfg.chroma_offset[0] = 0; + ctx->pict_bufcfg.chroma_offset[1] = 0; + } + + vxd_dec_submit_opconfig(ctx); + } + + return ret; +} + +static int vxd_dec_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) +{ + if (sub->type != V4L2_EVENT_EOS) + return -EINVAL; + + v4l2_event_subscribe(fh, sub, 0, NULL); + return 0; +} + +static int vxd_dec_try_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) +{ + if (cmd->cmd != V4L2_DEC_CMD_STOP) + return -EINVAL; + + return 0; +} + +static int vxd_dec_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) +{ + struct vxd_dec_ctx *ctx = file2ctx(file); + + if (cmd->cmd != V4L2_DEC_CMD_STOP) + return -EINVAL; + +#ifdef DEBUG_DECODER_DRIVER + pr_info("%s CMD_STOP\n", __func__); +#endif + /* + * When stop command is received, notify device_run if it is + * scheduled to run, or tell the decoder that eos has + * happened. + */ + mutex_lock_nested(ctx->mutex, SUBCLASS_VXD_V4L2); + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("V4L2 src bufs not empty, set a flag to notify device_run\n"); +#endif + ctx->stop_initiated = TRUE; + mutex_unlock(ctx->mutex); + } else { + if (ctx->num_decoding) { +#ifdef DEBUG_DECODER_DRIVER + pr_info("buffers are still being decoded, so just set eos flag\n"); +#endif + ctx->eos = TRUE; + mutex_unlock(ctx->mutex); + } else { + mutex_unlock(ctx->mutex); +#ifdef DEBUG_DECODER_DRIVER + pr_info("All buffers are decoded, so issue dummy stream end\n"); +#endif + vxd_return_resource((void *)ctx, VXD_CB_STR_END, 0, 0); + } + } + + return 0; +} + +static int vxd_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vxd_dec_ctx *ctx = file2ctx(file); + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + s->r.left = 0; + s->r.top = 0; + s->r.width = ctx->width; + s->r.height = ctx->height; + break; + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + s->r.left = 0; + s->r.top = 0; + s->r.width = ctx->width_orig; + s->r.height = ctx->height_orig; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ioctl_ops vxd_dec_ioctl_ops = { + .vidioc_querycap = vxd_dec_querycap, + + .vidioc_enum_fmt_vid_cap = vxd_dec_enum_fmt, + .vidioc_g_fmt_vid_cap_mplane = vxd_dec_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = vxd_dec_try_fmt, + .vidioc_s_fmt_vid_cap_mplane = vxd_dec_s_fmt, + + .vidioc_enum_fmt_vid_out = vxd_dec_enum_fmt, + .vidioc_g_fmt_vid_out_mplane = vxd_dec_g_fmt, + .vidioc_try_fmt_vid_out_mplane = vxd_dec_try_fmt, + .vidioc_s_fmt_vid_out_mplane = vxd_dec_s_fmt, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = vxd_dec_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_try_decoder_cmd = vxd_dec_try_cmd, + .vidioc_decoder_cmd = vxd_dec_cmd, + + .vidioc_g_selection = vxd_g_selection, +}; + +static const struct v4l2_file_operations vxd_dec_fops = { + .owner = THIS_MODULE, + .open = vxd_dec_open, + .release = vxd_dec_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static void device_run(void *priv) +{ + struct vxd_dec_ctx *ctx = priv; + struct vxd_dev *vxd_dev = ctx->dev; + struct device *dev = vxd_dev->v4l2_dev.dev; + struct vb2_v4l2_buffer *src_vb; + struct vb2_v4l2_buffer *dst_vb; + struct vxd_buffer *src_vxdb; + struct vxd_buffer *dst_vxdb; + struct bspp_bitstr_seg *item = NULL, *next = NULL; + struct bspp_preparsed_data *preparsed_data; + unsigned int data_size; + int ret; + struct timespec64 time; + static int cnt; + int i; + + mutex_lock(ctx->mutex2); + mutex_lock_nested(ctx->mutex, SUBCLASS_VXD_V4L2); + ctx->num_decoding++; + + src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + if (!src_vb) { + dev_err(dev, "Next src buffer is null\n"); + mutex_unlock(ctx->mutex); + mutex_unlock(ctx->mutex2); + return; + } + + dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!dst_vb) { + dev_err(dev, "Next dst buffer is null\n"); + mutex_unlock(ctx->mutex); + mutex_unlock(ctx->mutex2); + return; + } + + + dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; + + src_vxdb = container_of(src_vb, struct vxd_buffer, buffer.vb); + dst_vxdb = container_of(dst_vb, struct vxd_buffer, buffer.vb); + + preparsed_data = &dst_vxdb->preparsed_data; + + data_size = vb2_get_plane_payload(&src_vxdb->buffer.vb.vb2_buf, 0); + + ret = bspp_stream_submit_buffer(ctx->bspp_context, + &src_vxdb->bstr_info, + src_vxdb->buf_map_id, + data_size, NULL, + VDEC_BSTRELEMENT_UNSPECIFIED); + if (ret) + dev_err(dev, "bspp_stream_submit_buffer failed %d\n", ret); + + if (ctx->stop_initiated && + (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) == 0)) + ctx->eos = TRUE; + + mutex_unlock(ctx->mutex); + + ret = bspp_stream_preparse_buffers(ctx->bspp_context, NULL, 0, &ctx->seg_list, + preparsed_data, ctx->eos); + if (ret) + dev_err(dev, "bspp_stream_preparse_buffers failed %d\n", ret); + + ktime_get_real_ts64(&time); + vxd_dev->time_drv[cnt].start_time = timespec64_to_ns(&time); + vxd_dev->time_drv[cnt].id = dst_vxdb->buf_map_id; + cnt++; + + if (cnt >= ARRAY_SIZE(vxd_dev->time_drv)) + cnt = 0; + + core_stream_fill_pictbuf(dst_vxdb->buf_map_id); + + if (preparsed_data->new_sequence) { + src_vxdb->seq_unit.str_unit_type = + VDECDD_STRUNIT_SEQUENCE_START; + src_vxdb->seq_unit.str_unit_handle = ctx; + src_vxdb->seq_unit.err_flags = 0; + src_vxdb->seq_unit.dd_data = NULL; + src_vxdb->seq_unit.seq_hdr_info = + &preparsed_data->sequ_hdr_info; + src_vxdb->seq_unit.seq_hdr_id = 0; + src_vxdb->seq_unit.closed_gop = TRUE; + src_vxdb->seq_unit.eop = FALSE; + src_vxdb->seq_unit.pict_hdr_info = NULL; + src_vxdb->seq_unit.dd_pict_data = NULL; + src_vxdb->seq_unit.last_pict_in_seq = FALSE; + src_vxdb->seq_unit.str_unit_tag = NULL; + src_vxdb->seq_unit.decode = FALSE; + src_vxdb->seq_unit.features = 0; + core_stream_submit_unit(ctx->res_str_id, &src_vxdb->seq_unit); + } + + src_vxdb->pic_unit.str_unit_type = VDECDD_STRUNIT_PICTURE_START; + src_vxdb->pic_unit.str_unit_handle = ctx; + src_vxdb->pic_unit.err_flags = 0; + /* Move the processed segments to the submission buffer */ + for (i = 0; i < BSPP_MAX_PICTURES_PER_BUFFER; i++) { + item = lst_first(&preparsed_data->picture_data.pre_pict_seg_list[i]); + while (item) { + next = lst_next(item); + lst_remove(&preparsed_data->picture_data.pre_pict_seg_list[i], item); + lst_add(&src_vxdb->pic_unit.bstr_seg_list, item); + item = next; + } + /* Move the processed segments to the submission buffer */ + item = lst_first(&preparsed_data->picture_data.pict_seg_list[i]); + while (item) { + next = lst_next(item); + lst_remove(&preparsed_data->picture_data.pict_seg_list[i], item); + lst_add(&src_vxdb->pic_unit.bstr_seg_list, item); + item = next; + } + } + + src_vxdb->pic_unit.dd_data = NULL; + src_vxdb->pic_unit.seq_hdr_info = NULL; + src_vxdb->pic_unit.seq_hdr_id = 0; + if (preparsed_data->new_sequence) + src_vxdb->pic_unit.closed_gop = TRUE; + else + src_vxdb->pic_unit.closed_gop = FALSE; + src_vxdb->pic_unit.eop = TRUE; + src_vxdb->pic_unit.eos = ctx->eos; + src_vxdb->pic_unit.pict_hdr_info = + &preparsed_data->picture_data.pict_hdr_info; + src_vxdb->pic_unit.dd_pict_data = NULL; + src_vxdb->pic_unit.last_pict_in_seq = FALSE; + src_vxdb->pic_unit.str_unit_tag = NULL; + src_vxdb->pic_unit.decode = FALSE; + src_vxdb->pic_unit.features = 0; + core_stream_submit_unit(ctx->res_str_id, &src_vxdb->pic_unit); + + src_vxdb->end_unit.str_unit_type = VDECDD_STRUNIT_PICTURE_END; + src_vxdb->end_unit.str_unit_handle = ctx; + src_vxdb->end_unit.err_flags = 0; + src_vxdb->end_unit.dd_data = NULL; + src_vxdb->end_unit.seq_hdr_info = NULL; + src_vxdb->end_unit.seq_hdr_id = 0; + src_vxdb->end_unit.closed_gop = FALSE; + src_vxdb->end_unit.eop = FALSE; + src_vxdb->end_unit.eos = ctx->eos; + src_vxdb->end_unit.pict_hdr_info = NULL; + src_vxdb->end_unit.dd_pict_data = NULL; + src_vxdb->end_unit.last_pict_in_seq = FALSE; + src_vxdb->end_unit.str_unit_tag = NULL; + src_vxdb->end_unit.decode = FALSE; + src_vxdb->end_unit.features = 0; + core_stream_submit_unit(ctx->res_str_id, &src_vxdb->end_unit); + mutex_unlock(ctx->mutex2); + +} + +static int job_ready(void *priv) +{ + struct vxd_dec_ctx *ctx = priv; + + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < 1 || + v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < 1 || + !ctx->core_streaming) + return 0; + + return 1; +} + +static void job_abort(void *priv) +{ + struct vxd_dec_ctx *ctx = priv; + + /* Cancel the transaction at next callback */ + ctx->aborting = 1; +} + +static const struct v4l2_m2m_ops m2m_ops = { + .device_run = device_run, + .job_ready = job_ready, + .job_abort = job_abort, +}; + +static const struct of_device_id vxd_dec_of_match[] = { + {.compatible = "img,d5500-vxd"}, + { /* end */}, +}; +MODULE_DEVICE_TABLE(of, vxd_dec_of_match); + +static int vxd_dec_probe(struct platform_device *pdev) +{ + struct vxd_dev *vxd; + struct resource *res; + const struct of_device_id *of_dev_id; + int ret; + int module_irq; + struct video_device *vfd; + + struct heap_config *heap_configs; + int num_heaps; + unsigned int i_heap_id; + /* Protect structure fields */ + spinlock_t **lock; + + of_dev_id = of_match_device(vxd_dec_of_match, &pdev->dev); + if (!of_dev_id) { + dev_err(&pdev->dev, "%s: Unable to match device\n", __func__); + return -ENODEV; + } + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); + if (ret) { + dev_err(&pdev->dev, "%s: Failed to Set DMA Mask\n", __func__); + return ret; + } + + vxd = devm_kzalloc(&pdev->dev, sizeof(*vxd), GFP_KERNEL); + if (!vxd) + return -ENOMEM; + + vxd->dev = &pdev->dev; + vxd->plat_dev = pdev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + vxd->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR_VALUE((unsigned long)vxd->reg_base)) + return (long)(vxd->reg_base); + + module_irq = platform_get_irq(pdev, 0); + if (module_irq < 0) + return -ENXIO; + vxd->module_irq = module_irq; +#ifdef ERROR_RECOVERY_SIMULATION + g_module_irq = module_irq; +#endif + + heap_configs = vxd_dec_heap_configs; + num_heaps = ARRAY_SIZE(vxd_dec_heap_configs); + + vxd->mutex = kzalloc(sizeof(*vxd->mutex), GFP_KERNEL); + if (!vxd->mutex) + return -ENOMEM; + + mutex_init(vxd->mutex); + + vxd->mutex_queue = kzalloc(sizeof(*vxd->mutex_queue), GFP_KERNEL); + if (!vxd->mutex_queue) + return -ENOMEM; + + mutex_init(vxd->mutex_queue); + + platform_set_drvdata(pdev, vxd); + + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "%s: failed to enable clock, status = %d\n", __func__, ret); + goto exit; + } + + /* Read HW properties */ + ret = vxd_pvdec_get_props(vxd->dev, vxd->reg_base, &vxd->props); + if (ret) { + dev_err(&pdev->dev, "%s: failed to fetch core properties!\n", __func__); + ret = -ENXIO; + goto out_put_sync; + } + vxd->mmu_config_addr_width = VXD_EXTRN_ADDR_WIDTH(vxd->props); +#ifdef DEBUG_DECODER_DRIVER + dev_info(&pdev->dev, "hw:%u.%u.%u, num_pix: %d, num_ent: %d, mmu: %d, MTX RAM: %d\n", + VXD_MAJ_REV(vxd->props), + VXD_MIN_REV(vxd->props), + VXD_MAINT_REV(vxd->props), + VXD_NUM_PIX_PIPES(vxd->props), + VXD_NUM_ENT_PIPES(vxd->props), + VXD_EXTRN_ADDR_WIDTH(vxd->props), + vxd->props.mtx_ram_size); +#endif + + INIT_LIST_HEAD(&vxd->msgs); + INIT_LIST_HEAD(&vxd->pend); + + /* initialize memory manager */ + ret = img_mem_init(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize memory\n"); + ret = -ENOMEM; + goto out_put_sync; + } + vxd->streams = kzalloc(sizeof(*vxd->streams), GFP_KERNEL); + if (!vxd->streams) { + ret = -ENOMEM; + goto out_init; + } + + idr_init(vxd->streams); + + ret = vxd_init(&pdev->dev, vxd, heap_configs, num_heaps); + if (ret) { + dev_err(&pdev->dev, "%s: main component initialisation failed!\n", __func__); + goto out_idr_init; + } + + /* initialize core */ + i_heap_id = vxd_g_internal_heap_id(); + if (i_heap_id < 0) { + dev_err(&pdev->dev, "%s: Invalid internal heap id", __func__); + goto out_vxd_init; + } + ret = core_initialise(vxd, i_heap_id, vxd_return_resource); + if (ret) { + dev_err(&pdev->dev, "%s: core initialization failed!", __func__); + goto out_vxd_init; + } + + vxd->fw_refcnt = 0; + vxd->hw_on = 0; + +#ifdef DEBUG_DECODER_DRIVER + vxd->hw_pm_delay = 10000; + vxd->hw_dwr_period = 10000; +#else + vxd->hw_pm_delay = 1000; + vxd->hw_dwr_period = 1000; +#endif + ret = vxd_prepare_fw(vxd); + if (ret) { + dev_err(&pdev->dev, "%s fw acquire failed!", __func__); + goto out_core_init; + } + + if (vxd->no_fw) { + dev_err(&pdev->dev, "%s fw acquire failed!", __func__); + goto out_core_init; + } + + lock = (spinlock_t **)&vxd->lock; + *lock = kzalloc(sizeof(spinlock_t), GFP_KERNEL); + + if (!(*lock)) { + pr_err("Memory allocation failed for spin-lock\n"); + ret = ENOMEM; + goto out_core_init; + } + spin_lock_init(*lock); + + ret = v4l2_device_register(&pdev->dev, &vxd->v4l2_dev); + if (ret) + goto out_clean_fw; + +#ifdef ERROR_RECOVERY_SIMULATION + /* + * create a sysfs entry here, to debug firmware error recovery. + */ + vxd_dec_kobject = kobject_create_and_add("vxd_decoder", kernel_kobj); + if (!vxd_dec_kobject) { + dev_err(&pdev->dev, "Failed to create kernel object\n"); + goto out_clean_fw; + } + + ret = sysfs_create_group(vxd_dec_kobject, &attr_group); + if (ret) { + dev_err(&pdev->dev, "Failed to create sysfs files\n"); + kobject_put(vxd_dec_kobject); + } +#endif + + vfd = video_device_alloc(); + if (!vfd) { + dev_err(&pdev->dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto out_v4l2_device; + } + + snprintf(vfd->name, sizeof(vfd->name), "%s", IMG_VXD_DEC_MODULE_NAME); + vfd->fops = &vxd_dec_fops; + vfd->ioctl_ops = &vxd_dec_ioctl_ops; + vfd->minor = -1; + vfd->release = video_device_release; + vfd->vfl_dir = VFL_DIR_M2M; + vfd->v4l2_dev = &vxd->v4l2_dev; + vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + vfd->lock = vxd->mutex; + + vxd->vfd_dec = vfd; + video_set_drvdata(vfd, vxd); + + ret = devm_request_threaded_irq(&pdev->dev, module_irq, (irq_handler_t)hard_isrcb, + (irq_handler_t)soft_thread_irq, IRQF_SHARED, + IMG_VXD_DEC_MODULE_NAME, pdev); + if (ret) { + dev_err(&pdev->dev, "failed to request irq\n"); + goto out_vid_dev; + } + + vxd->m2m_dev = v4l2_m2m_init(&m2m_ops); + if (IS_ERR_VALUE((unsigned long)vxd->m2m_dev)) { + dev_err(&pdev->dev, "Failed to init mem2mem device\n"); + ret = -EINVAL; + goto out_vid_dev; + } + + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); + if (ret) { + dev_err(&pdev->dev, "Failed to register video device\n"); + goto out_vid_reg; + } + v4l2_info(&vxd->v4l2_dev, "decoder registered as /dev/video%d\n", vfd->num); + + return 0; + +out_vid_reg: + v4l2_m2m_release(vxd->m2m_dev); + +out_vid_dev: + video_device_release(vfd); + +out_v4l2_device: + v4l2_device_unregister(&vxd->v4l2_dev); + +out_clean_fw: + vxd_clean_fw_resources(vxd); + +out_core_init: + core_deinitialise(); + +out_vxd_init: + vxd_deinit(vxd); + +out_idr_init: + idr_destroy(vxd->streams); + kfree(vxd->streams); + +out_init: + img_mem_exit(); + +out_put_sync: + pm_runtime_put_sync(&pdev->dev); + +exit: + pm_runtime_disable(&pdev->dev); + mutex_destroy(vxd->mutex); + kfree(vxd->mutex); + vxd->mutex = NULL; + + return ret; +} + +static int vxd_dec_remove(struct platform_device *pdev) +{ + struct vxd_dev *vxd = platform_get_drvdata(pdev); + + core_deinitialise(); + + vxd_clean_fw_resources(vxd); + vxd_deinit(vxd); + idr_destroy(vxd->streams); + kfree(vxd->streams); + get_delayed_work_buff(&vxd->dwork, TRUE); + kfree(&vxd->lock); + img_mem_exit(); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + kfree(vxd->dwork); + mutex_destroy(vxd->mutex); + mutex_destroy(vxd->mutex_queue); + kfree(vxd->mutex); + kfree(vxd->mutex_queue); + vxd->mutex = NULL; + vxd->mutex_queue = NULL; + + video_unregister_device(vxd->vfd_dec); + v4l2_m2m_release(vxd->m2m_dev); + v4l2_device_unregister(&vxd->v4l2_dev); + + return 0; +} + +static int __maybe_unused vxd_dec_suspend(struct device *dev) +{ + int ret = 0; + + ret = vxd_suspend_dev(dev); + if (ret) + dev_err(dev, "failed to suspend core hw!\n"); + + return ret; +} + +static int __maybe_unused vxd_dec_resume(struct device *dev) +{ + int ret = 0; + + ret = vxd_resume_dev(dev); + if (ret) + dev_err(dev, "failed to resume core hw!\n"); + + return ret; +} + +static UNIVERSAL_DEV_PM_OPS(vxd_dec_pm_ops, + vxd_dec_suspend, vxd_dec_resume, NULL); + +static struct platform_driver vxd_dec_driver = { + .probe = vxd_dec_probe, + .remove = vxd_dec_remove, + .driver = { + .name = "img_dec", + .pm = &vxd_dec_pm_ops, + .of_match_table = vxd_dec_of_match, + }, +}; +module_platform_driver(vxd_dec_driver); + +MODULE_AUTHOR("Prashanth Kumar Amai Sidraya Jayagond "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("IMG D5520 video decoder driver"); diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_binaries/ALL_CODECS_FW_ALL_pipes_2_contexts_8_hwconfig_1_bin.c b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_binaries/ALL_CODECS_FW_ALL_pipes_2_contexts_8_hwconfig_1_bin.c --- a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_binaries/ALL_CODECS_FW_ALL_pipes_2_contexts_8_hwconfig_1_bin.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_binaries/ALL_CODECS_FW_ALL_pipes_2_contexts_8_hwconfig_1_bin.c 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,29013 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Encoder FW binary file + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +/* note that order of defines has to match the structure declaration! + */ + +unsigned char *all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_define_names_array[] = { + "TOPAZHP_NUM_PIPES", + "TOPAZHP_MAX_BU_SUPPORT", + "MAX_REF_B_LEVELS_FW", + "SEI_INSERTION", + "TOPAZHP_MAX_NUM_STREAMS", +}; + +unsigned int all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_define_values_array[] = { + 2, + (TOPAZHP_MAX_BU_SUPPORT_HD), + 0, + 1, + 8, +}; + +unsigned int all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_text[] = { + 0x9040c001, + 0xc80993fe, + 0xc0000e42, + 0xc8290e00, + 0xcc3e8426, + 0xc8298420, + 0xceea8622, + 0x9e838660, + 0xc8099e43, + 0xcdd40d46, + 0xc8090d40, + 0xcdd60946, + 0xc8090900, + 0xc00a0e42, + 0xc8090e40, + 0xc00e87c2, + 0x9c1887c0, + 0x0c020802, + 0x09820d82, + 0x09020d02, + 0x08820c82, + 0x9320fffe, + 0xa401c838, + 0x0dc6c809, + 0x0d80cdd4, + 0x0e42c809, + 0x0c66b080, + 0x0882a992, + 0x9ff3a48d, + 0x93e0ffff, + 0x80819d13, + 0xa205f839, + 0x03070707, + 0x9e970685, + 0xc8090383, + 0xcdd60ac6, + 0xc8090aa0, + 0xcdd61ac4, + 0x060f1a80, + 0x07fac101, + 0x018d058d, + 0x9c62008f, + 0x9320ffff, + 0xc101060b, + 0x9c6206da, + 0x9380ffff, + 0x018d058d, + 0x460cb700, + 0x4594b780, + 0xa6059c01, + 0xc8090687, + 0xcdd60ac6, + 0xc8090aa0, + 0xcdd61ac4, + 0x060b1a80, + 0x06dac101, + 0xffff9c62, + 0xf9f89380, + 0xf9f8aa9d, + 0x9c22aa1d, + 0x420cb700, + 0xc000587c, + 0xe0003800, + 0xc0003800, + 0x9c22901a, + 0x9c8fc127, + 0x080a9c22, + 0x9c81c017, + 0x9c80c071, + 0x9c80c017, + 0x0d849c22, + 0x9e5a5db0, + 0x4018b960, + 0x0900c021, + 0x0940c00e, + 0xaa45f031, + 0xf0009dad, + 0x0910a261, + 0x9341ffff, + 0xc3fe9e5c, + 0xc02129c0, + 0xc0010a00, + 0xc00e3988, + 0x9dcd0a30, + 0xa1e1f000, + 0xc0219c22, + 0xd1100d80, + 0x9d3d05b7, + 0x2244aa61, + 0xffff7115, + 0x9c229384, + 0xd011a605, + 0xc3fe0eb2, + 0xc28029c0, + 0x020b5ab0, + 0x0a00c021, + 0x398cc001, + 0xc00e0685, + 0x9dcd0a30, + 0xa1e1f000, + 0xc00e9eab, + 0x0d020992, + 0x0902cff0, + 0x0a80c021, + 0x9bdbfff4, + 0x0ac0c00e, + 0x4018b960, + 0xaa619d5d, + 0xa225f231, + 0xffff0a90, + 0xb79f9361, + 0xb7bf7f6e, + 0x8c407fee, + 0xfffd9c22, + 0xf0129040, + 0x9e582d36, + 0xc0009e5a, + 0xc18093a4, + 0x9e515a0b, + 0xd2247500, + 0x9e825988, + 0x9c83c810, + 0x0106c101, + 0x4418b313, + 0x9080c000, + 0xa0c5f031, + 0x93c1ffff, + 0x11b6c101, + 0x90c0c000, + 0xa146d029, + 0x9120c000, + 0x9e540d02, + 0xb33474c0, + 0xc8104436, + 0xffff9c83, + 0x9c2292a1, + 0xa285f839, + 0xc00272d7, + 0x70d79022, + 0xc0009e59, + 0x0a8690a6, + 0x9100c000, + 0xd0101d04, + 0xc10104b4, + 0x0aff01b4, + 0xc0017c46, + 0xf0139124, + 0xc0012936, + 0xd12290a4, + 0x9e885e0b, + 0x5808c200, + 0x9e99610b, + 0x00947500, + 0xc81001b4, + 0xc2809c83, + 0xb3235908, + 0xc0004c18, + 0x9e9590e0, + 0xaa29e059, + 0xa209e059, + 0x9361ffff, + 0x1520c101, + 0x9100c000, + 0xa966c059, + 0xa126c059, + 0x9100c000, + 0x0a029e52, + 0x7088d012, + 0x9c83c810, + 0x9281ffff, + 0xf9f89e58, + 0x9c22aa9d, + 0x59300904, + 0x9d299da9, + 0x9e919e90, + 0x76c00005, + 0x8700c021, + 0x0da2c020, + 0x8500c021, + 0x0800c021, + 0x0c00c021, + 0x0c80c021, + 0x1db0d021, + 0x08820d08, + 0x8730c00e, + 0x8540c00e, + 0x0850c00e, + 0x0c60c00e, + 0x0cf0c00e, + 0x92a0c001, + 0xaa41d9d0, + 0xa95dd990, + 0x5a40c200, + 0x9e2e3244, + 0xa261f000, + 0xaa49d9d0, + 0xa945d9d0, + 0x5a40c200, + 0x9d8d3244, + 0xa261f000, + 0xaa51d9d0, + 0xa94dd9d0, + 0x5a40c200, + 0x9d8e3244, + 0xa261f000, + 0xaa59d9d0, + 0xa955d9d0, + 0x5a40c200, + 0x9d9e3244, + 0xa261f000, + 0x5e10d1a2, + 0xc3fe08a0, + 0xc0012a40, + 0x83853a08, + 0xa261f000, + 0x70460d84, + 0xfffe0d40, + 0x9c229166, + 0x8420a61d, + 0x0b820307, + 0xc001a19a, + 0xf04892a0, + 0xa91aaac6, + 0x9e6b7740, + 0xc001672b, + 0xf0489162, + 0x05d6a9ce, + 0xc3b41d84, + 0xc1019924, + 0xf208628b, + 0x018ba34a, + 0xc3b4058d, + 0x628b991c, + 0x6979d031, + 0x16ebd110, + 0xa041f208, + 0xa2c5f208, + 0x430cb780, + 0x0679d110, + 0xaa09f248, + 0xf2086009, + 0xb780a041, + 0x0128430c, + 0xa945f008, + 0x000a6005, + 0xa049f208, + 0x0b300b84, + 0x430cb780, + 0x5b90d3a4, + 0x0579d110, + 0xaa15f288, + 0xfffe71c8, + 0xb79f9086, + 0xb7bf7dee, + 0xb7df7e6e, + 0xb7ff7eee, + 0xc0027f6e, + 0x9c228c20, + 0xb7a0a60d, + 0x9e5e430c, + 0xf2489e9e, + 0xf248a9ae, + 0xd120aaa5, + 0x018b01d7, + 0xc3b41d84, + 0x9e8598da, + 0xc101636b, + 0x9eb366db, + 0xf2109e6b, + 0xc3b4a349, + 0xd13298d0, + 0xf210628b, + 0xc101a041, + 0xf210136a, + 0xb780a345, + 0xf248430c, + 0x6009aa09, + 0xa041f210, + 0x430cb780, + 0xaa05f208, + 0x000c6009, + 0xa049f210, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0x9c228c60, + 0x5db00d84, + 0xc0219e5c, + 0xc0100a00, + 0x9dcd0a00, + 0xa162f000, + 0x592809bc, + 0xcff05990, + 0xc00f2980, + 0xc021297c, + 0x31260d80, + 0x0d80c00e, + 0xf0009dbe, + 0x9c22a161, + 0x5db00d84, + 0x0992c00e, + 0xcff00d02, + 0xfff20902, + 0xaa1d91c0, + 0x09bc0405, + 0xd0117500, + 0xd0120e32, + 0xd0a2299e, + 0xc0015cc0, + 0xd2249004, + 0x9e545930, + 0x0a00c021, + 0x0a00c010, + 0xf0009dcd, + 0xc100a062, + 0x9e525a18, + 0x2a00cffc, + 0x0900c021, + 0x0930c010, + 0xf0009dad, + 0xc180a261, + 0xcff05a10, + 0xc0112a00, + 0xc0003a00, + 0xd22492e0, + 0x9e545930, + 0x0a00c021, + 0x0a10c010, + 0xf0009dcd, + 0x5958a062, + 0x9dcd0a20, + 0xa161f000, + 0x5a10c180, + 0x2a00cff0, + 0x3a00c031, + 0xc00f9e5a, + 0x324428fc, + 0x0d00c021, + 0xc00e3242, + 0x9dae0d00, + 0xa261f000, + 0xa61d9c22, + 0x8400c00a, + 0x430cb7c0, + 0x0802c004, + 0xb55fa011, + 0x74807dec, + 0xa945f208, + 0x7decb79f, + 0x7d74b57f, + 0x5b99c100, + 0x4422b340, + 0x5a18c380, + 0xa0117104, + 0x7c74b55f, + 0x7cecb53f, + 0xf248000d, + 0xf248a94d, + 0x9e4dab46, + 0xb7809e9f, + 0xb7a040cd, + 0xd0125eb4, + 0xc006136c, + 0xd0209244, + 0x9e7311a8, + 0x9811c3b4, + 0x701b9e6c, + 0x4434b304, + 0xb347711f, + 0xf2084454, + 0xf208a9c1, + 0x657daa29, + 0xb740008d, + 0xd0f2572b, + 0xd0200eae, + 0xb77f0138, + 0x74887468, + 0x2e81cffc, + 0x293ed3f1, + 0x9172c000, + 0x9e93a892, + 0x0a029e6b, + 0x0892010f, + 0xc000a21d, + 0xa8929120, + 0x9e6b0a02, + 0xa21d9e93, + 0x0896010f, + 0x9b57fff4, + 0x7468b79f, + 0x29ced3f2, + 0x9b48fff4, + 0xaa25f208, + 0x0659d110, + 0xa225f208, + 0xa94df248, + 0xc0007104, + 0x0a029186, + 0xa225f208, + 0xa949f248, + 0xaa21f208, + 0xf2080244, + 0xb740a221, + 0xf208430c, + 0xf208aa21, + 0xf008a926, + 0x6129a945, + 0x0124c101, + 0xa129f208, + 0x4314b700, + 0x574ab780, + 0xc0007506, + 0x750a90a2, + 0x9144c000, + 0xaa11a911, + 0x0a08090c, + 0x00899e91, + 0x9100c000, + 0xa911aa11, + 0x090c0a08, + 0x00859ea1, + 0x7decb71f, + 0x5dccb780, + 0x7c6cb77f, + 0xa8110100, + 0x6679d131, + 0xcffe9e83, + 0xcffe28fc, + 0xd0202cfc, + 0xd0200334, + 0xd0101110, + 0xda101516, + 0x5d18a241, + 0xcffe5930, + 0xc2002a7c, + 0xc1015a48, + 0xd1100524, + 0xb79f0729, + 0x71887cec, + 0x9322c001, + 0x8c80f292, + 0x8c84f271, + 0x0c029e68, + 0x91a0c000, + 0x7c6ab77f, + 0xa1b1da31, + 0x7eb2b57f, + 0x7f32b55f, + 0xa231da29, + 0x9e44a111, + 0xa9c1da10, + 0xcffea911, + 0xd0202a7c, + 0x09100142, + 0x0242c101, + 0xcffe7217, + 0xcffe2a7c, + 0xcffe2d7c, + 0x0c10297c, + 0xc0200820, + 0xc0103a00, + 0xd0123d00, + 0xfffe19a6, + 0xb77f9366, + 0xb75f7df4, + 0xe2927d6c, + 0xfff48d00, + 0x000d99b3, + 0x746eb79f, + 0x74eeb7bf, + 0x756eb7df, + 0x75eeb7ff, + 0x8c00c00c, + 0xa61d9c22, + 0x8400c00c, + 0x430cb7c0, + 0x40d5b700, + 0x000d9e4f, + 0x5732b720, + 0xaa4df248, + 0xaac5f248, + 0x76400f86, + 0x79f4b57f, + 0x11c1d120, + 0xd002040f, + 0x9e9d0c72, + 0xb51f018b, + 0xb55f7874, + 0xb55f7d6c, + 0xb53f78f4, + 0xb51f796c, + 0xc3947b74, + 0x9eb09b14, + 0xa946f208, + 0x5eccb780, + 0xa941f208, + 0x7d6cb77f, + 0xb3047008, + 0x711b4434, + 0x4454b345, + 0x9e695d19, + 0x7bf4b5bf, + 0xaa69f208, + 0xb71f629b, + 0xd0326670, + 0x74c00ade, + 0xb55f0128, + 0xc0047af4, + 0xb3300802, + 0x9e924422, + 0x7a6cb55f, + 0xb75f2ec1, + 0xc00e7aec, + 0x9e6b2c7c, + 0x9e799e81, + 0x05810a02, + 0xa015a21d, + 0xfff4a012, + 0xa9929a54, + 0x5a8dc280, + 0x9a46fff4, + 0xaa49f248, + 0xc0017510, + 0xf2089114, + 0xf248aa61, + 0x0a20a951, + 0xc0017104, + 0xa8159008, + 0x4314b740, + 0x7a74b71f, + 0xf010020a, + 0x9ea6a946, + 0x7aecb75f, + 0xcffea992, + 0x9e792f7c, + 0x5d0c9e6b, + 0x05200a02, + 0xa21d048d, + 0x9a2bfff4, + 0xfff4a992, + 0xb5df9a1f, + 0xc0007df4, + 0xab1690a0, + 0x7df4b5df, + 0xaa65f208, + 0x0659d110, + 0xa265f208, + 0xa94df248, + 0xc0007104, + 0x0a029186, + 0xa265f208, + 0xa949f248, + 0xaa61f208, + 0xf2080244, + 0xb780a261, + 0xf208430c, + 0xf208a961, + 0xf208a966, + 0x6245aa05, + 0x0244c101, + 0xa269f208, + 0x4314b7e0, + 0xa971f210, + 0x5819d124, + 0xb51f9e44, + 0xc2007cf4, + 0x71045a18, + 0x90e2c000, + 0xb53f0882, + 0xc00a7c6c, + 0xf2509140, + 0xb77faa75, + 0xd0327bec, + 0xd1100af8, + 0x6239056b, + 0xa92af210, + 0xa9edf210, + 0xd0319e96, + 0xb75f0b4e, + 0xa9927cec, + 0x7b6cb73f, + 0xd1202b41, + 0xcffe0135, + 0x0a062f7c, + 0x048d018d, + 0xfff4a21d, + 0xf21099cc, + 0x0268aa25, + 0xa225f210, + 0xa97df250, + 0xc0007104, + 0x0a029186, + 0xa225f210, + 0xa979f250, + 0xaa21f210, + 0xf2100244, + 0xb720a221, + 0xf210430c, + 0xf210aa21, + 0xb740a926, + 0x6129422d, + 0x0124c101, + 0xa129f210, + 0x572bb780, + 0xc0007502, + 0xd0119144, + 0x040d0e62, + 0xcffe9ea1, + 0xc0022cfc, + 0x750491a0, + 0x9144c000, + 0x0e62d011, + 0x9ea0048d, + 0x2c7ccffe, + 0x9040c002, + 0x0af0d072, + 0x5a0dc300, + 0x0669d110, + 0x432db7a0, + 0xa929f210, + 0x0389a992, + 0xcffe02d4, + 0xfff42bfc, + 0xb75f9979, + 0xb73f7cec, + 0xa9927b6c, + 0x9eb99eaa, + 0x018d8506, + 0xfff4a11f, + 0xf2109976, + 0x0268aa25, + 0xa225f210, + 0xa97df250, + 0xc0007104, + 0x0a029186, + 0xa225f210, + 0xa979f250, + 0xaa21f210, + 0xf2100244, + 0xb740a221, + 0xf210430c, + 0xf210aa21, + 0xf008a926, + 0x9eb9a95d, + 0x6129040d, + 0x0124c101, + 0xa129f210, + 0x7d6cb71f, + 0x78ecb75f, + 0x430cb720, + 0x02a80200, + 0x5dadb720, + 0x7becb79f, + 0x7df4b77f, + 0xd01060c3, + 0xda081516, + 0x0203a0a1, + 0xcffea815, + 0xc2002a7c, + 0x9e595a48, + 0x12401506, + 0x797cb75f, + 0x02425d18, + 0x0244c101, + 0x02445930, + 0xb59f7135, + 0xc0007c6c, + 0xb71f9182, + 0xb740706a, + 0x0d824304, + 0x287ccffe, + 0xc0029d8d, + 0xa9929020, + 0x9914fff4, + 0x9320c003, + 0x7d6ab75f, + 0x0d34d012, + 0x0624d010, + 0xa121da10, + 0xa041da08, + 0xa949f040, + 0xcffe9d4d, + 0xe31328fc, + 0x74908d00, + 0xf010a095, + 0xc0008026, + 0xb71f9254, + 0xd0127b6a, + 0xda080d38, + 0xda10a001, + 0xcffea1c1, + 0xd01129fc, + 0xcffe0a32, + 0xb59f2a7c, + 0xd0107dec, + 0xd0110524, + 0x9d2d0e22, + 0xe3130248, + 0xe0108d00, + 0x9d4d8126, + 0xa3c1d808, + 0x8026f010, + 0x0da4d012, + 0xa382da08, + 0x0536d010, + 0x0e32d011, + 0xe3139d2d, + 0x02488d00, + 0x7decb75f, + 0x80a6f020, + 0xd0119d4d, + 0x09040e36, + 0xf0100248, + 0x01858126, + 0xda089d4d, + 0xd010a922, + 0xd0100607, + 0xa8150517, + 0x9e47a895, + 0x9ea00783, + 0x72c49e91, + 0xf0200804, + 0x08888126, + 0x3b80c010, + 0x3f80c020, + 0x2c7ccffe, + 0x2cfccffe, + 0x9306fffc, + 0xfff4a992, + 0xb77f98a5, + 0xda087d74, + 0xb75fa9a1, + 0xe31279ec, + 0xffd48d00, + 0xb71f9b9d, + 0xb79f7c6c, + 0xb7bf726e, + 0xb7df72ee, + 0xb7ff736e, + 0xc00e73ee, + 0x9c228c00, + 0xa6059c22, + 0x4c8cb7a0, + 0x6da2c146, + 0x06bbd110, + 0x008b099a, + 0x6031b76d, + 0xc3940d84, + 0x008b9961, + 0x60a9b78d, + 0x287cc00e, + 0x08027100, + 0x0802d001, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0xb7409e5c, + 0xc1464c8c, + 0x02446a22, + 0x0902c021, + 0x430cb580, + 0x4490b560, + 0x0920c030, + 0xaa619d2d, + 0xc0015dc0, + 0x9e5b2dbc, + 0x2a42cfff, + 0x9dad3246, + 0xa261f000, + 0xb7209c22, + 0x9e58430c, + 0x4829b78a, + 0x71172208, + 0x90c4c000, + 0x48a9b78a, + 0x9c222008, + 0x4588b780, + 0x9c222008, + 0xb720a60d, + 0x0b06430c, + 0x4731b7aa, + 0x46a9b7aa, + 0x90e0c000, + 0x0a52d011, + 0xc00e0289, + 0xd2242afc, + 0x715b51d4, + 0x2dfcc00e, + 0x90e8c000, + 0x9bd9fff4, + 0xffff7400, + 0x000b9224, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0x9c228c60, + 0x430cb720, + 0x4cadb782, + 0x5b2db743, + 0xb5823244, + 0xb7204cad, + 0xb782430c, + 0xc0104cad, + 0xb5822a04, + 0xb7204cad, + 0xb782430c, + 0xc0204cad, + 0xb3407d00, + 0x3a0448a2, + 0x4cadb582, + 0x0d849c22, + 0x9e5c5db0, + 0x0a00c021, + 0x0a00c010, + 0xf0009dcd, + 0x09bca162, + 0x59285990, + 0x2980cff0, + 0x297cc00f, + 0x3980c011, + 0x0d80c021, + 0xc00e31b4, + 0x9dbe0d80, + 0xa1e1f000, + 0xa61d9c22, + 0x8400c002, + 0x0abed031, + 0x2ac19e9f, + 0xa119a192, + 0xc001a116, + 0xc1fc9300, + 0xc0fc7562, + 0xb3560f02, + 0xa9164446, + 0x9e73a992, + 0xfff40902, + 0xa9929bce, + 0x068d0b82, + 0x9bcaffd4, + 0x010fab19, + 0x92e0c000, + 0xc0007dde, + 0xa9929144, + 0x8d00e092, + 0xffd4018f, + 0xe0919a1d, + 0x77c08d00, + 0xc0000b84, + 0xd02990e2, + 0x1f84aa45, + 0xa241d208, + 0x1e840b04, + 0xffff777f, + 0xa91a9124, + 0x12dcc101, + 0xa11a052c, + 0x052ca916, + 0x7540a116, + 0x9124fffe, + 0x7c6eb79f, + 0x7ceeb7bf, + 0x7d6eb7df, + 0x7deeb7ff, + 0x8c00c004, + 0xa61d9c22, + 0x8400c002, + 0x9e9f9e5c, + 0x5a30c200, + 0x0a00c021, + 0xc110a19a, + 0x09820a30, + 0xf0009dcd, + 0xd032a1e1, + 0x2ec10efe, + 0xa115a112, + 0x9180c002, + 0x7762c1fc, + 0x0f02c0fc, + 0x4846b356, + 0x9e760d02, + 0x7df4b55f, + 0x7d74b55f, + 0x7cf4b55f, + 0x7c74b55f, + 0xe0920b82, + 0x77c08d80, + 0x0534d010, + 0x9162c000, + 0x1f84a991, + 0xaa65d029, + 0xd008a191, + 0xc000a241, + 0xd0089080, + 0x0b84a3c2, + 0x2afef031, + 0xc0000d04, + 0xa99a9244, + 0x8d00e092, + 0x19f0d051, + 0x9987ffd4, + 0xb5bf9eaa, + 0xb5bf7dec, + 0xb5bf7d6c, + 0xb5bf7cec, + 0xe0007c6c, + 0xfffe1b04, + 0xa91692c4, + 0x9e73a99a, + 0xffd4010d, + 0xa99a9b23, + 0xffd416dc, + 0xa9969b39, + 0xa19605bc, + 0xfffd7740, + 0xb79f92a4, + 0xb7bf7c6e, + 0xb7df7cee, + 0xb7ff7d6e, + 0xc0047dee, + 0x9c228c00, + 0x430cb720, + 0x0992c144, + 0x5badb743, + 0x6c31b76d, + 0xfffc9e8a, + 0xf8399100, + 0x9e90a285, + 0xaa4df008, + 0x0caed091, + 0xa949f008, + 0x5815c080, + 0x0244c101, + 0x76400120, + 0x41ccb580, + 0x414cb540, + 0x9202c000, + 0x40ccb780, + 0x404cb740, + 0x4254b740, + 0x0a061128, + 0x5208c200, + 0x35229ea1, + 0x4254b540, + 0x5e30d1a2, + 0x08fec00f, + 0xcff19ea3, + 0xc0210d02, + 0xc0100d80, + 0xc1409c83, + 0xc00e0de0, + 0xcff008fc, + 0xc0000d00, + 0xf0299200, + 0x9e55aa65, + 0x2242214a, + 0xc2005921, + 0x32445a20, + 0x4006ba24, + 0xf0009dbe, + 0xffffa261, + 0xb7809241, + 0x0a04404c, + 0x404cb580, + 0xaa9df9f8, + 0xa6859c22, + 0x87029e91, + 0x85220685, + 0x0b7ec00e, + 0x882bf210, + 0xc2007640, + 0xc0025153, + 0xf0089182, + 0x9e69aa61, + 0x2a1ce000, + 0xc28022a2, + 0xb4235920, + 0xf0084442, + 0xd010aa61, + 0x2a1ca962, + 0x8821f310, + 0x1242c101, + 0x400aba0c, + 0x52411003, + 0x5921c200, + 0xc00e9e95, + 0xd0312a7c, + 0xc2000910, + 0x3454520b, + 0x2aced3f2, + 0x92eac000, + 0x5224c200, + 0x32429e51, + 0xa261d010, + 0xa961f008, + 0x2a2ed011, + 0x0619d110, + 0xd110750e, + 0xd0090615, + 0xf0080db2, + 0xc000a261, + 0xd0109240, + 0xf008a062, + 0xd110aa61, + 0x9e810619, + 0xf0080242, + 0xcffea261, + 0xd0322cfc, + 0xfffda164, + 0x9e589220, + 0x7f6eb7bf, + 0x7feeb7df, + 0x9c228c40, + 0x9e58a60d, + 0x9e569e9e, + 0x709b0ee2, + 0x923cc000, + 0x9eb39e6d, + 0x2afccffe, + 0x112a5575, + 0x9e739e83, + 0x297ccffe, + 0x2d7cc00e, + 0x9b8dfff4, + 0x1ea0010b, + 0xffff7771, + 0xb79f9184, + 0xb7bf7eee, + 0xb7df7f6e, + 0x8c607fee, + 0xa60d9c22, + 0x9e589e56, + 0x09069e9e, + 0xc0000d02, + 0x13649080, + 0xd0110124, + 0x710c1a22, + 0x2eaed3f2, + 0xffff0d04, + 0x9e6d9306, + 0x9080c000, + 0x9b69fff4, + 0x0a52d011, + 0x9e837510, + 0x0d029e73, + 0x1aa00922, + 0x92d2ffff, + 0x294ed3f1, + 0xfff40d04, + 0xc0009b5a, + 0xd3f291e0, + 0x9e6c2ace, + 0x52d1c200, + 0x295ed3f2, + 0x9b4ffff4, + 0xc2009e6c, + 0x136a52b0, + 0xd0317750, + 0x9e831e50, + 0x09229e73, + 0x91b2ffff, + 0x296ed3f2, + 0xb79f9e6a, + 0xb7bf7eee, + 0xb7df7f6e, + 0x8c607fee, + 0x92e0fff9, + 0x1d20f011, + 0xd01d9e9a, + 0xd00d0224, + 0xc0001a42, + 0x1205909a, + 0x9e531244, + 0xfffd9ea2, + 0x02079140, + 0xa1c1d010, + 0x9ea29e53, + 0xfff60c82, + 0xa6059240, + 0x02870d0a, + 0x9b9dfff4, + 0x430cb720, + 0x7ea9b785, + 0xc0007500, + 0x02039122, + 0x0a00c098, + 0xaa01d208, + 0x3a040248, + 0x9ea29e83, + 0xb79f018b, + 0xb7bf7f6e, + 0x8c407fee, + 0x90a0fffc, + 0xb720a605, + 0xf011430c, + 0xc0020ea0, + 0xb7450a02, + 0xb3547ea9, + 0x02894424, + 0x9e9d7480, + 0x90a2c000, + 0xba2c0248, + 0x75404000, + 0x9116c000, + 0x0d02120b, + 0x4000ba2c, + 0x9060c000, + 0xfff40d06, + 0x9e839b66, + 0xd0129e6b, + 0xb79f1952, + 0xb7bf7f6e, + 0x8c407fee, + 0x9360fffa, + 0x8460a60d, + 0x8c88e051, + 0xa2190a02, + 0xa211a215, + 0x7d6cb59f, + 0x402db580, + 0xa9e1f008, + 0x07059e5e, + 0xc004198c, + 0xd01274c4, + 0xc0020a92, + 0xd1a691b2, + 0x8520590c, + 0x8044e050, + 0x9120c002, + 0x91c0c002, + 0x9360c002, + 0x9140c003, + 0x91e0c003, + 0x9300c003, + 0x90c0c017, + 0x9280c016, + 0x93a0c015, + 0x9280c001, + 0x9120c011, + 0x9220c011, + 0x9320c011, + 0x9060c013, + 0x91a0c013, + 0x93c0c013, + 0x90c0c014, + 0x9340c011, + 0x9020c019, + 0x9280c018, + 0x9000c017, + 0x9180c017, + 0x9300c017, + 0x90e0c003, + 0x92a0c003, + 0x9360c006, + 0x9120c007, + 0x93c0c007, + 0x9200c00d, + 0x9180c000, + 0x9140c000, + 0x9240c018, + 0x9240c01a, + 0x9320c01a, + 0x92e0c01b, + 0xc01d0802, + 0xd0729000, + 0xe0711924, + 0x058b8d80, + 0x91a0c000, + 0x430cb780, + 0x8d80e071, + 0xc09c058b, + 0xd2080a1c, + 0xd120a902, + 0xfff41125, + 0xc01c9b2b, + 0xd3f19020, + 0xe0712aae, + 0x9eaa8d80, + 0x0916058b, + 0x9a55fff4, + 0x430cb780, + 0x0a1cc09c, + 0xa281d208, + 0x9200c01b, + 0x292ed3f2, + 0x8d80e071, + 0xc016058b, + 0xf01091a0, + 0x0d06aacd, + 0x8d80e071, + 0x9e524afd, + 0x2a9c058b, + 0x93e0c013, + 0xaacdf010, + 0x8d80e071, + 0x0d02058b, + 0xfff40906, + 0x4afd9a32, + 0x9e832a9c, + 0x8d80e071, + 0xc00e010b, + 0xc01a0d7e, + 0xb7809120, + 0x0d02430c, + 0x8d80e071, + 0x0a40c09a, + 0xaa01d208, + 0x090a058b, + 0xd0027500, + 0xc0190d22, + 0xb7209320, + 0x7640430c, + 0xb7840a82, + 0xd002752d, + 0x75000ad2, + 0x9204c000, + 0xc0007540, + 0xb74491a2, + 0xb78475ad, + 0xe0716fad, + 0x058b8d80, + 0x090a7104, + 0x9060c013, + 0x6fadb744, + 0x75adb784, + 0xc0027088, + 0x0d069004, + 0x8d80e071, + 0x058b9e52, + 0x99f1fff4, + 0xc0007540, + 0xb72093a2, + 0xb785430c, + 0x75007ea9, + 0x91c2c000, + 0x6cadb784, + 0xc0007502, + 0x9e839122, + 0x8d80e071, + 0x0d2ec002, + 0x90e0c000, + 0xe0719e83, + 0xc0028d80, + 0x09220d2a, + 0x99d3fff4, + 0xe0719e83, + 0x09168d80, + 0xfff40d1e, + 0xb78099cc, + 0x9e83430c, + 0x8d80e071, + 0x0a04c098, + 0xa902d208, + 0x9a43fff4, + 0x9e830d06, + 0x8d80e071, + 0xc0169e52, + 0x02039360, + 0x0a40c09a, + 0xaa01d208, + 0xc0167500, + 0xc00992a2, + 0xb7809180, + 0x0d02430c, + 0x8d80e071, + 0x0a14c098, + 0xaa01d208, + 0x0906058b, + 0xd0017500, + 0xc0160d22, + 0xb7809020, + 0xc098430c, + 0xd2080a10, + 0x7500aa01, + 0x9122c000, + 0x8d80e071, + 0x0d2a058b, + 0xc0150912, + 0x9ea29220, + 0x8d80e071, + 0x0906058b, + 0x9140c015, + 0x4314b720, + 0x6ccdb784, + 0xd0227504, + 0xc0011524, + 0x9e4c93a4, + 0xc0969e4a, + 0xd2080a54, + 0xb744aa01, + 0xc09875d5, + 0xc2000910, + 0xc1015a08, + 0xb76400c2, + 0xd008722d, + 0xd011a941, + 0x72990a32, + 0xd0020d02, + 0x74800d22, + 0x9042c001, + 0x7ec9b785, + 0xd0127500, + 0xc0001124, + 0x9e4c9244, + 0xc0960902, + 0xd2080a58, + 0xc200aa01, + 0xc1015a08, + 0xb72400c2, + 0x0884722d, + 0xd00270c2, + 0x9e4c0922, + 0xc0989e51, + 0xd2080a0c, + 0x3218aa01, + 0x3144d020, + 0x9e529e4c, + 0x0a08c098, + 0xaa01d208, + 0x3228e000, + 0x91a2fffd, + 0xe0710d06, + 0x9e528d80, + 0xfff4058b, + 0xb7209934, + 0x0203430c, + 0x0a08c098, + 0xaa01d208, + 0xc0007500, + 0x9e839122, + 0x8d80e071, + 0x9a07fff4, + 0x92e0c000, + 0xc0960203, + 0xd2080a54, + 0xb744aa01, + 0x9e8375b5, + 0x5a08c200, + 0xb72400c2, + 0xe071722d, + 0xd1208d80, + 0xba121115, + 0xfff44001, + 0xb7209a0d, + 0x0203430c, + 0x0a10c098, + 0xaa01d208, + 0xc0037500, + 0x02039342, + 0x0a0cc098, + 0xaa01d208, + 0xc0027500, + 0x020392c4, + 0x0a08c098, + 0xaa01d208, + 0xc0960103, + 0x75000958, + 0x90c2c000, + 0xaa41d008, + 0x9260c002, + 0xc0960203, + 0xd2080a54, + 0xd008aa01, + 0x9e83a941, + 0x5a08c200, + 0x00c2d020, + 0x00a25908, + 0x722db724, + 0x7255b724, + 0x8d80e071, + 0x1113d120, + 0x90e0c002, + 0x430cb720, + 0xc0980203, + 0xd2080a0c, + 0x7500aa01, + 0x9284c000, + 0x6f2db784, + 0xc0027500, + 0x02039044, + 0x0a54c096, + 0xaa01d208, + 0x5a08c200, + 0xb78400c2, + 0x7500722d, + 0x92a4c001, + 0xe0710d06, + 0x9e528d80, + 0xfff4058b, + 0xb72098b2, + 0x0203430c, + 0x0a0cc098, + 0xaa01d208, + 0xc0007500, + 0x9e839122, + 0x8d80e071, + 0x9985fff4, + 0x92e0c000, + 0xc0960203, + 0xd2080a58, + 0xc200aa01, + 0xb7445a08, + 0x00c275b5, + 0x722db724, + 0xe0719e83, + 0xd1208d80, + 0xba121115, + 0xfff44001, + 0x9e83998b, + 0x8d80e071, + 0xc0020d0e, + 0xe0719200, + 0x058b8d80, + 0xfff70d02, + 0xb72092c0, + 0xe071430c, + 0x058b8d80, + 0x75b5b744, + 0xc0060916, + 0xb72091a0, + 0xe071430c, + 0x058b8d80, + 0x75b5b744, + 0xc0060922, + 0xb7209060, + 0xe071430c, + 0x058b8d80, + 0x75b5b744, + 0x5d21090a, + 0x9300c005, + 0x430cb720, + 0x67adb784, + 0xd01a7502, + 0xc0001248, + 0xb7619174, + 0x9ea34d2d, + 0x9811c374, + 0x0a027400, + 0x0a42d001, + 0x09c0f012, + 0x04850d0a, + 0x1ca2d001, + 0x76c09e4a, + 0x8d80e071, + 0x4842b332, + 0xc00b058b, + 0xb7209020, + 0xe071430c, + 0x058b8d80, + 0x6d35b744, + 0xfff42d04, + 0xc00a98b8, + 0xb72092e0, + 0x7640430c, + 0xb7240d02, + 0xd001752d, + 0xe0710d22, + 0x00928d80, + 0x0522c101, + 0xc00e058b, + 0x091a2d7c, + 0x9040c00a, + 0x430cb720, + 0x8d80e071, + 0xb744058b, + 0x090a7535, + 0x91c0c003, + 0x430cb720, + 0x4d2db761, + 0x67b5b764, + 0xc00074c0, + 0x0a8690a4, + 0x9220c000, + 0xc0029e9a, + 0xc0000902, + 0xd0119100, + 0x01091a22, + 0xc00e0524, + 0x7680297c, + 0x9336ffff, + 0xc3540285, + 0x9e829bb8, + 0x8d80e071, + 0xc00e058b, + 0xd3f12d7c, + 0xc008295e, + 0xb7209220, + 0xe071430c, + 0x058b8d80, + 0x75adb7a4, + 0xc03e090a, + 0xd2a42afc, + 0xffd45921, + 0x9e839be2, + 0x8d80e071, + 0x295ed3f2, + 0x91e0c000, + 0x8d80e071, + 0xc00e058b, + 0x09220d7e, + 0x9bd3ffd4, + 0xe0719e83, + 0xc00e8d80, + 0x09220d7e, + 0x9180c007, + 0xaa4df010, + 0xd0114a7d, + 0x754e2ace, + 0x90c2c007, + 0x8d80e071, + 0x0d02058b, + 0xffd40906, + 0x9e839bbc, + 0x8d80e071, + 0x0d02010b, + 0x92c0c006, + 0x5614b740, + 0x8d80e071, + 0x9e54058b, + 0xc2400922, + 0x0d04a946, + 0x2d7cc00e, + 0x9100c006, + 0x430cb720, + 0x8d80e071, + 0xb784058b, + 0x09066cad, + 0x0d027502, + 0x0d22d001, + 0x9340c005, + 0x430cb720, + 0x7ea9b785, + 0xd0017500, + 0xc0000a46, + 0xb78590e2, + 0x9e497f29, + 0x0a044242, + 0x294ed3f2, + 0x8d80e071, + 0x090a058b, + 0x9080c005, + 0x5614b740, + 0x8d80e071, + 0x9e52058b, + 0xa946c220, + 0xc0040916, + 0xb7209320, + 0xe071430c, + 0x058b8d80, + 0x7f31b745, + 0x45220906, + 0x91c0c004, + 0x430cb720, + 0x67adb780, + 0xc0007500, + 0xb78690c4, + 0xc00050ad, + 0xb7819380, + 0x75045dad, + 0x9164c000, + 0xb7860902, + 0xd0126bad, + 0xc8127088, + 0xb5407088, + 0xb72067ad, + 0xb781430c, + 0x75045dad, + 0x9122c000, + 0xb7460a02, + 0xd0126dad, + 0xb5807104, + 0xb7a067ad, + 0x0d82430c, + 0xb760008b, + 0xfa0867ad, + 0xc354a921, + 0x008b9a64, + 0x67b5b500, + 0x430cb720, + 0x8d80e071, + 0xb740058b, + 0xb72067b5, + 0x095e682d, + 0x1115d120, + 0x90e0c001, + 0x430cb720, + 0x8d80e071, + 0xb740058b, + 0xc00067b5, + 0xb78093a0, + 0xb720558c, + 0xc240430c, + 0x0103aa45, + 0x4ab5b746, + 0xc0c47500, + 0xc0000960, + 0xd00890c2, + 0xc000aa41, + 0xd00890c0, + 0xc101aa41, + 0xe0710244, + 0xb5868d80, + 0x058b4aad, + 0xffd4095e, + 0xc0019b63, + 0xb72090a0, + 0xb784430c, + 0x75066cad, + 0x1124d011, + 0x9282c000, + 0x67adb784, + 0xc0c40103, + 0x75000960, + 0x9142c000, + 0x4badb781, + 0xa941d008, + 0x61290a04, + 0x9080c000, + 0xa941d008, + 0x8d80e071, + 0x292ed3f2, + 0x091e058b, + 0x9adfffd4, + 0x7d6cb77f, + 0x9e729eb3, + 0x8d08e052, + 0x9bb1ffd4, + 0xb79f0806, + 0xb7bf7d6e, + 0xb7df7dee, + 0xc0027e6e, + 0x9c228c40, + 0xc002a61d, + 0x9e5f8440, + 0xabc6f031, + 0x0a72d011, + 0x5a30c200, + 0x0d829ea6, + 0x0a00c040, + 0x0f00c021, + 0xa191a215, + 0x7decb55f, + 0x7d74b53f, + 0xb57fa099, + 0x9e567c74, + 0x7a74b57f, + 0x7af4b57f, + 0x7b74b57f, + 0x7bf4b57f, + 0x0f50c040, + 0x0a02c801, + 0xf0009dee, + 0x0687a261, + 0xc002a19e, + 0xf2089200, + 0x028daa41, + 0x75000b10, + 0x9102c000, + 0xc0007504, + 0x750290a2, + 0x9284c000, + 0x09d8d011, + 0xa962d008, + 0x0c827504, + 0xe0d19ebb, + 0xd0028d00, + 0xffd40c92, + 0x58089a38, + 0x08060360, + 0x9200c000, + 0x7decb75f, + 0x7d74b73f, + 0xe0d29ebb, + 0x018b8d00, + 0x9ba0ffd4, + 0x1e72d011, + 0x03c0d020, + 0xa9a1f208, + 0xc00074c0, + 0xa19d90a4, + 0x91e0c000, + 0xc00074d8, + 0xa9199124, + 0x0e860d06, + 0xa142d808, + 0x9220c000, + 0xc0007740, + 0xa91d9144, + 0x02200e82, + 0x2a7cc00e, + 0xc000a21d, + 0xd11090c0, + 0xd3f20651, + 0xb79f2ace, + 0x711f7a6c, + 0x91e6fffd, + 0xc0007740, + 0xa91d9322, + 0x1e52d011, + 0xc1f05920, + 0x2a7c2900, + 0xa9113244, + 0x32445940, + 0xc021a915, + 0xc0080900, + 0x9dad0900, + 0xa261f000, + 0x0a06a91a, + 0xa241d810, + 0xd808a919, + 0x7500aa41, + 0x9284c000, + 0xb79fa915, + 0xc0217c6c, + 0x09700900, + 0x2a7ec7ff, + 0xf0009dad, + 0xb79fa261, + 0xd1107aec, + 0x9dee1679, + 0xa261f000, + 0x7becb71f, + 0x7b6eb79f, + 0x7beeb7bf, + 0x7c6eb7df, + 0x7ceeb7ff, + 0x8c40c004, + 0xa61d9c22, + 0xc1800d84, + 0x9e745f30, + 0xc0409e76, + 0x9ea50a00, + 0xc021078d, + 0xc0210b00, + 0x02870f80, + 0x0e80c021, + 0x0b82c008, + 0xc0400b40, + 0xc0000fd0, + 0xc03c93e0, + 0xc01e757e, + 0xb3540a7e, + 0xc2004434, + 0x12d85914, + 0x2900c3fe, + 0xf0009dfe, + 0x9d5ea161, + 0x9dedaa61, + 0xa3e1f000, + 0x9dde3a40, + 0xa261f000, + 0x09929eba, + 0x010f058d, + 0x9afbff94, + 0xffff7540, + 0xc0089044, + 0x9ded0a02, + 0xa261f000, + 0x7e6eb79f, + 0x7eeeb7bf, + 0x7f6eb7df, + 0x7feeb7ff, + 0x8c00c002, + 0xa6059c22, + 0x5db00d84, + 0xc0089e5d, + 0xc0210e82, + 0x0ac00a80, + 0xf0009ddd, + 0x9e5aa2e2, + 0x0900c021, + 0x0900c040, + 0xa9629d2d, + 0xd05174c0, + 0xc0003e20, + 0xd0d19082, + 0x9dad3e20, + 0xa261f000, + 0x09929e6a, + 0xff94050b, + 0x9ddd9ac6, + 0xa2e2f000, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0xc008a61d, + 0xf2128420, + 0x9e5e8c88, + 0x03850705, + 0x9e6a9e9a, + 0xc0080a82, + 0xb5bf0982, + 0xffd45e6a, + 0x9eb39872, + 0x9eb99e72, + 0x8c80e231, + 0x050b018b, + 0x9ab6fff4, + 0x018b9eb3, + 0x9bb9fff4, + 0x75eeb79f, + 0x766eb7bf, + 0x76eeb7df, + 0x776eb7ff, + 0x8c20c00a, + 0xb7209c22, + 0x09824f0c, + 0xb9600c96, + 0x9e8a4038, + 0x01030203, + 0x0a39cfca, + 0x0929cfdc, + 0x0d09cfac, + 0x40a9b57f, + 0x4129b57f, + 0x4029b560, + 0x64a9b575, + 0xa082f208, + 0xa0c2f008, + 0xa1c1f010, + 0x08a0c146, + 0x90e1ffff, + 0x0c7f9e99, + 0x4608b560, + 0x91c0c000, + 0x430cb740, + 0x04a5d110, + 0x6fadb789, + 0x02446a32, + 0x0a20c138, + 0xa012d208, + 0x2e1ed3f1, + 0x71170c84, + 0x5908d224, + 0x91d8ffff, + 0x588cb740, + 0xb9600a02, + 0x9ea24058, + 0xa106c220, + 0xffff0a04, + 0x9c229381, + 0x588cb720, + 0x09029e5b, + 0x0d34d012, + 0x4038b960, + 0xd2080222, + 0x7115aa09, + 0x90c4c000, + 0x297cc00e, + 0x90c0c000, + 0xffff0904, + 0x090292a1, + 0x588cb780, + 0x01280904, + 0x0a049ea2, + 0x11a8d000, + 0x90e0c000, + 0xaa41d008, + 0xa245d008, + 0xffff1904, + 0xd0119361, + 0xd0100a34, + 0x9c22a249, + 0xc912a61d, + 0xc9129cc4, + 0xb7a09cce, + 0xb7a05814, + 0xf010478c, + 0x0507a1ed, + 0x1fd6d032, + 0xd0510b86, + 0x0f020b50, + 0x167ad010, + 0x4a7d9e6a, + 0x9c83c810, + 0xaa5dd1e9, + 0xd0206a52, + 0xf01001ca, + 0x7500aa6d, + 0x93a4c000, + 0x0e20d051, + 0xa003f208, + 0xa3edf010, + 0x0e38d011, + 0xa803f208, + 0xaa61d050, + 0xa961f010, + 0x4508b580, + 0x9c629e94, + 0xa843f208, + 0xb5c09eaa, + 0xf2084510, + 0xfffea3ad, + 0x750292e0, + 0x91c4c000, + 0x0e20d051, + 0xa003f208, + 0x0e30d051, + 0xa803f208, + 0xaa61d050, + 0x9240c000, + 0x9181fffe, + 0x9200c003, + 0x0e20d051, + 0xa003f208, + 0x4b8cb780, + 0xa803f208, + 0x478cb780, + 0xaa01d248, + 0x4508b580, + 0x9120c003, + 0x0a02c021, + 0x9d4d0a10, + 0xdfe0aa61, + 0xc0007d00, + 0xc10090c2, + 0xc0010a82, + 0xb7609120, + 0x0b0a4688, + 0x74c0010d, + 0x0a02c021, + 0x0a00c030, + 0x1962d001, + 0xa9629d4d, + 0x9e512d71, + 0x3122290c, + 0xf0009dcd, + 0xc100a161, + 0xc017080a, + 0x74c09c81, + 0x90a4c000, + 0xff949e9b, + 0xc171996d, + 0xc8179c81, + 0x9eb39c84, + 0x2afccffe, + 0x9964ff94, + 0xff940d8a, + 0xc0219961, + 0xc0300902, + 0x9d2d0900, + 0x3a0caa61, + 0xf0009dad, + 0xb740a261, + 0x018b4a8c, + 0x2954d012, + 0x2980c100, + 0xb9600d86, + 0xf0084050, + 0x7506aa41, + 0x90a4c000, + 0xc00074c0, + 0x750490c0, + 0x90a4c000, + 0xb41a7680, + 0x19504a24, + 0x9221ffff, + 0x9160c000, + 0x478cb780, + 0xaa0df208, + 0xfffc7502, + 0xfffc93a4, + 0xb79f9160, + 0xb7bf7e6e, + 0xb7df7eee, + 0xb7ff7f6e, + 0xc0027fee, + 0x9c228c00, + 0xb780a605, + 0x9e5b4508, + 0x4794b760, + 0xb7a06a52, + 0xd1204488, + 0xfff401c7, + 0x9eab9b23, + 0x7f6eb79f, + 0x7feeb7bf, + 0xffb38c40, + 0xa60592e0, + 0x9080c000, + 0x9be8fff4, + 0x430cb720, + 0x47a9b7aa, + 0xffb49eab, + 0x700a9a86, + 0xffff0d92, + 0xb79f92a2, + 0xb7bf7f6e, + 0x8c407fee, + 0x9180ffb4, + 0xc002a61d, + 0x9e5e8400, + 0xa116a199, + 0xc000a111, + 0xfff49080, + 0xb7809bcb, + 0x0d924408, + 0x7d3ec01c, + 0x9324ffff, + 0x4408b780, + 0x0d02c021, + 0x0d10c010, + 0xb5800a04, + 0x9d2e4408, + 0xc021ab62, + 0xc0100902, + 0xd0720920, + 0x9d2d2eee, + 0x9e55aa61, + 0x29ced071, + 0xc0000385, + 0xfff49180, + 0x9d5d9ba9, + 0xd072ab62, + 0x9d7d2eee, + 0xd071aa61, + 0xd01229ce, + 0xd0710fd2, + 0x0d8a2e7e, + 0xffff7106, + 0x0a029202, + 0x7c6cb59f, + 0x7cecb59f, + 0x7d6cb59f, + 0x7decb59f, + 0xb9600389, + 0xaa154078, + 0xe0939d7d, + 0xc2708d00, + 0xf010a905, + 0x0b848026, + 0xa101d208, + 0x92a1ffff, + 0x9eb39dcb, + 0xff940982, + 0x9eb398aa, + 0x8d00e092, + 0xff940982, + 0xaa9198cd, + 0x4c8cb780, + 0x5e88c280, + 0x6aa2c146, + 0x02d89eb3, + 0x0aa0c050, + 0xa922f208, + 0x7decb79f, + 0xe050018f, + 0x0902a94a, + 0xff94a21d, + 0x9eb39a3d, + 0x2f01cffe, + 0x9a52ff94, + 0x9eb3aa1d, + 0x8d00e092, + 0x09824a7d, + 0x7decb59f, + 0x987fff94, + 0xaaa1f208, + 0x9eb39e6c, + 0xa926e240, + 0x0902018f, + 0x9a3dffb4, + 0xff949eb3, + 0xc0049a3b, + 0x0a0277c0, + 0x4824b374, + 0x2a7c9e72, + 0xc0213244, + 0xc0100902, + 0x9dad0910, + 0xa261f000, + 0xe0929eb3, + 0x09828d00, + 0x9886ff94, + 0xb79fa91f, + 0x71357dec, + 0x92c4ffff, + 0x4408b780, + 0x1a04a919, + 0xb5807480, + 0xc0004408, + 0xb7809164, + 0xc0a4430c, + 0xd2080a10, + 0x7500aa01, + 0x9102c000, + 0xff940d8e, + 0x0d8a9837, + 0x9834ff94, + 0x7c6eb79f, + 0x7ceeb7bf, + 0x7d6eb7df, + 0x7deeb7ff, + 0x8c00c004, + 0xf8399c22, + 0x8440a205, + 0x9e9b9e5a, + 0x5a20c100, + 0xc7f09e53, + 0xe0522a00, + 0xc0018d00, + 0xa2113a04, + 0xfff4a096, + 0xf9f89b1f, + 0x9c22aa15, + 0xa205f839, + 0x0a028440, + 0x0a20c146, + 0x4c8cb720, + 0x00c26229, + 0x5aadb783, + 0x5ca0c180, + 0x5b35b703, + 0x2a7cc006, + 0xb7039ea3, + 0xc7f05bad, + 0xb7232c80, + 0x34965c2d, + 0x9e539e9b, + 0x8d00e052, + 0xa019a016, + 0xa092a09d, + 0x9af8fff4, + 0xaa15f9f8, + 0xa6059c22, + 0x0d80c021, + 0x06b7d110, + 0xc0000685, + 0xb78091c0, + 0x0a044688, + 0x4688b580, + 0x9abafff4, + 0x4688b780, + 0xb5801a04, + 0x9d5d4688, + 0x791baa61, + 0xffff0d8e, + 0xb79f9202, + 0xb7bf7f6e, + 0x8c407fee, + 0xa6059c22, + 0xc4019e5c, + 0xc0210902, + 0x9e5d0a00, + 0x0900c008, + 0x9dcd0a20, + 0xa161f000, + 0xc0080992, + 0xc0210d02, + 0xfff40a80, + 0x0ac09bce, + 0x0a02c008, + 0xf0009ddd, + 0xb79fa261, + 0xb7bf7f6e, + 0x8c407fee, + 0xa61d9c22, + 0xb7208440, + 0xd132430c, + 0x06876f31, + 0x46b1b76a, + 0x04e3d110, + 0x05d60b02, + 0x4294b560, + 0x4c2bb5c1, + 0x430cb780, + 0xd0120c06, + 0xd1100d32, + 0x5d300669, + 0x0a48c012, + 0xa301da08, + 0x430cb720, + 0xd1109e52, + 0xc02104e3, + 0xb5c00900, + 0xb78066ad, + 0xc01a430c, + 0xd1100920, + 0xc0120669, + 0xf2080a60, + 0xb720a301, + 0xd110430c, + 0xb50004e3, + 0xb78065b5, + 0xd110430c, + 0xc0120669, + 0xd2080a20, + 0x9dada301, + 0xa361f000, + 0xc0089e54, + 0xc0210902, + 0x0a400a00, + 0xf0009dcd, + 0xb7a0a161, + 0x9e51430c, + 0x0d00c040, + 0x046ac101, + 0x0d80d3f1, + 0x604cb780, + 0xa965f008, + 0x0880c021, + 0x08c0c046, + 0x9d9d0244, + 0xa261f000, + 0x0d00c021, + 0xf0009dae, + 0xb702a361, + 0xd0105450, + 0xe0530636, + 0xc1018d00, + 0xc2000240, + 0x9d4d5a08, + 0xf010008b, + 0x050d81a6, + 0x5cadb700, + 0xa9e1f008, + 0xa8e1f208, + 0x00ddd120, + 0x0d40c012, + 0x0155d120, + 0xc0109e42, + 0x9e840c90, + 0xb7209c62, + 0x7740430c, + 0x04e3d110, + 0x67adb5c0, + 0x4314b720, + 0x04e2d010, + 0x714db780, + 0x5f2db720, + 0xb5800242, + 0xc000714d, + 0x9eb790e4, + 0xa061f208, + 0x9240c008, + 0x4294b760, + 0xd0110d7f, + 0xc2000e32, + 0x01095a30, + 0x0900c021, + 0x0940c00e, + 0xf0009dad, + 0x0910a162, + 0xf0009dad, + 0x0910a361, + 0xf0009dad, + 0xc021a361, + 0xc00e0a00, + 0x9dcd0a70, + 0xa361f000, + 0x430cb720, + 0x2dfcc00e, + 0xd110010d, + 0x09c204e3, + 0x5fadb720, + 0x1910d052, + 0x7d6eb79f, + 0x7deeb7bf, + 0x7e6eb7df, + 0x7eeeb7ff, + 0x8c40c002, + 0x9280ff84, + 0x4729b7ea, + 0xc380070f, + 0x02895a30, + 0x0a80c021, + 0x0a80c116, + 0x9100c002, + 0x5f4db780, + 0xc0027500, + 0xb7809002, + 0x750067cd, + 0x9162c000, + 0xb5e09eab, + 0xcfdf67d5, + 0xcfea0dfc, + 0xfff40d80, + 0xb7409af0, + 0xd0914314, + 0xc1016e59, + 0xb74200e4, + 0x02445429, + 0x74800248, + 0x00c5d120, + 0x91e2c000, + 0x4c4bb781, + 0x0902c201, + 0x0900c004, + 0x5a40c200, + 0x2a7cc00f, + 0xc0003244, + 0xb7819140, + 0xc2004c2b, + 0xc00f5a40, + 0xc2012a7c, + 0xb5803a00, + 0xb78066ad, + 0xd131430c, + 0x00986cd1, + 0x66adb720, + 0xf0009ddd, + 0x0f04a0e1, + 0x0a81cf00, + 0x430cb720, + 0x117cc101, + 0x46a9b78a, + 0x12a8d020, + 0xd1317088, + 0xd0206f51, + 0xfffd00e2, + 0xb7ca91b6, + 0xc0034729, + 0xd0209200, + 0xd1321368, + 0xd0916ee1, + 0xd0106d69, + 0x9ea806d2, + 0x5f4cb780, + 0xc0037500, + 0xb7229022, + 0xb7605448, + 0x00a25e4d, + 0xc1010092, + 0xb7610092, + 0xc3344c33, + 0x008b98c4, + 0x67adb500, + 0x430cb720, + 0x04d3d110, + 0x0910d3f1, + 0xaa41f008, + 0x67adb720, + 0xf0081242, + 0xb720a241, + 0xd0104314, + 0xb78004d2, + 0xb720714d, + 0x124267ad, + 0x714db580, + 0x430cb780, + 0x0659d110, + 0xc0120089, + 0xb78008a0, + 0x75004029, + 0x90c2c000, + 0x4031b5e0, + 0x90a0c000, + 0xb5400906, + 0xb7004029, + 0xd1324314, + 0xd0106d61, + 0xb76004a0, + 0x74c05f2d, + 0x9382c000, + 0x5429b742, + 0xe053026c, + 0x02448d00, + 0x5a08c200, + 0xb7009d4d, + 0xf0105ccc, + 0x048480a6, + 0xa8a1f208, + 0x0d40c012, + 0xc0109eb3, + 0x05040c90, + 0x9c629e84, + 0xa021f208, + 0xb7201b04, + 0xb78a4314, + 0x718846c9, + 0x91b6fffc, + 0x430cb720, + 0x712db740, + 0xfff97480, + 0xb78a9024, + 0x028546a9, + 0x9220c000, + 0x67adb780, + 0xc0007500, + 0xd0129122, + 0xb5a009a2, + 0x5db067ad, + 0x9a1dfff4, + 0x428cb780, + 0xb7200a04, + 0xb580430c, + 0xb740428c, + 0xb78a428c, + 0xb74a4729, + 0x708846b1, + 0x2e2ed3f1, + 0xc0041228, + 0x00c26a22, + 0x9014ffff, + 0x2e2ed3f1, + 0x0f8ec001, + 0xc0020b02, + 0xc0010bc2, + 0xce000f0a, + 0xb5800f80, + 0xc005428c, + 0xb78a93a0, + 0x122846a9, + 0x6ac1d132, + 0x04d3d110, + 0x65adb780, + 0xc0057500, + 0xd0129182, + 0xb5c009a2, + 0x5db067ad, + 0xc0219e5c, + 0xc0400a00, + 0x9dcd0a00, + 0xa3e1f000, + 0x99ddfff4, + 0x428cb7a0, + 0x0952d011, + 0x02055930, + 0x0a00c021, + 0x0a20c040, + 0xaa619d4d, + 0x430cb720, + 0x9e929e7b, + 0x04d3d110, + 0x0d00c021, + 0x65adb580, + 0x430cb720, + 0x0d40c046, + 0x04d3d110, + 0x65adb780, + 0xc2002246, + 0xb5805a35, + 0x9d2e672d, + 0xb720a962, + 0x9e91430c, + 0x04d3d110, + 0x0c80c021, + 0x65b5b540, + 0x430cb720, + 0x0cc0c00e, + 0x04d3d110, + 0xb7409e8b, + 0xc01065b5, + 0xf0100d80, + 0xb760aa61, + 0xb720672d, + 0xc1015fad, + 0x12460244, + 0xf0101242, + 0xb720a261, + 0xd110430c, + 0xb78004d3, + 0x9d9e602d, + 0xa261f000, + 0xc0210205, + 0xc00e0a00, + 0x9dcd0a50, + 0xa361f000, + 0x9dcd0a10, + 0xa361f000, + 0x9dcd0a10, + 0xa361f000, + 0x0900c021, + 0x0930c00e, + 0xf0009dad, + 0xb720a362, + 0xc00e5fad, + 0x9eab2afc, + 0x1910d052, + 0x010d09c2, + 0x9af2ff74, + 0xff749eab, + 0xb7809b09, + 0xd110430c, + 0xc0100659, + 0xf2080a00, + 0xb780a301, + 0xd110430c, + 0xc00e0659, + 0xf2080a60, + 0xb780a305, + 0xd110430c, + 0xc00e0659, + 0xf2080a60, + 0xb720a301, + 0xd110430c, + 0xb5c004d3, + 0xb72067ad, + 0xb5c0430c, + 0xb720712d, + 0xd110430c, + 0xb5c004d3, + 0xb78065ad, + 0x0a04428c, + 0x428cb580, + 0x430cb720, + 0x428cb740, + 0x4729b78a, + 0xfff97088, + 0xb79f93d4, + 0xb7bf7d6e, + 0xb7df7dee, + 0xb7ff7e6e, + 0xc0027eee, + 0x9c228c40, + 0xb720a605, + 0x9e5d430c, + 0x4829b78a, + 0x22d8d020, + 0xc0007346, + 0xc0009244, + 0xffd49080, + 0xb7209bc1, + 0x0d92430c, + 0x48a9b78a, + 0xffff7b59, + 0xc0009304, + 0xffd49380, + 0xb7209bb5, + 0xb740430c, + 0x0d924588, + 0x4829b78a, + 0x22444a7d, + 0xffff790a, + 0x322a9284, + 0x4588b580, + 0x4829b78a, + 0xb58a3258, + 0xb7204829, + 0xb78a430c, + 0x325848a9, + 0x0d82c021, + 0x48a9b58a, + 0x0da0c030, + 0xa9629d3e, + 0x4488b740, + 0x59080a3e, + 0x5208c200, + 0x51a8c200, + 0x4a7d21b8, + 0x25229ea1, + 0x35229e99, + 0xf0009dbe, + 0xb79fa162, + 0xb7bf7f6e, + 0x8c407fee, + 0xa6059c22, + 0x478cb780, + 0xb7400906, + 0xf2084c14, + 0xf010a10d, + 0x0a10a043, + 0xa803f208, + 0x4a8cb7a0, + 0xb5800a02, + 0xd3724508, + 0x010b1ad8, + 0xaa4df1e9, + 0xc000750c, + 0x0d9290e2, + 0x9b60ffd4, + 0x92e0ffff, + 0xffff709b, + 0xb78092a4, + 0xf2084c0c, + 0xb79fa803, + 0xb7bf7f6e, + 0x8c407fee, + 0xb7409c22, + 0x0d064b0c, + 0x4058b960, + 0xaa41f008, + 0xb4127508, + 0x09504a22, + 0x9341ffff, + 0xb7209c22, + 0xb785430c, + 0x750044ab, + 0x9142c000, + 0x48a9b78a, + 0x42289e5a, + 0x48a9b58a, + 0x9300c000, + 0xb74a9e5c, + 0x4a7d4829, + 0x4000ba24, + 0xb54a2144, + 0xb7204829, + 0xb74a430c, + 0x224448a9, + 0x48a9b58a, + 0x4588b780, + 0x42289e5a, + 0x4588b580, + 0x0982c021, + 0x09a0c030, + 0xa9629d3d, + 0x4488b740, + 0x2e3ed031, + 0xc2005908, + 0x4a7d5208, + 0x25269ea3, + 0xf0009dbd, + 0xfffda162, + 0xf8399340, + 0xb720a205, + 0xb783430c, + 0xb58a5b2d, + 0xb72047a9, + 0xb783430c, + 0xc2005b2d, + 0xb58a5a21, + 0xb7204729, + 0xb786430c, + 0xb58a76ab, + 0xb72046a9, + 0xb78d430c, + 0xb58a6da9, + 0xb7204629, + 0xb76a430c, + 0xfff447b1, + 0xb7209b19, + 0x0982430c, + 0xb74a0dff, + 0xba1246b1, + 0xc0004001, + 0xb7899140, + 0x6a326fcd, + 0xc1380242, + 0xd2080a20, + 0xb720a192, + 0xc101430c, + 0xc2000234, + 0xd0205908, + 0xb74a00a2, + 0x09844729, + 0xffff7104, + 0xb76a919c, + 0xf9f847b1, + 0xfffcaa1d, + 0xa60d9000, + 0x8400c004, + 0xc0210705, + 0x03070d02, + 0xc0309e95, + 0x9d2e0d00, + 0x0205a961, + 0x2a70c03e, + 0xcfc00a10, + 0xc03e290d, + 0x32442a70, + 0xf0009dae, + 0xc021a261, + 0xc0300902, + 0x9d2d0920, + 0xc180aa61, + 0x9e515d60, + 0x2a7ec00f, + 0x9dad3242, + 0xa261f000, + 0x76d6097f, + 0xa121d210, + 0x90a4c002, + 0x2a3ed3f1, + 0xd1a4750c, + 0xc0105921, + 0xd2269312, + 0xb720590c, + 0x8520430c, + 0x8044e050, + 0x91c0c000, + 0x91a0c010, + 0x91c0c000, + 0x9340c000, + 0x9380c000, + 0x90a0c010, + 0x9380c000, + 0x4835b545, + 0x93e0c00f, + 0x0a060103, + 0x0970c0a2, + 0xa241d008, + 0x430cb780, + 0x0a74c0a2, + 0xa102d208, + 0x9220c00f, + 0x6735b544, + 0x91a0c00f, + 0x68b5b544, + 0x9120c00f, + 0x5e30d122, + 0x2d7cc03e, + 0x5d18d122, + 0x2a00cffd, + 0xb5813244, + 0xc00e482d, + 0x76d89380, + 0x9084c002, + 0x430cb720, + 0x5e2db781, + 0xc0017500, + 0xd3f191a2, + 0xc01c2a3e, + 0xb59f753e, + 0xc0006268, + 0xc18091c2, + 0xc2005a21, + 0xb59f5a0c, + 0xb55f786c, + 0xb55f6368, + 0xc00062e8, + 0xd1a491e0, + 0x09025941, + 0x5a21c180, + 0x62e8b59f, + 0x6370b55f, + 0x6268b55f, + 0x786cb55f, + 0x430cb720, + 0x8d80e112, + 0x6cadb729, + 0x9c629e8c, + 0x90e0c00d, + 0x67a9b566, + 0x430cb720, + 0x5a21c180, + 0x5941c180, + 0x6829b586, + 0x430cb720, + 0x68a9b546, + 0x92e0c00c, + 0xc00476da, + 0xffd49124, + 0x9e839a1c, + 0x9eaa0a86, + 0x2dfcc00e, + 0xd21055cc, + 0xc00ea021, + 0xfff42dfc, + 0xd2109a2d, + 0xe111a9a2, + 0x050d8d00, + 0x09a2c002, + 0x9905ff94, + 0xaa21d210, + 0x52b0c200, + 0x29ded3f2, + 0x9aa9fff4, + 0x8c80e111, + 0x430cb780, + 0x50a9b740, + 0xb75f0244, + 0xc0987068, + 0xd2080a60, + 0xb780a115, + 0xb72050a9, + 0xc200430c, + 0x00c25a08, + 0x796cb79f, + 0x63adb582, + 0x8c80e111, + 0x50a9b780, + 0x430cb720, + 0x5a08c200, + 0xb79f00c2, + 0xb58279ec, + 0xe111682d, + 0xb7808c80, + 0xb72050a9, + 0xc200430c, + 0x00c25a08, + 0x7a6cb79f, + 0x6cadb582, + 0x8c80e111, + 0x50a9b780, + 0x430cb720, + 0x5a08c200, + 0xb79f00c2, + 0xb5827aec, + 0xe111712d, + 0xb7808c80, + 0xb72050a9, + 0xc200430c, + 0x00c25a08, + 0x7b6cb79f, + 0x75adb582, + 0x8c80e111, + 0x50a9b780, + 0x430cb720, + 0x5a08c200, + 0xb79f00c2, + 0xb5827bec, + 0xe1117a2d, + 0xb75f8c80, + 0xb7807c6e, + 0xb72050a9, + 0xc200430c, + 0x00c25a0c, + 0x61afb541, + 0x91a0c008, + 0xc00176dc, + 0xd3f192e4, + 0x75022a3e, + 0x90c2c001, + 0xc0007502, + 0x750492e6, + 0x93e4c007, + 0x430cb720, + 0x5a21c180, + 0x5941c180, + 0x4535b5c2, + 0x430cb720, + 0x6c29b588, + 0x430cb720, + 0x6ca9b548, + 0x91a0c007, + 0x430cb720, + 0x5a41c180, + 0x45b5b5c2, + 0x430cb720, + 0x6d29b588, + 0x9020c007, + 0x430cb720, + 0x5a41c180, + 0x4635b5c2, + 0x430cb720, + 0x6da9b588, + 0x92a0c006, + 0xc00376de, + 0xffd49164, + 0x9e85995a, + 0xc00e0a86, + 0x9e6b2efc, + 0x52acc200, + 0x2afcc00e, + 0xfff49eab, + 0xe111996b, + 0x050d8d00, + 0x0982c004, + 0xff94058b, + 0x058b9844, + 0x9826ff74, + 0xfff49eab, + 0xb78099ea, + 0xd032430c, + 0x0982296e, + 0x0629d110, + 0xc1369e9b, + 0xd2080a20, + 0xb720a18d, + 0xc300430c, + 0xcfc05a18, + 0xb5822a01, + 0xb7807ead, + 0xd031430c, + 0x00986ca9, + 0x78ecb79f, + 0x712db589, + 0x0624d010, + 0x796cb75f, + 0x0045d120, + 0x430cb780, + 0x2900c01e, + 0xc1365915, + 0xd2080a28, + 0xc000a101, + 0xb78090c0, + 0xb589404d, + 0xd3f170ad, + 0xb7602d3e, + 0xc100430c, + 0x9d4d5a08, + 0xc1360207, + 0xd2080a28, + 0xd110a902, + 0xe1130605, + 0xc2008d00, + 0x72955a08, + 0x80a6e020, + 0x0d8400c6, + 0x90b2ffff, + 0x9120c003, + 0xc00176ea, + 0xf01190a4, + 0xc0002a32, + 0xffd49362, + 0x9e8398ea, + 0x9eaa0a86, + 0x2dfcc00e, + 0xc00e55cc, + 0xd2102dfc, + 0xfff4a021, + 0xb74098fb, + 0xd210430c, + 0x050da9a2, + 0x0920c046, + 0x09d2c002, + 0x9040c001, + 0x430cb720, + 0x4f2db582, + 0x9060c002, + 0xc00176ec, + 0xffd490a4, + 0x9e8398c8, + 0x9eaa0a86, + 0x2dfcc00e, + 0xc00e55cc, + 0xd2102dfc, + 0xfff4a021, + 0xb74098d9, + 0xd210430c, + 0x050da9a2, + 0x0970c048, + 0x0982c002, + 0x9bafff74, + 0xaa21d210, + 0x52b0c200, + 0x29ded3f2, + 0x9953fff4, + 0x93a0c000, + 0xc00076e0, + 0xb7809164, + 0x0906430c, + 0x0a10c0a4, + 0xa101d208, + 0x9220c000, + 0xc00076c6, + 0xc2d490c4, + 0xc0009a1f, + 0xb7409140, + 0xd1a2598c, + 0xe2205e08, + 0x9ea4aa05, + 0xb7209c62, + 0x0203430c, + 0x0a10c0a4, + 0xaa01d208, + 0xc0007500, + 0x0a029222, + 0x44abb585, + 0x430cb720, + 0x4829b78a, + 0x48b1b76a, + 0x45b49ea2, + 0x2dfcc00e, + 0x991dfff4, + 0x7aeeb79f, + 0x7b6eb7bf, + 0x7beeb7df, + 0x8c60c004, + 0xa61d9c22, + 0x8400c002, + 0xd050a192, + 0x0c82aa61, + 0x0ca0c146, + 0x9ea51a08, + 0x4c8cb780, + 0x2efcc00e, + 0xb7e064d3, + 0x9e4a4794, + 0x03a8a096, + 0x9eba9eb9, + 0x0882010f, + 0x0c80c06c, + 0x0960c06c, + 0x0d00c06e, + 0xa09d028f, + 0xb55fa09a, + 0xb55f7dec, + 0x058b7d74, + 0x9ab6ff74, + 0x430cb780, + 0x0a38c0a2, + 0xab01d208, + 0x90a0c000, + 0xffd40d92, + 0xa99a9821, + 0xb78d008f, + 0xd01060a9, + 0xb7c0a961, + 0x70884c94, + 0x9282ffff, + 0xc0007580, + 0xb7209164, + 0xb76a430c, + 0xff7447b1, + 0x74009ab2, + 0x9104ffff, + 0xff74058b, + 0xa9199a91, + 0xd0089ea9, + 0xb76daa41, + 0x710660c9, + 0x9102c001, + 0xc180aa15, + 0xb73f5890, + 0x00987df4, + 0x009cc101, + 0x4cadb783, + 0x4db5b743, + 0x4c2db743, + 0x4d2db723, + 0x404db580, + 0xd0129ea9, + 0xb52309b2, + 0xb79f5bcd, + 0x099a7d6c, + 0x5acdb543, + 0xa102f208, + 0x297cc006, + 0xc2f4a11d, + 0x008b9bb5, + 0x60a9b50d, + 0xff74058b, + 0xb7209a5f, + 0xa99e430c, + 0x8d00e091, + 0x5bb5b743, + 0x5b2db763, + 0x990bfff4, + 0x7068b79f, + 0x753ec01c, + 0x90c4c000, + 0x9a78ff74, + 0x7068b51f, + 0x7070b77f, + 0x55ac0c86, + 0x2dfcc00e, + 0x9beaffd4, + 0x4490b760, + 0x4c8cb740, + 0x7068b77f, + 0xc1469e5c, + 0x00c46a22, + 0x5ab5b743, + 0x5d3d9e5a, + 0xffd42d04, + 0xb77f98b9, + 0x0d067070, + 0xc00e55cc, + 0xfff42dfc, + 0xf250985e, + 0x7508aa61, + 0x90a4c000, + 0xf2500d86, + 0xb720a1e2, + 0xb740430c, + 0xb7604914, + 0xf0104e8c, + 0x7508aa41, + 0x91c4c000, + 0x47a9b78a, + 0xa961d008, + 0xc01c2244, + 0xc0007d3e, + 0x0a0690a2, + 0xa241f010, + 0x4894b720, + 0xc1460d50, + 0x728209a0, + 0x9124ffff, + 0x7482a91d, + 0x90e4fffa, + 0x4794b740, + 0xa141f050, + 0x4608b780, + 0x0a04a992, + 0x4608b580, + 0xf0100a1a, + 0xb79fa26d, + 0xb7bf7c6e, + 0xb7df7cee, + 0xb7ff7d6e, + 0xc0047dee, + 0x9c228c00, + 0xc006a61d, + 0xb7208440, + 0xf1d2430c, + 0xb7838d00, + 0xb7c35c2d, + 0xa2155b2d, + 0x5badb783, + 0x0a06a219, + 0x5218c200, + 0xb7239ea5, + 0xc00e5aad, + 0x058b2efc, + 0xffd4a091, + 0xb7209b73, + 0xe1d14314, + 0xb9608d00, + 0xb7ed4028, + 0xb7ed6049, + 0x9e4960d1, + 0x4c2db783, + 0xa241f008, + 0x4cadb783, + 0xa245f008, + 0x4d2db783, + 0xa249f008, + 0x4dadb783, + 0xf00808c0, + 0x0940a24d, + 0x91c1ffff, + 0xb5aa0a82, + 0xb7204849, + 0xd3f2430c, + 0xc00629ee, + 0xb5aa0992, + 0xa91a48a9, + 0x430cb740, + 0x9a25ff74, + 0x430cb720, + 0xb5aa058b, + 0xb7204831, + 0xb5aa430c, + 0xb78048b1, + 0xc0a4430c, + 0xd2080a10, + 0xb720a281, + 0xb5a5430c, + 0xffd444ab, + 0xb7209bbc, + 0x9eaa430c, + 0x4028b960, + 0x6029b5ed, + 0x430cb720, + 0x60b1b5ed, + 0x430cb720, + 0xaa41f210, + 0x5c90c100, + 0x0493d110, + 0xb5830d04, + 0xb7204c2d, + 0xf210430c, + 0xd110aa45, + 0xb5830493, + 0xb7204cad, + 0xf210430c, + 0xd110aa49, + 0xb5830493, + 0xb7804d2d, + 0xf210430c, + 0x0f40a94d, + 0x0498c101, + 0x4dcdb543, + 0x9381fffe, + 0x430cb720, + 0xb583aa11, + 0xb7205aad, + 0xb5c3430c, + 0xb7205b2d, + 0xaa19430c, + 0x5badb583, + 0x430cb720, + 0xb583aa15, + 0xb7205c2d, + 0xb780430c, + 0xb58a70a9, + 0xb72047a9, + 0xb780430c, + 0xb58a7029, + 0xb7204729, + 0xb780430c, + 0xb58a6fa9, + 0xb72046a9, + 0xb780430c, + 0xb58a6f29, + 0xb7204629, + 0xb780430c, + 0x7504572b, + 0x91d2c001, + 0x0a42c809, + 0x0a30c0ec, + 0x5cadb580, + 0x430cb720, + 0x0a42c809, + 0x0a40c06c, + 0x5d2db580, + 0x430cb720, + 0x44b5b760, + 0x46b5b740, + 0x452db740, + 0x472db780, + 0x572bb760, + 0x6127c101, + 0x6245c101, + 0xd02074c0, + 0xc00102c4, + 0xb7409024, + 0xb78048ad, + 0x6245492d, + 0x06d8c101, + 0x9300c000, + 0x0a42c809, + 0x0a30c0aa, + 0x5cadb580, + 0x430cb720, + 0x0a42c809, + 0x0a40c080, + 0x5d2db580, + 0x430cb780, + 0xa905f248, + 0xaa09f248, + 0x62c4d032, + 0x430cb720, + 0x0a02c100, + 0xb5809e6b, + 0xb7a05ead, + 0x008b430c, + 0x5eb5b760, + 0x99d7c2f4, + 0xb500008b, + 0xb7a05ead, + 0xf248430c, + 0x7500aa35, + 0x9242c000, + 0xb760008b, + 0x01895eb5, + 0x61c7d132, + 0x2d81cffc, + 0x99c3c2f4, + 0xc0007400, + 0x008b90a2, + 0x5eadb500, + 0x430cb720, + 0x5e19d2a2, + 0x5dadb580, + 0x4314b740, + 0xaa4df050, + 0xa945f050, + 0x1a040244, + 0xa24df050, + 0x430cb7a0, + 0xaaa6f248, + 0xa9aef248, + 0xc2f49e6b, + 0xc10199a4, + 0xf248600b, + 0xb720a02d, + 0xb720430c, + 0xb78046b5, + 0xb740472d, + 0xb7604535, + 0xb74044b5, + 0xb760492d, + 0xc10148ad, + 0x65276243, + 0xc1016127, + 0x02440244, + 0x5a19c200, + 0x5e2db580, + 0x430cb740, + 0xaa45f008, + 0x7d3ec004, + 0x90e4c001, + 0xaa51f008, + 0x2a7ce002, + 0x9024c001, + 0x01899ea2, + 0x91c0c000, + 0x5f4db560, + 0x430cb720, + 0xb56000a2, + 0xb72067ad, + 0x00a2430c, + 0x65adb560, + 0x430cb720, + 0x6d21d131, + 0x4629b78a, + 0x00a2d020, + 0x0d047299, + 0x9146ffff, + 0xb5800a02, + 0xb79f712d, + 0xb7bf776e, + 0xb7df77ee, + 0xb7ff786e, + 0xc00878ee, + 0x9c228c40, + 0xb7a0a605, + 0x0e86430c, + 0xb763008b, + 0xb7a35b35, + 0xc2005bad, + 0xc00e55ac, + 0xffd42dfc, + 0xb72099e5, + 0x9eaa430c, + 0x0982c008, + 0x6c31b76d, + 0x0918d191, + 0x98bbff74, + 0x430cb720, + 0x5b35b743, + 0x56a8c200, + 0x2dded3f2, + 0x9a5dffd4, + 0x430cb720, + 0x0a18d191, + 0x612db582, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0xb7a0a605, + 0x0e86430c, + 0xb763008b, + 0xb7a35b35, + 0xc2005bad, + 0xc00e55ac, + 0xffd42dfc, + 0xb72099b5, + 0x9eaa430c, + 0x0982c008, + 0x6c31b76d, + 0xc0180103, + 0xff740930, + 0xb720988a, + 0xb743430c, + 0xc2005b35, + 0xd3f256a8, + 0xb79f2dde, + 0xb7bf7f6e, + 0x8c407fee, + 0x90e0ffd1, + 0xb7a0a60d, + 0xb7204994, + 0x09024c8c, + 0x0d96050b, + 0xb9600185, + 0x0a024038, + 0x0a20c146, + 0x02426229, + 0x0a18c144, + 0xa182f208, + 0xf0310904, + 0xffffa1d5, + 0xb7409281, + 0xc809478c, + 0xcbdc0a46, + 0xf0480a30, + 0xf008a1c1, + 0x0287a255, + 0xffd40b06, + 0xf23199c6, + 0xd3f1aa35, + 0x0d82295e, + 0x9eb27500, + 0xc0000a84, + 0x9e5b90e2, + 0x4508b5c0, + 0x9a44ffb4, + 0xffff7550, + 0xb79f9204, + 0xb7bf7eee, + 0xb7df7f6e, + 0x8c607fee, + 0x5db09c22, + 0x0d80c021, + 0x0da0c102, + 0xaa619d3e, + 0xc40059b8, + 0xcbfe2980, + 0x32462a7d, + 0xf0009dbe, + 0x9c22a261, + 0x430cb720, + 0x9e5b0926, + 0x6735b744, + 0xd0110802, + 0x75101e22, + 0x4826b322, + 0x9c8bc010, + 0x9160c000, + 0xaa01d208, + 0xc0007106, + 0xc00e90a4, + 0x9c22287c, + 0x02030804, + 0x0a74c098, + 0xffff0884, + 0xc00e9261, + 0x9c22087e, + 0xb740a605, + 0xd1a2430c, + 0x00d45e88, + 0x6fadb789, + 0x02446a32, + 0x0a20c138, + 0xa911d208, + 0xd2080904, + 0xb740a111, + 0x00d4430c, + 0x6fadb789, + 0x02446a32, + 0x0a20c138, + 0xaa11d208, + 0xc0007502, + 0xc00e90d4, + 0xc001087e, + 0xc10192c0, + 0x090200a6, + 0x4829b54c, + 0x430cb720, + 0x5e18d1a2, + 0x0982c004, + 0x04b3d110, + 0x5914b760, + 0x4929b54c, + 0x01c7d120, + 0x430cb780, + 0xc05e0258, + 0xf2080a60, + 0xb720a101, + 0xb543430c, + 0xb720402d, + 0x00d2430c, + 0x40adb543, + 0x430cb720, + 0x41adb543, + 0x9a2fff34, + 0x430cb740, + 0xb78900d4, + 0x6a326fad, + 0xc1380244, + 0xd2080a20, + 0xb79fa811, + 0xb7bf7f6e, + 0x8c407fee, + 0xb7609c22, + 0x0d02430c, + 0x4078b960, + 0x0134c101, + 0xc1360205, + 0xd2080a2c, + 0x7500aa01, + 0x92a4c000, + 0x0920c136, + 0xd0080a04, + 0xb740a24d, + 0xd031430c, + 0xc00e6e29, + 0x02442d7c, + 0x0a20c138, + 0xd208097f, + 0xc000a111, + 0x0d0490e0, + 0x9041ffff, + 0x0d7ec00e, + 0x9c229e50, + 0xb720a61d, + 0x9e5f430c, + 0xc0a40203, + 0xd2080a10, + 0xb7caaa01, + 0x75004729, + 0x93a4c005, + 0x5a88c300, + 0x02d2d020, + 0xb7899e69, + 0xc01c6fad, + 0xc001753e, + 0x9eb39004, + 0xfff49eae, + 0x9e699bbc, + 0x9180c000, + 0x984cffb4, + 0x430cb7a0, + 0xd1109eb3, + 0xfff406eb, + 0x008b9bb0, + 0x6fadb509, + 0x430cb720, + 0xd1100d92, + 0xb78904e3, + 0xc01c6fad, + 0xffff753e, + 0xb7209162, + 0xc300430c, + 0xd0205908, + 0x9e8a00a2, + 0x6fcdb789, + 0x0d10c09c, + 0x00c26a32, + 0x712db729, + 0x568cb780, + 0xe0409e8b, + 0xd010a1c6, + 0x7500aa41, + 0x9284c003, + 0xc0009eb3, + 0xffb491c0, + 0xb7809819, + 0x9eb3430c, + 0x0a10c0a4, + 0xaa01d208, + 0xc0037500, + 0xfff49184, + 0xc01c9b1b, + 0x0d92743e, + 0x91e2ffff, + 0xc00175c0, + 0xb7209062, + 0x0982430c, + 0xb76a9e9a, + 0xb72a46b1, + 0xd1a24729, + 0x01095e30, + 0x0900c021, + 0x0930c140, + 0x91a0c000, + 0xf0009dad, + 0xd011a162, + 0x9dcd0a28, + 0xa162f000, + 0xc1000984, + 0xc1010900, + 0x71020236, + 0x925cffff, + 0x4314b720, + 0x5988d324, + 0x59b0c300, + 0x04b2d010, + 0x0980c021, + 0x6fb5b749, + 0x09c0c146, + 0x6d29d031, + 0x0624d010, + 0x0122c101, + 0x0920c138, + 0xa951d008, + 0x0244c101, + 0xc2000244, + 0xc1015a08, + 0xb78000c2, + 0xb7294f8c, + 0x9ea270ad, + 0xa0e9e020, + 0xf0009dbd, + 0xb786a0e1, + 0x750040c9, + 0x9184c000, + 0x53cbb78c, + 0xc0007500, + 0xb76690e2, + 0x9eb34a4d, + 0x99cbff94, + 0x430cb780, + 0xc09c0906, + 0xd2080a10, + 0xb79fa101, + 0xb7bf7e6e, + 0xb7df7eee, + 0xb7ff7f6e, + 0xc0027fee, + 0x9c228c00, + 0xb720a605, + 0x9e5d430c, + 0x63adb744, + 0xc0017ca0, + 0xb7819202, + 0x75045dad, + 0x90e4c000, + 0x5a21c100, + 0xb5842a04, + 0xb7207e2b, + 0xb781430c, + 0x1a105dad, + 0xc0007502, + 0x0a0690b2, + 0x7f2bb584, + 0x430cb720, + 0x6e29b788, + 0x9e8b0183, + 0x5333b741, + 0x6aadb749, + 0x098cc026, + 0xc04a01b8, + 0x9e940df0, + 0xb7209c62, + 0xb784430c, + 0xcffe63ad, + 0xb5842a3d, + 0xb72063ad, + 0xb78c430c, + 0x7500532b, + 0x9222c001, + 0x6cadb744, + 0xc0007484, + 0xb7819124, + 0x75004bad, + 0x9084c001, + 0x9140c000, + 0xc0007482, + 0xb78190e4, + 0x75024b2d, + 0x9344c000, + 0xc09c0203, + 0xd2080a14, + 0x7500aa01, + 0x9244c000, + 0xc0007486, + 0x02039144, + 0x0a40c09a, + 0xaa01d208, + 0xc0007500, + 0xb78190e4, + 0x750a5dad, + 0x90a4c000, + 0xb58c0a02, + 0xb720532b, + 0x0203430c, + 0x0a18c0a4, + 0xaa01d208, + 0x6cb5b764, + 0xc0007500, + 0xb74193e2, + 0xb70953ab, + 0xb76c6c2d, + 0x9eaa532b, + 0x9c629e84, + 0x430cb720, + 0x5dadb781, + 0x75021a10, + 0x90f2c000, + 0x532bb78c, + 0xc0017500, + 0x02039064, + 0x0a20c09c, + 0xa001d208, + 0x9380c000, + 0xc00076c4, + 0xb7499164, + 0x020375a9, + 0x0a20c09c, + 0xa101d208, + 0x9200c000, + 0x76c60103, + 0x0920c09c, + 0x90c4c000, + 0x7629b789, + 0x9080c000, + 0x7529b789, + 0xa241d008, + 0x430cb720, + 0x5dadb781, + 0x75021a10, + 0x90f2c000, + 0x532bb78c, + 0xc0007500, + 0xb74a9344, + 0xb76046a9, + 0x01835514, + 0x09a0c09c, + 0x9140c000, + 0xaa61d008, + 0x9e529e91, + 0xa229c030, + 0x297cc00e, + 0x4729b78a, + 0x0922d012, + 0xffff7104, + 0xb79f9268, + 0xb7bf7f6e, + 0x8c407fee, + 0xb7209c22, + 0x05964314, + 0x0da0c098, + 0xa8edd010, + 0x6e4db704, + 0x4000ba09, + 0xd001747f, + 0xb3401802, + 0x009248a2, + 0x0092c101, + 0x532bb789, + 0x2a60c00e, + 0x5a0fc200, + 0x9c220040, + 0xb7a0a61d, + 0x0687430c, + 0x020b9e9e, + 0x0a58c096, + 0xa982d208, + 0xfff49e57, + 0x020b9bda, + 0x0a54c096, + 0xa982d208, + 0xfff40301, + 0x020b9bd2, + 0x0a50c096, + 0xaa01d208, + 0x9e819ea8, + 0xc0980258, + 0xd2080a20, + 0xb744aa0d, + 0xba246e4c, + 0x753f4000, + 0x19a2d001, + 0x9202c000, + 0xc096020b, + 0xd2080a30, + 0x0092a881, + 0xb789009a, + 0xc00e532b, + 0xc2002a60, + 0x01c45a0f, + 0xc0007780, + 0x9eaa9102, + 0xc0260d82, + 0xc0010d50, + 0x75c69320, + 0x91e2c000, + 0xd01d7186, + 0xd01e1266, + 0xd012123c, + 0xd03119c2, + 0xc0286e39, + 0xc0010a00, + 0x020b90e0, + 0x0a08c098, + 0xaa01d208, + 0xc0007500, + 0x9e699222, + 0x0a02c409, + 0x622db580, + 0x0a42c001, + 0x0a00c010, + 0x6335b5c0, + 0x62adb580, + 0x9220c001, + 0x0c0270d3, + 0x1617d11e, + 0x1233d11d, + 0x1942d012, + 0x7280cc12, + 0x6e39d031, + 0x0a60c09c, + 0x0158d020, + 0xaa49f010, + 0x76c09e69, + 0x622db580, + 0xaa45f010, + 0x62adb580, + 0xaa41f010, + 0x632db580, + 0x9236c000, + 0x5d60d0a2, + 0x2a6ed3f1, + 0x5a20c200, + 0xd3f13244, + 0xc00e293e, + 0x59403a7c, + 0xb5803244, + 0xb79f622d, + 0xb7bf7e6e, + 0xb7df7eee, + 0xb7ff7f6e, + 0xc0027fee, + 0x9c228c00, + 0x8420a605, + 0x430cb720, + 0xb5bf0a82, + 0xb72a7e6a, + 0xb72046a9, + 0x04075514, + 0x02079e8b, + 0xa969c010, + 0x04859e43, + 0x8c80e031, + 0xff749ea2, + 0xb7209b4b, + 0x018b430c, + 0x46b1b76a, + 0x984bff94, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x9c228c60, + 0x4314b720, + 0x5cb0d1a2, + 0xb7859e9a, + 0xc1407ec9, + 0xc0210880, + 0xc2000880, + 0xc0205a24, + 0x3a042a00, + 0xf0009d9d, + 0x0185a261, + 0xff820906, + 0xf8399320, + 0x8420a205, + 0x430cb720, + 0xb59f0a02, + 0xb7417e6a, + 0x02035f2b, + 0x0a20c09c, + 0xd2087480, + 0xc000a981, + 0xb7409104, + 0xe0326ead, + 0xfff48d00, + 0xf9f89bd3, + 0x9c22aa19, + 0xa205f839, + 0xb7208420, + 0x0a02430c, + 0x7e6ab59f, + 0x5f2bb741, + 0x74809ea2, + 0x9204c000, + 0xc0a40203, + 0xd2080a14, + 0xb720a102, + 0xe032430c, + 0x09ea8d00, + 0x6cadb740, + 0x9bb4fff4, + 0xaa19f9f8, + 0xa6059c22, + 0x430cb720, + 0xb7810687, + 0x75045dad, + 0x93c4c000, + 0x558cb780, + 0xc0409e5a, + 0x7500aa45, + 0x9142c000, + 0x2ebed3f1, + 0xfff49eab, + 0x9eab9bb2, + 0x9180c000, + 0xc0a40203, + 0xd2080a14, + 0x7500aa01, + 0x90c2c000, + 0x2dfcc00e, + 0x9bbefff4, + 0x430cb720, + 0xc09c0203, + 0xd2080a18, + 0x7500aa01, + 0x9162c001, + 0x5dadb781, + 0xc0017504, + 0xb78690c4, + 0x75004129, + 0x9022c001, + 0x558cb780, + 0xc0409e6a, + 0x7500aa45, + 0x9142c000, + 0x68adb760, + 0x2dded3f2, + 0x09060d02, + 0x9bd6ff74, + 0x430cb720, + 0x2dded3f2, + 0xb7600d02, + 0x0906692d, + 0x7f6eb79f, + 0x7feeb7bf, + 0xff7e8c40, + 0xb79f90e0, + 0xb7bf7f6e, + 0x8c407fee, + 0xa61d9c22, + 0x558cb740, + 0x4314b720, + 0x9e920a02, + 0xc0200687, + 0xb741a269, + 0xd0115dcd, + 0x75021a28, + 0x9172c000, + 0x534bb78c, + 0xc0007500, + 0xb74090c2, + 0xc0006e55, + 0xb7849140, + 0xc2006ccd, + 0xc1015a08, + 0xb74000c2, + 0x748a6cb5, + 0x90a2c000, + 0xc0000906, + 0xb78090e0, + 0x9e6b500c, + 0xa965c040, + 0x46d1b76a, + 0xb7409e53, + 0xc0205514, + 0xff74a96a, + 0xb7209b8b, + 0xb7814314, + 0x1a105dcd, + 0xc0037502, + 0xb78c91b2, + 0x7500534b, + 0x9102c003, + 0x0ed2d011, + 0x0b02c008, + 0x5ab0c280, + 0xc0219eae, + 0x0f400f00, + 0xf0009dee, + 0x010ba361, + 0x0900c040, + 0x0900c021, + 0xaa619d2d, + 0x3a40c002, + 0xf0009dad, + 0xd2a2a261, + 0x9ead5c88, + 0x0092c101, + 0x6fb5b749, + 0x0e80c021, + 0xd0310ea0, + 0xd0106d29, + 0xc1010624, + 0xc1380122, + 0xd0080920, + 0xc101a951, + 0x02440244, + 0x5a08c200, + 0x00c2c101, + 0x0a02c401, + 0x70adb7e9, + 0x0a00c008, + 0xf0009dde, + 0x9eaba261, + 0x09929eb2, + 0xff14010d, + 0x0a0299f6, + 0xf0009dde, + 0x9deea261, + 0xa361f000, + 0xc021020b, + 0xc0400a00, + 0x9d4d0a20, + 0x1a10a962, + 0xaa619d4d, + 0x0a80c021, + 0x0ac0c046, + 0xa9619d5d, + 0xc0007480, + 0xd12290e2, + 0x112e5e35, + 0x11282a7c, + 0x430cb720, + 0x76adb544, + 0x7e6eb79f, + 0x7eeeb7bf, + 0x7f6eb7df, + 0x7feeb7ff, + 0x8c00c002, + 0xa6059c22, + 0x068774c0, + 0x9324c000, + 0x500cb780, + 0xc0409e5a, + 0x7500aa45, + 0x9222c000, + 0x430cb720, + 0xc09c0203, + 0xd2080a10, + 0x7500aa01, + 0x90e2c000, + 0x4729b78a, + 0xc0017117, + 0xb7209302, + 0x0203430c, + 0x0a38c0a2, + 0xaa01d208, + 0xc0007500, + 0x010393c4, + 0x4729b78a, + 0x091cc0a4, + 0xa941d008, + 0x4629b76a, + 0x124ac101, + 0xd0126245, + 0xc10119b2, + 0xc0a2029a, + 0xc1010ac0, + 0xd20805b8, + 0xc2b4aaa5, + 0x08049bcf, + 0xc0007140, + 0xb7409244, + 0xd2a24f94, + 0xd2a25e30, + 0x9e535d08, + 0x0a00c021, + 0xa945e030, + 0x0a40c146, + 0xf0009dcd, + 0xb79fa161, + 0xb7bf7f6e, + 0x8c407fee, + 0xa60d9c22, + 0x030774c6, + 0xc0009e5d, + 0x74c490a2, + 0x90a4c000, + 0xc0009eb6, + 0xb74092c0, + 0x0205430c, + 0x0a14c09c, + 0xaa01d208, + 0xc0007500, + 0x0f0690a4, + 0x9120c000, + 0xc06e0205, + 0x71480a10, + 0xd0020f02, + 0xf2080f62, + 0xb720aa31, + 0x73994314, + 0x9344c000, + 0x58cdb783, + 0xa221f208, + 0x430cb720, + 0x592db723, + 0xa0a5f208, + 0x430cb720, + 0x59adb723, + 0xa0a9f208, + 0x430cb720, + 0x5a2db723, + 0xa0adf208, + 0x90e0c001, + 0x5c88d322, + 0x46d1b76a, + 0x0092c101, + 0x6a35b740, + 0x09c2c010, + 0xff34010b, + 0xb7209aea, + 0xf208430c, + 0xb583aa21, + 0xb72058ad, + 0xf208430c, + 0xb583aa25, + 0xb720592d, + 0xf208430c, + 0xb583aa29, + 0xb72059ad, + 0xf208430c, + 0xb583aa2d, + 0xb7205a2d, + 0xd0524314, + 0xb7880ad8, + 0xba0c6c49, + 0xc0004008, + 0x5888922a, + 0x0092c101, + 0x46d1b76a, + 0x46b5b742, + 0xc00e9e6a, + 0xff3409f2, + 0x0a169abc, + 0xa231f208, + 0xaa21d210, + 0x0982c400, + 0x0902c200, + 0xa221f210, + 0xa92ef208, + 0x2d7dc9fe, + 0xa12ef208, + 0x430cb720, + 0x752db784, + 0xb3437500, + 0x75004422, + 0x4422b342, + 0x9e533126, + 0xf2083126, + 0xb720a12d, + 0xb784430c, + 0x75026cad, + 0x90c2c000, + 0x3900c020, + 0xa12df208, + 0xaa2df208, + 0x3a00c010, + 0xa22df208, + 0x430cb720, + 0x6cadb784, + 0xc0007506, + 0xf20891c4, + 0xc080aa21, + 0xc0007d00, + 0x010391c2, + 0x0914c098, + 0xc0000a02, + 0x010390c0, + 0x0914c098, + 0xd0080a0a, + 0xf208a241, + 0xc040aa21, + 0xc0027d00, + 0xb72093a2, + 0xb784430c, + 0x75046cad, + 0x92c4c002, + 0xc0980183, + 0xd0080990, + 0x7480a961, + 0x91c4c002, + 0x702db784, + 0x7d3edffd, + 0x92c2c000, + 0xc0980203, + 0xd2080a08, + 0x7500aa01, + 0x9082c001, + 0xc0980203, + 0xd2080a0c, + 0x7500aa01, + 0x9382c000, + 0xa161d008, + 0x90a0c001, + 0x01030203, + 0x0a58c096, + 0x0954c096, + 0xa902d208, + 0xaa41d008, + 0xc0007299, + 0xb7859164, + 0x75007ea9, + 0x90c4c000, + 0xa261d008, + 0x91e0c000, + 0xc0980103, + 0x0a060910, + 0xa241d008, + 0x430cb780, + 0xc0980902, + 0xd2080a14, + 0xb780a101, + 0xc098430c, + 0xd2080a10, + 0x7500aa01, + 0x9102c000, + 0xaa2df208, + 0x2a7dcfbe, + 0xa22df208, + 0x430cb720, + 0x5dadb781, + 0xc0007504, + 0xf2089102, + 0xcfdeaa2d, + 0xf2082a7d, + 0xb720a22d, + 0xb781430c, + 0x75045dad, + 0x9304c001, + 0xa92df208, + 0x0a5ecfff, + 0x0a7cc7fe, + 0x2128d020, + 0xa12ef208, + 0x430cb720, + 0xc09a0203, + 0xd2080a40, + 0x7500aa01, + 0x90e2c000, + 0x4b2db781, + 0xc0007502, + 0xb78690e4, + 0x75004029, + 0x9142c000, + 0xc8009e53, + 0x32262900, + 0x3a20c001, + 0xa22df208, + 0x430cb720, + 0x4b2db781, + 0xc0007502, + 0xf2089164, + 0xcfffaa2d, + 0xc8fe0962, + 0x2244097c, + 0xa22df208, + 0x430cb780, + 0xa9adf208, + 0x0d02c011, + 0x0a08c098, + 0xa901d208, + 0xc0215964, + 0x31262900, + 0xa12df208, + 0x430cb780, + 0x0a0cc098, + 0xaa01d208, + 0x5a68c200, + 0x2a00c041, + 0xf2083128, + 0xb780a12d, + 0xcfef430c, + 0xc098297e, + 0xd2080a14, + 0x7500aa01, + 0xb3420a02, + 0x9e544444, + 0xf2083144, + 0xb720a12d, + 0xb781430c, + 0x7500612d, + 0x90c2c000, + 0x3940c001, + 0xa12df208, + 0x430cb720, + 0x5e2db781, + 0xc0007508, + 0xb78191a4, + 0x75045dad, + 0x9104c000, + 0xaa2df208, + 0x3a00c201, + 0xa22df208, + 0x9eab7780, + 0x09829eb2, + 0x09b2d001, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0xffdd8c60, + 0xf8399320, + 0x04b6a285, + 0xb7600407, + 0x9e485114, + 0x518cb780, + 0xa8aac030, + 0x5094b760, + 0xc00f59c0, + 0xc84029fc, + 0xc030aa05, + 0x9e9da98a, + 0x5a20c200, + 0x76c0349a, + 0xe0329e48, + 0xcff08d80, + 0x32082a00, + 0xa9f9d9d0, + 0x90c2c000, + 0x3a00c201, + 0x90e0c000, + 0xc0007680, + 0xc1019082, + 0x74803a00, + 0x9082c000, + 0x3a00c011, + 0xc0007440, + 0x74c09122, + 0x3a00c021, + 0x9082c000, + 0x3a00c041, + 0x5d08d028, + 0x549cb740, + 0xe0209e2d, + 0xf9f8a26d, + 0x9c22aa9d, + 0x8420a61d, + 0x558cb780, + 0xb7c09e5e, + 0xc2404314, + 0xa199aa45, + 0x9e8f9e73, + 0x8c80e0b1, + 0x09c4c09a, + 0x9e937500, + 0xabe1d008, + 0x7e29b7bf, + 0x7e33b7bf, + 0x7d33b73f, + 0x9244c000, + 0xb7849e71, + 0x7500752d, + 0x90e4c000, + 0x6cadb784, + 0xc0007502, + 0x9e7190e2, + 0x6cadb704, + 0x9060c000, + 0x77400802, + 0x9142c000, + 0xb7849e71, + 0xd1106c2d, + 0x9ea30639, + 0x2dfccffe, + 0xc09c9e74, + 0xd2080a18, + 0x7480a901, + 0x90a4c000, + 0xc0019e90, + 0x9e749100, + 0x0a38c0a2, + 0xaa01d208, + 0xc0007500, + 0x0c0690a2, + 0x93a0c000, + 0xc1019e71, + 0xb78a01ec, + 0x710c4729, + 0x9124c000, + 0xc0a20207, + 0xd2080a20, + 0xc000a812, + 0x010791c0, + 0xc0a20207, + 0xc0a20924, + 0xd2080a20, + 0xd008aa11, + 0xd020a951, + 0x75421044, + 0x90d2c000, + 0x00ecc101, + 0x4a31b56a, + 0xc0007640, + 0x9e719104, + 0x6729b786, + 0xc0067500, + 0xb7209062, + 0x5d184314, + 0x5908c380, + 0x049dd110, + 0x684db784, + 0x4a31b76a, + 0x2d00c03c, + 0x5a38c200, + 0x2a00cc00, + 0x4b29b76a, + 0x2970c002, + 0x31289e51, + 0xb78c5de0, + 0x3122534b, + 0x59c09e59, + 0x31263122, + 0xd0117500, + 0xd0202a06, + 0xc00031a8, + 0xc0809082, + 0x9e4c3d80, + 0x0a18c09c, + 0xaa01d208, + 0xc0007500, + 0xc0409082, + 0x77c03d80, + 0x9082c000, + 0x3d80c100, + 0x570cb780, + 0x5938d324, + 0x5d40d022, + 0xaa45c240, + 0x2d00cc00, + 0xc2009e51, + 0xc2805a08, + 0x324259e0, + 0xc00f3246, + 0xd020297c, + 0x9e4c3144, + 0xc0967740, + 0xd2080a50, + 0xb740aa01, + 0xd002590c, + 0xc2003d24, + 0xc1015a08, + 0xf208024c, + 0xc380aa11, + 0xc101588c, + 0x75000092, + 0x5a18c300, + 0xa9190244, + 0x3d22d002, + 0xf2080289, + 0xb721a109, + 0xc12461af, + 0xf2080e82, + 0xf208a18e, + 0xfa08a112, + 0x9e6ba081, + 0x9eb39eaa, + 0xfef40ec0, + 0xc2509a52, + 0x0ac07740, + 0x92e4ffff, + 0x568cb780, + 0x5a88d324, + 0xd1109eb3, + 0xc00406d9, + 0xf2080982, + 0xc124a922, + 0xfef40902, + 0x9eb39bed, + 0x9804ff14, + 0xb7869e71, + 0x75006729, + 0x92c2c000, + 0x4f8cb740, + 0xf208aa19, + 0xd110a922, + 0x0a3c0555, + 0xa9c1f008, + 0x0d00c004, + 0xa122f208, + 0x2a410246, + 0xa241f008, + 0x9300c000, + 0xa922f208, + 0xc0049eb3, + 0xc1240982, + 0xff140902, + 0x9eb39be0, + 0x7deeb79f, + 0x7e6eb7bf, + 0x7eeeb7df, + 0x7f6eb7ff, + 0x8c20c002, + 0x9280fefe, + 0x7deeb79f, + 0x7e6eb7bf, + 0x7eeeb7df, + 0x7f6eb7ff, + 0x8c20c002, + 0xb7209c22, + 0x9e5a430c, + 0xc0a20203, + 0xd2080a38, + 0x7500aa01, + 0x9222c000, + 0x02039e8a, + 0x0d20c0a4, + 0x0a40c0a2, + 0xa901d208, + 0xaa41d010, + 0x70880802, + 0x0802d003, + 0xb7859c22, + 0x75007ea9, + 0x9162c000, + 0x500cb780, + 0xaa45c040, + 0xc0007500, + 0x08069082, + 0x02229c22, + 0xc0a20109, + 0xc0a20920, + 0xd2080a40, + 0xd008aa05, + 0x0802a951, + 0xd0037104, + 0x9c220802, + 0x430cb720, + 0x02030c06, + 0x0a20c136, + 0xa902d208, + 0x46b1b76a, + 0xa886d228, + 0x19049e52, + 0xc0007097, + 0xb74a9096, + 0x9e404729, + 0x29aed3f1, + 0x7913520c, + 0x90a4c000, + 0xffff7095, + 0xd0319244, + 0x6a520a24, + 0x478cb740, + 0xd0310244, + 0xf0080948, + 0x7508aa41, + 0xc1360203, + 0xb4020a20, + 0xd2084a22, + 0x9c22a181, + 0x430cb740, + 0xc1360205, + 0xd2080a24, + 0x7500aa01, + 0x90e4c000, + 0xc1360205, + 0xd2080a20, + 0x9e5aa182, + 0xc2000a06, + 0xb7405208, + 0xc136430c, + 0xd0080924, + 0x9e53a942, + 0xd0083246, + 0x9c22a241, + 0x9e5da605, + 0x9080c000, + 0x9846ff74, + 0x430cb780, + 0xc1360d92, + 0xd2080a20, + 0x710aaa01, + 0x92c4ffff, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0x550cb780, + 0xb7209e5a, + 0xc040430c, + 0x5db0aa45, + 0x67adb741, + 0x2a7cc002, + 0x0d80c021, + 0xc1163244, + 0x9dbe0df0, + 0xa261f000, + 0xa60d9c22, + 0x430cb720, + 0x02039e5e, + 0x0a30c096, + 0xaa01d208, + 0xc0047500, + 0xb7a49344, + 0xb76468ad, + 0x7540672d, + 0x9222c000, + 0x67b5b744, + 0xc000729b, + 0x02039188, + 0x0a34c096, + 0xa901d208, + 0x1254c101, + 0xc0007104, + 0x74c090c6, + 0x9022c004, + 0x01030287, + 0x67adb784, + 0x0934c096, + 0xa941d008, + 0x71041258, + 0x92a8c003, + 0x46b1b76a, + 0xc2000e86, + 0xc00e55ac, + 0xff942dfc, + 0xb7209819, + 0xc004430c, + 0xb78409d2, + 0xc09667ad, + 0x125808b4, + 0x4029b580, + 0x430cb720, + 0xc0960203, + 0xd2080a34, + 0x1a04aa01, + 0x4badb581, + 0x430cb720, + 0xc0960203, + 0xb7410a34, + 0xd2085c35, + 0xb76aaa01, + 0x010346b1, + 0x5a1cc200, + 0x0d01cff0, + 0x0528c101, + 0x0960c09c, + 0x9acfff14, + 0x430cb720, + 0x46b1b76a, + 0x55acc200, + 0x2dfcc00e, + 0x9871ff94, + 0x478cb740, + 0xaa41f048, + 0xc0007508, + 0xf0489084, + 0xb720a2c2, + 0x0203430c, + 0x0a34c096, + 0xaa01d208, + 0x532bb749, + 0xc2001a04, + 0xcff05a0c, + 0xc00e291d, + 0x32442a60, + 0x532bb589, + 0x430cb740, + 0xc09c0205, + 0xd2080a14, + 0x7500aa01, + 0x9224c000, + 0xc0960205, + 0xd2080a30, + 0x0092a881, + 0xb7890094, + 0xc00e532b, + 0xc2002a60, + 0xd2085a0f, + 0xb720a241, + 0xd208430c, + 0xb744aa41, + 0xba246e2d, + 0x02444000, + 0x752db584, + 0x430cb720, + 0x752db784, + 0x08f0c098, + 0x4029b580, + 0x430cb720, + 0x752db784, + 0x6d2db744, + 0xb5841244, + 0xb79f752d, + 0xb7bf7eee, + 0xb7df7f6e, + 0x8c607fee, + 0xa61d9c22, + 0x8460c010, + 0x4314b7a0, + 0x9e699e6c, + 0x0a10c0a4, + 0xa902d208, + 0x5e35b7e1, + 0xc0337680, + 0x0a069184, + 0x44abb585, + 0x430cb780, + 0x0585096a, + 0x0a1cc09c, + 0xa101d208, + 0x430cb720, + 0xb5440405, + 0xb72079b5, + 0xb76a430c, + 0xba1b46a9, + 0xc0004000, + 0xb5049080, + 0xb7207a55, + 0xd110430c, + 0x0d840637, + 0x4731b74a, + 0x5908c200, + 0x00a2d020, + 0xffff7115, + 0x0203925c, + 0x0a40c09a, + 0xaa01d208, + 0xc0007500, + 0xb78490e2, + 0x0a0475ad, + 0x75adb584, + 0x430cb740, + 0x0930c096, + 0xaa41d008, + 0xd0080a04, + 0xb780a241, + 0x9ea2430c, + 0xc0960109, + 0xc0960d30, + 0xd0100934, + 0xd008aa41, + 0x7104a941, + 0x1248d011, + 0x4442b422, + 0x430cb720, + 0x692db784, + 0xb5841a04, + 0xb740692d, + 0x0205430c, + 0x0a30c096, + 0xa881d208, + 0x00929e92, + 0xb7890094, + 0xc09a532b, + 0x2a100d40, + 0x5a0bc200, + 0xa241d010, + 0x4314b720, + 0xc0969e4c, + 0xd2080a30, + 0x0092a881, + 0x0092c101, + 0x532bb789, + 0xc0f00109, + 0xd1242900, + 0xc2005821, + 0x9e435831, + 0x70c0c812, + 0xb5842a0c, + 0xb7206ccd, + 0x09044314, + 0x9e4a0385, + 0x0930c096, + 0xa8c1d008, + 0xc1010092, + 0xb7890092, + 0xc00e532b, + 0xc2002a60, + 0xb59d5a0f, + 0xd0087468, + 0x7500aa41, + 0x9084c006, + 0x67cdb784, + 0x6e4db584, + 0x430cb720, + 0x4835b745, + 0xc0027684, + 0xb7449182, + 0x748067ad, + 0x9242c000, + 0x4b2db781, + 0xc0007500, + 0xb78490e2, + 0x7500692d, + 0x911cc000, + 0xc0007682, + 0x768090a2, + 0x92e4c001, + 0x6d2db784, + 0x1128e000, + 0x9142c000, + 0x4aadb781, + 0xc0007088, + 0x768090a8, + 0x93c4c000, + 0xc09c0103, + 0x0a060914, + 0xa241d008, + 0x430cb720, + 0xb5440902, + 0xb72075ad, + 0xb544430c, + 0xb720752d, + 0xb784430c, + 0xb58467ad, + 0xb7206d2d, + 0x0a7f430c, + 0x7468b55d, + 0x6fadb584, + 0x430cb720, + 0xb5840a06, + 0xb7206cad, + 0xb781430c, + 0xb5844b2d, + 0xb720692d, + 0xc00e430c, + 0xb5850a7e, + 0xb720482d, + 0xb781430c, + 0x75065dad, + 0x9144c000, + 0xc09c0203, + 0xd2080a18, + 0x7500aa01, + 0x9342c002, + 0xc0980103, + 0xd008091c, + 0x0d86aa41, + 0xd0080a04, + 0xb780a241, + 0x9ea2430c, + 0xc0980109, + 0xc0980d1c, + 0xd0100918, + 0xd008aa41, + 0x7104a941, + 0x1244d014, + 0x4448b422, + 0x93a0c000, + 0xaa41d010, + 0x0639d110, + 0xa25dd008, + 0x430cb780, + 0x0146c101, + 0xc0980185, + 0xc0980a18, + 0xd2080980, + 0xd008a901, + 0x0d84aa7d, + 0xd0207104, + 0xc0001144, + 0xd0089086, + 0xb720a17e, + 0xc101430c, + 0x01090216, + 0xc0980203, + 0xd2080a18, + 0x9e8aaa01, + 0x0900c098, + 0x0d1cc098, + 0xfffe72d9, + 0xb78892b8, + 0x02186e29, + 0x0a00c098, + 0xaa1dd208, + 0xc0980218, + 0xd2080a20, + 0x1904a90d, + 0xa10dd208, + 0x4314b740, + 0xc09a9e54, + 0xd2080a40, + 0x7500aa01, + 0x91c2c001, + 0x2bfcc00e, + 0x062fd110, + 0xc0989e52, + 0xd2080a00, + 0xc096aa1d, + 0xd0080950, + 0xb780a241, + 0x0109430c, + 0x0950c096, + 0xa942d008, + 0xa941d1e8, + 0x0244c101, + 0x0a20c098, + 0xa10dd208, + 0x430cb720, + 0xc0960203, + 0xd2080a50, + 0xb744aa01, + 0xc20075ad, + 0x00c25a08, + 0x722db544, + 0x92a0c001, + 0xc0989e54, + 0xd2080a18, + 0xd110a901, + 0xc0980525, + 0xd0080900, + 0x0a04aa5d, + 0xa25dd008, + 0x430cb780, + 0xc0980109, + 0xd0080918, + 0x0228a941, + 0x09089ea2, + 0x0d00c098, + 0xaa5dd010, + 0xc0007104, + 0x1a0890b8, + 0xa25dd010, + 0x430cb780, + 0xc0980109, + 0xd0080918, + 0x9ea2a941, + 0xc0980244, + 0xd2080a00, + 0xc096aa1d, + 0xd0100d50, + 0xb740a241, + 0xc101430c, + 0xc0980220, + 0xd2080a00, + 0xc096aa1d, + 0xd0080954, + 0xb720a241, + 0xb748430c, + 0xb7846e29, + 0x9e8a75ad, + 0xc0967104, + 0xc0000d58, + 0x02109134, + 0x0a00c098, + 0xaa1dd208, + 0x90e0c000, + 0xc0960203, + 0xd2080a54, + 0xd010aa01, + 0xb740a241, + 0x9e69430c, + 0xc0980d02, + 0xb7850910, + 0xd0087e29, + 0xb720a142, + 0x75004314, + 0x6ccdb764, + 0x90c2c000, + 0x6acdb781, + 0x9080c000, + 0x6b4db781, + 0xb58474c6, + 0xc00063cd, + 0x74c29182, + 0x9222c000, + 0x430cb720, + 0x63adb784, + 0xc0003a04, + 0xb7209100, + 0xb784430c, + 0xc00863ad, + 0xb5843a00, + 0xb78063ad, + 0xc096430c, + 0xd2080a50, + 0xc200aa01, + 0xc1015a08, + 0xf2080242, + 0x7480a911, + 0x9222c000, + 0xa111f248, + 0x430cb780, + 0xc0960902, + 0xd2080a50, + 0xc200aa01, + 0xc1015a08, + 0xf2080242, + 0xb742a111, + 0x76804555, + 0x9102c002, + 0x430cb780, + 0x6cc9b748, + 0x0a50c096, + 0xaa01d208, + 0xc2007480, + 0xc1015a08, + 0xf2480242, + 0xf208a911, + 0xb780a111, + 0x0902430c, + 0x454db542, + 0x0a50c096, + 0xaa01d208, + 0x5a08c200, + 0x0242c101, + 0xa112f248, + 0x90c2c001, + 0x430cb720, + 0x7ea9b785, + 0xc0007500, + 0x74c29202, + 0x91a2c000, + 0xc0980203, + 0xd2080a00, + 0x0103aa01, + 0x0904c098, + 0xc0004a04, + 0x010390c0, + 0x0904c098, + 0xd0080a02, + 0xb720a241, + 0x0a02430c, + 0x6cc9b588, + 0x75adb784, + 0x6fadb584, + 0x430cb720, + 0x45cdb742, + 0xc0960203, + 0xd2080a50, + 0x7480aa01, + 0x5a08c200, + 0x0242c101, + 0xaa11f248, + 0x642db584, + 0x430cb720, + 0x9262c000, + 0xb5440a02, + 0xb582652d, + 0xb74045cd, + 0xb748430c, + 0xb5886d51, + 0xc0986d49, + 0xd0080908, + 0xc001a142, + 0x020390c0, + 0x0a54c096, + 0xaa01d208, + 0x5a08c200, + 0x0242c101, + 0xaa11f248, + 0x652db584, + 0x430cb720, + 0xc0960203, + 0xd2080a54, + 0xb744aa01, + 0x9e8a6f2d, + 0x5a08c200, + 0xb72400c2, + 0x0a02722d, + 0x0d08c098, + 0xd0017082, + 0xd0100a42, + 0xb742a241, + 0xb720464d, + 0x7480430c, + 0x9262c000, + 0xb5440a02, + 0xb582662d, + 0xb740464d, + 0xb748430c, + 0xb5886dd1, + 0xc0986dc9, + 0xd008090c, + 0xc001a142, + 0x020390c0, + 0x0a58c096, + 0xaa01d208, + 0x5a08c200, + 0x0242c101, + 0xaa11f248, + 0x662db584, + 0x430cb720, + 0xc0960203, + 0xd2080a58, + 0xb744aa01, + 0x9e8a6f2d, + 0x5a08c200, + 0xb72400c2, + 0x0a02722d, + 0x0d0cc098, + 0xd0017082, + 0xd0100a42, + 0xb720a241, + 0xb740430c, + 0x048b4155, + 0x6badb744, + 0xb7845d10, + 0x5910642d, + 0xcffe097c, + 0xc1012901, + 0xb7426125, + 0x02285b53, + 0x64adb584, + 0x430cb720, + 0x5bcbb762, + 0x652db784, + 0x61b4c101, + 0x193ed012, + 0xb5840228, + 0xb72065ad, + 0x769c430c, + 0x662db784, + 0xb5440128, + 0xc00066ad, + 0x0d3a90bc, + 0x90a0c000, + 0xc8120d82, + 0xb7207286, + 0xb780430c, + 0xd031500c, + 0xb70a2dae, + 0x0b0246a9, + 0xba000f06, + 0x02884000, + 0x5a30c000, + 0xc0219ea3, + 0xc1c80d80, + 0xc0050d90, + 0x9e699140, + 0xa322d208, + 0x4f35b702, + 0xc0037600, + 0xb7429022, + 0xd2114dad, + 0x9dcd1e38, + 0xa161f000, + 0x4e2db742, + 0x1e38d1f1, + 0xf0009dcd, + 0xb742a161, + 0xd2114ead, + 0x9dcd1e30, + 0xa161f000, + 0x4018b960, + 0xd152048b, + 0xb7821d38, + 0x9dae4fad, + 0xa261f000, + 0x0d20d051, + 0xf0009dad, + 0xb742a261, + 0xd09151ad, + 0x9dcd1e20, + 0xa161f000, + 0x1e20d051, + 0xf0009dcd, + 0x0890a161, + 0xffff0d10, + 0x9e699101, + 0x1e38d071, + 0x4d2db742, + 0xf0009dcd, + 0x7e04a161, + 0x9042c001, + 0x1d30d072, + 0x53cdb782, + 0xf0009dae, + 0xb742a261, + 0xd011564d, + 0x9dcd0e28, + 0xa161f000, + 0x72860d20, + 0xffff0c90, + 0x048b9224, + 0x554db782, + 0xf0009dbe, + 0xb742a261, + 0xd01155cd, + 0x9dcd0e38, + 0xa161f000, + 0x1e30d091, + 0xf0009dcd, + 0xb720a062, + 0xf210430c, + 0x0507a929, + 0x6badb724, + 0xc00e1904, + 0xd011297c, + 0xc2001a12, + 0xc00f5a40, + 0xcf4a2a7c, + 0x32440d01, + 0xf0009dae, + 0x9e69a261, + 0xb7419e5c, + 0xcf8068ad, + 0x9dcd0a01, + 0xa161f000, + 0x692db741, + 0x9dcd0a20, + 0xa161f000, + 0x682db741, + 0x1a30c008, + 0xf0009dcd, + 0xb781a161, + 0x1a0c5dad, + 0xc0007504, + 0x9e5c9112, + 0x0a41cf6a, + 0xf0009dcd, + 0x0b04a1e1, + 0xc1000a84, + 0xb7200d80, + 0x0260430c, + 0x4729b72a, + 0xfffa7102, + 0x77c0925c, + 0x9182c000, + 0xb785048b, + 0x75007e49, + 0x9024c001, + 0x59cdb582, + 0x93a0c000, + 0x048b9e69, + 0x67a9b786, + 0x6829b746, + 0x68b1b746, + 0x7529b589, + 0x75a9b549, + 0x7631b549, + 0x430cb720, + 0x5bcbb782, + 0x5b4bb742, + 0x6c2db724, + 0xb5246244, + 0xb582714b, + 0xb740584d, + 0xf048478c, + 0x7508aa41, + 0x90a4c000, + 0xf0481a0c, + 0xb720a241, + 0x9d8f430c, + 0x68b5b7c4, + 0x672db7c4, + 0x0da1cfee, + 0x9360c000, + 0x9b08ff34, + 0x430cb720, + 0x02039d8f, + 0x0a10c0a4, + 0xaa01d208, + 0x0da1cfee, + 0xc0107500, + 0xb78493c4, + 0x7188672d, + 0x90e4c000, + 0x68adb784, + 0xc0007399, + 0xffd49082, + 0xb7809ad0, + 0xc098430c, + 0xd2080a70, + 0xff94a982, + 0xc01c99d3, + 0x0281743e, + 0xfffe0d92, + 0xb7809322, + 0x0906430c, + 0x0a18c09c, + 0xa101d208, + 0x430cb720, + 0xc0a20203, + 0xd2080a70, + 0x7500aa01, + 0x9082c000, + 0x532bb54c, + 0x430cb720, + 0x2bfcc00e, + 0x6e29b728, + 0xd01210f2, + 0xcffe1992, + 0xff942dfc, + 0x9e699b29, + 0x7e29b785, + 0xc0007500, + 0xb7209162, + 0x0a16430c, + 0x5eadb583, + 0x430cb720, + 0x422db584, + 0x048b0d02, + 0x7e51b545, + 0x430cb720, + 0x532bb78c, + 0xc0007500, + 0x010392e2, + 0x0970c0a2, + 0xaa41d008, + 0xc0007500, + 0xd00891e2, + 0xb740a142, + 0x0205430c, + 0x0a74c0a2, + 0xaa01d208, + 0x0918c09c, + 0xa241d008, + 0x430cb720, + 0x532bb78c, + 0xc0007500, + 0xb78191a2, + 0x75065dad, + 0x9104c000, + 0xc09c0103, + 0x1a0c0918, + 0xa241d008, + 0x430cb720, + 0xc09c0203, + 0xd2080a18, + 0x7500aa01, + 0x9302c001, + 0x67adb784, + 0xc0007500, + 0x9ea190a4, + 0x9080c000, + 0x6135b721, + 0x4badb786, + 0x61adb741, + 0x46b1b74a, + 0x2a7cc00e, + 0x4731b70a, + 0x31c4d020, + 0xc0000802, + 0x9dcd9260, + 0xa0e2f000, + 0xc0210205, + 0xc0320a00, + 0x9dcd0a70, + 0xa1e2f000, + 0x9dcd0a10, + 0xa061f000, + 0x293ed3f2, + 0x0da2d011, + 0xc1807280, + 0x02055930, + 0x0a00c021, + 0x0a60c032, + 0x90b4ffff, + 0xb5840a02, + 0xb72079ad, + 0x9ea3430c, + 0xb76a9ea1, + 0xba1b46a9, + 0xc0004000, + 0xf0089080, + 0xb720a0c2, + 0xd110430c, + 0x0d840637, + 0x4731b74a, + 0x5908c200, + 0xc09c0122, + 0x71150940, + 0x923cffff, + 0x47b1b76a, + 0x9a50ff54, + 0xb7809e69, + 0xb743430c, + 0xc09a572b, + 0x74800a44, + 0xa281d208, + 0x9262c008, + 0x4314b7c0, + 0xc09c9e74, + 0xd2080a18, + 0x7500aa01, + 0x9182c007, + 0x048d9e74, + 0x0a44c09a, + 0xaa01d208, + 0xb76a9d17, + 0xc20046d1, + 0xc1015a08, + 0xb74000cc, + 0xcfee7035, + 0xc0100ab1, + 0x010b0986, + 0x9905fef4, + 0x430cb780, + 0xa921d208, + 0xc0a4030b, + 0xd2080a1c, + 0xb720a101, + 0xd229430c, + 0xb785a945, + 0xc0a47ea9, + 0x750008a0, + 0xd0020a02, + 0x51500a42, + 0x4029b540, + 0x430cb720, + 0x582db762, + 0x4135b760, + 0x995fc274, + 0x9ea80982, + 0xc00e9e9b, + 0xc001287c, + 0xd20893c0, + 0x7480aac1, + 0xc10100da, + 0xb56a0092, + 0xd030532b, + 0xb720a90a, + 0xc000430c, + 0xb78a9164, + 0xba2452ab, + 0x62094002, + 0x0629d110, + 0x9240c000, + 0xc0a40203, + 0xd2080a1c, + 0x1a04aa01, + 0xc0007088, + 0xb78a9184, + 0xba2452ab, + 0x62094002, + 0x1629d110, + 0xc00e9ea2, + 0x9e712d7c, + 0x430cb780, + 0x5babb742, + 0x29fccffe, + 0x009800da, + 0x0627d110, + 0x6124c101, + 0x532bb54b, + 0x0d840189, + 0xb7200b08, + 0xd3f14314, + 0x9e4c2d3e, + 0x0a1cc0a4, + 0xaa01d208, + 0xfffd7104, + 0xb7829352, + 0xb7425bcb, + 0x61465c53, + 0xc0007295, + 0x00da9188, + 0x0092c101, + 0x532bb78b, + 0x1124c101, + 0xb58b1244, + 0x048b532b, + 0x5dcdb781, + 0xc0007508, + 0x750a90a2, + 0x91e4c000, + 0x430cb720, + 0x532bb78c, + 0xc0007500, + 0x9e8b9102, + 0xc06e098e, + 0xc0000d90, + 0xb7209120, + 0x9e8b430c, + 0x6cadb764, + 0x0d90c06e, + 0x9931ffb4, + 0xb7859e69, + 0x75007ea9, + 0x9082c001, + 0x430cb720, + 0xc09c0203, + 0xd2080a14, + 0x9e8baa01, + 0xc0807500, + 0xc0000d80, + 0xb7649102, + 0xffb46cad, + 0xc000991a, + 0x9e8a9220, + 0xc06e0109, + 0xb9600d10, + 0x9e5348d8, + 0xc0209e91, + 0x0904aa65, + 0xa269c010, + 0x9321ffff, + 0x430cb720, + 0x09020a7f, + 0x6c29b588, + 0x430cb780, + 0x0a3cc0a2, + 0xa101d208, + 0x430cb720, + 0x47b1b76a, + 0x99d7ff54, + 0x430cb720, + 0xb78a0902, + 0xc1364729, + 0xb58008a0, + 0xb7804029, + 0xc136430c, + 0xd2080a24, + 0xb780a101, + 0xc0a2430c, + 0xd2080a38, + 0xc001a101, + 0x9e929080, + 0x4030b960, + 0x430cb720, + 0x5c8cc100, + 0xd1100d04, + 0xb5430493, + 0xb7207bab, + 0xd110430c, + 0xb5430493, + 0xb7207c2b, + 0xd110430c, + 0xb5430493, + 0xb7807cab, + 0xc101430c, + 0xb5430498, + 0xffff7d4b, + 0xfff690a1, + 0xb79f91e0, + 0xb7bf6cee, + 0xb7df6d6e, + 0xb7ff6dee, + 0xcfec6e6e, + 0x9c228421, + 0xa205f839, + 0x430cb720, + 0x0d860902, + 0x6e29b788, + 0x0898c098, + 0xb5800a08, + 0xb7804029, + 0xc098430c, + 0xd2080a1c, + 0xc000a101, + 0xd0089320, + 0xb780a1de, + 0xc101430c, + 0x01850146, + 0x0a18c098, + 0x0980c098, + 0xa901d208, + 0xaa7dd008, + 0x71040d84, + 0x1144d020, + 0x9086c000, + 0xa17ed008, + 0x430cb720, + 0x0216c101, + 0x02030109, + 0x0a18c098, + 0xaa01d208, + 0x0900c098, + 0xfffe72d9, + 0xb7819398, + 0x01034bad, + 0x0934c096, + 0xd0080a04, + 0xb780a241, + 0x097f430c, + 0xc09609c2, + 0xd2080a30, + 0xb720a101, + 0xb76a430c, + 0xb74046b1, + 0x010374b5, + 0x0930c094, + 0x9b91fed4, + 0x430cb720, + 0x4badb781, + 0x532bb749, + 0x5a0cc200, + 0x291dcff0, + 0x2a60c00e, + 0xb5893244, + 0xb720532b, + 0x0a02430c, + 0x68adb584, + 0xaa1df9f8, + 0xa61d9c22, + 0x8420c006, + 0x430cb720, + 0x0a060902, + 0x4829b54a, + 0x4314b720, + 0x5ab5b703, + 0x5b35b7a3, + 0xb54aa01a, + 0xb72048c9, + 0x9e6b4314, + 0x5bb5b7e3, + 0x44cbb545, + 0x520cc200, + 0xb7800389, + 0xb723430c, + 0xc00e5c2d, + 0xc0a42bfc, + 0x9ebb0a10, + 0xa101d208, + 0xff54a09d, + 0xb720986f, + 0x9e4c4314, + 0x0a10c0a4, + 0xaa01d208, + 0xc0157500, + 0xf1b192a4, + 0xb7cd8c80, + 0xb7cd6049, + 0x9e4960d1, + 0xb960010b, + 0xb7834028, + 0xf0084c2d, + 0xb783a241, + 0xf0084cad, + 0xb783a245, + 0xf0084d2d, + 0xb783a249, + 0x08c04dad, + 0xa24df008, + 0xffff0940, + 0xb74391c1, + 0x9e4a5bd5, + 0x2dded3f2, + 0x0992c144, + 0x9b1ffed4, + 0x430cb720, + 0xb9600d02, + 0xb5cd4028, + 0xb7206029, + 0xb5cd430c, + 0xb72060b1, + 0xf208430c, + 0xc100aa21, + 0xd1105c90, + 0x0d040493, + 0x4c2db583, + 0x430cb720, + 0xaa25f208, + 0x0493d110, + 0x4cadb583, + 0x430cb720, + 0xaa29f208, + 0x0493d110, + 0x4d2db583, + 0x430cb780, + 0xa92df208, + 0xc1010ac0, + 0xb5430498, + 0xfffe4dcd, + 0xb7209381, + 0xaa19430c, + 0x5a0cb700, + 0x5a94b700, + 0x5aadb583, + 0x430cb720, + 0x0c82c021, + 0x0d82c021, + 0x5b35b5a3, + 0x430cb720, + 0x0c80c014, + 0x0d90c014, + 0x5bb5b5e3, + 0x430cb720, + 0xb960a99d, + 0xb5634038, + 0xb7a05c2d, + 0x9e694314, + 0x0dd8d2f1, + 0x7029b788, + 0x6fa9b748, + 0x6f31b748, + 0x47a9b58a, + 0x430cb7a0, + 0x6ea9b788, + 0xb54a008b, + 0xb7204729, + 0xb54a430c, + 0xb72046b1, + 0xb58a430c, + 0xb7204629, + 0xb562430c, + 0xb720612d, + 0xd9e9430c, + 0x9d9eaa1d, + 0xa261f000, + 0xaa1dd9f1, + 0xf0009dbe, + 0xffffa261, + 0x048b92c1, + 0x7e49b785, + 0xc0067500, + 0xc00e91c2, + 0xb5850a7e, + 0xb720482d, + 0x0a82430c, + 0xb5a40906, + 0xb72067ad, + 0xb5a4430c, + 0xb720682d, + 0xb5a4430c, + 0xb720692d, + 0xb544430c, + 0xb7206cad, + 0xb5a4430c, + 0xb7806d2d, + 0xc09c430c, + 0xd2080a10, + 0xb780a281, + 0xc09c430c, + 0xd2080a18, + 0xfff4a101, + 0xb7809a8d, + 0x0109430c, + 0x0918c098, + 0xa941d008, + 0xc0980244, + 0xd2080a00, + 0xb720a11d, + 0xb781430c, + 0x75004bad, + 0x9262c000, + 0x5c35b741, + 0x46b1b76a, + 0x5a1cc200, + 0x1d00c008, + 0xc1010103, + 0xc09c0528, + 0xc0040960, + 0xfed409d2, + 0xb7809a4e, + 0x090a430c, + 0xa9aef210, + 0x0a40c09a, + 0xa281d208, + 0x430cb720, + 0xb762040b, + 0xb5a65b4a, + 0xb7804aad, + 0xb742430c, + 0xf2105bd2, + 0xc0c4a8aa, + 0xd2080a60, + 0xb720a101, + 0xd111430c, + 0xb56465a7, + 0xb7a06bb5, + 0x008b430c, + 0x6bb5b764, + 0xc25465b3, + 0x048b9aa0, + 0x5f4bb781, + 0x75009ea8, + 0x6c4cb504, + 0x4314b740, + 0x9142c000, + 0x0a6a9e52, + 0x091cc09c, + 0xa241d008, + 0x9140c000, + 0x9e549e69, + 0x67a9b746, + 0x0a1cc09c, + 0xa101d208, + 0x430cb720, + 0x087f0d82, + 0x67a9b786, + 0x08a0c09c, + 0x0c7ec00e, + 0x4029b580, + 0x430cb720, + 0x46b1b74a, + 0x4001ba12, + 0x91e0c000, + 0x6fcdb789, + 0x02426a32, + 0x0a20c138, + 0xa011d208, + 0x430cb720, + 0xb50900b2, + 0xb7206fb5, + 0xd010430c, + 0x0d840534, + 0x4729b78a, + 0x5988c100, + 0x00b2d020, + 0xffff7088, + 0x090290fc, + 0xb9600d7f, + 0xb7804040, + 0x0228430c, + 0x0a60c098, + 0xa116d208, + 0xffff0904, + 0x048b9301, + 0x5e55b741, + 0x430cb780, + 0x76800902, + 0x0a18c0a4, + 0x0922d002, + 0xa101d208, + 0x430cb720, + 0x76860a02, + 0x52abb58a, + 0x9102c009, + 0xc0017684, + 0xb7819304, + 0x1a0c5dcd, + 0xc0017504, + 0xb7209252, + 0xc809430c, + 0xccf00a42, + 0xb5890a20, + 0xb7206aad, + 0xc809430c, + 0xc9be0a46, + 0xb5890a60, + 0xb7206b2d, + 0xc809430c, + 0xccf80a42, + 0xb5890a50, + 0xb7206a2d, + 0xc809430c, + 0xc5f80a46, + 0xb5890a20, + 0xb7206c2d, + 0xc809430c, + 0xc40a0a46, + 0xb5890a10, + 0xb7206bad, + 0xc809430c, + 0xcd0a0a42, + 0xb5890a10, + 0x040b6cad, + 0x5dccb781, + 0xc0017504, + 0xb78192e4, + 0x75045e4c, + 0x9244c001, + 0x430cb720, + 0x0a42c809, + 0x0a70cf1a, + 0x6aadb589, + 0x430cb720, + 0x0a46c809, + 0x0a30cac6, + 0x6b2db589, + 0x430cb720, + 0x0a42c809, + 0x0a70cd0c, + 0x6a2db589, + 0x430cb720, + 0x0a46c809, + 0x0a30cb92, + 0x6c2db589, + 0x430cb720, + 0x0a46c809, + 0x0a50cc94, + 0x6badb589, + 0x430cb720, + 0x0a42c809, + 0x0a20cd2e, + 0x6cadb589, + 0xb7819e69, + 0x75025e2d, + 0x92e4c001, + 0x5dadb781, + 0xc0017504, + 0xb7209244, + 0xc809430c, + 0xcf1a0a42, + 0xb5890a70, + 0xb7206aad, + 0xc809430c, + 0xcb360a46, + 0xb5890a00, + 0xb7206b2d, + 0xc809430c, + 0xc9dc0a46, + 0xb5890a10, + 0xb7206a2d, + 0xc809430c, + 0xcb0a0a46, + 0xb5890a30, + 0xb7206c2d, + 0xc809430c, + 0xcc940a46, + 0xb5890a50, + 0xb7206bad, + 0xc809430c, + 0xcd2e0a42, + 0xb5890a20, + 0x048b6cad, + 0x5e4db781, + 0xc0017508, + 0xb78192e4, + 0x75045dcd, + 0x9244c001, + 0x430cb720, + 0x0a46c809, + 0x0a40caca, + 0x6aadb589, + 0x430cb720, + 0x0a46c809, + 0x0a00cb36, + 0x6b2db589, + 0x430cb720, + 0x0a46c809, + 0x0a10c9dc, + 0x6a2db589, + 0x430cb720, + 0x0a46c809, + 0x0a30cb0a, + 0x6c2db589, + 0x430cb720, + 0x0a46c809, + 0x0a50cc94, + 0x6badb589, + 0x430cb720, + 0x0a46c809, + 0x0a70cab8, + 0x6cadb589, + 0xb781040b, + 0x75025e4c, + 0x9304c001, + 0x5dccb781, + 0x75041a0c, + 0x9252c001, + 0x430cb720, + 0x0a46c809, + 0x0a30c050, + 0x6aadb589, + 0x430cb720, + 0x0a46c809, + 0x0a50c9c8, + 0x6b2db589, + 0x430cb720, + 0x0a42c809, + 0x0a10cd38, + 0x6a2db589, + 0x430cb720, + 0x0a46c809, + 0x0a60c1a0, + 0x6c2db589, + 0x430cb720, + 0x0a46c809, + 0x0a00c0aa, + 0x6badb589, + 0x430cb720, + 0x0a42c809, + 0x0a20cd68, + 0x6cadb589, + 0x430cb720, + 0xb5ea9ebb, + 0xb7204829, + 0xb5ea430c, + 0xb79f48a9, + 0xb7bf77ee, + 0xb7df786e, + 0xb7ff78ee, + 0xc008796e, + 0xff318c20, + 0xa60d9140, + 0xb7208440, + 0x0203430c, + 0x0a10c0a4, + 0xaa01d208, + 0xc0107500, + 0x02039104, + 0x0a18c09c, + 0xaa01d208, + 0xc0017500, + 0xb7aa90c2, + 0xb7c046a9, + 0xc000478c, + 0xd0319320, + 0xc00e0a54, + 0x6a522a7c, + 0xd032024c, + 0xc0000ac8, + 0xff149080, + 0xf2109945, + 0x0d92aa21, + 0xffff750c, + 0xd0119344, + 0x02890a52, + 0x2afcc00e, + 0x430cb720, + 0x4729b78a, + 0xffff710a, + 0xb7209088, + 0x0203430c, + 0x0a18c09c, + 0xaa01d208, + 0xc0027500, + 0x9ea39304, + 0x4731b7ca, + 0x98b8ff74, + 0x430cb780, + 0x0a10c0a4, + 0xab01d208, + 0xc00e7580, + 0x0a869084, + 0x56d89eaa, + 0x2efcc00e, + 0xff34058b, + 0x9eb29945, + 0x018d9eb1, + 0x010d008b, + 0xa31d058d, + 0xa295a319, + 0x9af4ff94, + 0x4314b700, + 0x5e88d322, + 0x4490b760, + 0x00d0c101, + 0x6fb5b729, + 0x6c50b74d, + 0xd0319e73, + 0xc00e6d19, + 0xc1012cfc, + 0xc1380120, + 0xd0080920, + 0x1b04a951, + 0x99ebff14, + 0x430cb740, + 0x00d4058b, + 0x6fadb789, + 0x02446a32, + 0x0a20c138, + 0xa311d208, + 0x430cb780, + 0x008b02d8, + 0x0a7ec00e, + 0x6fadb589, + 0x9997ff34, + 0x560cb780, + 0xc2209ea2, + 0xb720a349, + 0x0203430c, + 0x0a18c0a4, + 0xaa01d208, + 0xc0007500, + 0xb78991a2, + 0xb7646bad, + 0x018379b5, + 0x09b0c0c4, + 0x9c629ea4, + 0x9080c000, + 0x532bb58c, + 0x430cb720, + 0x67adb784, + 0xb5840a04, + 0xb7a067ad, + 0x008b430c, + 0x612db781, + 0xc0017500, + 0xb7849122, + 0x750067ad, + 0x9082c001, + 0x46a9b74a, + 0x4729b76a, + 0xc0000d82, + 0x9d4d9100, + 0xd3f1aa61, + 0xc1012d2e, + 0xd01205b8, + 0x70860922, + 0x5e30d122, + 0x0a00c021, + 0x0a00c034, + 0x9234ffff, + 0xaa2df208, + 0xa9a9f208, + 0xc25461c7, + 0x008b9816, + 0x4badb506, + 0x430cb720, + 0xb5a50a82, + 0xb72044ab, + 0xb76a430c, + 0xff344831, + 0xb720993a, + 0x0203430c, + 0x0a18c09c, + 0xaa01d208, + 0xc0027500, + 0xb7849162, + 0x0a04682d, + 0x682db584, + 0x430cb740, + 0x0914c09c, + 0xaa41d008, + 0xc0007500, + 0xd0089322, + 0xb720a2c1, + 0x097f430c, + 0x6e29b788, + 0xc0980218, + 0xd2080a04, + 0x0098aa1d, + 0x08a0c098, + 0x41a9b5a0, + 0x430cb780, + 0x0a30c096, + 0xa101d208, + 0x430cb720, + 0x6cadb784, + 0xc0007506, + 0xb7849182, + 0xb584782d, + 0xb720772d, + 0xb784430c, + 0xb58477ad, + 0xb720782d, + 0xb784430c, + 0xb5846fad, + 0xb7406f2d, + 0x0205430c, + 0x0a04c098, + 0xaa01d208, + 0x0900c098, + 0xa241d008, + 0x9180c000, + 0xc0c40203, + 0xd2080a60, + 0xb786a901, + 0x02444aad, + 0x4aadb586, + 0x430cb780, + 0xc09c0a82, + 0xd2080a10, + 0xb720a281, + 0xb744430c, + 0x748068ad, + 0x91a2c000, + 0x67adb784, + 0xc0007088, + 0xffd49104, + 0xb7209b37, + 0xb5a5430c, + 0xb720482d, + 0xb743430c, + 0x76805733, + 0x93c4c004, + 0x5eadb783, + 0x09020e82, + 0xd00a7502, + 0x75040ed2, + 0x0922d001, + 0x0a027508, + 0x0a42d001, + 0x31287740, + 0x90a2c000, + 0xc0009e55, + 0x748090c0, + 0xd0010a86, + 0x08020ad2, + 0x5b14b7c0, + 0x49049e83, + 0x0b7ec03e, + 0x4018b960, + 0x9000c004, + 0xaa49c060, + 0x430cb760, + 0x5c88c100, + 0x4000ba24, + 0x0058d020, + 0xd0220496, + 0x04925c88, + 0x0096c101, + 0x0496c101, + 0xb7830092, + 0x00967bcb, + 0x57abb723, + 0x4002ba24, + 0x0242e000, + 0x90acc000, + 0xc0000201, + 0xd0109080, + 0xd022710c, + 0xc1015c88, + 0x00920096, + 0xb5830096, + 0xd12257ab, + 0xb7805c88, + 0xc101430c, + 0x00920096, + 0x00980d04, + 0xb5037688, + 0xfffe7bab, + 0x77409124, + 0x9364c001, + 0xaa49c060, + 0x430cb760, + 0x5c88c100, + 0x4000ba24, + 0x0028d020, + 0xd0220496, + 0x04925c88, + 0x0096c101, + 0x0496c101, + 0xb7830092, + 0x00967bcb, + 0x57abb723, + 0x4002ba24, + 0x0242e000, + 0x90acc000, + 0xc0000201, + 0xd0109080, + 0xd022710c, + 0xc1015c88, + 0x00920096, + 0xb5830096, + 0xd12257ab, + 0xb7805c88, + 0xc101430c, + 0x00920096, + 0x00980d04, + 0xb503768e, + 0xfffe7bab, + 0x0d849124, + 0x9101c000, + 0x4490b760, + 0x9a60fef4, + 0x90a0c000, + 0xfffc9e82, + 0xb79f9020, + 0xb7bf7dee, + 0xb7df7e6e, + 0xc0027eee, + 0x9c228c20, + 0x430cb720, + 0x5dadb781, + 0x7eadb742, + 0xc1007504, + 0xc000580c, + 0xcd8e90a4, + 0x9c220841, + 0x0850cfff, + 0x0800c480, + 0x9e589c22, + 0xe0000c86, + 0xd0054030, + 0x9e511c94, + 0x72c0c814, + 0x70c0c814, + 0x7480c008, + 0x483cb323, + 0x445cb323, + 0x927cc000, + 0x5a1be100, + 0x90ccc000, + 0x0a02c002, + 0x90e0c000, + 0x7100d002, + 0xba240a04, + 0x9e504000, + 0x51d3d024, + 0xc0055193, + 0xc00074c0, + 0xe180923c, + 0xc0005a57, + 0xc00290cc, + 0xc0000a02, + 0xd00290e0, + 0x0a047100, + 0x4000ba24, + 0x51f30098, + 0x470cb740, + 0xd0109e58, + 0xc0200636, + 0xb740a906, + 0x7293468c, + 0xaa05ca20, + 0xd11d6039, + 0xd11e1623, + 0xd01a1215, + 0xd01c5013, + 0xc1015010, + 0x9c226003, + 0xb7a0a60d, + 0x0707430c, + 0xb781008b, + 0x75045dad, + 0x93c4c007, + 0x9b94fff4, + 0x5c88d322, + 0x009a0d06, + 0x7f2db722, + 0x10029e52, + 0x7080d812, + 0xb781008b, + 0x9eb55e2d, + 0xc0007502, + 0x750890a2, + 0x93a4c000, + 0xb787008b, + 0x75004e2d, + 0x92e2c000, + 0x402db743, + 0xb3207104, + 0xc0004834, + 0x008b9154, + 0x4629b76a, + 0x11c4d020, + 0xfff40d02, + 0x0a069b7e, + 0x7100d012, + 0x7188c810, + 0xb7209e95, + 0xb7804314, + 0x0b1e448c, + 0x75009e4a, + 0x0938c0a2, + 0xa941d008, + 0x4422b346, + 0xc0007480, + 0xb7809282, + 0xb764414d, + 0xb7436bd5, + 0xb76a41cd, + 0xc1014649, + 0x0d0265b9, + 0x15b4c101, + 0x9b59fff4, + 0xc0009e82, + 0xd3229180, + 0xc1015c88, + 0xb7830092, + 0xb72540ad, + 0x109846ad, + 0xcffe9e8a, + 0x76802d7c, + 0x9382c004, + 0x7740c080, + 0x9094c000, + 0x0e81cfc0, + 0x4314b720, + 0x5e4db781, + 0xc0007508, + 0xb78192c4, + 0x1a045ecd, + 0xc0007502, + 0xb7449192, + 0x0a1a6ccd, + 0x74829e69, + 0x1a46d009, + 0xc00052b1, + 0xd2a29140, + 0xc0005e85, + 0xd2a290c0, + 0xd1105e0d, + 0x9e5316d9, + 0x15dac101, + 0xfff40d02, + 0x09869b1c, + 0x70c0c812, + 0x4314b700, + 0x5c88d322, + 0x5e4cb781, + 0x0090c101, + 0x7f35b742, + 0xd0127508, + 0xc0001248, + 0xc10090c4, + 0xd0125a05, + 0xc03e70c8, + 0xc41009fe, + 0x0a067106, + 0x9ea39e89, + 0x7246c412, + 0x7086cc10, + 0x70c8cc12, + 0x0a7ec00f, + 0x0a7ccffe, + 0x0155d120, + 0xc8109ea3, + 0x0d827286, + 0x7286c812, + 0x5c88d322, + 0x5918c300, + 0x0090c101, + 0x40adb723, + 0x9e4c5cd8, + 0x2900c01c, + 0x04877440, + 0xd0013904, + 0x31280cb4, + 0xc0037440, + 0xcf000a7e, + 0xd0010a00, + 0x59b00db8, + 0x9e5c21b8, + 0xd0113126, + 0x31280de2, + 0x59b09e4c, + 0x02073128, + 0x0a00c021, + 0x0a40c01e, + 0xf0009dcd, + 0xc0ffa161, + 0xcffe0a7e, + 0x9ea30a40, + 0x0a0a7440, + 0x1a44d002, + 0x25265d10, + 0x3d049ea3, + 0x0980c021, + 0xc01e3526, + 0x9dbd09d0, + 0xa162f000, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0x9c228c60, + 0x8440a61d, + 0x0a32d011, + 0x5b30c200, + 0x6931d0d1, + 0x540cb780, + 0xa1969e9e, + 0x03a8d020, + 0xc021010d, + 0xa1120900, + 0x0930c03c, + 0xa9619d2d, + 0xda109e92, + 0xcff0aa61, + 0x5d212d00, + 0x0629d110, + 0x5e88d322, + 0xa261da10, + 0x430cb720, + 0x297cc00e, + 0x00d2018d, + 0x40adb783, + 0x0980c021, + 0x0980c03a, + 0x0629d110, + 0x40adb583, + 0x430cb720, + 0x41adb783, + 0x0244c101, + 0x41adb583, + 0xaa65da10, + 0xda100228, + 0xb720a265, + 0x00d2430c, + 0x40adb783, + 0xb5830228, + 0xb72040ad, + 0xb783430c, + 0x024441ad, + 0x41adb583, + 0xa9e19d3d, + 0xaa65f210, + 0x29fec7ff, + 0x0246010d, + 0x0900c021, + 0x0920c03a, + 0xa265f210, + 0xa9619d2d, + 0xaa69f210, + 0xc7ff9eb2, + 0x0244297e, + 0x0d00c021, + 0x0d10c03a, + 0xa269f210, + 0xa9629d2e, + 0xaa61f250, + 0xc021010d, + 0xc1010900, + 0xc03a0244, + 0xf2500930, + 0x9d2da261, + 0xf250a961, + 0x9eb3aa65, + 0xc040000d, + 0x02440800, + 0x0d80c021, + 0xc042a019, + 0xf2500dc0, + 0x9d3ea265, + 0xf210a9e2, + 0xc00faa71, + 0x018d2dfe, + 0x0246c101, + 0x0980c021, + 0x09d0c042, + 0xa271f210, + 0xa9e19d3d, + 0xaa75f210, + 0x29fec00f, + 0x0246038d, + 0x0b80c021, + 0x0ba0c042, + 0xa275f210, + 0xa8e19d7d, + 0xaa7df210, + 0x28fccffe, + 0x0242010d, + 0x0900c021, + 0x0930c042, + 0xa27df210, + 0xa9619d2d, + 0xaa79f210, + 0xc00f9eb2, + 0x0244297e, + 0x0d00c021, + 0x0d40c048, + 0xa279f210, + 0xa9629d2e, + 0x01b6c101, + 0x020d01b2, + 0xc00f01b4, + 0xc0212d7e, + 0xc1010a00, + 0xc04601b4, + 0x9d4d0a60, + 0x9ea2aa61, + 0xa979da10, + 0x2d7cc3ff, + 0xda105d41, + 0xc101a9fe, + 0xb7400524, + 0xc3fe430c, + 0xc1012a7c, + 0x01540246, + 0xa17ada10, + 0xa27dda10, + 0x0960c05e, + 0xaa41f008, + 0x0238058d, + 0xa241f008, + 0x430cb720, + 0x402db783, + 0xb5830246, + 0xb7a0402d, + 0xfff44314, + 0xc1019999, + 0xc05e02da, + 0xf2080ae0, + 0x7140aaa1, + 0x90e6c000, + 0x04dcd010, + 0xb58c0a06, + 0xb7204829, + 0xb747430c, + 0x74804e2d, + 0x9222c000, + 0x402db783, + 0xc0007104, + 0xb78c9186, + 0x750065ab, + 0x90e4c000, + 0x009cc101, + 0xb58c0a04, + 0xb7204929, + 0xb781430c, + 0x75045dad, + 0x92c4c002, + 0xc021020d, + 0xc01e0a00, + 0x9d4d0a60, + 0x9e79aa61, + 0xb7009e78, + 0x9ea25431, + 0x54b1b760, + 0x55b0b720, + 0x5529b720, + 0xc2000109, + 0xcff059e1, + 0xc1012900, + 0xc00f0240, + 0xb5802d7c, + 0x59215428, + 0x5d41020d, + 0x0126c101, + 0x0522c101, + 0x01b2c101, + 0x0a00c021, + 0x54a8b540, + 0x5530b540, + 0x55a8b560, + 0x0a70c01e, + 0xaa619d4d, + 0xb7009ea2, + 0xb7605630, + 0xb72056b0, + 0xb7205728, + 0x010957b0, + 0x2900cff0, + 0x2d7cc00f, + 0x59e1c200, + 0x5d415921, + 0x0126c101, + 0x0522c101, + 0x01b2c101, + 0x0240c101, + 0x5628b580, + 0x56a8b540, + 0x5730b540, + 0x57a8b560, + 0x2deed3f2, + 0x9978fff4, + 0x7600a812, + 0x9322c005, + 0xb780a919, + 0xc300590c, + 0xc0215d18, + 0xc0020900, + 0xd1300910, + 0x9d2d0529, + 0x9e92a961, + 0xa9cad858, + 0xa8cdd858, + 0xa8d2d858, + 0xa856d858, + 0xcff00205, + 0xc00f2a00, + 0xc1002d7c, + 0xc20059e1, + 0x5d415a21, + 0x297cc00e, + 0x0246c101, + 0x05220122, + 0x01b0c101, + 0xa249d858, + 0xa14dd858, + 0xa152d858, + 0xa1d5d858, + 0xaa619d7d, + 0xabf9da10, + 0xa87ef210, + 0xa941f058, + 0xa879f210, + 0xaaf1f210, + 0xaaf6f210, + 0xab7dda10, + 0xa9dbd858, + 0xa946f058, + 0xa9c9f058, + 0xa9cef058, + 0xa8d5f058, + 0xa8d2f058, + 0xc101a39d, + 0xf0580120, + 0xa81eabd9, + 0xa964f212, + 0x5a61c200, + 0x9eb80490, + 0x0246c301, + 0xc1014c7d, + 0x01ba0520, + 0x009c05ba, + 0xd8587205, + 0xf058a259, + 0xf058a141, + 0xf058a146, + 0xf058a1c9, + 0xf058a1ce, + 0xf058a0d5, + 0xc000a0d2, + 0xd0d891b2, + 0xe010aa59, + 0x0a048b21, + 0xa159f058, + 0xa259d0d8, + 0x90c0c000, + 0x0274c001, + 0xa259f058, + 0xaa5df058, + 0xa969f210, + 0x4d7d9ea2, + 0xc0007295, + 0xd0d891b2, + 0xc101aa5d, + 0xf0581124, + 0x0a04a15d, + 0xa25dd0d8, + 0x90a0c000, + 0xf0580244, + 0xb720a25d, + 0x0203430c, + 0x0a18c0a4, + 0xaa01d208, + 0xc0007500, + 0xb7899122, + 0xa9966a2d, + 0x050f9e73, + 0x9c629ea4, + 0xc002058f, + 0xb79f09c2, + 0xb7bf7d6e, + 0xb7df7dee, + 0xb7ff7e6e, + 0xc0027eee, + 0xfe698c40, + 0xb79f9200, + 0xb7bf7d6e, + 0xb7df7dee, + 0xb7ff7e6e, + 0xc0027eee, + 0x9c228c40, + 0x430cb740, + 0x0d020487, + 0xc0c60185, + 0xb9600980, + 0xc0204258, + 0x9e9baa29, + 0xa269c020, + 0xffff0d04, + 0xc0d29341, + 0x0a060960, + 0xa241d008, + 0x430cb720, + 0x0a70c002, + 0x792bb58c, + 0x5749b780, + 0x430cb720, + 0x4aabb58d, + 0xb7209c22, + 0x9e53430c, + 0xa95df010, + 0xa956f010, + 0x712db786, + 0x0124c101, + 0xb5860244, + 0xb720712d, + 0xf008430c, + 0xf008a972, + 0xb786a979, + 0xc10170ad, + 0x02440124, + 0x70adb586, + 0x430cb720, + 0xa966f008, + 0xa969f008, + 0x71adb786, + 0x0124c101, + 0xb5860244, + 0xb72071ad, + 0xd808430c, + 0xd808a961, + 0xb786a966, + 0xc101702d, + 0x02440124, + 0x702db586, + 0x430cb720, + 0x64adb786, + 0xb3407502, + 0xd80848a4, + 0xb786a965, + 0x02446fad, + 0x6fadb586, + 0xf0109c22, + 0xb720a9e2, + 0x0906430c, + 0x6435b566, + 0x430cb780, + 0x0a70c0d0, + 0xa101d208, + 0xa6059c22, + 0x430cb7a0, + 0xaa41d810, + 0xa945d810, + 0x0685008b, + 0x5e35b741, + 0x00890244, + 0xf2107684, + 0xcffea9b1, + 0xc00028fc, + 0x9ea99224, + 0x5a4bb78d, + 0x6dcdb746, + 0xb58d0238, + 0xf2105a4b, + 0x0128aa35, + 0x6dcdb546, + 0x9120c000, + 0xb56d9ea9, + 0xf2105a4b, + 0xb586aa35, + 0x9ea96dcd, + 0xa9a1f250, + 0x6fcdb786, + 0x704db746, + 0x6ed5b746, + 0xb5860246, + 0xf2506fcd, + 0xb786a9a5, + 0xb7666f4d, + 0x01265ad5, + 0x704db546, + 0xa925da10, + 0xb5860242, + 0xc1016f4d, + 0xb5460524, + 0xf2106ed5, + 0xf210a931, + 0xd0a4aa35, + 0x01835905, + 0xc1010244, + 0xb56605b8, + 0xda105ad5, + 0xda10aa39, + 0xc101a9be, + 0x05b405b8, + 0x9a5ec214, + 0xb786008b, + 0xb74c69ad, + 0x02406d2b, + 0xb5860904, + 0xb54c69ad, + 0xb7806d2b, + 0x7500448c, + 0x90a4c000, + 0xc0000109, + 0x9e699180, + 0xb9600902, + 0xb7804030, + 0x088454a9, + 0xffff0128, + 0x9ea99381, + 0x614bb54d, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0xaa61f010, + 0xb7209e5a, + 0x7500430c, + 0x9082c000, + 0x76adb586, + 0xa956d008, + 0x76bec01c, + 0x90e2c000, + 0xc0da0203, + 0xd2080a64, + 0xd008a102, + 0xc01ca959, + 0xc00074be, + 0x020390e2, + 0x0a68c0da, + 0xa101d208, + 0xc0da0103, + 0x0a060940, + 0xa241d008, + 0xa6059c22, + 0xf0109e55, + 0xf010a955, + 0xf010aa51, + 0xf208a95a, + 0xb720a9bd, + 0x0244430c, + 0x0244c101, + 0xb5860246, + 0xf208752d, + 0xf208a929, + 0xda08a9a6, + 0xda08aa25, + 0xb7a0a9a1, + 0xd1204314, + 0x01c601a7, + 0xffd40d02, + 0x9e699b22, + 0x712db506, + 0x430cb720, + 0xa935f208, + 0x702db786, + 0xb5860244, + 0xb720702d, + 0xf208430c, + 0xb786a935, + 0x0244722d, + 0x722db586, + 0x430cb720, + 0xa925f208, + 0x6fadb786, + 0xb5860244, + 0xb7206fad, + 0xda08430c, + 0xb78da939, + 0x0244612b, + 0x612bb58d, + 0x430cb720, + 0xa921da08, + 0x61abb78d, + 0xb58d0244, + 0xb72061ab, + 0xf208430c, + 0xb786a929, + 0x0244732d, + 0x732db586, + 0x430cb720, + 0xa93dda08, + 0x652bb78d, + 0xb58d0244, + 0xb720652b, + 0xda08430c, + 0xb78da925, + 0x024465ab, + 0x65abb58d, + 0x430cb720, + 0xaa25f208, + 0xa92af208, + 0x73adb746, + 0xc1010244, + 0xb5860244, + 0xb72073ad, + 0xf208430c, + 0xb786a939, + 0x0244742d, + 0x742db586, + 0x430cb720, + 0xa93df208, + 0x74adb786, + 0xb5860244, + 0xb72074ad, + 0xda08430c, + 0xda08a93a, + 0xb786a93d, + 0xc10175ad, + 0x02440124, + 0x75adb586, + 0x430cb720, + 0xaa21da08, + 0xa926da08, + 0x632bb74d, + 0xc1010244, + 0xb58d0244, + 0xb720632b, + 0xb787430c, + 0xb746462d, + 0x0244752d, + 0x462db587, + 0x430cb720, + 0xa939da08, + 0xaabdda08, + 0x492db787, + 0x024a02d4, + 0x492db587, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0xa9e2f010, + 0x430cb720, + 0xb5660906, + 0xb7806435, + 0xc0d0430c, + 0xd2080a70, + 0x9c22a101, + 0x430cb720, + 0xb78e9e58, + 0x11095bab, + 0x9060c000, + 0x70080004, + 0x93d6ffff, + 0x9060c000, + 0x74000008, + 0x93d8ffff, + 0x287ccffe, + 0xa6059c22, + 0x430cb7a0, + 0xb78e008b, + 0xc2005b2b, + 0x009a5888, + 0x7eb5b7a6, + 0x7eb5b566, + 0x09c2d012, + 0x9bdcfff4, + 0xb50e008b, + 0x9e685b2b, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0x430cb720, + 0x5e2db781, + 0xc0007502, + 0xb78691c4, + 0x750040a9, + 0x9122c000, + 0x5aabb78c, + 0x75020802, + 0x0802d002, + 0x08029c22, + 0xa60d9c22, + 0x4314b7a0, + 0xb7669e69, + 0xfff45ab5, + 0x03019bca, + 0x9be2fff4, + 0xc0007400, + 0x9e6991c2, + 0x6cadb786, + 0x5aadb746, + 0x4e35b746, + 0xc1010128, + 0xb5461124, + 0xb7a06cad, + 0x008b430c, + 0x75adb786, + 0xc0017500, + 0xfff49264, + 0x74009bc9, + 0x91a2c000, + 0xb78e008b, + 0xb7445bab, + 0x708867ad, + 0xd0040a02, + 0xc0000a42, + 0x008b9360, + 0x5e2db781, + 0xc0007502, + 0x750890a2, + 0x9204c000, + 0xb784008b, + 0xb74667ad, + 0xb7464e2d, + 0x624550b5, + 0x0a027115, + 0x0a42d00b, + 0x9080c000, + 0x008b0a06, + 0x75adb586, + 0xb706008b, + 0x740075ad, + 0x93a2c000, + 0x9b98fff4, + 0xc0007400, + 0x9e6992a2, + 0x532db786, + 0x7188c010, + 0x5b2bb78e, + 0x5a08c200, + 0x00cac101, + 0x7eadb786, + 0x12400268, + 0x7eadb586, + 0x90a0c000, + 0xb7069e69, + 0xb79f4e2d, + 0xb7bf7eee, + 0xb7df7f6e, + 0x8c607fee, + 0xf8399c22, + 0xfff4a205, + 0x74009b73, + 0x430cb700, + 0x91e2c000, + 0x5b2ab78e, + 0x532cb746, + 0x5a08c200, + 0xb78600c0, + 0xc0107ead, + 0xc0017104, + 0xb74192a0, + 0x74885e2c, + 0x9164c000, + 0x5b2ab78e, + 0x5a08c200, + 0xb70600c0, + 0xc0017ead, + 0xb78690e0, + 0x750075ac, + 0x9004c001, + 0xc0007482, + 0x748890a2, + 0x91e4c000, + 0x67acb784, + 0x4e2cb746, + 0x50b4b746, + 0x71156245, + 0xd00b0a02, + 0xc0000a42, + 0x0a069060, + 0x75acb586, + 0x75acb786, + 0xc0007500, + 0x000990a4, + 0x9080c000, + 0x4e2cb706, + 0xaa1df9f8, + 0xf0109c22, + 0xf010a966, + 0x9e5ca9e2, + 0x7100c814, + 0x7080c802, + 0x0e22d011, + 0x753c0244, + 0x915cc000, + 0x087ec7ff, + 0xcffe76c0, + 0xd00e087c, + 0x9c220804, + 0xc0007680, + 0xd02290bc, + 0x9c225468, + 0xc1019e5a, + 0x50531205, + 0x76e69c22, + 0x1000d01e, + 0x48bcb340, + 0x76c0c380, + 0x1524d02e, + 0x913cc000, + 0x084ec002, + 0xd0119c22, + 0xd2240e32, + 0x9e525987, + 0x76c8c004, + 0x4002ba12, + 0xffff0d04, + 0xb78092da, + 0x9e5b5d8c, + 0xc040691a, + 0x0244aa65, + 0xba000009, + 0x9c224002, + 0xa205f839, + 0x1cb0f011, + 0x9e539e99, + 0x90d6c000, + 0x0902c002, + 0x9100c000, + 0x7040d002, + 0x01090a04, + 0x4000ba12, + 0x19400d02, + 0xc8129e50, + 0x0a067004, + 0xcc1251eb, + 0xc00270c8, + 0xcc100dce, + 0xcc127246, + 0xba1b72c4, + 0xb7804003, + 0x05b65d0c, + 0x512b9e58, + 0xa986c840, + 0x4003ba1b, + 0x65b5c101, + 0x9bc4c1f4, + 0xfff49e83, + 0xf9f89baa, + 0x9c22aa1d, + 0x0e30f011, + 0x4314b760, + 0x92e2c000, + 0xc10100c8, + 0xb74c0096, + 0x750273b3, + 0xba120912, + 0xd0024003, + 0xd0311926, + 0xd0100e20, + 0xc10170c8, + 0xd0120124, + 0xba1c7104, + 0x9e5c4002, + 0x0a48c0c8, + 0xa801d208, + 0x70c0c010, + 0xaa1dd3e8, + 0x7008c012, + 0x287ccffe, + 0xf8399c22, + 0xb720a205, + 0x0a02430c, + 0x9e8b0992, + 0x702bb58c, + 0x0db0c0d4, + 0x6d2bb58c, + 0x5aadb586, + 0x542bb58d, + 0x672db586, + 0x67adb586, + 0x692db586, + 0x64adb586, + 0x996ffe54, + 0x4314b760, + 0x0982c002, + 0x0da0c0d6, + 0xaa1df9f8, + 0x90a0fe4b, + 0x430cb780, + 0xd11005b6, + 0xb78c04b9, + 0x01b87cab, + 0x4002ba1b, + 0x70c0d014, + 0x753ec7fc, + 0x48bab340, + 0x7cabb56c, + 0xa6059c22, + 0x430cb7a0, + 0xb781008b, + 0xb7a65e2d, + 0x75026bb5, + 0x9184c000, + 0x9a40fff4, + 0xc0007400, + 0x008b90e4, + 0x50adb706, + 0x9060c000, + 0xd1100802, + 0xb79f1451, + 0xb7bf7f6e, + 0x8c407fee, + 0xa6059c22, + 0x430cb7a0, + 0xb766008b, + 0xfff45ab5, + 0x008b9a0c, + 0x6cadb746, + 0x5aadb786, + 0x12400244, + 0x6cadb586, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0xb7a0a60d, + 0x097a430c, + 0xb786008b, + 0xd010502d, + 0x196c7104, + 0x7104cc12, + 0x4e2db786, + 0xb76c9e9d, + 0x9ea35a2b, + 0x6a7ac006, + 0x5bb3b5ae, + 0x0d025988, + 0x5b1fc200, + 0x983fffd4, + 0x7740008b, + 0x4eadb506, + 0x9c87c820, + 0x9116c000, + 0x4000b960, + 0x9080c000, + 0x7e2db5c6, + 0xffff0890, + 0x008b93a1, + 0x4e2db786, + 0x655dd131, + 0x6659d131, + 0x6cadb546, + 0x4fadb586, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0x9c228c60, + 0x8420a61d, + 0x430cb7a0, + 0x0787a199, + 0xb7869ea8, + 0x7502714c, + 0x1092d019, + 0x9132c000, + 0x08829ea8, + 0x634ab78d, + 0xd00a7502, + 0x9ea80892, + 0xb786a09d, + 0x7504564c, + 0x9364c001, + 0x5e4cb781, + 0x734ab7cc, + 0x594cb7e6, + 0xc0007502, + 0xfff49284, + 0x740099b1, + 0x91e4c000, + 0xb786008b, + 0xb74650ad, + 0xc2006bad, + 0x70885a08, + 0x90bcc000, + 0xc0000f32, + 0x0f129060, + 0xb7819ea8, + 0x75025e4c, + 0x9104c006, + 0x4e4cb786, + 0x4fccb746, + 0x70886a1e, + 0x9016c006, + 0x5e05d322, + 0x9ea50268, + 0x2efccffe, + 0x9180c001, + 0xc0c8020b, + 0xd2080a38, + 0xc001aa82, + 0x77c090a0, + 0x91e4c000, + 0xb78c008b, + 0x75006e2b, + 0x9122c000, + 0xc0c8020b, + 0xd2080a38, + 0xc003ab01, + 0xd01092e0, + 0x9ea804fe, + 0xc380009a, + 0xb78c5c88, + 0xb7cc654a, + 0xc101742b, + 0xb7e6049a, + 0x752a5b4d, + 0x9eb50f0e, + 0x1f62d009, + 0x7440a89d, + 0x9004c003, + 0xc00075c0, + 0x020b9124, + 0x0a48c0c8, + 0xa902d208, + 0x9100c004, + 0x9ebba91a, + 0x4002ba1e, + 0x9a6afff4, + 0x430cb720, + 0xb7819e82, + 0xcffe5e2d, + 0x75042d7c, + 0x9304c003, + 0xb7869ea8, + 0x7504564c, + 0x9242c003, + 0x5c88d3a2, + 0xb746009a, + 0xb7865f2d, + 0xb726602d, + 0xb7666135, + 0xe0006235, + 0xc0030244, + 0xc2009062, + 0x01a85905, + 0x6525d131, + 0xc18005b2, + 0xc1015a05, + 0xc10105b8, + 0xc1f405b4, + 0x9e829a2a, + 0x2d7ccffe, + 0x9200c002, + 0x5eadb781, + 0x75021a04, + 0x9192c000, + 0x066cd010, + 0xc1019e51, + 0xd010024a, + 0x9e6a7048, + 0x9120c000, + 0x066ad010, + 0xd0109e51, + 0xd0107048, + 0xd012155c, + 0x03097104, + 0x2b7ccffe, + 0x4314b7a0, + 0xb781040b, + 0x75025e4c, + 0x92a4c001, + 0x98f4fff4, + 0xc0017400, + 0x008b9204, + 0x562db786, + 0xc0017504, + 0x040b9144, + 0x64cab78d, + 0x7510c004, + 0x9074c001, + 0x50adb786, + 0x6badb746, + 0x5a08c200, + 0xc0007088, + 0x020b9356, + 0x0a38c0c8, + 0xab01d208, + 0x9260c000, + 0xb7ac008b, + 0x774073b3, + 0x9204fffb, + 0x9080fffa, + 0x430cb720, + 0x5e2db781, + 0xfffd7508, + 0xfffd93a4, + 0x058f9160, + 0x4002ba1e, + 0x9a12fff4, + 0x7deeb79f, + 0x7e6eb7bf, + 0x7eeeb7df, + 0x7f6eb7ff, + 0x8c20c002, + 0xa60d9c22, + 0x430cb7a0, + 0xb786008b, + 0x750075ad, + 0x9264c001, + 0x98a8fff4, + 0xc0007400, + 0x008b91a2, + 0x5babb78e, + 0x67adb744, + 0x0a027088, + 0x0a42d004, + 0x9360c000, + 0xb781008b, + 0x75025e2d, + 0x90a2c000, + 0xc0007508, + 0x008b9204, + 0x67adb784, + 0x4e2db746, + 0x50b5b746, + 0x71156245, + 0xd00b0a02, + 0xc0000a42, + 0x0a069080, + 0xb586008b, + 0x008b75ad, + 0x75adb786, + 0xc0037500, + 0x008b9042, + 0x5e2db781, + 0xc0027508, + 0x75029382, + 0x9224c000, + 0x986efff4, + 0x0a80f012, + 0x9164c000, + 0xb786008b, + 0xb7464e2d, + 0x6a1e4fad, + 0xc0017088, + 0x008b93f6, + 0x53abb78c, + 0xc0027500, + 0x008b9082, + 0x7433b7ac, + 0x6badb786, + 0xd8120906, + 0xb7817104, + 0x75025e2d, + 0x9184c000, + 0x984cfff4, + 0xc0007400, + 0x008b90e4, + 0x50adb786, + 0x9060c000, + 0xba2d0a02, + 0x9ea24003, + 0x9eb39e6b, + 0x995afff4, + 0x15d1d110, + 0x59870a0e, + 0x70c8cc10, + 0xcc121a08, + 0x008b70c8, + 0x6db3b76c, + 0xba1b1187, + 0xb79f4002, + 0xb7bf7eee, + 0xb7df7f6e, + 0x8c607fee, + 0x90c0ffee, + 0x99d7fff4, + 0x9e6c1001, + 0x7008c012, + 0xfffe7400, + 0xfffd905a, + 0xb79f9340, + 0xb7bf7eee, + 0xb7df7f6e, + 0x8c607fee, + 0xa6059c22, + 0x4314b7a0, + 0xb78c9e69, + 0x75025aab, + 0x1a42d001, + 0x90c2c000, + 0xb78c9e69, + 0x0a045b2b, + 0x652bb58d, + 0xb74c9e69, + 0xd0115aab, + 0xcffe1a22, + 0xc07c2a7c, + 0xc000753e, + 0x097f91f4, + 0x0a7ecffe, + 0x63abb54d, + 0x732db586, + 0x642bb54d, + 0x64abb54d, + 0x9120c001, + 0x9e939e69, + 0x5b2bb7ac, + 0x09d2d011, + 0x98f0c1f4, + 0x75401804, + 0x09029e69, + 0x287ccffe, + 0x0922d002, + 0xb50d0104, + 0x0a06642b, + 0x7088c812, + 0x652bb78d, + 0x4e35b746, + 0x62400a84, + 0xb5ad02d8, + 0xcffe64ab, + 0xc1012afc, + 0xb54d62d5, + 0xb5a663ab, + 0x9e69732d, + 0x652bb78d, + 0x4e2db746, + 0xb5866245, + 0xb79f73ad, + 0xb7bf7f6e, + 0x8c407fee, + 0xa61d9c22, + 0xb7c08440, + 0x008d430c, + 0x5e2db781, + 0x76adb726, + 0xc0087508, + 0x744092e4, + 0x90c2c006, + 0x0d029eb1, + 0x654bb76d, + 0x64cbb78d, + 0x4e4db746, + 0x5985d1a4, + 0xc1011094, + 0xa09905b8, + 0x99d7ffb4, + 0x008da015, + 0x652bb7ed, + 0x68abb78d, + 0x76b5b7c6, + 0x6333b7ed, + 0x1a041278, + 0x7780c005, + 0xc0009ea5, + 0xb7669152, + 0xc0054e2d, + 0xd31474c0, + 0xc0005da8, + 0x9eb190f4, + 0xb766058d, + 0x59ab4e4d, + 0x987fc1f4, + 0xcffea916, + 0xa9992efc, + 0x162ed010, + 0xba249e6a, + 0x624f4002, + 0x0659d110, + 0xb766008d, + 0xb7466ab5, + 0xba246b35, + 0xba124002, + 0x62474002, + 0xb76c6127, + 0xc1015a2b, + 0xc10105b8, + 0xb5660524, + 0xb5466ab5, + 0xb5c66b35, + 0x058d4e35, + 0x02815988, + 0x985cc1f4, + 0xb786008d, + 0xb506532d, + 0xc0054ead, + 0xc0007500, + 0xc20090f4, + 0x61595a2b, + 0x90a0c000, + 0xc2006259, + 0x9eb15929, + 0x4fcdb786, + 0x534db546, + 0x7500c005, + 0x90f4c000, + 0x5a2bc200, + 0xc0006159, + 0x625990a0, + 0x5929c200, + 0xb786008d, + 0xb5466bad, + 0xc0054fad, + 0xc0007500, + 0xc20090f4, + 0x62595a2b, + 0x90a0c000, + 0xc2006259, + 0x9eb15a29, + 0x6ccdb706, + 0x6bcdb586, + 0x7400c005, + 0x90f4c000, + 0x5a2bc000, + 0xc0006059, + 0x625190a0, + 0x5829c200, + 0xb7a6008d, + 0xb7a64e2d, + 0xb5064fb5, + 0xd2a46cad, + 0xd01059fd, + 0xc101065a, + 0xc10105ba, + 0xc200024a, + 0x5d875a13, + 0x01c7d120, + 0x50adb586, + 0xc1d4018b, + 0x600b9bff, + 0xb5069eb1, + 0xc01250cd, + 0x0a02700a, + 0x16d0c101, + 0x5155b5a6, + 0x76cdb586, + 0x50cdb506, + 0xc0da9eb2, + 0xd0100d60, + 0x7480a941, + 0x9142c000, + 0xc0c8020d, + 0xd2080a38, + 0x0a02a101, + 0xa241d010, + 0xc0da9eb2, + 0xd0100d68, + 0xc01ca941, + 0xc00074be, + 0xc0029222, + 0xd0100a4e, + 0x09027088, + 0x7104d012, + 0xc0c8010d, + 0xd0080948, + 0x0a7fa241, + 0xa241d010, + 0xc0da9eb2, + 0xd0100d64, + 0xc01ca941, + 0xc00074be, + 0xc0029222, + 0xd0100a4e, + 0x09027088, + 0x7104d012, + 0xc0c8010d, + 0xd0080944, + 0x0a7fa241, + 0xa241d010, + 0x9a8ffff4, + 0x7d6eb79f, + 0x7deeb7bf, + 0x7e6eb7df, + 0x7eeeb7ff, + 0x8c40c002, + 0x9380ffe3, + 0xc0067440, + 0x9eb190c2, + 0xb76d0d02, + 0xb78d654b, + 0xb74664cb, + 0xd1a44e4d, + 0x10945985, + 0x05b8c101, + 0xffb4a09d, + 0xa01198c2, + 0xb7ed008d, + 0xb78d652b, + 0xb7c668ab, + 0xb7ed76b5, + 0x12786333, + 0xc0051a04, + 0x9ea57780, + 0x9152c000, + 0x4e2db766, + 0x74c0c005, + 0x5da8d314, + 0x90f4c000, + 0x058d9eb1, + 0x4e4db766, + 0xc1d459ab, + 0xa9129b6a, + 0x2efccffe, + 0xd010a99d, + 0x9e6a162e, + 0x4002ba24, + 0xd110624f, + 0x008d0659, + 0x6ab5b766, + 0x6b35b746, + 0x4002ba24, + 0x4002ba12, + 0x61276247, + 0x5a2bb76c, + 0x05b8c101, + 0x0524c101, + 0x6ab5b566, + 0x6b35b546, + 0x4e35b5c6, + 0x5988058d, + 0xc1d40281, + 0x008d9b47, + 0x532db786, + 0x4eadb506, + 0x7500c005, + 0x90f4c000, + 0x5a2bc200, + 0xc0006159, + 0x625990a0, + 0x5929c200, + 0xb7869eb1, + 0xb5464fcd, + 0xc005534d, + 0xc0007500, + 0xc20090f4, + 0x61595a2b, + 0x90a0c000, + 0xc2006259, + 0x008d5929, + 0x6badb786, + 0x4fadb546, + 0x7500c005, + 0x90f4c000, + 0x5a2bc200, + 0xc0006259, + 0x625990a0, + 0x5a29c200, + 0xb7069eb1, + 0xb5866ccd, + 0xc0056bcd, + 0xc0007400, + 0xc00090f4, + 0x60595a2b, + 0x90a0c000, + 0xc2006251, + 0x008d5829, + 0x4e2db7a6, + 0x4fb5b7a6, + 0x6cadb506, + 0x59fdd2a4, + 0x065ad010, + 0x05bac101, + 0x024ac101, + 0x5a13c200, + 0xd1205d87, + 0xb58601c7, + 0x018b50ad, + 0x9aeac1d4, + 0x9eb1600b, + 0x50cdb506, + 0x700ac012, + 0xc1010a02, + 0xb5a616d0, + 0xb5865155, + 0xb50676cd, + 0x9eb250cd, + 0x0d60c0da, + 0xa941d010, + 0xc0007480, + 0x020d9142, + 0x0a38c0c8, + 0xa101d208, + 0xd0100a02, + 0x9eb2a241, + 0x0d68c0da, + 0xa941d010, + 0x74bec01c, + 0x9222c000, + 0x0a4ec002, + 0x7088d010, + 0xd0120902, + 0x010d7104, + 0x0948c0c8, + 0xa241d008, + 0xd0100a7f, + 0x9eb2a241, + 0x0d64c0da, + 0xa941d010, + 0x74bec01c, + 0x9222c000, + 0x0a4ec002, + 0x7088d010, + 0xd0120902, + 0x010d7104, + 0x0944c0c8, + 0xa241d008, + 0xd0100a7f, + 0xb79fa241, + 0xb7bf7d6e, + 0xb7df7dee, + 0xb7ff7e6e, + 0xc0027eee, + 0xffeb8c40, + 0x9e5a9200, + 0x70c0d014, + 0x1a0476c0, + 0x0244d01b, + 0x1228d01c, + 0xff9d9ea3, + 0xa60d92c0, + 0x4314b7a0, + 0x03079e5d, + 0xc0d8058b, + 0xc00e0da0, + 0xfe3409b2, + 0xb760986c, + 0xc00a4314, + 0xc0ca0992, + 0xfe340dc0, + 0xb7609864, + 0xc0024314, + 0xc0d60982, + 0xfe340da0, + 0xb760985c, + 0x09d24314, + 0x0dd0c0d4, + 0x9855fe34, + 0x4314b760, + 0x09f2c04c, + 0x0dd0c0e6, + 0x984dfe34, + 0x018b058b, + 0x0d80c0c6, + 0x0d32c004, + 0x9870fe34, + 0x9e699e68, + 0x4facb786, + 0x040b097f, + 0x7520c001, + 0xc0c89e6c, + 0xc0da0c38, + 0xc0de0a64, + 0xd20808a0, + 0x0a22a101, + 0x4029b580, + 0x4050b760, + 0xd00d9e6b, + 0x0c821a48, + 0xb421050b, + 0x9e69443a, + 0x09e8c0da, + 0x0d60c0da, + 0xd0089e4d, + 0x9d0aa161, + 0xb56c018d, + 0xd0107332, + 0xb526a0c2, + 0x040b76b4, + 0x08e0c12a, + 0x0b02c010, + 0xa961d008, + 0x9e689e44, + 0x0a6cc0da, + 0xa101d208, + 0xaa61d008, + 0x6fb2b74d, + 0xa9c2d018, + 0x0a027500, + 0x0a42d002, + 0x0244c101, + 0x6faab58d, + 0x7e7edffc, + 0x0d38d012, + 0x430cb740, + 0x05a2d022, + 0xc0c80205, + 0xd2080a48, + 0x9e58aa01, + 0x7008d010, + 0x0944c0c8, + 0xa941d008, + 0x7104d012, + 0x76440c84, + 0x462bb59a, + 0x402bb5c0, + 0x412bb5a0, + 0x0c040984, + 0xfffe0888, + 0xb7209124, + 0xb78c430c, + 0x752a652b, + 0x9112c000, + 0x0a169e69, + 0x7b2bb58d, + 0x90a0c000, + 0xb52d9e68, + 0x9e697b32, + 0xb7660d02, + 0xb76650b5, + 0xfff44e2d, + 0xcffe9b40, + 0x0a7a287c, + 0x7008c010, + 0xc0121a74, + 0x9e697008, + 0x5babb50e, + 0x98a1fff4, + 0xb78c9e68, + 0x750065aa, + 0xd0010a02, + 0xb5800a42, + 0xb79f448c, + 0xb7bf7eee, + 0xb7df7f6e, + 0x8c607fee, + 0xb7209c22, + 0x0a02430c, + 0x4aabb72d, + 0xa271f010, + 0xa269f010, + 0xa0e1f010, + 0xa265f010, + 0xa27dd810, + 0xa279d810, + 0xa279f010, + 0xa271f050, + 0xa261f050, + 0xa27dd850, + 0xa279d850, + 0xa269d850, + 0xa26df050, + 0xa269f050, + 0xa265f050, + 0xa275f050, + 0x430cb720, + 0x4aabb74d, + 0x6f2db546, + 0x430cb720, + 0x712db586, + 0x430cb720, + 0x702db586, + 0x430cb720, + 0x6fadb586, + 0x430cb720, + 0x61abb58d, + 0x430cb720, + 0x612bb58d, + 0x430cb720, + 0x722db586, + 0x430cb720, + 0x732db586, + 0x430cb720, + 0x65abb58d, + 0x430cb720, + 0x652bb58d, + 0x430cb720, + 0x632bb58d, + 0x430cb720, + 0x74adb586, + 0x430cb720, + 0x742db586, + 0x430cb720, + 0x73adb586, + 0x430cb720, + 0x75adb586, + 0x430cb720, + 0x752db586, + 0x74c29c22, + 0xc0019e98, + 0xb78091a4, + 0x0902430c, + 0x0a00c0e2, + 0xa101d208, + 0x4314b720, + 0x684bb78c, + 0xc0017500, + 0xb7269104, + 0xb74d54cd, + 0xb7876353, + 0xb766464d, + 0xb7466dcd, + 0xb766514d, + 0xc10150d5, + 0x02466523, + 0x1244c101, + 0x1126c101, + 0xc0007104, + 0x9e4c925c, + 0x0a00c0e2, + 0xa002d208, + 0x9160c000, + 0xc00074c0, + 0xf0109104, + 0xb720aa61, + 0xb58d430c, + 0xb7804aab, + 0xc0e2430c, + 0xd2080a00, + 0x9c22a801, + 0x8420a61d, + 0xa1199e57, + 0x9e4a9e9f, + 0xcc120d02, + 0xd0317286, + 0xaa1966be, + 0x7540d001, + 0x020b134e, + 0x4828b334, + 0xc0007580, + 0x9ea3935c, + 0xff94018d, + 0xaa199a22, + 0xc2009e86, + 0x71885a0b, + 0x931ac000, + 0x5990d3a4, + 0x01fec101, + 0xff940d02, + 0xc1019a14, + 0xd024600d, + 0xc0005b13, + 0xb7209160, + 0x0d02430c, + 0x4c2db726, + 0xff941194, + 0x9e869a06, + 0x77400e82, + 0x913ac000, + 0xc0007740, + 0xcfff90e4, + 0xc000757e, + 0x676f9074, + 0xb79f9e70, + 0xb7bf7dee, + 0xb7df7e6e, + 0xb7ff7eee, + 0xc0027f6e, + 0x9c228c20, + 0xb720a61d, + 0x0d02430c, + 0x4c2db766, + 0x45b5b767, + 0x5ab3b7cc, + 0x632bb7ad, + 0x712db7e6, + 0x73b5b7e6, + 0x99dbff94, + 0x430cb720, + 0xb7860301, + 0xb70764ad, + 0x7504462d, + 0x9264c001, + 0x45adb787, + 0xd0207540, + 0xc00012c0, + 0xb7669282, + 0x018b74b5, + 0xff940d02, + 0xb72099c4, + 0x0a02430c, + 0x4c2db726, + 0x6003109a, + 0x1451d110, + 0x7100c812, + 0xb7209e95, + 0xb786430c, + 0x750265ad, + 0x91b4c000, + 0xc00077ba, + 0x9ea99152, + 0x49adb747, + 0x4003ba09, + 0xc001058b, + 0xb76690c0, + 0x058b4c2d, + 0xc0010d02, + 0xb7879120, + 0x754044ad, + 0x11c0d020, + 0x9142c000, + 0x4c2db786, + 0x4aadb747, + 0x6245124a, + 0x15b8c101, + 0x65adb786, + 0xc0007502, + 0xb78d90f2, + 0x75004a2b, + 0x91a2c000, + 0xb7479ea9, + 0xba094a2d, + 0x018f4003, + 0xfff4050f, + 0xc0009b45, + 0xb7669100, + 0x9ea24c2d, + 0xff9411ba, + 0x0a029976, + 0x7100d012, + 0x000c006c, + 0x7008c010, + 0x7e6eb79f, + 0x7eeeb7bf, + 0x7f6eb7df, + 0x7feeb7ff, + 0x8c00c002, + 0xf8399c22, + 0xb740a205, + 0xd0105c8c, + 0x02440624, + 0xaa1ddbc8, + 0x9e5b0107, + 0x70886a0c, + 0x4834b320, + 0x91b4c001, + 0xc00076c0, + 0xb760927c, + 0xc18040d5, + 0x0d025a07, + 0x61a7d132, + 0xc1015d99, + 0xff9405b8, + 0x582b9944, + 0x4002ba00, + 0x90c0c000, + 0x0e22d011, + 0x4002ba04, + 0x430cb740, + 0xc0e40205, + 0xd2080a14, + 0x7008aa01, + 0x443ab340, + 0x913ac000, + 0xc0e40205, + 0xd2080a10, + 0xc012aa01, + 0xf9f87008, + 0x9c22aa1d, + 0xa205f839, + 0x430cb720, + 0x64adb786, + 0xc0007504, + 0xc0e690c4, + 0xc0000890, + 0xc0e69080, + 0xb78008d0, + 0xdffc43ab, + 0xc0007d3e, + 0x9e5090a4, + 0x90a0c000, + 0xfff49e89, + 0xb7209ba8, + 0xb78d430c, + 0x75024dab, + 0x91c4c000, + 0xc0c80203, + 0xd2080a60, + 0x7500aa01, + 0x90c4c000, + 0x0a04d011, + 0x4002ba04, + 0xc0d20203, + 0xd2080a60, + 0x7502aa01, + 0x90c4c000, + 0x0a02d011, + 0x4002ba04, + 0x522bb74d, + 0x0a28d011, + 0xc0007008, + 0xd01190fa, + 0x70081a28, + 0x9096c000, + 0x4002ba04, + 0xc0e40203, + 0xd2080a0c, + 0x097ba902, + 0xc1010183, + 0xba241204, + 0xd0124002, + 0x09107104, + 0x7104d010, + 0x0994c0e4, + 0x0528c101, + 0xa961d008, + 0xba009e50, + 0x70044002, + 0x443ab320, + 0x913ac000, + 0xc0e40203, + 0xd2080a10, + 0xc012aa01, + 0xf9f87008, + 0x9c22aa1d, + 0x76c0a61d, + 0x430cb720, + 0x9264c000, + 0x65abb74d, + 0x61abb78d, + 0xb7a69e8d, + 0xb766702d, + 0xb72d6fad, + 0xd0206133, + 0xc0e60128, + 0xc0000ed0, + 0x9e8d91a0, + 0x65b3b74d, + 0x722db7a6, + 0x732db766, + 0x6533b72d, + 0x0e90c0e6, + 0x7680c008, + 0x92bcc000, + 0x5e1bf122, + 0x90ccc000, + 0x0a02c002, + 0x90e0c000, + 0x7100d002, + 0xba240a04, + 0x9ea34000, + 0x52b3c200, + 0x554f54af, + 0x768051f3, + 0x93a2c002, + 0x468cb780, + 0x0524d010, + 0xc8409e51, + 0xb780ab46, + 0xda10470c, + 0xc100a931, + 0xc0405d87, + 0xd131aba5, + 0x09046667, + 0xda109e53, + 0xc200a131, + 0x05b2531f, + 0xff940d02, + 0xc00c985e, + 0x9e877588, + 0xa935da10, + 0x937cc001, + 0x4002ba12, + 0x12440a6e, + 0x65ebc101, + 0x02899eba, + 0x4002ba2d, + 0xc07e55eb, + 0xcc100d7e, + 0x9eaa72c4, + 0x5a07c300, + 0xc10155e8, + 0x018d05b8, + 0xff940d02, + 0x9e83983e, + 0xaa21f210, + 0xa9b1da10, + 0xc10165bf, + 0xf21005b8, + 0xba1ba1a2, + 0x0d024002, + 0x982fff94, + 0xf210755e, + 0xd04da025, + 0xd01a1a50, + 0xc0005213, + 0x0a4290ba, + 0x5210124a, + 0xa225f210, + 0xda100a06, + 0xb79fa23d, + 0xb7bf7e6e, + 0xb7df7eee, + 0xb7ff7f6e, + 0xc0027fee, + 0x9c228c00, + 0x76c2a605, + 0x91e4c001, + 0x430cb720, + 0x64adb786, + 0xd0227504, + 0xfff415b6, + 0xb7209b53, + 0xb74d430c, + 0xb786632b, + 0x70884c2d, + 0x93a2c000, + 0x712db7a6, + 0x9a0efff4, + 0x430cb780, + 0x018b9e83, + 0xc0c80109, + 0xd0080938, + 0xc0e4a941, + 0x9e920a0c, + 0xa101d208, + 0xfff40916, + 0xb7809ac5, + 0xc0c8430c, + 0xd2080a38, + 0xb780a001, + 0xc0c8430c, + 0xd2080a38, + 0xb79fa801, + 0xb7bf7f6e, + 0x8c407fee, + 0xa6059c22, + 0x4314b720, + 0x05839e5b, + 0x0d88c0e2, + 0xa961d010, + 0x4655b747, + 0x6dcdb786, + 0xd1107480, + 0xc0000529, + 0xb7869102, + 0x02484e4d, + 0xc00110c4, + 0xb7809060, + 0xc101440c, + 0xb5400528, + 0xb7864414, + 0x729950cd, + 0x91b8c000, + 0xd0100a06, + 0xb720a261, + 0xb726430c, + 0x00924e2d, + 0xc0001094, + 0xb78d91a0, + 0xb7464a4b, + 0x0a084e4d, + 0x729360c5, + 0x9216c000, + 0x1094c101, + 0xc0007440, + 0xd071917c, + 0xc2000a1e, + 0xf0085a17, + 0x0a06a265, + 0x90a0c000, + 0xf0080a02, + 0xd808a265, + 0xb7a0a265, + 0x0d02430c, + 0xb78d008b, + 0xb76d65ab, + 0xb74761ab, + 0x01b8492d, + 0x5985d1a4, + 0x05b4c101, + 0x9b7bff74, + 0xb50c008b, + 0xb7206a2b, + 0xb78c430c, + 0xc0c86a2b, + 0xb58008b8, + 0xb7204029, + 0xb787430c, + 0xb587452d, + 0xb72044ad, + 0xb786430c, + 0x750464ad, + 0x9024c001, + 0x65adb786, + 0xc0007502, + 0xb7879284, + 0x09964b2d, + 0xc2000d02, + 0xb5875a0b, + 0xb7a04bad, + 0x008b430c, + 0x7d35b766, + 0x9b4fff74, + 0xb506008b, + 0xb7207d2d, + 0xb786430c, + 0xb58773ad, + 0xc00149ad, + 0xb7869040, + 0xb587742d, + 0xb7204bad, + 0xb786430c, + 0xb58773ad, + 0xb7204a2d, + 0xb787430c, + 0xb58644ad, + 0xb7207d2d, + 0xb78d430c, + 0xb74c52ab, + 0x02446a2b, + 0x52abb58d, + 0x430cb720, + 0x4a2bb78d, + 0xb58d0a04, + 0xb79f4a2b, + 0xb7bf7f6e, + 0x8c407fee, + 0x9e9a9c22, + 0xd1220906, + 0x52445c87, + 0x72d91a04, + 0x933cc000, + 0x1a32d011, + 0x19045250, + 0x9160c000, + 0xc0007917, + 0xd11090c2, + 0xc0001627, + 0xc2009360, + 0xba1a5a07, + 0x70c24002, + 0xffff0904, + 0x08029278, + 0xd0119c22, + 0x75001a12, + 0xc8100d02, + 0x51509c83, + 0x4818b323, + 0x9160c000, + 0xc0007897, + 0x121890e2, + 0xba000009, + 0x9c224002, + 0x9e545907, + 0xba240d04, + 0xffff4002, + 0x08069261, + 0xa6059c22, + 0x430cb7a0, + 0x09020687, + 0xb9609eaa, + 0xc0c64258, + 0x9e690d00, + 0xc0209e93, + 0x0904aa25, + 0xa249c030, + 0x9321ffff, + 0xc0020d82, + 0xfff40982, + 0x74009bae, + 0x0a02010b, + 0x0a42d002, + 0x0964c0c8, + 0xa241d008, + 0x430cb7a0, + 0x008b09ba, + 0x4c35b766, + 0x9b9dfff4, + 0xb50e008b, + 0xb7205bab, + 0x0902430c, + 0x5babb78e, + 0x5fabb58e, + 0x430cb720, + 0x0a06c001, + 0x5cabb54e, + 0x430cb720, + 0x60abb54e, + 0x430cb720, + 0x4d2db587, + 0x430cb720, + 0x4e2db786, + 0x6e2db586, + 0xb7809e69, + 0xb7205729, + 0xb58d430c, + 0xb79f4aab, + 0xb7bf7f6e, + 0x8c407fee, + 0x0a029c22, + 0xa261d810, + 0x430cb720, + 0x632bb78c, + 0xb3407500, + 0xb74648a4, + 0xb7664e2d, + 0xb7464fad, + 0x02246db5, + 0xc1010244, + 0xc20011b4, + 0xb7465a07, + 0xd0126e2d, + 0xb7477104, + 0xb74c46b5, + 0x70c85aab, + 0x1124c101, + 0xc0001904, + 0x0a0690b6, + 0xa261d810, + 0x430cb720, + 0x6035b746, + 0xc0007680, + 0x748691e2, + 0x919ac000, + 0x4e2db786, + 0x02466229, + 0xc0007115, + 0x0a0690b6, + 0xa261d810, + 0x430cb720, + 0x4e2db786, + 0x6dadb746, + 0x70880248, + 0x1248d01c, + 0x4459b423, + 0xa6059c22, + 0x430cb720, + 0xb7870687, + 0x1a04472d, + 0x472db587, + 0xa961d810, + 0x430cb720, + 0xc0007482, + 0x0a029164, + 0x44adb587, + 0x430cb720, + 0x4dabb54d, + 0x9160c000, + 0xb58d0a02, + 0xb7204dab, + 0xb787430c, + 0xb58746ad, + 0xb72047ad, + 0x9e8b430c, + 0x4e35b746, + 0x0d84c0e2, + 0xa9e1d010, + 0xc00074c0, + 0x058590a2, + 0x9280c000, + 0x67adb784, + 0x50adb746, + 0x6629d131, + 0xb3337104, + 0xc0004458, + 0x0a069138, + 0xa261d010, + 0x430cb720, + 0x4e35b766, + 0x430cb720, + 0x0d02091e, + 0x6dadb766, + 0x462db787, + 0xc1010246, + 0xb5861246, + 0xb7206dad, + 0xb786430c, + 0xb76776ad, + 0x1246462d, + 0x76adb586, + 0x430cb720, + 0x4e35b726, + 0x462db787, + 0x5e2fb763, + 0x1419d110, + 0x587fd024, + 0x01b0e000, + 0xd00305b0, + 0xb5630db2, + 0xb7205e2f, + 0xb787430c, + 0xb726462d, + 0xb7634e35, + 0xd1105d2f, + 0xd0241419, + 0xe000587f, + 0x05b001b0, + 0x0db2d003, + 0x5d2fb563, + 0x430cb7a0, + 0xb763008b, + 0xc1b45d2f, + 0xd022984e, + 0x01015e74, + 0x3144590d, + 0x597fd124, + 0xb543008b, + 0xb7205daf, + 0xb786430c, + 0xb74764ad, + 0x75044635, + 0x9344c000, + 0x6035b546, + 0x430cb720, + 0xb7860d02, + 0xb5866dad, + 0xb7a0762d, + 0x008b430c, + 0x5aabb76c, + 0x6db5b766, + 0xff741984, + 0x008b999a, + 0x4c2db507, + 0x9180c000, + 0x6e2db746, + 0x02440224, + 0x0244c101, + 0x5a09c200, + 0x6e2db586, + 0xfff4058b, + 0xb7209afc, + 0x0a02430c, + 0x462db587, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0xb7a0a60d, + 0x0687430c, + 0x03070d86, + 0x9964fff4, + 0xb506008b, + 0xb7606f2d, + 0x09864314, + 0x0de0c0d6, + 0x9af3ffd4, + 0x430cb720, + 0x4635b5a7, + 0xaa41da08, + 0xc0007500, + 0x9eb390a4, + 0x998bfff4, + 0x4314b700, + 0xc0d09e44, + 0xd2080a70, + 0x7502aa01, + 0x9044c002, + 0x6454b746, + 0x4e54b726, + 0x5acab74c, + 0x4e54b546, + 0x430cb720, + 0x4a52b76d, + 0xb7661522, + 0xb78c642d, + 0x19045aab, + 0x1126c101, + 0xc1016247, + 0xb5866125, + 0xb72053ad, + 0xb786430c, + 0x024476ad, + 0x76adb586, + 0x430cb7a0, + 0xb76c008b, + 0xb7665a2b, + 0x59884e35, + 0x9bf8c194, + 0xb506008b, + 0xb7a04ead, + 0x008b430c, + 0x4eb5b766, + 0x4cadb766, + 0x9be7c194, + 0xb506008b, + 0xb78054ad, + 0x0902430c, + 0x0a70c0d0, + 0xa101d208, + 0xb79f9eb3, + 0xb7bf7eee, + 0xb7df7f6e, + 0x8c607fee, + 0x90e0fff6, + 0x6e3bd331, + 0xd2249e5a, + 0xd0115921, + 0x72991a26, + 0x90bcc000, + 0xba129ea2, + 0xd0114003, + 0x0d8a09a6, + 0xc8120124, + 0x70867286, + 0x9096c000, + 0x4002ba13, + 0xd0100a7e, + 0xb7407088, + 0xc0e4430c, + 0xd0080914, + 0xb780a241, + 0xc0e4430c, + 0xd2080a10, + 0x9c22a102, + 0xb720a60d, + 0x76c2430c, + 0x46adb787, + 0xb5870a04, + 0xb72046ad, + 0xb566430c, + 0xc00a64b5, + 0xb7209364, + 0x0d02430c, + 0xb7860a82, + 0xb747762d, + 0xb7674c2d, + 0xb76746b5, + 0x124447ad, + 0x762db586, + 0x4314b720, + 0x1737d110, + 0x4bb5b7a7, + 0x474db767, + 0x76d5b766, + 0x98b9ff74, + 0x430cb720, + 0x6dadb746, + 0x7635b746, + 0x4e2db786, + 0x1124c101, + 0x12445907, + 0x7148d012, + 0x08040008, + 0xb5075807, + 0xb72045ad, + 0xb787430c, + 0xb74645ad, + 0xd0127c2d, + 0xb5877104, + 0xb72045ad, + 0xb747430c, + 0xb78645ad, + 0xc8107b2d, + 0x75827088, + 0x45adb547, + 0x93dcc000, + 0x430cb720, + 0x058b9eaa, + 0x4c2db766, + 0x9887ff74, + 0x430cb720, + 0x02030936, + 0x0a64c0c8, + 0xa902d208, + 0x4c2db726, + 0xc1011d04, + 0x02401264, + 0x7104d010, + 0x0244c101, + 0x62c2d032, + 0x430cb720, + 0x45adb787, + 0x124ac101, + 0x44adb587, + 0x430cb720, + 0x4b2db787, + 0x44adb747, + 0x5a1bc200, + 0xc0007088, + 0xb5879096, + 0xb72044ad, + 0x9eaa430c, + 0x4c2db786, + 0x5a05c200, + 0x0659d110, + 0x4aadb587, + 0x430cb7a0, + 0xb767008b, + 0xb7664ab5, + 0xff744c2d, + 0x008b984a, + 0x4aadb507, + 0x430cb720, + 0x44adb787, + 0x0659d110, + 0x45adb587, + 0x430cb720, + 0x65adb786, + 0xc0007502, + 0xb78d90f2, + 0x75004a2b, + 0x92a2c001, + 0x4d2bb74d, + 0x6a2bb70c, + 0xd0027480, + 0xc0010a02, + 0xb7869264, + 0xcffe7d2d, + 0x7500287c, + 0x919cc000, + 0x44adb767, + 0x9e926209, + 0x5987d1a4, + 0x01c7d120, + 0x9819ff74, + 0x430cb720, + 0x6a33b74c, + 0x1204c101, + 0x7100d014, + 0xc0007504, + 0xb50c90da, + 0xc0006a2b, + 0x729192a0, + 0x0a7acffe, + 0xb324090a, + 0xc101443c, + 0xc0000244, + 0xb74c9120, + 0xb78c6a2b, + 0x02446aab, + 0x5a07c200, + 0x6a2bb58c, + 0x430cb720, + 0x4d2bb78d, + 0xc0007500, + 0xb78c9204, + 0x753e6a2b, + 0x90b4c000, + 0xc0000a7e, + 0x750090c0, + 0x90a4c000, + 0xb58c0a04, + 0xb7206a2b, + 0xb786430c, + 0x750265ad, + 0x90f2c000, + 0x4a2bb78d, + 0xc0007500, + 0xb78d91e2, + 0x75004d2b, + 0x92e4c000, + 0x6a33b76c, + 0x2dfcc00e, + 0x9ac2fff4, + 0x91e0c000, + 0xc0e40103, + 0x0a0a0910, + 0xa241d008, + 0x430cb780, + 0xc0e4097e, + 0xd2080a14, + 0xb720a101, + 0xb78e430c, + 0x7502502b, + 0x91e4c000, + 0xc0c80203, + 0xd2080a60, + 0x7500aa01, + 0x90e4c000, + 0x6a2bb78c, + 0xb58c0a08, + 0xb7206a2b, + 0xb78c430c, + 0xc0c86a2b, + 0x0a0408b8, + 0x4029b580, + 0x430cb740, + 0x02059e92, + 0x0d38c0c8, + 0x0a14c0e4, + 0xaa01d208, + 0xa9c1d010, + 0xc00070c8, + 0x02059152, + 0x0a10c0e4, + 0xaa01d208, + 0xc00070c8, + 0xd0109088, + 0xb740a241, + 0x0205430c, + 0x0a38c0c8, + 0xaa01d208, + 0x090cc0e4, + 0xa241d008, + 0x430cb720, + 0xb5870a02, + 0xb7204cad, + 0xb58e430c, + 0xb7205b2b, + 0xb58e430c, + 0xb7205c2b, + 0xb587430c, + 0xb7204ead, + 0xb58e430c, + 0xb7205f2b, + 0xb58e430c, + 0xb720602b, + 0xb587430c, + 0xb720462d, + 0xb587430c, + 0xb720452d, + 0xb587430c, + 0xb720492d, + 0x0203430c, + 0x0a0cc0e4, + 0xaa01d208, + 0x522bb58d, + 0x430cb720, + 0xc0c80203, + 0xd2080a38, + 0xb58daa01, + 0xb79f4aab, + 0xb7bf7eee, + 0xb7df7f6e, + 0x8c607fee, + 0xa6059c22, + 0x430cb720, + 0xb7860d02, + 0x0a0465ad, + 0x65adb586, + 0x430cb720, + 0x46b5b547, + 0x430cb720, + 0x5aabb78c, + 0x472db587, + 0x430cb720, + 0x5033b54e, + 0x430cb780, + 0x5aabb76c, + 0x0a60c0d2, + 0xa102d208, + 0x430cb720, + 0x65adb786, + 0xc0007502, + 0xb5469184, + 0xb72076b5, + 0xb78c430c, + 0xb58d6aab, + 0xc00052ab, + 0xb7869120, + 0xb74650ad, + 0x12446dad, + 0x76adb586, + 0x430cb720, + 0x76adb746, + 0x4e2db786, + 0xd1240144, + 0xb543597f, + 0xb7205e2f, + 0xb746430c, + 0xb78676ad, + 0x0144512d, + 0x597fd124, + 0x5d2fb543, + 0x430cb720, + 0x5d2fb743, + 0x5dafb543, + 0x430cb720, + 0x76adb786, + 0x53adb746, + 0xb5860244, + 0xb72076ad, + 0xb786430c, + 0xb74653ad, + 0xc20076ad, + 0x70885a07, + 0x93f6c000, + 0xc0d20203, + 0x0d060a60, + 0xa102d208, + 0x430cb720, + 0x53adb786, + 0x76adb746, + 0xc2006a16, + 0x70885a13, + 0x91b6c000, + 0x5033b54e, + 0x430cb720, + 0x53adb786, + 0xc2006a16, + 0xb5865a13, + 0xb7a076ad, + 0x0990430c, + 0x9ea80d02, + 0x76d4b766, + 0x9aafff54, + 0xb507008b, + 0xb7204b2d, + 0xb787430c, + 0x6a164b2d, + 0x45adb587, + 0x430cb720, + 0x76adb786, + 0xc0007500, + 0x0a0290b6, + 0x45adb587, + 0x430cb7a0, + 0x094ec002, + 0x9ea80d02, + 0x4f4cb766, + 0x59ffd1a4, + 0x991dc194, + 0xb767008b, + 0xd02245ad, + 0xc0005e64, + 0x30c2589d, + 0xc00070c2, + 0x9ea890bc, + 0x45ccb527, + 0x430cb720, + 0x45adb787, + 0x7c2db746, + 0x7104d012, + 0x45adb587, + 0x430cb720, + 0x45adb787, + 0x7b2db746, + 0x7104d010, + 0x45adb587, + 0x430cb720, + 0x45adb787, + 0x44adb587, + 0x430cb7a0, + 0xb76d008b, + 0x74c04a2b, + 0x9142c000, + 0x52b3b76d, + 0xff540d02, + 0x9ea89a5a, + 0x52cab50d, + 0x430cb720, + 0x65adb786, + 0xc0007502, + 0x018393b4, + 0x09e0c0c8, + 0xa962d008, + 0xc0007680, + 0xb78d92a2, + 0x753052ab, + 0x9212c000, + 0x53adb786, + 0x76adb746, + 0xc2006a1e, + 0x70885a0f, + 0x90dcc000, + 0x1e22d011, + 0xa261d008, + 0x430cb720, + 0x6a2bb78c, + 0xd0097506, + 0xd3e91a44, + 0xc0002ace, + 0x0a8a9072, + 0x65adb786, + 0xc0007502, + 0x757a9194, + 0xb3540a72, + 0x9ea34426, + 0xfff40289, + 0xc0009913, + 0x010391e0, + 0x0910c0e4, + 0xd0080a0a, + 0xb780a241, + 0x097e430c, + 0x0a14c0e4, + 0xa101d208, + 0x430cb720, + 0x502bb78e, + 0xc0007502, + 0x020391c4, + 0x0a60c0c8, + 0xaa01d208, + 0xd0017500, + 0xd3e10a54, + 0xc000294e, + 0x010b9062, + 0xc0d20203, + 0xd2080a60, + 0x7502aa01, + 0x0a24d001, + 0x294ed3e1, + 0xc0e40203, + 0xd2080a14, + 0x7097a982, + 0x4832b332, + 0x91f2c000, + 0xc0e40203, + 0xd2080a10, + 0x9e92a981, + 0x2a3ed3f1, + 0xb3327088, + 0xd3f14446, + 0xb78c2d2e, + 0xd0206a2b, + 0x76bd1128, + 0x1a44d00c, + 0x90d8c000, + 0xc0007684, + 0x0a0890bc, + 0x294ed3f1, + 0xc0007097, + 0x020391f2, + 0x0a10c0e4, + 0xa981d208, + 0xd3f19e92, + 0x70882a3e, + 0x4446b332, + 0x2daed3f2, + 0xc0e40203, + 0xd2080a0c, + 0xb780a182, + 0x0902430c, + 0x0a38c0c8, + 0xa182d208, + 0x430cb720, + 0x4a2bb54d, + 0x430cb720, + 0x52abb54d, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0xa205f839, + 0x430cb720, + 0xb56d76c2, + 0xc0004d2b, + 0xb72091f2, + 0x0982430c, + 0xb72c9e9a, + 0xd0125aab, + 0xfff41992, + 0x0d8a9a52, + 0x90c0c000, + 0xc00076c4, + 0x0d8690a4, + 0x98a2fff4, + 0x4314b760, + 0x0de0c0d6, + 0x9a9dffb4, + 0x430cb700, + 0x6f2cb706, + 0xaa1df9f8, + 0xa60d9c22, + 0x4314b740, + 0x09760687, + 0x0d48c0c8, + 0xaa41d010, + 0x7104d010, + 0xa241d010, + 0x430cb720, + 0xd0110a02, + 0xb5860932, + 0xd01158ad, + 0xb7200e32, + 0x6129430c, + 0x77adb546, + 0x430cb720, + 0x6a2db786, + 0x5d2db586, + 0x430cb720, + 0x5b2bb56c, + 0x430cb720, + 0x65adb786, + 0xc0007500, + 0xb78690e2, + 0xb7466dad, + 0x124450ad, + 0x59adb586, + 0x430cb720, + 0x76adb786, + 0x512db746, + 0xd1240128, + 0xb543597f, + 0xb7205d2f, + 0xb786430c, + 0xc20065ad, + 0x749c5908, + 0x90f2c000, + 0xc0ca0103, + 0xc000094c, + 0x02489260, + 0xc000751c, + 0x01039112, + 0x094cc0ca, + 0xc0000a0e, + 0xc00491a0, + 0x01037498, + 0x094cc0ca, + 0x90b2c000, + 0xc0000a0a, + 0x0a069060, + 0xa241d008, + 0x430cb720, + 0x4f35b766, + 0xc0ca0203, + 0xd2080a4c, + 0xc101a902, + 0xb7661207, + 0xd13159ad, + 0xc1806629, + 0x70885910, + 0x91f6c000, + 0xc0ca0203, + 0xd2080a50, + 0x7500aa01, + 0x90e4c000, + 0x792bb78c, + 0xc0000a04, + 0xd0319280, + 0xc1806526, + 0x71045a0c, + 0x931cc000, + 0xc0ca0203, + 0xd2080a50, + 0x7500aa01, + 0x9204c000, + 0x792bb78c, + 0xb58c1a04, + 0xb780792b, + 0x0906430c, + 0x0a50c0ca, + 0xa101d208, + 0x9100c000, + 0xc0ca0103, + 0x0a020950, + 0xa241d008, + 0x430cb720, + 0x792bb78c, + 0x4002ba24, + 0x752ac004, + 0x90dac000, + 0x0a5ac002, + 0x9100c000, + 0x7502c008, + 0x90dcc000, + 0x0a06c004, + 0x792bb58c, + 0x430cb720, + 0xb78c0902, + 0xb546792b, + 0xb74676ad, + 0xb7204e2d, + 0xba244314, + 0xb7264002, + 0x624577ad, + 0x40cbb74e, + 0x74826243, + 0x0a00c002, + 0x5999c200, + 0x9184c000, + 0x76cdb746, + 0x59cdb786, + 0xd2187480, + 0x12285a07, + 0x93e0c000, + 0x59d5b746, + 0x4f4db786, + 0x5d10d122, + 0x70881209, + 0x90b8c000, + 0xc0007680, + 0xd010921c, + 0xb7460624, + 0xc10176cd, + 0xc2000244, + 0x11285a13, + 0xb5460126, + 0xc00076cd, + 0xb78690e0, + 0x024676cd, + 0x76cdb586, + 0x430cb720, + 0x7735b5a6, + 0x430cb720, + 0x65adb786, + 0xc000751c, + 0x0a0490b2, + 0x65adb586, + 0x430cb720, + 0x65adb786, + 0xc0007502, + 0x02039224, + 0x0a38c0c8, + 0xaa01d208, + 0x6aabb58c, + 0x430cb720, + 0x6aabb78c, + 0x512bb58d, + 0x9380c007, + 0x50abb78d, + 0xc0007500, + 0xb78e9184, + 0x750040ab, + 0x9142c000, + 0x532bb78d, + 0xc0007504, + 0x0a0690b4, + 0x9060c000, + 0xb58d0a02, + 0xb7204f2b, + 0x0b02430c, + 0x662db746, + 0x4a2bb76d, + 0xc0c80203, + 0x11b40a4c, + 0xa902d208, + 0x5fadb726, + 0x5987d1a4, + 0xc1010524, + 0x55eb05b2, + 0x9825ff54, + 0x430cb720, + 0x5fadb5c6, + 0x430cb720, + 0x5db5b746, + 0x65adb786, + 0x1944d011, + 0x6125c101, + 0xc2001a04, + 0x02445a05, + 0xb5860240, + 0xb7a05dad, + 0x020b430c, + 0x0a4cc0c8, + 0xaa01d208, + 0xb766008b, + 0xb7665db5, + 0x9ea265ad, + 0x55eb1984, + 0x9bffff34, + 0xb5069ea9, + 0xb7005dcd, + 0xb74d430c, + 0x748050aa, + 0x9342c000, + 0x51aab78d, + 0xc0007500, + 0xb76d90e2, + 0x74c0532a, + 0x90c4c000, + 0x4aaab70d, + 0x92e0c000, + 0x5985d1a4, + 0xc1019eb2, + 0xff3405b8, + 0x18049be0, + 0x91a0c000, + 0x4a2ab76d, + 0x422ab78e, + 0xd1a49e92, + 0xc1015985, + 0xff3405b8, + 0xb7209bd2, + 0xb766430c, + 0x74c465ad, + 0x93d4c000, + 0x512bb74d, + 0x0a04d011, + 0xc0007088, + 0xb74c913a, + 0xd0116f33, + 0x72991a24, + 0x90b6c000, + 0xc0001804, + 0xd01191a0, + 0x70881a04, + 0x90f8c000, + 0x0a24d011, + 0xc0007299, + 0x0804907c, + 0x0e52d031, + 0x5a13c200, + 0x0a027502, + 0x0a42d00d, + 0x1108d020, + 0xc0007696, + 0xb74c921c, + 0xd0116f2b, + 0x72991a24, + 0x0d22d00e, + 0x90fcc000, + 0x0a24d011, + 0xd00d7299, + 0x74c41d22, + 0x9334c000, + 0x652bb78c, + 0xc000752c, + 0xb76c9292, + 0xb78d6f2b, + 0xd01152ab, + 0xba241938, + 0x71044002, + 0x9136c000, + 0x6a2bb74c, + 0x1a34d011, + 0xd00d7088, + 0x02031d24, + 0x0a48c0c8, + 0xa901d208, + 0xc8109e54, + 0x02037088, + 0x0a44c0c8, + 0xaa01d208, + 0x7104d012, + 0x6a2bb58c, + 0x430cb720, + 0x6a2bb78c, + 0x6aabb58c, + 0x430cb720, + 0x6aabb78c, + 0x512bb58d, + 0x430cb720, + 0x6a2bb78c, + 0x4aabb58d, + 0x430cb720, + 0xb78c0902, + 0xb58d6aab, + 0xb72052ab, + 0xb546430c, + 0xb720662d, + 0xb78c430c, + 0xc0d25b2b, + 0x0a0408e0, + 0x4029b580, + 0x430cb720, + 0x6aabb78c, + 0x59abb58d, + 0x430cb720, + 0x6aabb78c, + 0x592bb58d, + 0x430cb720, + 0x40abb54e, + 0x430cb720, + 0x502bb54d, + 0x430cb720, + 0x402bb54e, + 0x430cb720, + 0x50abb54d, + 0x430cb720, + 0x422bb54e, + 0x430cb720, + 0x4a2bb54d, + 0x430cb720, + 0x51abb54d, + 0x430cb720, + 0x532bb54d, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0x9c228c60, + 0xb720a605, + 0xb566430c, + 0xb72064b5, + 0xb786430c, + 0x750264ad, + 0x9004c006, + 0xb5460902, + 0xb7206fad, + 0xb786430c, + 0xc00477ad, + 0xc0037510, + 0xb7669092, + 0xb76659b5, + 0x9e9258ad, + 0xff3405b6, + 0x0a229af0, + 0x7008c010, + 0xcc121a40, + 0xb7207008, + 0xb78d430c, + 0x75004a2b, + 0x92e2c000, + 0x58adb786, + 0x6badb586, + 0x430cb720, + 0x4e35b746, + 0x6badb746, + 0x02246d7e, + 0x0a080244, + 0xc1015d17, + 0xc2000244, + 0xb5865a0b, + 0xb7206bad, + 0xb746430c, + 0xb74658ad, + 0x02246bb5, + 0xc2000244, + 0x9e525a0b, + 0x7104d012, + 0x6badb586, + 0x430cb720, + 0x50abb78d, + 0xc0007500, + 0xb78e91c2, + 0x750040ab, + 0x9124c000, + 0x6badb786, + 0xc2006a26, + 0xb5865a0f, + 0xb7206bad, + 0xb746430c, + 0x62356bad, + 0x5a17c200, + 0xb5461128, + 0xb7206bad, + 0xb786430c, + 0xb7466bad, + 0xd0107b2d, + 0xb5867104, + 0xc0006bad, + 0xb7469280, + 0xb78650ad, + 0x12446dad, + 0x59adb586, + 0x430cb720, + 0x59adb786, + 0x4e2db746, + 0x5a17c200, + 0xb5461128, + 0xb7206bad, + 0xb78c430c, + 0x75005b2b, + 0x9342c001, + 0x78adb786, + 0xc0007500, + 0xb7669302, + 0x74c0792d, + 0x9262c000, + 0x0d029ea3, + 0x9a6fff34, + 0x9e857420, + 0x90b4c000, + 0xc0000ec2, + 0x74029120, + 0x90d2c000, + 0xc0000e8a, + 0x0e969060, + 0x430cb7a0, + 0x008b0d02, + 0x6bb5b766, + 0x5b2bb76c, + 0xd11065d7, + 0xff3405d7, + 0x008b9a54, + 0x6badb506, + 0x430cb7a0, + 0x0d029e6b, + 0xb766008b, + 0xff346bb5, + 0x008b9a48, + 0x6c2db506, + 0x430cb720, + 0xb5860a02, + 0xb72070ad, + 0xb586430c, + 0xb720712d, + 0xb586430c, + 0xb7206fad, + 0xb586430c, + 0xb720712d, + 0xb586430c, + 0xb72070ad, + 0xb586430c, + 0xb79f7e2d, + 0xb7bf7f6e, + 0x8c407fee, + 0xa6059c22, + 0xaa61d810, + 0x430cb720, + 0xb58d0687, + 0xb7204dab, + 0xb786430c, + 0xb74676ad, + 0x12447e2d, + 0x76adb586, + 0x430cb720, + 0xb7469e8b, + 0xc0e24e35, + 0xd0100d84, + 0x74c0a9e1, + 0x9284c000, + 0x67adb784, + 0x50adb746, + 0x6629d131, + 0xb3327104, + 0xc0004458, + 0x0a069138, + 0xa261d010, + 0x430cb720, + 0x4e35b746, + 0x430cb720, + 0x6dadb746, + 0x7e2db786, + 0xc1010244, + 0xb5861244, + 0xb7206dad, + 0xb746430c, + 0xb78659b5, + 0xb7467e2d, + 0xc1014e2d, + 0x12440244, + 0x59adb586, + 0x430cb720, + 0x59adb786, + 0x7500de01, + 0x90d6c000, + 0x0a02cf01, + 0x59adb586, + 0x430cb720, + 0x0d02091e, + 0x7e2db786, + 0x4e35b726, + 0x5d2fb763, + 0x1419d110, + 0x587fd024, + 0x01b0e000, + 0xd00305b0, + 0xb5630db2, + 0xb7a05d2f, + 0x008b430c, + 0x5d2fb763, + 0x9845c174, + 0x5e74d022, + 0x590d0101, + 0xd1243144, + 0x008b597f, + 0x5dafb543, + 0x430cb720, + 0x64adb786, + 0xc0027504, + 0xb7869124, + 0xc00477ad, + 0xc0017510, + 0xb74693b2, + 0x768076b5, + 0x909cc001, + 0x772db786, + 0xc0c80103, + 0xd008094c, + 0xc200a941, + 0xc1015a05, + 0xc2000244, + 0xb5865209, + 0xb7a058ad, + 0x020b430c, + 0xc0c8008b, + 0xb7660a4c, + 0xb76658b5, + 0xd208772d, + 0xff34a902, + 0x008b997e, + 0x58adb506, + 0x9100c000, + 0x4e2db786, + 0x5a0bc200, + 0x58adb586, + 0x430cb720, + 0x4e2db786, + 0x58adb746, + 0x5a0bc200, + 0x7088c812, + 0x58adb546, + 0x9300c001, + 0x4e2db786, + 0x58adb586, + 0x9240c001, + 0xb58d0a02, + 0xb7204eab, + 0xb746430c, + 0x768264b5, + 0x9024c001, + 0x772db786, + 0xb5861a04, + 0xb720772d, + 0xb74c430c, + 0xb7865aab, + 0x7104772d, + 0x9094c000, + 0x7735b546, + 0x430cb720, + 0x4a2bb78d, + 0xb58d0a04, + 0xb7204a2b, + 0xb786430c, + 0xb5867e2d, + 0xc00078ad, + 0x76809120, + 0x90c4c000, + 0x7e2db786, + 0x792db586, + 0x430cb720, + 0x6dadb746, + 0xc0007480, + 0xb7869196, + 0x024476ad, + 0x76adb586, + 0x430cb720, + 0xb5860a02, + 0xb7206dad, + 0xb78c430c, + 0x7500632b, + 0x9184c001, + 0x6dadb746, + 0x4fadb786, + 0xc0017088, + 0x0203905c, + 0x0a48c0c8, + 0x4aabb74d, + 0xaa01d208, + 0xc0007088, + 0x0a069306, + 0xa221da10, + 0x430cb720, + 0x772db786, + 0xc0007500, + 0x02039222, + 0x0a48c0c8, + 0x422bb74e, + 0xaa01d208, + 0xb58e0244, + 0xc000422b, + 0x0a0290a0, + 0xa221da10, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0x430cb720, + 0x64adb786, + 0xc0087502, + 0xb78d9284, + 0x75004a2b, + 0x90e2c000, + 0x4eb3b76d, + 0xc00076c0, + 0xb7869102, + 0xb5866fad, + 0xc0015c2d, + 0xb74691c0, + 0xb7664c35, + 0xd0106fad, + 0xd0110624, + 0xc101693b, + 0x70880244, + 0x9154c000, + 0x5c2db786, + 0x5908c180, + 0x70886a16, + 0x9132c000, + 0x6e27d3f1, + 0x5a21c200, + 0xc00070c8, + 0x0a069214, + 0x402bb58e, + 0x430cb720, + 0x5b2bb78c, + 0x08e0c0d2, + 0xb5800a0c, + 0xc0004029, + 0xb56e9080, + 0xb7204033, + 0xb786430c, + 0xc00477ad, + 0xc0047510, + 0xb78693b2, + 0x750265ad, + 0x9364c000, + 0x4a2bb74d, + 0xc0007480, + 0xb54d92c4, + 0xb7204fab, + 0xb786430c, + 0xb5867e2d, + 0xb7205a2d, + 0xb786430c, + 0xb5866fad, + 0xb720582d, + 0xb54d430c, + 0xc003502b, + 0xb76d93e0, + 0xb746502b, + 0x74c06fb5, + 0x93e2c000, + 0x582db746, + 0x0624d010, + 0x0244c101, + 0xc2000244, + 0xb5865a09, + 0xb720582d, + 0xb786430c, + 0xb5867e2d, + 0xb7205a2d, + 0x0a02430c, + 0x502bb58d, + 0x430cb720, + 0xb58d0a04, + 0xc0024fab, + 0xb7869360, + 0xd0314c2d, + 0x6a266d25, + 0xc0017088, + 0xb78691f4, + 0xb7465a2d, + 0x01487e35, + 0x05240128, + 0xc0017295, + 0x0d0690bc, + 0x5033b54d, + 0x430cb720, + 0x50b3b54d, + 0x430cb720, + 0x51abb56d, + 0x430cb720, + 0x532bb56d, + 0x430cb720, + 0x5aabb78c, + 0x4a2bb74d, + 0xc2006a14, + 0x70885a0f, + 0x90dac000, + 0x40abb56e, + 0x9140c001, + 0x40b3b54e, + 0x90c0c001, + 0xb58d0a02, + 0xb720502b, + 0xb78e430c, + 0x7500402b, + 0x9384c000, + 0x582db746, + 0x6fb5b746, + 0x02440224, + 0x0244c101, + 0x5a09c200, + 0x582db586, + 0x430cb720, + 0x5a2db746, + 0x7e35b746, + 0x02440224, + 0x0244c101, + 0x5a0bc200, + 0x5a2db586, + 0x430cb720, + 0x6fadb786, + 0x5c2db586, + 0x430cb720, + 0x50abb78d, + 0xc0007500, + 0xb78d9382, + 0x7500502b, + 0x91e2c000, + 0x40abb78e, + 0xc0007500, + 0xb78c9144, + 0x01035b2b, + 0x0960c0d2, + 0xc0000a0c, + 0xb78c9100, + 0x01035b2b, + 0x0960c0d2, + 0xd0080a08, + 0xb720a241, + 0xb78d430c, + 0x75004a2b, + 0x48a4b340, + 0x70adb786, + 0x5eadb586, + 0x75049c22, + 0x48a4b340, + 0x7e2db766, + 0x5a4be180, + 0x90ccc000, + 0x0d82c002, + 0x9100c000, + 0x7100d002, + 0x9ea30a04, + 0x4001ba1b, + 0x6aabb78c, + 0xba24097e, + 0xd0104002, + 0x0c867104, + 0xd0129e48, + 0xba247100, + 0x9e584002, + 0x5a18c200, + 0x65b5b746, + 0xba245163, + 0x62454002, + 0xc1010936, + 0x76841126, + 0x518bc200, + 0x9054c006, + 0xb58d0a02, + 0xb7204eab, + 0xb78d430c, + 0x75004f2b, + 0x92c4c005, + 0x592db746, + 0x590cd1a4, + 0x6a2bd031, + 0xc0007299, + 0xd01190f6, + 0x72996a2b, + 0x911ac005, + 0x4eb3b52d, + 0x430cb720, + 0x592db746, + 0x022470c4, + 0x921cc002, + 0xc00070c8, + 0x023690d6, + 0xc0017104, + 0xb78c90ba, + 0x0a18792b, + 0x792bb58c, + 0x430cb720, + 0x77b5b746, + 0x4e2db786, + 0x76adb746, + 0x6245c101, + 0xc2000a20, + 0x01285a11, + 0x76adb546, + 0x430cb780, + 0xc0d2091a, + 0xd2080a60, + 0xb780a101, + 0x190c430c, + 0x0a48c0ca, + 0x9240c003, + 0x792bb78c, + 0xb58c0a08, + 0xb720792b, + 0xb746430c, + 0xb78677b5, + 0xb7464e2d, + 0xc10176ad, + 0x0a406245, + 0x5a15c200, + 0xb5460128, + 0xb78076ad, + 0x090e430c, + 0x0a60c0d2, + 0xa101d208, + 0x430cb780, + 0x0a48c0ca, + 0xa082d208, + 0x9200c002, + 0xc00070c8, + 0x023690d6, + 0xc0017104, + 0xb78c90ba, + 0x1a08792b, + 0x792bb58c, + 0x430cb720, + 0x77b5b746, + 0x4e2db786, + 0x76adb746, + 0x6245c101, + 0xc2000a40, + 0x11285a15, + 0x76adb546, + 0x430cb780, + 0xc0d2091a, + 0xd2080a60, + 0xb780a101, + 0x1920430c, + 0x0a48c0ca, + 0x9080c001, + 0x792bb78c, + 0xb58c1a04, + 0xb720792b, + 0xb746430c, + 0xb78677b5, + 0xb7464e2d, + 0xc10176ad, + 0xc0026245, + 0xc2000a00, + 0x11285a19, + 0x76adb546, + 0x430cb780, + 0xc0d2090e, + 0xd2080a60, + 0xb780a101, + 0x1910430c, + 0x0a48c0ca, + 0xa101d208, + 0x430cb720, + 0x592db566, + 0x430cb720, + 0x4eabb78d, + 0x50abb58d, + 0xa60d9c22, + 0x430cb720, + 0xb7460307, + 0x768464b5, + 0x90c4c000, + 0x6ab3b74c, + 0x9020c00a, + 0xc0077682, + 0xb78d9364, + 0x75004a2b, + 0x9224c000, + 0x4eabb78d, + 0xc0007500, + 0xb78c9184, + 0xb74e6aab, + 0x9ea2422b, + 0xb58e0244, + 0xc009422b, + 0xb78d9140, + 0x75004eab, + 0x90c2c001, + 0x01030203, + 0x0a48c0ca, + 0xaa01d208, + 0x0938c0c8, + 0xa942d008, + 0x4000ba24, + 0xc1010910, + 0xd0080244, + 0xd010a941, + 0x01037104, + 0x0944c0c8, + 0xa941d008, + 0x7104c812, + 0x4dabb78d, + 0x4233b74e, + 0xd0027500, + 0x75000922, + 0x9000c001, + 0x502bb78d, + 0xc0017500, + 0x020392c2, + 0x0a38c0c8, + 0xaa01d208, + 0xc0c80103, + 0xd0080948, + 0x0a04a941, + 0x7104d010, + 0xc0c80103, + 0xd0080944, + 0xc812a941, + 0xb78d7104, + 0xb74e4dab, + 0x75004233, + 0x0a28d002, + 0x4422b324, + 0x2a7ccffe, + 0x0244c101, + 0x422bb58e, + 0x430cb720, + 0xb78d9e92, + 0x022851ab, + 0x51abb58d, + 0x430cb720, + 0x532bb78d, + 0xb58d0a04, + 0xc006532b, + 0xb7869100, + 0xb5865f2d, + 0xb7a05e2d, + 0x9e694314, + 0x6badb746, + 0xc0007480, + 0xb78e9316, + 0x750040ab, + 0x09e2d002, + 0x9104c000, + 0xc0d29e6c, + 0xd2080a60, + 0x01e8aa01, + 0xc0c89e6c, + 0xd2080a48, + 0xcc10aa01, + 0xc00170c8, + 0x9e6990e0, + 0x5e2db766, + 0x4e2db786, + 0x6a35b746, + 0xc20011a6, + 0xcc125a0b, + 0x9e6c70c8, + 0xc0c89e6a, + 0xd2080a4c, + 0xc0d2aa01, + 0xd0080960, + 0x0a14aac1, + 0x554c9ea3, + 0x5987d1a4, + 0xc15405b4, + 0x581998d6, + 0xc010026a, + 0x12ea7008, + 0x700acc12, + 0xb78d9e69, + 0x9e694dab, + 0xb74e7500, + 0xd002422b, + 0x750009b2, + 0x0a38d002, + 0x4422b334, + 0xcffe9e69, + 0x02442a7c, + 0x422bb58e, + 0x430cb720, + 0x50abb78d, + 0xc0007500, + 0xb78d91c2, + 0x023851ab, + 0x51abb58d, + 0x430cb720, + 0x532bb78d, + 0xb58d0a04, + 0xb720532b, + 0x0203430c, + 0x0a48c0c8, + 0xaa01d208, + 0x70c8d010, + 0xc0c80103, + 0xd0080944, + 0xd012a941, + 0x9ea27104, + 0x6f2bb58c, + 0x90a0c002, + 0xc0007680, + 0x000790a2, + 0x93c0c001, + 0x6c2db766, + 0x5aadb746, + 0x4e2db786, + 0xc20011b4, + 0xcc125a0b, + 0x020370c8, + 0x0a4cc0c8, + 0xaa01d208, + 0x6aadb746, + 0x5a05c200, + 0x515051f3, + 0x5987d1a4, + 0xc1015914, + 0xff1405b4, + 0xb72099a8, + 0x5819430c, + 0xb74d0810, + 0xb78d59ab, + 0x0244592b, + 0x5a07c200, + 0x094ed011, + 0x7004c010, + 0xc0120a04, + 0x02037008, + 0x0a48c0c8, + 0xaa01d208, + 0x7008c010, + 0x08c4c0c8, + 0x4029b780, + 0x7008c012, + 0x9e509e82, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0x9c228c60, + 0xb720a605, + 0x0687430c, + 0x64adb786, + 0xc00a7502, + 0xb7469144, + 0xb76d712d, + 0xe1004a33, + 0xc0005a4b, + 0xc00290cc, + 0xc0000982, + 0xd0029100, + 0x0a047100, + 0xba1b0189, + 0x9e6c4000, + 0x514fd024, + 0x4002ba24, + 0xd010097e, + 0x19787104, + 0x7104d012, + 0xc0c80103, + 0xba24094c, + 0xd0084002, + 0xc200a941, + 0xba245a18, + 0xc1014002, + 0x09146245, + 0x76c01126, + 0x510bd224, + 0x90e2c000, + 0x4eabb78d, + 0xc0007500, + 0xb78693c2, + 0xc1015fad, + 0xb5860244, + 0xb7205fad, + 0xb546430c, + 0xb7206a35, + 0xb546430c, + 0xb7206ab5, + 0xb786430c, + 0xb58670ad, + 0xb7205ead, + 0xb786430c, + 0xb5865ead, + 0xc0065f2d, + 0xb78d9260, + 0x7500502b, + 0x9124c006, + 0x402bb78e, + 0xc0067500, + 0xb7869084, + 0xc1015fad, + 0xb5860244, + 0xb7205fad, + 0xb78d430c, + 0xb7664fab, + 0x750070ad, + 0x90c2c000, + 0x5eadb566, + 0x9180c000, + 0x5eadb746, + 0x02460236, + 0x02446916, + 0x5a0dc200, + 0x5eadb586, + 0x430cb720, + 0x5eadb786, + 0x5f2db586, + 0x430cb720, + 0x4fabb78d, + 0xc0007500, + 0xb54690c2, + 0xc0016a35, + 0xb78d91e0, + 0xb74650ab, + 0x75006a2d, + 0x9182c001, + 0x532bb78d, + 0x62451a04, + 0x0629d110, + 0x6a2db586, + 0x430cb720, + 0x532bb78d, + 0x6a2db746, + 0x5a05c200, + 0xb5460128, + 0xb7a06a2d, + 0x020b430c, + 0x0a4cc0c8, + 0xaa01d208, + 0xb766008b, + 0x9ea26a35, + 0x532bb76d, + 0xff1455eb, + 0x9ea998c2, + 0x6a4db506, + 0x430cb720, + 0x9100c001, + 0x662db786, + 0x4a2bb76d, + 0xd01111b8, + 0x62451a32, + 0x0629d110, + 0x5907c180, + 0x6a2db586, + 0x430cb720, + 0x6a2db786, + 0xb5860244, + 0xb7a06a2d, + 0x008b430c, + 0x6a35b766, + 0x9b6cc134, + 0xb5069ea9, + 0xb7206a4d, + 0xb786430c, + 0x750265ad, + 0x90c4c000, + 0x6a2db786, + 0x9280c000, + 0x4a33b74d, + 0x5aabb74c, + 0x6a35b766, + 0x0624d010, + 0x71041904, + 0x5d2db766, + 0x9156c000, + 0x0236c101, + 0x5a07c200, + 0x6aadb586, + 0x9140c001, + 0x1224c101, + 0x6526d031, + 0x02446247, + 0x6aadb586, + 0x430cb720, + 0x5aabb78c, + 0x6aadb746, + 0xc2001a04, + 0x01285a07, + 0x6aadb546, + 0x430cb7a0, + 0xb76c008b, + 0xb7665aab, + 0x19846ab5, + 0x9b2ac134, + 0xb5069ea9, + 0xc0006acd, + 0xb78690e0, + 0x0a04662d, + 0x662db586, + 0x430cb720, + 0x6ab5b746, + 0x5dadb746, + 0x6b35b546, + 0x430cb720, + 0x65adb786, + 0xc0007502, + 0x022491d4, + 0xb7460244, + 0xc1016aad, + 0xc2000244, + 0xc8105a0b, + 0xb5467088, + 0xb7206aad, + 0xb78d430c, + 0xb58d592b, + 0xb72059ab, + 0xb5ad430c, + 0xb7205933, + 0xb786430c, + 0x750064ad, + 0x90c4c000, + 0x70adb786, + 0x5aadb586, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0x430cb720, + 0x6435b746, + 0x4e2db746, + 0x5aabb78c, + 0x4e35b546, + 0x4314b720, + 0x4a2bb72d, + 0x1524c101, + 0xb7461a04, + 0x124276cd, + 0x6245c101, + 0xb5460128, + 0xb78076cd, + 0x0902430c, + 0x0a70c0d0, + 0xa101d208, + 0xa6059c22, + 0x430cb720, + 0xb5660287, + 0xd8087e35, + 0x7500aa61, + 0x9144c000, + 0x430cb720, + 0x6f35b766, + 0x9a6efff4, + 0x9b04ffd4, + 0x430cb780, + 0x0a70c0d0, + 0xaa01d208, + 0xc0007502, + 0xfff49084, + 0x9eab9bc3, + 0x7f6eb79f, + 0x7feeb7bf, + 0xffcd8c40, + 0x01079240, + 0xa9e1f010, + 0x70c0d014, + 0x753ec03f, + 0x90dcc000, + 0x4226e000, + 0x48acb340, + 0xf0100226, + 0x9c22a261, + 0xb7c0a60d, + 0x008d430c, + 0x5b33b7ae, + 0x1dd2d012, + 0x9948ff34, + 0x028c5808, + 0xd0129ea9, + 0xb7a61dd4, + 0xff347ecd, + 0x5808993f, + 0xb726008c, + 0x9eb17ead, + 0xc2000252, + 0xb7665a05, + 0x9ea25ad5, + 0x72c4cc12, + 0x4e4db766, + 0x0d025d9c, + 0x9b9ffef4, + 0xc0dc020d, + 0xd2080a50, + 0xc006a901, + 0x11c00a7a, + 0xc0007480, + 0x9e9390a4, + 0x90e0c000, + 0xb786008d, + 0xd0207a2d, + 0x9eb111b8, + 0xb7460a02, + 0x592779cd, + 0x7088c810, + 0xc0dc020d, + 0xd2080a60, + 0xc180aa01, + 0x9eb25a8f, + 0xd01102d8, + 0x9eb36e3f, + 0x0d50c0dc, + 0x02d40e86, + 0x5a23c200, + 0xa2c2d010, + 0x7a4db566, + 0x0db0c0dc, + 0xfff402d8, + 0xc0089b96, + 0xd4100a02, + 0x9e6c7148, + 0x7148d412, + 0x2afcc00e, + 0xb79f000b, + 0xb7bf7eee, + 0xb7df7f6e, + 0x8c607fee, + 0xa60d9c22, + 0x430cb7a0, + 0xb786008b, + 0xb741562d, + 0x75045e2d, + 0x92a4c005, + 0xc0007488, + 0xb78190e4, + 0x75045ead, + 0x9322c005, + 0xb746008b, + 0xb7464fad, + 0xb7616bb5, + 0xd1205e2d, + 0xc02111a5, + 0xc00076c0, + 0x74c29354, + 0x93e4c009, + 0x4e2db786, + 0x70886a1e, + 0x9336c009, + 0x5e15d1a2, + 0x6ac5d072, + 0x9060c001, + 0xc00074c2, + 0xd1a293e2, + 0xd0325e15, + 0xc0006acd, + 0x74c29340, + 0x9184c009, + 0xb786008b, + 0x6a1e4e2d, + 0xc0097088, + 0xd07190b6, + 0xc0006e35, + 0x74c290e0, + 0x9102c000, + 0x6e3dd031, + 0x5a97d224, + 0x9060c000, + 0x008b0e82, + 0x5ab3b7cc, + 0xc0027782, + 0xff3491c4, + 0x008b9a72, + 0x4e35b7a6, + 0xc0109e6b, + 0xc1017006, + 0xd812120b, + 0xb7867008, + 0x750075ad, + 0x92e4c001, + 0x98acff34, + 0xc0007400, + 0x008b91a2, + 0x5babb78e, + 0x67adb744, + 0x0a027088, + 0x0a42d004, + 0x92c0c000, + 0xb781008b, + 0x75025e2d, + 0x90a2c000, + 0xc0007508, + 0x008b9224, + 0x67adb784, + 0x50adb746, + 0x6659d131, + 0x0a027104, + 0x0a42d00b, + 0x75adb586, + 0x90a0c000, + 0xb5c6008b, + 0x008b75b5, + 0x75adb786, + 0xc0007500, + 0xc81290c4, + 0xc000710c, + 0x010d9060, + 0xb786008b, + 0xd0204e2d, + 0x008b12c4, + 0x5e2db781, + 0xc0007502, + 0xff349264, + 0x7400986b, + 0x91c4c000, + 0xb786008b, + 0xb74650ad, + 0xc2006bad, + 0x70885a08, + 0x909cc000, + 0x73b5b7a6, + 0xd4120d06, + 0xc0047344, + 0x748291e0, + 0x92c2c001, + 0xc0047488, + 0x008b9024, + 0x5eadb781, + 0xc0007500, + 0xb7a690c2, + 0xc0034e35, + 0x008b93e0, + 0x65abb78c, + 0x75009ead, + 0xd0010a02, + 0xb5800a42, + 0xb78c448c, + 0xc0dc71ab, + 0x75000ee0, + 0x90c2c000, + 0xa922d210, + 0x90e0c000, + 0x9ab0fff4, + 0xd2109e82, + 0x008ba021, + 0x4e2db786, + 0xd131092a, + 0xc2006629, + 0xcc125a1f, + 0x9e9d7104, + 0x9300c002, + 0xb78c008b, + 0xc2006dab, + 0x00ca5a08, + 0x5cb5b7a6, + 0x9816ff34, + 0x0b00f011, + 0x90e4c001, + 0xb786008b, + 0x750075ad, + 0x9244c000, + 0x67adb784, + 0x4e2db746, + 0x50b5b746, + 0x61450802, + 0xd00b7095, + 0x74000802, + 0x75adb506, + 0x9122c000, + 0x99afff34, + 0xc0121001, + 0xc000700c, + 0x008b9100, + 0x6badb786, + 0xc0121228, + 0xc1017100, + 0x008b06d0, + 0x5e2db781, + 0xc0007502, + 0xff1493e4, + 0x74009be5, + 0x9344c000, + 0xb78d008b, + 0xc00464ab, + 0xc0007510, + 0xb7869274, + 0xc2004e2d, + 0x9ea25a0f, + 0x7344d412, + 0x9140c000, + 0xb78c008b, + 0xc2006dab, + 0x00ca5a08, + 0x5cb5b7a6, + 0x430cb720, + 0x5e2db781, + 0xc0007508, + 0x750290a2, + 0x92e4c000, + 0xb787008b, + 0x75004e2d, + 0x9222c000, + 0xd4109ea2, + 0xc0007344, + 0x72959180, + 0x9238fff6, + 0x9180fff6, + 0xfff77295, + 0xfff69078, + 0x9e6893c0, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0x9c228c60, + 0xb7a0a60d, + 0x9e5e430c, + 0xb781008b, + 0x75025e2d, + 0x91a6c004, + 0xc0007504, + 0x750890f4, + 0x90e4c004, + 0x93a0c001, + 0x76c2008b, + 0x5635b566, + 0x6db3b7ac, + 0x9084c000, + 0x9ad5ff34, + 0x9a71fff4, + 0xb506008b, + 0x01815dad, + 0xff34058b, + 0x9e8299a7, + 0x0902008b, + 0x9100c000, + 0x7c2bb78c, + 0x4002ba24, + 0x0528c101, + 0x0888709b, + 0xffff0904, + 0xb74092fc, + 0x9e53430c, + 0xc0c80205, + 0xd2080a48, + 0xd010aa01, + 0xc0c870c8, + 0xd0080944, + 0xc412a941, + 0x9e8d7104, + 0xb5ac008b, + 0xff347c33, + 0xc00298d4, + 0x008b9140, + 0xb56676c2, + 0xb7ac5635, + 0xc0006db3, + 0xff349084, + 0xfff49a9a, + 0x008b9a36, + 0x5dadb506, + 0x058b0181, + 0x996cff34, + 0x008b9e82, + 0xc0000902, + 0xb78c9100, + 0xba247c2b, + 0xc1014002, + 0x709b0528, + 0x09040888, + 0x92fcffff, + 0x430cb740, + 0x02059e53, + 0x0a48c0c8, + 0xaa01d208, + 0x70c8d010, + 0x0944c0c8, + 0xa941d008, + 0x7104c412, + 0x008b9e8d, + 0x7c33b5ac, + 0x9899ff34, + 0xc0007584, + 0xb72091c4, + 0xb781430c, + 0x75045ead, + 0x90e2c000, + 0xc0c80203, + 0xd2080a38, + 0x9e68aa82, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0x9c228c60, + 0x8440a61d, + 0x4314b7a0, + 0x1236c101, + 0x9e699ea2, + 0xb72c9e6a, + 0xc0de712b, + 0xd0080920, + 0xa095ab42, + 0x55d89e69, + 0x73adb726, + 0xc114a099, + 0x9e6c9bfd, + 0xc0de0301, + 0xd2080a10, + 0x7480a901, + 0x90c2c000, + 0xb7869e69, + 0x11087c2d, + 0xb78d9e69, + 0xb7ac64ab, + 0xc0046e2b, + 0xc0007510, + 0xd3249114, + 0x0b825b93, + 0xc000a391, + 0x9e699180, + 0xb7866916, + 0x590f7bad, + 0x5b87d324, + 0x5b97c200, + 0x9e69a111, + 0xb7467780, + 0x0a22712d, + 0x4824b364, + 0x9ea67482, + 0x9332c003, + 0x632bb78d, + 0xc0037502, + 0xc0019292, + 0xa91593c0, + 0x3154e000, + 0x9324c001, + 0xb7869e69, + 0x750075ad, + 0x9144c002, + 0x9aa8ff14, + 0xc0007400, + 0x9e6991a2, + 0x5babb78e, + 0x67adb744, + 0x0a027088, + 0x0a42d004, + 0x9360c000, + 0xb7819e69, + 0x75025e2d, + 0x90a2c000, + 0xc0007508, + 0x9e699204, + 0x67adb784, + 0x4e2db746, + 0x50b5b746, + 0x71156245, + 0xd00b0a02, + 0xc0000a42, + 0x9e699080, + 0xb5860a06, + 0x9e6975ad, + 0x75adb786, + 0xc0007500, + 0x75409324, + 0x9104c000, + 0xb78d9e69, + 0x7500632b, + 0x9104c000, + 0x0a029e6a, + 0x0910c0de, + 0xa241d008, + 0xaa19a915, + 0x74800802, + 0x4422b340, + 0x90e0c001, + 0x9e699e6c, + 0x0a10c0de, + 0x058b0a86, + 0xa281d208, + 0x7c2db5c6, + 0x0df0c0dc, + 0xfff4018d, + 0xa91298c2, + 0xa9199e71, + 0x0674d010, + 0x52a4c200, + 0x024a024e, + 0xc2006245, + 0xc0005007, + 0x9e699140, + 0x632bb78d, + 0xfffe7500, + 0xfffc9102, + 0xb79f9140, + 0xb7bf7d6e, + 0xb7df7dee, + 0xb7ff7e6e, + 0xc0027eee, + 0x9c228c40, + 0xb7a0a60d, + 0x008b430c, + 0x5e2db781, + 0xc0047502, + 0xff149004, + 0xf0119a27, + 0xc0000880, + 0x9ea99184, + 0x4e55b766, + 0x4fcdb746, + 0x6e3fd011, + 0xc0017088, + 0x008b91d6, + 0x64abb78d, + 0x6cadb7c6, + 0x73b5b7a6, + 0x7510c004, + 0x9332c002, + 0x63b3b76d, + 0x6333b74d, + 0x4e2db786, + 0x592db746, + 0x15b49e5b, + 0xba1b7088, + 0x1d844003, + 0x1248d01a, + 0x1228d019, + 0x61c7d132, + 0x4002ba1b, + 0x5a07c180, + 0x05b8c101, + 0xfef40d02, + 0xc1019834, + 0xc00106d0, + 0x9ea99300, + 0x64cbb78d, + 0x6bcdb7c6, + 0x50d5b7a6, + 0x7510c004, + 0x9012c001, + 0x594db706, + 0x63cbb74d, + 0x6353b74d, + 0x01857017, + 0x1007d119, + 0x11a5d120, + 0x4434b310, + 0x4003ba1b, + 0xba1b1d84, + 0xd1324002, + 0xc1806187, + 0xc1015a07, + 0x0d0205b8, + 0x9809fef4, + 0x06d0c101, + 0xb78c008b, + 0x75006eab, + 0x9122c000, + 0x065ad010, + 0x024ac101, + 0xd224024c, + 0x9eb35a8b, + 0xfff49e6b, + 0x0a029ab1, + 0x7100d012, + 0xb5869ea9, + 0xc0016b4d, + 0x008b90a0, + 0x64abb78d, + 0x63b3b74d, + 0x632bb74d, + 0x7510c004, + 0x6aadb706, + 0x90d4c000, + 0x73adb706, + 0x9220c000, + 0x1625d110, + 0xba1b0189, + 0x74c24002, + 0x913cc000, + 0x5987d1a4, + 0xc1010d02, + 0xfed405b0, + 0x9ea99bce, + 0x6b4db506, + 0x430cb7a0, + 0x008b0902, + 0x632bb78d, + 0x7135b746, + 0x68abb54d, + 0x76820a04, + 0x632bb58d, + 0x5b2bb74c, + 0x9192c005, + 0x2a7ccffe, + 0xc0057502, + 0xb74d90f2, + 0x76806833, + 0x9144c005, + 0xc0017480, + 0xb78693c2, + 0x74826b2d, + 0x5907c200, + 0x5cadb546, + 0x9104c000, + 0x02440224, + 0x5a07c200, + 0x5cadb586, + 0x0e869ea9, + 0x6b55b766, + 0x5ccdb786, + 0x6fcbb76d, + 0x15b8c101, + 0xfed41984, + 0x03019b90, + 0x9200c000, + 0xa9cdd008, + 0x9b89fed4, + 0x0e52d011, + 0x5c88d2a2, + 0x009a9ea5, + 0x5cadb506, + 0x2efccffe, + 0x025ac101, + 0x0109008b, + 0x6fabb78d, + 0x0960c0da, + 0x711b9eb3, + 0xffff0d02, + 0xc00390f2, + 0x9ea99160, + 0xb76d9e92, + 0xb78664cb, + 0x19846acd, + 0x29fccffe, + 0x5985d1a4, + 0x05b8c101, + 0x9b61fed4, + 0xb506008b, + 0xc0025cad, + 0x9ea992e0, + 0x64cbb78d, + 0x7510c004, + 0x9194c000, + 0x4e4db786, + 0xb7460904, + 0x61296c55, + 0x1124c101, + 0x6b4db546, + 0x0902008b, + 0x6b2db786, + 0x7088d812, + 0x5b33b7ac, + 0xc0017740, + 0xb78691c2, + 0x75005b2d, + 0x9262c000, + 0x5badb766, + 0xc00074c0, + 0x9ea391c2, + 0xfed49e92, + 0x0a429b32, + 0x7008c010, + 0xcc121a38, + 0xc0007008, + 0x09969060, + 0x61bcd032, + 0xc1010d02, + 0xfed401ba, + 0x9ea99b22, + 0x11e0d020, + 0xb5069e6b, + 0x0d025ccd, + 0x9b19fed4, + 0xb506008b, + 0xc0005d2d, + 0x9ea991e0, + 0x5ccdb5c6, + 0x9140c000, + 0xb781008b, + 0x75085e2d, + 0x9004fffe, + 0x91a0fffd, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0x9c228c60, + 0xb7a0a605, + 0x008b430c, + 0x752db766, + 0xc00074c0, + 0x008b91c2, + 0x74adb786, + 0x5985d1a4, + 0x05b8c101, + 0x99b5c114, + 0xcffe0181, + 0x008b29fc, + 0x5e2db781, + 0x73abb56c, + 0xc0007504, + 0x75089142, + 0x9302c001, + 0xc0047502, + 0xc00193c4, + 0xff149260, + 0x74009895, + 0xb746008b, + 0xc0007335, + 0xb74690c2, + 0xc0006cad, + 0x008b90a0, + 0x6badb746, + 0xb781008b, + 0x75025e2d, + 0x9124c000, + 0xc0007400, + 0xb78690c4, + 0xc00050ad, + 0x0a029060, + 0x9e521228, + 0x7104d010, + 0x1105c101, + 0x7104d012, + 0x5a07c200, + 0x1629d110, + 0xb586008b, + 0x0a0a6aad, + 0x7b2bb58d, + 0x9160c003, + 0x9864ff14, + 0x008b7400, + 0x7335b746, + 0x9222c000, + 0x6cadb786, + 0xd0109e52, + 0xc1017104, + 0xd0121105, + 0xc2007104, + 0xd1105a07, + 0xc0011429, + 0x008b92e0, + 0x5e2db781, + 0xc0007502, + 0x008b90a4, + 0x50adb706, + 0xb786008b, + 0xb746712d, + 0x75006bad, + 0x90e4c000, + 0x50adb786, + 0xc0001040, + 0x008b93e0, + 0x64abb78d, + 0xc0041020, + 0xc0007510, + 0x740092f2, + 0x5807d018, + 0x9258c000, + 0xb786008b, + 0xc2004fad, + 0x70885a07, + 0x1000d01e, + 0x911cc000, + 0xb786008b, + 0x6209542d, + 0x5833c200, + 0x1421d110, + 0xb781008b, + 0x75025e2d, + 0x90a4c000, + 0xb5871a04, + 0x008b4e2d, + 0x5e2db781, + 0xc0007508, + 0xb7819144, + 0x75045ead, + 0x90a2c000, + 0xb5870a02, + 0x0a024e2d, + 0x7100d012, + 0xb586008b, + 0x008b6aad, + 0x712db786, + 0x09b29eab, + 0xb5860a04, + 0xc0ca712d, + 0xfd540de0, + 0x9eab9af6, + 0xc0cc0992, + 0xfd540d90, + 0x9eab9af0, + 0xc0ce0992, + 0xfd540dc8, + 0x9eab9aea, + 0xc0da09a2, + 0xfd540d90, + 0x0a029ae4, + 0xb58d008b, + 0xb58d68ab, + 0xb58d632b, + 0xb79f682b, + 0xb7bf7f6e, + 0x8c407fee, + 0x9000ffed, + 0xd0149e52, + 0xd00270c0, + 0xf0127100, + 0xc0000942, + 0x9e5290a4, + 0x9120c000, + 0xc1010a7a, + 0xd0101244, + 0x11287104, + 0xf01051f0, + 0xf010a165, + 0x9c22a1e1, + 0xaa65f010, + 0xa961f010, + 0xc4129e50, + 0xd1207100, + 0x12181115, + 0x9e545153, + 0x51f39e8a, + 0xfffe11a6, + 0x0d029320, + 0x91c0ffff, + 0xa966f008, + 0xa9e1f008, + 0x9100ffff, + 0xaa65f010, + 0xa8e1f010, + 0xc4129ea0, + 0xd1107204, + 0x15141619, + 0x9e5450b3, + 0xc81451f3, + 0xc8027040, + 0xd0147080, + 0xd00270c0, + 0x09047100, + 0xc8120a04, + 0x19747088, + 0x9e900d02, + 0x7280c812, + 0x5d070d04, + 0x05249e54, + 0x51f350b3, + 0x052201b2, + 0x9100fffd, + 0xfffe0d02, + 0xf01092e0, + 0xf010aa65, + 0x9ea0a8e1, + 0x7204c412, + 0x1619d110, + 0x50b31514, + 0x51f39e54, + 0x7040c814, + 0x7080c802, + 0x70c0d014, + 0x7100d002, + 0x196c0128, + 0x9e900d02, + 0x7280c812, + 0x5d070d04, + 0x05249e54, + 0x51f350b3, + 0x052261b3, + 0x9000fffc, + 0xa966f008, + 0xa9e1f008, + 0x92e0fffe, + 0xfffe0d02, + 0xa60d9280, + 0xaae5f010, + 0x9e5e0685, + 0xf0107155, + 0xd11ca962, + 0x0107165b, + 0x4458b343, + 0x4838b355, + 0x554fd018, + 0xd0120986, + 0x9ea370c4, + 0x70c4cc12, + 0x05b45d87, + 0x983ac114, + 0xd1209eb3, + 0x0181115b, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0xfffa8c60, + 0xf00891e0, + 0xf008a966, + 0xfffea9e1, + 0x0d029280, + 0x9220fffe, + 0xa966f010, + 0xaa61f010, + 0xc8109e51, + 0x11b47046, + 0x518fc200, + 0x1524c101, + 0x9300fff9, + 0xc002a61d, + 0xd1718420, + 0xb7c06e35, + 0x0246430c, + 0x06b6d010, + 0x5a08c200, + 0x00cca199, + 0xb7e702dc, + 0xc12a502d, + 0xda080ac0, + 0xc180aab1, + 0xc1015e88, + 0x9e6906dc, + 0xc00f0707, + 0xe0b22bfe, + 0x09028d80, + 0x4002ba2d, + 0xb7a6018f, + 0xb55f6835, + 0xb5bf7bec, + 0xfff47b6c, + 0xe0b29b95, + 0x09a28d80, + 0x9bc4fff4, + 0x0e62d011, + 0x8d80f092, + 0x5a0cc200, + 0xa21d01e8, + 0x0980c0d2, + 0x058f0a02, + 0xa2e1f210, + 0x7cecb59f, + 0x9b78fff4, + 0x09a2058f, + 0x9baefff4, + 0xb786008d, + 0xf0515dad, + 0x9e6b8c80, + 0x09029eab, + 0xa221f208, + 0xfff4a115, + 0x008d9b6d, + 0x5a2bb78c, + 0x6d2bb76c, + 0x11c69eab, + 0x9b95fff4, + 0x09a29eab, + 0x9b94fff4, + 0x7b6cb79f, + 0xc0007500, + 0xf21090fc, + 0x7500aa61, + 0x923ac000, + 0x0902aa1d, + 0x7becb55f, + 0xb5ff00cc, + 0xb7867b6c, + 0xb72664ad, + 0xb59f642d, + 0xf2107cec, + 0xb79fa0e1, + 0x75007b6c, + 0x913cc000, + 0x8c80f092, + 0xaa21f210, + 0xc0007500, + 0x008d919a, + 0x4eadb746, + 0xb59f0a06, + 0xb55f7dec, + 0xc0007d6c, + 0x008d9340, + 0x5dadb786, + 0x8c80f071, + 0x8d80e051, + 0xf2089eab, + 0x0a02a221, + 0x7decb59f, + 0x9ac6fff4, + 0xe0b19eab, + 0xfff48d80, + 0x9eab9b17, + 0xfff49e6b, + 0xa9199b44, + 0x6e65d171, + 0x04ecd010, + 0x02480244, + 0xc114024c, + 0x009c0a20, + 0xa991da08, + 0x5f2bb72e, + 0xd02a7046, + 0xd02901b6, + 0xd0090192, + 0xd00a0a32, + 0xd1200a12, + 0x098e01c7, + 0x9b4dc0f4, + 0x8d80e0b2, + 0xfff40181, + 0xe0719af7, + 0xe0b28d80, + 0xfff48d80, + 0xe0b29b1c, + 0xfef48d80, + 0x9e839b0a, + 0x9b29fef4, + 0x7beeb79f, + 0x7c6eb7bf, + 0x7ceeb7df, + 0x7d6eb7ff, + 0x8c20c004, + 0xa6059c22, + 0x430cb720, + 0x0d829e5d, + 0x4aabb76d, + 0x998dffb4, + 0xa021f208, + 0x430cb720, + 0x64adb786, + 0xc0007500, + 0xb50d9082, + 0x0a024aab, + 0xa225f208, + 0xa22df208, + 0xa231f208, + 0xa235f208, + 0xa229f208, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0xb720a605, + 0x76c2430c, + 0xb56d9e5c, + 0xc0004d2b, + 0xb7209292, + 0xb7ac430c, + 0xb76c5b2b, + 0xd0115ab3, + 0xc0f409d2, + 0x9e839afd, + 0x1d84018b, + 0x9ab7ff74, + 0xc0000d8a, + 0x76c69160, + 0x15b6d021, + 0x90c2c000, + 0xc0007504, + 0x0d8690a4, + 0x9910ff94, + 0x4314b760, + 0x0de0c0d6, + 0x9bb1fff4, + 0x430cb700, + 0x6f2cb706, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0x8420a60d, + 0x430cb720, + 0xb5850a06, + 0xb72044ab, + 0xb76a430c, + 0xfdd447b1, + 0xb7209b6d, + 0x0982430c, + 0x46b1b76a, + 0x4731b74a, + 0x5e30d1a2, + 0xc0219e5a, + 0xc1120a00, + 0xc0000a10, + 0x9dcd90e0, + 0xa1e1f000, + 0x0a00c100, + 0x09047095, + 0x9334ffff, + 0x5badb7c3, + 0x8d00e031, + 0x9eb209a2, + 0x9a2dfd74, + 0xb720aa19, + 0x09024314, + 0x2ac6d011, + 0x68d1d131, + 0x46d1b7aa, + 0x0092c101, + 0x602db540, + 0x430cb720, + 0x9e889d29, + 0xb76a9e89, + 0xb70a46b1, + 0xc0184729, + 0xc01c0c30, + 0xc0010cb0, + 0xd1a29020, + 0x9dcb5e30, + 0xc0210189, + 0xc1280980, + 0xe0200980, + 0x9dbdaa09, + 0xa261f000, + 0xa929e020, + 0x0a30d111, + 0xf0009dcd, + 0x0d10a161, + 0x7680c008, + 0xffff0990, + 0xd0119204, + 0x9ea30e32, + 0x2dfcc00e, + 0xffff72d1, + 0xaa1d9014, + 0xc0017d02, + 0xd1319342, + 0xa99a69d1, + 0x5d2db780, + 0x5d890196, + 0x0990c010, + 0x9c629ea4, + 0x025ac101, + 0xc2000a04, + 0x01095a30, + 0x0900c021, + 0xc0260d02, + 0x9dad0970, + 0xa162f000, + 0x0a00c021, + 0x0a60c026, + 0xf0009dcd, + 0xb720a162, + 0x098e430c, + 0x46a9b74a, + 0x4731b74a, + 0x5a30c100, + 0x0a00c021, + 0x0a50c114, + 0x90e0c000, + 0xf0009dcd, + 0xc100a1e1, + 0x70950a00, + 0xffff0904, + 0xb7209334, + 0xd132430c, + 0xd05168d1, + 0xd1100a60, + 0x9eab0493, + 0x5fadb580, + 0x430cb780, + 0x0498c101, + 0xc200aa1d, + 0xb5805a05, + 0xfdd45f4d, + 0x75409802, + 0x90c4c000, + 0x430cb720, + 0x44abb5a5, + 0x430cb720, + 0x47b1b76a, + 0x9b3bfdd4, + 0xfd340d8e, + 0x0d8a9b9d, + 0x9b9afd34, + 0x7e6eb79f, + 0x7eeeb7bf, + 0x7f6eb7df, + 0x8c00c002, + 0xa60d9c22, + 0x430cb720, + 0xc0a40203, + 0xd2080a10, + 0xb7caaa82, + 0x77404729, + 0x92a4c002, + 0xb5a50a86, + 0xb72044ab, + 0xb76a430c, + 0xfdd447b1, + 0x9eab9a89, + 0x99e8fe14, + 0x430cb720, + 0x5dadb781, + 0x75061a08, + 0x4832b353, + 0x92d2c000, + 0x5908d226, + 0xe0508520, + 0x94088044, + 0x940c940a, + 0xc1019401, + 0xc0000982, + 0x09869120, + 0x90c0c000, + 0xc000098e, + 0x098a9060, + 0x7eb1b745, + 0x0a02c020, + 0x5930c300, + 0xb3247680, + 0xc1404822, + 0x32460900, + 0x0900c021, + 0xf0009dad, + 0x0203a261, + 0x0a20c09c, + 0x5badb763, + 0xa902d208, + 0x09069eb3, + 0x98acfdb4, + 0x430cb720, + 0x47b1b76a, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0xfdd68c60, + 0xb79f9180, + 0xb7bf7eee, + 0xb7df7f6e, + 0x8c607fee, + 0xa61d9c22, + 0x8420c016, + 0x6f74b57f, + 0xaa61d050, + 0xa9e6d050, + 0x03091a28, + 0xc00e1d88, + 0xc00e2b7c, + 0xfd742dfc, + 0xd031987d, + 0xd0116869, + 0xd2240a62, + 0x02015b30, + 0x0a20c014, + 0x5808d324, + 0x0a00c021, + 0x6aecb59f, + 0x568cb780, + 0x6e6cb51f, + 0x9e400101, + 0x020801ec, + 0x57ecb59f, + 0x4f8cb780, + 0x0930c014, + 0x0900c021, + 0xb59f0208, + 0xb7806b6c, + 0xb55f558c, + 0x9e716a6c, + 0xb59f0268, + 0xb780576c, + 0xd0d1500c, + 0x02686961, + 0x7c6cb59f, + 0x518cb780, + 0x0880c040, + 0x59ecb53f, + 0xb59f0238, + 0xb78071ec, + 0xb51f540c, + 0xb7207b74, + 0x0128430c, + 0x596cb55f, + 0x59f4b71f, + 0xb7800906, + 0x9e91570c, + 0x7becb57f, + 0xc24000e2, + 0xc021a0c6, + 0x0a020c00, + 0xb51f9e72, + 0x9e737974, + 0x4c29b58a, + 0x9e749e70, + 0xc0219e71, + 0x050d0900, + 0x078d058d, + 0x048d040d, + 0x0900c01e, + 0x0d00c021, + 0x0980c021, + 0x0d80c021, + 0x0a00c021, + 0x0f80c021, + 0x0800c021, + 0x0c00c021, + 0x0880c021, + 0x0c80c021, + 0x756cb55f, + 0x0d10c01e, + 0x09a0c01e, + 0x0df0c014, + 0x0a00c010, + 0x0f90c010, + 0x0820c010, + 0x0c30c010, + 0x0880c004, + 0x0ca0c012, + 0x1950c00a, + 0x75f4b55f, + 0x776cb57f, + 0x5a74b57f, + 0x5cecb59f, + 0x5bf4b5ff, + 0x5b6cb51f, + 0x5af4b51f, + 0x61ecb53f, + 0x6174b53f, + 0x60ecb55f, + 0x1d50c00c, + 0x19d0c00c, + 0x1d90c004, + 0xc0080a70, + 0xc0020f90, + 0xc0020830, + 0xc00e0c30, + 0x0cf008f0, + 0xb55f0950, + 0xb57f72f4, + 0xb57f726c, + 0xb59f7174, + 0xb5ff70ec, + 0xc0026074, + 0xb51f0d60, + 0x09f05fec, + 0x7074b51f, + 0x78ecb53f, + 0x5ef4b53f, + 0x5e6cb55f, + 0x0db0c034, + 0x0a50c004, + 0xc0041fd0, + 0xc00c0810, + 0xc0240c20, + 0xc00e08d0, + 0xc0121cd0, + 0xb55f0900, + 0xb57f5df4, + 0xb57f5d6c, + 0xb59f7374, + 0xb5ff73ec, + 0xb51f69f4, + 0xb51f696c, + 0xb53f68f4, + 0xb53f746c, + 0xb55f6874, + 0xc03074ec, + 0xc0320d50, + 0xcfd009c0, + 0xc01e0da1, + 0x1ff00a40, + 0x0850c06a, + 0x0c50c026, + 0x08e1cfe0, + 0x0cf0c014, + 0x0931cfee, + 0x67f4b55f, + 0x676cb57f, + 0x66f4b57f, + 0x666cb59f, + 0x65f4b5ff, + 0x656cb51f, + 0x64f4b51f, + 0x646cb53f, + 0x63f4b53f, + 0x766cb55f, + 0x0d31cfd0, + 0x09c1cfce, + 0xcfe21de0, + 0xcfea0a01, + 0xcf7c0fe1, + 0x0c200871, + 0x08d0c01e, + 0x0cf0c024, + 0x0910c032, + 0x76f4b55f, + 0x77ecb57f, + 0x62f4b57f, + 0x626cb59f, + 0x7a74b5ff, + 0x79ecb51f, + 0x6df4b51f, + 0x6d6cb53f, + 0x6cf4b53f, + 0x6c6cb55f, + 0x9060c059, + 0x09829eb3, + 0x9b91fdf4, + 0x4314b740, + 0xb55f9e50, + 0xb7437af4, + 0x7480572a, + 0x9364c003, + 0x6cacb784, + 0x0e820b82, + 0xd00a7502, + 0x75040bf2, + 0x0ed2d001, + 0xc00075c0, + 0x774090c4, + 0xd0010906, + 0xb73f0922, + 0xc1007aec, + 0x69635a0c, + 0x0118d020, + 0xc0010802, + 0x04050abe, + 0x03a8d020, + 0xcfc09d09, + 0xc0340a80, + 0xb9600c78, + 0xd0114018, + 0xb75f4e52, + 0xc2007aec, + 0xd0105a08, + 0x024004f0, + 0xd0200248, + 0xb78000c4, + 0xb7405a2b, + 0x75c0502b, + 0x4002ba24, + 0x5a28c200, + 0xc03e224a, + 0x9dcb297c, + 0xb76031c4, + 0xb7204052, + 0xc000462b, + 0xb78392a4, + 0xb7436dcb, + 0xb74377cb, + 0xba2463d3, + 0xc2004002, + 0x224a5a28, + 0x9ea15950, + 0x2940c3ff, + 0x2d7cc03e, + 0x351431b4, + 0x2a0ed3f1, + 0xc0007506, + 0xb75f90e2, + 0x9dad756c, + 0xa1e1f000, + 0x4002ba21, + 0x2dfcc03e, + 0xc2009e5b, + 0x224a5a28, + 0xb77f3246, + 0x9dbe75f4, + 0xa261f000, + 0x776cb79f, + 0xf0009dcd, + 0x0804a162, + 0xfffd0c08, + 0x9eb391c1, + 0x9be6fe34, + 0x430cb720, + 0x4cadb742, + 0x7c80c020, + 0x90e2c000, + 0x438cb780, + 0xc0005158, + 0x7c8291e0, + 0x438cb740, + 0x91a2c000, + 0x0a02c010, + 0x5218c200, + 0x22444a7d, + 0x51580906, + 0xc0003244, + 0xc0109100, + 0xc2000a06, + 0x4a7d5218, + 0xb5802228, + 0xc021438c, + 0xb7400a02, + 0xc020438c, + 0x9dcd0a00, + 0xa161f000, + 0x430cb780, + 0x7b6cb71f, + 0x9ea80288, + 0x6fccb789, + 0x753ec01c, + 0x9164c001, + 0xfdf49eb3, + 0x008b9b5e, + 0x6fadb509, + 0x91e0c000, + 0x9becfd94, + 0xb7a09eb3, + 0xfdf4430c, + 0xb75f9b52, + 0x02aa7b6c, + 0xb5099ea8, + 0xb7806fcc, + 0xb75f430c, + 0x0d927b6c, + 0xb72900a8, + 0xc01c6fad, + 0xffff747e, + 0x68b29122, + 0x57f4b75f, + 0xb7290098, + 0xf010712d, + 0xb740a0c1, + 0xb77f430c, + 0x00b47b6c, + 0x6fadb789, + 0x02446a32, + 0x0a20c138, + 0xaa11d208, + 0x753ec01c, + 0x9084c001, + 0xfdf49eb3, + 0xb7209ac7, + 0xb77f4314, + 0xd0107b74, + 0xb74904b2, + 0xd0316fb5, + 0xd0106d29, + 0xc1010624, + 0xc1380122, + 0xd0080920, + 0xc101a951, + 0x02440244, + 0x5a08c200, + 0x00c3d120, + 0x6b6cb79f, + 0x70d5b729, + 0xa082f208, + 0xfe349eb3, + 0x74009ac8, + 0x90c4c000, + 0x097ec00e, + 0x9020c004, + 0x430cb740, + 0xc0a20205, + 0xd2080a38, + 0x7680a902, + 0x90e2c001, + 0x01859e93, + 0x09c0c0a2, + 0x0d9cc0a4, + 0xa962d008, + 0xaa61d010, + 0xc0007115, + 0xb7ff91f2, + 0x0a027c74, + 0xa261d210, + 0xaa61d008, + 0xa961d010, + 0x9ea21244, + 0x2d7cc00e, + 0x430cb740, + 0x0940c0a2, + 0xaa41d008, + 0xd0080a04, + 0xc001a241, + 0x00ac9380, + 0x02030103, + 0x0940c0a2, + 0x0a20c0a2, + 0xa945d008, + 0xaa11d208, + 0xc0017088, + 0xb71f9064, + 0xb5407c6c, + 0xb54a4030, + 0xb7a04c31, + 0x9ea8430c, + 0xc0a4020b, + 0xb76a0a1c, + 0xd2084750, + 0xb76aaa01, + 0xc1014648, + 0x02dc15bc, + 0x65b9c101, + 0x1a32d011, + 0x01c7d120, + 0x0ac0c0a2, + 0x9ac6c0d4, + 0xa025d208, + 0x430cb780, + 0xc0a2024c, + 0xd2080a40, + 0xd011a906, + 0xd2080d22, + 0xb780a105, + 0xc09c430c, + 0xd2080a14, + 0x7500aa01, + 0x9142c000, + 0x7c6cb73f, + 0x4029b780, + 0x0a027500, + 0x0a42d002, + 0x5774b73f, + 0xb5809e52, + 0xb7804049, + 0xc00e430c, + 0xb760297c, + 0x9e93560c, + 0xc23000cc, + 0xb78aa1c6, + 0x75004c29, + 0x9304c000, + 0x4b29b54a, + 0x7c74b7ff, + 0xaa61d210, + 0xc0007500, + 0xb72091e4, + 0x0103430c, + 0x091cc0a4, + 0xb78a009c, + 0xd0084b29, + 0x0244a941, + 0x4b29b58a, + 0x560cb700, + 0xaa45c200, + 0xc0007500, + 0x9eb390a4, + 0x9957fe14, + 0x7c74b71f, + 0x430cb7a0, + 0x4048b780, + 0xc0007500, + 0x9eaf90e2, + 0x0f90c06e, + 0x90a0c000, + 0xc0809eaf, + 0x9eb30f80, + 0x9be2fe94, + 0x7aecb73f, + 0xa9e1f210, + 0x6835b741, + 0x2d4d7cc2, + 0x9202c000, + 0x430cb780, + 0xc0983d10, + 0xd2080a10, + 0x7500aa01, + 0x92c2c000, + 0x3d00c200, + 0x9240c000, + 0x7cc0c010, + 0x91c2c000, + 0x430cb780, + 0xc0983d20, + 0xd2080a14, + 0x7500aa01, + 0x9084c000, + 0x3d00c100, + 0x430cb720, + 0x5dadb781, + 0xc001750a, + 0xb7859084, + 0x75007ea9, + 0x93e2c000, + 0x7f29b785, + 0xc0007500, + 0xb73f9202, + 0xc8007c74, + 0xb7800902, + 0x75004049, + 0xb3420a02, + 0x9e934424, + 0xc0003526, + 0xb71f9180, + 0xb7807c6c, + 0xc2004028, + 0xc8005a3c, + 0x9ea02a00, + 0xb73f3520, + 0x9d9d796c, + 0xa162f000, + 0x560cb740, + 0x7cc2c010, + 0x508cb780, + 0xb55f0164, + 0xd008636c, + 0x0902aac2, + 0x0922d001, + 0xb71f9e92, + 0xc2407aec, + 0xb780a146, + 0x06da430c, + 0x5baab742, + 0x06d8c101, + 0xb74a040b, + 0xb7825352, + 0xb7205b2a, + 0xb7a0412c, + 0x6244510c, + 0x63c5c101, + 0x01839ebb, + 0x6fecb53f, + 0x99d9c0d4, + 0x71f4b73f, + 0x6fecb77f, + 0xb5009ebb, + 0xb75f404b, + 0x02aa7bec, + 0x9a29c0d4, + 0xa021da08, + 0xb73f9e68, + 0xb74b7bec, + 0xb780532a, + 0x0d02520c, + 0xb7409e91, + 0xc840538c, + 0xb780a0a6, + 0xb77f528c, + 0x01145974, + 0xa126c840, + 0x5332b7aa, + 0x530cb780, + 0x09c2c002, + 0xa142d808, + 0xa2a6c840, + 0x9ba5fd14, + 0x4314b720, + 0xc0a49e4c, + 0xd2080a18, + 0x7500aa01, + 0x9202c001, + 0x636cb75f, + 0x7c74b75f, + 0xa8c1d008, + 0xaa41d010, + 0xc1010092, + 0x75000092, + 0x532bb74a, + 0x9104c000, + 0x6c4db784, + 0x01090228, + 0x297ccffe, + 0x6b4db709, + 0x018d9e93, + 0x9c629e84, + 0x430cb720, + 0x5dadb781, + 0x75021a10, + 0x90f2c000, + 0x532bb78c, + 0xc0007500, + 0xb78090e4, + 0x9e83550c, + 0xa1c6c240, + 0x7aecb71f, + 0x5dacb781, + 0xc0007506, + 0xb7209204, + 0x00e2430c, + 0x4829b78c, + 0xc0007500, + 0x097e9102, + 0x550cb780, + 0xc2409e90, + 0xb73fa046, + 0xb7817aec, + 0x1a085dad, + 0xc0037506, + 0xd22691f2, + 0x8520590c, + 0x8044e050, + 0x9100c000, + 0x9240c002, + 0x9260c001, + 0x9280c001, + 0x7af4b73f, + 0x4149b786, + 0xc0007500, + 0xb7409202, + 0xc220560c, + 0x7500aa45, + 0x9124c000, + 0x7c74b75f, + 0xaa41d010, + 0xc0007500, + 0x9eb390c4, + 0xfe14018f, + 0xb77f992a, + 0xb7407c6c, + 0x9d07550c, + 0xa8e2d008, + 0xa945c220, + 0x0a029eb3, + 0xd052018f, + 0xcfe80d78, + 0xb59e08e1, + 0xfd74666a, + 0xc0019aef, + 0x0d829260, + 0x9080c001, + 0x560cb700, + 0xaa45c200, + 0xc0007500, + 0x9ea390a4, + 0x9853fe14, + 0x430cb720, + 0xb76a018f, + 0xfe1446b1, + 0xb71f9900, + 0x9ebb7c74, + 0x0df8d051, + 0x4050b740, + 0x9280c000, + 0x560cb720, + 0xaa45c210, + 0xc0007500, + 0x9ea390e4, + 0x9839fe14, + 0x9140c000, + 0x430cb760, + 0x0d060d82, + 0x09e0c06e, + 0x9b5cfdf4, + 0xfe349eb3, + 0xb7a09925, + 0xb780430c, + 0x9ea9550c, + 0xaa45c240, + 0x70c9b744, + 0x2a7cc002, + 0xc0305920, + 0x32442900, + 0x5a6cb75f, + 0xf0009dad, + 0xb75fa261, + 0x020b7c74, + 0x5dc5b741, + 0xabc1d010, + 0x0a44c09a, + 0xc00075c0, + 0xd20891e2, + 0xc200aa01, + 0x00ca5a08, + 0x6cb5b742, + 0x63adb742, + 0x682db782, + 0x91a0c000, + 0xaa01d208, + 0x5a08c200, + 0xb74200ca, + 0xb7427a35, + 0xb782712d, + 0xb77f75ad, + 0x9dbd5cec, + 0xa161f000, + 0x5bf4b77f, + 0xf0009dbe, + 0xb79fa261, + 0x9dcd5b6c, + 0xa162f000, + 0xb781000b, + 0xb71f482c, + 0x9d8e5af4, + 0xa261f000, + 0xa8a9f208, + 0xb53f75c0, + 0xb7496eec, + 0x0203573a, + 0x5a10c200, + 0xc0029d4b, + 0xcffc0a7c, + 0x59102a01, + 0x0148d020, + 0xcffe097c, + 0xc1012901, + 0x02030528, + 0x6525c101, + 0x2a710a0c, + 0x5890c200, + 0xc0005d05, + 0xb78391a2, + 0x0e825e2c, + 0xe003048b, + 0xb3152a00, + 0x05834442, + 0x92e0c000, + 0xc3019ea9, + 0xb7846115, + 0xd0f241cd, + 0xc00508ae, + 0xcffc7d00, + 0xc0002c81, + 0x068390a2, + 0x9080c000, + 0x0692c101, + 0x0092c101, + 0x020b0585, + 0x0a10c098, + 0xd2089ea8, + 0xb781a801, + 0x09c24b4c, + 0xd0217400, + 0x750209b8, + 0x1124d011, + 0x9102c000, + 0xc1800207, + 0xc0815920, + 0x31443a20, + 0x61ecb77f, + 0xf0009dbd, + 0x9ea8a161, + 0x7ec8b785, + 0x664cb764, + 0x66ccb744, + 0xc0007500, + 0x740092e2, + 0x9282c000, + 0xc00075c0, + 0xb7649102, + 0xb744654c, + 0xc00065cc, + 0x9ea89100, + 0xb7649eba, + 0xb744644c, + 0x858664cc, + 0x9080c000, + 0x05078582, + 0xb7849ea8, + 0xb71f644c, + 0xd1106174, + 0x9d8e0639, + 0xa261f000, + 0xb7849ea8, + 0xb71f64cc, + 0xd11060f4, + 0x9d8e0639, + 0xa261f000, + 0xb7849ea8, + 0xb71f654c, + 0xd11072f4, + 0x9d8e0639, + 0xa261f000, + 0xb7849ea8, + 0xd11065cc, + 0xb77f0639, + 0x9dbe7274, + 0xa261f000, + 0x0627d110, + 0x7174b71f, + 0xf0009d8e, + 0xd110a261, + 0xb75f0625, + 0x9dad70ec, + 0xa261f000, + 0x75c09ea8, + 0x7f48b785, + 0x9102c000, + 0x7d3ec01c, + 0x9104c000, + 0x9140c000, + 0x7d3ec01c, + 0x90c4c000, + 0x0a060d02, + 0x9080c000, + 0x0a020d0a, + 0x74809d6b, + 0x9102c000, + 0xc0007500, + 0x090690a2, + 0x9100c000, + 0x09029d6f, + 0x31c6e000, + 0x0922d001, + 0x4a049e53, + 0x59083238, + 0xb77f3244, + 0x9dbe6074, + 0xa261f000, + 0xc096020b, + 0xd2080a58, + 0xb71fa901, + 0xc1005ff4, + 0x024a5a08, + 0xaa11f288, + 0x0619d110, + 0xf0009d8e, + 0x590ca261, + 0xf0c8012a, + 0x0114a951, + 0x706cb73f, + 0xf0009d9d, + 0xb75fa161, + 0x9dae78f4, + 0xa161f000, + 0xc096020b, + 0xd2080a50, + 0xb77fa901, + 0xd0205eec, + 0xd1220124, + 0x024a5e08, + 0xaa11f2c8, + 0x0659d110, + 0xf0009dbd, + 0x5908a261, + 0xf088012a, + 0xb77fa951, + 0xd1105e74, + 0x9dbe0515, + 0xa161f000, + 0x5d080d04, + 0x052ac101, + 0xa952f0d0, + 0x5decb79f, + 0x9dcd0554, + 0xa162f000, + 0x7b6cb75f, + 0x5d74b75f, + 0xb72100aa, + 0x9dae48ad, + 0xa0e1f000, + 0xb7849ea8, + 0xf21163cc, + 0xc00128c0, + 0x74009004, + 0x93a4c000, + 0x72f4b73f, + 0xaa619d1e, + 0x716cb75f, + 0xf0009dad, + 0xb75fa261, + 0x9d2e7274, + 0xb77faa61, + 0x9dbd70ec, + 0xa261f000, + 0x7074b77f, + 0xaa619d3e, + 0x78ecb71f, + 0xf0009d8d, + 0xb71fa261, + 0xb75f7aec, + 0xb7807bec, + 0xb722510c, + 0x000b5b32, + 0x622cb701, + 0xa9c7c840, + 0x520cb780, + 0xb51f9dc0, + 0x7604566c, + 0x71f4b75f, + 0xa846c840, + 0xa965f210, + 0xaac2d810, + 0x56ecb55f, + 0x9104c001, + 0x5b8cb760, + 0x5c14b740, + 0xb9600902, + 0xe0304018, + 0xb77faa45, + 0x9dbe6af4, + 0xa261f000, + 0xb77f9e50, + 0xe0006a74, + 0x9dbeaa45, + 0xa261f000, + 0xffff0910, + 0xb79f9201, + 0xc0746e6c, + 0xc0140976, + 0xc0210a40, + 0x9dcd0a00, + 0xa161f000, + 0x9060c001, + 0x75069d50, + 0x93e4c000, + 0x0906c001, + 0x0a02c021, + 0x0900c4d0, + 0x0a20c014, + 0xf0009dcd, + 0xc02ca161, + 0x0a100932, + 0xf0009dcd, + 0xc002a161, + 0x0a10097e, + 0xf0009dcd, + 0x0a02a161, + 0x736cb71f, + 0xf0009d8d, + 0xf011a261, + 0x75028e28, + 0x9072c001, + 0x0906c001, + 0x0a02c021, + 0x0900cca0, + 0x0a20c014, + 0xf0009dcd, + 0xc040a161, + 0x0a10091a, + 0xf0009dcd, + 0xc002a161, + 0x0a10097e, + 0xf0009dcd, + 0x000ba161, + 0x60acb781, + 0x736cb75f, + 0x2a1c1a04, + 0xf0009dad, + 0x9e78a261, + 0x73f4b75f, + 0x622cb740, + 0xc1010205, + 0x9dae3a00, + 0xa261f000, + 0xf0009dae, + 0xb780a161, + 0xb77f62ac, + 0x9dbd69ec, + 0xa261f000, + 0x632cb780, + 0x6974b77f, + 0xf0009dbe, + 0xf210a261, + 0xb71faa69, + 0x9d8d68ec, + 0xa261f000, + 0xc098020b, + 0xd2080a0c, + 0x7500aa01, + 0x9222c000, + 0xc0007440, + 0x008b91c2, + 0x62adb781, + 0x746cb75f, + 0x3a00c020, + 0xf0009dad, + 0xc000a261, + 0x000b9140, + 0x62acb781, + 0x746cb73f, + 0xf0009d9d, + 0x000ba261, + 0x632cb781, + 0x686cb73f, + 0xf0009d9d, + 0xb78ca261, + 0xb741532a, + 0x750063ac, + 0x90c2c001, + 0x7c82c001, + 0x90c4c000, + 0x9e92097e, + 0x9220c000, + 0x292ed3f2, + 0x9ea30a7e, + 0x2900cff0, + 0x592176be, + 0x4846b323, + 0xb32474be, + 0x05074426, + 0xc0010109, + 0x9e503d04, + 0x5a20c100, + 0xb73f3208, + 0x9d9d74ec, + 0xa261f000, + 0x90e0c000, + 0x74f4b75f, + 0xf0009dae, + 0x000ba161, + 0x652cb781, + 0x67ecb73f, + 0xf0009d9d, + 0xb781a261, + 0xb75f65ac, + 0x9dad676c, + 0xa261f000, + 0x6602d011, + 0x8db2e012, + 0x6fecb77f, + 0x05b8c101, + 0x7d7cb55f, + 0x7de4b55f, + 0x9a17c0b4, + 0x0451d110, + 0x566cb77f, + 0xcff05820, + 0x30062800, + 0x66f4b77f, + 0xf0009dbe, + 0x000ba061, + 0x662cb781, + 0x6674b71f, + 0xf0009d8e, + 0xd2a2a261, + 0xb73f5e20, + 0xcff056ec, + 0xb73f2a00, + 0x324265f4, + 0xf0009d9e, + 0xb781a261, + 0xb75f672c, + 0x9dad656c, + 0xa261f000, + 0x532ab783, + 0x64f4b75f, + 0xf0009dae, + 0xc021a261, + 0xc0120902, + 0x9dad0950, + 0xa261f000, + 0x7decb77f, + 0x7d7cb75f, + 0xc00074c4, + 0xb7819204, + 0xb77f642c, + 0x9dbe6474, + 0xa261f000, + 0x64acb781, + 0x63ecb71f, + 0xf0009d8d, + 0x020ba261, + 0xc09a75c0, + 0xc0000a44, + 0xd20893c2, + 0xb71faa01, + 0xc2007674, + 0x00ca5a08, + 0x7aadb780, + 0xf0009d8e, + 0xb780a261, + 0xb73f7f2d, + 0x9d9e76f4, + 0xa261f000, + 0x43adb721, + 0x77ecb75f, + 0xf0009dad, + 0xc001a0e1, + 0xd2089380, + 0xb77ea902, + 0xb77f7a68, + 0x5d087674, + 0x293ed3f1, + 0x5a0cc100, + 0x04abd110, + 0x0a7cc002, + 0x7ab5b740, + 0x2a01cffc, + 0x6245c301, + 0x0244c101, + 0xf0009dbe, + 0xd012a261, + 0x9d53692b, + 0x5d0b0d0c, + 0x7f2db760, + 0x5a18c200, + 0x6245c101, + 0x76ecb71f, + 0x9d8d0246, + 0xa261f000, + 0x6125c301, + 0x43adb721, + 0xc0020124, + 0xcffc097c, + 0x01222901, + 0x77f4b71f, + 0xf0009d8e, + 0xf210a161, + 0xb73fa96d, + 0x9d9d62ec, + 0xa161f000, + 0xb75f9ea9, + 0xb7816274, + 0x9dae66cd, + 0xa261f000, + 0x7aecb71f, + 0x7fa8b785, + 0xc0007500, + 0xb78a9164, + 0x75024649, + 0x90c4c000, + 0x3900c080, + 0xa16df210, + 0x0a7ec7fe, + 0x7a74b71f, + 0xf0009d8e, + 0xc401a261, + 0xc5000a02, + 0xb73f0a00, + 0x9d9d79ec, + 0xa261f000, + 0x991afe14, + 0x7becb75f, + 0x528cb780, + 0x7b6cb77f, + 0xb59f0228, + 0xb780786c, + 0x0228520c, + 0x5c6cb59f, + 0x510cb780, + 0x03a8d020, + 0x548cb780, + 0xb59f0238, + 0xb780586c, + 0x03a8538c, + 0x560cb780, + 0xb59f0268, + 0xc0095f6c, + 0x74809380, + 0x08021a04, + 0x0802d001, + 0x70880c02, + 0x0c02d001, + 0xb51f7400, + 0xc0006bec, + 0x008b9142, + 0x5b2bb762, + 0x5333b74c, + 0xc0020906, + 0xb73f9080, + 0x020b5f74, + 0x0a1cc0a4, + 0xa901d208, + 0x4049b780, + 0xc0017104, + 0x00dc93c8, + 0x4929b78c, + 0x08c0c060, + 0xc0007500, + 0xb7809204, + 0x75004029, + 0x9164c000, + 0xb78c000b, + 0x0d02532a, + 0xd0027500, + 0xc0000d22, + 0x0d069060, + 0xda10008b, + 0xb742aa61, + 0x02445b2b, + 0xa261da10, + 0x9160c000, + 0x71f4b73f, + 0xa1e1da10, + 0x404bb780, + 0xb5800a04, + 0xf208404b, + 0xda10a929, + 0x7104aa61, + 0xffff11c4, + 0x000b9228, + 0x5b2ab762, + 0x9eb30902, + 0x9e419e91, + 0xfdf4a01e, + 0xb71f9ada, + 0x9e745874, + 0x0a00c021, + 0x404cb740, + 0x0a00c016, + 0xf0009dcd, + 0x9eb3a161, + 0x98dafe14, + 0x0992058d, + 0x0d02c400, + 0x9a57fd74, + 0x0a02c400, + 0x7a6cb73f, + 0xf0009d9d, + 0xb73fa261, + 0xda087874, + 0x000baa61, + 0x404bb740, + 0xda080a04, + 0x0904a261, + 0x404bb540, + 0x5baab742, + 0x2a7ccffe, + 0xc0007088, + 0x0a0291e4, + 0xa261da08, + 0x7becb73f, + 0x530cb740, + 0xd8080114, + 0x0a04aa41, + 0xa241d808, + 0x7c74b73f, + 0x530cb780, + 0x7becb75f, + 0x4051b760, + 0xaa45c840, + 0xc00076c0, + 0x9ea590a2, + 0x9100c000, + 0x430cb720, + 0x6c2db724, + 0x02c2d020, + 0x6bf4b75f, + 0xc0017680, + 0xda089024, + 0x000ba961, + 0x5baab762, + 0x0d027482, + 0x0d22d001, + 0xd00174c2, + 0xb3321a44, + 0xc0004442, + 0x748290a2, + 0x1a42d00a, + 0xc00076c0, + 0xb72090e4, + 0xb724430c, + 0x02426c2d, + 0x018d9ea3, + 0x9adefe74, + 0x430cb720, + 0xc0a40203, + 0xd2080a18, + 0x7500aa01, + 0x9322c001, + 0x5f74b71f, + 0xc0a40203, + 0xd2080a1c, + 0xb780a901, + 0x71044048, + 0x91e8c002, + 0x7874b73f, + 0x5c74b75f, + 0x404bb740, + 0xaa41d810, + 0xc0027088, + 0xda089088, + 0x7500aa61, + 0x93e4c001, + 0x6b2db709, + 0x018d058b, + 0x9c629e84, + 0x430cb720, + 0x5dadb781, + 0x75021a10, + 0x90f2c000, + 0x532bb78c, + 0xc0017500, + 0xb7809184, + 0x9e80550c, + 0xc2409eb3, + 0xc001a046, + 0x009c9040, + 0x4829b78c, + 0xc0007500, + 0x008b93c2, + 0x5dadb781, + 0x550cb740, + 0xc0007504, + 0xc0029124, + 0x9ea10a44, + 0xa0c6c220, + 0x9180c000, + 0xd2080264, + 0x0d7ea901, + 0x9e930908, + 0x7286c810, + 0xa102d208, + 0xfe149eb3, + 0xfdf49825, + 0xb79f9bbf, + 0xb71f786c, + 0xb7a05c6c, + 0xda08430c, + 0xb780a901, + 0x7088402a, + 0x9366fff5, + 0xc0a2020b, + 0xd2080a38, + 0x7500aa01, + 0x90a2c000, + 0xc0000a06, + 0x025c9200, + 0xc0a20109, + 0xc0a20920, + 0xd2080a40, + 0xd008aa05, + 0x7104a951, + 0xd0010a02, + 0x9eb30a42, + 0xfdf40389, + 0x058d9be3, + 0xc1000992, + 0xfd740d02, + 0xcffe9960, + 0xc1002bfc, + 0xb71f0a02, + 0x9d8e7a74, + 0xa261f000, + 0xb73f0a86, + 0x9d9d6dec, + 0xa2e1f000, + 0x6d74b73f, + 0xf0009d9e, + 0xb77fa2e1, + 0xc00659f4, + 0x0d0209f2, + 0xfcf4010b, + 0xc0389958, + 0x0d0209f2, + 0x058d010b, + 0x9951fcf4, + 0x7c74b75f, + 0x530cb780, + 0x7becb77f, + 0xa941d010, + 0xaa65c840, + 0x1a047480, + 0x9144c000, + 0x430cb720, + 0x2a7ccffe, + 0x6c2db724, + 0x020300c2, + 0x2a7ccffe, + 0x9eaa9ea3, + 0xfe74018d, + 0x75c09a09, + 0x90a4c000, + 0xc000010f, + 0xb7209280, + 0xb785430c, + 0x75007ea9, + 0x90a4c000, + 0xc000010b, + 0xb77f9140, + 0x09027c74, + 0xaa61d010, + 0xd0017500, + 0x9e950922, + 0xcffe75c0, + 0xc0002efc, + 0xb7209124, + 0xb786430c, + 0x75006729, + 0x9042c002, + 0x0a82c008, + 0x7a6cb79f, + 0xf0009dcd, + 0xb7ffa2e1, + 0x9d7e7974, + 0xc002aa61, + 0x9dfe3a40, + 0xa261f000, + 0x0a02c401, + 0x0a00c008, + 0x79ecb71f, + 0xf0009d8d, + 0x9eaaa261, + 0x058d0992, + 0x98ddfd74, + 0xb71f0a02, + 0x9d8e79f4, + 0xa261f000, + 0x7a6cb73f, + 0xf0009d9d, + 0xb73fa2e1, + 0x9d1e6cf4, + 0xb75faa61, + 0x9d2d6c6c, + 0x7680a962, + 0x91c2c000, + 0x6b6cb77f, + 0x5a35c200, + 0xf0082a7c, + 0xd110a961, + 0x12a81525, + 0x9060c000, + 0xb7400a82, + 0x9eb3430c, + 0xc0a20986, + 0xd008093c, + 0x0a04aa41, + 0xa241d008, + 0x430cb740, + 0xc050012c, + 0xd0080960, + 0x0a04aa41, + 0xa241d008, + 0x9a45fdb4, + 0xc00075c0, + 0xb7209322, + 0xd2a4430c, + 0xb784590c, + 0xc10179ad, + 0xb5840244, + 0xb78079ad, + 0xb71f430c, + 0x02087b6c, + 0x0a40c09c, + 0xa901f208, + 0x0524c101, + 0xa102f208, + 0xc0007740, + 0xb7809242, + 0x9ea2430c, + 0x0a3cc0a2, + 0x0d20c0a4, + 0xa901d208, + 0xaa41d010, + 0x0a027088, + 0x4828b354, + 0xb7009ea5, + 0xb7814314, + 0x1a105dcc, + 0xc0007502, + 0xb78c9132, + 0x7500534a, + 0x9082c000, + 0x76ccb7a4, + 0x560cb740, + 0x7bf4b75f, + 0x7c6cb77f, + 0xa8c5c220, + 0xb7209e44, + 0x00925314, + 0x0a50c096, + 0x0090c101, + 0x532bb72a, + 0xa8cac810, + 0xa902d208, + 0xaa61d008, + 0x040cc101, + 0x4c50b70a, + 0xc1017500, + 0x01031492, + 0x9e699eb3, + 0xd0010a02, + 0xcffe0a42, + 0x018b2cfc, + 0xa219a01e, + 0xfdf4a395, + 0x75c098ed, + 0x9042c001, + 0x4314b720, + 0x7b74b7ff, + 0x9eb39d0b, + 0x04f2d010, + 0xb7290992, + 0xcfe86fad, + 0xd0320971, + 0x02126919, + 0xc1380522, + 0xd0100d20, + 0x0242a952, + 0x0244c101, + 0x5a08c200, + 0x00c3d120, + 0x70d5b749, + 0x99f1fd14, + 0x430cb720, + 0x5733b743, + 0xc0067680, + 0xb7839184, + 0x87825ead, + 0x75020902, + 0x87b2e00a, + 0x75049d60, + 0x0922d001, + 0x0a027508, + 0x0a42d001, + 0xd0407400, + 0xc0003128, + 0x9e5490a2, + 0x90e0c000, + 0x0a069dc0, + 0xd0017600, + 0xc0010a42, + 0xc200853e, + 0x0e825a08, + 0x8500cfc0, + 0x58ecb59f, + 0x4018b960, + 0x2e5ed3f1, + 0xd0117506, + 0xc00012da, + 0xb73f90c2, + 0x9d1d756c, + 0xb73faae1, + 0x9d1e75f4, + 0xb75fa9e1, + 0x9d2d776c, + 0xb75fa9e2, + 0xb72058f4, + 0xd0104314, + 0x042a045a, + 0xd0100400, + 0xd1200482, + 0xb7230083, + 0xb78357ab, + 0x9e9a7bcb, + 0xc03e9d48, + 0x12422d7c, + 0x0244c101, + 0x7bcbb583, + 0x4314b720, + 0x59084904, + 0x0482d010, + 0x0083d120, + 0x012ac101, + 0x7dcbb783, + 0x5dabb723, + 0x0124d020, + 0x12429d4b, + 0x59a921b4, + 0xb5830246, + 0xb7207dcb, + 0x010b4314, + 0x297cc03e, + 0x0482d010, + 0x0083d120, + 0x67abb723, + 0x7fcbb783, + 0xc03e0787, + 0x12422ffc, + 0xb5830244, + 0xb7207fcb, + 0x9d4f430c, + 0xc1019d7e, + 0x00820402, + 0xb7849ddf, + 0xb70341ab, + 0x215671d2, + 0x9dfc25be, + 0xc1015929, + 0xc3ff1240, + 0x02442ac0, + 0x5da977c0, + 0xc2800e84, + 0xb58459d1, + 0xc00141ab, + 0xb72091c4, + 0xd0104314, + 0xd12004a2, + 0xb7230083, + 0xb78463ab, + 0x124243cb, + 0x0246c301, + 0x43cbb584, + 0x4314b720, + 0x04a2d010, + 0x0083d120, + 0x6dabb723, + 0x45cbb784, + 0xc1011242, + 0xb5840246, + 0xb72045cb, + 0xd0104314, + 0xd12004a2, + 0xb7230083, + 0xb78477ab, + 0x124247cb, + 0xb5840246, + 0xfffa47cb, + 0xb70093e1, + 0x9e444314, + 0x0a38c0a2, + 0xaa01d208, + 0xc0007500, + 0xd1109204, + 0xb700060d, + 0xc0a2560c, + 0xd2080a20, + 0xc200aa11, + 0x1a04a945, + 0xc0027088, + 0x75c09038, + 0x9202c001, + 0x7b74b73f, + 0x6c50b74d, + 0x4490b760, + 0x0490d010, + 0xb729018d, + 0xd0316fb5, + 0xc00e6d19, + 0xc1012cfc, + 0xc1380120, + 0xd0080920, + 0xfd54a951, + 0xb7409ad8, + 0xb77f430c, + 0x00b47b6c, + 0x6fadb789, + 0x02446a32, + 0x0a20c138, + 0xd208097f, + 0xb720a111, + 0xc00e430c, + 0x00b20a7e, + 0x6fadb589, + 0x9200c000, + 0x7b74b77f, + 0xd010097f, + 0xb78904b0, + 0x6a326fad, + 0x0240c101, + 0x0a20c138, + 0xa111d208, + 0x430cb740, + 0xb7000a7f, + 0x9ea0560c, + 0xc2000205, + 0xc0a2a046, + 0xd2080a38, + 0x7500aa01, + 0x92a4c000, + 0x02059e92, + 0x0a3cc0a2, + 0x0d20c0a4, + 0xa901d208, + 0xaa41d010, + 0xc0007088, + 0x9eb39108, + 0x98c7fdf4, + 0xffa67400, + 0xb73f9364, + 0x0a1a6f6c, + 0x41adb580, + 0x430cb720, + 0xc0a20203, + 0xd2080a38, + 0x7500aa01, + 0x9044c001, + 0x4729b76a, + 0x46a9b74a, + 0x4794b720, + 0x0d069ea3, + 0x9120c000, + 0x5aadb780, + 0x750c0787, + 0x4842b327, + 0xd051050f, + 0x70866a29, + 0x00c2c101, + 0x0a22d011, + 0xc00e0109, + 0xffff297c, + 0x768091f4, + 0x9162c000, + 0x4488b780, + 0x478cb740, + 0x02446a52, + 0xf2480906, + 0x9e72a115, + 0x0a02c002, + 0x0900c021, + 0xf0009dad, + 0xc002a261, + 0x9dad1a00, + 0xa261f000, + 0x430cb740, + 0xc2000a86, + 0xc13652b8, + 0xd0080924, + 0x0a7fa942, + 0x9e50424a, + 0xd0082240, + 0xfdf4a241, + 0xd3f298a5, + 0xfd7429de, + 0xb79f99f8, + 0xb7bf67ee, + 0xb7df686e, + 0xb7ff68ee, + 0xcfe6696e, + 0x9c228461, + 0xfcd4a605, + 0xc0219a45, + 0x09060a02, + 0x0a00c010, + 0xf0009dcd, + 0x0d82a161, + 0x9baafcf4, + 0xfcd40d8a, + 0x09029a41, + 0x0a02c021, + 0x438cb540, + 0x0a00c020, + 0xf0009dcd, + 0xc01ca161, + 0x9d4d0a40, + 0xc021aa61, + 0xc00f0a82, + 0xb5802a7e, + 0xc004450c, + 0x9d5d0ae0, + 0x2afcaae1, + 0xfd349eab, + 0xb7809bbc, + 0xb9604e0c, + 0xd2084038, + 0xc146a281, + 0xffff0a20, + 0xc0219381, + 0xc0060a02, + 0x9d4d0a50, + 0x7d1eaa61, + 0x92c2c000, + 0x0a02c021, + 0x0a40c006, + 0xa9629d4d, + 0xc008090a, + 0x9dcd0a40, + 0xa161f000, + 0xc00076bf, + 0xc00c90e2, + 0x9dcd1a70, + 0xa162f000, + 0x0a02c401, + 0x0902c021, + 0x0a00cff0, + 0x9dad0920, + 0xa261f000, + 0x578cb720, + 0xb7400a02, + 0x9ea34a14, + 0x4588b580, + 0x4688b580, + 0x018928e1, + 0xc03c851a, + 0xc0580ac2, + 0xc01c0802, + 0xc0140c02, + 0xb9600c82, + 0xd3f14058, + 0xf0102d3e, + 0x7480a147, + 0xa141d010, + 0x90e4c000, + 0xf1d09e4b, + 0xc000a0dd, + 0xf1d09240, + 0x7482aa49, + 0x02460a1c, + 0xf1d02a61, + 0xb303a25d, + 0xc0004822, + 0x749290c2, + 0xb303018b, + 0x0d844432, + 0xffff0d50, + 0xc0219001, + 0x0a820a02, + 0x0a10c010, + 0xf0009dcd, + 0x0a10a2e1, + 0xf0009dcd, + 0x090aa2e1, + 0x0a30c104, + 0xf0009dcd, + 0xc123a161, + 0xc5660952, + 0xcefa0960, + 0x9dcd0a31, + 0xa161f000, + 0x99fffcd4, + 0x0926c829, + 0x0900cc3e, + 0xaa41f008, + 0xc0007500, + 0x0a0490a2, + 0xa241f008, + 0x9b06fd94, + 0xfcd49eab, + 0x000b998d, + 0x7f6eb79f, + 0x7feeb7bf, + 0x9c228c40, + 0x4314b720, + 0xd0109e9a, + 0xb78c0494, + 0x75004829, + 0x9342c000, + 0x6f4db746, + 0xc0c89e4c, + 0xd2080a48, + 0x0908aa01, + 0x7104d010, + 0x6f4db586, + 0x430cb720, + 0x550cb780, + 0x6f2db746, + 0xaa65c040, + 0x7104d012, + 0x6f2db586, + 0x430cb700, + 0x6f2cb706, + 0xa6059c22, + 0x430cb7a0, + 0x9e9d0d86, + 0x98e8fed4, + 0xb506008b, + 0xb7206f2d, + 0xd0104314, + 0xb78c049a, + 0x75004829, + 0x9082c001, + 0x6f4db786, + 0xc0c89e4a, + 0xd0080948, + 0x0a08a941, + 0x7104d010, + 0x6f4db586, + 0x430cb720, + 0x550cb740, + 0xb7869e6b, + 0xc0206f2d, + 0xd012a965, + 0xb5867088, + 0xb7206f2d, + 0x0908430c, + 0x6f2db786, + 0x7104d010, + 0x6f2db586, + 0x4314b760, + 0xc0d60986, + 0xfeb40de0, + 0xb7209a4c, + 0xb786430c, + 0xb58d6f2d, + 0xb7004aab, + 0xb706430c, + 0xb79f6f2c, + 0xb7bf7f6e, + 0x8c407fee, + 0xa61d9c22, + 0x8420c002, + 0x430cb7e0, + 0xaa41d810, + 0xa945d810, + 0x9eb9008f, + 0xb7419e55, + 0xb57f5e35, + 0xb7267c6c, + 0x024469d5, + 0x00897684, + 0x7d74b53f, + 0xcffe9e5e, + 0xf20828fc, + 0xc000a932, + 0x9eb99244, + 0x5a4bb78d, + 0x6dcdb746, + 0x0629d110, + 0x5a4bb58d, + 0xaa35f208, + 0xb5460128, + 0xc0006dcd, + 0x9eb99120, + 0x5a53b54d, + 0xaa35f208, + 0x6dcdb586, + 0xf2489eb9, + 0xb786a9a1, + 0xb7466fcd, + 0xb746704d, + 0x02466ed5, + 0x6fcdb586, + 0xa9a5f248, + 0x6f4db786, + 0x5ad5b766, + 0xb5460126, + 0xda08704d, + 0x0242a925, + 0x6f4db586, + 0x0524c101, + 0x6ed5b546, + 0xa931f208, + 0xaa35f208, + 0x5905d0a4, + 0x02440183, + 0x05b8c101, + 0x5ad5b566, + 0xaa39da08, + 0xa9beda08, + 0x05b8c101, + 0xc07405b4, + 0x008f9b19, + 0x69adb786, + 0x6d2bb74c, + 0x09040240, + 0x69adb586, + 0x6d2bb54c, + 0x448cb780, + 0x4314b720, + 0xc0007500, + 0x010990a4, + 0x9180c000, + 0x0902008b, + 0x4030b960, + 0x54a9b780, + 0x01280884, + 0x9381ffff, + 0x614bb54d, + 0xf2089eb9, + 0xb786a935, + 0xf2085dcd, + 0xb766a932, + 0x1244564d, + 0x1244c101, + 0x5dcdb586, + 0x69d5b726, + 0xb53f74c4, + 0xc0167cf4, + 0x008f91e2, + 0x71abb78c, + 0xc0167500, + 0xb7a09124, + 0xf2084314, + 0xf208a925, + 0x048baa29, + 0x4ccdb766, + 0x6dd3b7cc, + 0xd1a40244, + 0x9eb75985, + 0x01c7d120, + 0x2ffccffe, + 0x9ac3c074, + 0x6e65d171, + 0x5c88d322, + 0x024ec101, + 0x5a08c200, + 0x024ac101, + 0xc101a01d, + 0xc0e6009a, + 0xd2480a60, + 0xb746ab0d, + 0x048b682d, + 0x5a4bb76d, + 0x5c53b74d, + 0x6d53b72c, + 0xba12112c, + 0xa0924003, + 0x682db546, + 0x9e69a892, + 0x066cd010, + 0xa11a1514, + 0xb72d9e9b, + 0xc101612b, + 0xba1b024a, + 0xc12a4003, + 0x76c00a40, + 0xaa99da08, + 0x7decb53f, + 0x917cc001, + 0xb786048b, + 0x75006dcd, + 0x90bcc001, + 0x05b9d110, + 0xc0745da0, + 0x75409a87, + 0x90a4c000, + 0xc0000101, + 0x025a90e0, + 0x0240024a, + 0x590bc200, + 0x066cd010, + 0xc1017580, + 0xc12a024a, + 0xda080a40, + 0xc000a119, + 0x028190a4, + 0x90e0c000, + 0x02400200, + 0xc200024c, + 0xc00e5a8b, + 0xc810097e, + 0xd1717144, + 0x9e696e65, + 0x01cec101, + 0x5a08c180, + 0x024ac101, + 0x0a60c0e6, + 0xa10dd248, + 0x7df4b73f, + 0x5433b74d, + 0x76400a02, + 0x0a42d002, + 0x692db746, + 0x0244c101, + 0x012aa91e, + 0x692db546, + 0xb58d7680, + 0xc000542b, + 0xb7869122, + 0x9e494cad, + 0x70481a04, + 0x9326c000, + 0x04ecd010, + 0xb74d048b, + 0xc1015c4b, + 0xb72e009a, + 0x02365f2b, + 0x024ac101, + 0xc1140904, + 0x0d060a20, + 0xda08a116, + 0xb54da091, + 0xc0045c4b, + 0x9e6990e0, + 0x6dadb746, + 0xc0007480, + 0x0a169204, + 0x7b6cb59f, + 0x7becb55f, + 0x5c2bb78d, + 0xa0960c86, + 0xb58d0a04, + 0xc0005c2b, + 0x0a029100, + 0x7b6cb55f, + 0x7becb59f, + 0xb79fa215, + 0xb75f7d6c, + 0x11a87cec, + 0x4002ba1b, + 0x0a4ec002, + 0x70c8cc10, + 0x1a4cc002, + 0x70c8cc12, + 0x5d0cb780, + 0x4002ba1b, + 0xc84001b6, + 0xe0b2a9e5, + 0xba1b8d80, + 0xff744002, + 0xa99d9999, + 0x8d80e0b2, + 0x99c5ff74, + 0x8d80e0b2, + 0x99adfe74, + 0xc0120a16, + 0xd1717008, + 0xcffe6e65, + 0xc101287c, + 0x0248024e, + 0x024ac101, + 0xc1140289, + 0xda080aa0, + 0x7580ab31, + 0x9142c000, + 0x01ecd020, + 0x0d88098e, + 0x05b0c101, + 0x99cac074, + 0x6de5d172, + 0x5c88d322, + 0x05b605be, + 0xda0805ba, + 0xc101a031, + 0xc114009a, + 0xd8100da0, + 0xb787a9f2, + 0x048b4ead, + 0x5a4bb76c, + 0x05b8c101, + 0x15bcc101, + 0xcc129e9a, + 0xd01072c4, + 0xc18006ec, + 0xb5675a05, + 0xc1014eb5, + 0xc10102da, + 0xc07405b8, + 0x008b999e, + 0x5f2bb50e, + 0x6e65d171, + 0x5d8cc300, + 0x024ec101, + 0x5a08c200, + 0x00cac101, + 0x502db7a7, + 0xc0d205d6, + 0xc00f0da0, + 0x018b2afe, + 0x98d7ff74, + 0x7640a896, + 0x93e4c000, + 0x6e69d091, + 0x4038b960, + 0x0659d110, + 0xc12c9ea2, + 0xf0100d70, + 0xf090aa41, + 0xf010a949, + 0xf090a245, + 0x1d10a14d, + 0x92e1ffff, + 0x6ce9d091, + 0x009ac101, + 0x612db5a9, + 0xb549a91d, + 0xd171582d, + 0xa91d6e65, + 0x024ec101, + 0x5a08c200, + 0x00cac101, + 0x502db787, + 0x297ec00f, + 0xcff1a99d, + 0x32442a00, + 0xb587058b, + 0xc0d2502d, + 0xff740de0, + 0xa91a98cf, + 0xc0027680, + 0x9e69917c, + 0x682bb74d, + 0x5a2bb78c, + 0xa9116244, + 0x75080244, + 0x901cc002, + 0x0a040205, + 0x75062a0c, + 0x9344c001, + 0x9e510a18, + 0x7102d010, + 0x6d69d091, + 0x4002ba24, + 0x0555d110, + 0x75020982, + 0xd0109e92, + 0x9e9b19c2, + 0x0d30c130, + 0x4418b333, + 0x9140c000, + 0xaa41f010, + 0xa959f150, + 0x01b80d10, + 0x05b4c101, + 0x9301ffff, + 0xd01074c0, + 0xc00004ec, + 0xc1019184, + 0xc12a021a, + 0xc0100a40, + 0xda080902, + 0xc000a111, + 0xc1019160, + 0x5da0029a, + 0x0ac0c12a, + 0x9903c074, + 0xa031da08, + 0xb7869eb9, + 0x7502564d, + 0x9184c007, + 0x430cb7a0, + 0xb7cc0a10, + 0x008b6d4b, + 0x652bb74c, + 0x6f2db726, + 0xd00374ae, + 0x61441a44, + 0xd0137044, + 0xc0001124, + 0x9ea99146, + 0x4ccdb786, + 0x70480228, + 0xd0030902, + 0x9ea90922, + 0x674bb78c, + 0x6dd3b7ac, + 0xc0067500, + 0x74809124, + 0x9222c003, + 0x6f53b76c, + 0xc00276c0, + 0xb7669324, + 0xb746704d, + 0xb7866fd5, + 0xd110644d, + 0x02480527, + 0xc0027104, + 0xd05191a8, + 0x70c86e29, + 0x9114c002, + 0x6ecdb786, + 0x6917d051, + 0x71046a52, + 0x9006c002, + 0x7c4bb78c, + 0xc0c8010b, + 0xd0080938, + 0x0a08a941, + 0x19149ea2, + 0x2d7ccffe, + 0x72950a06, + 0x6ecbb58c, + 0x704bb58c, + 0x90f6c000, + 0x0e28d011, + 0xcffe9ea2, + 0xb79f2d7c, + 0x9e52786a, + 0x2a7ccffe, + 0x00ca0248, + 0x7c2bb72d, + 0x0992d011, + 0x7086cc12, + 0x430cb740, + 0xc0c80205, + 0xd2080a48, + 0xcc10aa01, + 0xc0c870c8, + 0xd0080944, + 0xcc12aa41, + 0xba1b70c8, + 0xfe744002, + 0x008b98c7, + 0x472bb50d, + 0x7c2bb50c, + 0xb7469ea9, + 0xb7866455, + 0xb7666fcd, + 0xd010704d, + 0x02460524, + 0x0124c101, + 0xc2000244, + 0xb5865a09, + 0xc002644d, + 0x008b92e0, + 0x702bb78c, + 0xc0027500, + 0xd2a29222, + 0x9ea95c88, + 0xb766009a, + 0xb76c5cb5, + 0xc0745a4b, + 0x008b985b, + 0xb766600d, + 0xc0005aad, + 0xb74d5a08, + 0x70c84733, + 0x91fcc000, + 0x04dad010, + 0xb72c009a, + 0x08a0742b, + 0xc0017293, + 0xd0119036, + 0xc0000e22, + 0x02009340, + 0xc00070c8, + 0x9ea99336, + 0x6bcdb786, + 0x514db746, + 0x71040238, + 0x9216c000, + 0x04dad010, + 0xb72c009a, + 0x1890742b, + 0xc0007293, + 0xd01190fc, + 0x9ea21e22, + 0x2d7ccffe, + 0xc0c8020b, + 0xd2080a48, + 0x9e52aa01, + 0x7088d010, + 0xc0c8010b, + 0xd0080944, + 0xd012a941, + 0x008b7104, + 0x472bb58d, + 0x7beeb79f, + 0x7c6eb7bf, + 0x7ceeb7df, + 0x7d6eb7ff, + 0x8c20c004, + 0xf0109c22, + 0x9e5baa61, + 0x430cb720, + 0xc0007500, + 0xb5869082, + 0xd00876ad, + 0xc01ca975, + 0xc00074be, + 0x020390e2, + 0x0a64c0da, + 0xa101d208, + 0xa979d008, + 0x74bec01c, + 0x90e2c000, + 0xc0da0203, + 0xd2080a68, + 0x0103a101, + 0xc0da9e8a, + 0x0a060940, + 0xa241d008, + 0x0d50c0dc, + 0xd0101a04, + 0xd008a241, + 0x0203a971, + 0x0a60c0da, + 0xa101d208, + 0xb7209c22, + 0xd1104314, + 0xb70c0497, + 0xb78c7c4b, + 0x75004829, + 0x48a2b340, + 0xc0c89e4c, + 0xd2080a48, + 0x9c22a801, + 0xb7a0a60d, + 0x9e5d4314, + 0x058b0307, + 0x0da0c0d8, + 0x09b2c00e, + 0x99affcb4, + 0x4314b760, + 0x0992c00a, + 0x0dc0c0ca, + 0x99a7fcb4, + 0x4314b760, + 0x0982c002, + 0x0da0c0d6, + 0x999ffcb4, + 0x4314b760, + 0xc0d409d2, + 0xfcb40dd0, + 0xb7609998, + 0xc04c4314, + 0xc0e609f2, + 0xfcb40dd0, + 0x058b9990, + 0xc0c6018b, + 0xc0040d80, + 0xfcb40d32, + 0x9e6899b3, + 0xb7869e69, + 0x097f4fac, + 0xc001040b, + 0x9e6c7520, + 0x0c38c0c8, + 0x0a64c0da, + 0x08a0c0de, + 0xa101d208, + 0xb5800a22, + 0xb7604029, + 0x9e6b4050, + 0x1a48d00d, + 0x050b0c82, + 0x443ab421, + 0xc0da9e69, + 0xc0da09e8, + 0x9e4d0d60, + 0xa161d008, + 0x018d9d0a, + 0x7332b56c, + 0xa0c2d010, + 0x76b4b526, + 0xc12a040b, + 0xc01008e0, + 0xd0080b02, + 0x9e44a961, + 0xc0da9e68, + 0xd2080a6c, + 0xd008a101, + 0xb74daa61, + 0xd0186fb2, + 0x7500a9c2, + 0xd0020a02, + 0xc1010a42, + 0xb58d0244, + 0xdffc6faa, + 0xd0127e7e, + 0xb7400d38, + 0xd022430c, + 0x020505a2, + 0x0a48c0c8, + 0xaa01d208, + 0xd0109e58, + 0xc0c87008, + 0xd0080944, + 0xd012a941, + 0x0c847104, + 0xb59a7644, + 0xb5c0462b, + 0xb5a0402b, + 0x0984412b, + 0x08880c04, + 0x9124fffe, + 0x430cb720, + 0x652bb78c, + 0xc000752a, + 0x9e699112, + 0xb58d0a16, + 0xc0007b2b, + 0x9e6890a0, + 0x7b32b52d, + 0x0d029e69, + 0x50b5b766, + 0x4e2db766, + 0x9883fe94, + 0x287ccffe, + 0xc0100a7a, + 0x1a747008, + 0x7008c012, + 0xb50e9e69, + 0xfe745bab, + 0x9e6899e4, + 0xb78c9e6a, + 0xc0dc65aa, + 0x75000960, + 0xd0010a02, + 0xb5800a42, + 0xc006448c, + 0xd0080a02, + 0xb720a241, + 0xb781430c, + 0x75045ead, + 0x93c4c000, + 0x5f35b761, + 0x4e2cb7a6, + 0x0992c006, + 0xd1320d02, + 0xb5a761d7, + 0xc0024e2c, + 0xfe340dc8, + 0x9e699810, + 0xb746000a, + 0xb5074e2d, + 0x02244e2d, + 0x7100d010, + 0x7088c812, + 0x4e2db547, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0xfe5d8c60, + 0xa60d9020, + 0x430cb7a0, + 0x07079e9d, + 0x030b008b, + 0x712bb78c, + 0x0b40c0da, + 0xa941d208, + 0x31c6e000, + 0xd0020a02, + 0x74800a42, + 0x6db3b54c, + 0x712bb58c, + 0x71b3b5ac, + 0x90e2c000, + 0x99e9fe74, + 0xd2080a02, + 0x7786a241, + 0x92d2c001, + 0x5d08d326, + 0xe0508520, + 0x94298044, + 0x94059428, + 0x0d829401, + 0x90e0c001, + 0xb78c008b, + 0xb5ac5b2b, + 0x75007133, + 0x9162c000, + 0x430cb720, + 0x67adb784, + 0xc0007502, + 0xc0009204, + 0x9ea99100, + 0x684bb78d, + 0xc0007500, + 0x008b9104, + 0x632bb78d, + 0xb58d1a04, + 0xff34632b, + 0x0d869b39, + 0x90a0c000, + 0x98aaff54, + 0xff340d8a, + 0x9e8599c1, + 0x430cb720, + 0x02039e6a, + 0x0a48c0c8, + 0xaa01d208, + 0x7088d010, + 0xc0c80103, + 0xd0080944, + 0xcc12a941, + 0x9ea97104, + 0xb74c0207, + 0xcffe694b, + 0x9e9a2a7c, + 0xb58d7480, + 0xb58d7ccb, + 0xc0017c4b, + 0x020b91a2, + 0x0a1cc0ca, + 0xaa01d208, + 0xc0017299, + 0x020390bc, + 0x0a1cc0a4, + 0xa901d208, + 0xc0007482, + 0xb78a93b4, + 0x71044629, + 0x9304c000, + 0x52abb78a, + 0xc0ca010b, + 0x0a040918, + 0x52abb58a, + 0x430cb720, + 0xa941d008, + 0x52abb78a, + 0x4002ba24, + 0xc0007104, + 0x1205911c, + 0x9060c000, + 0xb58a0a02, + 0x9e5052ab, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0x9c228c60, + 0x8420a61d, + 0x4314b7a0, + 0x00b6a19d, + 0xb78c040b, + 0xc10171ca, + 0x9e5b009a, + 0xb7cd7500, + 0xb76c7c2b, + 0xb72c6dd2, + 0xc0005a4a, + 0xb7869184, + 0x7502714c, + 0x91b2c000, + 0x634ab78d, + 0xc0007502, + 0x048b9112, + 0x564db786, + 0xc0087504, + 0x040b92a4, + 0x564cb786, + 0xc0007502, + 0x750490f4, + 0x9184c008, + 0x9360c005, + 0xc00074c0, + 0x9e6991c4, + 0x5dadb786, + 0x7c2bb7cc, + 0xd00e7500, + 0xc0070a62, + 0xc007935c, + 0x048b9360, + 0x704bb78c, + 0xc0007500, + 0xb7cd90c2, + 0xc0014753, + 0x040b93e0, + 0x5dccb786, + 0xd00e7500, + 0xc0010a62, + 0xba1b929c, + 0xff544003, + 0xb72099b1, + 0x9e82430c, + 0x5e2db781, + 0xc0007508, + 0xb7819344, + 0x1a045ead, + 0xc0007502, + 0xcffe9292, + 0xd0d12d7c, + 0x9e510964, + 0x7044c810, + 0xb78d048b, + 0xba247b4b, + 0x12684002, + 0x7088c812, + 0xc0009e96, + 0x040b9220, + 0x7b4ab74d, + 0x2d7ccffe, + 0xba129e51, + 0x02644002, + 0x7048d010, + 0xd0121164, + 0x9ea67104, + 0x2f7ccffe, + 0x430cb720, + 0xb78c048b, + 0xb741654b, + 0x0b9a5e2d, + 0xd009752a, + 0x74881bf6, + 0x92c4c000, + 0x5eadb781, + 0x75021a04, + 0x9212c000, + 0x7c4bb78c, + 0x03fed020, + 0xd019753c, + 0xb374027e, + 0xd0194434, + 0x0389024e, + 0x9060c000, + 0x040b9ebf, + 0x4e4cb7a7, + 0xc0017540, + 0xb72c9222, + 0xa09a5a52, + 0x6d4ab76c, + 0xc2009e4c, + 0x70c85a0d, + 0x90d4c001, + 0x402db743, + 0x5a0cc100, + 0xc000710a, + 0xd1a493f4, + 0xc1015985, + 0xc05405b4, + 0xa919994e, + 0x700a6005, + 0x9286c000, + 0xb74c040b, + 0xd0117c4a, + 0x9ea60e68, + 0xcffe7184, + 0xc0002f7c, + 0xc00290d2, + 0xc0000fca, + 0x126490a0, + 0x0bc4d0d2, + 0x9e739e69, + 0x7c2bb74c, + 0x0675d110, + 0x70c8d010, + 0xc002112e, + 0x040b9180, + 0x5e4cb781, + 0xc0027508, + 0xb78d9162, + 0xb7465a4a, + 0xb74c6dcc, + 0xba246d52, + 0xe0004002, + 0xc10103c4, + 0xc0011194, + 0x74c093a2, + 0x9342c001, + 0x5dd4b766, + 0xcc120f06, + 0xc18072cc, + 0xc1015a05, + 0xc05405b8, + 0x9e82990a, + 0x4002ba2e, + 0x018b9ebb, + 0x9916fe54, + 0x6a67d011, + 0xc2000208, + 0x9ea25a0b, + 0x2d7ccffe, + 0xc000729d, + 0x700c91e4, + 0x9182c000, + 0x0a7ecffe, + 0xb346700c, + 0xd110444a, + 0x9ea2066d, + 0x2d7ccffe, + 0x9e539e69, + 0x7c2bb74c, + 0x0a26d011, + 0x70c8d010, + 0xd012190c, + 0x03097104, + 0x2b7ccffe, + 0x430cb760, + 0xc0c80207, + 0xd2080a48, + 0xd010aa01, + 0x01077188, + 0x0944c0c8, + 0xa941d008, + 0x7104d012, + 0x040baa9d, + 0x64ccb746, + 0x00bad020, + 0xb74c0009, + 0xcffe4851, + 0x00da287c, + 0x009ac101, + 0x76800120, + 0x64ccb546, + 0x7c2bb50d, + 0x90e4c000, + 0x4949b78c, + 0xc0007500, + 0x020790e2, + 0x0a48c0c8, + 0xa801d208, + 0x7deeb79f, + 0x7e6eb7bf, + 0x7eeeb7df, + 0x7f6eb7ff, + 0x8c20c002, + 0xa61d9c22, + 0x4314b7c0, + 0x07850287, + 0x9e769e71, + 0x712bb78c, + 0x0b40c0da, + 0x04a4d010, + 0xa941d208, + 0x009cc101, + 0x3246e000, + 0x742bb7ec, + 0x9e710a02, + 0x0a42d002, + 0xb58c7480, + 0x0687712b, + 0x71abb56c, + 0x6db3b54c, + 0x90e2c000, + 0x9bc1fe54, + 0xd2080a02, + 0x7746a241, + 0x92d2c001, + 0x5d08d2a6, + 0xe0508520, + 0x94298044, + 0x94059428, + 0x0d829401, + 0x90e0c001, + 0xb78c9e71, + 0xb5ac5b2b, + 0x7500712b, + 0x9162c000, + 0x430cb720, + 0x67adb784, + 0xc0007502, + 0xc0009204, + 0x9e719100, + 0x682bb78d, + 0xc0007500, + 0x9e719104, + 0x632bb78d, + 0xb58d1a04, + 0xff34632b, + 0x0d869911, + 0x90a0c000, + 0x9a82ff34, + 0xff140d8a, + 0x02819b99, + 0x4314b7a0, + 0xc0c89e6c, + 0xd2080a48, + 0xd010aa01, + 0x9e6a7148, + 0x0944c0c8, + 0xa941d008, + 0x7104d012, + 0xba349e69, + 0xb7464002, + 0x7482712d, + 0x9172c003, + 0x632bb78d, + 0xc0037502, + 0xc00390d2, + 0x9e6992c0, + 0x6cadb766, + 0x90a0c000, + 0xb7669e69, + 0x9e696bad, + 0x5e2db781, + 0xc0007502, + 0x76809124, + 0x90c4c000, + 0x50adb746, + 0x9060c000, + 0x11340902, + 0xcc120a02, + 0x9e697088, + 0xb78c9e9b, + 0xb7466dab, + 0xb766562d, + 0xc2004fad, + 0xc1015a08, + 0x748200ca, + 0x5b35b746, + 0x9172c002, + 0xb7869e69, + 0x75005dad, + 0x92dac000, + 0x4e2db746, + 0xc0007295, + 0x7540923a, + 0x90e2c000, + 0x5a07c180, + 0xc00072d9, + 0xc10090fc, + 0x71485a07, + 0x9094c000, + 0x4002ba37, + 0xb78c9e69, + 0x752a652b, + 0x9152c000, + 0x0a78d011, + 0x7188d010, + 0x1978d011, + 0x9160c000, + 0xb74d9e69, + 0xba127b2b, + 0x02744002, + 0x7188d010, + 0xd0121174, + 0xba347104, + 0xc0004002, + 0x9e699280, + 0xb7860902, + 0xb7466c2d, + 0xc1016bb5, + 0xd4121244, + 0xfe347088, + 0xf0129aab, + 0xfffc0900, + 0xfffc9204, + 0x9e6c9260, + 0x0a48c0c8, + 0xaa81d208, + 0x718ad410, + 0xaa1dd3e8, + 0x7148d412, + 0x4002ba2d, + 0x058f018b, + 0x9be8fe34, + 0x0a029e71, + 0x6dadb586, + 0x5a2bb58d, + 0x7c2bb50c, + 0x430cb740, + 0x2afccffe, + 0xc0c80205, + 0xd2080a48, + 0xd410aa01, + 0xc0c87148, + 0xd0080944, + 0xd412aa41, + 0x000b7148, + 0x7e6eb79f, + 0x7eeeb7bf, + 0x7f6eb7df, + 0x7feeb7ff, + 0x8c00c002, + 0xa61d9c22, + 0xb7808460, + 0x09024d8c, + 0x4038b960, + 0xa101d208, + 0xa105d208, + 0x0a20c146, + 0x9341ffff, + 0x0882c021, + 0x08d0c006, + 0xaa619d1d, + 0x2a7cc00e, + 0xc0007506, + 0x0d8a90f2, + 0x9bd0fcf4, + 0x9240ffff, + 0x0902c021, + 0x0940c006, + 0xab629d2d, + 0xabe29d2d, + 0xa9629d2d, + 0x9d2da11a, + 0x9e74a9e2, + 0x478cb720, + 0x2a00c7f0, + 0x5aa1d224, + 0xd011a196, + 0x6a520e54, + 0xd0310242, + 0xf2080b48, + 0x750caa41, + 0x9204c000, + 0x6e59d051, + 0x498cb740, + 0x0dc2c809, + 0x02440d02, + 0x0db0c5c2, + 0xa10ef208, + 0xa182f208, + 0x7f80c010, + 0x9322c003, + 0xfcb4058b, + 0xa91a9a23, + 0xe0719e7b, + 0xd1f28d00, + 0xfd342dee, + 0xb79f98d2, + 0xc01c7468, + 0xc000753e, + 0xfcf490c4, + 0xb51f9b9e, + 0xb77f7468, + 0x0d067470, + 0xc00e55cc, + 0xfd142dfc, + 0x9e6c9bb1, + 0x4c8cb720, + 0x6a22c146, + 0x7468b77f, + 0x008b02c2, + 0x5aadb723, + 0x9ead058b, + 0xc06ca091, + 0x008b0ee0, + 0x5ab5b5c3, + 0xaba1f210, + 0xa3a2f210, + 0xc300a919, + 0xb7c35d3d, + 0xb5435bb5, + 0xaa155bad, + 0xc06e030b, + 0x9e5a0b00, + 0xabc2f208, + 0xf2082d04, + 0xfd14a241, + 0x008b9867, + 0x7470b77f, + 0xa3a1f210, + 0x5bb5b5c3, + 0xa3c2f208, + 0x0d06aa11, + 0xc00e55cc, + 0xb5832dfc, + 0xfd345aad, + 0xb7409802, + 0xb740490c, + 0xf0084d14, + 0x7508aa41, + 0x9142c000, + 0xc0007504, + 0xd0109144, + 0x7500aa41, + 0x90a2c000, + 0xf0080886, + 0xb760a0c1, + 0x09504894, + 0x0d20c146, + 0xfffa7097, + 0xffff9162, + 0x058b9100, + 0x998ffcb4, + 0xc0017400, + 0x9e6c9044, + 0x4c8cb720, + 0x6a22c146, + 0x4c8cb740, + 0xc06c02c2, + 0xd2080a80, + 0xa916a9a2, + 0xd1a2099a, + 0x0d845c90, + 0x00940098, + 0x4db5b543, + 0x4c35b5c3, + 0x4cb5b5e3, + 0xb583aa19, + 0xc0344d2d, + 0xd2089adb, + 0xf208a021, + 0x7508aa41, + 0x9124c000, + 0xf2080886, + 0xc000a0c1, + 0xfcf49080, + 0x058b9af3, + 0x995dfcb4, + 0x0d927400, + 0x9324ffff, + 0x91c0fff8, + 0xb740a60d, + 0x0205430c, + 0x0a10c0a4, + 0xaa01d208, + 0xc0037500, + 0x9e9292a4, + 0x0d38c0a2, + 0xa941d010, + 0xc0007480, + 0x0a0492e4, + 0xa241d010, + 0x430cb780, + 0xc0a29e93, + 0xd2080a40, + 0xfd54a101, + 0xb7809a5f, + 0xc0a4430c, + 0xd2080a10, + 0x7500aa01, + 0x9304c002, + 0x430cb720, + 0xc09c0203, + 0xd2080a18, + 0x7500aa01, + 0x91c2c002, + 0x4729b7aa, + 0x4814b7c0, + 0x9220c001, + 0xaa2df210, + 0xc000750c, + 0x9eaa93e4, + 0x55e80d86, + 0x2dfcc00e, + 0x9ad8fd14, + 0x478cb720, + 0x4508b780, + 0x29ded3f2, + 0xb58100e2, + 0xfd9468a9, + 0x0a029a33, + 0xa22df210, + 0x0a46c809, + 0x0a30c656, + 0xa221f210, + 0x90c0c001, + 0x46a9b78a, + 0x02857148, + 0x9124c000, + 0xfcf40d92, + 0xb7209a87, + 0xb7aa430c, + 0xb7204729, + 0xba2d430c, + 0xd0514000, + 0x02036b59, + 0xc0a20103, + 0xc0a40a40, + 0xd2080920, + 0xd008a902, + 0xd120aa41, + 0xd01102ed, + 0x72991952, + 0x9386fffd, + 0x7eeeb79f, + 0x7f6eb7bf, + 0x7feeb7df, + 0x9c228c60, + 0x8440a61d, + 0x430cb780, + 0x0a10c0a4, + 0xaa01d208, + 0xc00a7500, + 0xfd9490a4, + 0xb7209b00, + 0x0203430c, + 0x0a10c0a4, + 0xa901d208, + 0xc0097480, + 0xc0069324, + 0xd2081a78, + 0x7500aa01, + 0x91a2c005, + 0xc0a40203, + 0xb7ca0a1c, + 0xd2084629, + 0x9e97ab81, + 0x1962d011, + 0xd020627d, + 0x068f0328, + 0xba26110f, + 0xa1194000, + 0xc002a211, + 0xb78a9000, + 0xc10146a9, + 0x02d8029a, + 0x99bcc034, + 0x0e72d011, + 0x0aa0c0a2, + 0x75889ea7, + 0x4001ba3f, + 0xa031d208, + 0x9324c000, + 0xba249e6c, + 0x75044000, + 0x9264c000, + 0xc00075c4, + 0xb7209204, + 0xb78a430c, + 0xd11046a9, + 0x02420659, + 0x0a20c0a2, + 0xa911d208, + 0xd2080904, + 0xb720a111, + 0xb78a430c, + 0xf11046a9, + 0x0e840659, + 0x9ea20242, + 0xc0a20109, + 0xc0a20d20, + 0xc000093c, + 0xd01090c2, + 0xd008aa51, + 0xa911a245, + 0x058da91a, + 0x73d5018d, + 0xb7200764, + 0xfffd430c, + 0xb78a9344, + 0x09024729, + 0x02189e93, + 0x0a40c0a2, + 0x9c8bc810, + 0xd2080005, + 0xc002a105, + 0xb7209000, + 0xb78a430c, + 0xd11046a9, + 0xc2000639, + 0x00c25a08, + 0x46adb505, + 0x430cb720, + 0x46a9b78a, + 0x0096c101, + 0xc0a20098, + 0xb76008c0, + 0xc00040a9, + 0xb78b91a0, + 0xb742534a, + 0xb7455b2b, + 0x624446d5, + 0x0244c101, + 0x46cdb585, + 0x430cb720, + 0xd0120136, + 0xb78a0932, + 0xd02046a9, + 0xd1100022, + 0xc2000639, + 0x02425908, + 0x0a20c0a2, + 0xaa11d208, + 0x00a2d020, + 0x9e537106, + 0x29fcc00e, + 0x93b2fffe, + 0xfffe0d84, + 0x0d829041, + 0x992cfd54, + 0x430cb720, + 0xc0a40203, + 0xd2080a10, + 0x7680a902, + 0x9344c003, + 0x1a78c006, + 0xaa01d208, + 0xc0037500, + 0x020390e2, + 0x0a1cc0a4, + 0xaa01d208, + 0x4629b74a, + 0x4731b7aa, + 0x71040705, + 0x4001ba2d, + 0x0d7ecfff, + 0xcffe0189, + 0xd0510d30, + 0xb3236e59, + 0x65554432, + 0x478cb740, + 0x0528c101, + 0x01449e6e, + 0x1fa2d031, + 0x29fcc00e, + 0x0aa2d351, + 0x0fa6d012, + 0xc000a195, + 0xfd149360, + 0xb780998f, + 0xd3f24508, + 0xd20829ee, + 0xfd94a221, + 0xc80998ed, + 0xc6560d46, + 0x9e7a0d30, + 0xa166e250, + 0x1a62d011, + 0xe0500d02, + 0xba34a146, + 0x1ad04000, + 0x430cb720, + 0x165cd010, + 0xd0240906, + 0xb72a51d0, + 0xa9154729, + 0x2dfcc00e, + 0x10940f04, + 0xfffe7102, + 0xc000931a, + 0xfcf49080, + 0xb7809931, + 0x0d92430c, + 0xc0a29ea2, + 0xc0a40a3c, + 0xd2080d1c, + 0xd010a901, + 0x7088aa41, + 0x9226ffff, + 0x7d6eb79f, + 0x7deeb7bf, + 0x7e6eb7df, + 0x7eeeb7ff, + 0x8c40c002, + 0x91a0fddd, + 0x7d6eb79f, + 0x7deeb7bf, + 0x7e6eb7df, + 0x7eeeb7ff, + 0x8c40c002, + 0xa61d9c22, + 0xb7c08460, + 0xa1954314, + 0xaae1d808, + 0xb706040d, + 0x9e715654, + 0xa012048d, + 0x6dabb72c, + 0x7540068d, + 0xb72da099, + 0x9e5e5453, + 0x0ec8c0c8, + 0x7d74b53f, + 0x9102c000, + 0xaaa2d210, + 0x7df4b5bf, + 0x9380c000, + 0xb76c040d, + 0xb7866d4a, + 0xb75f69cc, + 0xd1a47d6c, + 0x59085985, + 0x05b8c101, + 0x05b4c101, + 0x9867c034, + 0xaa21d210, + 0x7008c010, + 0x700ac012, + 0x287ccffe, + 0x7decb51f, + 0xb5c69e71, + 0xb7205aad, + 0xb781430c, + 0x75025e2d, + 0x90c4c000, + 0x9b5bfe14, + 0x90e0c000, + 0xc0007508, + 0xfe3490e4, + 0x9e839912, + 0x90a0c000, + 0xb766048d, + 0x040d4e55, + 0x5accb746, + 0x6accb786, + 0x6b54b746, + 0x6bccb766, + 0xc1011244, + 0x01261524, + 0x6accb586, + 0x6b54b546, + 0x1126c101, + 0x6c4cb566, + 0x0a02c201, + 0x7088c810, + 0x0a02ce01, + 0x7088c812, + 0x6bccb546, + 0xb740a895, + 0x7480402b, + 0x92a4c009, + 0x430cb7e0, + 0xb7869eb9, + 0x7502564d, + 0x9024c005, + 0x6e4bb78c, + 0x6e4bb54c, + 0x7d3edffc, + 0x6f4bb58c, + 0x9144c004, + 0x674bb78c, + 0xc0047500, + 0xb76690a4, + 0xb78c5acd, + 0xd1a4744b, + 0xc8025949, + 0x0d047280, + 0x4002ba24, + 0x094cc002, + 0x7104d010, + 0x194cc002, + 0x7104d012, + 0x5d0cb740, + 0x4002ba24, + 0xca200248, + 0xba12aa05, + 0x9e524001, + 0x7053b76c, + 0xba2451e9, + 0x62474002, + 0xc1010936, + 0x76c01124, + 0x5389d224, + 0x9084c001, + 0x6fcbb78c, + 0xc0027506, + 0xb74692d4, + 0xb7666fd5, + 0xd051704d, + 0x70c86e27, + 0x90f4c000, + 0x5c4db786, + 0xc00073d9, + 0x9eb89232, + 0x5e05d3a2, + 0x5c4cb746, + 0xc0027104, + 0xd0109014, + 0xc1010624, + 0x70c80244, + 0x9334c001, + 0x430cb7c0, + 0xc0020a06, + 0x008d09b2, + 0x6eabb58c, + 0x6e2bb58c, + 0x430cb7a0, + 0xc0de9eab, + 0xc0dc0aa0, + 0xd2080d80, + 0xfc74aaa2, + 0x9eb199a0, + 0xb7869eb3, + 0xb74c5acd, + 0xd208744b, + 0xb586a2a2, + 0x0a02594d, + 0x6fcbb58c, + 0x734bb54c, + 0x0d90c0da, + 0xfc7409a2, + 0xb720998c, + 0xb781430c, + 0x75045e2d, + 0x9124c000, + 0x0a049eb0, + 0x7b4ab58d, + 0x9060c000, + 0x008f0f82, + 0x5c2db786, + 0x6d7bd012, + 0x01280148, + 0x0524c101, + 0xb5465d0d, + 0xa9195c35, + 0x9e9b0982, + 0xd1100224, + 0x00870669, + 0xc0ce9ea2, + 0xc0000d48, + 0xd8109120, + 0xd831aa41, + 0xba24a0c5, + 0x01b84002, + 0x040da89a, + 0x6fcab74d, + 0x0632d010, + 0x71040d84, + 0x9238ffff, + 0xc0007640, + 0x05839142, + 0xcffe1d84, + 0xba1b2dfc, + 0xfe144002, + 0x040d9be7, + 0x6e4ab78c, + 0xc0037500, + 0xa8919002, + 0xc0027442, + 0xfe149384, + 0x74009a39, + 0x430cb720, + 0x90c2c000, + 0x6cadb746, + 0x9080c000, + 0x6badb746, + 0x5e2db781, + 0xc0007502, + 0x74009124, + 0x90c4c000, + 0x50adb786, + 0x9060c000, + 0x12440a02, + 0xd0120a82, + 0x7500710a, + 0x93fcc001, + 0xb766048d, + 0xb7664fcd, + 0xb78d6bd5, + 0xb746654b, + 0xd1204e55, + 0xb74d11b7, + 0xc101634b, + 0xb78d65b9, + 0x65b563cb, + 0x12449eaa, + 0x65b9c101, + 0x9845fdf4, + 0xb786040d, + 0x9e836acc, + 0xc0007500, + 0xb5a69096, + 0x9e716acc, + 0x6aadb786, + 0x632bb74d, + 0x6b35b746, + 0x5aadb766, + 0x0246c101, + 0xc1011904, + 0xb5861526, + 0xb54d6aad, + 0xb546632b, + 0xfef46b35, + 0xc0009bb3, + 0xa89290c0, + 0xc0017640, + 0x040d90c2, + 0xb77fa891, + 0xb7867dec, + 0xb74674cc, + 0x7442754c, + 0x09040246, + 0x74ccb586, + 0x754cb546, + 0x9142c000, + 0xc0007442, + 0x74449246, + 0x9184c007, + 0x9300c004, + 0xb78d040d, + 0xb74c684a, + 0x0a046fca, + 0xb58d0904, + 0xb54c684a, + 0xaa196fca, + 0x048d9e71, + 0x67adb746, + 0x6735b746, + 0xc2000a04, + 0xc1015a0c, + 0xb54600cc, + 0xb54664ad, + 0xaa196435, + 0x694db746, + 0xc200040d, + 0xd1205a08, + 0x0a0200cd, + 0x684db546, + 0x694cb586, + 0x674cb586, + 0x67ccb586, + 0xb780a895, + 0x7500402b, + 0x9344c002, + 0x5accb746, + 0xb546a999, + 0xb79f5b4d, + 0x00b67b6a, + 0x009cc101, + 0x742bb58c, + 0x430cb720, + 0x5e2db781, + 0xc0027504, + 0xb76690e4, + 0x74c05dcc, + 0x90c4c000, + 0x0d82c010, + 0x9080c001, + 0xc1807086, + 0xc0005a07, + 0xd02091bc, + 0x5da811a6, + 0x05b8c101, + 0x9a7ac014, + 0x0800c040, + 0x9180c000, + 0x11b4d020, + 0xc1015da8, + 0xc01405b8, + 0xc0409a6f, + 0x10400a02, + 0x0a02c100, + 0x7008d010, + 0xc4120902, + 0x9e8b7104, + 0xb71fa89a, + 0x05127df4, + 0xc0d0052c, + 0xd8100d60, + 0x9e49a941, + 0x65b0d031, + 0x02420224, + 0x5a08c200, + 0xc1010904, + 0x290400cc, + 0x612db566, + 0xa141d810, + 0x5f35b566, + 0x7640a892, + 0x9384c002, + 0xb78d040d, + 0x0a0468ca, + 0x68cab58d, + 0x9280c002, + 0x7d6cb73f, + 0xc0007440, + 0xb7209282, + 0xb781430c, + 0x75025e2d, + 0x91a4c000, + 0xb746048d, + 0xc1005acd, + 0x02445a7d, + 0x5a07c200, + 0xb5860244, + 0x040d5acd, + 0x7b6ab73f, + 0x5ad4b7a6, + 0x734ab52c, + 0x5954b5a6, + 0x430cb7a0, + 0xb7819ea9, + 0x75025e4d, + 0x92a4c000, + 0x9904fe14, + 0xc0007400, + 0x9ea89204, + 0x64cab78d, + 0x7510c004, + 0x9134c000, + 0xb5a69e71, + 0xb73f5b35, + 0xb52c7b72, + 0x040d7433, + 0x714cb786, + 0xc0007502, + 0xb7669264, + 0xb7665ad4, + 0xc0144e4c, + 0x741099f7, + 0x915cc000, + 0x1980d031, + 0x5987a99a, + 0x4002ba1b, + 0x9a7efe14, + 0x430cb720, + 0x5e2db781, + 0xc0017508, + 0x9e719302, + 0x712db786, + 0xc0017502, + 0xb7869244, + 0x7504562d, + 0x91a2c001, + 0x542bb78d, + 0xc0007500, + 0xa89992a4, + 0xb746048d, + 0x58885acd, + 0x009cc101, + 0x5cadb726, + 0x02125908, + 0x70880242, + 0x90d6c000, + 0x09ffa99a, + 0x9260c000, + 0x040da899, + 0x5accb746, + 0xc1015888, + 0xb726009c, + 0x01245cad, + 0x02420212, + 0xc0007088, + 0xa99a90dc, + 0xfe140986, + 0xa8959a41, + 0xb5800a02, + 0xb58040ab, + 0xb7a040ad, + 0x9ea9430c, + 0x5e55b7a1, + 0xc0037744, + 0x774893a2, + 0x9342c003, + 0x75cdb786, + 0xc0017500, + 0xfe149284, + 0x74009887, + 0x91e2c000, + 0xb78e9ea8, + 0xb7445bca, + 0x708867cc, + 0xd0040a02, + 0xb5860a42, + 0xc00075cc, + 0x77429380, + 0x90a2c000, + 0xc0007748, + 0x008b9244, + 0x67adb784, + 0x4e2db746, + 0x50b5b746, + 0x71156245, + 0xd00b0a02, + 0xb5860a42, + 0xc00075ad, + 0x9ea990c0, + 0xb5860a06, + 0x9ea875cd, + 0x75ccb786, + 0xc0027500, + 0xb7209062, + 0xb781430c, + 0x75025e2d, + 0x91a4c008, + 0x4e35b746, + 0x4fadb746, + 0x6e2fd011, + 0xc0087088, + 0xd0119096, + 0x76800e2e, + 0x4458b342, + 0x5d0fd122, + 0x9140c000, + 0x5b2bb78c, + 0xc0007500, + 0x02249082, + 0x59070144, + 0x50adb786, + 0x5a07c200, + 0x7088c810, + 0x6badb786, + 0xc0007104, + 0xa89590d6, + 0xb5801228, + 0xa89640ad, + 0x40cdb740, + 0xc0007480, + 0x0a0691a2, + 0x40cbb580, + 0xd0121a04, + 0x0a7c7088, + 0x5a17c200, + 0x40cdb580, + 0x0902a916, + 0x4314b7c0, + 0xa141d810, + 0x4314b7a0, + 0xb721040b, + 0xb7cc5e54, + 0x76486dca, + 0x9084c002, + 0x5eccb781, + 0x75021a04, + 0x9032c001, + 0x4e4cb7a6, + 0xc0069e92, + 0xb5a70992, + 0xb7204e4c, + 0xb721430c, + 0x60d35f2d, + 0x0994d0d2, + 0x9a33fdd4, + 0x000a9e69, + 0x4e2db746, + 0x4e2db507, + 0xd0100224, + 0xc8127100, + 0xb5477088, + 0xc0044e2d, + 0x048b9100, + 0x6ccdb786, + 0x4fcdb7a6, + 0xfe1412d8, + 0x000a9864, + 0x0a02c040, + 0x7008c012, + 0xb786040b, + 0xb5074e4c, + 0xc2004e4c, + 0x70085a07, + 0x9228c003, + 0x0a06a895, + 0x402bb580, + 0x9160c003, + 0xb746040b, + 0xb74c4e54, + 0xba2e6e4a, + 0xd0104002, + 0x74800624, + 0x0244c101, + 0x5987c200, + 0x9144c000, + 0x5888c280, + 0x009ac101, + 0x5b2db786, + 0x70c8cc12, + 0x76429e69, + 0x4fb5b766, + 0x6badb786, + 0x1539d110, + 0x92e4c000, + 0x6e2fd011, + 0xc00072d9, + 0xd0119136, + 0x76800e26, + 0x4458b342, + 0x5d8bd122, + 0x0a02c040, + 0x7088d012, + 0xb587048b, + 0xc0004e4d, + 0xc1019080, + 0x70860124, + 0x91d6c000, + 0x448cb780, + 0xc0007500, + 0x748090a2, + 0x90dac000, + 0x0a06a915, + 0xa241d808, + 0x992ffe14, + 0x10010d02, + 0xc0129e53, + 0x74007006, + 0x92dac000, + 0x430cb720, + 0x5e2db781, + 0xc0007504, + 0x9e6c9244, + 0xc10100da, + 0xc0c8009a, + 0xb74c0a48, + 0xd208742b, + 0x7088aa01, + 0x90a8c000, + 0xda08aa15, + 0xa816a102, + 0x404ab780, + 0xc0007500, + 0x9eb390c2, + 0xfe140992, + 0x9e7198f3, + 0x632bb78c, + 0xc0007500, + 0xa8969222, + 0xb5800a02, + 0xc000404b, + 0xb7869160, + 0xb746562d, + 0x75024e2d, + 0x9124fff8, + 0x9000fff8, + 0x7ceeb79f, + 0x7d6eb7bf, + 0x7deeb7df, + 0x7e6eb7ff, + 0x8c60c002, + 0xa68d9c22, + 0x02059e9d, + 0x29fccffe, + 0x2a7ccffe, + 0xd1240705, + 0xd0325941, + 0x07876046, + 0x5dc1c280, + 0xd1310285, + 0xc1016527, + 0xd02260c7, + 0x01145e41, + 0x704601a8, + 0x6426d031, + 0x9094c000, + 0x0804c001, + 0x665cd031, + 0x615fd132, + 0x5941c180, + 0xc1010104, + 0xcffe0244, + 0xcffe29fc, + 0x02442c7c, + 0xc10159c0, + 0x9ea001b0, + 0xb7bf0007, + 0xb7df7eee, + 0xb7ff7f6e, + 0x8c607fee, + 0x9e989c22, + 0x09020802, + 0x9140c000, + 0x08029e98, + 0x4530d010, + 0x72c0cc14, + 0x7200c014, + 0xc18072c0, + 0xe0095d09, + 0xf0127204, + 0xc0005d04, + 0x72c49254, + 0x0804d004, + 0x15b4d024, + 0xd00472c0, + 0xd0240802, + 0xe00015b0, + 0x11813124, + 0x442ab330, + 0x72c09c22, + 0xffff0886, + 0xc40293a6, + 0xd06572c0, + 0xd0652c9e, + 0xc8023c9e, + 0xd0657200, + 0xd0652d2e, + 0xe0003d2e, + 0x9e531514, + 0x5408d01a, + 0x50acd01a, + 0xd01472c0, + 0xd0240002, + 0xe08015b0, + 0x5c055885, + 0x9304ffff, + 0x3124e000, + 0xb3301181, + 0x9c22442a, + 0x9d3a9e64, + 0x0e46c809, + 0x1e06b09b, + 0x9dc39ea4, + 0xe0009e58, + 0x15873400, + 0x482ab330, + 0x9e649c22, + 0x0e46c809, + 0x1d66b09b, + 0x9e589ea4, + 0x00009c22, + 0x87c2c809, + 0x0e60b060, + 0x87c2c809, + 0x0b80b060, + 0x87c2c809, + 0x0ac0b060, +}; + +unsigned int all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_data[] = { + 0x00000000, + 0x00000000, + 0x0000ff00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x809000b0, + 0x809198c8, + 0x8288f08a, + 0x8288f10c, + 0x8288f1e0, + 0x8288f2a8, + 0x8288f2b4, + 0x8288f214, + 0x8288f208, + 0x8288f1e8, + 0x8288f2c8, + 0x8288f1ec, + 0x8288f1f0, + 0x8288f2d0, + 0x8288f2d8, + 0x8288fd1c, + 0x8288f998, + 0x8288f7e4, + 0x8288f7e7, + 0x8288fd1e, + 0x82899618, + 0x82899620, + 0x82899624, + 0x82899626, + 0x8289962a, + 0x8289962e, + 0x82899632, + 0x82899636, + 0x8289963a, + 0x82899640, + 0x828996a0, + 0x828996a8, + 0x828996ac, + 0x828996b0, + 0x828996b4, + 0x828996bc, + 0x828996c7, + 0x8289c35b, + 0x8289c350, + 0x8289c360, + 0x8288efa8, + 0x8288f012, + 0x8288f022, + 0x8288f024, + 0x8288f02c, + 0x8288f03c, + 0x8288f04c, + 0x8288f14e, + 0x8288f1b8, + 0x80901728, + 0x80901728, + 0x809163cc, + 0x8091c3f0, + 0x8090901c, + 0x8091c1d8, + 0x8090b7d4, + 0x8090abe4, + 0x80901cc0, + 0x8090515c, + 0x809018e0, + 0x80901728, + 0x80901728, + 0x80901728, + 0x80901728, + 0x80901728, + 0x80901728, + 0x80906738, + 0x80906678, + 0x80916060, + 0x80906010, + 0x80901728, + 0x80901728, + 0x01030004, + 0x01010102, + 0x02010101, + 0x04000301, + 0x01030004, + 0x01010102, + 0x02010101, + 0x04000301, + 0x0d080300, + 0x00100b06, + 0x00584aaf, + 0x007f1410, + 0x005030c6, + 0x007f500c, + 0x00027dac, + 0x000021f5, + 0x000308d1, + 0x0000057a, + 0x00260019, + 0x003f0032, + 0x0058004b, + 0x00710064, + 0x008a007d, + 0x00a30096, + 0x00bc00af, + 0x00d500c8, + 0x00ee00e1, + 0x010700fa, + 0x01070107, + 0x01070107, + 0x01070107, + 0x01070107, + 0x01070107, + 0x00000107, + 0x00200040, + 0x001002ab, + 0x015500cd, + 0x00080249, + 0x00cd01c7, + 0x0155005d, + 0x0249013b, + 0x00040111, + 0x01c700f1, + 0x00cd01af, + 0x005d00c3, + 0x01550059, + 0x013b0029, + 0x0249025f, + 0x01110235, + 0x00020021, + 0x00f1001f, + 0x01c70075, + 0x01af006f, + 0x00cd0069, + 0x00c30019, + 0x005d017d, + 0x0059005b, + 0x015502b9, + 0x002900a7, + 0x013b0283, + 0x025f0135, + 0x02490095, + 0x0235023f, + 0x0111008b, + 0x00210219, + 0x00010041, + 0x0b060600, + 0x0c0b0a06, + 0x0a0b0c06, + 0x0c0d0c0c, + 0x0d0d0c06, + 0x0b0b0c0c, + 0x0e0d0a0d, + 0x0a0d0e0e, + 0x0c0d0a06, + 0x0c0e0c0e, + 0x0e0d0a0d, + 0x0f0c0c0c, + 0x0f0b0d0e, + 0x0d0f0e0e, + 0x0d0f0f0f, + 0x0c0b0f0e, + 0x00140006, + 0x001a0016, + 0x0020001c, + 0x00280024, + 0x0034002c, + 0x00400038, + 0x00500048, + 0x00680058, + 0x00800070, + 0x00a00090, + 0x00d000b0, + 0x010000e0, + 0x01400120, + 0x01a00160, + 0x020001c0, + 0x02800240, + 0x034002c0, + 0x04000380, + 0x05000480, + 0x06800580, + 0x08000700, + 0x0a000900, + 0x0d000b00, + 0x10000e00, + 0x14001200, + 0x1a001600, + 0x00001c00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x01010000, + 0x02020201, + 0x04030303, + 0x05040404, + 0x00000005, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x1234baac, +}; + +unsigned int all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_textreloc[] = { + 0x00000000, +}; + +unsigned int all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_datareloc[] = { + 0x00000000, +}; + +unsigned int all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_textrelocfulladdr[] = { + 0x00000000, +}; + +unsigned int all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_textreloctype[] = { + 0x00000000, +}; + +struct IMG_COMPILED_FW_BIN_RECORD simg_compiled_all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1 = { + /* unsigned int ui32TextSize, ui32DataSize; */ + 15278, 13643, + /* unsigned int ui32DataOrigin, ui32TextOrigin; */ + 0x8288eeb8, 0x80900000, + /* unsigned int ui32TextRelocSize, ui32DataRelocSize; */ + 0, 0, + + /* + * unsigned int ui32Pipes; + * unsigned char *sFormat, *rcMode; + * unsigned int ui32FormatsMask, ui32HwConfig; + */ + 2, "ALL_CODECS", "ALL", 31, 1, + + /* unsigned int ui32IntDefineCount; */ + 5, + /* unsigned char **pscIntDefineNames; */ + all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_define_names_array, + /* unsigned int *pui32IntDefines; */ + all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_define_values_array, + + /* + * unsigned int *pui32Text, *pui32Data; + * unsigned int *pui32TextReloc, *pui32DataDeloc; + * unsigned int *pui32TextRelocFullAddr, *pui32TextRelocType; + */ + + all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_text, + all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_data, + all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_textreloc, + all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_datareloc, + all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_textrelocfulladdr, + all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1_textreloctype, +}; + +/* Py_Return simg_compiled_all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1 */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_binaries/include_all_fw_variants.h b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_binaries/include_all_fw_variants.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_binaries/include_all_fw_variants.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_binaries/include_all_fw_variants.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef __INCLUDE_ALL_VARIANTS_INC_INCLUDED__ +#define __INCLUDE_ALL_VARIANTS_INC_INCLUDED__ + +#define INCLUDE_ALL_VARIANTS_TEMPLATE_VERSION (1) + +#define FW_BIN_FORMAT_VERSION (2) + +struct IMG_COMPILED_FW_BIN_RECORD { + unsigned int text_size, data_size; + unsigned int data_origin, text_origin; + unsigned int text_reloc_size, data_reloc_size; + + unsigned int pipes; + unsigned char *fmt, *rc_mode; + unsigned int formats_mask, hw_config; + + unsigned int int_define_cnt; + unsigned char **int_define_names; + unsigned int *int_defines; + + unsigned int *text, *data; + unsigned int *text_reloc, *data_reloc; + unsigned int *text_reloc_full_addr, *text_reloc_type; +}; + +#include "ALL_CODECS_FW_ALL_pipes_2_contexts_8_hwconfig_1_bin.c" + +unsigned int all_fw_binaries_cnt = 1; +struct IMG_COMPILED_FW_BIN_RECORD *all_fw_binaries[] = { + &simg_compiled_all_codecs_fw_all_pipes_2_contexts_8_hwconfig_1, +}; + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/coreflags.h b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/coreflags.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/coreflags.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/coreflags.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _COREFLAGS_H_ +#define _COREFLAGS_H_ + +#define SERIALIZED_PIPES (1) + +/* The number of TOPAZ cores present in the system */ +#define TOPAZHP_MAX_NUM_PIPES (4) + +#define TOPAZHP_MAX_POSSIBLE_STREAMS (8) +#define TOPAZHP_MAX_BU_SUPPORT_HD 90 +#define TOPAZHP_MAX_BU_SUPPORT_4K 128 + +#define USE_VCM_HW_SUPPORT (1) +/* controls the firmwares ability to support the optional hardware input scaler */ +#define INPUT_SCALER_SUPPORTED (1) +/* controls the firmwares ability to support secure mode firmware upload */ +#define SECURE_MODE_POSSIBLE (1) + +/* controls the firmwares ability to support secure input/output ports */ +#define SECURE_IO_PORTS (1) + +/* Line counter feature is not ready for Onyx yet + * (comment the define to remove the feature from builds) + */ +#define LINE_COUNTER_SUPPORTED (1) + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/defs.h b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/defs.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/defs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/defs.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#if !defined DEFS_H_ +#define DEFS_H_ + +#include + +/* + * MACROS to insert values into fields within a word. The basename of the + * field must have MASK_BASENAME and SHIFT_BASENAME constants. + */ +#define F_MASK(basename) (MASK_##basename) +#define F_SHIFT(basename) (SHIFT_##basename) +/* + * Extract a value from an instruction word. + */ +#define F_EXTRACT(val, basename) (((val) & (F_MASK(basename))) >> (F_SHIFT(basename))) + +/* + * Mask and shift a value to the position of a particular field. + */ +#define F_ENCODE(val, basename) (((val) << (F_SHIFT(basename))) & (F_MASK(basename))) +#define F_DECODE(val, basename) (((val) & (F_MASK(basename))) >> (F_SHIFT(basename))) + +/* + * Insert a value into a word. + */ +#define F_INSERT(word, val, basename) (((word) & ~(F_MASK(basename))) | (F_ENCODE((val), basename))) + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/mtx_fwif.h b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/mtx_fwif.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/mtx_fwif.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/mtx_fwif.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _MTX_FWIF_H_ +#define _MTX_FWIF_H_ + +#include "vxe_common.h" +#include "topazscfwif.h" + +//#define VXE_MEASURE_MTX_CLK_FREQ + +/* + * enum describing the MTX load method + */ +enum mtx_load_method { + MTX_LOADMETHOD_NONE = 0, /* don't load MTX code */ + MTX_LOADMETHOD_BACKDOOR, /* backdoor - writes MTX load data direct to out.res */ + MTX_LOADMETHOD_REGIF, /* load mtx code via register interface */ + MTX_LOADMETHOD_DMA, /* load mtx code via DMA */ + MTX_LOADMETHOD_FORCE32BITS = 0x7FFFFFFFU + +}; + +/* + * defines that should come from auto generated headers + */ +#define MTX_DMA_MEMORY_BASE (0x82880000) +#define PC_START_ADDRESS (0x80900000) + +#define MTX_CORE_CODE_MEM (0x10) +#define MTX_CORE_DATA_MEM (0x18) + +#define MTX_PC (0x05) + +/* + * MTX Firmware Context Structure + */ + +/* + * struct img_fw_int_defines_table - contains info for the fw int defines + * + * @length: length of the table + * @names: array of names of entries + * @values: array of values of entries + */ +struct img_fw_int_defines_table { + unsigned int length; + unsigned char **names; + unsigned int *values; +}; + +/* + * struct img_fw_context - contains info for the context of the loaded firmware + * + * @initialized: TRUE if MTX core is initialized + * @populated: TRUE if MTX firmware context had been populated with data + * @active_ctx_mask: A bit mask of active encode contexts in the firmware + * @dev_ctx: Pointer to the device context + * @load_method: method used to load this MTX + * @supported_codecs: Codec mask + * @mtx_debug_val: Value in MTX Debug register (for RAM config) + * @mtx_ram_size: Size of MTX RAM + * @mtx_bank_size: Size of MTX RAM banks + * @mtx_reg_mem_space_addr: Memspace ID for MTX registers + * @topaz_reg_mem_space_addr: Memspace ID for TOPAZ registers + * @topaz_multicore_reg_addr: Memspace ID for TOPAZ multicore control registers + * @core_rev: Hardware core revision ID + * @core_des1: Hardware core designer (feature bits) + * @drv_has_mtx_ctrl: TRUE if driver (not DASH) has control of MTX + * @access_control: Use to get read/write access to MTX + * @hw_num_pipes: Number of pipes available in hardware + * @num_pipes: Number of pipes supported by firmware + * @num_contexts: Number of contexts supported by firmware + * @mtx_context_data_copy: Copy of MTX Context Data during hibernate + * @mtx_reg_copy: Copy of MTX Register block during hibernate + * @mtx_topaz_fw_text_size: Size of MTX Firmware Text Section in words + * @mtx_topaz_fw_text: Pointer to MTX Firmware Text Section + * @mtx_topaz_fw_data_size: Size of MTX Firmware Data Section in words + * @mtx_topaz_fw_data: Pointer to MTX Firmware Data Section + * @mtx_topaz_fw_data_origin: Offset to location of Data section + * @int_defines: table of int defines + */ +struct img_fw_context { + unsigned short initialized; + unsigned short populated; + unsigned char active_ctx_mask; + + void *dev_ctx; + + enum mtx_load_method load_method; + + unsigned int supported_codecs; + + unsigned int mtx_debug_val; + unsigned int mtx_ram_size; + unsigned int mtx_bank_size; + + void *mtx_reg_mem_space_addr; + void *topaz_reg_mem_space_addr[TOPAZHP_MAX_NUM_PIPES]; + void *topaz_multicore_reg_addr; + unsigned int core_rev; + unsigned int core_des1; + + unsigned short drv_has_mtx_ctrl; + unsigned int access_control; + + unsigned int hw_num_pipes; + unsigned int num_pipes; + unsigned int num_contexts; + + struct vidio_ddbufinfo *mtx_context_data_copy[TOPAZHP_MAX_POSSIBLE_STREAMS]; + unsigned int *mtx_reg_copy; + + unsigned int mtx_topaz_fw_text_size; + unsigned int *mtx_topaz_fw_text; + + unsigned int mtx_topaz_fw_data_size; + unsigned int *mtx_topaz_fw_data; + + unsigned int mtx_topaz_fw_data_origin; + + struct img_fw_int_defines_table int_defines; +}; + +/* + * Populates MTX context structure + * @param codec : version of codec specific firmware to associate with this MTX + * @param fw_ctx : Output context + * @return int : Standard IMG_ERRORCODE + */ +int mtx_populate_fw_ctx(enum img_codec codec, + struct img_fw_context *fw_ctx); + +/* + * Initialise the hardware using given (populated) MTX context structure + * @param fw_ctx : Pointer to the context of the target MTX + * @return None + */ +void mtx_initialize(void *dev_ctx, struct img_fw_context *fw_ctx); + +/* + * Return the integer define used to compile given version of firmware. + * @param fw_ctx : Pointer to the context of the target MTX + * @param name : Name of a define (string) + * @return Value of define or -1 if not found. + */ +int mtx_get_fw_config_int(struct img_fw_context const * const fw_ctx, + unsigned char const * const name); + +/* + * Load text and data sections onto an MTX. + * @param fw_ctx : Pointer to the context of the target MTX + * @param load_method : Method to use for loading code + * @return None + */ +void mtx_load(void *dev_ctx, struct img_fw_context *fw_ctx, + enum mtx_load_method load_method); + +/* + * Deinitialises MTX and MTX control structure + */ +void mtx_deinitialize(struct img_fw_context *fw_ctx); + +/* + * Saves MTX State -- Registers and Data Memory + */ +void mtx_save_state(struct img_fw_context *fw_ctx); + +/* + * Restores MTX State -- Registers and Data Memory + */ +void mtx_restore_state(void *ctx, struct img_fw_context *fw_ctx); + +/* + * mtx_start + */ +void mtx_start(struct img_fw_context *fw_ctx); + +/* + * mtx_stop + */ +void mtx_stop(struct img_fw_context *fw_ctx); + +/* + * Kicks MTX + */ +void mtx_kick(struct img_fw_context *fw_ctx, unsigned int kick_count); + +/* + * Waits for MTX to halt + */ +void mtx_wait_for_completion(struct img_fw_context *fw_ctx); + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/topazscfwif.h b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/topazscfwif.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/topazscfwif.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/topazscfwif.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,1104 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _TOPAZSCFWIF_H_ +#define _TOPAZSCFWIF_H_ + +#include "coreflags.h" +#include + +#define MAX_QP_H264 (51) + +/* + * The number of bytes used by each MVEA MV param & above param region + */ +#define MVEA_MV_PARAM_REGION_SIZE 16 +#define MVEA_ABOVE_PARAM_REGION_SIZE 96 + +/* + * Macros to align to the correct number of bytes + */ +#define ALIGN_4(X) (((X) + 3) & ~3) +#define ALIGN_16(X) (((X) + 15) & ~15) +#define ALIGN_64(X) (((X) + 63) & ~63) +#define ALIGN_128(X) (((X) + 127) & ~127) +#define ALIGN_1024(X) (((X) + 1023) & ~1023) + +/* + * Context size allocated from host application + */ +#define MTX_CONTEXT_SIZE (13 * 1024) + +/* + * SEI (Buffering Period and Picture Timing) Constants shared + * between host and firmware + */ +#define BPH_SEI_NAL_INITIAL_CPB_REMOVAL_DELAY_SIZE 23 +#define PTH_SEI_NAL_CPB_REMOVAL_DELAY_SIZE 23 +#define PTH_SEI_NAL_DPB_OUTPUT_DELAY_SIZE 7 + +/* + * Size of the header in output coded buffer. This varies based on + * whether data logging is enabled/disabled + */ +#if defined(INCLUDE_CRC_REGISTER_CHECKS) +#define CRC_REGISTER_FEEDBACK_SIZE (80 * 4) +#else +#define CRC_REGISTER_FEEDBACK_SIZE 0 +#endif + +/* MUST be aligned to the DMA 64 byte boundary condition + * (CRC data is DMA'd after the coded buffer header) + */ +#define CODED_BUFFER_HEADER_SIZE 64 +#define CODED_BUFFER_INFO_SECTION_SIZE (CODED_BUFFER_HEADER_SIZE + CRC_REGISTER_FEEDBACK_SIZE) + +/* + * Mask defines for the -ui8EnableSelStatsFlags variable + */ +#define ESF_FIRST_STAGE_STATS 1 +#define ESF_MP_BEST_MB_DECISION_STATS 2 +#define ESF_MP_BEST_MOTION_VECTOR_STATS 4 + +#define CUSTOM_QUANT_PARAMSIZE_8x8 2 + +/* + * Combined size of H.264 quantization lists (6 * 16 + {2 or 6} * 64) + */ +#define QUANT_LISTS_SIZE (6 * 16 + CUSTOM_QUANT_PARAMSIZE_8x8 * 64) + +/* + * Size in bytes and words of memory to transfer partially coded header data + */ +#define MAX_HEADERSIZEBYTES (128) +#define MAX_HEADERSIZEWORDS (32) + +/* + * Maximum number of slices per field + */ +#define MAX_SLICESPERPIC (128) + +/* + * Picture parameter flags used in the PIC_PARAM structure + */ +#define ISINTERP_FLAGS (0x00000001) +#define ISRC_FLAGS (0x00000010) +#define ISRC_I16BIAS (0x00000020) +#define ISINTERB_FLAGS (0x00000080) +#define ISSCENE_DISABLED (0x00000100) +#define ISMULTIREF_FLAGS (0x00000200) +#define SPATIALDIRECT_FLAGS (0x00000400) + +/* + * Enum describing contents of scratch registers + */ +enum mtx_scratch_regdata { + MTX_SCRATCHREG_BOOTSTATUS = 0, + MTX_SCRATCHREG_UNUSED = 0, + MTX_SCRATCHREG_TOHOST, //!< Reg for MTX->Host data + MTX_SCRATCHREG_TOMTX, //!< Reg for Host->MTX data + + MTX_SCRATCHREG_SIZE, //!< End marker for enum + MTX_SCRATCHREG_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * `MTX_SCRATCHREG_IDLE` register that is used for synchronous communication and debug. + * + * Current register usage: + * : + * 2-10 : Number of executed commands (mod 255) + * 0-1 : FW idle status + */ +#define MTX_SCRATCHREG_IDLE TOPAZHP_TOP_CR_FIRMWARE_REG_4 //!< Reg for firmware IDLE status + +/* Flags relating to MTX_SCRATCHREG_IDLE */ +/* Bits [10-22] are used for the line information */ +/* TOPAZHP_LINE_COUNTER (see TRM 8.1.1) uses 12 bits for the line count */ +#define SHIFT_FW_IDLE_REG_STATUS (0) +#define MASK_FW_IDLE_REG_STATUS (3) +#define FW_IDLE_STATUS_IDLE (1) + +/* + * In secure FW mode the first value written to the command FIFO is copied to MMU_CONTROL_0 + * by the firmware. When we don't want that to happen we can write this value instead. + * The firmware will know to ignore it as + * long as it is written BEFORE the firmware starts up + */ +#define TOPAZHP_NON_SECURE_FW_MARKER (0xffffffff) + +/* + * This value is an arbitrary value that the firmware will write to TOPAZHP_TOP_CR_FIRMWARE_REG_1 + * (MTX_SCRATCHREG_BOOTSTATUS) + * when it has completed the boot process to indicate that it is ready + */ +#define TOPAZHP_FW_BOOT_SIGNAL (0x12345678) + +/* + * Sizes for arrays that depend on reference usage pattern + */ +#define MAX_REF_B_LEVELS 3 +#define MAX_REF_SPACING 1 +#define MAX_REF_I_OR_P_LEVELS (MAX_REF_SPACING + 2) +#define MAX_REF_LEVELS (MAX_REF_B_LEVELS + MAX_REF_I_OR_P_LEVELS) +#define MAX_PIC_NODES (MAX_REF_LEVELS + 2) +#define MAX_MV (MAX_PIC_NODES * 2) + +#define MAX_BFRAMES 7 //B-frame count limit for Hierarchical mode +#define MAX_GOP_SIZE (MAX_BFRAMES + 1) +#define MAX_SOURCE_SLOTS_SL (MAX_GOP_SIZE + 1) + +#define MV_ROW_STRIDE (ALIGN_64(sizeof(struct img_mv_settings) * MAX_BFRAMES)) + +/* + * MTX -> host message FIFO + */ +#define LOG2_WB_FIFO_SIZE (5) + +#define WB_FIFO_SIZE (1 << (LOG2_WB_FIFO_SIZE)) + +#define SHIFT_WB_PRODUCER (0) +#define MASK_WB_PRODUCER (((1 << LOG2_WB_FIFO_SIZE) - 1) << SHIFT_WB_PRODUCER) + +#define SHIFT_WB_CONSUMER (0) +#define MASK_WB_CONSUMER (((1 << LOG2_WB_FIFO_SIZE) - 1) << SHIFT_WB_CONSUMER) + +/* + * Number of buffers per encode task (default: 2 - double bufferring) + */ +#define CODED_BUFFERING_CNT 2 //default to double-buffering + +/* + * Calculates the ideal minimum coded buffers for a frame level encode + */ +#define CALC_OPTIMAL_CODED_PACKAGES_FRAME_ENCODE(numcores, isinterlaced) \ + ((((isinterlaced) ? 2 : 1) * (numcores)) * CODED_BUFFERING_CNT) + +/* + * Calculates the ideal minimum coded buffers for a slice level encode + */ +#define CALC_OPTIMAL_CODED_PACKAGES_SLICE_ENCODE(slicesperpic) \ + ((slicesperpic) * CODED_BUFFERING_CNT) + +/* + * Calculates the ideal minimum coded buffers for an encode + */ +#define CALC_OPTIMAL_CODED_PACKAGES_ENCODE(bis_slice_level, slicesperpic, numcores, isinterlaced) \ + (bis_slice_level ? CALC_OPTIMAL_CODED_PACKAGES_SLICE_ENCODE(slicesperpic) \ + : CALC_OPTIMAL_CODED_PACKAGES_FRAME_ENCODE(numcores, isinterlaced)) + +/* + * Calculates the actual number of coded buffers that can be used for an encode + */ +#define CALC_NUM_CODED_PACKAGES_ENCODE(bis_slice_level, slicesperpic, numcores, isinterlaced) \ + (CALC_OPTIMAL_CODED_PACKAGES_ENCODE(bis_slice_level, slicesperpic, numcores, isinterlaced)) + +/* + * Maximum number of coded packages + */ +#define MAX_CODED_PACKAGES CALC_NUM_CODED_PACKAGES_ENCODE(0, 0, TOPAZHP_MAX_NUM_PIPES, 1) + +/* + * DMA configuration parameters + */ +#define MTX_DMA_BURSTSIZE_BYTES 32 + +/* + * types that should be in DMAC header file + */ +enum dmac_acc_del { + DMAC_ACC_DEL_0 = 0x0, //!< Access delay zero clock cycles + DMAC_ACC_DEL_256 = 0x1, //!< Access delay 256 clock cycles + DMAC_ACC_DEL_512 = 0x2, //!< Access delay 512 clock cycles + DMAC_ACC_DEL_768 = 0x3, //!< Access delay 768 clock cycles + DMAC_ACC_DEL_1024 = 0x4, //!< Access delay 1024 clock cycles + DMAC_ACC_DEL_1280 = 0x5, //!< Access delay 1280 clock cycles + DMAC_ACC_DEL_1536 = 0x6, //!< Access delay 1536 clock cycles + DMAC_ACC_DEL_1792 = 0x7, //!< Access delay 1792 clock cycles + DMAC_ACC_FORCE32BITS = 0x7FFFFFFFU +}; + +enum dmac_bswap { + DMAC_BSWAP_NO_SWAP = 0x0, //!< No byte swapping will be performed. + DMAC_BSWAP_REVERSE = 0x1, //!< Byte order will be reversed. + DMAC_BSWAP_FORCE32BITS = 0x7FFFFFFFU +}; + +enum dmac_burst { + DMAC_BURST_0 = 0x0, //!< burst size of 0 + DMAC_BURST_1 = 0x1, //!< burst size of 1 + DMAC_BURST_2 = 0x2, //!< burst size of 2 + DMAC_BURST_3 = 0x3, //!< burst size of 3 + DMAC_BURST_4 = 0x4, //!< burst size of 4 + DMAC_BURST_5 = 0x5, //!< burst size of 5 + DMAC_BURST_6 = 0x6, //!< burst size of 6 + DMAC_BURST_7 = 0x7, //!< burst size of 7 + DMAC_BURST_FORCE32BITS = 0x7FFFFFFFU +}; + +#define DMAC_VALUE_COUNT(BSWAP, PW, DIR, PERIPH_INCR, COUNT) \ + ((((BSWAP) << SHIFT_IMG_SOC_BSWAP) & MASK_IMG_SOC_BSWAP) |\ + (((PW) << SHIFT_IMG_SOC_PW) & MASK_IMG_SOC_PW) |\ + (((DIR) << SHIFT_IMG_SOC_DIR) & MASK_IMG_SOC_DIR) |\ + (((PERIPH_INCR) << SHIFT_IMG_SOC_PI) & MASK_IMG_SOC_PI) |\ + (((COUNT) << SHIFT_IMG_SOC_CNT) & MASK_IMG_SOC_CNT)) + +#define DMAC_VALUE_PERIPH_PARAM(ACC_DEL, INCR, BURST) \ + ((((ACC_DEL) << SHIFT_IMG_SOC_ACC_DEL) & MASK_IMG_SOC_ACC_DEL) |\ + (((INCR) << SHIFT_IMG_SOC_INCR) & MASK_IMG_SOC_INCR) |\ + (((BURST) << SHIFT_IMG_SOC_BURST) & MASK_IMG_SOC_BURST)) + +enum dmac_pw { + DMAC_PWIDTH_32_BIT = 0x0, //!< Peripheral width 32-bit. + DMAC_PWIDTH_16_BIT = 0x1, //!< Peripheral width 16-bit. + DMAC_PWIDTH_8_BIT = 0x2, //!< Peripheral width 8-bit. + DMAC_PWIDTH_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Enum describing Command IDs. Some commands require data to be DMA'd in + * from the Host, with the base address of the data specified in the Command + * Data Address word of the command. The data required is specific to each + * command type. + */ +enum mtx_cmd_id { + // Common Commands + MTX_CMDID_NULL, //!< (no data)\n Null command does nothing\n + MTX_CMDID_SHUTDOWN, //!< (no data)\n shutdown the MTX\n + + // Video Commands + /* !< (extra data: #MTX_HEADER_PARAMS) Command for Sequence, Picture and Slice headers */ + MTX_CMDID_DO_HEADER, + /* !< (data: low latency encode activation, HBI usage) Encode frame data*/ + MTX_CMDID_ENCODE_FRAME, + MTX_CMDID_START_FRAME, //!< (no data)\n Prepare to encode frame\n + MTX_CMDID_ENCODE_SLICE, //!< (no data)\n Encode slice data\n + MTX_CMDID_END_FRAME, //!< (no data)\n Complete frame encoding\n + /* !< (data: pipe number, extra data: #IMG_MTX_VIDEO_CONTEXT)\n Set MTX Video Context */ + MTX_CMDID_SETVIDEO, + /* !< (data: pipe number, extra data: #IMG_MTX_VIDEO_CONTEXT) + * Get MTX Video Context + */ + MTX_CMDID_GETVIDEO, + /* !< (data: new pipe allocations for the context) + * Change pipe allocation for a Video Context + */ + MTX_CMDID_DO_CHANGE_PIPEWORK, +#if SECURE_IO_PORTS + MTX_CMDID_SECUREIO, //!< (data: )\n Change IO security\n +#endif + /* !< (data: subtype and parameters, extra data: #IMG_PICMGMT_CUSTOM_QUANT_DATA + * (optional))\n Change encoding parameters + */ + MTX_CMDID_PICMGMT, + /* !< (data: QP and bitrate)\n Change encoding parameters */ + MTX_CMDID_RC_UPDATE, + /* !< (extra data: #IMG_SOURCE_BUFFER_PARAMS) + * Transfer source buffer from host + */ + MTX_CMDID_PROVIDE_SOURCE_BUFFER, + /* !< (data: buffer parameters, extra data: reference buffer) + * Transfer reference buffer from host + */ + MTX_CMDID_PROVIDE_REF_BUFFER, + /* !< (data: slot and size, extra data: coded package)\n Transfer coded package from host + *(coded package contains addresses of header and coded output buffers/1st linked list node) + */ + MTX_CMDID_PROVIDE_CODEDPACKAGE_BUFFER, + MTX_CMDID_ABORT, //!< (no data)\n Stop encoding and release all buffers\n + + // JPEG commands + MTX_CMDID_SETQUANT, //!< (extra data: #JPEG_MTX_QUANT_TABLE)\n + MTX_CMDID_SETUP_INTERFACE, //!< (extra data: #JPEG WRITEBACK POINTERS)\n + MTX_CMDID_ISSUEBUFF, //!< (extra data: #MTX_ISSUE_BUFFERS)\n + MTX_CMDID_SETUP, //!< (extra data: #JPEG_MTX_DMA_SETUP)\n\n + /* !< (extra data: #IMG_VXE_SCALER_SETUP)\nChange source + * pixel format after context creation\ + */ + MTX_CMDID_UPDATE_SOURCE_FORMAT, + /* !< (extra data: #IMG_VXE_CSC_SETUP)\nChange Colour Space Conversion setup dynamically */ + MTX_CMDID_UPDATE_CSC, + + MTX_CMDID_ENDMARKER, //!< end marker for enum + MTX_CMDID_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Priority for the command. + * Each Command ID will only work with the correct priority. + */ +#define MTX_CMDID_PRIORITY 0x80 + +/* + * Indicates whether or not to issue an interrupt when the firmware sends the + * command's writeback message. + */ +#define MTX_CMDID_WB_INTERRUPT 0x8000 + +/* + * Enum describing response IDs + */ +enum mtx_message_id { + MTX_MESSAGE_ACK, + MTX_MESSAGE_CODED, + MTX_MESSAGE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Mask and shift values for command word + */ +#define SHIFT_MTX_MSG_CMD_ID (0) +#define MASK_MTX_MSG_CMD_ID (0x7f << SHIFT_MTX_MSG_CMD_ID) +#define SHIFT_MTX_MSG_PRIORITY (7) +#define MASK_MTX_MSG_PRIORITY (0x1 << SHIFT_MTX_MSG_PRIORITY) +#define SHIFT_MTX_MSG_CORE (8) +#define MASK_MTX_MSG_CORE (0x7f << SHIFT_MTX_MSG_CORE) +#define SHIFT_MTX_MSG_COUNT (16) +#define MASK_MTX_MSG_COUNT (0xffffU << SHIFT_MTX_MSG_COUNT) +#define SHIFT_MTX_MSG_MESSAGE_ID (16) +#define MASK_MTX_MSG_MESSAGE_ID (0xff << SHIFT_MTX_MSG_MESSAGE_ID) + +/* + * Mask and shift values for data word + */ +#define SHIFT_MTX_MSG_ENCODE_CODED_INTERRUPT (0) +#define MASK_MTX_MSG_ENCODE_CODED_INTERRUPT \ + (0xff << SHIFT_MTX_MSG_ENCODE_CODED_INTERRUPT) +#define SHIFT_MTX_MSG_ENCODE_USE_LINE_COUNTER (20) +#define MASK_MTX_MSG_ENCODE_USE_LINE_COUNTER \ + (0x1 << SHIFT_MTX_MSG_ENCODE_USE_LINE_COUNTER) + +#define SHIFT_MTX_MSG_PICMGMT_SUBTYPE (0) +#define MASK_MTX_MSG_PICMGMT_SUBTYPE (0xff << SHIFT_MTX_MSG_PICMGMT_SUBTYPE) +#define SHIFT_MTX_MSG_PICMGMT_DATA (8) +#define MASK_MTX_MSG_PICMGMT_DATA (0xffffffU << SHIFT_MTX_MSG_PICMGMT_DATA) +#define SHIFT_MTX_MSG_PICMGMT_STRIDE_Y (0) +#define MASK_MTX_MSG_PICMGMT_STRIDE_Y (0x3ff << SHIFT_MTX_MSG_PICMGMT_STRIDE_Y) +#define SHIFT_MTX_MSG_PICMGMT_STRIDE_UV (10) +#define MASK_MTX_MSG_PICMGMT_STRIDE_UV (0x3ff << SHIFT_MTX_MSG_PICMGMT_STRIDE_UV) + +/*Values for updating static Qp values when Rate Control is disabled*/ +#define SHIFT_MTX_MSG_NUM_CODED_BUFFERS_PER_HEADER (5) +#define MASK_MTX_MSG_NUM_CODED_BUFFERS_PER_HEADER \ + (0xf << SHIFT_MTX_MSG_NUM_CODED_BUFFERS_PER_HEADER) + +#define SHIFT_MTX_MSG_PROVIDE_CODEDPACKAGE_BUFFER_SLOT (0) +#define MASK_MTX_MSG_PROVIDE_CODEDPACKAGE_BUFFER_SLOT \ + (0x0f << SHIFT_MTX_MSG_PROVIDE_CODEDPACKAGE_BUFFER_SLOT) +#define SHIFT_MTX_MSG_PROVIDE_CODED_BUFFER_SIZE (4) +#define MASK_MTX_MSG_PROVIDE_CODED_BUFFER_SIZE \ + (0x3fffff << SHIFT_MTX_MSG_PROVIDE_CODED_BUFFER_SIZE) + +/* + * Enum describing partially coded header element types + */ +enum header_element_type { + ELEMENT_STARTCODE_RAWDATA = 0, //!< Raw data that includes a start code + /*!< Raw data that includes a start code in the middle of the header */ + ELEMENT_STARTCODE_MIDHDR, + ELEMENT_RAWDATA, //!< Raw data + ELEMENT_QP, //!< Insert the H264 Picture Header QP parameter + ELEMENT_SQP, //!< Insert the H264 Slice Header QP parameter + /* Insert the H263/MPEG4 Frame Q_scale parameter (vob_quant field) */ + ELEMENT_FRAMEQSCALE, + /* !< Insert the H263/MPEG4 Slice Q_scale parameter (quant_scale field) */ + ELEMENT_SLICEQSCALE, + ELEMENT_INSERTBYTEALIGN_H264, //!< Insert the byte alignment bits for H264 + ELEMENT_INSERTBYTEALIGN_MPG4, //!< Insert the byte alignment bits for MPEG4 + ELEMENT_INSERTBYTEALIGN_MPG2, //!< Insert the byte alignment bits for MPEG2 + ELEMENT_VBV_MPG2, + ELEMENT_TEMPORAL_REF_MPG2, + ELEMENT_CURRMBNR, //!< Insert the current macrloblock number for a slice. + + /* !< Insert frame_num field (used as ID for ref. pictures in H264) */ + ELEMENT_FRAME_NUM, //!< Insert frame_num field (used as ID for ref. pictures in H264) + /* !< Insert Temporal Reference field (used as ID for ref. pictures in H263) */ + ELEMENT_TEMPORAL_REFERENCE, + ELEMENT_EXTENDED_TR, //!< Insert Extended Temporal Reference field + /*//!< Insert idr_pic_id field (used to distinguish consecutive IDR frames) */ + ELEMENT_IDR_PIC_ID, + /* !< Insert pic_order_cnt_lsb field (used for display ordering in H264) */ + ELEMENT_PIC_ORDER_CNT, + /* !< Insert gob_frame_id field (used for display ordering in H263) */ + ELEMENT_GOB_FRAME_ID, + /* !< Insert vop_time_increment field (used for display ordering in MPEG4) */ + ELEMENT_VOP_TIME_INCREMENT, + /* !< Insert modulo_time_base used in MPEG4 (depends on vop_time_increment_resolution) */ + ELEMENT_MODULO_TIME_BASE, + + ELEMENT_BOTTOM_FIELD, //!< Insert bottom_field flag + ELEMENT_SLICE_NUM, //!< Insert slice num (used for GOB headers in H263) + ELEMENT_MPEG2_SLICE_VERTICAL_POS, //!< Insert slice vertical pos (MPEG2 slice header) + /* !< Insert 1 bit flag indicating if slice is Intra or not (MPEG2 slice header) */ + ELEMENT_MPEG2_IS_INTRA_SLICE, + /* !< Insert 2 bit field indicating if the current header is for a frame picture (11), + * top field (01) or bottom field (10) - (MPEG2 picture header + */ + ELEMENT_MPEG2_PICTURE_STRUCTURE, + /* !< Insert flag indicating whether or not this picture is a reference */ + ELEMENT_REFERENCE, + ELEMENT_ADAPTIVE, //!< Insert reference picture marking + ELEMENT_DIRECT_SPATIAL_MV_FLAG, //!< Insert spatial direct mode flag + ELEMENT_NUM_REF_IDX_ACTIVE, //!< Insert number of active references + ELEMENT_REORDER_L0, //!< Insert reference list 0 reordering + ELEMENT_REORDER_L1, //!< Insert reference list 1 reordering + ELEMENT_TEMPORAL_ID, //!< Insert temporal ID of the picture, used for MVC header + /*!< Insert flag indicating whether or not this picture is an anchor picture */ + ELEMENT_ANCHOR_PIC_FLAG, + + BPH_SEI_NAL_INITIAL_CPB_REMOVAL_DELAY, //!< Insert nal_initial_cpb_removal_delay + /* !< Insert nal_initial_cpb_removal_delay_offset */ + BPH_SEI_NAL_INITIAL_CPB_REMOVAL_DELAY_OFFSET, + PTH_SEI_NAL_CPB_REMOVAL_DELAY, //!< Insert cpb_removal_delay + PTH_SEI_NAL_DPB_OUTPUT_DELAY, //!< Insert dpb_output_delay + + ELEMENT_SLICEWEIGHTEDPREDICTIONSTRUCT, //!< Insert weighted prediciton parameters + ELEMENT_CUSTOM_QUANT, //!< Insert custom quantization values + ELEMENT_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Struct describing a partially coded header element + */ +struct mtx_header_element { + enum header_element_type element_type; //!< Element type + /* !< Number of bits of coded data to be inserted */ + unsigned char size; + unsigned char bits; //!< Raw data to be inserted. +}; + +/* + * Struct describing partially coded header parameters + */ +struct mtx_header_params { + unsigned int elements; //!< Number of header elements + /*!< array of element data */ + struct mtx_header_element element_stream[MAX_HEADERSIZEWORDS - 1]; +}; + +/* + * Enum describing threshold values for skipped MB biasing + */ +enum th_skip_scale { + TH_SKIP_0 = 0, //!< Bias threshold for QP 0 to 12 + TH_SKIP_12 = 1, //!< Bias threshold for QP 12 to 24 + TH_SKIP_24 = 2, //!< Bias threshold for QP 24 and above + TH_SKIP_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Struct describing rate control input parameters + */ +struct in_rc_params { + unsigned int mb_per_frm; //!< Number of MBs Per Frame + unsigned int mb_per_bu; //!< Number of MBs Per BU + unsigned short bu_per_frm; //!< Number of BUs Per Frame + + unsigned short intra_period; //!< Intra frame frequency + unsigned short bframes; //!< B frame frequency + + int bits_per_frm; //!< Bits Per Frame + int bits_per_bu; //!< Bits Per BU + + int bit_rate; //!< Bit Rate (bps) + int buffer_size; //!< Size of Buffer in bits + int buffer_size_frames;//!< Size of Buffer in frames, to be used in VCM + int initial_level; //!< Initial Level of Buffer + int initial_delay; //!< Initial Delay of Buffer + + unsigned short frm_skip_disable; //!< Disable Frame skipping + + unsigned char se_init_qp_i; //!< Initial QP for sequence (I frames) + unsigned char se_init_qp_p; //!< Initial QP for sequence (P frames) + unsigned char se_init_qp_b; //!< Initial QP for sequence (B frames) + + unsigned char min_qp; //!< Minimum QP value to use + unsigned char max_qp; //!< Maximum QP value to use + + /* !< Scale Factor used to limit the range + * of arithmetic with high resolutions and bitrates + */ + unsigned char scale_factor; + unsigned short mb_per_row; //!< Number of MBs Per Row + + unsigned short disable_vcm_hardware; //!< Disable using vcm hardware in RC modes. + + union { + struct { + /* !< Rate at which bits are sent from encoder + * to the output after each frame finished encoding + */ + int transfer_rate; + /* !< Disable Scene Change detection */ + unsigned short sc_detect_disable; + /* !< Flag indicating Hierarchical B Pic or Flat mode rate control */ + unsigned short hierarchical_mode; + /* !< Constant used in rate control = + * (GopSize/(BufferSize-InitialLevel))*256 + */ + unsigned int rc_scale_factor; + /* !< Enable movement of slice boundary when Qp is high */ + unsigned short enable_slice_bob; + /* !< Maximum number of rows the slice boundary can be moved */ + unsigned char max_slice_bob; + /* !< Minimum Qp at which slice bobbing should take place */ + unsigned char slice_bob_qp; + } h264; + struct { + unsigned char half_framerate; //!< Half Frame Rate (MP4 only) + unsigned char f_code; //!< F Code (MP4 only) + int bits_pergop; //!< Bits Per GOP (MP4 only) + unsigned short bu_skip_disable; //!< Disable BU skipping + int bits_per_mb; //!< Bits Per MB + unsigned short avg_qp_val; //!< Average QP in Current Picture + unsigned short initial_qp; //!< Initial Quantizer + } other; + } mode; +}; + +/* + * Enum describing MTX firmware version (codec and rate control) + */ +enum img_codec { + IMG_CODEC_NONE = 0, //!< There is no FW in MTX memory + IMG_CODEC_JPEG, //!< JPEG + IMG_CODEC_H264_NO_RC, //!< H264 with no rate control + IMG_CODEC_H264_VBR, //!< H264 variable bitrate + IMG_CODEC_H264_CBR, //!< H264 constant bitrate + IMG_CODEC_H264_VCM, //!< H264 video conferance mode + IMG_CODEC_H263_NO_RC, //!< H263 with no rate control + IMG_CODEC_H263_VBR, //!< H263 variable bitrate + IMG_CODEC_H263_CBR, //!< H263 constant bitrate + IMG_CODEC_MPEG4_NO_RC, //!< MPEG4 with no rate control + IMG_CODEC_MPEG4_VBR, //!< MPEG4 variable bitrate + IMG_CODEC_MPEG4_CBR, //!< MPEG4 constant bitrate + IMG_CODEC_MPEG2_NO_RC, //!< MPEG2 with no rate control + IMG_CODEC_MPEG2_VBR, //!< MPEG2 variable bitrate + IMG_CODEC_MPEG2_CBR, //!< MPEG2 constant bitrate + IMG_CODEC_H264_ERC, //!< H264 example rate control + IMG_CODEC_H263_ERC, //!< H263 example rate control + IMG_CODEC_MPEG4_ERC, //!< MPEG4 example rate control + IMG_CODEC_MPEG2_ERC, //!< MPEG2 example rate control + IMG_CODEC_H264MVC_NO_RC, //!< MVC H264 with no rate control + IMG_CODEC_H264MVC_CBR, //!< MVC H264 constant bitrate + IMG_CODEC_H264MVC_VBR, //!< MVC H264 variable bitrate + IMG_CODEC_H264MVC_ERC, //!< MVC H264 example rate control + IMG_CODEC_H264_ALL_RC, //!< H264 with multiple rate control modes + IMG_CODEC_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Enum describing encoding standard (codec) + */ +enum img_standard { + IMG_STANDARD_NONE = 0, //!< There is no FW in MTX memory + IMG_STANDARD_JPEG, //!< JPEG + IMG_STANDARD_H264, //!< H264 with no rate control + IMG_STANDARD_H263, //!< H263 with no rate control + IMG_STANDARD_MPEG4, //!< MPEG4 with no rate control + IMG_STANDARD_MPEG2, //!< MPEG2 with no rate control + IMG_STANDARD_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Enum describing image surface format types + */ +enum img_format { + IMG_CODEC_420_YUV = 100, //!< Planar Y U V + IMG_CODEC_420_YV12 = 44, //!< YV12 format Data + IMG_CODEC_420_IMC2 = 36, //!< IMC2 format Data + IMG_CODEC_420_PL8 = 47, //!< PL8 format YUV data + IMG_CODEC_420_PL12 = 101, //!< PL12 format YUV data + /* |< PL12 format packed into a single plane (not currently supported by JPEG) */ + IMG_CODEC_420_PL12_PACKED = 25, + /* !< PL21 format packed into a single plane (not currently supported by JPEG) */ + IMG_CODEC_420_PL21_PACKED = 26, + /* !< YUV format 4:2:2 data; start the incrementing auto enumeration + * values after the last ones we have used. + */ + IMG_CODEC_422_YUV = 102, + IMG_CODEC_422_YV12, //!< YV12 format 4:2:2 data + IMG_CODEC_422_PL8, //!< PL8 format 4:2:2 data + IMG_CODEC_422_IMC2, //!< IMC2 format 4:2:2 data + IMG_CODEC_422_PL12, //!< PL12 format 4:2:2 data + IMG_CODEC_Y0UY1V_8888, //!< 4:2:2 YUYV data + IMG_CODEC_Y0VY1U_8888, //!< 4:2:2 YVYU data + IMG_CODEC_UY0VY1_8888, //!< 4:2:2 UYVY data + IMG_CODEC_VY0UY1_8888, //!< 4:2:2 VYUY data + IMG_CODEC_444_YUV, //!< YUV format 4:4:4 data (not currently supported by JPEG) + IMG_CODEC_444_YV12, //!< YV12 format 4:4:4 data (not currently supported by JPEG) + IMG_CODEC_444_PL8, //!< PL8 format 4:4:4 data (not currently supported by JPEG) + IMG_CODEC_444_IMC2, //!< PL8 format 4:4:4 data (not currently supported by JPEG) + IMG_CODEC_444_PL12, //!< PL12 format 4:4:4 data (not currently supported by JPEG) + IMG_CODEC_ABCX, //!< Interleaved 4:4:4 data (not currently supported by JPEG) + IMG_CODEC_XBCA, //!< Interleaved 4:4:4 data (not currently supported by JPEG) + IMG_CODEC_ABC565, //!< Packed 4:4:4 data (not currently supported by JPEG) + + IMG_CODEC_420_PL21, //!< PL21 format YUV data + IMG_CODEC_422_PL21, //!< 4:2:2 PL21 format YUV data + /* !< 4:4:4 PL21 format YUV data (not currently supported by JPEG) */ + IMG_CODEC_444_PL21, + + PVR_SURF_UNSPECIFIED, //!< End of the enum + IMG_CODEC_FORMAT_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Enum describing presets for source image colour space conversion + */ +enum img_csc_preset { + IMG_CSC_NONE, //!< No colour space conversion + IMG_CSC_709_TO_601, //!< ITU BT.709 YUV to be converted to ITU BT.601 YUV + IMG_CSC_601_TO_709, //!< ITU BT.601 YUV to be converted to ITU BT.709 YUV + IMG_CSC_RGB_TO_601_ANALOG, //!< RGB to be converted to ITU BT.601 YUV + /* !< RGB to be converted to ITU BT.601 YCbCr for SDTV (reduced scale - 16-235) */ + IMG_CSC_RGB_TO_601_DIGITAL, + /* !< RGB to be converted to ITU BT.601 YCbCr for HDTV (full range - 0-255) */ + IMG_CSC_RGB_TO_601_DIGITAL_FS, + IMG_CSC_RGB_TO_709, //!< RGB to be converted to ITU BT.709 YUV + IMG_CSC_YIQ_TO_601, //!< YIQ to be converted to ITU BT.601 YUV + IMG_CSC_YIQ_TO_709, //!< YIQ to be converted to ITU BT.709 YUV + IMG_CSC_BRG_TO_601, //!< BRG to be converted to ITU BT.601 YUV (for XRGB format) + IMG_CSC_RBG_TO_601, //!< RBG to be converted to ITU BT.601 YUV (for XBGR format) + IMG_CSC_BGR_TO_601, //!< BGR to be converted to ITU BT.601 YUV (for BGRX format) + IMG_CSC_UYV_TO_YUV, //!< UYV to be converted to YUV (BT.601 or BT.709) + IMG_CSC_PRESETS, //!< End of the enum + IMG_CSC_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * GOP structure information + */ +#define SHIFT_GOP_FRAMETYPE (0) +#define MASK_GOP_FRAMETYPE (0x3 << SHIFT_GOP_FRAMETYPE) +#define SHIFT_GOP_REFERENCE (2) +#define MASK_GOP_REFERENCE (0x1 << SHIFT_GOP_REFERENCE) +#define SHIFT_GOP_POS (3) +#define MASK_GOP_POS (0x1f << SHIFT_GOP_POS) +#define SHIFT_GOP_REF0 (0 + 8) +#define MASK_GOP_REF0 (0xf << SHIFT_GOP_REF0) +#define SHIFT_GOP_REF1 (4 + 8) +#define MASK_GOP_REF1 (0xf << SHIFT_GOP_REF1) + +/* + * Frame types + */ +enum img_frame_type { + IMG_INTRA_IDR = 0, + IMG_INTRA_FRAME, + IMG_INTER_P, + IMG_INTER_B, + IMG_INTER_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Motion vector calculation register settings + */ +struct img_mv_settings { + unsigned int mv_calc_below; + unsigned int mv_calc_colocated; + unsigned int mv_calc_config; +}; + +/* + * Frame template types + */ +enum img_frame_template_type { + IMG_FRAME_IDR = 0, + IMG_FRAME_INTRA, + IMG_FRAME_INTER_P, + IMG_FRAME_INTER_B, + IMG_FRAME_INTER_P_IDR, + IMG_FRAME_UNDEFINED, + IMG_FRAME_TYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Rate control modes + */ +enum img_rcmode { + IMG_RCMODE_NONE = 0, + IMG_RCMODE_CBR, + IMG_RCMODE_VBR, + IMG_RCMODE_ERC, // Example Rate Control + IMG_RCMODE_VCM, + IMG_RCMODE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Video Conferencing Mode (VCM) rate control method's sub modes + */ +enum img_rc_vcm_mode { + IMG_RC_VCM_MODE_DEFAULT = 0, + IMG_RC_VCM_MODE_CFS_NONIFRAMES, + IMG_RC_VCM_MODE_CFS_ALLFRAMES, + IMG_RC_VCM_MODE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Weighted prediction values + */ +struct weighted_prediction_values { + unsigned char frame_type; + unsigned char weighted_pred_flag; // Corresponds to field in the pps + unsigned char weighted_bipred_idc; + unsigned int luma_log2_weight_denom; + unsigned int chroma_log2_weight_denom; + /* Y, Cb, Cr Support for 2 ref pictures on P, or 1 pic in each direction on B. */ + unsigned char weight_flag[3][2]; + int weight[3][2]; + int offset[3][2]; +}; + +enum weighted_bipred_idc { + WBI_NONE = 0x0, + WBI_EXPLICIT, + WBI_IMPLICIT, + WBI_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Registers required to configure input scaler + */ +struct img_vxe_scaler_setup { + unsigned int input_scaler_control; + unsigned int scaler_input_size_reg; + unsigned int scaler_crop_reg; + unsigned int scaler_pitch_reg; + unsigned int scaler_control; + unsigned int hor_scaler_coeff_regs[4]; + unsigned int ver_scaler_coeff_regs[4]; +}; + +/* + * Registers required to configure input Colour Space conversion + */ +struct img_vxe_csc_setup { + unsigned int csc_source_y[3]; + unsigned int csc_output_clip[2]; + unsigned int csc_source_cbcr[3]; +}; + +/* + * SETVIDEO & GETVIDEO - Video encode context + */ +struct img_mtx_video_context { + /* // keep this at the top as it has alignment issues */ + unsigned long long clock_div_bitrate; + unsigned int width_in_mbs; //!< target output width + unsigned int picture_height_in_mbs; //!< target output height + unsigned int tmp_reconstructed[MAX_PIC_NODES]; + unsigned int reconstructed[MAX_PIC_NODES]; + unsigned int colocated[MAX_PIC_NODES]; + unsigned int mv[MAX_MV]; + unsigned int inter_view_mv[2]; + /* !< Send debug information from Register CRCs to Host with the coded buffer */ + unsigned int debug_crcs; + unsigned int writeback_regions[WB_FIFO_SIZE]; //!< Data section + unsigned int initial_cpb_removal_delayoffset; + unsigned int max_buffer_mult_clock_div_bitrate; + unsigned int sei_buffering_period_template; + unsigned int sei_picture_timing_template; + unsigned short enable_mvc; + unsigned short mvc_view_idx; + unsigned int slice_params_templates[5]; + unsigned int pichdr_templates[4]; + unsigned int seq_header; + unsigned int subset_seq_header; + unsigned short no_sequence_headers; + + /* !< Slice map of the source picture */ + unsigned int slice_map[MAX_SOURCE_SLOTS_SL]; + unsigned int flat_gop_struct; //!< Address of Flat MiniGop structure + unsigned char weighted_prediction_enabled; + unsigned char mtx_weighted_implicit_bi_pred; + unsigned int weighted_prediction_virt_addr[MAX_SOURCE_SLOTS_SL]; + /* !< Address of hierarchical MiniGop structure */ + unsigned int hierar_gop_struct; + /* Output Parameters of the First Pass */ + unsigned int firstpass_out_param_addr[MAX_SOURCE_SLOTS_SL]; + /* !< Selectable Output Best MV Parameters data of the First Pass */ + unsigned int firstpass_out_best_multipass_param_addr[MAX_SOURCE_SLOTS_SL]; + /* !< Input Parameters to the second pass */ + unsigned int mb_ctrl_in_params_addr[MAX_SOURCE_SLOTS_SL]; + /* !< Strides of source Y data and chroma data */ + unsigned int pic_row_stride_bytes; + /* !< Picture level parameters (supplied by driver) */ + unsigned int above_params[TOPAZHP_MAX_NUM_PIPES]; + unsigned int idr_period; + unsigned int intra_loop_cnt; + unsigned int bframe_count; + unsigned char hierarchical; + /* !< Only used in MPEG2, 2 bit field (0 = 8 bit, 1 = 9 bit, 2 = 10 bit and 3=11 bit + * precision). Set to zero for other encode standards. + */ + unsigned char mpeg2_intra_dc_precision; + unsigned char pic_on_level[MAX_REF_LEVELS]; + unsigned int vop_time_resolution; + unsigned short kick_size; //!< Number of Macroblocks per kick + unsigned short kicks_per_bu; //!< Number of kicks per BU + unsigned short kicks_per_picture; //!< Number of kicks per picture + struct img_mv_settings mv_settings_idr; + struct img_mv_settings mv_settings_non_b[MAX_BFRAMES + 1]; + unsigned int mv_settings_b_table; + unsigned int mv_settings_hierarchical; + enum img_format format; //!< Pixel format of the source surface + enum img_standard standard; //!< Encoder standard (H264 / H263 / MPEG4 / JPEG) + enum img_rcmode rc_mode; //!< RC flavour + enum img_rc_vcm_mode rc_vcm_mode; //!< RC VCM flavour + /* !< RC VCM maximum frame size percentage allowed to exceed in CFS */ + unsigned int rc_cfs_max_margin_perc; + unsigned char first_pic; + unsigned char is_interlaced; + unsigned char top_field_first; + unsigned char arbitrary_so; + unsigned char output_reconstructed; + unsigned char disable_bit_stuffing; + unsigned char insert_hrd_params; + unsigned char max_slices_per_picture; + unsigned int f_code; + /* Contents Adaptive Rate Control parameters*/ + unsigned int jmcomp_rc_reg0; + unsigned int jmcomp_rc_reg1; + /* !< Value to use for MVClip_Config register */ + unsigned int mv_clip_config; + /* !< Value to use for Predictor combiner register */ + unsigned int pred_comb_control; + /* !< Value to use for LRITC_Cache_Chunk_Config register */ + unsigned int lritc_cache_chunk_config; + /* !< Value to use for IPEVectorClipping register */ + unsigned int ipe_vector_clipping; + /* !< Value to use for H264CompControl register */ + unsigned int h264_comp_control; + /* !< Value to use for H264CompIntraPredMode register */ + unsigned int h264_comp_intra_pred_modes; + /* !< Value to use for IPCM_0 Config register */ + unsigned int ipcm_0_config; + /* !< Value to use for IPCM_1 Config register */ + unsigned int ipcm_1_config; + /* !< Value to use for SPEMvdClipRange register */ + unsigned int spe_mvd_clip_range; + /* !< Value to use for MB_HOST_CONTROL register */ + unsigned int mb_host_ctrl; + /* !< Value for the CR_DB_DISABLE_DEBLOCK_IDC register */ + unsigned int deblock_ctrl; + /* !< Value for the CR_DB_DISABLE_DEBLOCK_IDC register */ + unsigned int skip_coded_inter_intra; + unsigned int vlc_control; + /* !< Slice control register value. Configures the size of a slice */ + unsigned int vlc_slice_control; + /* !< Slice control register value. Configures the size of a slice */ + unsigned int vlc_slice_mb_control; + /* !< Chroma QP offset to use (when PPS id = 0)*/ + unsigned short cqp_offset; + unsigned char coded_header_per_slice; + unsigned char initial_qp_i; //!< Initial QP I frames + unsigned char initial_qp_p; //!< Initial QP P frames + unsigned char initial_qp_b; //!< Initial QP B frames + unsigned int first_pic_flags; + unsigned int non_first_pic_flags; + unsigned char mc_adaptive_rounding_disable; +#define AR_REG_SIZE 18 +#define AR_DELTA_SIZE 7 + unsigned short mc_adaptive_rounding_offsets[AR_REG_SIZE][4]; + short mc_adaptive_rounding_offsets_delta[AR_DELTA_SIZE][4]; + /* !< Reconstructed address to allow host picture management */ + unsigned int patched_recon_address; + /* !< Reference 0 address to allow host picture management */ + unsigned int patched_ref0_address; + /* !< Reference 1 address to allow host picture management */ + unsigned int patched_ref1_address; + unsigned int ltref_header[MAX_SOURCE_SLOTS_SL]; + signed char slice_header_slot_num; + unsigned char recon_is_longterm; + unsigned char ref0_is_longterm; + unsigned char ref1_is_longterm; + unsigned char ref_spacing; + unsigned char fw_num_pipes; + unsigned char fw_first_pipe; + unsigned char fw_last_pipe; + unsigned char fw_pipes_to_use_flags; +#if SECURE_IO_PORTS + unsigned int secure_io_control; +#endif + struct img_vxe_scaler_setup scaler_setup; + struct img_vxe_csc_setup csc_setup; + + struct in_rc_params in_params; +}; + +/* + * PICMGMT - Command sub-type + */ +enum img_picmgmt_type { + IMG_PICMGMT_REF_TYPE = 0, + IMG_PICMGMT_GOP_STRUCT, + IMG_PICMGMT_SKIP_FRAME, + IMG_PICMGMT_EOS, + IMG_PICMGMT_FLUSH, + IMG_PICMGMT_QUANT, + IMG_PICMGMT_STRIDE, + IMG_PICMGMT_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * MTX- > host message structure + */ +struct img_writeback_msg { + unsigned int cmd_word; + union { + struct { + unsigned int data; + unsigned int extra_data; + unsigned int writeback_val; + }; + unsigned int coded_package_consumed_idx; + }; +}; + +/* + * PROVIDE_SOURCE_BUFFER - Details of the source picture buffer + */ +struct img_source_buffer_params { + /* !< Host context value. Keep at start for alignment. */ + unsigned long long host_context; + unsigned int phys_addr_y_plane_field_0; //!< Source pic phys addr (Y plane, Field 0) + unsigned int phys_addr_u_plane_field_0; //!< Source pic phys addr (U plane, Field 0) + unsigned int phys_addr_v_plane_field_0; //!< Source pic phys addr (V plane, Field 0) + unsigned int phys_addr_y_plane_field_1; //!< Source pic phys addr (Y plane, Field 1) + unsigned int phys_addr_u_plane_field_1; //!< Source pic phys addr (U plane, Field 1) + unsigned int phys_addr_v_plane_field_1; //!< Source pic phys addr (V plane, Field 1) + /* !< Number of frames in the stream (incl. skipped) */ + unsigned char display_order_num; + unsigned char slot_num; //!< Source slot number + unsigned char reserved1; + unsigned char reserved2; +}; + +/* + * Struct describing input parameters to encode a video slice + */ +struct slice_params { + unsigned int flags; //!< Flags for slice encode + + /* Config registers. These are passed straight + * through from drivers to hardware. + */ + unsigned int slice_config; //!< Value to use for Slice Config register + unsigned int ipe_control; //!< Value to use for IPEControl register + /* !MTX = IsLinkedList, list segment + * (CB memory) size, number of list segments per coded buffer + */ + unsigned int coded_buffer_info; + + // PAD TO 64 BYTES + unsigned int padding[16 - MAX_CODED_BUFFERS_PER_PACKAGE_FW - 2]; +}; + +/* + * Contents of the coded data buffer header feedback word + */ +#define SHIFT_CODED_FIRST_BU (24) +#define MASK_CODED_FIRST_BU (0xFFU << SHIFT_CODED_FIRST_BU) +#define SHIFT_CODED_SLICE_NUM (16) +#define MASK_CODED_SLICE_NUM (0xFF << SHIFT_CODED_SLICE_NUM) +#define SHIFT_CODED_STORAGE_FRAME_NUM (14) +#define MASK_CODED_STORAGE_FRAME_NUM (0x03 << SHIFT_CODED_STORAGE_FRAME_NUM) +#define SHIFT_CODED_ENTIRE_FRAME (12) +#define MASK_CODED_ENTIRE_FRAME (0x01 << SHIFT_CODED_ENTIRE_FRAME) +#define SHIFT_CODED_IS_SKIPPED (11) +#define MASK_CODED_IS_SKIPPED (0x01 << SHIFT_CODED_IS_SKIPPED) +#define SHIFT_CODED_IS_CODED (10) +#define MASK_CODED_IS_CODED (0x01 << SHIFT_CODED_IS_CODED) +#define SHIFT_CODED_RECON_IDX (6) +#define MASK_CODED_RECON_IDX (0x0F << SHIFT_CODED_RECON_IDX) +#define SHIFT_CODED_SOURCE_SLOT (2) +#define MASK_CODED_SOURCE_SLOT (0x0F << SHIFT_CODED_SOURCE_SLOT) +#define SHIFT_CODED_FRAME_TYPE (0) +#define MASK_CODED_FRAME_TYPE (0x03 << SHIFT_CODED_FRAME_TYPE) + +/* + * Contents of the coded data buffer header extra feedback word + */ +#define SHIFT_CODED_SLICES_SO_FAR (24) +#define MASK_CODED_SLICES_SO_FAR (0xFFU << SHIFT_CODED_SLICES_SO_FAR) + +#define SHIFT_CODED_SLICES_IN_BUFFER (16) +#define MASK_CODED_SLICES_IN_BUFFER (0xFF << SHIFT_CODED_SLICES_IN_BUFFER) + +#define SHIFT_CODED_BUFFER_NUMBER_USED (2) +#define MASK_CODED_BUFFER_NUMBER_USED (0xFF << SHIFT_CODED_BUFFER_NUMBER_USED) + +#define SHIFT_CODED_FIELD (1) +#define MASK_CODED_FIELD (0x01 << SHIFT_CODED_FIELD) + +#define SHIFT_CODED_PATCHED_RECON (0) +#define MASK_CODED_PATCHED_RECON (0x01 << SHIFT_CODED_PATCHED_RECON) + +#endif /* _TOPAZSCFWIF_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/vxe_common.h b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/vxe_common.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/vxe_common.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/fw_headers/vxe_common.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _VXECOMMON_H_ +#define _VXECOMMON_H_ + +#include "topazscfwif.h" +#include "../common/vid_buf.h" + +/* + * Enum describing buffer lock status + */ +enum lock_status { + BUFFER_FREE = 1, //!< Buffer is not locked + HW_LOCK, //!< Buffer is locked by hardware + SW_LOCK, //!< Buffer is locked by software + NOTDEVICEMEMORY, //!< Buffer is not a device memory buffer + LOCK_ST_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Struct describing a data buffer + */ +struct img_buffer { + struct vidio_ddbufinfo mem_info; //!< Pointer to the memory handle for the buffer + enum lock_status lock; //!< Lock status for the buffer + unsigned int size; //!< Size in bytes of the buffer + unsigned int bytes_written; //!< Number of bytes written into buffer +}; + +/* + * Struct describing a coded data buffer + */ +struct img_coded_buffer { + struct vidio_ddbufinfo mem_info; //!< Pointer to the memory handle for the buffer + enum lock_status lock; //!< Lock status for the buffer + unsigned int size; //!< Size in bytes of the buffer + unsigned int bytes_written; //!< Number of bytes written into buffer +}; + +struct coded_info { + struct img_buffer *code_package_fw_buffer; + struct coded_package_dma_info *coded_package_fw; +}; + +// This structure is used by the Drivers +struct coded_package_host { + struct coded_info mtx_info; + /* Array of pointers to buffers */ + struct img_coded_buffer *coded_buffer[MAX_CODED_BUFFERS_PER_PACKAGE]; + struct img_buffer *header_buffer; + unsigned char num_coded_buffers; + unsigned char busy; +}; + +/* + * Struct describing surface component info + */ +struct img_surf_component_info { + unsigned int step; + unsigned int width; + unsigned int height; + unsigned int phys_width; + unsigned int phys_height; +}; + +/* + * Struct describing a frame + */ +struct img_frame { + struct img_buffer *y_plane_buffer; //!< pointer to the image buffer + struct img_buffer *u_plane_buffer; //!< pointer to the image buffer + struct img_buffer *v_plane_buffer; //!< pointer to the image buffer + unsigned int width_bytes; //!< stride of pBuffer + unsigned int height; //!< height of picture in pBuffer + + unsigned int component_count; //!< number of colour components used + enum img_format format; + unsigned int component_offset[3]; + unsigned int bottom_component_offset[3]; + struct img_surf_component_info component_info[3]; + int y_component_offset; + int u_component_offset; + int v_component_offset; + int field0_y_offset, field1_y_offset; + int field0_u_offset, field1_u_offset; + int field0_v_offset, field1_v_offset; + unsigned short src_y_stride_bytes, src_uv_stride_bytes; + unsigned char imported; +}; + +/* + * Struct describing an array of frames + */ +struct img_frame_array { + unsigned int array_size; //!< Number of frames in array + struct img_frame *frame; //!< Pointer to start of frame array +}; + +/* + * Struct describing list items + */ +struct list_item { + struct list_item *next; //!< Next item in the list + void *data; //!< pointer to list item data +}; + +/* + * Struct describing rate control params + */ +struct img_rc_params { + unsigned int bits_per_second; //!< Bit rate + /* !< Transfer rate of encoded data from encoder to the output */ + unsigned int transfer_bits_per_second; + unsigned int initial_qp_i; //!< Initial QP I frames (only field used by JPEG) + unsigned int initial_qp_p; //!< Initial QP P frames (only field used by JPEG) + unsigned int initial_qp_b; //!< Initial QP B frames (only field used by JPEG) + unsigned int bu_size; //!< Basic unit size + unsigned int frame_rate; + unsigned int buffer_size; + unsigned int intra_freq; + short min_qp; + short max_qp; + unsigned char rc_enable; + int initial_level; + int initial_delay; + unsigned short bframes; + unsigned char hierarchical; + + /* !< Enable movement of slice boundary when Qp is high */ + unsigned char enable_slice_bob; + /* !< Maximum number of rows the slice boundary can be moved */ + unsigned char max_slice_bob; + /* !< Minimum Qp at which slice bobbing should take place */ + unsigned char slice_bob_qp; + + signed char qcp_offset; + unsigned char sc_detect_disable; + unsigned int slice_byte_limit; + unsigned int slice_mb_limit; + enum img_rcmode rc_mode; + enum img_rc_vcm_mode rc_vcm_mode; + unsigned int rc_cfs_max_margin_perc; + unsigned char disable_frame_skipping; + unsigned char disable_vcm_hardware; +}; + +/* + * Bit fields for ui32MmuFlags + */ +#define MMU_USE_MMU_FLAG 0x00000001 +#define MMU_EXTENDED_ADDR_FLAG 0x00000004 + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/header_gen.c b/drivers/media/platform/imagination/vxe-vxd/encoder/header_gen.c --- a/drivers/media/platform/imagination/vxe-vxd/encoder/header_gen.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/header_gen.c 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,1751 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Encoder coded header generation function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#include +#include "fw_headers/topazscfwif.h" +#include "fw_headers/defs.h" +#include "header_gen.h" +#include "img_errors.h" +#include "reg_headers/topazhp_core_regs.h" +#include "topaz_api.h" + +#define ELEMENTS_EMPTY 9999 +#define MAXNUMBERELEMENTS 32 +#define _1080P_30FPS (((1920 * 1088) / 256) * 30) + +void insert_element_token(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, + enum header_element_type token) +{ + unsigned char offset; + unsigned char *p; + + if (mtx_header->elements != ELEMENTS_EMPTY) { + if (element_pointers[mtx_header->elements]->element_type == + ELEMENT_STARTCODE_RAWDATA || + element_pointers[mtx_header->elements]->element_type == ELEMENT_RAWDATA || + element_pointers[mtx_header->elements]->element_type == + ELEMENT_STARTCODE_MIDHDR) { + /* + * Add a new element aligned to word boundary + * Find RAWBit size in bytes (rounded to word boundary)) + * NumberofRawbits (excluding size of bit count field)+ + * size of the bitcount field + */ + offset = element_pointers[mtx_header->elements]->size + 8 + 31; + offset /= 32; /*Now contains rawbits size in words */ + offset += 1; /*Now contains rawbits+element_type size in words */ + /* Convert to number of bytes (total size of structure + * in bytes, aligned to word boundary). + */ + offset *= 4; + } else { + offset = 4; + } + + mtx_header->elements++; + p = (unsigned char *)element_pointers[mtx_header->elements - 1]; + p += offset; + element_pointers[mtx_header->elements] = (struct mtx_header_element *)p; + } else { + mtx_header->elements = 0; + } + + element_pointers[mtx_header->elements]->element_type = token; + element_pointers[mtx_header->elements]->size = 0; +} + +unsigned int write_upto_8bits_to_elements(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, + unsigned int write_bits, unsigned short bit_cnt) +{ + /* This is the core function to write bits/bytes to a header stream, + * it writes them directly to ELEMENT structures. + */ + unsigned char *write_bytes; + unsigned char *size_bits; + union input_value { + unsigned int input16; + unsigned char input8[2]; + } input_val; + + unsigned char out_byte_index; + short shift; + + if (bit_cnt == 0) + return 0; + + /* First ensure that unused bits in ui32WriteBits are zeroed */ + write_bits &= (0x00ff >> (8 - bit_cnt)); + input_val.input16 = 0; + /*Pointer to the bit count field */ + size_bits = &element_pointers[mtx_header->elements]->size; + /*Pointer to the space where header bits are to be written */ + write_bytes = &element_pointers[mtx_header->elements]->bits; + out_byte_index = (size_bits[0] / 8); + + if (!(size_bits[0] & 7)) { + if (size_bits[0] >= 120) { + /*Element maximum bits send to element, time to start a new one */ + mtx_header->elements++; /* Increment element index */ + /*Element pointer set to position of next element (120/8 = 15 bytes) */ + element_pointers[mtx_header->elements] = + (struct mtx_header_element *)&write_bytes[15]; + /*Write ELEMENT_TYPE */ + element_pointers[mtx_header->elements]->element_type = ELEMENT_RAWDATA; + /* Set new element size (bits) to zero */ + element_pointers[mtx_header->elements]->size = 0; + /* Begin writing to the new element */ + write_upto_8bits_to_elements(mtx_header, element_pointers, write_bits, + bit_cnt); + return (unsigned int)bit_cnt; + } + write_bytes[out_byte_index] = 0; /* Beginning a new byte, clear byte */ + } + + shift = (short)((8 - bit_cnt) - (size_bits[0] & 7)); + + if (shift >= 0) { + write_bits <<= shift; + write_bytes[out_byte_index] |= write_bits; + size_bits[0] = size_bits[0] + bit_cnt; + } else { + input_val.input8[1] = (unsigned char)write_bits + 256; + input_val.input16 >>= -shift; + write_bytes[out_byte_index] |= input_val.input8[1]; + + size_bits[0] = size_bits[0] + bit_cnt; + size_bits[0] = size_bits[0] - ((unsigned char)-shift); + input_val.input8[0] = input_val.input8[0] >> (8 + shift); + write_upto_8bits_to_elements(mtx_header, element_pointers, input_val.input8[0], + (unsigned short)-shift); + } + + return (unsigned int)bit_cnt; +} + +unsigned int write_upto_32bits_to_elements(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, + unsigned int write_bits, unsigned int bit_cnt) +{ + unsigned int bit_lp; + unsigned int end_byte; + unsigned char bytes[4]; + + for (bit_lp = 0; bit_lp < 4; bit_lp++) { + bytes[bit_lp] = (unsigned char)(write_bits & 255); + write_bits = write_bits >> 8; + } + + end_byte = ((bit_cnt + 7) / 8); + if ((bit_cnt) % 8) + write_upto_8bits_to_elements(mtx_header, element_pointers, bytes[end_byte - 1], + (unsigned char)((bit_cnt) % 8)); + else + write_upto_8bits_to_elements(mtx_header, element_pointers, bytes[end_byte - 1], 8); + + if (end_byte > 1) + for (bit_lp = end_byte - 1; bit_lp > 0; bit_lp--) + write_upto_8bits_to_elements(mtx_header, element_pointers, + bytes[bit_lp - 1], 8); + + return bit_cnt; +} + +void h264_write_bits_startcode_prefix_element(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, + unsigned int byte_size) +{ + /* GENERATES THE FIRST ELEMENT OF THE H264_SEQUENCE_HEADER() STRUCTURE */ + unsigned int lp; + /* + * Byte aligned (bit 0) + * (3 bytes in slice header when slice is first in + * a picture without sequence/picture_header before picture + */ + for (lp = 0; lp < byte_size - 1; lp++) + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 8); + + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 8); + /* Byte aligned (bit 32 or 24) */ +} + +unsigned int generate_ue(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, unsigned int val) +{ + unsigned int lp; + unsigned char zeros; + unsigned int chunk; + unsigned int bit_cnter = 0; + + for (lp = 1, zeros = 0; (lp - 1) < val; lp = lp + lp, zeros++) + val = val - lp; + + /* + * zeros = number of preceding zeros required + * Val = value to append after zeros and 1 bit + * Write preceding zeros + */ + for (lp = (unsigned int)zeros; lp + 1 > 8; lp -= 8) + bit_cnter += write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 8); + + /* Write zeros and 1 bit set */ + bit_cnter += + write_upto_8bits_to_elements(mtx_header, element_pointers, (unsigned char)1, + (unsigned char)(lp + 1)); + + /* Write Numeric part */ + while (zeros > 8) { + zeros -= 8; + chunk = (val >> zeros); + bit_cnter += write_upto_8bits_to_elements(mtx_header, element_pointers, + (unsigned char)chunk, 8); + val = val - (chunk << zeros); + } + + bit_cnter += write_upto_8bits_to_elements(mtx_header, + element_pointers, (unsigned char)val, zeros); + + return bit_cnter; +} + +unsigned int generate_se(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, int val) +{ + unsigned int bit_cnter; + unsigned int code_num; + + bit_cnter = 0; + + if (val > 0) + code_num = (unsigned int)(val + val - 1); + else + code_num = (unsigned int)(-val - val); + + bit_cnter = generate_ue(mtx_header, element_pointers, code_num); + + return bit_cnter; +} + +void h264_write_bits_scaling_lists(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, + struct h264_scaling_matrix_params *scaling_matrix, + unsigned char write_8x8) +{ + /* Used by H264_WriteBits_SequenceHeader and H264_WriteBits_PictureHeader */ + unsigned int list, index; + int cur_scale, delta_scale; + + if (!scaling_matrix) { + insert_element_token(mtx_header, element_pointers, ELEMENT_CUSTOM_QUANT); + return; + } + + for (list = 0; list < 6; list++) { + /* seq_scaling_list_present_flag[ui32List] = 1 */ + if (scaling_matrix->list_mask & (1 << list)) { + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + + cur_scale = 8; + for (index = 0; index < 16; index++) { + delta_scale = + ((int)scaling_matrix->scaling_lists4x4[list][index]) - + cur_scale; + cur_scale += delta_scale; + /* delta_scale */ + generate_se(mtx_header, element_pointers, delta_scale); + } + } else { + /* seq_scaling_list_present_flag[ui32List] = 0 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + } + } + + if (!write_8x8) + return; + + for (; list < 8; list++) { + /* seq_scaling_list_present_flag[ui32List] = 1 */ + if (scaling_matrix->list_mask & (1 << list)) { + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + + cur_scale = 8; + for (index = 0; index < 64; index++) { + delta_scale = + ((int)scaling_matrix->scaling_lists8x8[list - 6][index]) - + cur_scale; + cur_scale += delta_scale; + /* delta_scale */ + generate_se(mtx_header, element_pointers, delta_scale); + } + } else { + /* seq_scaling_list_present_flag[ui32List] = 0 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + } + } +} + +void h264_write_bits_vui_params(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, + struct h264_vui_params *vui_params) +{ + /* Builds VUI Params for the Sequence Header (only present in the 1st sequence of stream) */ + + if (vui_params->aspect_ratio_info_present_flag == 1) { + /* aspect_ratio_info_present_flag = 1 in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + vui_params->aspect_ratio_info_present_flag, 1); + /* aspect_ratio_idc (8 bits) = vui_params->aspect_ratio_idc in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + vui_params->aspect_ratio_idc, 8); + + if (vui_params->aspect_ratio_idc == 255) { + write_upto_8bits_to_elements(mtx_header, element_pointers, + (vui_params->sar_width >> 8), 8); + write_upto_8bits_to_elements(mtx_header, element_pointers, + vui_params->sar_width, 8); + write_upto_8bits_to_elements(mtx_header, element_pointers, + (vui_params->sar_height >> 8), 8); + write_upto_8bits_to_elements(mtx_header, element_pointers, + vui_params->sar_height, 8); + } + } else { + /* aspect_ratio_info_present_flag = 0 in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + } + + write_upto_8bits_to_elements(mtx_header, element_pointers, + /* overscan_info_present_flag (1 bit) = 0 in Topaz */ + (0 << 3) | + /* video_signal_type_present_flag (1 bit) = 0 in Topaz */ + (0 << 2) | + /* chroma_loc_info_present_flag (1 bit) = 0 in Topaz */ + (0 << 1) | + /* timing_info_present_flag (1 bit) = 1 in Topaz */ + (1), + /* num_units_in_tick (32 bits) = 1 in Topaz */ + 4); + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 8); + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 8); + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 8); + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 8); + + /* time_scale (32 bits) = frame rate */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 8); + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 8); + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 8); + write_upto_8bits_to_elements(mtx_header, element_pointers, + (unsigned char)vui_params->time_scale, 8); + /* fixed_frame_rate_flag (1 bit) = 1 in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + /* nal_hrd_parameters_present_flag (1 bit) = 1 in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + /* Definitions for nal_hrd_parameters() contained in VUI structure for Topaz + * cpb_cnt_minus1 ue(v) = 0 in Topaz = 1b + */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + /* bit_rate_scale (4 bits) = 0 in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 4); + /* cpb_size_scale (4 bits) = 2 in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 2, 4); + /* bit_rate_value_minus1[0] ue(v) = (Bitrate/64)-1 [RANGE:0 to (2^32)-2] */ + generate_ue(mtx_header, element_pointers, vui_params->bit_rate_value_minus1); + /* cpb_size_value_minus1[0] ue(v) = (CPB_Bits_Size/16)- + * 1 where CPB_Bits_Size = 1.5 * Bitrate [RANGE:0 to (2^32)-2] + */ + generate_ue(mtx_header, element_pointers, vui_params->cbp_size_value_minus1); + /* cbr_flag[0] (1 bit) = 0 for VBR, 1 for CBR */ + write_upto_8bits_to_elements(mtx_header, element_pointers, vui_params->cbr, 1); + /*initial_cpb_removal_delay_length_minus1 (5 bits) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + vui_params->initial_cpb_removal_delay_length_minus1, 5); + /* cpb_removal_delay_length_minus1 (5 bits) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + vui_params->cpb_removal_delay_length_minus1, 5); + /* dpb_output_delay_length_minus1 (5 bits) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + vui_params->dpb_output_delay_length_minus1, 5); + /* time_offst_length (5 bits) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, vui_params->time_offset_length, + 5); + + /* End of nal_hrd_parameters() */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + /* low_delay_hrd_flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + /* pic_struct_present_flag (1 bit) = 0 in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + + write_upto_8bits_to_elements(mtx_header, element_pointers, + /* bitstream_restriction_flag (1 bit) = 1 in Topaz */ + (1 << 1) | + /* motion_vectors_over_pic_boundaries_flag (1 bit) = 1 + * in Topaz; + */ + (1 << 0), + 2); + /* max_bytes_per_pic_denom ue(v) = 0 */ + generate_ue(mtx_header, element_pointers, 0); + /* max_bits_per_mb_denom ue(v) = 0 */ + generate_ue(mtx_header, element_pointers, 0); + /* log2_max_mv_length_horizontal ue(v) = 9(max horizontal vector is 128 integer samples) */ + generate_ue(mtx_header, element_pointers, 9); + /* log2_max_mv_length_vertical ue(v) = 9 (max vertical vecotr is 103 integer samples) */ + generate_ue(mtx_header, element_pointers, 9); + /* num_reorder_frames ue(v) = 0 */ + generate_ue(mtx_header, element_pointers, vui_params->num_reorder_frames); + /* max_dec_frame_buffering ue(v) = 0 */ + generate_ue(mtx_header, element_pointers, vui_params->max_dec_frame_buffering); +} + +void h264_write_bits_sequence_header(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, + struct h264_sequence_header_params *sh_params, + struct h264_crop_params *crop, + struct h264_scaling_matrix_params *scaling_matrix, + unsigned char aso) +{ + /* calculate some of the VUI parameters here */ + if (sh_params->profile == SH_PROFILE_BP) { + /* for Baseline profile we never re-roder frames */ + sh_params->vui_params.num_reorder_frames = 0; + sh_params->vui_params.max_dec_frame_buffering = sh_params->max_num_ref_frames; + } else { + /* in higher profiles we can do up to 3 level hierarchical B frames */ + if (!sh_params->vui_params.num_reorder_frames) + sh_params->vui_params.num_reorder_frames = sh_params->max_num_ref_frames; + sh_params->vui_params.max_dec_frame_buffering = + max(sh_params->max_num_ref_frames, + sh_params->vui_params.num_reorder_frames); + } + + insert_element_token(mtx_header, element_pointers, ELEMENT_STARTCODE_RAWDATA); + h264_write_bits_startcode_prefix_element(mtx_header, element_pointers, 4); + + /* GENERATES THE FIRST ELEMENT OF THE H264_SEQUENCE_HEADER() STRUCTURE */ + /* + * 4 Byte StartCodePrefix Pregenerated in: H264_WriteBits_StartCodePrefix_Element() + * Byte aligned (bit 32) + * forbidden_zero_bit=0 + */ + write_upto_8bits_to_elements(mtx_header, element_pointers, (0 << 7) | + (0x3 << 5) | /* nal_ref_idc=01 (may be 11) */ + (7), /* nal_unit_type=00111 */ + 8); + + /* Byte aligned (bit 40) */ + switch (sh_params->profile) { + case SH_PROFILE_BP: + /* profile_idc = 8 bits = 66 for BP (PROFILE_IDC_BP) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 66, 8); + + /* Byte aligned (bit 48) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + /* constraint_set0_flag = 1 for BP constra ints */ + (1 << 7) | + /* constraint_set1_flag = 1 for MP constraints */ + ((aso ? 0 : 1) << 6) | + /* constraint_set2_flag = 1 for EP constra ints */ + (1 << 5) | + /* constraint_set3_flag = 1 + * for level 1b, 0 for others + */ + ((sh_params->level == SH_LEVEL_1B ? 1 : 0) << 4), + /* reserved_zero_4bits = 0 */ + 8); + break; + + case SH_PROFILE_MP: + /* profile_idc = 8 bits = 77 for MP (PROFILE_IDC_MP) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 77, 8); + + /* Byte aligned (bit 48) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + /* constraint_set0_flag = 0 for no BP constraints */ + (0 << 7) | + /* constraint_set1_flag = 1 for MP constraints */ + (1 << 6) | + /* constraint_set2_flag = 1 for EP constraints */ + (1 << 5) | + /* constraint_set3_flag = 1 + * for level 1b, 0 for others + */ + ((sh_params->level == SH_LEVEL_1B ? 1 : 0) << 4), + /* reserved_zero_4bits = 0 */ + 8); + break; + + case SH_PROFILE_HP: + /* profile_idc = 8 bits = 100 for HP (PROFILE_IDC_HP) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 100, 8); + + /* Byte aligned (bit 48) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + /* constraint_set0_flag = 0 for no BP constraints */ + (0 << 7) | + /* constraint_set1_flag = 0 for no MP constraints */ + (0 << 6) | + /* constraint_set2_flag = 0 for no EP constraints */ + (0 << 5) | + /* constraint_set3_flag = 0 */ + (0 << 4), + /* reserved_zero_4bits = 0 */ + 8); + break; + + case SH_PROFILE_H444P: + /* profile_idc = 8 bits = 244 for H444P (PROFILE_IDC_H444P) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 244, 8); + + /* Byte aligned (bit 48) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + /* constraint_set0_flag = 0 for no BP constraints */ + (0 << 7) | + /* constraint_set1_flag = 0 for no MP constraints */ + (0 << 6) | + /* constraint_set2_flag = 0 for no EP constraints */ + (0 << 5) | + /* constraint_set3_flag = 0 */ + (0 << 4), + /* reserved_zero_4bits = 0 */ + 8); + break; + + default: + break; + } + + /* + * Byte aligned (bit 56) + * level_idc should be set to 9 in the sps in case of + * level is Level 1B and the profile is High or High 4:4:4 Profile + */ + if (sh_params->profile == SH_PROFILE_HP || sh_params->profile == SH_PROFILE_H444P) + /* level_idc (8 bits) = 9 for 1b, 10xlevel for others */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + (sh_params->level == SH_LEVEL_1B) ? 9 : + (unsigned char)sh_params->level, 8); + + else + /* level_idc (8 bits) = 11 for 1b, 10xlevel for others */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + (sh_params->level == SH_LEVEL_1B) ? 11 : + (unsigned char)sh_params->level, 8); + + generate_ue(mtx_header, element_pointers, 0); /* seq_parameter_set_id = 0 */ + + if (sh_params->profile == SH_PROFILE_HP || sh_params->profile == SH_PROFILE_H444P) { + generate_ue(mtx_header, element_pointers, 1); /* chroma_format_idc = 1 */ + /* bit_depth_luma_minus8 = 0 */ + generate_ue(mtx_header, element_pointers, 0); + /* bit_depth_chroma_minus8 = 0 */ + generate_ue(mtx_header, element_pointers, 0); + + write_upto_8bits_to_elements(mtx_header, element_pointers, + /* qpprime_y_zero_transform_bypass_flag = 1 + * if lossless + */ + sh_params->is_lossless ? 1 : 0, 1); + + if (sh_params->use_default_scaling_list || + sh_params->seq_scaling_matrix_present_flag) { + /* seq_scaling_matrix_present_flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + if (!sh_params->use_default_scaling_list) { + h264_write_bits_scaling_lists(mtx_header, element_pointers, + scaling_matrix, TRUE); + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + } else { + /* seq_scaling_list_present_flag[i] = 0; 0 < i < 8 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 8); + } + } else { + /* seq_scaling_matrix_present_flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + } + } + + generate_ue(mtx_header, element_pointers, 1); /* log2_max_frame_num_minus4 = 1 */ + generate_ue(mtx_header, element_pointers, 0); /* pic_order_cnt_type = 0 */ + /* log2_max_pic_order_cnt_Isb_minus4 = 2 */ + generate_ue(mtx_header, element_pointers, sh_params->log2_max_pic_order_cnt - 4); + /*num_ref_frames ue(2), typically 2 */ + generate_ue(mtx_header, element_pointers, sh_params->max_num_ref_frames); + + /* Bytes aligned (bit 72) */ + /* gaps_in_frame_num_value_allowed_Flag - (1 bit) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + (sh_params->gaps_in_frame_num_value), 1); + + /* + * GENERATES THE SECOND, VARIABLE LENGTH, ELEMENT OF THE H264_SEQUENCE_HEADER() STRUCTURE + * ELEMENT BITCOUNT: xx + */ + /*pic_width_in_mbs_minus1: ue(v) from 10 to 44 (176 to 720 pixel per row) */ + generate_ue(mtx_header, element_pointers, sh_params->width_in_mbs_minus1); + /* pic_height_in_maps_units_minus1: + * ue(v) Value from 8 to 35 (144 to 576 pixels per column) + */ + generate_ue(mtx_header, element_pointers, sh_params->height_in_maps_units_minus1); + /* We don't know the alignment at this point, so will have to use bit writing functions */ + /* frame_mb_only_flag 1=frame encoding, 0=field encoding */ + write_upto_8bits_to_elements(mtx_header, element_pointers, sh_params->frame_mbs_only_flag, + 1); + + if (!sh_params->frame_mbs_only_flag) /* in the case of interlaced encoding */ + /* mb_adaptive_frame_field_flag = 0 in Topaz(field encoding at the sequence level) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + + /* direct_8x8_inference_flag=1 in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + + if (crop->clip) { + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + generate_ue(mtx_header, element_pointers, crop->left_crop_offset); + generate_ue(mtx_header, element_pointers, crop->right_crop_offset); + generate_ue(mtx_header, element_pointers, crop->top_crop_offset); + generate_ue(mtx_header, element_pointers, crop->bottom_crop_offset); + } else { + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + } + + /* + * GENERATES THE THIRD ELEMENT OF THE H264_SEQUENCE_HEADER() STRUCTURE + * ELEMENT BITCOUNT: xx + */ + /* vui_parameters_present_flag (VUI only in 1st sequence of stream) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + (sh_params->vui_params_present), + 1); + if (sh_params->vui_params_present > 0) + h264_write_bits_vui_params(mtx_header, element_pointers, &sh_params->vui_params); + + /* Finally we need to align to the next byte */ + /* Tell MTX to insert the byte align field (we don't know + * final stream size for alignment at this point) + */ + insert_element_token(mtx_header, element_pointers, ELEMENT_INSERTBYTEALIGN_H264); +} + +/* + * Prepare an H264 SPS in a form for the MTX to encode into a bitstream. + */ +void h264_prepare_sequence_header(struct mtx_header_params *mtx_header, + unsigned int pic_width_in_mbs, + unsigned int pic_height_in_mbs, + unsigned char vui_params_present, + struct h264_vui_params *params, + struct h264_crop_params *crop, + struct h264_sequence_header_params *sh_params, + unsigned char aso) +{ + struct mtx_header_element *this_element; + struct mtx_header_element *element_pointers[MAXNUMBERELEMENTS]; + + /* + * Builds a sequence, picture and slice header with from the given inputs + * parameters (start of new frame) Essential we initialise our header + * structures before building + */ + mtx_header->elements = ELEMENTS_EMPTY; + this_element = (struct mtx_header_element *)mtx_header->element_stream; + element_pointers[0] = this_element; + + h264_write_bits_sequence_header(mtx_header, element_pointers, sh_params, crop, NULL, aso); + /*Has been used as an index, so need to add 1 for a valid element count */ + mtx_header->elements++; +} + +void h264_write_bits_picture_header(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, + struct h264_picture_header_params *ph_params, + struct h264_scaling_matrix_params *scaling_matrix) +{ + /* Begin building the picture header element */ + insert_element_token(mtx_header, element_pointers, ELEMENT_STARTCODE_RAWDATA); + + h264_write_bits_startcode_prefix_element(mtx_header, element_pointers, 4); + + /* GENERATES THE FIRST (STATIC) ELEMENT OF THE H264_PICTURE_HEADER() STRUCTURE + * ELEMENT BITCOUNT: 18 + * 4 Byte StartCodePrefix Pregenerated in: H264_WriteBits_StartCodePrefix_Element() + * Byte aligned (bit 32) + */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + (0 << 7) | /* forbidden_zero_bit */ + (1 << 5) | /* nal_ref_idc (2 bits) = 1 */ + (8), /* nal_unit_tpye (5 bits) = 8 */ + 8); + + /* Byte aligned (bit 40) */ + /* pic_parameter_set_id ue(v) */ + generate_ue(mtx_header, element_pointers, ph_params->pic_parameter_set_id); + /* seq_parameter_set_id ue(v) */ + generate_ue(mtx_header, element_pointers, ph_params->seq_parameter_set_id); + + /* entropy_coding_mode_flag (1 bit) 0 for CAVLC */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + (ph_params->entropy_coding_mode_flag << 4) | + (0 << 3) | /* pic_order_present_flag (1 bit) = 0 */ + (1 << 2) | /* num_slice_group_minus1 ue(v) = 0 in Topaz */ + (1 << 1) | /* num_ref_idx_l0_active_minus1 ue(v) = 0 in Topaz*/ + (1),/* num_ref_idx_l1_active_minus1 ue(v) = 0 in Topaz */ + 5); + + /* WEIGHTED PREDICTION */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + /* weighted_pred_flag (1 bit) */ + (ph_params->weighted_pred_flag << 2) | + /* weighted_bipred_flag (2 bits) */ + (ph_params->weighted_bipred_idc), 3); + + /*MTX fills this value in */ + insert_element_token(mtx_header, element_pointers, ELEMENT_QP); + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + + /* + * GENERATES THE SECOND ELEMENT OF THE H264_PICTURE_HEADER() STRUCTURE + * ELEMENT BITCOUNT: 5 + * The following field will be generated as a special case by MTX - so not here + * Generate_se(mtx_header, ph_params->pic_init_qp_minus26); pic_int_qp_minus26 + * se(v) = -26 to 25 in Topaz + */ + generate_se(mtx_header, element_pointers, 0); /* pic_int_qs_minus26 se(v) = 0 in Topaz */ + /* chroma_qp_index_offset se(v) = 0 in Topaz */ + generate_se(mtx_header, element_pointers, ph_params->chroma_qp_index_offset); + /* deblocking_filter_control_present_flag (1 bit) = 1 in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, (1 << 2) | + /* constrained_intra_pred_Flag (1 bit) = 0 in Topaz */ + (ph_params->constrained_intra_pred_flag << 1) | + /* redundant_pic_cnt_present_flag (1 bit) = 0 in Topaz */ + (0), + 3); + + if (ph_params->transform_8x8_mode_flag || + ph_params->second_chroma_qp_index_offset != ph_params->chroma_qp_index_offset || + ph_params->pic_scaling_matrix_present_flag) { + /* 8x8 transform flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + ph_params->transform_8x8_mode_flag, 1); + if (ph_params->pic_scaling_matrix_present_flag) { + /* pic_scaling_matrix_present_flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + if (!ph_params->use_default_scaling_list) { + h264_write_bits_scaling_lists(mtx_header, element_pointers, + scaling_matrix, + ph_params->transform_8x8_mode_flag); + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + } else { + unsigned char scaling_list_size = + ph_params->transform_8x8_mode_flag ? 8 : 6; + + /* pic_scaling_list_present_flag[i] = 0; + * 0 < i < 6 (+ 2 ( +4 for chroma444) for 8x8) + */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, + scaling_list_size); + } + } else { + /* pic_scaling_matrix_present_flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + } + /* second_chroma_qp_index_offset se(v) = 0 in Topaz */ + generate_se(mtx_header, element_pointers, ph_params->second_chroma_qp_index_offset); + } + /* Tell MTX to insert the byte align field (we don't know final + * stream size for alignment at this point) + */ + insert_element_token(mtx_header, element_pointers, ELEMENT_INSERTBYTEALIGN_H264); +} + +/* + * Prepare an H264 PPS in a form for the MTX to encode into a bitstream + */ +void h264_prepare_picture_header(struct mtx_header_params *mtx_header, + unsigned char cabac_enabled, + unsigned char transform_8x8, + unsigned char intra_constrained, + signed char cqp_offset, + unsigned char weighted_prediction, + unsigned char weighted_bi_pred, + unsigned char mvc_pps, + unsigned char scaling_matrix, + unsigned char scaling_lists) +{ + /* + * Builds a picture header with from the given inputs parameters (start of new frame) + * Essential we initialise our header structures before building + */ + struct h264_picture_header_params ph_params; + struct mtx_header_element *this_element; + struct mtx_header_element *element_pointers[MAXNUMBERELEMENTS]; + + mtx_header->elements = ELEMENTS_EMPTY; + this_element = (struct mtx_header_element *)mtx_header->element_stream; + element_pointers[0] = this_element; + + ph_params.pic_parameter_set_id = mvc_pps ? MVC_PPS_ID : 0; + ph_params.seq_parameter_set_id = mvc_pps ? MVC_SPS_ID : 0; + ph_params.entropy_coding_mode_flag = cabac_enabled ? 1 : 0; + ph_params.weighted_pred_flag = weighted_prediction; + ph_params.weighted_bipred_idc = weighted_bi_pred; + ph_params.chroma_qp_index_offset = cqp_offset; + ph_params.constrained_intra_pred_flag = intra_constrained ? 1 : 0; + ph_params.transform_8x8_mode_flag = transform_8x8 ? 1 : 0; + ph_params.pic_scaling_matrix_present_flag = scaling_matrix ? 1 : 0; + ph_params.use_default_scaling_list = !scaling_lists; + ph_params.second_chroma_qp_index_offset = cqp_offset; + + h264_write_bits_picture_header(mtx_header, element_pointers, &ph_params, NULL); + /*Has been used as an index, so need to add 1 for a valid element count */ + mtx_header->elements++; +} + +/* SEI_INSERTION */ +void h264_write_bits_aud_header(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers) +{ + /* Essential we insert the element before we try to fill it! */ + insert_element_token(mtx_header, element_pointers, ELEMENT_STARTCODE_RAWDATA); + /* 00 00 00 01 start code prefix */ + h264_write_bits_startcode_prefix_element(mtx_header, element_pointers, 4); + /* AUD nal_unit_type = 09 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 9, 8); + + /* primary_pic_type u(3) 0=I slice, 1=P or I slice, 2=P,B or I slice */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 2, 3); + /* rbsp_trailing_bits */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1 << 4, 5); + + /* Write terminator */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0x80, 8); +} + +void h264_prepare_aud_header(struct mtx_header_params *mtx_header) +{ + /* Essential we initialise our header structures before building */ + struct mtx_header_element *this_element; + struct mtx_header_element *element_pointers[MAXNUMBERELEMENTS]; + + mtx_header->elements = ELEMENTS_EMPTY; + this_element = (struct mtx_header_element *)mtx_header->element_stream; + element_pointers[0] = this_element; + + h264_write_bits_aud_header(mtx_header, element_pointers); + /*Has been used as an index, so need to add 1 for a valid element count */ + mtx_header->elements++; +} + +static void insert_prefix_nal_header(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, + struct h264_slice_header_params *slh_params, + unsigned char cabac_enabled) +{ + insert_element_token(mtx_header, element_pointers, ELEMENT_STARTCODE_RAWDATA); + /*Can be 3 or 4 bytes - always 4 bytes in our implementations */ + h264_write_bits_startcode_prefix_element(mtx_header, element_pointers, + slh_params->startcode_prefix_size_bytes); + + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + /* forbidden_zero_bit */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + /*MTX fills this value in */ + insert_element_token(mtx_header, element_pointers, ELEMENT_REFERENCE); + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + /* nal unit type */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 14, 5); + /* SVC extension flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + /* non_idr_flag flag */ + if (slh_params->slice_frame_type == SLHP_IDR_SLICEFRAME_TYPE) + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + else + /* non_idr_flag flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + /* priority_id flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 6); + /* view_id flag */ + write_upto_32bits_to_elements(mtx_header, element_pointers, 0, 10); + /* temporal_id flag */ + insert_element_token(mtx_header, element_pointers, ELEMENT_TEMPORAL_ID); + /* anchor_pic_flag */ + insert_element_token(mtx_header, element_pointers, ELEMENT_ANCHOR_PIC_FLAG); + + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + /* interview flag */ + if (slh_params->slice_frame_type == SLHP_B_SLICEFRAME_TYPE) + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + else + /* interview flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + /* reserved one bit */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); +} + +/* helper function to start new raw data block */ +static unsigned char start_next_rawdata_element = FALSE; +static void check_start_rawdata_element(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers) +{ + if (start_next_rawdata_element) { + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + start_next_rawdata_element = FALSE; + } +} + +void h264_write_bits_extension_slice_header(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, + struct h264_slice_header_params *slh_params, + unsigned char cabac_enabled, + unsigned char is_idr) +{ + start_next_rawdata_element = FALSE; + + insert_element_token(mtx_header, element_pointers, ELEMENT_STARTCODE_RAWDATA); + /*Can be 3 or 4 bytes - always 4 bytes in our implementations */ + h264_write_bits_startcode_prefix_element(mtx_header, element_pointers, + slh_params->startcode_prefix_size_bytes); + + /* GENERATES THE FIRST ELEMENT OF THE H264_SLICE_HEADER() STRUCTURE + * ELEMENT BITCOUNT: 8 + + * StartCodePrefix Pregenerated in: Build_H264_4Byte_StartCodePrefix_Element() + * (4 or 3 bytes) (3 bytes when slice is first in a picture without + * sequence/picture_header before picture Byte aligned (bit 32 or 24) + * NOTE: Slice_Type and Frame_Type are always the same, hence slice_frame_type + */ + /* forbidden_zero_bit */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + /*MTX fills this value in */ + insert_element_token(mtx_header, element_pointers, ELEMENT_REFERENCE); + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + /* nal_unit_type for coded_slice_extension */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 20, 5); + /* SVC extension flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + + if (slh_params->slice_frame_type == SLHP_IDR_SLICEFRAME_TYPE) + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + /* non_idr_flag flag */ + else if ((slh_params->slice_frame_type == SLHP_P_SLICEFRAME_TYPE) && is_idr) + /* non_idr_flag flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + else + /* non_idr_flag flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + /* priority_id flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 6); + /* view_id = hardcoded to 1 for dependent view */ + write_upto_32bits_to_elements(mtx_header, element_pointers, 1, 10); + /* temporal_id flag */ + insert_element_token(mtx_header, element_pointers, ELEMENT_TEMPORAL_ID); + /* anchor_pic_flag */ + insert_element_token(mtx_header, element_pointers, ELEMENT_ANCHOR_PIC_FLAG); + + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + /* interview flag is always FALSE for dependent frames */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + /* reserved one bit */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + + /* slice header */ + /*MTX fills this value in */ + insert_element_token(mtx_header, element_pointers, ELEMENT_CURRMBNR); + + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + + /* GENERATES THE SECOND ELEMENT OF THE H264_SLICE_HEADER() STRUCTURE */ + + generate_ue(mtx_header, element_pointers, + (unsigned int)((slh_params->slice_frame_type == + SLHP_IDR_SLICEFRAME_TYPE) ? SLHP_I_SLICEFRAME_TYPE : + slh_params->slice_frame_type)); + /*slice_type ue(v): 0 for P-slice, 1 for B-slice, 2 for I-slice */ + + /* pic_parameter_set_id = 1 for dependent view */ + generate_ue(mtx_header, element_pointers, 1); + + /* Insert token to tell MTX to insert frame_num */ + insert_element_token(mtx_header, element_pointers, ELEMENT_FRAME_NUM); + start_next_rawdata_element = TRUE; + + if (slh_params->pic_interlace || + slh_params->slice_frame_type == SLHP_IDR_SLICEFRAME_TYPE) { + /* interlaced encoding */ + if (slh_params->pic_interlace) { + check_start_rawdata_element(mtx_header, element_pointers); + /* field_pic_flag = 1 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + /* Insert token to tell MTX to insert BOTTOM_FIELD flag if required */ + insert_element_token(mtx_header, element_pointers, ELEMENT_BOTTOM_FIELD); + start_next_rawdata_element = TRUE; + } + } + + if (slh_params->slice_frame_type == SLHP_IDR_SLICEFRAME_TYPE || (is_idr)) { + check_start_rawdata_element(mtx_header, element_pointers); + /* idr_pic_id ue(v) = 0 (1b) in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + } + /* Insert token to tell MTX to insert pic_order_cnt_lsb */ + insert_element_token(mtx_header, element_pointers, ELEMENT_PIC_ORDER_CNT); + start_next_rawdata_element = TRUE; + + if (slh_params->slice_frame_type == SLHP_B_SLICEFRAME_TYPE) + /* Insert token to tell MTX to insert direct_spatial_mv_pred_flag */ + insert_element_token(mtx_header, element_pointers, ELEMENT_DIRECT_SPATIAL_MV_FLAG); + + if (slh_params->slice_frame_type == SLHP_P_SLICEFRAME_TYPE) { + insert_element_token(mtx_header, element_pointers, ELEMENT_NUM_REF_IDX_ACTIVE); + start_next_rawdata_element = TRUE; + } else if (slh_params->slice_frame_type == SLHP_B_SLICEFRAME_TYPE) { + check_start_rawdata_element(mtx_header, element_pointers); + /* num_ref_idx_active_override_flag (1 bit) = 0 in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + } + + /* reference picture list modification */ + if (slh_params->slice_frame_type != SLHP_I_SLICEFRAME_TYPE && + slh_params->slice_frame_type != SLHP_IDR_SLICEFRAME_TYPE) { + /* Insert token to tell MTX to insert BOTTOM_FIELD flag if required */ + insert_element_token(mtx_header, element_pointers, ELEMENT_REORDER_L0); + start_next_rawdata_element = TRUE; + } + + if (slh_params->slice_frame_type == SLHP_B_SLICEFRAME_TYPE) { + check_start_rawdata_element(mtx_header, element_pointers); + /* ref_pic_list_ordering_flag_l1 (1 bit) = 0, no reference + * picture ordering in Topaz + */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + } + + if (slh_params->slice_frame_type == SLHP_IDR_SLICEFRAME_TYPE || (is_idr)) { + check_start_rawdata_element(mtx_header, element_pointers); + /* no_output_of_prior_pics_flag (1 bit) = 0 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + /* long_term_reference_flag (1 bit) = 0 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + } else { + /*MTX fills this value in */ + insert_element_token(mtx_header, element_pointers, ELEMENT_ADAPTIVE); + start_next_rawdata_element = TRUE; + } + + if (cabac_enabled && (slh_params->slice_frame_type == SLHP_P_SLICEFRAME_TYPE || + slh_params->slice_frame_type == SLHP_B_SLICEFRAME_TYPE)) { + check_start_rawdata_element(mtx_header, element_pointers); + /* hard code cabac_init_idc value of 0 */ + generate_ue(mtx_header, element_pointers, 0); + } + + /*MTX fills this value in */ + insert_element_token(mtx_header, element_pointers, ELEMENT_SQP); + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + + /* GENERATES ELEMENT OF THE H264_SLICE_HEADER() STRUCTURE + * ELEMENT BITCOUNT: 11 + */ + /*disable_deblocking_filter_idc ue(v) = 2? */ + generate_ue(mtx_header, element_pointers, slh_params->disable_deblocking_filter_idc); + if (slh_params->disable_deblocking_filter_idc != 1) { + /*slice_alpha_c0_offset_div2 se(v) = 0 (1b) in Topaz */ + generate_se(mtx_header, element_pointers, slh_params->deb_alpha_offset_div2); + /*slice_beta_offset_div2 se(v) = 0 (1b) in Topaz */ + generate_se(mtx_header, element_pointers, slh_params->deb_beta_offset_div2); + } + /* + * num_slice_groups_minus1 ==0 in Topaz, so no slice_group_change_cycle field here + * no byte alignment at end of slice headers + */ +} + +void h264_write_bits_slice_header(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, + struct h264_slice_header_params *slh_params, + unsigned char cabac_enabled, unsigned char is_idr) +{ + start_next_rawdata_element = FALSE; + if (slh_params->mvc_view_idx == (unsigned short)(NON_MVC_VIEW)) { + insert_element_token(mtx_header, element_pointers, ELEMENT_STARTCODE_RAWDATA); + } else if (slh_params->mvc_view_idx == MVC_BASE_VIEW_IDX) { + insert_prefix_nal_header(mtx_header, element_pointers, slh_params, cabac_enabled); + insert_element_token(mtx_header, element_pointers, ELEMENT_STARTCODE_MIDHDR); + } else { + /*Insert */ + h264_write_bits_extension_slice_header(mtx_header, element_pointers, + slh_params, cabac_enabled, is_idr); + return; + } + + h264_write_bits_startcode_prefix_element(mtx_header, element_pointers, + /*Can be 3 or 4 bytes - always 4 + * bytes in our implementations + */ + slh_params->startcode_prefix_size_bytes); + + /* GENERATES THE FIRST ELEMENT OF THE H264_SLICE_HEADER() STRUCTURE + * ELEMENT BITCOUNT: 8 + + * StartCodePrefix Pregenerated in: Build_H264_4Byte_StartCodePrefix_Element() + * (4 or 3 bytes) (3 bytes when slice is first in a picture without + * sequence/picture_header before picture Byte aligned (bit 32 or 24) + * NOTE: Slice_Type and Frame_Type are always the same, hence slice_frame_type + */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); /* forbidden_zero_bit */ + + /*MTX fills this value in */ + insert_element_token(mtx_header, element_pointers, ELEMENT_REFERENCE); + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + + write_upto_8bits_to_elements(mtx_header, element_pointers, + /* nal_unit_tpye (5 bits) = I-frame IDR, and 1 for rest */ + ((slh_params->slice_frame_type == SLHP_IDR_SLICEFRAME_TYPE ? + 5 : 1)), 5); + + /*MTX fills this value in */ + insert_element_token(mtx_header, element_pointers, ELEMENT_CURRMBNR); + + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + + /* GENERATES THE SECOND ELEMENT OF THE H264_SLICE_HEADER() STRUCTURE */ + + generate_ue(mtx_header, element_pointers, + (unsigned int)((slh_params->slice_frame_type == SLHP_IDR_SLICEFRAME_TYPE) ? + /*slice_type ue(v): 0 for P-slice, 1 for B-slice, 2 for I-slice */ + SLHP_I_SLICEFRAME_TYPE : slh_params->slice_frame_type)); + + if (slh_params->mvc_view_idx != (unsigned short)(NON_MVC_VIEW)) + /* pic_parameter_set_id = 0 */ + generate_ue(mtx_header, element_pointers, slh_params->mvc_view_idx); + else + generate_ue(mtx_header, element_pointers, 0); /* pic_parameter_set_id = 0 */ + /* Insert token to tell MTX to insert frame_num */ + insert_element_token(mtx_header, element_pointers, ELEMENT_FRAME_NUM); + + if (slh_params->pic_interlace || + slh_params->slice_frame_type == SLHP_IDR_SLICEFRAME_TYPE) { + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + /* interlaced encoding */ + if (slh_params->pic_interlace) { + /* field_pic_flag = 1 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + /* Insert token to tell MTX to insert BOTTOM_FIELD flag if required */ + insert_element_token(mtx_header, element_pointers, ELEMENT_BOTTOM_FIELD); + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + } + + if (slh_params->slice_frame_type == SLHP_IDR_SLICEFRAME_TYPE) + /* idr_pic_id ue(v) */ + insert_element_token(mtx_header, element_pointers, ELEMENT_IDR_PIC_ID); + } + /* Insert token to tell MTX to insert pic_order_cnt_lsb */ + insert_element_token(mtx_header, element_pointers, ELEMENT_PIC_ORDER_CNT); + + if (slh_params->slice_frame_type == SLHP_B_SLICEFRAME_TYPE) + /* Insert token to tell MTX to insert direct_spatial_mv_pred_flag */ + insert_element_token(mtx_header, element_pointers, ELEMENT_DIRECT_SPATIAL_MV_FLAG); + + if (slh_params->slice_frame_type == SLHP_P_SLICEFRAME_TYPE) { + /* Insert token to tell MTX to insert override for number of active references */ + insert_element_token(mtx_header, element_pointers, ELEMENT_NUM_REF_IDX_ACTIVE); + } else if (slh_params->slice_frame_type == SLHP_B_SLICEFRAME_TYPE) { + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + /* num_ref_idx_active_override_flag (1 bit) = 0 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + } + + if (slh_params->slice_frame_type != SLHP_I_SLICEFRAME_TYPE && + slh_params->slice_frame_type != SLHP_IDR_SLICEFRAME_TYPE) { + /* Insert token to tell MTX to insert reference list 0 reordering */ + insert_element_token(mtx_header, element_pointers, ELEMENT_REORDER_L0); + + if (slh_params->slice_frame_type == SLHP_B_SLICEFRAME_TYPE) + /* Insert token to tell MTX to insert reference list 1 reordering */ + insert_element_token(mtx_header, element_pointers, ELEMENT_REORDER_L1); + } + + /* WEIGHTED PREDICTION */ + insert_element_token(mtx_header, element_pointers, ELEMENT_SLICEWEIGHTEDPREDICTIONSTRUCT); + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + + if (slh_params->reference_picture && slh_params->is_longterm_ref) { + /* adaptive_ref_pic_marking_mode_flag (1 bit) = 0 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + + /* Clear any existing long-term reference */ + /* memory_management_control_operation */ + generate_ue(mtx_header, element_pointers, 5); + + /* Allow a single long-term reference */ + /* memory_management_control_operation */ + generate_ue(mtx_header, element_pointers, 4); + /* max_long_term_frame_idx_plus1 */ + generate_ue(mtx_header, element_pointers, 1); + + /* Set current picture as the long-term reference */ + /* memory_management_control_operation */ + generate_ue(mtx_header, element_pointers, 6); + /* long_term_frame_idx */ + generate_ue(mtx_header, element_pointers, 0); + + /* End */ + /* memory_management_control_operation */ + generate_ue(mtx_header, element_pointers, 0); + } else { + /*MTX fills this value in */ + insert_element_token(mtx_header, element_pointers, ELEMENT_ADAPTIVE); + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + } + + if (cabac_enabled && (slh_params->slice_frame_type == SLHP_P_SLICEFRAME_TYPE || + slh_params->slice_frame_type == SLHP_B_SLICEFRAME_TYPE)) + /* hard code cabac_init_idc value of 0 */ + generate_ue(mtx_header, element_pointers, 0); + + /*MTX fills this value in */ + insert_element_token(mtx_header, element_pointers, ELEMENT_SQP); + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + + /* GENERATES ELEMENT OF THE H264_SLICE_HEADER() STRUCTURE + * ELEMENT BITCOUNT: 11 + */ + /*disable_deblocking_filter_idc ue(v) = 2? */ + generate_ue(mtx_header, element_pointers, slh_params->disable_deblocking_filter_idc); + if (slh_params->disable_deblocking_filter_idc != 1) { + /*slice_alpha_c0_offset_div2 se(v) = 0 (1b) in Topaz */ + generate_se(mtx_header, element_pointers, slh_params->deb_alpha_offset_div2); + /*slice_beta_offset_div2 se(v) = 0 (1b) in Topaz */ + generate_se(mtx_header, element_pointers, slh_params->deb_beta_offset_div2); + } + + /* + * num_slice_groups_minus1 ==0 in Topaz, so no slice_group_change_cycle field here + * no byte alignment at end of slice headers + */ +} + +/* + * Prepare an H264 slice header in a form for the MTX to encode into a + * bitstream. + */ +void h264_prepare_slice_header(struct mtx_header_params *mtx_header, + unsigned char intra_slice, unsigned char inter_b_slice, + unsigned char disable_deblocking_filter_idc, + unsigned int first_mb_address, unsigned int mb_skip_run, + unsigned char cabac_enabled, unsigned char is_interlaced, + unsigned char is_idr, unsigned short mvc_view_idx, + unsigned char is_longterm_ref) +{ + struct h264_slice_header_params slh_params; + struct mtx_header_element *this_element; + struct mtx_header_element *element_pointers[MAXNUMBERELEMENTS]; + + slh_params.startcode_prefix_size_bytes = 4; + /* pcb - I think that this is more correct now -- This should also + * work for IDR-P frames which will be marked as SLHP_P_SLICEFRAME_TYPE + */ + slh_params.slice_frame_type = intra_slice ? (is_idr ? SLHP_IDR_SLICEFRAME_TYPE : + SLHP_I_SLICEFRAME_TYPE) : + (inter_b_slice ? SLHP_B_SLICEFRAME_TYPE : + SLHP_P_SLICEFRAME_TYPE); + + slh_params.first_mb_address = first_mb_address; + slh_params.disable_deblocking_filter_idc = (unsigned char)disable_deblocking_filter_idc; + slh_params.pic_interlace = is_interlaced; + slh_params.deb_alpha_offset_div2 = 0; + slh_params.deb_beta_offset_div2 = 0; + /* setup the new flags used for B frame as reference */ + slh_params.reference_picture = inter_b_slice ? 0 : 1; + slh_params.mvc_view_idx = mvc_view_idx; + slh_params.is_longterm_ref = is_longterm_ref; + slh_params.log2_max_pic_order_cnt = 2; + slh_params.longterm_ref_num = 0; + slh_params.ref_is_longterm_ref[0] = 0; + slh_params.ref_longterm_ref_num[0] = 0; + slh_params.ref_is_longterm_ref[1] = 0; + slh_params.ref_longterm_ref_num[1] = 0; + /* + * Builds a single slice header from the given parameters (mid frame) + * Essential we initialise our header structures before building + */ + mtx_header->elements = ELEMENTS_EMPTY; + this_element = (struct mtx_header_element *)mtx_header->element_stream; + element_pointers[0] = this_element; + + h264_write_bits_slice_header(mtx_header, element_pointers, &slh_params, cabac_enabled, + is_idr); + /*Has been used as an index, so need to add 1 for a valid element count */ + mtx_header->elements++; +} + +/* + * PrepareEncodeSliceParams + */ +unsigned int prepare_encode_slice_params(void *enc_ctx, struct slice_params *slice_params, + unsigned char is_intra, unsigned short current_row, + unsigned char deblock_idc, unsigned short slice_height, + unsigned char is_bpicture, unsigned char field_mode, + int fine_y_search_size) +{ + struct img_enc_context *enc; + struct img_video_context *video; + unsigned int frame_store_format; + unsigned char swap_chromas; + unsigned int mbs_per_kick, kicks_per_slice; + unsigned int ipe_control; + enum img_ipe_minblock_size blk_sz; + struct img_mtx_video_context *mtx_enc_context = NULL; + unsigned char restrict_4x4_search_size; + unsigned int lritc_boundary; + + if (!enc_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + enc = (struct img_enc_context *)enc_ctx; + video = enc->video; + + if (video->mtx_enc_ctx_mem.cpu_virt) + mtx_enc_context = (struct img_mtx_video_context *)(&video->mtx_enc_ctx_mem); + + /* We want multiple ones of these so we can submit multiple + * slices without having to wait for the next + */ + slice_params->flags = 0; + ipe_control = video->ipe_control; + + /* extract block size */ + blk_sz = (enum img_ipe_minblock_size)F_EXTRACT(ipe_control, TOPAZHP_CR_IPE_BLOCKSIZE); + + /* mask-out the block size bits from ipe_control */ + ipe_control &= ~(F_MASK(TOPAZHP_CR_IPE_BLOCKSIZE)); + + switch (video->standard) { + case IMG_STANDARD_H264: + if (blk_sz > 2) + blk_sz = (enum img_ipe_minblock_size)2; + if (is_bpicture && blk_sz > 1) + blk_sz = (enum img_ipe_minblock_size)1; + + if (video->mbps >= _1080P_30FPS) + ipe_control |= F_ENCODE(fine_y_search_size, TOPAZHP_CR_IPE_LRITC_BOUNDARY) | + F_ENCODE(fine_y_search_size, TOPAZHP_CR_IPE_Y_FINE_SEARCH); + else + ipe_control |= F_ENCODE(fine_y_search_size + 1, + TOPAZHP_CR_IPE_LRITC_BOUNDARY) | + F_ENCODE(fine_y_search_size, TOPAZHP_CR_IPE_Y_FINE_SEARCH); + + if (video->limit_num_vectors) + ipe_control |= F_ENCODE(1, TOPAZHP_CR_IPE_MV_NUMBER_RESTRICTION); + break; + default: + break; + } + + if (video->mbps >= _1080P_30FPS) + restrict_4x4_search_size = 1; + else + restrict_4x4_search_size = 0; + + ipe_control |= F_ENCODE(blk_sz, TOPAZHP_CR_IPE_BLOCKSIZE); + + lritc_boundary = + (blk_sz != + BLK_SZ_16x16) ? (fine_y_search_size + (restrict_4x4_search_size ? 0 : 1)) : 1; + if (lritc_boundary > 3) + IMG_DBG_ASSERT(0); + + /* Minimum sub block size to calculate motion vectors for. 0=16x16, 1=8x8, 2=4x4 */ + ipe_control = F_INSERT(ipe_control, blk_sz, TOPAZHP_CR_IPE_BLOCKSIZE); + ipe_control = F_INSERT(ipe_control, fine_y_search_size, TOPAZHP_CR_IPE_Y_FINE_SEARCH); + ipe_control = F_INSERT(ipe_control, video->limit_num_vectors, + TOPAZHP_CR_IPE_MV_NUMBER_RESTRICTION); + + /* 8x8 search */ + ipe_control = F_INSERT(ipe_control, lritc_boundary, TOPAZHP_CR_IPE_LRITC_BOUNDARY); + ipe_control = F_INSERT(ipe_control, restrict_4x4_search_size ? 0 : 1, + TOPAZHP_CR_IPE_4X4_SEARCH); + + ipe_control = F_INSERT(ipe_control, video->high_latency, TOPAZHP_CR_IPE_HIGH_LATENCY); + + slice_params->ipe_control = ipe_control; + + if (!is_intra) { + if (is_bpicture) + slice_params->flags |= ISINTERB_FLAGS; + else + slice_params->flags |= ISINTERP_FLAGS; + } + + if (video->multi_reference_p && !(is_intra || is_bpicture)) + slice_params->flags |= ISMULTIREF_FLAGS; + + if (video->spatial_direct && is_bpicture) + slice_params->flags |= SPATIALDIRECT_FLAGS; + + if (is_intra) { + slice_params->slice_config = F_ENCODE(TOPAZHP_CR_SLICE_TYPE_I_SLICE, + TOPAZHP_CR_SLICE_TYPE); + } else { + if (is_bpicture) + slice_params->slice_config = F_ENCODE(TOPAZHP_CR_SLICE_TYPE_B_SLICE, + TOPAZHP_CR_SLICE_TYPE); + else /* p frame */ + slice_params->slice_config = F_ENCODE(TOPAZHP_CR_SLICE_TYPE_P_SLICE, + TOPAZHP_CR_SLICE_TYPE); + } + + mbs_per_kick = video->kick_size; + + /* + * we need to figure out the number of kicks and mb's per kick to use. + * on H.264 we will use a MB's per kick of basic unit + * on other rc varients we will use mb's per kick of width + */ + kicks_per_slice = ((slice_height / 16) * (video->width / 16)) / mbs_per_kick; + + IMG_DBG_ASSERT((kicks_per_slice * mbs_per_kick) == + ((slice_height / 16) * (video->width / 16))); + + /* + * need some sensible ones don't look to be implemented yet... + * change per stream + */ + if (video->format == IMG_CODEC_UY0VY1_8888 || video->format == IMG_CODEC_VY0UY1_8888) + frame_store_format = 3; + else if ((video->format == IMG_CODEC_Y0UY1V_8888) || + (video->format == IMG_CODEC_Y0VY1U_8888)) + frame_store_format = 2; + else if (video->format == IMG_CODEC_420_PL12 || video->format == IMG_CODEC_422_PL12 || + video->format == IMG_CODEC_420_PL12_PACKED || + video->format == IMG_CODEC_420_PL21_PACKED || + video->format == IMG_CODEC_420_PL21 || video->format == IMG_CODEC_422_PL21) + frame_store_format = 1; + else + frame_store_format = 0; + + if (video->format == IMG_CODEC_VY0UY1_8888 || video->format == IMG_CODEC_Y0VY1U_8888 || + ((video->format == IMG_CODEC_420_PL21 || + video->format == IMG_CODEC_420_PL21_PACKED) && mtx_enc_context && + mtx_enc_context->scaler_setup.scaler_control == 0)) + swap_chromas = 1; + else + swap_chromas = 0; + + switch (video->standard) { + case IMG_STANDARD_H264: + /* H264 */ + slice_params->seq_config = F_ENCODE(0, TOPAZHP_CR_TEMPORAL_PIC0_BELOW_IN_VALID) | + F_ENCODE(0, TOPAZHP_CR_TEMPORAL_PIC1_BELOW_IN_VALID) | + F_ENCODE(0, TOPAZHP_CR_ABOVE_OUT_OF_SLICE_VALID) | + F_ENCODE(1, TOPAZHP_CR_WRITE_TEMPORAL_PIC0_BELOW_VALID) | + F_ENCODE(0, TOPAZHP_CR_REF_PIC0_VALID) | + F_ENCODE(0, TOPAZHP_CR_REF_PIC1_VALID) | + F_ENCODE(!is_bpicture, TOPAZHP_CR_REF_PIC1_EQUAL_PIC0) | + F_ENCODE(field_mode ? 1 : 0, TOPAZHP_CR_FIELD_MODE) | + F_ENCODE(swap_chromas, TOPAZHP_CR_FRAME_STORE_CHROMA_SWAP) | + F_ENCODE(frame_store_format, TOPAZHP_CR_FRAME_STORE_FORMAT) | + F_ENCODE(TOPAZHP_CR_ENCODER_STANDARD_H264, TOPAZHP_CR_ENCODER_STANDARD) | + F_ENCODE(deblock_idc == 1 ? 0 : 1, TOPAZHP_CR_DEBLOCK_ENABLE); + + if (video->rc_params.bframes) { + slice_params->seq_config |= + F_ENCODE(1, TOPAZHP_CR_WRITE_TEMPORAL_COL_VALID); + if ((slice_params->flags & ISINTERB_FLAGS) == ISINTERB_FLAGS) + slice_params->seq_config |= F_ENCODE(1, + TOPAZHP_CR_TEMPORAL_COL_IN_VALID); + } + if (!is_bpicture) + slice_params->seq_config |= + F_ENCODE(1, TOPAZHP_CR_WRITE_TEMPORAL_COL_VALID); + break; + + default: + break; + } + + if (is_bpicture) { + slice_params->seq_config |= F_ENCODE(0, TOPAZHP_CR_TEMPORAL_PIC1_BELOW_IN_VALID) | + F_ENCODE(0, TOPAZHP_CR_WRITE_TEMPORAL_PIC1_BELOW_VALID) | + F_ENCODE(1, TOPAZHP_CR_REF_PIC1_VALID) | + F_ENCODE(1, TOPAZHP_CR_TEMPORAL_COL_IN_VALID); + } + + if (video->enable_sel_stats_flags & ESF_FIRST_STAGE_STATS) + slice_params->seq_config |= F_ENCODE(1, TOPAZHP_CR_WRITE_MB_FIRST_STAGE_VALID); + + if (video->enable_sel_stats_flags & ESF_MP_BEST_MB_DECISION_STATS || + video->enable_sel_stats_flags & ESF_MP_BEST_MOTION_VECTOR_STATS) { + slice_params->seq_config |= F_ENCODE(1, TOPAZHP_CR_BEST_MULTIPASS_OUT_VALID); + + if (!(video->enable_sel_stats_flags & ESF_MP_BEST_MOTION_VECTOR_STATS)) + /* 64 Byte Best Multipass Motion Vector output disabled by default */ + slice_params->seq_config |= F_ENCODE(1, TOPAZHP_CR_BEST_MVS_OUT_DISABLE); + } + + if (video->enable_inp_ctrl) + slice_params->seq_config |= F_ENCODE(1, TOPAZHP_CR_MB_CONTROL_IN_VALID); + + return 0; +} + +/* + * Generates the slice params template + */ +void generate_slice_params_template(struct img_enc_context *enc, + struct vidio_ddbufinfo *mem_info, + enum img_frame_template_type slice_type, + unsigned char is_interlaced, int fine_y_search_size) +{ + unsigned char is_intra = ((slice_type == IMG_FRAME_IDR) || (slice_type == IMG_FRAME_INTRA)); + unsigned char is_bframe = (slice_type == IMG_FRAME_INTER_B); + unsigned char is_idr = ((slice_type == IMG_FRAME_IDR) || + (slice_type == IMG_FRAME_INTER_P_IDR)); + struct img_video_context *video = enc->video; + unsigned short mvc_view_idx = (unsigned short)(NON_MVC_VIEW); + /* Initialize Slice Params */ + struct slice_params *slice_params_dest; + unsigned int slice_height = video->picture_height / video->slices_per_picture; + + slice_height &= ~15; + + slice_params_dest = (struct slice_params *)(mem_info->cpu_virt); + + mvc_view_idx = video->mvc_view_idx; + + prepare_encode_slice_params(enc, slice_params_dest, is_intra, + 0, video->deblock_idc, slice_height, is_bframe, + is_interlaced, fine_y_search_size); + + slice_params_dest->template_type = slice_type; + + /* Prepare Slice Header Template */ + switch (video->standard) { + case IMG_STANDARD_H264: + h264_prepare_slice_header(&slice_params_dest->slice_hdr_tmpl, is_intra, + is_bframe, video->deblock_idc, 0, 0, video->cabac_enabled, + is_interlaced, is_idr, mvc_view_idx, FALSE); + break; + + default: + break; + } +} + +void h264_write_bits_mvc_sequence_header(struct mtx_header_params *mtx_header, + struct mtx_header_element **element_pointers, + struct h264_sequence_header_params *sh_params, + struct h264_crop_params *crop, + struct h264_scaling_matrix_params *scaling_matrix) +{ + int view_idx = 0; + int num_views = MAX_MVC_VIEWS; + + insert_element_token(mtx_header, element_pointers, ELEMENT_STARTCODE_RAWDATA); + h264_write_bits_startcode_prefix_element(mtx_header, element_pointers, 4); + + /* + * 4 Byte StartCodePrefix Pregenerated in: H264_WriteBits_StartCodePrefix_Element() + * Byte aligned (bit 32) + */ + /* forbidden_zero_bit=0 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, (0 << 7) | + (0x3 << 5) | /* nal_ref_idc=01 (may be 11) */ + (15), /* nal_unit_type=15 */ + 8); + + /* + * Byte aligned (bit 40) + * profile_idc = 8 bits = 66 for BP (PROFILE_IDC_BP), 77 for MP (PROFILE_IDC_MP) + */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 118, 8); + + /* Byte aligned (bit 48) */ + /* constrain_set0_flag = 1 for MP + BP constraints */ + write_upto_8bits_to_elements(mtx_header, element_pointers, (0 << 7) | + (0 << 6) | /* constrain_set1_flag = 1 for MP + BP constraints */ + (0 << 5) | /* constrain_set2_flag = always 0 in BP/MP */ + (0 << 4), /* constrain_set3_flag = 1 for level 1b, 0 for others */ + /* reserved_zero_4bits = 0 */ + 8); + + /* + * Byte aligned (bit 56) + * level_idc should be set to 9 in the sps in case of level is Level 1B and the profile + * is Multiview High or Stereo High profiles + */ + /* level_idc (8 bits) = 9 for 1b, 10xlevel for others */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + (sh_params->level == SH_LEVEL_1B) ? 9 : + (unsigned char)sh_params->level, 8); + + /* seq_parameter_Set_id = 1 FOR subset-SPS */ + generate_ue(mtx_header, element_pointers, MVC_SPS_ID); + generate_ue(mtx_header, element_pointers, 1); /* chroma_format_idc = 1 */ + generate_ue(mtx_header, element_pointers, 0); /* bit_depth_luma_minus8 = 0 */ + generate_ue(mtx_header, element_pointers, 0); /* bit_depth_chroma_minus8 = 0 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, sh_params->is_lossless ? 1 : 0, + 1); /* qpprime_y_zero_transform_bypass_flag = 0 */ + + if (sh_params->use_default_scaling_list || sh_params->seq_scaling_matrix_present_flag) { + /* seq_scaling_matrix_present_flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + if (!sh_params->use_default_scaling_list) { + h264_write_bits_scaling_lists(mtx_header, element_pointers, scaling_matrix, + TRUE); + insert_element_token(mtx_header, element_pointers, ELEMENT_RAWDATA); + } else { + /* seq_scaling_list_present_flag[i] = 0; 0 < i < 8 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 8); + } + } else { + /* seq_scaling_matrix_present_flag */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + } + + generate_ue(mtx_header, element_pointers, 1); /* log2_max_frame_num_minus4 = 1 */ + generate_ue(mtx_header, element_pointers, 0); /* pic_order_cnt_type = 0 */ + /* log2_max_pic_order_cnt_Isb_minus4 = 2 */ + generate_ue(mtx_header, element_pointers, 2); + + /*num_ref_frames ue(2), typically 2 */ + generate_ue(mtx_header, element_pointers, sh_params->max_num_ref_frames); + /* Bytes aligned (bit 72) */ + /* gaps_in_frame_num_value_allowed_Flag - (1 bit) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + sh_params->gaps_in_frame_num_value, 1); + + /* + * GENERATES THE SECOND, VARIABLE LENGTH, ELEMENT OF THE H264_SEQUENCE_HEADER() STRUCTURE + * ELEMENT BITCOUNT: xx + */ + /*pic_width_in_mbs_minus1: ue(v) from 10 to 44 (176 to 720 pixel per row) */ + generate_ue(mtx_header, element_pointers, sh_params->width_in_mbs_minus1); + /*pic_height_in_maps_units_minus1: ue(v) Value from 8 to 35 (144 to 576 pixels per column) + */ + generate_ue(mtx_header, element_pointers, sh_params->height_in_maps_units_minus1); + /* We don't know the alignment at this point, so will have to use bit writing functions */ + /* frame_mb_only_flag 1=frame encoding, 0=field encoding */ + write_upto_8bits_to_elements(mtx_header, element_pointers, sh_params->frame_mbs_only_flag, + 1); + + if (!sh_params->frame_mbs_only_flag) /* in the case of interlaced encoding */ + /* mb_adaptive_frame_field_flag = 0 in Topaz(field encoding at the sequence level) */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + + /* direct_8x8_inference_flag=1 in Topaz */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + + if (crop->clip) { + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); + generate_ue(mtx_header, element_pointers, crop->left_crop_offset); + generate_ue(mtx_header, element_pointers, crop->right_crop_offset); + generate_ue(mtx_header, element_pointers, crop->top_crop_offset); + generate_ue(mtx_header, element_pointers, crop->bottom_crop_offset); + + } else { + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 1); + } + + /* + * GENERATES THE THIRD ELEMENT OF THE H264_SEQUENCE_HEADER() STRUCTURE + * ELEMENT BITCOUNT: xx + * vui_parameters_present_flag (VUI only in 1st sequence of stream) + */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + (sh_params->vui_params_present), 1); + if (sh_params->vui_params_present > 0) + h264_write_bits_vui_params(mtx_header, element_pointers, &sh_params->vui_params); + + write_upto_8bits_to_elements(mtx_header, element_pointers, 1, 1); /*bit_equal_to_one */ + + /* sequence parameter set MVC extension */ + generate_ue(mtx_header, element_pointers, (num_views - 1)); /*num_views_minus1 */ + for (view_idx = 0; view_idx < num_views; view_idx++) + generate_ue(mtx_header, element_pointers, view_idx); + + /* anchor references */ + for (view_idx = 1; view_idx < num_views; view_idx++) { + /* num_anchor_refs_l0 = 1; view-1 refers to view-0 */ + generate_ue(mtx_header, element_pointers, 1); + generate_ue(mtx_header, element_pointers, 0); /* anchor_ref_l0 = 0 */ + generate_ue(mtx_header, element_pointers, 0); /* num_anchor_refs_l1 = 0 */ + } + + /* non-anchor references */ + for (view_idx = 1; view_idx < num_views; view_idx++) { + generate_ue(mtx_header, element_pointers, 1); /* num_non_anchor_refs_l0 = 0 */ + generate_ue(mtx_header, element_pointers, 0); /* non_anchor_refs_l0 = 0 */ + generate_ue(mtx_header, element_pointers, 0); /* num_non_anchor_refs_l1 = 0 */ + } + + generate_ue(mtx_header, element_pointers, 0);/* num_level_values_signaled_minus1 = 0 */ + + /* level_idc should be set to 9 in the sps in case of level is + * Level 1B and the profile is Multiview High or Stereo High profiles + */ + write_upto_8bits_to_elements(mtx_header, element_pointers, + (sh_params->level == SH_LEVEL_1B) ? 9 : + (unsigned char)sh_params->level, + 8);/* level_idc (8 bits) = 9 for 1b, 10xlevel for others */ + generate_ue(mtx_header, element_pointers, 0);/* num_applicable_ops_minus1 = 0 */ + /* applicable_ops_temporal_id = 0 */ + write_upto_8bits_to_elements(mtx_header, element_pointers, 0, 3); + /* applicable_op_num_target_views_minus1 = 0 */ + generate_ue(mtx_header, element_pointers, 0); + generate_ue(mtx_header, element_pointers, 0); /* applicable_op_target_view_id = 0 */ + generate_ue(mtx_header, element_pointers, 0); /* applicable_op_num_views_minus1 = 0 */ + + write_upto_8bits_to_elements(mtx_header, element_pointers, + 0, /* mvc_vui_parameters_present_flag =0 */ + 1); + + write_upto_8bits_to_elements(mtx_header, element_pointers, + 0, /* additional_extension2_flag =0 */ + 1); + + /* Finally we need to align to the next byte */ + /* Tell MTX to insert the byte align field + * (we don't know final stream size for alignment at this point) + */ + insert_element_token(mtx_header, element_pointers, ELEMENT_INSERTBYTEALIGN_H264); +} + +/* + * Prepare an H264 SPS in a form for the MTX to encode into a bitstream. + */ +void h264_prepare_mvc_sequence_header(struct mtx_header_params *mtx_header, + unsigned int pic_width_in_mbs, + unsigned int pic_height_in_mbs, + unsigned char vui_params_present, + struct h264_vui_params *params, + struct h264_crop_params *crop, + struct h264_sequence_header_params *sh_params) +{ + struct mtx_header_element *this_element; + struct mtx_header_element *element_pointers[MAXNUMBERELEMENTS]; + + /* + * Builds a sequence, picture and slice header with from the given inputs + * parameters (start of new frame) Essential we initialise our header + * structures before building + */ + mtx_header->elements = ELEMENTS_EMPTY; + this_element = (struct mtx_header_element *)mtx_header->element_stream; + element_pointers[0] = this_element; + + h264_write_bits_mvc_sequence_header(mtx_header, element_pointers, sh_params, crop, NULL); + /* Has been used as an index, so need to add 1 for a valid element count */ + mtx_header->elements++; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/header_gen.h b/drivers/media/platform/imagination/vxe-vxd/encoder/header_gen.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/header_gen.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/header_gen.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * encoder header generation interface header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#include "fw_headers/topazscfwif.h" +#include +#include "topaz_api.h" +#include "vid_buf.h" + +/* + * enum describing slice/frame type (H264) + */ +enum slhp_sliceframe_type { + SLHP_P_SLICEFRAME_TYPE, + SLHP_B_SLICEFRAME_TYPE, + SLHP_I_SLICEFRAME_TYPE, + SLHP_SP_SLICEFRAME_TYPE, + SLHP_SI_SLICEFRAME_TYPE, + SLHP_IDR_SLICEFRAME_TYPE, + SLHP_SLICE_FRAME_TYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * struct describing scaling lists (H264) + */ +struct h264_scaling_matrix_params { + unsigned char scaling_lists4x4[6][16]; + unsigned char scaling_lists8x8[2][64]; + unsigned int list_mask; +}; + +/* + * struct describing picture parameter set (H264) + */ +struct h264_picture_header_params { + unsigned char pic_parameter_set_id; + unsigned char seq_parameter_set_id; + unsigned char entropy_coding_mode_flag; + unsigned char weighted_pred_flag; + unsigned char weighted_bipred_idc; + signed char chroma_qp_index_offset; + unsigned char constrained_intra_pred_flag; + unsigned char transform_8x8_mode_flag; + unsigned char pic_scaling_matrix_present_flag; + unsigned char use_default_scaling_list; + signed char second_chroma_qp_index_offset; +}; + +/* + * struct describing slice header (H264) + */ +struct h264_slice_header_params { + unsigned char startcode_prefix_size_bytes; + enum slhp_sliceframe_type slice_frame_type; + unsigned int first_mb_address; + unsigned char log2_max_pic_order_cnt; + unsigned char disable_deblocking_filter_idc; + unsigned char pic_interlace; + unsigned char reference_picture; + signed char deb_alpha_offset_div2; + signed char deb_beta_offset_div2; + unsigned short mvc_view_idx; + unsigned char is_longterm_ref; + unsigned char longterm_ref_num; + /* Long term reference info for reference frames */ + unsigned char ref_is_longterm_ref[2]; + unsigned char ref_longterm_ref_num[2]; +}; + +void generate_slice_params_template(struct img_enc_context *enc, + struct vidio_ddbufinfo *mem_info, + enum img_frame_template_type slice_type, + unsigned char is_interlaced, int fine_y_search_size); + +void h264_prepare_sequence_header(struct mtx_header_params *mtx_header, + unsigned int pic_width_in_mbs, + unsigned int pic_height_in_mbs, unsigned char vui_params_present, + struct h264_vui_params *params, + struct h264_crop_params *crop, + struct h264_sequence_header_params *sh_params, + unsigned char aso); + +void h264_prepare_mvc_sequence_header(struct mtx_header_params *mtx_header, + unsigned int pic_width_in_mbs, unsigned int pic_height_in_mbs, + unsigned char vui_params_present, + struct h264_vui_params *params, + struct h264_crop_params *crop, + struct h264_sequence_header_params *sh_params); + +void h264_prepare_aud_header(struct mtx_header_params *mtx_header); + +void h264_prepare_picture_header(struct mtx_header_params *mtx_header, + unsigned char cabac_enabled, + unsigned char transform_8x8, + unsigned char intra_constrained, + signed char cqp_offset, + unsigned char weighted_prediction, + unsigned char weighted_bi_pred, + unsigned char mvc_pps, + unsigned char scaling_matrix, + unsigned char scaling_lists); diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/mtx_fwif.c b/drivers/media/platform/imagination/vxe-vxd/encoder/mtx_fwif.c --- a/drivers/media/platform/imagination/vxe-vxd/encoder/mtx_fwif.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/mtx_fwif.c 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,990 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MTX Firmware Interface + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#include +#include +#include + +#include "fw_headers/mtx_fwif.h" +#include "fw_headers/defs.h" +#include "fw_binaries/include_all_fw_variants.h" +#include "img_errors.h" +#include "reg_headers/mtx_regs.h" +/* still used for DMAC regs */ +#include "reg_headers/img_soc_dmac_regs.h" +#include "target_config.h" +#include "topaz_device.h" +#include "topazmmu.h" +#include "vxe_public_regdefs.h" + +extern struct mem_space topaz_mem_space[]; + +/* + * Static Function Decl + */ +static void mtx_get_mtx_ctrl_from_dash(struct img_fw_context *fw_ctx); + +static unsigned int mtx_read_core_reg(struct img_fw_context *fw_ctx, + const unsigned int reg); + +static void mtx_write_core_reg(struct img_fw_context *fw_ctx, + const unsigned int reg, + const unsigned int val); + +static int mtx_select_fw_build(struct img_fw_context *fw_ctx, enum img_codec codec); + +static void mtx_reg_if_upload(struct img_fw_context *fw_ctx, + const unsigned int data_mem, unsigned int addr, + const unsigned int words, const unsigned int *const data); + +/* + * Polling Configuration for TAL + */ +#define TAL_REG_RD_WR_TRIES 1000 /* => try 1000 times before giving up */ + +/* + * defines that should come from auto generated headers + */ +#define MTX_DMA_MEMORY_BASE (0x82880000) +#define PC_START_ADDRESS (0x80900000) + +#define MTX_CORE_CODE_MEM (0x10) +#define MTX_CORE_DATA_MEM (0x18) + +#define MTX_PC (0x05) + +/* + * Get control of the MTX. + * @Input fw_ctx : Pointer to the context of the target MTX + * @Return None + */ +static void mtx_get_mtx_ctrl_from_dash(struct img_fw_context *fw_ctx) +{ + unsigned int reg = 0; + + IMG_DBG_ASSERT(!fw_ctx->drv_has_mtx_ctrl); + + /* Request the bus from the Dash...*/ + reg = F_ENCODE(1, TOPAZHP_TOP_CR_MTX_MSTR_DBG_IS_SLAVE) | + F_ENCODE(0x2, TOPAZHP_TOP_CR_MTX_MSTR_DBG_GPIO_IN); + VXE_WR_REG32(fw_ctx->topaz_multicore_reg_addr, TOPAZHP_TOP_CR_MTX_DEBUG_MSTR, reg); + + do { + reg = VXE_RD_REG32(fw_ctx->topaz_multicore_reg_addr, TOPAZHP_TOP_CR_MTX_DEBUG_MSTR); + + } while ((reg & 0x18) != 0); + + /* Save the access control register...*/ + fw_ctx->drv_has_mtx_ctrl = VXE_RD_REG32(fw_ctx->mtx_reg_mem_space_addr, + MTX_CR_MTX_RAM_ACCESS_CONTROL); + + fw_ctx->drv_has_mtx_ctrl = TRUE; +} + +/* + * Release control of the MTX. + * @Input fw_ctx : Pointer to the context of the target MTX + * @Return None + */ +static void mtx_release_mtx_ctrl_from_dash(struct img_fw_context *fw_ctx) +{ + unsigned int reg = 0; + + IMG_DBG_ASSERT(fw_ctx->drv_has_mtx_ctrl); + + /* Restore the access control register...*/ + VXE_WR_REG32(fw_ctx->mtx_reg_mem_space_addr, MTX_CR_MTX_RAM_ACCESS_CONTROL, + fw_ctx->access_control); + + /* Release the bus...*/ + reg = F_ENCODE(1, TOPAZHP_TOP_CR_MTX_MSTR_DBG_IS_SLAVE); + VXE_WR_REG32(fw_ctx->topaz_multicore_reg_addr, TOPAZHP_TOP_CR_MTX_DEBUG_MSTR, reg); + + fw_ctx->drv_has_mtx_ctrl = FALSE; +} + +/* + * Read an MTX register. + * @Input fw_ctx : Pointer to the context of the target MTX + * @Input reg : Offset of register to read + * @Return unsigned int : Register value + */ +static unsigned int mtx_read_core_reg(struct img_fw_context *fw_ctx, const unsigned int reg) +{ + unsigned int ret = 0; + + mtx_get_mtx_ctrl_from_dash(fw_ctx); + + /* Issue read request */ + VXE_WR_REG32(fw_ctx->mtx_reg_mem_space_addr, MTX_CR_MTX_REGISTER_READ_WRITE_REQUEST, + MASK_MTX_MTX_RNW | (reg & ~MASK_MTX_MTX_DREADY)); + + /* Wait for done */ + VXE_POLL_REG32_ISEQ(fw_ctx->mtx_reg_mem_space_addr, + MTX_CR_MTX_REGISTER_READ_WRITE_REQUEST, + MASK_MTX_MTX_DREADY, + MASK_MTX_MTX_DREADY, + TAL_REG_RD_WR_TRIES); + + /* Read */ + ret = VXE_RD_REG32(fw_ctx->mtx_reg_mem_space_addr, MTX_CR_MTX_REGISTER_READ_WRITE_DATA); + + mtx_release_mtx_ctrl_from_dash(fw_ctx); + + return ret; +} + +/* + * Write an MTX register. + * @Input fw_ctx : Pointer to the context of the target MTX + * @Input reg : Offset of register to write + * @Input val : Value to write to register + */ +static void mtx_write_core_reg(struct img_fw_context *fw_ctx, + const unsigned int reg, const unsigned int val) +{ + mtx_get_mtx_ctrl_from_dash(fw_ctx); + + /* Put data in MTX_RW_DATA */ + VXE_WR_REG32(fw_ctx->mtx_reg_mem_space_addr, MTX_CR_MTX_REGISTER_READ_WRITE_DATA, val); + + /* DREADY is set to 0 and request a write*/ + VXE_WR_REG32(fw_ctx->mtx_reg_mem_space_addr, MTX_CR_MTX_REGISTER_READ_WRITE_REQUEST, + (reg & ~MASK_MTX_MTX_DREADY)); + + /* Wait for DREADY to become set*/ + VXE_POLL_REG32_ISEQ(fw_ctx->mtx_reg_mem_space_addr, + MTX_CR_MTX_REGISTER_READ_WRITE_REQUEST, + MASK_MTX_MTX_DREADY, + MASK_MTX_MTX_DREADY, + TAL_REG_RD_WR_TRIES); + + mtx_release_mtx_ctrl_from_dash(fw_ctx); +} + +/* ****** Utility macroses for `mtx_select_fw_build` ************** */ + +#if FW_BIN_FORMAT_VERSION != 2 +# error Unsupported firmware format version +#endif + +/* + * Assign a firmware binary to an MTX. + * @Input fw_ctx : Pointer to the context of the target MTX + * @Input codec : Firmware version to use + */ +static int mtx_select_fw_build(struct img_fw_context *fw_ctx, enum img_codec codec) +{ + unsigned char *fmt, *rc_mode; + unsigned int target_fw_pipes = 0; + unsigned int codec_mask = 0; + unsigned int cur_hw_config; + unsigned char force_specific_pipe_cnt = FALSE; + +# define HW_CONFIG_ALL_FEATURES 0 +# define HW_CONFIG_8CONTEXT 1 + +#define CORE_REV_CONFIG_1_MIN 0x00030906 +#define CORE_REV_CONFIG_1_MAX 0x0003090a + +# define CODEC_MASK_JPEG 0x0001 +# define CODEC_MASK_MPEG2 0x0002 +# define CODEC_MASK_MPEG4 0x0004 +# define CODEC_MASK_H263 0x0008 +# define CODEC_MASK_H264 0x0010 +# define CODEC_MASK_H264MVC 0x0020 +# define CODEC_MASK_VP8 0x0040 +# define CODEC_MASK_H265 0x0080 +# define CODEC_MASK_FAKE 0x007F + +#define _MVC_CODEC_CASE(RC) { case IMG_CODEC_H264MVC_ ## RC: fmt = "H264MVC"; rc_mode = #RC; \ + force_specific_pipe_cnt = TRUE; codec_mask = CODEC_MASK_H264MVC; break; } + + switch (codec) { + case IMG_CODEC_H264_NO_RC: + case IMG_CODEC_H264_VBR: + case IMG_CODEC_H264_CBR: + + case IMG_CODEC_H264_VCM: + fmt = "H264"; + rc_mode = "ALL"; + force_specific_pipe_cnt = TRUE; + codec_mask = CODEC_MASK_H264; + break; + case IMG_CODEC_H263_NO_RC: + case IMG_CODEC_H263_VBR: + case IMG_CODEC_H263_CBR: + fmt = "LEGACY_VIDEO"; + rc_mode = "ALL"; + codec_mask = CODEC_MASK_H263; + break; + case IMG_CODEC_MPEG2_NO_RC: + case IMG_CODEC_MPEG2_VBR: + case IMG_CODEC_MPEG2_CBR: + fmt = "LEGACY_VIDEO"; + rc_mode = "ALL"; + codec_mask = CODEC_MASK_MPEG2; + break; + case IMG_CODEC_MPEG4_NO_RC: + case IMG_CODEC_MPEG4_VBR: + case IMG_CODEC_MPEG4_CBR: + fmt = "LEGACY_VIDEO"; + rc_mode = "ALL"; + codec_mask = CODEC_MASK_MPEG4; + break; + _MVC_CODEC_CASE(NO_RC); + _MVC_CODEC_CASE(VBR); + _MVC_CODEC_CASE(CBR); + _MVC_CODEC_CASE(ERC); + case IMG_CODEC_JPEG: + fmt = "JPEG"; + rc_mode = "NO_RC"; + codec_mask = CODEC_MASK_JPEG; + break; + default: + pr_err("Failed to locate firmware for codec %d\n", codec); + return IMG_ERROR_UNDEFINED; + } +#undef _MVC_CODEC_CASE + + /* rc mode name fix */ + if (strcmp(rc_mode, "NO_RC") == 0) + rc_mode = "NONE"; + + { + /* + * Pick firmware type (done implicitly via determining number + * of pipes given firmware is expected to have + */ + const unsigned int core_id = fw_ctx->core_rev; +#define IS_REV(name) ((core_id >= MIN_ ## name ## _REV) && \ + (core_id <= MAX_ ## name ## _REV)) + + if (core_id >= CORE_REV_CONFIG_1_MIN && core_id <= CORE_REV_CONFIG_1_MAX) { + /* + * For now, it is assumed that this revision ID means 8 + * context 2 pipe variant + */ + cur_hw_config = HW_CONFIG_8CONTEXT; + target_fw_pipes = 2; + } else { + cur_hw_config = HW_CONFIG_ALL_FEATURES; + if (fw_ctx->hw_num_pipes < 3 && force_specific_pipe_cnt) + target_fw_pipes = 2; + else + target_fw_pipes = 4; + } +#undef IS_REV + } + + { + /* Search for matching firmwares */ + + unsigned int fmts_included = 0; + unsigned int ii; + unsigned char preferred_fw_located = FALSE; + unsigned int req_size = 0; + struct IMG_COMPILED_FW_BIN_RECORD *selected, *iter; + + selected = NULL; + + for (ii = 0; ii < all_fw_binaries_cnt; ii++) { + iter = all_fw_binaries[ii]; + /* + * With HW_3_6, we want to allow 3 pipes if it was + * required, this is mainly for test purposes + */ + if ((strcmp("JPEG_H264", iter->fmt) == 0) && target_fw_pipes != 3) { + preferred_fw_located = TRUE; + req_size = (4 * iter->data_size + (iter->data_origin - + MTX_DMA_MEMORY_BASE)); + break; + } + } + + if (preferred_fw_located && req_size <= fw_ctx->mtx_ram_size && + cur_hw_config == iter->hw_config && iter->pipes >= target_fw_pipes && + (codec_mask == CODEC_MASK_JPEG || codec_mask == CODEC_MASK_H264) && + ((iter->formats_mask & codec_mask) != 0)) { + selected = iter; + } else { + for (ii = 0; ii < all_fw_binaries_cnt; ii++) { + iter = all_fw_binaries[ii]; + /* The hardware config modes need to match */ + if (cur_hw_config != iter->hw_config) { + pr_err("cur_hw_config %x iter->hw_config %x mismatch\n", + cur_hw_config, iter->hw_config); + continue; + } + + fmts_included = iter->formats_mask; + + if (((fmts_included & codec_mask) != 0) && + (codec_mask == CODEC_MASK_JPEG || + /* no need to match RC for JPEG */ + strcmp(rc_mode, iter->rc_mode) == 0)) { + /* + * This firmware matches by format/mode + * combination, now to check if it fits + * better than current best + */ + if (!selected && iter->pipes >= target_fw_pipes) { + /* + * Select firmware ether if it + * is first matchin one we've + * encountered or if it better + * matches desired number of + * pipes. + */ + selected = iter; + } + + if (iter->pipes == target_fw_pipes) { + /* Found ideal firmware version */ + selected = iter; + break; + } + } + } + } + + if (!selected) { + pr_err("Failed to locate firmware for format '%s' and RC mode '%s'.\n", + fmt, rc_mode); + return IMG_ERROR_UNDEFINED; + } +#ifdef DEBUG_ENCODER_DRIVER + pr_info("Using firmware: %s with %i pipes, hwconfig=%i (text size = %i, data size = %i) for requested codec: %s RC mode %s\n", + selected->fmt, selected->pipes, + selected->hw_config, selected->text_size, + selected->data_size, fmt, rc_mode); +#endif + + /* Export selected firmware to the fw context */ + fw_ctx->mtx_topaz_fw_text_size = selected->text_size; + fw_ctx->mtx_topaz_fw_data_size = selected->data_size; + fw_ctx->mtx_topaz_fw_text = selected->text; + fw_ctx->mtx_topaz_fw_data = selected->data; + fw_ctx->mtx_topaz_fw_data_origin = selected->data_origin; + fw_ctx->num_pipes = selected->pipes; + fw_ctx->int_defines.length = selected->int_define_cnt; + fw_ctx->int_defines.names = selected->int_define_names; + fw_ctx->int_defines.values = selected->int_defines; + fw_ctx->supported_codecs = selected->formats_mask; + fw_ctx->num_contexts = mtx_get_fw_config_int(fw_ctx, "TOPAZHP_MAX_NUM_STREAMS"); + } + return IMG_SUCCESS; +} + +/* + * Upload MTX text and data sections via register interface + * @Input fw_ctx : Pointer to the context of the target MTX + * @Input data_mem : RAM ID for text/data section + * @Input address : Address to upload data to + * @Input words : Number of words of data to upload + * @Input data : Pointer to data to upload + */ +static void mtx_reg_if_upload(struct img_fw_context *fw_ctx, const unsigned int data_mem, + unsigned int address, const unsigned int words, + const unsigned int *const data) +{ + unsigned int loop; + unsigned int ctrl; + unsigned int ram_id; + unsigned int addr; + unsigned int curr_bank = ~0; + unsigned int uploaded = 0; + + mtx_get_mtx_ctrl_from_dash(fw_ctx); + + VXE_POLL_REG32_ISEQ(fw_ctx->mtx_reg_mem_space_addr, + MTX_CR_MTX_RAM_ACCESS_STATUS, + MASK_MTX_MTX_MTX_MCM_STAT, + MASK_MTX_MTX_MTX_MCM_STAT, + TAL_REG_RD_WR_TRIES); + + for (loop = 0; loop < words; loop++) { + ram_id = data_mem + (address / fw_ctx->mtx_bank_size); + if (ram_id != curr_bank) { + addr = address >> 2; + ctrl = 0; + ctrl = F_ENCODE(ram_id, MTX_MTX_MCMID) | + F_ENCODE(addr, MTX_MTX_MCM_ADDR) | + F_ENCODE(1, MTX_MTX_MCMAI); + VXE_WR_REG32(fw_ctx->mtx_reg_mem_space_addr, + MTX_CR_MTX_RAM_ACCESS_CONTROL, ctrl); + curr_bank = ram_id; + } + address += 4; + + if (uploaded > (1024 * 24)) /* should this be RAM bank size?? */ + break; + uploaded += 4; + + VXE_WR_REG32(fw_ctx->mtx_reg_mem_space_addr, + MTX_CR_MTX_RAM_ACCESS_DATA_TRANSFER, + data[loop]); + + VXE_POLL_REG32_ISEQ(fw_ctx->mtx_reg_mem_space_addr, + MTX_CR_MTX_RAM_ACCESS_STATUS, + MASK_MTX_MTX_MTX_MCM_STAT, + MASK_MTX_MTX_MTX_MCM_STAT, + TAL_REG_RD_WR_TRIES); + } + + mtx_release_mtx_ctrl_from_dash(fw_ctx); +} + +/* + * Transfer memory between the Host and MTX via DMA. + * @Input fw_ctx : Pointer to the context of the target MTX + * @Input channel : DMAC channel to use (0 for TopazSC) + * @Input hHostMemTransfer : void * for the host memory + * @Input hostMemOffset : offset into the host memory + * @Input mtx_addr : Address on MTX + * @Input numWords : size of transfer in 32-bit words (PW units) + * @Input bRNW : Read not Write (FALSE to write to the MTX) + */ +void mtx_dmac_transfer(struct img_fw_context *fw_ctx, unsigned int channel, + struct vidio_ddbufinfo *host_mem_transfer, + unsigned int host_mem_offset, unsigned int mtx_addr, + unsigned int words, unsigned char rnw) +{ + unsigned int irq_stat; + unsigned int count_reg; + void *dmac_reg_addr; + void *reg_addr; + unsigned int config_reg; + unsigned int mmu_status = 0; + + unsigned int dmac_burst_size = DMAC_BURST_2; /* 2 * 128 bits = 32 bytes */ + unsigned int mtx_burst_size = 4; /* 4 * 2 * 32 bits = 32 bytes */ + + /* check the burst sizes */ + IMG_DBG_ASSERT(dmac_burst_size * 16 == MTX_DMA_BURSTSIZE_BYTES); + IMG_DBG_ASSERT(mtx_burst_size * 8 == MTX_DMA_BURSTSIZE_BYTES); + + /* check transfer size matches burst width */ + IMG_DBG_ASSERT(0 == (words & ((MTX_DMA_BURSTSIZE_BYTES >> 2) - 1))); + + /* check DMA channel */ + IMG_DBG_ASSERT(channel < DMAC_MAX_CHANNELS); + + /* check that no transfer is currently in progress */ + dmac_reg_addr = (void *)topaz_mem_space[REG_DMAC].cpu_addr; + count_reg = VXE_RD_REG32(dmac_reg_addr, IMG_SOC_DMAC_COUNT(channel)); + IMG_DBG_ASSERT(0 == (count_reg & + (MASK_IMG_SOC_EN | MASK_IMG_SOC_LIST_EN))); + + /* check we don't already have a page fault condition */ + reg_addr = (void *)topaz_mem_space[REG_TOPAZHP_MULTICORE].cpu_addr; + mmu_status = VXE_RD_REG32(reg_addr, TOPAZHP_TOP_CR_MMU_STATUS); + + IMG_DBG_ASSERT(mmu_status == 0); + + if (mmu_status || (count_reg & (MASK_IMG_SOC_EN | + MASK_IMG_SOC_LIST_EN))) { + /* DMA engine not idle or pre-existing page fault condition */ + pr_err("DMA engine not idle or pre-existing page fault condition!\n"); + fw_ctx->initialized = FALSE; + return; + } + + /* clear status of any previous interrupts */ + VXE_WR_REG32(dmac_reg_addr, IMG_SOC_DMAC_IRQ_STAT(channel), 0); + + /* and that no interrupts are outstanding */ + irq_stat = VXE_RD_REG32(dmac_reg_addr, IMG_SOC_DMAC_IRQ_STAT(channel)); + IMG_DBG_ASSERT(irq_stat == 0); + + /* Write MTX DMAC registers (for current MTX) */ + /* MTX Address */ + VXE_WR_REG32(fw_ctx->mtx_reg_mem_space_addr, MTX_CR_MTX_SYSC_CDMAA, + mtx_addr); + + /* MTX DMAC Config */ + config_reg = F_ENCODE(mtx_burst_size, MTX_BURSTSIZE) | + F_ENCODE((rnw ? 1 : 0), MTX_RNW) | + F_ENCODE(1, MTX_ENABLE) | + F_ENCODE(words, MTX_LENGTH); + VXE_WR_REG32(fw_ctx->mtx_reg_mem_space_addr, MTX_CR_MTX_SYSC_CDMAC, + config_reg); + + /* Write System DMAC registers */ + /* per hold - allow HW to sort itself out */ + VXE_WR_REG32(dmac_reg_addr, IMG_SOC_DMAC_PER_HOLD(channel), 16); + + VXE_WR_REG32(dmac_reg_addr, IMG_SOC_DMAC_SETUP(channel), + host_mem_transfer->dev_virt + host_mem_offset); + + /* count reg */ + count_reg = DMAC_VALUE_COUNT(DMAC_BSWAP_NO_SWAP, DMAC_PWIDTH_32_BIT, + rnw, DMAC_PWIDTH_32_BIT, words); + count_reg |= MASK_IMG_SOC_TRANSFER_IEN; /* generate an interrupt at end of transfer */ + VXE_WR_REG32(dmac_reg_addr, IMG_SOC_DMAC_COUNT(channel), count_reg); + + /* don't inc address, set burst size */ + VXE_WR_REG32(dmac_reg_addr, IMG_SOC_DMAC_PERIPH(channel), + DMAC_VALUE_PERIPH_PARAM(DMAC_ACC_DEL_0, FALSE, dmac_burst_size)); + + /* Target correct MTX DMAC port */ + VXE_WR_REG32(dmac_reg_addr, IMG_SOC_DMAC_PERIPHERAL_ADDR(channel), + MTX_CR_MTX_SYSC_CDMAT + REG_START_TOPAZ_MTX_HOST); + + /* + * Finally, rewrite the count register with the enable bit set to kick + * off the transfer + */ + VXE_WR_REG32(dmac_reg_addr, IMG_SOC_DMAC_COUNT(channel), + (count_reg | MASK_IMG_SOC_EN)); + + /* Wait for it to finish */ + VXE_POLL_REG32_ISEQ(dmac_reg_addr, IMG_SOC_DMAC_IRQ_STAT(channel), + F_ENCODE(1, IMG_SOC_TRANSFER_FIN), + F_ENCODE(1, IMG_SOC_TRANSFER_FIN), + TAL_REG_RD_WR_TRIES); + count_reg = VXE_RD_REG32(dmac_reg_addr, IMG_SOC_DMAC_COUNT(channel)); + mmu_status = VXE_RD_REG32(reg_addr, TOPAZHP_TOP_CR_MMU_STATUS); + if (mmu_status || (count_reg & + (MASK_IMG_SOC_EN | MASK_IMG_SOC_LIST_EN))) { + pr_err("DMA has failed or page faulted\n"); + /* DMA has failed or page faulted */ + fw_ctx->initialized = FALSE; + } + + /* Clear the interrupt */ + VXE_WR_REG32(dmac_reg_addr, IMG_SOC_DMAC_IRQ_STAT(channel), 0); +} + +/* + * Sets target MTX for DMA and register writes + * @Input fw_ctx : Pointer to the context of the target MTX + * @Input bTargetAll : TRUE indicates register and DMA writes go to all MTX + */ +void mtx_set_target(struct img_fw_context *fw_ctx) +{ + unsigned int reg = 0; + + reg = F_ENCODE(0, TOPAZHP_TOP_CR_WRITES_CORE_ALL); + VXE_WR_REG32(fw_ctx->topaz_multicore_reg_addr, + TOPAZHP_TOP_CR_MULTICORE_CORE_SEL_0, reg); +} + +/* + * Upload text and data sections via DMA + * @Input fw_ctx : Pointer to the context of the target MTX + */ +static void mtx_uploadfw(void *dev_ctx, struct img_fw_context *fw_ctx) +{ + struct topaz_dev_ctx *ctx = (struct topaz_dev_ctx *)dev_ctx; + struct vidio_ddbufinfo text, data; + void *add_lin_text, *add_lin_data; + unsigned int text_size = fw_ctx->mtx_topaz_fw_text_size; + unsigned int data_size = fw_ctx->mtx_topaz_fw_data_size; + + if (topaz_mmu_alloc(ctx->topaz_mmu_ctx.mmu_context_handle, + ctx->vxe_arg, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + text_size * 4 + MTX_DMA_BURSTSIZE_BYTES, 64, &text)) { + pr_err("mmu_alloc for text failed!\n"); + fw_ctx->initialized = FALSE; + return; + } + if (topaz_mmu_alloc(ctx->topaz_mmu_ctx.mmu_context_handle, + ctx->vxe_arg, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + data_size * 4 + MTX_DMA_BURSTSIZE_BYTES, 64, &data)) { + pr_err("mmu_alloc for data failed!\n"); + topaz_mmu_free(ctx->vxe_arg, &text); + fw_ctx->initialized = FALSE; + } + + add_lin_text = text.cpu_virt; + memcpy((void *)add_lin_text, fw_ctx->mtx_topaz_fw_text, text_size * 4); + add_lin_data = data.cpu_virt; + memcpy((void *)add_lin_data, fw_ctx->mtx_topaz_fw_data, data_size * 4); + + topaz_update_device_mem(ctx->vxe_arg, &text); + topaz_update_device_mem(ctx->vxe_arg, &data); + + /* adjust transfer sizes of text and data sections to match burst size */ + text_size = + ((text_size * 4 + (MTX_DMA_BURSTSIZE_BYTES - 1)) & ~(MTX_DMA_BURSTSIZE_BYTES - 1)) / + 4; + data_size = + ((data_size * 4 + (MTX_DMA_BURSTSIZE_BYTES - 1)) & ~(MTX_DMA_BURSTSIZE_BYTES - 1)) / + 4; + + /* ensure that data section (+stack) will not wrap in memory */ + IMG_DBG_ASSERT(fw_ctx->mtx_ram_size >= + (fw_ctx->mtx_topaz_fw_data_origin + (data_size * 4) - MTX_DMA_MEMORY_BASE)); + if (fw_ctx->mtx_ram_size < + (fw_ctx->mtx_topaz_fw_data_origin + (data_size * 4) - MTX_DMA_MEMORY_BASE)) + fw_ctx->initialized = FALSE; + + /* data section is already prepared/cached */ + /* Transfer the text section */ + if (fw_ctx->initialized) { + mtx_dmac_transfer(fw_ctx, 0, &text, 0, MTX_DMA_MEMORY_BASE, + text_size, FALSE); + } + /* Transfer the data section */ + if (fw_ctx->initialized) { + mtx_dmac_transfer(fw_ctx, 0, &data, 0, + fw_ctx->mtx_topaz_fw_data_origin, data_size, + FALSE); + } + + topaz_mmu_free(ctx->vxe_arg, &text); + topaz_mmu_free(ctx->vxe_arg, &data); + + /* Flush the MMU table cache used during code download */ + topaz_core_mmu_flush_cache(); +#ifdef DEBUG_ENCODER_DRIVER + if (fw_ctx->initialized) + pr_info("%s complete!\n", __func__); +#endif +} + +/* + * Load text and data sections onto an MTX. + * @Input fw_ctx : Pointer to the context of the target MTX + * @Input load_method : Method to use for loading code + * @Input bTargetAll : Load to one (FALSE) or all (TRUE) MTX + */ +void mtx_load(void *dev_ctx, struct img_fw_context *fw_ctx, + enum mtx_load_method load_method) +{ + struct topaz_dev_ctx *ctx = (struct topaz_dev_ctx *)dev_ctx; + unsigned int reg; + unsigned short i; + + IMG_DBG_ASSERT(fw_ctx->initialized); + if (!fw_ctx->initialized) + return; + + fw_ctx->load_method = load_method; + + /* set target to current or all MTXs */ + mtx_set_target(fw_ctx); + + /* MTX Reset */ + VXE_WR_REG32(fw_ctx->mtx_reg_mem_space_addr, MTX_CR_MTX_SOFT_RESET, + MASK_MTX_MTX_RESET); + ndelay(300); + + switch (load_method) { + case MTX_LOADMETHOD_REGIF: + /* Code Upload */ + mtx_reg_if_upload(fw_ctx, MTX_CORE_CODE_MEM, 0, + fw_ctx->mtx_topaz_fw_text_size, + fw_ctx->mtx_topaz_fw_text); + + /* Data Upload */ + mtx_reg_if_upload(fw_ctx, MTX_CORE_DATA_MEM, + fw_ctx->mtx_topaz_fw_data_origin - MTX_DMA_MEMORY_BASE, + fw_ctx->mtx_topaz_fw_data_size, + fw_ctx->mtx_topaz_fw_data); + break; + + case MTX_LOADMETHOD_DMA: + mtx_uploadfw(ctx, fw_ctx); + break; + + case MTX_LOADMETHOD_NONE: + break; + + default: + IMG_DBG_ASSERT(FALSE); + } + + /* if we have had any failures up to this point then return now */ + if (!fw_ctx->initialized) + return; + + if (load_method != MTX_LOADMETHOD_NONE) { + for (i = 5; i < 8; i++) + mtx_write_core_reg(fw_ctx, 0x1 | (i << 4), 0); + + /* Restore 8 Registers of D1 Bank */ + /* D1Re0, D1Ar5, D1Ar3, D1Ar1, D1RtP, D1.5, D1.6 and D1.7 */ + for (i = 5; i < 8; i++) + mtx_write_core_reg(fw_ctx, 0x2 | (i << 4), 0); + + /* Set Starting PC address */ + mtx_write_core_reg(fw_ctx, MTX_PC, PC_START_ADDRESS); + + /* Verify Starting PC */ + reg = mtx_read_core_reg(fw_ctx, MTX_PC); + +#ifdef DEBUG_ENCODER_DRIVER + pr_info("PC_START_ADDRESS = 0x%08X\n", reg); +#endif + IMG_DBG_ASSERT(reg == PC_START_ADDRESS); + } +} + +/* + * Deinitialise the given MTX context structure + * @Input fw_ctx : Pointer to the context of the target MTX + */ +void mtx_deinitialize(struct img_fw_context *fw_ctx) +{ + struct topaz_dev_ctx *ctx = (struct topaz_dev_ctx *)fw_ctx->dev_ctx; + unsigned int i; + + if (!fw_ctx->initialized) + pr_warn("Warning detected multi de-initialiseations\n"); + + for (i = 0; i < TOPAZHP_MAX_POSSIBLE_STREAMS; i++) { + if (fw_ctx->mtx_context_data_copy[i]) + topaz_mmu_free(ctx->vxe_arg, fw_ctx->mtx_context_data_copy[i]); + fw_ctx->mtx_context_data_copy[i] = NULL; + } + + kfree(fw_ctx->mtx_reg_copy); + fw_ctx->mtx_reg_copy = NULL; + fw_ctx->initialized = FALSE; +} + +/* + * Initialise the given MTX context structure + * @Input fw_ctx : Pointer to the context of the target MTX + * @Input core_num : Core number of the MTX to target + * @Input codec : version of codec specific firmware to associate with this MTX + */ +int mtx_populate_fw_ctx(enum img_codec codec, struct img_fw_context *fw_ctx) +{ + unsigned int pipe_cnt; + unsigned int size; + unsigned int i; + + if (fw_ctx->initialized || fw_ctx->populated) + return IMG_ERROR_INVALID_CONTEXT; + + /* initialise Context structure */ + fw_ctx->mtx_reg_mem_space_addr = (void *)topaz_mem_space[REG_MTX].cpu_addr; + fw_ctx->topaz_multicore_reg_addr = (void *)topaz_mem_space[REG_TOPAZHP_MULTICORE].cpu_addr; + + fw_ctx->core_rev = VXE_RD_REG32(fw_ctx->topaz_multicore_reg_addr, + TOPAZHP_TOP_CR_TOPAZHP_CORE_REV); + fw_ctx->core_rev &= (MASK_TOPAZHP_TOP_CR_TOPAZHP_MAINT_REV | + MASK_TOPAZHP_TOP_CR_TOPAZHP_MINOR_REV | + MASK_TOPAZHP_TOP_CR_TOPAZHP_MAJOR_REV); + fw_ctx->core_des1 = VXE_RD_REG32(fw_ctx->topaz_multicore_reg_addr, + TOPAZHP_TOP_CR_TOPAZHP_CORE_DES1); + + /* Number of hw pipes */ + pipe_cnt = VXE_RD_REG32(fw_ctx->topaz_multicore_reg_addr, TOPAZHP_TOP_CR_MULTICORE_HW_CFG); + pipe_cnt = (pipe_cnt & MASK_TOPAZHP_TOP_CR_NUM_CORES_SUPPORTED); + fw_ctx->hw_num_pipes = pipe_cnt; + + IMG_DBG_ASSERT(fw_ctx->hw_num_pipes > 0 && fw_ctx->hw_num_pipes <= TOPAZHP_MAX_NUM_PIPES); + + if (fw_ctx->hw_num_pipes <= 0 || fw_ctx->hw_num_pipes > TOPAZHP_MAX_NUM_PIPES) + return IMG_ERROR_INVALID_ID; + + for (i = 0; i < fw_ctx->hw_num_pipes; i++) + fw_ctx->topaz_reg_mem_space_addr[i] = + (void *)topaz_mem_space[REG_TOPAZHP_CORE_0 + (4 * i)].cpu_addr; + + fw_ctx->mtx_debug_val = VXE_RD_REG32(fw_ctx->topaz_multicore_reg_addr, + TOPAZHP_TOP_CR_MTX_DEBUG_MSTR); + + /* last bank size */ + size = 0x1 << + (F_EXTRACT(fw_ctx->mtx_debug_val, TOPAZHP_TOP_CR_MTX_MSTR_LAST_RAM_BANK_SIZE) + 2); + /* all other banks */ + fw_ctx->mtx_bank_size = 0x1 << + (F_EXTRACT(fw_ctx->mtx_debug_val, TOPAZHP_TOP_CR_MTX_MSTR_RAM_BANK_SIZE) + 2); + /* total RAM size */ + fw_ctx->mtx_ram_size = size + + (fw_ctx->mtx_bank_size * + (F_EXTRACT(fw_ctx->mtx_debug_val, TOPAZHP_TOP_CR_MTX_MSTR_RAM_BANKS) - 1)); + + fw_ctx->drv_has_mtx_ctrl = FALSE; + fw_ctx->access_control = 0; + + fw_ctx->active_ctx_mask = 0; + + if (mtx_select_fw_build(fw_ctx, codec) != IMG_SUCCESS) { + fw_ctx->populated = FALSE; + fw_ctx->initialized = FALSE; + return IMG_ERROR_UNDEFINED; + } + + if (fw_ctx->mtx_topaz_fw_data_size != 0) { + /* check FW fits in memory */ + /* could also add stack size estimate */ + size = 4 * fw_ctx->mtx_topaz_fw_data_size; + size += (fw_ctx->mtx_topaz_fw_data_origin - MTX_DMA_MEMORY_BASE); + if (size > fw_ctx->mtx_ram_size) { + IMG_DBG_ASSERT(fw_ctx->mtx_ram_size > size); + return IMG_ERROR_OUT_OF_MEMORY; + } + } + + fw_ctx->populated = TRUE; + return IMG_SUCCESS; +} + +void mtx_initialize(void *dev_ctx, struct img_fw_context *fw_ctx) +{ + struct topaz_dev_ctx *ctx = (struct topaz_dev_ctx *)dev_ctx; + unsigned int i = 0; + + if (fw_ctx->initialized) + return; + + if (fw_ctx->mtx_topaz_fw_data_size != 0) { + fw_ctx->mtx_reg_copy = kmalloc((53 * 4), GFP_KERNEL); + for (i = 0; i < TOPAZHP_MAX_POSSIBLE_STREAMS; i++) { + fw_ctx->mtx_context_data_copy[i] = kmalloc + (sizeof(*fw_ctx->mtx_context_data_copy[i]), + GFP_KERNEL); + if (!fw_ctx->mtx_context_data_copy[i]) + goto alloc_failed; + + if (topaz_mmu_alloc(ctx->topaz_mmu_ctx.mmu_context_handle, + ctx->vxe_arg, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + MTX_CONTEXT_SIZE, 64, + fw_ctx->mtx_context_data_copy[i])) { + pr_err("mmu_alloc for data copy failed!\n"); + kfree(fw_ctx->mtx_context_data_copy[i]); + fw_ctx->mtx_context_data_copy[i] = NULL; + goto alloc_failed; + } + } + + fw_ctx->dev_ctx = dev_ctx; + fw_ctx->initialized = TRUE; + } + + return; + +alloc_failed: + while (i > 0) { + topaz_mmu_free(ctx->vxe_arg, fw_ctx->mtx_context_data_copy[i - 1]); + kfree(fw_ctx->mtx_context_data_copy[i - 1]); + fw_ctx->mtx_context_data_copy[i - 1] = NULL; + i--; + } +} + +int mtx_get_fw_config_int(struct img_fw_context const * const fw_ctx, + unsigned char const * const name) +{ + const unsigned long max_len = 1024; + unsigned int ii; + + if (fw_ctx->mtx_topaz_fw_data_size == 0) { + IMG_DBG_ASSERT("FW context structure is not initialised!" == NULL); + return -1; + } + + for (ii = 0; ii < fw_ctx->int_defines.length; ii++) { + if (strncmp(fw_ctx->int_defines.names[ii], name, max_len) == 0) + return fw_ctx->int_defines.values[ii]; + } + + return -1; +} + +/* + * Start an MTX. + * @Input fw_ctx : Pointer to the context of the target MTX + */ +void mtx_start(struct img_fw_context *fw_ctx) +{ + IMG_DBG_ASSERT(fw_ctx->initialized); + if (!fw_ctx->initialized) + return; + + /* target only the current MTX */ + mtx_set_target(fw_ctx); + + /* Turn on the thread */ + VXE_WR_REG32(fw_ctx->mtx_reg_mem_space_addr, MTX_CR_MTX_ENABLE, + MASK_MTX_MTX_ENABLE); +} + +/* + * Stop an MTX. + * @Input fw_ctx : Pointer to the context of the target MTX + */ +void mtx_stop(struct img_fw_context *fw_ctx) +{ + IMG_DBG_ASSERT(fw_ctx->initialized); + + /* target only the current MTX */ + mtx_set_target(fw_ctx); + + /* + * Turn off the thread by writing one to the MTX_TOFF field of the MTX_ENABLE + * register. + */ + VXE_WR_REG32(fw_ctx->mtx_reg_mem_space_addr, MTX_CR_MTX_ENABLE, + MASK_MTX_MTX_TOFF); +} + +/* + * Kick an MTX. + * @Input fw_ctx : Pointer to the context of the target MTX + * @Input kick_count : The number of kicks to register + */ +void mtx_kick(struct img_fw_context *fw_ctx, unsigned int kick_count) +{ + IMG_DBG_ASSERT(fw_ctx->initialized); + if (!fw_ctx->initialized) + return; + + /* target only the current MTX */ + mtx_set_target(fw_ctx); + + VXE_WR_REG32(fw_ctx->mtx_reg_mem_space_addr, MTX_CR_MTX_KICK, + kick_count); +} + +/* + * Wait for MTX to halt + * @Input fw_ctx : Pointer to the MTX context + */ +void mtx_wait_for_completion(struct img_fw_context *fw_ctx) +{ + IMG_DBG_ASSERT(fw_ctx->initialized); + + if (fw_ctx->load_method != MTX_LOADMETHOD_NONE) { + /* target only the current MTX */ + mtx_set_target(fw_ctx); + + /* Wait for the Completion */ + VXE_POLL_REG32_ISEQ(fw_ctx->mtx_reg_mem_space_addr, + MTX_CR_MTX_ENABLE, MASK_MTX_MTX_TOFF, + (MASK_MTX_MTX_TOFF | MASK_MTX_MTX_ENABLE), + TAL_REG_RD_WR_TRIES); + } +} + +unsigned int poll_hw_inactive(struct img_fw_context *fw_ctx) +{ + return VXE_POLL_REG32_ISEQ(fw_ctx->topaz_multicore_reg_addr, + MTX_SCRATCHREG_IDLE, + F_ENCODE(FW_IDLE_STATUS_IDLE, FW_IDLE_REG_STATUS), + MASK_FW_IDLE_REG_STATUS, + TAL_REG_RD_WR_TRIES); +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/img_soc_dmac_regs.h b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/img_soc_dmac_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/img_soc_dmac_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/img_soc_dmac_regs.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _REGCONV_H_img_soc_dmac_regs_h +#define _REGCONV_H_img_soc_dmac_regs_h + +/* Register DMAC_COUNT */ +#define IMG_SOC_DMAC_COUNT(X) (0x0004 + (32 * (X))) +#define MASK_IMG_SOC_BSWAP 0x40000000 +#define SHIFT_IMG_SOC_BSWAP 30 +#define SHIFT_IMG_SOC_PW 27 +#define MASK_IMG_SOC_PW 0x18000000 +#define MASK_IMG_SOC_DIR 0x04000000 +#define SHIFT_IMG_SOC_DIR 26 + +/* Register DMAC_COUNT */ +#define MASK_IMG_SOC_EN 0x00010000 +#define MASK_IMG_SOC_LIST_EN 0x00040000 + +/* Register DMAC_COUNT */ +#define MASK_IMG_SOC_PI 0x03000000 +#define SHIFT_IMG_SOC_PI 24 +#define MASK_IMG_SOC_CNT 0x0000FFFF +#define SHIFT_IMG_SOC_CNT 0 +#define MASK_IMG_SOC_TRANSFER_IEN 0x20000000 + +/* Register DMAC_IRQ_STAT */ +#define IMG_SOC_DMAC_IRQ_STAT(X) (0x000C + (32 * (X))) +#define MASK_IMG_SOC_TRANSFER_FIN 0x00020000 +#define SHIFT_IMG_SOC_TRANSFER_FIN 17 + +/* Register DMAC_PER_HOLD */ +#define IMG_SOC_DMAC_PER_HOLD(X) (0x0018 + (32 * (X))) + +/* Register DMAC_SETUP */ +#define IMG_SOC_DMAC_SETUP(X) (0x0000 + (32 * (X))) + +/* Register DMAC_PERIPH */ +#define IMG_SOC_DMAC_PERIPH(X) (0x0008 + (32 * (X))) +#define MASK_IMG_SOC_ACC_DEL 0xE0000000 +#define SHIFT_IMG_SOC_ACC_DEL 29 +#define MASK_IMG_SOC_INCR 0x08000000 +#define SHIFT_IMG_SOC_INCR 27 +#define MASK_IMG_SOC_BURST 0x07000000 +#define SHIFT_IMG_SOC_BURST 24 + +/* Register DMAC_PERIPHERAL_ADDR */ +#define IMG_SOC_DMAC_PERIPHERAL_ADDR(X) (0x0014 + (32 * (X))) + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/mtx_regs.h b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/mtx_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/mtx_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/mtx_regs.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _REGCONV_H_mtx_regs_h +#define _REGCONV_H_mtx_regs_h + +/* Register CR_MTX_ENABLE */ +#define MTX_CR_MTX_ENABLE 0x0000 +#define MASK_MTX_MTX_ENABLE 0x00000001 +#define MASK_MTX_MTX_TOFF 0x00000002 + +/* Register CR_MTX_KICK */ +#define MTX_CR_MTX_KICK 0x0080 + +/* Register CR_MTX_REGISTER_READ_WRITE_DATA */ +#define MTX_CR_MTX_REGISTER_READ_WRITE_DATA 0x00F8 + +/* Register CR_MTX_REGISTER_READ_WRITE_REQUEST */ +#define MTX_CR_MTX_REGISTER_READ_WRITE_REQUEST 0x00FC +#define MASK_MTX_MTX_RNW 0x00010000 +#define MASK_MTX_MTX_DREADY 0x80000000 + +/* Register CR_MTX_RAM_ACCESS_DATA_TRANSFER */ +#define MTX_CR_MTX_RAM_ACCESS_DATA_TRANSFER 0x0104 + +/* Register CR_MTX_RAM_ACCESS_CONTROL */ +#define MTX_CR_MTX_RAM_ACCESS_CONTROL 0x0108 +#define MASK_MTX_MTX_MCMR 0x00000001 +#define MASK_MTX_MTX_MCMAI 0x00000002 +#define SHIFT_MTX_MTX_MCMAI 1 +#define MASK_MTX_MTX_MCM_ADDR 0x000FFFFC +#define SHIFT_MTX_MTX_MCM_ADDR 2 +#define MASK_MTX_MTX_MCMID 0x0FF00000 +#define SHIFT_MTX_MTX_MCMID 20 + +/* Register CR_MTX_RAM_ACCESS_STATUS */ +#define MTX_CR_MTX_RAM_ACCESS_STATUS 0x010C +#define MASK_MTX_MTX_MTX_MCM_STAT 0x00000001 + +/* Register CR_MTX_SOFT_RESET */ +#define MTX_CR_MTX_SOFT_RESET 0x0200 +#define MASK_MTX_MTX_RESET 0x00000001 + +/* Register CR_MTX_SYSC_CDMAC */ +#define MTX_CR_MTX_SYSC_CDMAC 0x0340 +#define MASK_MTX_LENGTH 0x0000FFFF +#define SHIFT_MTX_LENGTH 0 +#define MASK_MTX_ENABLE 0x00010000 +#define SHIFT_MTX_ENABLE 16 +#define MASK_MTX_RNW 0x00020000 +#define SHIFT_MTX_RNW 17 +#define MASK_MTX_BURSTSIZE 0x07000000 +#define SHIFT_MTX_BURSTSIZE 24 + +/* Register CR_MTX_SYSC_CDMAA */ +#define MTX_CR_MTX_SYSC_CDMAA 0x0344 + +/* Register CR_MTX_SYSC_CDMAT */ +#define MTX_CR_MTX_SYSC_CDMAT 0x0350 + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topaz_coreext_regs.h b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topaz_coreext_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topaz_coreext_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topaz_coreext_regs.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _REGCONV_H_topazhp_coreext_regs_h +#define _REGCONV_H_topazhp_coreext_regs_h + +/* Register CR_SCALER_INPUT_SIZE */ +#define MASK_TOPAZHP_EXT_CR_SCALER_INPUT_WIDTH_MIN1 0x00000FFF +#define SHIFT_TOPAZHP_EXT_CR_SCALER_INPUT_WIDTH_MIN1 0 +#define MASK_TOPAZHP_EXT_CR_SCALER_INPUT_HEIGHT_MIN1 0x0FFF0000 +#define SHIFT_TOPAZHP_EXT_CR_SCALER_INPUT_HEIGHT_MIN1 16 + +/* Register CR_SCALER_PITCH */ +#define MASK_TOPAZHP_EXT_CR_SCALER_INPUT_HOR_PITCH 0x00007FFF +#define SHIFT_TOPAZHP_EXT_CR_SCALER_INPUT_HOR_PITCH 0 +#define MASK_TOPAZHP_EXT_CR_SCALER_HOR_BILINEAR_FILTER 0x00008000 +#define SHIFT_TOPAZHP_EXT_CR_SCALER_HOR_BILINEAR_FILTER 15 +#define MASK_TOPAZHP_EXT_CR_SCALER_INPUT_VER_PITCH 0x7FFF0000 +#define SHIFT_TOPAZHP_EXT_CR_SCALER_INPUT_VER_PITCH 16 +#define MASK_TOPAZHP_EXT_CR_SCALER_VER_BILINEAR_FILTER 0x80000000 +#define SHIFT_TOPAZHP_EXT_CR_SCALER_VER_BILINEAR_FILTER 31 + +/* Register CR_SCALER_CROP */ +#define MASK_TOPAZHP_EXT_CR_SCALER_INPUT_CROP_VER 0x000000FF +#define SHIFT_TOPAZHP_EXT_CR_SCALER_INPUT_CROP_VER 0 +#define MASK_TOPAZHP_EXT_CR_SCALER_INPUT_CROP_HOR 0x0000FF00 +#define SHIFT_TOPAZHP_EXT_CR_SCALER_INPUT_CROP_HOR 8 + +/* Register CR_SCALER_CONTROL */ +#define MASK_TOPAZHP_EXT_CR_SCALER_ENABLE 0x00000001 +#define SHIFT_TOPAZHP_EXT_CR_SCALER_ENABLE 0 +#define MASK_TOPAZHP_EXT_CR_ENABLE_COLOUR_SPACE_CONVERSION 0x00000002 +#define SHIFT_TOPAZHP_EXT_CR_ENABLE_COLOUR_SPACE_CONVERSION 1 +#define MASK_TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT 0x007F0000 +#define SHIFT_TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT 16 + +/* 4:4:4, Any 3 colour space components plus reserved byte (e.g. + * RGB), 8-bit components, packed 32-bit per pixel in a single plane, 8 LSBits not used + */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_444IL4XBCA8 0x0000007E + +/* 4:4:4, Any 3 colour space components plus reserved byte (e.g. + * RGB), 8-bit components, packed 32-bit per pixel in a single plane, 8 MSBits not used + */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_444IL4ABCX8 0x0000007C + +/* RGB with 5 bits for R, 6 bits for G and 5 bits for B */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_444IL3RGB565 0x00000070 + +/* 4:4:4, Y in 1 plane, CrCb interleaved in 2nd plane, 8-bit components */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_444PL12YCRCB8 0x0000006A + +/* 4:4:4, Y in 1 plane, CbCr interleaved in 2nd plane, 8-bit components */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_444PL12YCBCR8 0x00000068 + +/* 4:4:4, Y Cb Cr in 3 separate planes, 8-bit components + * (could also be ABC, but colour space conversion is not supported by input scaler + */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_444PL111YCBCR8 0x00000060 + +/* 4:2:2, CrYCbY interleaved in a single plane, 8-bit components */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422IL3CRYCBY8 0x00000056 + +/* 4:2:2, CbYCrY interleaved in a single plane, 8-bit components */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422IL3CBYCRY8 0x00000054 + +/* 4:2:2, YCrYCb interleaved in a single plane, 8-bit components */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422IL3YCRYCB8 0x00000052 + +/* 4:2:2, YCbYCr interleaved in a single plane, 8-bit components */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422IL3YCBYCR8 0x00000050 + +/* 4:2:2, Y in 1 plane, CrCb interleaved in 2nd plane, 8-bit components */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422PL12YCRCB8 0x0000004A + +/* 4:2:2, Y in 1 plane, CbCr interleaved in 2nd plane, 8-bit components */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422PL12YCBCR8 0x00000048 + +/* 4:2:2, Y Cb Cr in 3 separate planes, 8-bit components */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422PL111YCBCR8 0x00000040 + +/* 4:2:0, Y in 1 plane, CrCb interleaved in 2nd plane, 8-bit components */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_420PL12YCRCB8 0x0000002A + +/* 4:2:0, Y in 1 plane, CbCr interleaved in 2nd plane, 8-bit components */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_420PL12YCBCR8 0x00000028 + +/* 4:2:0, Y Cb Cr in 3 separate planes, 8-bit components */ +#define TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_420PL111YCBCR8 0x00000020 + +/* Register CR_CSC_SOURCE_MOD_Y_0 */ +#define MASK_TOPAZHP_EXT_CR_CSC_SOURCE_MOD_00 0x00000003 +#define SHIFT_TOPAZHP_EXT_CR_CSC_SOURCE_MOD_00 0 + +/* Subtract 1/2 maximum value from unsigned pixel component */ +#define TOPAZHP_EXT_CR_CSC_SOURCE_MOD_00_MINUS_1_2 0x00000003 + +/* Subtract 1/16th maximum value from unsigned pixel component */ +#define TOPAZHP_EXT_CR_CSC_SOURCE_MOD_00_MINUS_1_16 0x00000002 + +/* Source pixel component is unsigned */ +#define TOPAZHP_EXT_CR_CSC_SOURCE_MOD_00_UNSIGNED 0x00000000 + +/* Register CR_CSC_SOURCE_MOD_Y_1 */ +#define MASK_TOPAZHP_EXT_CR_CSC_SOURCE_MOD_01 0x00000003 +#define SHIFT_TOPAZHP_EXT_CR_CSC_SOURCE_MOD_01 0 + +/* Subtract 1/2 maximum value from unsigned pixel component */ +#define TOPAZHP_EXT_CR_CSC_SOURCE_MOD_01_MINUS_1_2 0x00000003 + +/* Subtract 1/16th maximum value from unsigned pixel component */ +#define TOPAZHP_EXT_CR_CSC_SOURCE_MOD_01_MINUS_1_16 0x00000002 + +/* Source pixel component is unsigned */ +#define TOPAZHP_EXT_CR_CSC_SOURCE_MOD_01_UNSIGNED 0x00000000 + +/* Register CR_CSC_SOURCE_CB_CR_1 */ +#define MASK_TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_CB_01 0x00000FFF +#define SHIFT_TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_CB_01 0 +#define SHIFT_TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_CR_01 16 + +/* Register CR_CSC_SOURCE_MOD_Y_2 */ +#define MASK_TOPAZHP_EXT_CR_CSC_SOURCE_MOD_02 0x00000003 +#define SHIFT_TOPAZHP_EXT_CR_CSC_SOURCE_MOD_02 0 + +/* Subtract 1/2 maximum value from unsigned pixel component */ +#define TOPAZHP_EXT_CR_CSC_SOURCE_MOD_02_MINUS_1_2 0x00000003 + +/* Subtract 1/16th maximum value from unsigned pixel component */ +#define TOPAZHP_EXT_CR_CSC_SOURCE_MOD_02_MINUS_1_16 0x00000002 + +/* Source pixel component is unsigned */ +#define TOPAZHP_EXT_CR_CSC_SOURCE_MOD_02_UNSIGNED 0x00000000 + +/* Register CR_CSC_SOURCE_CB_CR_2 */ +#define MASK_TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_CB_02 0x00000FFF +#define SHIFT_TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_CR_02 16 + +/* Register CR_CSC_OUTPUT_COEFF_0 */ +#define SHIFT_TOPAZHP_EXT_CR_CSC_OUTPUT_MIN_CLIP_00 0 +#define SHIFT_TOPAZHP_EXT_CR_CSC_OUTPUT_MAX_CLIP_00 16 +#define MASK_TOPAZHP_EXT_CR_CSC_OUTPUT_MOD_00 0x30000000 +#define SHIFT_TOPAZHP_EXT_CR_CSC_OUTPUT_MOD_00 28 + +/* Add 1/16th maximum value prior to applying unsigned clamping */ +#define TOPAZHP_EXT_CR_CSC_OUTPUT_MOD_00_ADD_1_16 0x00000002 + +/* Register CR_CSC_OUTPUT_COEFF_1 */ +#define MASK_TOPAZHP_EXT_CR_CSC_OUTPUT_MIN_CLIP_01 0x000003FF +#define SHIFT_TOPAZHP_EXT_CR_CSC_OUTPUT_MIN_CLIP_01 0 +#define SHIFT_TOPAZHP_EXT_CR_CSC_OUTPUT_MAX_CLIP_01 16 +#define MASK_TOPAZHP_EXT_CR_CSC_OUTPUT_MOD_01 0x30000000 +#define SHIFT_TOPAZHP_EXT_CR_CSC_OUTPUT_MOD_01 28 + +/* Add 1/2 maximum value prior to applying unsigned clamping */ +#define TOPAZHP_EXT_CR_CSC_OUTPUT_MOD_01_ADD_1_2 0x00000003 +#define MASK_TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_Y 0x0FFF0000 +#define SHIFT_TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_Y 16 + +/* Register CR_CSC_SOURCE_CB_CR */ +#define MASK_TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_CB 0x00000FFF +#define SHIFT_TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_CB 0 +#define MASK_TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_CR 0x0FFF0000 +#define SHIFT_TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_CR 16 + +/* Register CR_CSC_OUTPUT_COEFF */ +#define MASK_TOPAZHP_EXT_CR_CSC_OUTPUT_MIN_CLIP 0x000003FF +#define SHIFT_TOPAZHP_EXT_CR_CSC_OUTPUT_MIN_CLIP 0 +#define MASK_TOPAZHP_EXT_CR_CSC_OUTPUT_MAX_CLIP 0x03FF0000 +#define SHIFT_TOPAZHP_EXT_CR_CSC_OUTPUT_MAX_CLIP 16 + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topaz_db_regs.h b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topaz_db_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topaz_db_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topaz_db_regs.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _REGCONV_H_topaz_db_regs_h +#define _REGCONV_H_topaz_db_regs_h + +/* Register CR_DB_DISABLE_DEBLOCK_IDC */ +#define MASK_TOPAZ_DB_CR_DISABLE_DEBLOCK_IDC 0x00000003 +#define SHIFT_TOPAZ_DB_CR_DISABLE_DEBLOCK_IDC 0 + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topazhp_core_regs.h b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topazhp_core_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topazhp_core_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topazhp_core_regs.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,232 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _REGCONV_H_topazhp_core_regs_h +#define _REGCONV_H_topazhp_core_regs_h + +/* Register CR_LRITC_CACHE_CHUNK_CONFIG */ +#define MASK_TOPAZHP_CR_CACHE_CHUNKS_PRIORITY 0x000000FF +#define SHIFT_TOPAZHP_CR_CACHE_CHUNKS_PRIORITY 0 +#define MASK_TOPAZHP_CR_CACHE_CHUNKS_MAX 0x0000FF00 +#define SHIFT_TOPAZHP_CR_CACHE_CHUNKS_MAX 8 +#define MASK_TOPAZHP_CR_CACHE_CHUNKS_PER_MB 0x00FF0000 +#define SHIFT_TOPAZHP_CR_CACHE_CHUNKS_PER_MB 16 + +/* Register CR_SEQ_CUR_PIC_ROW_STRIDE */ +#define MASK_TOPAZHP_CR_CUR_PIC_LUMA_STRIDE 0x0000FFC0 +#define SHIFT_TOPAZHP_CR_CUR_PIC_LUMA_STRIDE 6 +#define MASK_TOPAZHP_CR_CUR_PIC_CHROMA_STRIDE 0xFFC00000 +#define SHIFT_TOPAZHP_CR_CUR_PIC_CHROMA_STRIDE 22 + +/* Register CR_SEQUENCER_CONFIG */ +#define MASK_TOPAZHP_CR_ENCODER_STANDARD 0x00000007 +#define SHIFT_TOPAZHP_CR_ENCODER_STANDARD 0 +#define TOPAZHP_CR_ENCODER_STANDARD_H264 0x00000002 /* H264 encode */ +#define MASK_TOPAZHP_CR_FRAME_STORE_FORMAT 0x00000030 +#define SHIFT_TOPAZHP_CR_FRAME_STORE_FORMAT 4 + +/* 4:2:0 frame, with Luma, Cb and Cr all in separate planes (if the frame + * store actually contains 4:2:2 chroma, the chroma stride can be doubled + * so that it is read as 4:2:0) + */ +#define MASK_TOPAZHP_CR_FRAME_STORE_CHROMA_SWAP 0x00000040 +#define SHIFT_TOPAZHP_CR_FRAME_STORE_CHROMA_SWAP 6 +#define MASK_TOPAZHP_CR_FIELD_MODE 0x00000080 +#define SHIFT_TOPAZHP_CR_FIELD_MODE 7 +#define MASK_TOPAZHP_CR_REF_PIC0_VALID 0x00000100 +#define SHIFT_TOPAZHP_CR_REF_PIC0_VALID 8 +#define MASK_TOPAZHP_CR_REF_PIC1_VALID 0x00000200 +#define SHIFT_TOPAZHP_CR_REF_PIC1_VALID 9 +#define MASK_TOPAZHP_CR_REF_PIC1_EQUAL_PIC0 0x00000400 +#define SHIFT_TOPAZHP_CR_REF_PIC1_EQUAL_PIC0 10 +#define MASK_TOPAZHP_CR_ABOVE_OUT_OF_SLICE_VALID 0x00000800 +#define SHIFT_TOPAZHP_CR_ABOVE_OUT_OF_SLICE_VALID 11 +#define MASK_TOPAZHP_CR_TEMPORAL_COL_IN_VALID 0x00001000 +#define SHIFT_TOPAZHP_CR_TEMPORAL_COL_IN_VALID 12 +#define MASK_TOPAZHP_CR_TEMPORAL_PIC0_BELOW_IN_VALID 0x00002000 +#define SHIFT_TOPAZHP_CR_TEMPORAL_PIC0_BELOW_IN_VALID 13 +#define MASK_TOPAZHP_CR_TEMPORAL_PIC1_BELOW_IN_VALID 0x00004000 +#define SHIFT_TOPAZHP_CR_TEMPORAL_PIC1_BELOW_IN_VALID 14 +#define MASK_TOPAZHP_CR_DEBLOCK_ENABLE 0x00008000 +#define SHIFT_TOPAZHP_CR_DEBLOCK_ENABLE 15 +#define MASK_TOPAZHP_CR_WRITE_TEMPORAL_COL_VALID 0x00010000 +#define SHIFT_TOPAZHP_CR_WRITE_TEMPORAL_COL_VALID 16 +#define MASK_TOPAZHP_CR_WRITE_TEMPORAL_PIC0_BELOW_VALID 0x00020000 +#define SHIFT_TOPAZHP_CR_WRITE_TEMPORAL_PIC0_BELOW_VALID 17 +#define MASK_TOPAZHP_CR_WRITE_TEMPORAL_PIC1_BELOW_VALID 0x00040000 +#define SHIFT_TOPAZHP_CR_WRITE_TEMPORAL_PIC1_BELOW_VALID 18 +#define MASK_TOPAZHP_CR_WRITE_MB_FIRST_STAGE_VALID 0x00200000 +#define SHIFT_TOPAZHP_CR_WRITE_MB_FIRST_STAGE_VALID 21 +#define MASK_TOPAZHP_CR_MB_CONTROL_IN_VALID 0x00800000 +#define SHIFT_TOPAZHP_CR_MB_CONTROL_IN_VALID 23 +#define MASK_TOPAZHP_CR_BEST_MULTIPASS_OUT_VALID 0x10000000 +#define SHIFT_TOPAZHP_CR_BEST_MULTIPASS_OUT_VALID 28 +#define MASK_TOPAZHP_CR_BEST_MVS_OUT_DISABLE 0x40000000 +#define SHIFT_TOPAZHP_CR_BEST_MVS_OUT_DISABLE 30 +#define MASK_TOPAZHP_CR_SLICE_TYPE 0x00030000 +#define SHIFT_TOPAZHP_CR_SLICE_TYPE 16 +#define TOPAZHP_CR_SLICE_TYPE_B_SLICE 0x00000002 /* B-slice */ +#define TOPAZHP_CR_SLICE_TYPE_P_SLICE 0x00000001 /* P-slice */ +#define TOPAZHP_CR_SLICE_TYPE_I_SLICE 0x00000000 /* I-slice */ +#define MASK_TOPAZHP_CR_MVCALC_RESTRICT_PICTURE 0x00010000 +#define SHIFT_TOPAZHP_CR_MVCALC_RESTRICT_PICTURE 16 + +/* Register CR_MVCALC_CONFIG */ +#define MASK_TOPAZHP_CR_MVCALC_GRID_MB_X_STEP 0x0000000F +#define SHIFT_TOPAZHP_CR_MVCALC_GRID_MB_X_STEP 0 +#define MASK_TOPAZHP_CR_MVCALC_GRID_MB_Y_STEP 0x00000F00 +#define SHIFT_TOPAZHP_CR_MVCALC_GRID_MB_Y_STEP 8 +#define MASK_TOPAZHP_CR_MVCALC_GRID_SUB_STEP 0x000F0000 +#define SHIFT_TOPAZHP_CR_MVCALC_GRID_SUB_STEP 16 +#define MASK_TOPAZHP_CR_MVCALC_GRID_DISABLE 0x00800000 +#define SHIFT_TOPAZHP_CR_MVCALC_GRID_DISABLE 23 +#define MASK_TOPAZHP_CR_MVCALC_IPE0_JITTER_FACTOR 0x03000000 +#define SHIFT_TOPAZHP_CR_MVCALC_IPE0_JITTER_FACTOR 24 +#define MASK_TOPAZHP_CR_MVCALC_IPE1_JITTER_FACTOR 0x0C000000 +#define SHIFT_TOPAZHP_CR_MVCALC_IPE1_JITTER_FACTOR 26 +#define MASK_TOPAZHP_CR_MVCALC_JITTER_POINTER_RST 0x10000000 +#define MASK_TOPAZHP_CR_MVCALC_NO_PSEUDO_DUPLICATES 0x20000000 +#define SHIFT_TOPAZHP_CR_MVCALC_NO_PSEUDO_DUPLICATES 29 +#define MASK_TOPAZHP_CR_MVCALC_DUP_VEC_MARGIN 0xC0000000 +#define SHIFT_TOPAZHP_CR_MVCALC_DUP_VEC_MARGIN 30 + +/* Register CR_MVCALC_COLOCATED */ +#define MASK_TOPAZHP_CR_COL_DIST_SCALE_FACT 0x000007FF +#define SHIFT_TOPAZHP_CR_COL_DIST_SCALE_FACT 0 + +/* Register CR_MVCALC_BELOW */ +#define MASK_TOPAZHP_CR_PIC0_DIST_SCALE_FACTOR 0x000007FF +#define SHIFT_TOPAZHP_CR_PIC0_DIST_SCALE_FACTOR 0 +#define MASK_TOPAZHP_CR_PIC1_DIST_SCALE_FACTOR 0x07FF0000 +#define SHIFT_TOPAZHP_CR_PIC1_DIST_SCALE_FACTOR 16 + +/* Register CR_PREFETCH_QP */ +#define MASK_TOPAZHP_CR_SKIPPED_CODED_SCALE_IDX 0x00007000 +#define SHIFT_TOPAZHP_CR_SKIPPED_CODED_SCALE_IDX 12 +#define MASK_TOPAZHP_CR_INTER_INTRA_SCALE_IDX 0x00000700 +#define SHIFT_TOPAZHP_CR_INTER_INTRA_SCALE_IDX 8 + +/* Register CR_MB_HOST_CONTROL */ +#define MASK_TOPAZHP_CR_MB_HOST_QP 0x00000001 +#define SHIFT_TOPAZHP_CR_MB_HOST_QP 0 +#define MASK_TOPAZHP_CR_MB_HOST_SKIPPED_CODED_SCALE 0x00000002 +#define SHIFT_TOPAZHP_CR_MB_HOST_SKIPPED_CODED_SCALE 1 +#define MASK_TOPAZHP_CR_MB_HOST_INTER_INTRA_SCALE 0x00000004 +#define SHIFT_TOPAZHP_CR_MB_HOST_INTER_INTRA_SCALE 2 +#define MASK_TOPAZHP_CR_H264COMP_8X8_TRANSFORM 0x00000001 +#define SHIFT_TOPAZHP_CR_H264COMP_8X8_TRANSFORM 0 +#define MASK_TOPAZHP_CR_H264COMP_CONSTRAINED_INTRA 0x00000002 +#define SHIFT_TOPAZHP_CR_H264COMP_CONSTRAINED_INTRA 1 +#define MASK_TOPAZHP_CR_H264COMP_8X8_CAVLC 0x00000004 +#define SHIFT_TOPAZHP_CR_H264COMP_8X8_CAVLC 2 +#define MASK_TOPAZHP_CR_H264COMP_DEFAULT_SCALING_LIST 0x00000008 +#define SHIFT_TOPAZHP_CR_H264COMP_DEFAULT_SCALING_LIST 3 +#define MASK_TOPAZHP_CR_H264COMP_ADAPT_ROUND_ENABLE 0x00000010 +#define SHIFT_TOPAZHP_CR_H264COMP_ADAPT_ROUND_ENABLE 4 +#define MASK_TOPAZHP_CR_H264COMP_VIDEO_CONF_ENABLE 0x00000020 +#define SHIFT_TOPAZHP_CR_H264COMP_VIDEO_CONF_ENABLE 5 +#define MASK_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_8X8_INTER_LUMA_ENABLE 0x00000080 +#define SHIFT_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_8X8_INTER_LUMA_ENABLE 7 +#define MASK_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTER_CR_ENABLE 0x00000100 +#define SHIFT_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTER_CR_ENABLE 8 +#define MASK_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTER_CB_ENABLE 0x00000200 +#define SHIFT_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTER_CB_ENABLE 9 +#define MASK_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTER_LUMA_ENABLE 0x00000400 +#define SHIFT_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTER_LUMA_ENABLE 10 +#define MASK_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_8X8_INTRA_LUMA_ENABLE 0x00000800 +#define SHIFT_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_8X8_INTRA_LUMA_ENABLE 11 +#define MASK_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTRA_CR_ENABLE 0x00001000 +#define SHIFT_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTRA_CR_ENABLE 12 +#define MASK_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTRA_CB_ENABLE 0x00002000 +#define SHIFT_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTRA_CB_ENABLE 13 +#define MASK_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTRA_LUMA_ENABLE 0x00004000 +#define SHIFT_TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTRA_LUMA_ENABLE 14 +#define MASK_TOPAZHP_CR_H264COMP_LOSSLESS 0x00010000 +#define SHIFT_TOPAZHP_CR_H264COMP_LOSSLESS 16 +#define MASK_TOPAZHP_CR_H264COMP_LOSSLESS_8X8_PREFILTER 0x00020000 +#define SHIFT_TOPAZHP_CR_H264COMP_LOSSLESS_8X8_PREFILTER 17 + +/* The Intra8x8 Pre-filter is performed in Lossless Mode. H.264 standard lossless. */ +#define TOPAZHP_CR_H264COMP_LOSSLESS_8X8_PREFILTER_FILTER 0x00000001 + +/* The Intra8x8 Pre-filter is bypassed in Lossless Mode. x264 compatibility mode for lossless. */ +#define TOPAZHP_CR_H264COMP_LOSSLESS_8X8_PREFILTER_BYPASS 0x00000000 + +/* Register CR_IPE_CONTROL */ +#define MASK_TOPAZHP_CR_IPE_BLOCKSIZE 0x00000003 +#define SHIFT_TOPAZHP_CR_IPE_BLOCKSIZE 0 +#define MASK_TOPAZHP_CR_IPE_16X8_ENABLE 0x00000004 +#define SHIFT_TOPAZHP_CR_IPE_16X8_ENABLE 2 +#define MASK_TOPAZHP_CR_IPE_8X16_ENABLE 0x00000008 +#define SHIFT_TOPAZHP_CR_IPE_8X16_ENABLE 3 +#define MASK_TOPAZHP_CR_IPE_Y_FINE_SEARCH 0x00000030 +#define SHIFT_TOPAZHP_CR_IPE_Y_FINE_SEARCH 4 +#define MASK_TOPAZHP_CR_IPE_4X4_SEARCH 0x00000040 +#define SHIFT_TOPAZHP_CR_IPE_4X4_SEARCH 6 +#define MASK_TOPAZHP_CR_IPE_LRITC_BOUNDARY 0x00000300 +#define SHIFT_TOPAZHP_CR_IPE_LRITC_BOUNDARY 8 +#define MASK_TOPAZHP_CR_IPE_HIGH_LATENCY 0x00001000 +#define SHIFT_TOPAZHP_CR_IPE_HIGH_LATENCY 12 +#define MASK_TOPAZHP_CR_IPE_MV_NUMBER_RESTRICTION 0x00004000 +#define SHIFT_TOPAZHP_CR_IPE_MV_NUMBER_RESTRICTION 14 + +/* Register CR_IPE_VECTOR_CLIPPING */ +#define MASK_TOPAZHP_CR_IPE_VECTOR_CLIPPING_X 0x000000FF +#define SHIFT_TOPAZHP_CR_IPE_VECTOR_CLIPPING_X 0 +#define MASK_TOPAZHP_CR_IPE_VECTOR_CLIPPING_Y 0x0000FF00 +#define SHIFT_TOPAZHP_CR_IPE_VECTOR_CLIPPING_Y 8 +#define MASK_TOPAZHP_CR_IPE_VECTOR_CLIPPING_ENABLED 0x00010000 +#define SHIFT_TOPAZHP_CR_IPE_VECTOR_CLIPPING_ENABLED 16 + +/* Register CR_JMCOMP_CARC_CONTROL_0 */ +#define MASK_TOPAZHP_CR_CARC_NEG_SCALE 0x3F000000 +#define SHIFT_TOPAZHP_CR_CARC_NEG_SCALE 24 +#define MASK_TOPAZHP_CR_CARC_NEG_RANGE 0x001F0000 +#define SHIFT_TOPAZHP_CR_CARC_NEG_RANGE 16 +#define MASK_TOPAZHP_CR_CARC_POS_SCALE 0x00003F00 +#define SHIFT_TOPAZHP_CR_CARC_POS_SCALE 8 +#define MASK_TOPAZHP_CR_CARC_POS_RANGE 0x0000001F +#define SHIFT_TOPAZHP_CR_CARC_POS_RANGE 0 + +/* Register CR_JMCOMP_CARC_CONTROL_1 */ +#define MASK_TOPAZHP_CR_CARC_SHIFT 0x03000000 +#define SHIFT_TOPAZHP_CR_CARC_SHIFT 24 +#define MASK_TOPAZHP_CR_CARC_CUTOFF 0x00F00000 +#define SHIFT_TOPAZHP_CR_CARC_CUTOFF 20 +#define MASK_TOPAZHP_CR_CARC_THRESHOLD 0x0007FF00 +#define SHIFT_TOPAZHP_CR_CARC_THRESHOLD 8 +#define MASK_TOPAZHP_CR_SPE_MVD_CLIP_ENABLE 0x80000000 +#define SHIFT_TOPAZHP_CR_SPE_MVD_CLIP_ENABLE 31 + +/* Register CR_PRED_COMB_CONTROL */ +#define MASK_TOPAZHP_CR_INTRA4X4_DISABLE 0x00000001 +#define SHIFT_TOPAZHP_CR_INTRA4X4_DISABLE 0 +#define MASK_TOPAZHP_CR_INTRA8X8_DISABLE 0x00000002 +#define SHIFT_TOPAZHP_CR_INTRA8X8_DISABLE 1 +#define MASK_TOPAZHP_CR_INTRA16X16_DISABLE 0x00000004 +#define SHIFT_TOPAZHP_CR_INTRA16X16_DISABLE 2 +#define MASK_TOPAZHP_CR_INTER8X8_DISABLE 0x00000010 +#define SHIFT_TOPAZHP_CR_INTER8X8_DISABLE 4 +#define MASK_TOPAZHP_CR_B_PIC0_DISABLE 0x00000100 +#define SHIFT_TOPAZHP_CR_B_PIC0_DISABLE 8 +#define MASK_TOPAZHP_CR_B_PIC1_DISABLE 0x00000200 +#define SHIFT_TOPAZHP_CR_B_PIC1_DISABLE 9 +#define MASK_TOPAZHP_CR_INTER_INTRA_SCALE_ENABLE 0x00001000 +#define SHIFT_TOPAZHP_CR_INTER_INTRA_SCALE_ENABLE 12 +#define MASK_TOPAZHP_CR_CUMULATIVE_BIASES_ENABLE 0x00000800 +#define SHIFT_TOPAZHP_CR_CUMULATIVE_BIASES_ENABLE 11 +#define MASK_TOPAZHP_CR_SKIPPED_CODED_SCALE_ENABLE 0x00002000 +#define SHIFT_TOPAZHP_CR_SKIPPED_CODED_SCALE_ENABLE 13 + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topazhp_multicore_regs_old.h b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topazhp_multicore_regs_old.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topazhp_multicore_regs_old.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topazhp_multicore_regs_old.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _REGCONV_H_topazhp_multicore_regs_old_h +#define _REGCONV_H_topazhp_multicore_regs_old_h + +///* Register CR_LAMBDA_DC_TABLE */ +#define MASK_TOPAZHP_CR_TEMPORAL_BLEND 0x001F0000 +#define SHIFT_TOPAZHP_CR_TEMPORAL_BLEND 16 + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topaz_vlc_regs.h b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topaz_vlc_regs.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topaz_vlc_regs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/reg_headers/topaz_vlc_regs.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * firmware header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _REGCONV_H_topaz_vlc_regs_h +#define _REGCONV_H_topaz_vlc_regs_h + +///* Register CR_VLC_CONTROL */ +#define MASK_TOPAZ_VLC_CR_CODEC 0x00000003 +#define SHIFT_TOPAZ_VLC_CR_CODEC 0 +#define MASK_TOPAZ_VLC_CR_CABAC_ENABLE 0x00000100 +#define SHIFT_TOPAZ_VLC_CR_CABAC_ENABLE 8 +#define MASK_TOPAZ_VLC_CR_VLC_FIELD_CODED 0x00000200 +#define SHIFT_TOPAZ_VLC_CR_VLC_FIELD_CODED 9 +#define MASK_TOPAZ_VLC_CR_VLC_8X8_TRANSFORM 0x00000400 +#define SHIFT_TOPAZ_VLC_CR_VLC_8X8_TRANSFORM 10 +#define MASK_TOPAZ_VLC_CR_VLC_CONSTRAINED_INTRA 0x00000800 +#define SHIFT_TOPAZ_VLC_CR_VLC_CONSTRAINED_INTRA 11 +#define MASK_TOPAZ_VLC_CR_CODEC_EXTEND 0x10000000 +#define SHIFT_TOPAZ_VLC_CR_CODEC_EXTEND 28 + +///* Register CR_VLC_IPCM_0 */ +#define MASK_TOPAZ_VLC_CR_CABAC_DB_MARGIN 0x03FF0000 +#define SHIFT_TOPAZ_VLC_CR_CABAC_DB_MARGIN 16 +#define MASK_TOPAZ_VLC_CR_CABAC_BIN_FLEX 0x00001FFF +#define SHIFT_TOPAZ_VLC_CR_CABAC_BIN_FLEX 0 +#define MASK_TOPAZ_VLC_CR_IPCM_THRESHOLD 0x00000FFF +#define SHIFT_TOPAZ_VLC_CR_IPCM_THRESHOLD 0 +#define MASK_TOPAZ_VLC_CR_CABAC_BIN_LIMIT 0x1FFF0000 +#define SHIFT_TOPAZ_VLC_CR_CABAC_BIN_LIMIT 16 +#define MASK_TOPAZ_VLC_CR_SLICE_SIZE_LIMIT 0x00FFFFFF +#define SHIFT_TOPAZ_VLC_CR_SLICE_SIZE_LIMIT 0 +#define MASK_TOPAZ_VLC_CR_SLICE_MBS_LIMIT 0x00003FFF +#define SHIFT_TOPAZ_VLC_CR_SLICE_MBS_LIMIT 0 + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/target_config.h b/drivers/media/platform/imagination/vxe-vxd/encoder/target_config.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/target_config.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/target_config.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Device specific memory configuration + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef __TARGET_CONFIG_H__ +#define __TARGET_CONFIG_H__ + +#include "target.h" + +/* Order MUST match with topaz_mem_space definition */ +enum topaz_mem_space_idx { + REG_TOPAZHP_MULTICORE = 0, + REG_DMAC, + REG_COMMS, + REG_MTX, + REG_MMU, + REG_TOPAZHP_TEST, + REG_MTX_RAM, + REG_TOPAZHP_CORE_0, + REG_TOPAZHP_VLC_CORE_0, + REG_TOPAZHP_DEBLOCKER_CORE_0, + REG_TOPAZHP_COREEXT_0, + REG_TOPAZHP_CORE_1, + REG_TOPAZHP_VLC_CORE_1, + REG_TOPAZHP_DEBLOCKER_CORE_1, + REG_TOPAZHP_COREEXT_1, + REG_TOPAZHP_CORE_2, + REG_TOPAZHP_VLC_CORE_2, + REG_TOPAZHP_DEBLOCKER_CORE_2, + REG_TOPAZHP_COREEXT_2, + REG_TOPAZHP_CORE_3, + REG_TOPAZHP_VLC_CORE_3, + REG_TOPAZHP_DEBLOCKER_CORE_3, + REG_TOPAZHP_COREEXT_3, + FW, + SYSMEM, + MEMSYSMEM, + MEM, + FB, + MEMDMAC_00, + MEMDMAC_01, + MEMDMAC_02, + MEM_SPACE_FORCE32BITS = 0x7FFFFFFFU +}; + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/target.h b/drivers/media/platform/imagination/vxe-vxd/encoder/target.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/target.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/target.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * target interface header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#if !defined(__TARGET_H__) +#define __TARGET_H__ + +#include + +#define TARGET_NO_IRQ (999) /* Interrupt number when no interrupt exists */ + +/* + * The memory space types + */ +enum mem_space_type { + MEMSPACE_REGISTER, /* Memory space is mapped to device registers */ + MEMSPACE_MEMORY, /* Memory space is mapped to device memory */ + MEMSPACE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * This structure contains all information about a device register + */ +struct mem_space_reg { + unsigned long long addr; /* Base address of device registers */ + unsigned int size; /* Size of device register block */ + unsigned int intr_num; /* The interrupt number */ +}; + +/* + * This structure contains all information about a device memory region + */ +struct mem_space_mem { + unsigned long long addr; /* Base address of memory region */ + unsigned long long size; /* Size of memory region */ + unsigned long long guard_band; /* Memory guard band */ +}; + +/* + * This structure contains all information about the device memory space + */ +struct mem_space { + unsigned char *name; /* Memory space name */ + enum mem_space_type type; /* Memory space type */ + union { + struct mem_space_reg reg; /* Device register info */ + struct mem_space_mem mem; /* Device memory region info */ + }; + + unsigned long cpu_addr; /* Cpu KM address for the mem space */ +}; + +struct target_config { + unsigned int num_mem_spaces; + struct mem_space *mem_spaces; +}; + +#endif /* __TARGET_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_api.c b/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_api.c --- a/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_api.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_api.c 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,3891 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Encoder Core API function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#include +#include +#include +#include +#include + +#include "fw_headers/coreflags.h" +#include "fw_headers/topazscfwif.h" +#include "header_gen.h" +#include "img_errors.h" +#include "img_mem_man.h" +#include "lst.h" +#include "reg_headers/topaz_coreext_regs.h" +#include "reg_headers/topazhp_core_regs.h" +#include "reg_headers/topaz_vlc_regs.h" +#include "reg_headers/topaz_db_regs.h" +#include "topaz_color_formats.h" +#include "topaz_device.h" +#include "topaz_api.h" +#include "topaz_api_utils.h" +#include "topazmmu.h" +#include "vxe_public_regdefs.h" +#include "img_errors.h" + +#define TOPAZ_TIMEOUT_RETRIES (5000000) +#define TOPAZ_TIMEOUT_WAIT_FOR_SPACE (500) + +#define COMM_WB_DATA_BUF_SIZE (64) + +/* + * All contexts should be able to send as many commands as possible before waiting for a response. + * There must be enough command memory buffers for all applicable commands, that is: + * -To fill all source slots + * -To supply custom quant data + */ +#define TOPAZ_CMD_DATA_BUF_NUM ((MAX_SOURCE_SLOTS_SL + 1) * TOPAZHP_MAX_POSSIBLE_STREAMS) +#define TOPAZ_CMD_DATA_BUF_SIZE (64) +#define COMM_CMD_DATA_BUF_SLOT_NONE 0xFF + +struct topaz_core_context *global_topaz_core_context; + +static unsigned char global_cmd_data_busy[TOPAZ_CMD_DATA_BUF_NUM]; +struct vidio_ddbufinfo global_cmd_data_dev_addr; /* Data section */ +struct vidio_ddbufinfo global_cmd_data_info[TOPAZ_CMD_DATA_BUF_NUM]; /* Data section */ +static unsigned char global_pipe_usage[TOPAZHP_MAX_NUM_PIPES] = { 0 }; + +struct vidio_ddbufinfo *global_wb_data_info; +static unsigned char is_topaz_core_initialized; + +/* + * Get a buffer reference + */ +static int topaz_get_buffer(struct topaz_stream_context *str_ctx, + struct img_buffer *buffer, void **lin_address, + unsigned char update_host_memory) +{ + if (buffer->lock == NOTDEVICEMEMORY) { + *lin_address = buffer->mem_info.cpu_virt; + return IMG_SUCCESS; + } + + if (buffer->lock == SW_LOCK) + return IMG_ERROR_SURFACE_LOCKED; + + if (update_host_memory) + topaz_update_host_mem(str_ctx->vxe_ctx, &buffer->mem_info); + + *lin_address = buffer->mem_info.cpu_virt; + buffer->lock = SW_LOCK; + + return IMG_SUCCESS; +} + +static int topaz_release_buffer(struct topaz_stream_context *str_ctx, + struct img_buffer *buffer, unsigned char update_device_memory) +{ + if (buffer->lock == NOTDEVICEMEMORY) + return IMG_SUCCESS; + + if (buffer->lock == HW_LOCK) + return IMG_ERROR_SURFACE_LOCKED; + + buffer->lock = BUFFER_FREE; + + if (update_device_memory) + topaz_update_device_mem(str_ctx->vxe_ctx, &buffer->mem_info); + + return IMG_SUCCESS; +} + +static int topaz_get_cmd_data_buffer(struct vidio_ddbufinfo **mem_info) +{ + int index = 0; + int res = IMG_SUCCESS; + + mutex_lock_nested(global_topaz_core_context->mutex, SUBCLASS_TOPAZ_API); + + do { + if (!global_cmd_data_busy[index]) + break; + index++; + } while (index < ARRAY_SIZE(global_cmd_data_info)); + + if (index == ARRAY_SIZE(global_cmd_data_info)) { + res = IMG_ERROR_UNEXPECTED_STATE; + } else { + global_cmd_data_busy[index] = TRUE; + *mem_info = &global_cmd_data_info[index]; + } + + mutex_unlock((struct mutex *)global_topaz_core_context->mutex); + + return res; +} + +static int topaz_release_cmd_data_buffer(struct vidio_ddbufinfo *mem_info) +{ + int index = 0; + int res = IMG_ERROR_UNEXPECTED_STATE; + + mutex_lock_nested(global_topaz_core_context->mutex, SUBCLASS_TOPAZ_API); + + do { + if (mem_info == &global_cmd_data_info[index]) { + global_cmd_data_busy[index] = FALSE; + res = IMG_SUCCESS; + break; + } + index++; + } while (index < ARRAY_SIZE(global_cmd_data_info)); + + mutex_unlock((struct mutex *)global_topaz_core_context->mutex); + + return res; +} + +/* + * Get a buffer reference + */ +static int get_coded_buffer(struct topaz_stream_context *str_ctx, void **lin_address, + unsigned char update_host_memory, unsigned char coded_package_idx) +{ + struct img_enc_context *enc; + struct img_video_context *video; + unsigned char coded_buffer_idx; + unsigned char found = FALSE; + unsigned int *address; + struct coded_data_hdr *coded_datahdr = NULL; + unsigned int offset_buffer_header = 0, offset_coded_buffer = 0; + /* Tells if all the slices have been retrieved */ + unsigned char all_slice_retrieved = FALSE; + /* Tells if we have reach the last coded buffer used or not */ + unsigned char slice_break = FALSE; + /* Tells if we are at the beginning of a slice or not */ + unsigned char new_coded_header = TRUE; + /* Tells the number of bytes remaining to be retrieved */ + unsigned int total_byte_written = 0; + unsigned int coded_slices_so_far = 0; + unsigned int coded_slices_in_buffer = 0; + + enc = str_ctx->enc_ctx; + video = enc->video; + + if (video->coded_package[coded_package_idx]->header_buffer->lock == SW_LOCK) + return IMG_ERROR_UNDEFINED; + + /* Retrieve the FW Package memory. Get linear address */ + video->coded_package[coded_package_idx]->mtx_info.coded_package_fw = + (struct coded_package_dma_info *)(&video->coded_package[coded_package_idx]->mtx_info + .code_package_fw_buffer->mem_info); + + if (update_host_memory) { + /* Go through all the coded buffers */ + for (coded_buffer_idx = 0; coded_buffer_idx < MAX_CODED_BUFFERS_PER_PACKAGE; + coded_buffer_idx++) { + /* Reset the Offset */ + offset_coded_buffer = 0; + do { + if (new_coded_header) { // beginning of a slice + slice_break = FALSE; + /* Get the coded header information */ + *lin_address = video->coded_package + [coded_package_idx]->header_buffer->mem_info.cpu_virt; + address = *lin_address; + /* Getting the nth buffer header */ + coded_datahdr = (struct coded_data_hdr *)(address + + (offset_buffer_header / 4)); + total_byte_written = coded_datahdr->bytes_written; + coded_slices_so_far = + F_DECODE(coded_datahdr->extra_feedback, + CODED_SLICES_SO_FAR); + coded_slices_in_buffer = + F_DECODE(coded_datahdr->extra_feedback, + CODED_SLICES_IN_BUFFER); + + /* Increment the offset in the coded header information + * buffer in order to point on the next header + */ + offset_buffer_header += CODED_BUFFER_INFO_SECTION_SIZE; + } + + if (!new_coded_header) { + /* Retrieve the last coded data */ + offset_coded_buffer = ALIGN_16(offset_coded_buffer + + total_byte_written); + slice_break = TRUE; + /* On next loop we will be at the start of a new slice */ + new_coded_header = TRUE; + } else { + /* + * New slice : Read all the bytes written for this slice + * Go after what we read, next 16bit align address + */ + offset_coded_buffer = + ALIGN_16(offset_coded_buffer + + coded_datahdr->bytes_written); + if (F_DECODE(coded_datahdr->extra_feedback, + CODED_SLICES_SO_FAR) == + F_DECODE(coded_datahdr->extra_feedback, + CODED_SLICES_IN_BUFFER)) { + /* We now have all the slices for this coded buffer, + * we should not try to read further. + */ + all_slice_retrieved = TRUE; + break; + } + } + } while (coded_slices_so_far != coded_slices_in_buffer); + + if (all_slice_retrieved || slice_break) { + /* If we are NOT in the middle of a slice */ + found = TRUE; + /* We lock this last buffer */ + video->coded_package[coded_package_idx]->coded_buffer + [coded_buffer_idx]->lock = SW_LOCK; + /* This function will do nothing if -debugCRCs (1 or 2) has not + * been specified on the command line + */ + break; + } + } + + if (!found) + topaz_update_host_mem(str_ctx->vxe_ctx, &video->coded_package + [coded_package_idx]->header_buffer->mem_info); + } + + /* address of first header if all buffer finish in middle of + * slice or !bUpdateHostMemory, last red header otherwise + */ + *lin_address = video->coded_package[coded_package_idx]->header_buffer->mem_info.cpu_virt; + /* Lock-it */ + video->coded_package[coded_package_idx]->header_buffer->lock = SW_LOCK; + + return IMG_SUCCESS; +} + +static void combine_feedback(struct topaz_stream_context *str_ctx, + unsigned char active_coded_package_idx, unsigned int *feedback, + unsigned int *extra_feedback, unsigned int *bytes_coded) +{ + struct img_enc_context *enc = str_ctx->enc_ctx; + struct coded_data_hdr *coded_datahdr; + unsigned int offset = 0; + unsigned int min_bu = 0xFFFFFFFF; + unsigned int coded_bytes = 0; + unsigned int bu; + unsigned int coded_slices_so_far; + unsigned int coded_slices_in_buffer; + + do { + /* we should be able to rely on the linear pointer here + * as the coded data header should have been updated. + */ + coded_datahdr = (struct coded_data_hdr *)((unsigned long)(enc->video->coded_package + [active_coded_package_idx]->header_buffer->mem_info.cpu_virt) + + offset); + + IMG_DBG_ASSERT(coded_datahdr); + if (!coded_datahdr) + return; + + bu = F_DECODE(coded_datahdr->feedback, CODED_FIRST_BU); + coded_slices_so_far = F_DECODE(coded_datahdr->extra_feedback, CODED_SLICES_SO_FAR); + coded_slices_in_buffer = F_DECODE(coded_datahdr->extra_feedback, + CODED_SLICES_IN_BUFFER); + + if (bu < min_bu) + min_bu = bu; + + coded_bytes += coded_datahdr->bytes_written; + offset += CODED_BUFFER_INFO_SECTION_SIZE; + } while (coded_slices_so_far != coded_slices_in_buffer); + + *bytes_coded = coded_bytes; + *feedback = F_INSERT(coded_datahdr->feedback, min_bu, CODED_FIRST_BU); + *extra_feedback = coded_datahdr->extra_feedback; +} + +/* + * Move around the reconstructed data and handle the list for frame reordering + */ +static void process_reconstructed(struct topaz_stream_context *str_ctx, unsigned char is_coded, + enum img_frame_type frame_type, struct list_item **recon_list) +{ + struct img_video_context *video = str_ctx->enc_ctx->video; + unsigned char *tmp_buffer; + unsigned short width, height; + struct list_item *new_item; + struct img_recon_node *new_node; + struct list_item *current_item; + + *recon_list = NULL; + + if (!video->output_reconstructed) + return; + + /* Create new reconstructed node */ + new_item = kzalloc(sizeof(*new_item), GFP_KERNEL); + if (!new_item) + return; + + new_item->data = kzalloc(sizeof(*new_node), GFP_KERNEL); + if (!new_item->data) { + kfree(new_item); + new_item = NULL; + return; + } + + new_node = (struct img_recon_node *)new_item->data; + + if (is_coded) { + topaz_update_host_mem(str_ctx->vxe_ctx, video->recon_buffer); + tmp_buffer = (unsigned char *)video->recon_buffer->cpu_virt; + width = ALIGN_64(video->width); + height = ALIGN_64(video->frame_height); + + new_node->buffer = kzalloc(width * height * 3 / 2, GFP_KERNEL); + if (!new_node->buffer) { + kfree(new_item->data); + kfree(new_item); + new_item = NULL; + new_node = NULL; + return; + } + memcpy(new_node->buffer, tmp_buffer, width * height * 3 / 2); + + } else { + new_node->buffer = NULL; + } + new_node->poc = video->recon_poc; + + /* Add new node to the queue */ + if (!video->ref_frame) { + /* First element */ + new_item->next = NULL; + video->ref_frame = new_item; + } else if (new_node->poc == 0) { + /* First element after aborted sequence */ + current_item = video->ref_frame; + + while (current_item->next) + current_item = current_item->next; + + /* Insert at end */ + new_item->next = NULL; + current_item->next = new_item; + } else { + struct img_recon_node *head_node = (struct img_recon_node *)video->ref_frame->data; + + if (head_node->poc > new_node->poc) { + /* Insert at start */ + new_item->next = video->ref_frame; + video->ref_frame = new_item; + } else { + struct img_recon_node *next_node = NULL; + + current_item = video->ref_frame; + while (current_item->next) { + next_node = (struct img_recon_node *)current_item->next->data; + + if (next_node->poc > new_node->poc) { + /* Insert between current and next */ + new_item->next = current_item->next; + current_item->next = new_item; + break; + } + current_item = current_item->next; + } + + if (!current_item->next) { + /* Insert at end */ + new_item->next = NULL; + current_item->next = new_item; + } + } + } + + if (video->next_recon == 0) { + video->next_recon++; + /* Flush all frames */ + *recon_list = video->ref_frame; + video->ref_frame = NULL; + } else if (new_node->poc == video->next_recon) { + struct list_item *flush_tail = video->ref_frame; + struct img_recon_node *next_node; + + video->next_recon++; + + /* Find all flushable frames */ + while (flush_tail->next) { + next_node = (struct img_recon_node *)flush_tail->next->data; + + /* Flushing sequence ends when POCs no longer match */ + if (next_node->poc != video->next_recon) + break; + + video->next_recon++; + + flush_tail = flush_tail->next; + } + + /* Flush consecutive sequence */ + *recon_list = video->ref_frame; + + /* Set new head */ + video->ref_frame = flush_tail->next; + + /* Separate sequences */ + flush_tail->next = NULL; + } +} + +int topaz_process_message(struct topaz_stream_context *str_ctx, struct mtx_tohost_msg tohost_msg) +{ + struct driver_tohost_msg *driver_msg; + struct list_item *current_el = NULL; + struct img_enc_context *enc; + struct img_video_context *video; + struct list_item *message_list = NULL; + unsigned int index = 0; + + enc = str_ctx->enc_ctx; + video = enc->video; + + /* add a new element */ + current_el = kzalloc(sizeof(*current_el), GFP_KERNEL); + if (!current_el) + return IMG_ERROR_OUT_OF_MEMORY; + + current_el->data = kzalloc(sizeof(*driver_msg), GFP_KERNEL); + if (!current_el->data) { + kfree(current_el); + current_el = NULL; + return IMG_ERROR_OUT_OF_MEMORY; + } + + /* adding to head */ + current_el->next = message_list; + message_list = current_el; + + driver_msg = (struct driver_tohost_msg *)current_el->data; + driver_msg->cmd_id = tohost_msg.cmd_id; + driver_msg->data = tohost_msg.data; + driver_msg->command_data_buf = tohost_msg.command_data_buf; + + switch (tohost_msg.cmd_id) { + case MTX_MESSAGE_ACK: + driver_msg->input_cmd_id = (enum mtx_cmd_id)F_DECODE(tohost_msg.input_cmd_word, + MTX_MSG_CMD_ID); + break; + + case MTX_MESSAGE_CODED: + { + struct coded_data_hdr *coded_datahdr = NULL; + unsigned int feedback, extra_feedback; + unsigned char active_coded_package_idx; + struct img_feedback_element *feedback_struct; + + active_coded_package_idx = tohost_msg.coded_pkg_idx; + + get_coded_buffer(str_ctx, (void **)&coded_datahdr, TRUE, + active_coded_package_idx); + + feedback = coded_datahdr->feedback; + extra_feedback = coded_datahdr->extra_feedback; + + /* detect the FrameNum of the coded buffer */ + feedback_struct = (struct img_feedback_element *)&driver_msg->feedback; + + combine_feedback(str_ctx, active_coded_package_idx, &feedback, &extra_feedback, + &feedback_struct->bytes_coded); + + feedback_struct->coded_buffer_count = F_DECODE(extra_feedback, + CODED_BUFFER_NUMBER_USED); + + /* Give the header buffer to the feedback structure */ + feedback_struct->coded_package = video->coded_package[active_coded_package_idx]; + feedback_struct->active_coded_package_idx = active_coded_package_idx; + /* update this frame, using the info from the coded buffer */ + feedback_struct->coded_package->coded_buffer[feedback_struct->coded_slot_num] = + video->coded_package[active_coded_package_idx]->coded_buffer[feedback_struct + ->coded_slot_num]; + + feedback_struct->first_bu = F_DECODE(feedback, CODED_FIRST_BU); + feedback_struct->storage_frame_num = F_DECODE(feedback, CODED_STORAGE_FRAME_NUM); + feedback_struct->entire_frame = F_DECODE(feedback, CODED_ENTIRE_FRAME); + feedback_struct->is_skipped = F_DECODE(feedback, CODED_IS_SKIPPED); + feedback_struct->is_coded = F_DECODE(feedback, CODED_IS_CODED); + feedback_struct->recon_idx = F_DECODE(feedback, CODED_RECON_IDX); + feedback_struct->source_slot = F_DECODE(feedback, CODED_SOURCE_SLOT); + feedback_struct->frame_type = (enum img_frame_type)F_DECODE + (feedback, CODED_FRAME_TYPE); + feedback_struct->slice_num = F_DECODE(feedback, CODED_SLICE_NUM); + feedback_struct->poc = video->source_slot_poc[feedback_struct->source_slot]; + + feedback_struct->slices_in_buffer = F_DECODE(extra_feedback, + CODED_SLICES_IN_BUFFER); + feedback_struct->field = F_DECODE(extra_feedback, CODED_FIELD); + feedback_struct->patched_recon = F_DECODE(extra_feedback, + CODED_PATCHED_RECON); + feedback_struct->bytes_coded = coded_datahdr->bytes_written; + feedback_struct->host_ctx = coded_datahdr->host_ctx; + + if (video->highest_storage_number != feedback_struct->storage_frame_num && + video->standard != IMG_STANDARD_H263) { + if (feedback_struct->storage_frame_num == + ((video->highest_storage_number + 1) & 0x03)) { + /* it is piece of the next frame */ + video->highest_storage_number = feedback_struct->storage_frame_num; + /* retrieve next WB */ + video->encode_pic_processing--; + video->extra_wb_retrieved++; + } else if (feedback_struct->storage_frame_num == + ((video->highest_storage_number + 2) & 0x03)) { + /* it is piece of the next frame */ + video->highest_storage_number = feedback_struct->storage_frame_num; + + video->encode_pic_processing -= 2; + video->extra_wb_retrieved += 2; + } + } + + while (index < feedback_struct->coded_buffer_count) { + if (video->coded_package + [active_coded_package_idx]->coded_buffer[index]->lock == SW_LOCK) + /* Unlock coded buffers used*/ + topaz_release_buffer(str_ctx, + (struct img_buffer *)(video->coded_package + [active_coded_package_idx]->coded_buffer[index]), + FALSE); + index++; + } + + /* Unlock header buffer */ + topaz_release_buffer(str_ctx, video->coded_package + [feedback_struct->active_coded_package_idx]->header_buffer, + FALSE); + + /* Release the coded slot */ + video->coded_package[feedback_struct->active_coded_package_idx]->busy = FALSE; + + feedback_struct->src_frame = video->source_slot_buff[feedback_struct->source_slot]; + + /* Detect the slice number based on the Slice Map and the first BU in a slice */ + if (feedback_struct->bytes_coded) { + struct img_buffer *output_slice_map; + unsigned char *src_buffer = NULL; + unsigned char slices_per_picture; + unsigned short first_bu_in_slice; + unsigned char slice_number; + unsigned char index; + unsigned char slice_size_in_bu[MAX_SLICESPERPIC]; + + /* postion the start of the slice map */ + output_slice_map = &video->slice_map[feedback_struct->source_slot]; + + topaz_get_buffer(str_ctx, output_slice_map, (void **)&src_buffer, FALSE); + + /* retrieve slices per field */ + slices_per_picture = *src_buffer; + src_buffer++; + + /* retrieve first BU in slices and Slice sizes in BUs */ + first_bu_in_slice = 0; + + for (index = 0; index < slices_per_picture; index++) { + slice_number = src_buffer[index * 2]; + slice_size_in_bu[slice_number] = src_buffer[index * 2 + 1]; + + first_bu_in_slice += slice_size_in_bu[slice_number]; + } + topaz_release_buffer(str_ctx, output_slice_map, FALSE); + + feedback_struct->slices_per_picture = slices_per_picture; + } + + if (feedback_struct->entire_frame) { + /* we encoded the entire frame */ + video->frames_encoded++; +#ifdef DEBUG_ENCODER_DRIVER + pr_info("FRAMES_CODED[%d]\n", video->frames_encoded); +#endif + + if (feedback_struct->coded_package->coded_buffer[0]) { + /* Send callback for coded_buffer ready */ + global_topaz_core_context->vxe_str_processed_cb(str_ctx->vxe_ctx, + VXE_CB_CODED_BUFF_READY, + (void *)(feedback_struct->coded_package->coded_buffer[0]), + feedback_struct->bytes_coded, video->frames_encoded, + feedback_struct->frame_type); + } + + if (!str_ctx->vxe_ctx->eos) { + if (feedback_struct->src_frame) { + /* Send callback for src ready */ + global_topaz_core_context->vxe_str_processed_cb( + str_ctx->vxe_ctx, + VXE_CB_SRC_FRAME_RELEASE, + (void *)(feedback_struct + ->src_frame), + 0, 0, 0); + } + } + if (video->flush_at_frame > 0 && + video->frames_encoded >= video->flush_at_frame) + feedback_struct->last_frame_encoded = TRUE; + + if (feedback_struct->patched_recon && video->patched_recon_buffer) { + video->recon_buffer = video->patched_recon_buffer; + video->patched_recon_buffer = NULL; + } else { + video->recon_buffer = + &video->recon_pictures[feedback_struct->recon_idx]; + } + video->recon_poc = feedback_struct->poc; + + video->frame_type = feedback_struct->frame_type; + + process_reconstructed(str_ctx, feedback_struct->is_coded, video->frame_type, + &feedback_struct->recon_list); + + /* If there are more frames to be encoded, release the source slot */ + if (video->frame_count == 0 || + video->encode_requested < video->frame_count) + video->source_slot_buff[feedback_struct->source_slot] = NULL; + + if (!video->extra_wb_retrieved) { + video->encode_pic_processing--; + video->highest_storage_number = + (video->highest_storage_number + 1) & 0x03; + } else { + video->extra_wb_retrieved--; + } + } else { + if (feedback_struct->coded_package->coded_buffer[0]) { + /* Send callback for coded_buffer ready */ + global_topaz_core_context->vxe_str_processed_cb(str_ctx->vxe_ctx, + VXE_CB_CODED_BUFF_READY, + (void *)(feedback_struct->coded_package->coded_buffer[0]), + feedback_struct->bytes_coded, video->frames_encoded, + feedback_struct->frame_type); + } + } + + if (feedback_struct->entire_frame && + (video->enable_sel_stats_flags & ESF_FIRST_STAGE_STATS)) + feedback_struct->motion_search_statistics_buf = + &video->firstpass_out_param_buf[feedback_struct->source_slot]; + else + feedback_struct->motion_search_statistics_buf = NULL; + + if (video->frame_count > 0 && video->frames_encoded >= video->frame_count) + feedback_struct->last_frame_encoded = TRUE; + + if (feedback_struct->entire_frame && + (video->enable_sel_stats_flags & ESF_MP_BEST_MB_DECISION_STATS || + video->enable_sel_stats_flags & ESF_MP_BEST_MOTION_VECTOR_STATS)) + feedback_struct->best_multipass_statistics_buf = + &video->firstpass_out_best_multipass_param_buf + [feedback_struct->source_slot]; + else + feedback_struct->best_multipass_statistics_buf = NULL; + break; + } + default: + break; + } + + kfree(current_el->data); + kfree(current_el); + + return IMG_SUCCESS; +} + +void handle_encoder_firmware_response(struct img_writeback_msg *wb_msg, void *priv) +{ + struct topaz_stream_context *str_ctx; + struct mtx_tohost_msg tohost_msg; + int index; + unsigned int cmd_buf_slot = COMM_CMD_DATA_BUF_SLOT_NONE; + unsigned int *cmdbuf_devaddr; + + str_ctx = (struct topaz_stream_context *)priv; + + if (!str_ctx) + return; + + memset(&tohost_msg, 0, sizeof(tohost_msg)); + tohost_msg.cmd_id = (enum mtx_message_id)F_DECODE(wb_msg->cmd_word, MTX_MSG_MESSAGE_ID); + + switch (tohost_msg.cmd_id) { + case MTX_MESSAGE_ACK: +#ifdef DEBUG_ENCODER_DRIVER + pr_info("MTX_MESSAGE_ACK received\n"); +#endif + + tohost_msg.wb_val = wb_msg->writeback_val; + tohost_msg.input_cmd_word = wb_msg->cmd_word; + tohost_msg.data = wb_msg->data; + break; + case MTX_MESSAGE_CODED: +#ifdef DEBUG_ENCODER_DRIVER + pr_info("MTX_MESSAGE_CODED Received\n"); +#endif + tohost_msg.input_cmd_word = wb_msg->cmd_word; + tohost_msg.coded_pkg_idx = wb_msg->coded_package_consumed_idx; + break; + default: + break; + } + + cmdbuf_devaddr = global_cmd_data_dev_addr.cpu_virt; + + for (index = 0; index < TOPAZ_CMD_DATA_BUF_NUM; index++) { + if (*cmdbuf_devaddr == wb_msg->extra_data) { + /* Input cmd buffer found */ + cmd_buf_slot = index; + break; + } + cmdbuf_devaddr++; + } + + if (cmd_buf_slot != COMM_CMD_DATA_BUF_SLOT_NONE) { + tohost_msg.command_data_buf = &global_cmd_data_info[cmd_buf_slot]; + topaz_release_cmd_data_buffer(tohost_msg.command_data_buf); + + } else { + tohost_msg.command_data_buf = NULL; + } + + mutex_lock_nested(str_ctx->vxe_ctx->mutex, SUBCLASS_VXE_V4L2); + topaz_process_message(str_ctx, tohost_msg); + mutex_unlock(str_ctx->vxe_ctx->mutex); +} + +static inline void populate_firmware_message(struct vidio_ddbufinfo *dest, unsigned int dest_offset, + struct vidio_ddbufinfo *src, unsigned int src_offset) +{ + *(unsigned int *)((unsigned long)dest->cpu_virt + dest_offset) = + src->dev_virt + src_offset; +} + +/* + * init_hardware + */ +int init_topaz_core(void *device_handle, unsigned int *num_pipes, + unsigned int mmu_flags, void *callback) +{ + unsigned int index; + + if (is_topaz_core_initialized) + return IMG_ERROR_INVALID_PARAMETERS; + + is_topaz_core_initialized = TRUE; + + global_topaz_core_context = kzalloc(sizeof(*global_topaz_core_context), GFP_KERNEL); + if (!global_topaz_core_context) { + is_topaz_core_initialized = FALSE; + return IMG_ERROR_OUT_OF_MEMORY; + } + + /* Initialise device context. */ + global_topaz_core_context->dev_handle = (struct topaz_dev_ctx *)device_handle; + global_topaz_core_context->vxe_str_processed_cb = (vxe_cb)callback; + + lst_init(&global_topaz_core_context->topaz_stream_list); + + *num_pipes = topazdd_get_num_pipes(device_handle); + + /* allocate memory for HighCmd FIFO data section */ + if (topaz_mmu_alloc(global_topaz_core_context->dev_handle->topaz_mmu_ctx.mmu_context_handle, + global_topaz_core_context->dev_handle->vxe_arg, MMU_GENERAL_HEAP_ID, + 1, (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + 4 * TOPAZ_CMD_DATA_BUF_NUM, 64, &global_cmd_data_dev_addr)) { + IMG_DBG_ASSERT("Global command data info buff alloc failed\n" != NULL); + kfree(global_topaz_core_context); + return IMG_ERROR_OUT_OF_MEMORY; + } + + for (index = 0; index < ARRAY_SIZE(global_cmd_data_info); index++) { + if (topaz_mmu_alloc + (global_topaz_core_context->dev_handle->topaz_mmu_ctx.mmu_context_handle, + global_topaz_core_context->dev_handle->vxe_arg, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + TOPAZ_CMD_DATA_BUF_SIZE, 64, &global_cmd_data_info[index])) { + IMG_DBG_ASSERT("Global command data info buff alloc failed\n" != NULL); + topaz_mmu_free(global_topaz_core_context->dev_handle->vxe_arg, + &global_cmd_data_dev_addr); + kfree(global_topaz_core_context); + return IMG_ERROR_OUT_OF_MEMORY; + } + populate_firmware_message(&global_cmd_data_dev_addr, 4 * index, + &global_cmd_data_info[index], 0); + global_cmd_data_busy[index] = FALSE; + } + + /*Lock for locking critical section in TopazAPI*/ + global_topaz_core_context->mutex = kzalloc(sizeof(*global_topaz_core_context->mutex), + GFP_KERNEL); + if (!global_topaz_core_context->mutex) + return IMG_ERROR_OUT_OF_MEMORY; + + mutex_init(global_topaz_core_context->mutex); + return IMG_SUCCESS; +} + +/* + * deinit_topaz_core + */ +int deinit_topaz_core(void) +{ + unsigned int index; + + mutex_destroy(global_topaz_core_context->mutex); + kfree(global_topaz_core_context->mutex); + global_topaz_core_context->mutex = NULL; + + if (topaz_mmu_free(global_topaz_core_context->dev_handle->vxe_arg, + &global_cmd_data_dev_addr)) + IMG_DBG_ASSERT("Free failed" == NULL); + + for (index = 0; index < ARRAY_SIZE(global_cmd_data_info); index++) + if (topaz_mmu_free(global_topaz_core_context->dev_handle->vxe_arg, + &global_cmd_data_info[index])) + IMG_DBG_ASSERT("Free failed" == NULL); + + return IMG_SUCCESS; +} + +static unsigned short create_gop_frame(unsigned char *level, unsigned char reference, + unsigned char pos, unsigned char ref0_level, + unsigned char ref1_level, enum img_frame_type frame_type) +{ + *level = max(ref0_level, ref1_level) + 1; + + return F_ENCODE(reference, GOP_REFERENCE) | + F_ENCODE(pos, GOP_POS) | + F_ENCODE(ref0_level, GOP_REF0) | + F_ENCODE(ref1_level, GOP_REF1) | + F_ENCODE(frame_type, GOP_FRAMETYPE); +} + +static void gop_split(unsigned short **gop_structure, signed char ref0, + signed char ref1, unsigned char ref0_level, + unsigned char ref1_level, unsigned char pic_on_level[]) +{ + unsigned char distance = ref1 - ref0; + unsigned char position = ref0 + (distance >> 1); + unsigned char level; + + if (distance == 1) + return; + + /* mark middle as this level */ + (*gop_structure)++; + **gop_structure = create_gop_frame(&level, distance >= 3, position, ref0_level, ref1_level, + IMG_INTER_B); + pic_on_level[level]++; + + if (distance >= 4) + gop_split(gop_structure, ref0, position, ref0_level, level, pic_on_level); + + if (distance >= 3) + gop_split(gop_structure, position, ref1, level, ref1_level, pic_on_level); +} + +static void mini_gop_generate_hierarchical(unsigned short gop_structure[], + unsigned int bframe_count, + unsigned int ref_spacing, + unsigned char pic_on_level[]) +{ + unsigned char level; + + gop_structure[0] = create_gop_frame(&level, TRUE, bframe_count, ref_spacing, 0, + IMG_INTER_P); + pic_on_level[level]++; + + gop_split(&gop_structure, -1, bframe_count, ref_spacing, ref_spacing + 1, pic_on_level); +} + +static void mini_gop_generate_flat(unsigned short gop_structure[], + unsigned int bframe_count, + unsigned int ref_spacing, + unsigned char pic_on_level[]) +{ + /* B B B B P */ + unsigned char encode_order_pos; + unsigned char level; + + gop_structure[0] = create_gop_frame(&level, TRUE, MAX_BFRAMES, ref_spacing, 0, + IMG_INTER_P); + pic_on_level[level]++; + + for (encode_order_pos = 1; encode_order_pos < MAX_GOP_SIZE; encode_order_pos++) { + gop_structure[encode_order_pos] = create_gop_frame(&level, + FALSE, encode_order_pos - 1, + ref_spacing, ref_spacing + 1, + IMG_INTER_B); + pic_on_level[level] = bframe_count; + } +} + +/* + * Create the MTX-side encoder context + */ +static int topaz_video_create_mtx_context(struct topaz_stream_context *str_ctx, + struct img_video_params *video_params) +{ + struct img_video_context *video; + struct img_enc_context *enc; + int index, i, j; + void *mtx_enc_context_mem; + struct img_mtx_video_context *mtx_enc_context; + unsigned char flag; + unsigned int max_cores; + unsigned int bit_limit; + unsigned int vert_mv_limit; + unsigned int packed_strides; + unsigned short *gop_structure; + + max_cores = topazdd_get_num_pipes(global_topaz_core_context->dev_handle); + + enc = str_ctx->enc_ctx; + video = enc->video; + + mtx_enc_context = (struct img_mtx_video_context *)(video->mtx_enc_ctx_mem.cpu_virt); + + /* clear the context region */ + memset(mtx_enc_context, 0x00, MTX_CONTEXT_SIZE); + + mtx_enc_context_mem = (void *)(&enc->video->mtx_enc_ctx_mem); + + mtx_enc_context->initial_qp_i = video->rc_params.initial_qp_i; + mtx_enc_context->initial_qp_p = video->rc_params.initial_qp_p; + mtx_enc_context->initial_qp_b = video->rc_params.initial_qp_b; + + mtx_enc_context->cqp_offset = (video->rc_params.qcp_offset & 0x1f) | + ((video->rc_params.qcp_offset & 0x1f) << 8); + mtx_enc_context->standard = video->standard; + mtx_enc_context->width_in_mbs = video->width >> 4; + mtx_enc_context->picture_height_in_mbs = video->picture_height >> 4; + + mtx_enc_context->kick_size = video->kick_size; + mtx_enc_context->kicks_per_bu = video->kicks_per_bu; + mtx_enc_context->kicks_per_picture = (mtx_enc_context->width_in_mbs * + mtx_enc_context->picture_height_in_mbs) / video->kick_size; + + mtx_enc_context->output_reconstructed = video->output_reconstructed; + + mtx_enc_context->vop_time_resolution = video->vop_time_resolution; + + mtx_enc_context->max_slices_per_picture = video->slices_per_picture; + + mtx_enc_context->is_interlaced = video->is_interlaced; + mtx_enc_context->top_field_first = video->top_field_first; + mtx_enc_context->arbitrary_so = video->arbitrary_so; + + mtx_enc_context->idr_period = video->idr_period; + mtx_enc_context->bframe_count = video->rc_params.bframes; + mtx_enc_context->hierarchical = (unsigned char)video->rc_params.hierarchical; + mtx_enc_context->intra_loop_cnt = video->intra_cnt; + mtx_enc_context->ref_spacing = video_params->ref_spacing; + + mtx_enc_context->debug_crcs = video_params->debug_crcs; + + mtx_enc_context->fw_num_pipes = enc->pipes_to_use; + mtx_enc_context->fw_first_pipe = enc->base_pipe; + mtx_enc_context->fw_last_pipe = enc->base_pipe + enc->pipes_to_use - 1; + mtx_enc_context->fw_pipes_to_use_flags = 0; + + flag = 0x1 << mtx_enc_context->fw_first_pipe; + /* Pipes used MUST be contiguous from the BasePipe offset */ + for (index = 0; index < mtx_enc_context->fw_num_pipes; index++, flag <<= 1) + mtx_enc_context->fw_pipes_to_use_flags |= flag; + + mtx_enc_context->format = video_params->format; + + /* copy scaler values to context in case we need them later */ + video->enable_scaler = video_params->enable_scaler; + video->crop_left = video_params->crop_left; + video->crop_right = video_params->crop_right; + video->crop_top = video_params->crop_top; + video->crop_bottom = video_params->crop_bottom; + video->source_width = video_params->source_width; + video->source_frame_height = video_params->source_frame_height; + video->intra_pred_modes = video_params->intra_pred_modes; + + topaz_setup_input_format(video, &mtx_enc_context->scaler_setup); + topaz_setup_input_csc(video, &mtx_enc_context->scaler_setup, &mtx_enc_context->csc_setup, + video_params->csc_preset); + + mtx_enc_context->enable_mvc = video->enable_mvc; + mtx_enc_context->mvc_view_idx = video->mvc_view_idx; + + if (video->standard == IMG_STANDARD_H264) + mtx_enc_context->no_sequence_headers = video->no_sequence_headers; + + mtx_enc_context->coded_header_per_slice = video->coded_header_per_slice; + + packed_strides = topaz_get_packed_buffer_strides + (video->buffer_stride_bytes, video->format, video_params->enable_scaler, + video_params->is_interlaced, video_params->is_interleaved); + + mtx_enc_context->pic_row_stride_bytes = + F_ENCODE(F_DECODE(packed_strides, MTX_MSG_PICMGMT_STRIDE_Y), + TOPAZHP_CR_CUR_PIC_LUMA_STRIDE) | + F_ENCODE(F_DECODE(packed_strides, MTX_MSG_PICMGMT_STRIDE_UV), + TOPAZHP_CR_CUR_PIC_CHROMA_STRIDE); + + mtx_enc_context->rc_mode = video->rc_params.rc_mode; + if (mtx_enc_context->rc_mode == IMG_RCMODE_VCM) { + mtx_enc_context->rc_vcm_mode = video->rc_params.rc_vcm_mode; + mtx_enc_context->rc_cfs_max_margin_perc = video->rc_params.rc_cfs_max_margin_perc; + } + + mtx_enc_context->disable_bit_stuffing = (unsigned char)video_params->disable_bit_stuffing; + + mtx_enc_context->first_pic = TRUE; + + /*Content Adaptive Rate Control Parameters*/ + if (video_params->carc) { + mtx_enc_context->jmcomp_rc_reg0 = + F_ENCODE(video_params->carc_pos_range, TOPAZHP_CR_CARC_POS_RANGE) | + F_ENCODE(video_params->carc_pos_scale, TOPAZHP_CR_CARC_POS_SCALE) | + F_ENCODE(video_params->carc_neg_range, TOPAZHP_CR_CARC_NEG_RANGE) | + F_ENCODE(video_params->carc_neg_scale, TOPAZHP_CR_CARC_NEG_SCALE); + + mtx_enc_context->jmcomp_rc_reg1 = + F_ENCODE(video_params->carc_threshold, TOPAZHP_CR_CARC_THRESHOLD) | + F_ENCODE(video_params->carc_cutoff, TOPAZHP_CR_CARC_CUTOFF) | + F_ENCODE(video_params->carc_shift, TOPAZHP_CR_CARC_SHIFT); + } else { + mtx_enc_context->jmcomp_rc_reg0 = 0; + mtx_enc_context->jmcomp_rc_reg1 = 0; + } + + mtx_enc_context->mv_clip_config = + F_ENCODE(video_params->no_offscreen_mv, TOPAZHP_CR_MVCALC_RESTRICT_PICTURE); + + mtx_enc_context->lritc_cache_chunk_config = 0; + + mtx_enc_context->ipcm_0_config = + F_ENCODE(enc->video->cabac_bin_flex, TOPAZ_VLC_CR_CABAC_BIN_FLEX) | + F_ENCODE(DEFAULT_CABAC_DB_MARGIN, TOPAZ_VLC_CR_CABAC_DB_MARGIN); + + bit_limit = 3100; + + mtx_enc_context->ipcm_1_config = F_ENCODE(bit_limit, TOPAZ_VLC_CR_IPCM_THRESHOLD) | + F_ENCODE(enc->video->cabac_bin_limit, TOPAZ_VLC_CR_CABAC_BIN_LIMIT); + + /* leave alone until high profile and constrained modes are defined. */ + mtx_enc_context->h264_comp_control = F_ENCODE((video->cabac_enabled ? 0 : 1), + TOPAZHP_CR_H264COMP_8X8_CAVLC); + mtx_enc_context->h264_comp_control |= + F_ENCODE(video_params->use_default_scaling_list ? 1 : 0, + TOPAZHP_CR_H264COMP_DEFAULT_SCALING_LIST); + mtx_enc_context->h264_comp_control |= F_ENCODE(video->h264_8x8_transform ? 1 : 0, + TOPAZHP_CR_H264COMP_8X8_TRANSFORM); + mtx_enc_context->h264_comp_control |= F_ENCODE(video->h264_intra_constrained ? 1 : 0, + TOPAZHP_CR_H264COMP_CONSTRAINED_INTRA); + + mtx_enc_context->mc_adaptive_rounding_disable = video_params->vp_adaptive_rounding_disable; + mtx_enc_context->h264_comp_control |= + F_ENCODE(mtx_enc_context->mc_adaptive_rounding_disable ? 0 : 1, + TOPAZHP_CR_H264COMP_ADAPT_ROUND_ENABLE); + + if (!mtx_enc_context->mc_adaptive_rounding_disable) + for (i = 0; i < 4; i++) + for (j = 0; j < AR_REG_SIZE; j++) + mtx_enc_context->mc_adaptive_rounding_offsets[j][i] = + video_params->vp_adaptive_rounding_offsets[j][i]; + + if (video->standard == IMG_STANDARD_H264) + mtx_enc_context->h264_comp_control |= + F_ENCODE(USE_VCM_HW_SUPPORT, TOPAZHP_CR_H264COMP_VIDEO_CONF_ENABLE); + + mtx_enc_context->h264_comp_control |= + F_ENCODE(video_params->use_custom_scaling_lists & 0x01 ? 1 : 0, + TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTRA_LUMA_ENABLE) | + F_ENCODE(video_params->use_custom_scaling_lists & 0x02 ? 1 : 0, + TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTRA_CB_ENABLE) | + F_ENCODE(video_params->use_custom_scaling_lists & 0x04 ? 1 : 0, + TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTRA_CR_ENABLE) | + F_ENCODE(video_params->use_custom_scaling_lists & 0x08 ? 1 : 0, + TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTER_LUMA_ENABLE) | + F_ENCODE(video_params->use_custom_scaling_lists & 0x10 ? 1 : 0, + TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTER_CB_ENABLE) | + F_ENCODE(video_params->use_custom_scaling_lists & 0x20 ? 1 : 0, + TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTER_CR_ENABLE) | + F_ENCODE(video_params->use_custom_scaling_lists & 0x40 ? 1 : 0, + TOPAZHP_CR_H264COMP_CUSTOM_QUANT_8X8_INTRA_LUMA_ENABLE) | + F_ENCODE(video_params->use_custom_scaling_lists & 0x80 ? 1 : 0, + TOPAZHP_CR_H264COMP_CUSTOM_QUANT_8X8_INTER_LUMA_ENABLE); + + mtx_enc_context->h264_comp_control |= + F_ENCODE(video_params->enable_lossless ? 1 : 0, TOPAZHP_CR_H264COMP_LOSSLESS) | + F_ENCODE(video_params->lossless_8x8_prefilter ? + TOPAZHP_CR_H264COMP_LOSSLESS_8X8_PREFILTER_BYPASS : + TOPAZHP_CR_H264COMP_LOSSLESS_8X8_PREFILTER_FILTER, + TOPAZHP_CR_H264COMP_LOSSLESS_8X8_PREFILTER); + + mtx_enc_context->h264_comp_intra_pred_modes = 0x3ffff;// leave at default for now. + + if (video->intra_pred_modes != 0) + mtx_enc_context->h264_comp_intra_pred_modes = video->intra_pred_modes; + + mtx_enc_context->pred_comb_control = video->pred_comb_control; + + mtx_enc_context->skip_coded_inter_intra = + F_ENCODE(video->inter_intra_index, TOPAZHP_CR_INTER_INTRA_SCALE_IDX) | + F_ENCODE(video->coded_skipped_index, TOPAZHP_CR_SKIPPED_CODED_SCALE_IDX); + + if (video->enable_inp_ctrl) { + mtx_enc_context->mb_host_ctrl = + F_ENCODE(video->enable_host_qp, TOPAZHP_CR_MB_HOST_QP) | + F_ENCODE(video->enable_host_bias, TOPAZHP_CR_MB_HOST_SKIPPED_CODED_SCALE) | + F_ENCODE(video->enable_host_bias, TOPAZHP_CR_MB_HOST_INTER_INTRA_SCALE); + mtx_enc_context->pred_comb_control |= F_ENCODE(1, + TOPAZHP_CR_INTER_INTRA_SCALE_ENABLE) + | F_ENCODE(1, TOPAZHP_CR_SKIPPED_CODED_SCALE_ENABLE); + } + + if (video_params->enable_cumulative_biases) + mtx_enc_context->pred_comb_control |= + F_ENCODE(1, TOPAZHP_CR_CUMULATIVE_BIASES_ENABLE); + + mtx_enc_context->pred_comb_control |= + F_ENCODE((((video->inter_intra_index == 3) && (video->coded_skipped_index == 3)) + ? 0 : 1), TOPAZHP_CR_INTER_INTRA_SCALE_ENABLE) | + F_ENCODE((video->coded_skipped_index == 3 ? 0 : 1), + TOPAZHP_CR_SKIPPED_CODED_SCALE_ENABLE); + + mtx_enc_context->deblock_ctrl = + F_ENCODE(video->deblock_idc, TOPAZ_DB_CR_DISABLE_DEBLOCK_IDC); + + /* Set up VLC Control Register */ + mtx_enc_context->vlc_control = 0; + + switch (video->standard) { + case IMG_STANDARD_H264: + /* 1 for H.264 note this is inconsistent with the sequencer value */ + mtx_enc_context->vlc_control |= F_ENCODE(1, TOPAZ_VLC_CR_CODEC); + mtx_enc_context->vlc_control |= F_ENCODE(0, TOPAZ_VLC_CR_CODEC_EXTEND); + break; + + default: + break; + } + + if (video->cabac_enabled) + /* 2 for Mpeg4 note this is inconsistent with the sequencer value */ + mtx_enc_context->vlc_control |= F_ENCODE(1, TOPAZ_VLC_CR_CABAC_ENABLE); + + mtx_enc_context->vlc_control |= F_ENCODE(video->is_interlaced ? 1 : 0, + TOPAZ_VLC_CR_VLC_FIELD_CODED); + mtx_enc_context->vlc_control |= F_ENCODE(video->h264_8x8_transform ? 1 : 0, + TOPAZ_VLC_CR_VLC_8X8_TRANSFORM); + mtx_enc_context->vlc_control |= F_ENCODE(video->h264_intra_constrained ? 1 : 0, + TOPAZ_VLC_CR_VLC_CONSTRAINED_INTRA); + + mtx_enc_context->vlc_slice_control = F_ENCODE(video->rc_params.slice_byte_limit, + TOPAZ_VLC_CR_SLICE_SIZE_LIMIT); + mtx_enc_context->vlc_slice_mb_control = F_ENCODE(video->rc_params.slice_mb_limit, + TOPAZ_VLC_CR_SLICE_MBS_LIMIT); + + switch (video->standard) { + case IMG_STANDARD_H264: + vert_mv_limit = 255; /* default to no clipping */ + if (video->vert_mv_limit) + vert_mv_limit = enc->video->vert_mv_limit; + + /* as topaz can only cope with at most 255 (in the register field) */ + vert_mv_limit = min(255U, vert_mv_limit); + mtx_enc_context->ipe_vector_clipping = + F_ENCODE(1, TOPAZHP_CR_IPE_VECTOR_CLIPPING_ENABLED) | + F_ENCODE(255, TOPAZHP_CR_IPE_VECTOR_CLIPPING_X) | + F_ENCODE(vert_mv_limit, TOPAZHP_CR_IPE_VECTOR_CLIPPING_Y); + + mtx_enc_context->spe_mvd_clip_range = F_ENCODE(0, TOPAZHP_CR_SPE_MVD_CLIP_ENABLE); + break; + default: + break; + } + + /* Update MV Scaling settings: IDR */ + memcpy(&mtx_enc_context->mv_settings_idr, &video->mv_settings_idr, + sizeof(struct img_mv_settings)); + + /* NonB (I or P) */ + for (i = 0; i <= MAX_BFRAMES; i++) + memcpy(&mtx_enc_context->mv_settings_non_b[i], &video->mv_settings_non_b[i], + sizeof(struct img_mv_settings)); + + /* WEIGHTED PREDICTION */ + mtx_enc_context->weighted_prediction_enabled = video_params->weighted_prediction; + mtx_enc_context->mtx_weighted_implicit_bi_pred = video_params->vp_weighted_implicit_bi_pred; + + /* SEI_INSERTION */ + mtx_enc_context->insert_hrd_params = video_params->insert_hrd_params; + if (mtx_enc_context->insert_hrd_params & enc->video->rc_params.bits_per_second) + /* HRD parameters are meaningless without a bitrate */ + mtx_enc_context->insert_hrd_params = FALSE; + + if (mtx_enc_context->insert_hrd_params) { + mtx_enc_context->clock_div_bitrate = (90000 * 0x100000000LL); + mtx_enc_context->clock_div_bitrate /= enc->video->rc_params.bits_per_second; + mtx_enc_context->max_buffer_mult_clock_div_bitrate = + (unsigned int)(((unsigned long long)(video->rc_params.buffer_size) * + 90000ULL) / + (unsigned long long)enc->video->rc_params.bits_per_second); + } + + memcpy(&mtx_enc_context->in_params, &video->pic_params.in_params, + sizeof(struct in_rc_params)); + + mtx_enc_context->lritc_cache_chunk_config = + F_ENCODE(enc->video->chunks_per_mb, + TOPAZHP_CR_CACHE_CHUNKS_PER_MB) + | F_ENCODE(enc->video->max_chunks, TOPAZHP_CR_CACHE_CHUNKS_MAX) + | F_ENCODE(enc->video->max_chunks - enc->video->priority_chunks, + TOPAZHP_CR_CACHE_CHUNKS_PRIORITY); + + mtx_enc_context->first_pic_flags = video->first_pic_flags; + mtx_enc_context->non_first_pic_flags = video->non_first_pic_flags; + + mtx_enc_context->slice_header_slot_num = -1; + + memset(mtx_enc_context->pic_on_level, 0, sizeof(mtx_enc_context->pic_on_level)); + + gop_structure = (unsigned short *)(video->flat_gop_struct.cpu_virt); + + mini_gop_generate_flat(gop_structure, mtx_enc_context->bframe_count, + mtx_enc_context->ref_spacing, mtx_enc_context->pic_on_level); + topaz_update_device_mem(str_ctx->vxe_ctx, &video->flat_gop_struct); + + if (video->rc_params.hierarchical) { + memset(mtx_enc_context->pic_on_level, 0, sizeof(mtx_enc_context->pic_on_level)); + gop_structure = (unsigned short *)(video->hierar_gop_struct.cpu_virt); + + mini_gop_generate_hierarchical(gop_structure, mtx_enc_context->bframe_count, + mtx_enc_context->ref_spacing, + mtx_enc_context->pic_on_level); + topaz_update_device_mem(str_ctx->vxe_ctx, &video->hierar_gop_struct); + } + + topaz_update_device_mem(str_ctx->vxe_ctx, &video->mtx_enc_ctx_mem); + + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->mv_settings_b_table - + (unsigned char *)mtx_enc_context), + &video->mv_settings_btable, 0); + + if (video->rc_params.hierarchical) + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->mv_settings_hierarchical - + (unsigned char *)mtx_enc_context), + &video->mv_settings_hierarchical, 0); + + for (i = 0; i < video->pic_nodes; i++) { + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->reconstructed[i] - + (unsigned char *)mtx_enc_context), + &video->recon_pictures[i], 0); + + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->colocated[i] - + (unsigned char *)mtx_enc_context), + &video->colocated[i], 0); + } + + for (i = 0; i < WB_FIFO_SIZE; i++) + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->writeback_regions[i] - + (unsigned char *)mtx_enc_context), + &global_wb_data_info[i], 0); + + for (i = 0; i < video->mv_stores; i++) + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *) + &mtx_enc_context->mv[i] - (unsigned char *)mtx_enc_context), + &video->mv[i], 0); + + if (video->enable_mvc) { + for (i = 0; i < 2; i++) + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->inter_view_mv[i] - + (unsigned char *)mtx_enc_context), + &video->inter_view_mv[i], 0); + } + + for (i = 0; i < (int)max_cores; i++) + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->above_params[i] - + (unsigned char *)mtx_enc_context), + &video->above_params[i], 0); + + /* SEI insertion */ + if (video_params->insert_hrd_params) { + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *) + &mtx_enc_context->sei_buffering_period_template - + (unsigned char *)mtx_enc_context), + &video->sei_buffering_period_header_mem, 0); + + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *) + &mtx_enc_context->sei_picture_timing_template - + (unsigned char *)mtx_enc_context), + &video->sei_picture_timing_header_mem, 0); + } + + for (i = 0; i < ARRAY_SIZE(video->slice_params_template_mem); i++) + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *) + &mtx_enc_context->slice_params_templates[i] - + (unsigned char *)mtx_enc_context), + &video->slice_params_template_mem[i], 0); + + for (i = 0; i < video->slots_in_use; i++) { + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->slice_map[i] - + (unsigned char *)mtx_enc_context), + &video->slice_map[i].mem_info, 0); + + /* WEIGHTED PREDICTION */ + if (video_params->weighted_prediction || + video_params->vp_weighted_implicit_bi_pred == WBI_EXPLICIT) { + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *) + &mtx_enc_context->weighted_prediction_virt_addr[i] - + (unsigned char *)mtx_enc_context), + &video->weighted_prediction_mem[i], 0); + } + } + + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->flat_gop_struct - + (unsigned char *)mtx_enc_context), &video->flat_gop_struct, 0); + + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->flat_gop_struct - + (unsigned char *)mtx_enc_context), + &video->flat_gop_struct, 0); + + for (i = 0; i < video->slots_in_use; i++) { + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->ltref_header[i] - + (unsigned char *)mtx_enc_context), + &video->ltref_header[i], 0); + } + + if (mtx_enc_context->hierarchical) + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->hierar_gop_struct - + (unsigned char *)mtx_enc_context), + &video->hierar_gop_struct, 0); + + for (i = 0; i < ARRAY_SIZE(video->pichdr_template_mem); i++) + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->pichdr_templates[i] - + (unsigned char *)mtx_enc_context), + &video->pichdr_template_mem[i], 0); + + if (video->standard == IMG_STANDARD_H264) { + populate_firmware_message(mtx_enc_context_mem, (unsigned int)((unsigned char *) + &mtx_enc_context->seq_header - (unsigned char *)mtx_enc_context), + &video->seq_header_mem, 0); + + if (video->enable_mvc) + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->subset_seq_header - + (unsigned char *)mtx_enc_context), + &video->subset_seq_header_mem, 0); + } + + /* Store the feedback memory address for all "5" slots in the context */ + if (video->enable_sel_stats_flags & ESF_FIRST_STAGE_STATS) { + for (i = 0; i < video->slots_in_use; i++) + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *) + &mtx_enc_context->firstpass_out_param_addr[i] - + (unsigned char *)mtx_enc_context), + &video->firstpass_out_param_buf[i].mem_info, 0); + } + + /* Store the feedback memory address for all "5" slots in the context */ + if (video->enable_sel_stats_flags & ESF_MP_BEST_MB_DECISION_STATS || + video->enable_sel_stats_flags & ESF_MP_BEST_MOTION_VECTOR_STATS) { + for (i = 0; i < video->slots_in_use; i++) { + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *) + &mtx_enc_context->firstpass_out_best_multipass_param_addr[i] - + (unsigned char *)mtx_enc_context), + &video->firstpass_out_best_multipass_param_buf[i].mem_info, 0); + } + } + + /* Store the MB-Input control parameter memory for all the 5-slots in the context */ + if (video->enable_inp_ctrl) { + for (i = 0; i < video->slots_in_use; i++) + populate_firmware_message + (mtx_enc_context_mem, + (unsigned int)((unsigned char *)&mtx_enc_context->mb_ctrl_in_params_addr[i] - + (unsigned char *)mtx_enc_context), + &video->mb_ctrl_in_params_buf[i].mem_info, 0); + } + + topaz_update_device_mem(str_ctx->vxe_ctx, &video->mtx_enc_ctx_mem); + + return IMG_SUCCESS; +} + +/* + * Prepares the header templates for the encode for H.264 + */ +static int h264_prepare_templates(struct topaz_stream_context *str_ctx, + struct img_rc_params *rc_params, + int fine_y_search_size) +{ + struct img_enc_context *enc; + struct img_video_context *video_ctx; + struct pic_params *pic_params; + + enc = str_ctx->enc_ctx; + video_ctx = enc->video; + + prepare_mv_estimates(enc); + + pic_params = &enc->video->pic_params; + + pic_params->flags = 0; + + if (rc_params->rc_enable) { + pic_params->flags |= ISRC_FLAGS; + setup_rc_data(enc->video, pic_params, rc_params); + } else { + pic_params->in_params.se_init_qp_i = rc_params->initial_qp_i; + pic_params->in_params.mb_per_row = (enc->video->width >> 4); + pic_params->in_params.mb_per_bu = rc_params->bu_size; + pic_params->in_params.mb_per_frm = ((unsigned int)(enc->video->width >> 4)) * + (enc->video->frame_height >> 4); + pic_params->in_params.bu_per_frm = (pic_params->in_params.mb_per_frm) / + rc_params->bu_size; + } + + /* Prepare Slice header templates */ + generate_slice_params_template(enc, &enc->video->slice_params_template_mem[IMG_FRAME_IDR], + IMG_FRAME_IDR, enc->video->is_interlaced, + fine_y_search_size); + topaz_update_device_mem(str_ctx->vxe_ctx, &enc->video->slice_params_template_mem + [IMG_FRAME_IDR]); + + generate_slice_params_template(enc, &enc->video->slice_params_template_mem[IMG_FRAME_INTRA], + IMG_FRAME_INTRA, enc->video->is_interlaced, + fine_y_search_size); + topaz_update_device_mem(str_ctx->vxe_ctx, &enc->video->slice_params_template_mem + [IMG_FRAME_INTRA]); + + generate_slice_params_template(enc, + &enc->video->slice_params_template_mem[IMG_FRAME_INTER_P], + IMG_FRAME_INTER_P, enc->video->is_interlaced, + fine_y_search_size); + topaz_update_device_mem(str_ctx->vxe_ctx, &enc->video->slice_params_template_mem + [IMG_FRAME_INTER_P]); + + generate_slice_params_template(enc, &enc->video->slice_params_template_mem + [IMG_FRAME_INTER_B], + IMG_FRAME_INTER_B, enc->video->is_interlaced, + fine_y_search_size); + topaz_update_device_mem(str_ctx->vxe_ctx, &enc->video->slice_params_template_mem + [IMG_FRAME_INTER_B]); + + if (video_ctx->enable_mvc) { + generate_slice_params_template(enc, &enc->video->slice_params_template_mem + [IMG_FRAME_INTER_P_IDR], + IMG_FRAME_INTER_P_IDR, enc->video->is_interlaced, fine_y_search_size); + topaz_update_device_mem(str_ctx->vxe_ctx, &enc->video->slice_params_template_mem + [IMG_FRAME_INTER_P_IDR]); + } + + /* Prepare Pic Params Templates */ + adjust_pic_flags(enc, rc_params, TRUE, &video_ctx->first_pic_flags); + adjust_pic_flags(enc, rc_params, FALSE, &video_ctx->non_first_pic_flags); + + return IMG_SUCCESS; +} + +/* + * Prepares the header templates for the encode. + */ +static int topaz_video_prepare_templates(struct topaz_stream_context *str_ctx, + unsigned char search_range, + int fine_y_search_size) +{ + struct img_enc_context *enc = str_ctx->enc_ctx; + struct img_video_context *video = enc->video; + int err_value = IMG_ERROR_UNEXPECTED_STATE; + + switch (video->standard) { + case IMG_STANDARD_H264: + err_value = h264_prepare_templates(str_ctx, &video->rc_params, fine_y_search_size); + break; + default: + break; + } + + return err_value; +} + +/* + * Prepare the sequence header for h.264 + */ +int topaz_h264_prepare_sequence_header(void *topaz_str_ctx, unsigned int mb_width, + unsigned int mb_height, + unsigned char vui_params_present, + struct h264_vui_params *params, + struct h264_crop_params *crop_params, + struct h264_sequence_header_params *sh_params, + unsigned char mvc_sps) +{ + struct mtx_header_params *seq_header; + struct img_enc_context *enc; + struct topaz_stream_context *str_ctx; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + + enc = str_ctx->enc_ctx; + + /* Ensure parameters are consistent with context */ + if (!enc->video->custom_scaling) + sh_params->seq_scaling_matrix_present_flag = FALSE; + + /* Get a pointer to the memory the header will be written to */ + seq_header = (struct mtx_header_params *)(enc->video->seq_header_mem.cpu_virt); + h264_prepare_sequence_header(seq_header, mb_width, mb_height, vui_params_present, + params, crop_params, sh_params, enc->video->arbitrary_so); + + topaz_update_device_mem(str_ctx->vxe_ctx, &enc->video->seq_header_mem); + + if (mvc_sps) { + /* prepare subset sequence parameter header */ + struct mtx_header_params *subset_seq_header; + + subset_seq_header = + (struct mtx_header_params *)(enc->video->subset_seq_header_mem.cpu_virt); + h264_prepare_mvc_sequence_header(subset_seq_header, mb_width, mb_height, + vui_params_present, params, crop_params, + sh_params); + topaz_update_device_mem(str_ctx->vxe_ctx, &enc->video->subset_seq_header_mem); + } + + return IMG_SUCCESS; +} + +/* + * Prepare the picture header for h.264 + */ +int topaz_h264_prepare_picture_header(void *topaz_str_ctx, signed char cqp_offset) +{ + struct mtx_header_params *pic_header; + struct topaz_stream_context *str_ctx; + struct img_enc_context *enc; + unsigned char dep_view_pps = FALSE; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + enc = str_ctx->enc_ctx; + + /* Get a pointer to the memory the header will be written to */ + pic_header = (struct mtx_header_params *)(enc->video->pichdr_template_mem[0].cpu_virt); + + if (enc->video->enable_mvc && enc->video->mvc_view_idx != 0 && + (enc->video->mvc_view_idx != (unsigned short)(NON_MVC_VIEW))) + dep_view_pps = TRUE; + + h264_prepare_picture_header(pic_header, enc->video->cabac_enabled, + enc->video->h264_8x8_transform, + enc->video->h264_intra_constrained, + cqp_offset, enc->video->weighted_prediction, + enc->video->weighted_bi_pred, + dep_view_pps, enc->video->pps_scaling, + enc->video->pps_scaling && enc->video->custom_scaling); + + topaz_update_device_mem(str_ctx->vxe_ctx, &enc->video->pichdr_template_mem[0]); + + return IMG_SUCCESS; +} + +/* + * Prepare the AUD header for H264 + */ +int topaz_h264_prepare_aud_header(void *str_context) +{ + struct mtx_header_params *aud_header; + struct img_enc_context *enc; + struct topaz_stream_context *str_ctx; + + str_ctx = (struct topaz_stream_context *)str_context; + if (!str_ctx) + return IMG_ERROR_INVALID_PARAMETERS; + + enc = str_ctx->enc_ctx; + + /* Get a pointer to the memory the header will be written to */ + aud_header = (struct mtx_header_params *)(&enc->video->aud_header_mem); + + h264_prepare_aud_header(aud_header); + + topaz_update_device_mem(str_ctx->vxe_ctx, &enc->video->aud_header_mem); + + return IMG_SUCCESS; +} + +static unsigned int topaz_get_max_coded_data_size(enum img_standard standard, unsigned short width, + unsigned short height, unsigned int initial_qp_i) +{ + unsigned int worst_qp_size; + + if (standard == IMG_STANDARD_H264) { + /* allocate based on worst case qp size */ + worst_qp_size = 400; + return ((unsigned int)(width / 16) * (unsigned int)(height / 16) * worst_qp_size); + } + + if (initial_qp_i <= 5) + return ((unsigned int)width * (unsigned int)height * 1600) / (16 * 16); + + return ((unsigned int)width * (unsigned int)height * 900) / (16 * 16); +} + +static int topaz_get_context_coded_buffer_size(struct img_enc_context *enc, + struct img_rc_params *rc_params, + unsigned int *coded_buffer_size) +{ + struct img_video_context *video; + + video = enc->video; + + *coded_buffer_size = topaz_get_max_coded_data_size(video->standard, video->width, + video->picture_height, + rc_params->initial_qp_i); + + if (!video->disable_bit_stuffing && rc_params->rc_mode == IMG_RCMODE_CBR) + *coded_buffer_size = max(*coded_buffer_size, + ((rc_params->bits_per_second + rc_params->frame_rate / 2) / + rc_params->frame_rate) * 2); + + if (video->coded_header_per_slice) + *coded_buffer_size += CODED_BUFFER_INFO_SECTION_SIZE * video->slices_per_picture; + else + *coded_buffer_size += CODED_BUFFER_INFO_SECTION_SIZE; + /* Ensure coded buffer sizes are always aligned to 1024 */ + *coded_buffer_size = ALIGN_1024(*coded_buffer_size); + + return IMG_SUCCESS; +} + +/* + * Description: Allocate a coded package + */ +static int topaz_allocate_coded_package(struct topaz_stream_context *str_ctx, + unsigned int coded_buffersize_bytes, + struct coded_package_host **package) +{ + struct coded_package_host *this_package; + struct img_video_context *video = str_ctx->enc_ctx->video; + + *package = kzalloc(sizeof(*package), GFP_KERNEL); + + this_package = *package; + + if (!this_package) + return IMG_ERROR_OUT_OF_MEMORY; + + this_package->busy = 0; + + this_package->num_coded_buffers = 1; + + /* Allocate FW Buffer IMG_BUFFER memory */ + this_package->mtx_info.code_package_fw_buffer = + kzalloc(sizeof(struct img_buffer), GFP_KERNEL); + + if (!this_package->mtx_info.code_package_fw_buffer) + goto error_handling; + + /* Allocate header IMG_BUFFER memory */ + this_package->header_buffer = kzalloc(sizeof(*this_package->header_buffer), GFP_KERNEL); + + if (!this_package->header_buffer) + goto error_handling; + + /* Allocate the FW Package (this will provide addresses + * of header and the coded buffer array) + */ + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + sizeof(struct coded_package_dma_info), 64, + &this_package->mtx_info.code_package_fw_buffer->mem_info)) + goto error_handling; + + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE), + (video->coded_header_per_slice ? video->slices_per_picture : 1) * + CODED_BUFFER_INFO_SECTION_SIZE, + 64, &this_package->header_buffer->mem_info)) + goto error_handling; + + this_package->header_buffer->size = + (video->coded_header_per_slice ? video->slices_per_picture : 1) * + CODED_BUFFER_INFO_SECTION_SIZE; + + return IMG_SUCCESS; + +error_handling: + if (*package) { + kfree(*package); + *package = NULL; + } + + if (this_package->mtx_info.code_package_fw_buffer) { + if (this_package->mtx_info.code_package_fw_buffer->mem_info.dev_virt) + topaz_mmu_stream_free + (str_ctx->mmu_ctx, + &this_package->mtx_info.code_package_fw_buffer->mem_info); + + kfree(this_package->mtx_info.code_package_fw_buffer); + this_package->mtx_info.code_package_fw_buffer = NULL; + } + + kfree(this_package->header_buffer); + this_package->header_buffer = NULL; + + return IMG_ERROR_OUT_OF_MEMORY; +} + +/* + * Create the Video Encoder context + */ +static int topaz_video_create_context(struct topaz_stream_context *str_ctx, + struct img_video_params *video_params, + struct img_rc_params *rc_params) +{ + struct img_enc_context *enc; + struct img_video_context *video; + unsigned int alloc_size; + int index, i; + unsigned short picture_height; + unsigned int coded_buffer_size; + unsigned short width_in_mbs; + unsigned short frame_height_in_mbs; + unsigned char pipes_to_use; + unsigned int max_cores; + unsigned int min_slice_height; + unsigned int factor = 1; + unsigned int kick_size, kicks_per_bu; + int ret; + + max_cores = topazdd_get_num_pipes(str_ctx->core_ctx->dev_handle); + + enc = str_ctx->enc_ctx; + + picture_height = + ((video_params->frame_height >> (video_params->is_interlaced ? 1 : 0)) + 15) & ~15; + width_in_mbs = (video_params->width + 15) >> 4; + frame_height_in_mbs = ((picture_height + 15) >> 4) << + (video_params->is_interlaced ? 1 : 0); + + if (topaz_get_encoder_caps(video_params->standard, video_params->width, picture_height, + &enc->caps) != IMG_SUCCESS) { + pr_err("\nERROR: Unable to encode the size %dx%d with current hardware version\n\n", + video_params->width, picture_height); + return IMG_ERROR_NOT_SUPPORTED; + } + + /*scaler input W/H limit is 4K*/ + if (video_params->source_width > 4096) { + pr_err("\nERROR: Source Width is bigger than the maximum supported Source Width(4096)\n"); + return IMG_ERROR_NOT_SUPPORTED; + } + + if (video_params->source_frame_height > 4096) { + pr_err("\nERROR: Source Height is bigger than the maximum supported Source Height(4096)\n"); + return IMG_ERROR_NOT_SUPPORTED; + } + + if (video_params->width > enc->caps.max_width) { + pr_err("\n ERROR: Width too big for given core revision 0x%x. Maximum width is %d.\n", + enc->caps.core_revision, enc->caps.max_width); + return IMG_ERROR_NOT_SUPPORTED; + } + + if (picture_height > enc->caps.max_height) { + pr_err("\n ERROR: Height too big for given core revision 0x%x. Maximum height is %d.\n", + enc->caps.core_revision, enc->caps.max_height); + return IMG_ERROR_NOT_SUPPORTED; + } + + if (video_params->width < enc->caps.min_width) { + pr_err("\n ERROR: Width too small for given core revision 0x%x. Minimum width is %d.\n", + enc->caps.core_revision, enc->caps.min_width); + return IMG_ERROR_NOT_SUPPORTED; + } + + if (video_params->standard == IMG_STANDARD_H264) { + if (video_params->slices_per_picture < enc->caps.min_slices) { + pr_err("WARNING: Minimum slices supported for this resolution is %d. Increasing slices per frame to %d\n", + enc->caps.min_slices, video_params->slices_per_picture); + video_params->slices_per_picture = (unsigned char)enc->caps.min_slices; + } + factor = min(enc->pipes_to_use, video_params->slices_per_picture); + } + + if (video_params->standard == IMG_STANDARD_H264) + pipes_to_use = min(enc->pipes_to_use, video_params->slices_per_picture); + else + pipes_to_use = 1; + + if (picture_height < (enc->caps.min_height * factor)) { + pr_err("\n ERROR: Height too small for given core revision 0x%x. Minimum height is %d.\n", + enc->caps.core_revision, enc->caps.min_height * factor); + return IMG_ERROR_NOT_SUPPORTED; + } + + if ((unsigned int)((width_in_mbs) * (picture_height >> 4)) > enc->caps.max_mb_num) { + pr_err("\n ERROR: Number of macroblocks too high. It should not be bigger than %d.\n", + enc->caps.max_mb_num); + return IMG_ERROR_NOT_SUPPORTED; + } + + calculate_kick_and_bu_size(width_in_mbs, picture_height / 16, video_params->is_interlaced, + enc->caps.max_bu_per_frame, &kick_size, &kicks_per_bu, + &min_slice_height); + + if (enc->caps.min_slice_height > min_slice_height) + min_slice_height = enc->caps.min_slice_height; + + if ((unsigned int)(video_params->slices_per_picture * min_slice_height) > + (unsigned int)(picture_height / 16)) { + /* we have too many slices for this resolution */ + pr_err("\n ERROR: Too many slices for this resolution.\n"); + return IMG_ERROR_NOT_SUPPORTED; + } + + video = kzalloc(sizeof(*video), GFP_KERNEL); + if (!video) + return IMG_ERROR_OUT_OF_MEMORY; + + enc->video = video; + + memcpy(&video->rc_params, rc_params, sizeof(*rc_params)); + + /* Setup BU size for rate control */ + video->rc_params.bu_size = kick_size * kicks_per_bu; + rc_params->bu_size = video->rc_params.bu_size; + + video->kick_size = kick_size; + video->kicks_per_bu = kicks_per_bu; + + video->debug_crcs = video_params->debug_crcs; + + /* stream level params */ + video->standard = video_params->standard; + video->format = video_params->format; + video->csc_preset = video_params->csc_preset; + video->width = width_in_mbs << 4; + video->frame_height = frame_height_in_mbs << 4; + video->unrounded_width = video_params->width; + video->unrounded_frame_height = video_params->frame_height; + + video->picture_height = picture_height; + video->is_interlaced = video_params->is_interlaced; + video->is_interleaved = video_params->is_interleaved; + video->top_field_first = !(video_params->bottom_field_first); + video->encode_requested = 0; + video->limit_num_vectors = video_params->limit_num_vectors; + video->disable_bit_stuffing = video_params->disable_bit_stuffing; + video->vert_mv_limit = video_params->vert_mv_limit; + /* Cabac Parameters */ + video->cabac_enabled = video_params->cabac_enabled; + video->cabac_bin_limit = video_params->cabac_bin_limit; + video->cabac_bin_flex = video_params->cabac_bin_flex; + + video->frame_count = 0; + video->flush_at_frame = 0; + video->flushed_at_frame = 0; + video->encoder_idle = TRUE; + video->high_latency = video_params->high_latency; + video->slices_per_picture = (unsigned char)video_params->slices_per_picture; + video->deblock_idc = video_params->deblock_idc; + video->output_reconstructed = video_params->output_reconstructed; + video->arbitrary_so = video_params->arbitrary_so; + video->f_code = video_params->f_code; + + /* Default f_code is 4 */ + if (!video->f_code) + video->f_code = 4; + + video->vop_time_resolution = video_params->vop_time_resolution; + video->frames_encoded = 0; + video->idr_period = video_params->idr_period; + + video->intra_cnt = video_params->intra_cnt; + video->multi_reference_p = video_params->multi_reference_p; + video->spatial_direct = video_params->spatial_direct; + video->enable_sel_stats_flags = video_params->enable_sel_stats_flags; + video->enable_inp_ctrl = video_params->enable_inp_ctrl; + video->enable_host_bias = video_params->enable_host_bias; + video->enable_host_qp = video_params->enable_host_qp; + /* Line counter */ + video->line_counter = video_params->line_counter_enabled; + + video->enable_air = video_params->enable_air; + video->num_air_mbs = video_params->num_air_mbs; + video->air_threshold = video_params->air_threshold; + video->air_skip_cnt = video_params->air_skip_cnt; + + video->extra_wb_retrieved = 0; + video->highest_storage_number = 0; + + video->buffer_stride_bytes = calculate_stride(video_params->format, + video_params->buffer_stride_bytes, + video_params->source_width); + video->buffer_height = ((video_params->buffer_height ? video_params->buffer_height : + video_params->source_frame_height)); + + if (!video_params->disable_bh_rounding) + video->buffer_height = + (((video->buffer_height >> (video_params->is_interlaced ? 1 : 0)) + 15) & + ~15) << (video_params->is_interlaced ? 1 : 0); + + video_params->buffer_stride_bytes = video->buffer_stride_bytes; + video_params->buffer_height = video->buffer_height; + + video->next_recon = 0; + + video->enable_mvc = video_params->enable_mvc; + video->mvc_view_idx = video_params->mvc_view_idx; + + enc->pipes_to_use = pipes_to_use; + + enc->requested_pipes_to_use = pipes_to_use; + video->slots_in_use = rc_params->bframes + 2; + enc->video->slots_required = enc->video->slots_in_use; + + video->h264_8x8_transform = video_params->h264_8x8; + video->h264_intra_constrained = video_params->constrained_intra; + video->custom_scaling = (video_params->use_custom_scaling_lists != 0); + video->pps_scaling = + (video_params->pps_scaling && + (video_params->use_default_scaling_list || video->custom_scaling)); + + video->encode_pic_processing = 0; + video->next_slice = 0; + video->ref_frame = NULL; + + /* create topaz device context */ + ret = topazdd_create_stream_context(global_topaz_core_context->dev_handle, + str_ctx->enc_ctx->codec, + handle_encoder_firmware_response, str_ctx, + &str_ctx->enc_ctx->video->dd_str_ctx, + &global_wb_data_info); + + if (ret != IMG_SUCCESS) + return ret; + + ret = topazdd_setup_stream_ctx + (str_ctx->enc_ctx->video->dd_str_ctx, video->frame_height, + video->width, (unsigned char *)&video->dd_ctx_num, &video->dd_ctx_num); + + if (ret != IMG_SUCCESS) + return ret; + + /* Create MMU stream context */ + ret = topaz_mmu_stream_create(&global_topaz_core_context->dev_handle->topaz_mmu_ctx, + 0x1 /*stream_id*/, str_ctx->vxe_ctx, &str_ctx->mmu_ctx); + if (ret) + return ret; + + /* WEIGHTED PREDICTION */ + if (video_params->weighted_prediction || + video_params->vp_weighted_implicit_bi_pred == WBI_EXPLICIT) { + video->weighted_prediction = TRUE; + + for (i = 0; i < video->slots_in_use; i++) { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + sizeof(struct weighted_prediction_values), 64, + &video->weighted_prediction_mem[i])) + IMG_DBG_ASSERT("Allocation failed (A)" == NULL); + } + } else { + video->weighted_prediction = FALSE; + } + + video->weighted_bi_pred = video_params->vp_weighted_implicit_bi_pred; + + video->coded_skipped_index = video_params->coded_skipped_index; + video->inter_intra_index = video_params->inter_intra_index; + + /* + * patch video parameters is the user has specified a profile + * calculate the number of macroblocks per second + */ + video->mbps = width_in_mbs * frame_height_in_mbs * video->rc_params.frame_rate; + + patch_hw_profile(video_params, video); + + enc->auto_expand_pipes = video_params->auto_expand_pipes; + + /* As ui32Vp8RefStructMode is not in use the worst case + * would have to be taken and hence 5 pic nodes + */ + video->pic_nodes = (rc_params->hierarchical ? MAX_REF_B_LEVELS : 0) + + video_params->ref_spacing + 4; + video->mv_stores = (video->pic_nodes * 2); + + /* We're using a common MACRO here so we can guarantee the same calculation + * when managing buffers either from host or within drivers + */ + video->coded_package_max_num = CALC_NUM_CODED_PACKAGES_ENCODE + (video_params->slice_level, + video_params->slices_per_picture, pipes_to_use, + video->is_interlaced); + + alloc_size = MVEA_ABOVE_PARAM_REGION_SIZE * (ALIGN_64(width_in_mbs)); + + for (index = 0; index < (int)max_cores; index++) { + if (str_ctx->vxe_ctx->above_mb_params_sgt[index].sgl) { + video->above_params[index].buf_size = alloc_size; + + topaz_mmu_stream_map_ext_sg + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, + &str_ctx->vxe_ctx->above_mb_params_sgt[index], + video->above_params[index].buf_size, + 64, (enum sys_emem_attrib)0, video->above_params[index].cpu_virt, + &video->above_params[index], + &video->above_params[index].buff_id); + } else { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + ALIGN_64(alloc_size), 64, &video->above_params[index])) + IMG_DBG_ASSERT("Allocation failed (C)" == NULL); + } + } + + alloc_size = MVEA_MV_PARAM_REGION_SIZE * ALIGN_4(width_in_mbs) * frame_height_in_mbs; + + for (index = 0; index < video->pic_nodes; index++) { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + alloc_size, 64, &video->colocated[index])) + IMG_DBG_ASSERT("Allocation failed (D)" == NULL); + } + + alloc_size = (ALIGN_64(video->width)) * (ALIGN_64(video->frame_height)) * 3 / 2; + + for (index = 0; index < video->pic_nodes; index++) { + void *data; + + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + alloc_size, 256, &video->recon_pictures[index])) + IMG_DBG_ASSERT("Allocation failed (E)" == NULL); + + data = video->recon_pictures[index].cpu_virt; + memset(data, 0, alloc_size); + + topaz_update_device_mem(str_ctx->vxe_ctx, &video->recon_pictures[index]); + } + + video->patched_recon_buffer = NULL; + + alloc_size = MVEA_MV_PARAM_REGION_SIZE * ALIGN_4(width_in_mbs) * frame_height_in_mbs; + for (i = 0; i < video->mv_stores; i++) { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + alloc_size, 64, &video->mv[i])) + IMG_DBG_ASSERT("Allocation failed (F)" == NULL); + topaz_update_device_mem(str_ctx->vxe_ctx, &video->mv[i]); + } + + if (video->enable_mvc) { + for (i = 0; i < 2; i++) { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + alloc_size, 64, &video->inter_view_mv[i])) + IMG_DBG_ASSERT("Allocation failed (G)" == NULL); + } + } + + /* memory for encoder context */ + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + ALIGN_64(MTX_CONTEXT_SIZE), 64, &video->mtx_enc_ctx_mem)) + IMG_DBG_ASSERT("Allocation failed (H)" == NULL); + + video->no_sequence_headers = video_params->no_sequence_headers; + video->auto_encode = video_params->auto_encode; + video->slice_level = video_params->slice_level; + video->coded_header_per_slice = video_params->coded_header_per_slice; + + /* partially coded headers supplied to HW */ + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + MAX_HEADERSIZEBYTES, 64, &video->seq_header_mem)) + IMG_DBG_ASSERT("Allocation failed (I)\n" == NULL); + + /* partially coded subset sequence parameter headers supplied to HW */ + if (video->enable_mvc) { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + MAX_HEADERSIZEBYTES, 64, &video->subset_seq_header_mem)) + IMG_DBG_ASSERT("Allocation failed (J)" == NULL); + } + + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + MAX_BFRAMES * MV_ROW_STRIDE, 64, &video->mv_settings_btable)) + + IMG_DBG_ASSERT("Allocation failed (K)" == NULL); + + if (video->rc_params.hierarchical) { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + MAX_BFRAMES * sizeof(struct img_mv_settings), 64, + &video->mv_settings_hierarchical)) + IMG_DBG_ASSERT("Allocation failed (L)" == NULL); + } else { + video->mv_settings_hierarchical.cpu_virt = NULL; + } + + video->insert_hrd_params = video_params->insert_hrd_params; + if (video_params->insert_hrd_params) { + alloc_size = 64; + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + alloc_size, 64, &video->aud_header_mem)) + IMG_DBG_ASSERT("Allocation failed (M)" == NULL); + + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + alloc_size, 64, &video->sei_buffering_period_header_mem)) + IMG_DBG_ASSERT("Allocation failed (N)" == NULL); + + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + alloc_size, 64, &video->sei_picture_timing_header_mem)) + IMG_DBG_ASSERT("Allocation failed (O)" == NULL); + } + + for (index = 0; index < ARRAY_SIZE(video->pichdr_template_mem); index++) { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + MAX_HEADERSIZEBYTES, 64, &video->pichdr_template_mem[index])) + IMG_DBG_ASSERT("Allocation failed (P)" == NULL); + } + + for (index = 0; index < ARRAY_SIZE(video->slice_params_template_mem); index++) { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + ALIGN_64(sizeof(struct slice_params)), 64, + &video->slice_params_template_mem[index])) + IMG_DBG_ASSERT("Allocation failed (Q)" == NULL); + } + + for (index = 0; index < video->slots_in_use; index++) { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + ALIGN_64(sizeof(struct mtx_header_params)), 64, + &video->ltref_header[index])) + IMG_DBG_ASSERT("Allocation failed (R)" == NULL); + } + + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE), + ALIGN_64(4), 64, &video->src_phys_addr)) + IMG_DBG_ASSERT("Allocation failed (S)" == NULL); + + for (index = 0; index < video->slots_in_use; index++) { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + (1 + MAX_SLICESPERPIC * 2 + 15) & ~15, 64, + &video->slice_map[index].mem_info) != IMG_SUCCESS) + IMG_DBG_ASSERT("Allocation failed (T)" == NULL); + } + + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE), + ALIGN_64(sizeof(unsigned short) * MAX_GOP_SIZE), 64, &video->flat_gop_struct)) + IMG_DBG_ASSERT("Allocation failed (U)" == NULL); + + if (video->rc_params.hierarchical) { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + ALIGN_64(sizeof(unsigned short) * MAX_GOP_SIZE), 64, + &video->hierar_gop_struct)) + IMG_DBG_ASSERT("Allocation failed (V)" == NULL); + } + + if (video->custom_scaling) { + for (index = 0; index < 2; index++) { + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + ALIGN_64(QUANT_LISTS_SIZE), 64, &video->custom_quant[index])) + IMG_DBG_ASSERT("Allocation failed (W)" == NULL); + + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + 192, 64, &video->custom_quant_regs4x4_sp[index])) + IMG_DBG_ASSERT("Allocation failed (X)" == NULL); + + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + 128 * CUSTOM_QUANT_PARAMSIZE_8x8, 64, + &video->custom_quant_regs8x8_sp[index])) + IMG_DBG_ASSERT("Allocation failed (Y)" == NULL); + + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + 128, 64, &video->custom_quant_regs4x4_q[index])) + IMG_DBG_ASSERT("Allocation failed (Z)" == NULL); + + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + 64 * CUSTOM_QUANT_PARAMSIZE_8x8, 64, + &video->custom_quant_regs8x8_q[index])) + IMG_DBG_ASSERT("Allocation failed (0)" == NULL); + } + video->custom_quant_slot = 0; + } + + /* Allocate device memory for storing feedback information for all "5" slots */ + if (video->enable_sel_stats_flags & ESF_FIRST_STAGE_STATS) { + for (index = 0; index < video->slots_in_use; index++) { + unsigned int row_size = + ALIGN_64(width_in_mbs * sizeof(struct img_first_stage_mb_params)); + + /* Allocate memory padding size of each row to be multiple of 64-bytes */ + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + frame_height_in_mbs * row_size, 64, + &video->firstpass_out_param_buf[index].mem_info)) + IMG_DBG_ASSERT("Allocation failed (1)" == NULL); + + video->firstpass_out_param_buf[index].lock = BUFFER_FREE; + video->firstpass_out_param_buf[index].bytes_written = 0; + video->firstpass_out_param_buf[index].size = + frame_height_in_mbs * row_size; + } + } else { + /* Set buffer pointers to NULL */ + for (index = 0; index < video->slots_in_use; index++) { + video->firstpass_out_param_buf[index].mem_info.cpu_virt = NULL; + video->firstpass_out_param_buf[index].lock = BUFFER_FREE; + video->firstpass_out_param_buf[index].bytes_written = 0; + video->firstpass_out_param_buf[index].size = 0; + } + } + + /* Allocate device memory for storing feedback information for all "5" slots */ + if (video->enable_sel_stats_flags & ESF_MP_BEST_MB_DECISION_STATS || + video->enable_sel_stats_flags & ESF_MP_BEST_MOTION_VECTOR_STATS) { + for (index = 0; index < video->slots_in_use; index++) { + unsigned int best_multipass_size = frame_height_in_mbs * + //From TRM (4.5.2) + (((5 * width_in_mbs) + 3) >> 2) * 64; + + /* Allocate memory padding size of each row to be multiple of 64-bytes */ + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), + best_multipass_size, 64, + &video->firstpass_out_best_multipass_param_buf[index].mem_info)) + IMG_DBG_ASSERT("Allocation failed (2)" == NULL); + + video->firstpass_out_best_multipass_param_buf[index].lock = + BUFFER_FREE; + video->firstpass_out_best_multipass_param_buf[index].bytes_written = 0; + video->firstpass_out_best_multipass_param_buf[index].size = + best_multipass_size; + } + } else { + /* Set buffer pointers to NULL */ + for (index = 0; index < video->slots_in_use; index++) { + video->firstpass_out_best_multipass_param_buf[index].mem_info.cpu_virt = + NULL; + video->firstpass_out_best_multipass_param_buf[index].lock = + BUFFER_FREE; + video->firstpass_out_best_multipass_param_buf[index].bytes_written = 0; + video->firstpass_out_best_multipass_param_buf[index].size = 0; + } + } + + if (video->enable_inp_ctrl) { + for (index = 0; index < video->slots_in_use; index++) { + alloc_size = frame_height_in_mbs * width_in_mbs * 2; + + /* + * Allocate memory for worst case slice structure + * i.e. assume number-of-slices == number-of-rows + */ + if (topaz_mmu_stream_alloc + (str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | + SYS_MEMATTRIB_WRITECOMBINE), alloc_size + 64, 64, + &video->mb_ctrl_in_params_buf[index].mem_info)) + IMG_DBG_ASSERT("Allocation failed (3)" == NULL); + + video->mb_ctrl_in_params_buf[index].lock = BUFFER_FREE; + video->mb_ctrl_in_params_buf[index].bytes_written = 0; + video->mb_ctrl_in_params_buf[index].size = alloc_size; + } + } else { + for (index = 0; index < video->slots_in_use; index++) { + video->mb_ctrl_in_params_buf[index].mem_info.cpu_virt = NULL; + video->mb_ctrl_in_params_buf[index].lock = BUFFER_FREE; + video->mb_ctrl_in_params_buf[index].bytes_written = 0; + video->mb_ctrl_in_params_buf[index].size = 0; + } + } + + for (index = 0; index < video->slots_in_use; index++) + video->source_slot_buff[index] = NULL; + + /* Allocate coded package */ + topaz_get_context_coded_buffer_size(enc, rc_params, &coded_buffer_size); + + video->coded_buffer_max_size = coded_buffer_size; + + for (i = 0; i < video->coded_package_max_num; i++) { + if (topaz_allocate_coded_package(str_ctx, coded_buffer_size, + &video->coded_package[i]) != IMG_SUCCESS) + IMG_DBG_ASSERT("Coded package Allocation failed\n" == NULL); + } + + video->encode_sent = 0; + + topaz_video_prepare_templates(str_ctx, video_params->f_code, + video_params->fine_y_search_size); + + enc->video->max_chunks = video_params->max_chunks; + enc->video->chunks_per_mb = video_params->chunks_per_mb; + enc->video->priority_chunks = video_params->priority_chunks; + + return topaz_video_create_mtx_context(str_ctx, video_params); +} + +unsigned char topaz_validate_params(struct img_video_params *video_params, + struct img_rc_params *rc_params) +{ + unsigned char modified = FALSE; + unsigned int required_core_des1 = 0; + unsigned int core_des1 = topazdd_get_core_des1(); + + if (video_params) { + /* Validate video params */ + if (video_params->standard == IMG_STANDARD_H264) { + if (video_params->is_interlaced) { + if ((core_des1 & + F_ENCODE + (1, TOPAZHP_TOP_CR_TOPAZHP_H264_INTERLACED_SUPPORTED)) == 0) { + video_params->is_interlaced = FALSE; + + if (!video_params->is_interleaved) { + /* Non-interleaved source. + * Encode field pictures as frames. + */ + video_params->frame_height >>= 1; + video_params->buffer_height >>= 1; + video_params->source_frame_height >>= 1; + } else { + /* Interleaved source. Unite fields into single picture. */ + video_params->is_interleaved = FALSE; + } + + video_params->bottom_field_first = FALSE; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_H264_INTERLACED_SUPPORTED); + } + } + + if (video_params->h264_8x8) { + if ((core_des1 & + F_ENCODE(1, TOPAZHP_TOP_CR_TOPAZHP_H264_8X8_TRANSFORM_SUPPORTED)) == + 0) { + video_params->h264_8x8 = FALSE; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_H264_8X8_TRANSFORM_SUPPORTED); + } + } + + if (video_params->cabac_enabled) { + if ((core_des1 & + F_ENCODE + (1, TOPAZHP_TOP_CR_TOPAZHP_H264_CABAC_SUPPORTED)) == 0) { + video_params->cabac_enabled = FALSE; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_H264_CABAC_SUPPORTED); + } + } + + if (!video_params->enc_features.disable_bframes) { + if ((core_des1 & + F_ENCODE + (1, TOPAZHP_TOP_CR_TOPAZHP_H264_B_PIC_SUPPORTED)) == 0) { + video_params->enc_features.disable_bframes = FALSE; + modified = TRUE; + } + } + + if (video_params->enable_sel_stats_flags) { + if ((core_des1 & + F_ENCODE + (1, TOPAZHP_TOP_CR_TOPAZHP_H264_MULTIPASS_SUPPORTED)) == 0) { + video_params->enable_sel_stats_flags = 0; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_H264_MULTIPASS_SUPPORTED); + } + } + + if (video_params->use_default_scaling_list) { + if ((core_des1 & + F_ENCODE + (1, TOPAZHP_TOP_CR_TOPAZHP_H264_DEFAULT_TABLES_SUPPORTED)) == + 0) { + video_params->use_default_scaling_list = FALSE; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_H264_DEFAULT_TABLES_SUPPORTED); + } + } + + if (video_params->use_custom_scaling_lists) { + if ((core_des1 & + F_ENCODE + (1, TOPAZHP_TOP_CR_TOPAZHP_H264_CUSTOM_QUANT_SUPPORTED)) == 0) { + video_params->use_custom_scaling_lists = 0; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_H264_CUSTOM_QUANT_SUPPORTED); + } + } + + if ((video_params->weighted_prediction || + video_params->vp_weighted_implicit_bi_pred)) { + if ((core_des1 & + F_ENCODE + (1, TOPAZHP_TOP_CR_TOPAZHP_H264_WEIGHTED_PRED_SUPPORTED)) == + 0) { + video_params->weighted_prediction = FALSE; + video_params->vp_weighted_implicit_bi_pred = 0; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_H264_WEIGHTED_PRED_SUPPORTED); + } + } + + if (video_params->multi_reference_p || video_params->enable_mvc) { + if ((core_des1 & + F_ENCODE + (1, TOPAZHP_TOP_CR_TOPAZHP_H264_2_REF_ON_P_PIC_SUPPORTED)) == + 0) { + video_params->multi_reference_p = FALSE; + video_params->enable_mvc = FALSE; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_H264_2_REF_ON_P_PIC_SUPPORTED); + } + } + + if (video_params->spatial_direct) { + if ((core_des1 & + F_ENCODE + (1, + TOPAZHP_TOP_CR_TOPAZHP_H264_SPATIAL_DIRECT_SUPPORTED)) == + 0) { + video_params->spatial_direct = FALSE; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_H264_SPATIAL_DIRECT_SUPPORTED); + } + } + + if (video_params->enable_lossless) { + if ((core_des1 & + F_ENCODE + (1, TOPAZHP_TOP_CR_TOPAZHP_H264_LOSSLESS_SUPPORTED)) == 0) { + video_params->enable_lossless = FALSE; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_H264_LOSSLESS_SUPPORTED); + } + } + } + + if (video_params->enable_scaler) { + if ((core_des1 & + F_ENCODE(1, TOPAZHP_TOP_CR_TOPAZHP_SCALER_SUPPORTED)) == 0) { + video_params->enable_scaler = FALSE; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_SCALER_SUPPORTED); + } + } + + if (rc_params) { + /* Validate RC params */ + if (video_params->standard == IMG_STANDARD_H264) { + if (rc_params->bframes) { + if ((core_des1 & + F_ENCODE + (1, TOPAZHP_TOP_CR_TOPAZHP_H264_B_PIC_SUPPORTED)) == + 0) { + rc_params->bframes = 0; + rc_params->hierarchical = FALSE; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_H264_B_PIC_SUPPORTED); + } + } + + if (rc_params->hierarchical && rc_params->bframes > 1) { + if ((core_des1 & + F_ENCODE + (1, TOPAZHP_TOP_CR_TOPAZHP_H264_SPATIAL_DIRECT_SUPPORTED)) + == 0) { + rc_params->hierarchical = FALSE; + modified = TRUE; + } else { + required_core_des1 |= F_ENCODE(1, + TOPAZHP_TOP_CR_TOPAZHP_H264_SPATIAL_DIRECT_SUPPORTED); + } + } + } + } + } + + return modified; +} + +/* + * Creat an encoder context + */ +int topaz_stream_create(void *vxe_ctx, struct img_video_params *video_params, + unsigned char base_pipe, unsigned char pipes_to_use, + struct img_rc_params *rc_params, void **topaz_str_context) +{ + struct img_enc_context *enc; + struct topaz_stream_context *str_ctx; + + if (!is_topaz_core_initialized) + return IMG_ERROR_NOT_INITIALISED; + + str_ctx = kzalloc(sizeof(*str_ctx), GFP_KERNEL); + if (!str_ctx) + return IMG_ERROR_OUT_OF_MEMORY; + + enc = kzalloc(sizeof(*enc), GFP_KERNEL); + if (!enc) { + kfree(str_ctx); + return IMG_ERROR_OUT_OF_MEMORY; + } + + *topaz_str_context = str_ctx; + str_ctx->enc_ctx = enc; + str_ctx->core_ctx = global_topaz_core_context; + str_ctx->vxe_ctx = (struct vxe_enc_ctx *)vxe_ctx; + + enc->core_rev = topazdd_get_core_rev(); + enc->sync_first_pass = true; + + enc->requested_base_pipe = base_pipe; + enc->base_pipe = base_pipe; + enc->requested_pipes_to_use = pipes_to_use; + enc->pipes_to_use = pipes_to_use; + + topaz_validate_params(video_params, rc_params); + + switch (video_params->standard) { + case IMG_STANDARD_H264: + if (video_params->enable_mvc) { + switch (rc_params->rc_mode) { + case IMG_RCMODE_NONE: + enc->codec = IMG_CODEC_H264MVC_NO_RC; + break; + case IMG_RCMODE_CBR: + enc->codec = IMG_CODEC_H264MVC_CBR; + break; + case IMG_RCMODE_VBR: + enc->codec = IMG_CODEC_H264MVC_VBR; + break; + case IMG_RCMODE_ERC: + enc->codec = IMG_CODEC_H264MVC_ERC; + break; + case IMG_RCMODE_VCM: + IMG_DBG_ASSERT("VCM mode is not supported for MVC" == NULL); + break; + default: + break; + } + } else { + switch (rc_params->rc_mode) { + case IMG_RCMODE_NONE: + enc->codec = IMG_CODEC_H264_NO_RC; + break; + case IMG_RCMODE_CBR: + enc->codec = IMG_CODEC_H264_CBR; + break; + case IMG_RCMODE_VBR: + enc->codec = IMG_CODEC_H264_VBR; + break; + case IMG_RCMODE_VCM: + enc->codec = IMG_CODEC_H264_VCM; + break; + case IMG_RCMODE_ERC: + enc->codec = IMG_CODEC_H264_ERC; + break; + default: + break; + } + } + break; + default: + IMG_DBG_ASSERT("Only H264 encode is supported" == NULL); + } + + /* initialise video context structure */ + return (topaz_video_create_context(str_ctx, video_params, rc_params)); +} + +/* + * Sends a command to the specified core. + * The function returns a writeback value. This is a unique value that will be + * written back by the target core after it completes its command. + */ +unsigned int topaz_insert_command(struct img_enc_context *enc_ctx, + enum mtx_cmd_id cmd_id, unsigned int data) +{ + unsigned int writeback_val; + + if (enc_ctx->debug_settings && + enc_ctx->debug_settings->serialized_communication_mode == + VXE_SERIALIZED_MODE_SERIAL) + /* in serial mode do not use the priority bit */ + cmd_id &= ~MTX_CMDID_PRIORITY; + + topazdd_send_msg(enc_ctx->video->dd_str_ctx, cmd_id, data, NULL, &writeback_val); + + return writeback_val; +} + +/* + * Sends a command to the specified core. + */ +unsigned int topaz_insert_command_with_sync(struct img_enc_context *enc_ctx, + enum mtx_cmd_id cmd_id, unsigned int data) +{ + int ret; + + if (enc_ctx->debug_settings && + enc_ctx->debug_settings->serialized_communication_mode == + VXE_SERIALIZED_MODE_SERIAL) + /* in serial mode do not use the priority bit */ + cmd_id &= ~MTX_CMDID_PRIORITY; + + ret = topazdd_send_msg_with_sync(enc_ctx->video->dd_str_ctx, cmd_id, data, NULL); + + return ret; +} + +/* + * Sends a command to the specified core. + * The data specified in psCommandData will be read via DMA by the MTX, + * so this memory must remain in scope for the duration of the execution + * of the command. + * The function returns a writeback value. This is a unique value that will be + * written back by the target core after it completes its command. + */ +unsigned int topaz_insert_mem_command(struct img_enc_context *enc_ctx, + enum mtx_cmd_id cmd_id, + unsigned int data, + struct vidio_ddbufinfo *command_data) +{ + unsigned int writeback_val; + + /* Priority bit is not supported for MEM commands */ + cmd_id &= ~MTX_CMDID_PRIORITY; + + topazdd_send_msg(enc_ctx->video->dd_str_ctx, cmd_id, data, command_data, &writeback_val); + + return writeback_val; +} + +/* + * Sends a command to the specified core. + * The data specified in psCommandData will be read via DMA by the MTX, + * so this memory must remain in scope for the duration of the execution + * of the command. + */ +unsigned int topaz_insert_mem_command_with_sync(struct img_enc_context *enc_ctx, + enum mtx_cmd_id cmd_id, + unsigned int data, + struct vidio_ddbufinfo *command_data) +{ + int ret; + + /* Priority bit is not supported for MEM commands */ + cmd_id &= ~MTX_CMDID_PRIORITY; + + ret = topazdd_send_msg_with_sync(enc_ctx->video->dd_str_ctx, cmd_id, + data, command_data); + return ret; +} + +/* + * Send the Access Unit Delimiter to the stream + */ +static int topaz_send_aud_header(struct img_enc_context *enc) +{ + if (enc->video->aborted) + return IMG_ERROR_UNDEFINED; + + /* must use unique writeback word */ + topaz_insert_mem_command(enc, MTX_CMDID_DO_HEADER, 0, + enc->video->aud_header_mem.cpu_virt); + + return IMG_SUCCESS; +} + +/* + * Transmit the picture headerts to MTX + */ +static int topaz_send_picture_headers(struct img_enc_context *enc) +{ + /* send Seqence headers only for IDR (I-frames) and only once in the beginning */ + struct img_video_context *video = enc->video; + + /* SEI_INSERTION */ + if (video->insert_hrd_params) { + /* Access unit delimiter */ + if (!video->enable_mvc || (video->enable_mvc && video->mvc_view_idx == 0)) + /* in case of MVC, both views are a single access unit. + * delimiter should be inserted by view 0 only. + */ + topaz_send_aud_header(enc); + } + + if (video->insert_seq_header && !video->no_sequence_headers) { + switch (video->standard) { + case IMG_STANDARD_H264: + IMG_DBG_ASSERT("SPS and PPS will be send from firmware." != NULL); + break; + default: + IMG_DBG_ASSERT("only H264 encode is supported." == NULL); + break; + } + } + + return IMG_SUCCESS; +} + +/* + * Encode a frame + */ +int topaz_encode_frame(void *topaz_str_ctx) +{ + struct img_enc_context *enc; + struct img_video_context *video; + struct topaz_stream_context *str_ctx; + /* If line counter is enabled, we add one more bit in the command data + * to inform the firmware context whether it should proceed + */ + unsigned int encode_cmd_data; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + + enc = str_ctx->enc_ctx; + video = enc->video; + + if (video->aborted) + return IMG_ERROR_UNEXPECTED_STATE; + + video->insert_seq_header = (video->encode_sent == 0); + + topaz_send_picture_headers(enc); + + encode_cmd_data = F_ENCODE(1, MTX_MSG_ENCODE_CODED_INTERRUPT); + + if (video->line_counter) + /* Set bit 20 to 1 to inform FW that we are using the line counter feature */ + encode_cmd_data |= F_ENCODE(1, MTX_MSG_ENCODE_USE_LINE_COUNTER); + + topaz_insert_command(enc, (enum mtx_cmd_id) + (MTX_CMDID_ENCODE_FRAME | MTX_CMDID_WB_INTERRUPT), + encode_cmd_data); + + video->encode_pic_processing++; + video->encode_sent++; + + return IMG_SUCCESS; +} + +int topaz_get_pipe_usage(unsigned char pipe, unsigned char *ctx_id) +{ + IMG_DBG_ASSERT(pipe < TOPAZHP_MAX_NUM_PIPES); + + if (pipe >= TOPAZHP_MAX_NUM_PIPES) + return 0; + + return global_pipe_usage[pipe]; +} + +void topaz_set_pipe_usage(unsigned char pipe, unsigned char val) +{ + IMG_DBG_ASSERT(pipe < TOPAZHP_MAX_NUM_PIPES); + + if (pipe < TOPAZHP_MAX_NUM_PIPES) + global_pipe_usage[pipe] = val; +} + +/* + * Set the mtx context to the one implicit in the encoder context + */ +static int topaz_video_setup_mtx_context(struct img_enc_context *enc) +{ + struct img_video_context *video_context; + unsigned char index; + + video_context = enc->video; + + for (index = 0; index < enc->pipes_to_use; index++) + topaz_set_pipe_usage(enc->base_pipe + index, enc->ctx_num); + + if (topaz_insert_mem_command_with_sync(enc, (enum mtx_cmd_id) + (MTX_CMDID_SETVIDEO | MTX_CMDID_WB_INTERRUPT), + enc->base_pipe, &video_context->mtx_enc_ctx_mem)) { + pr_err("topaz mtx context setup command failed\n"); + return IMG_ERROR_UNDEFINED; + } + + video_context->aborted = FALSE; + + return IMG_SUCCESS; +} + +/* + * Load the encoder and MTX context + */ +int topaz_load_context(void *topaz_str_ctx) +{ + struct topaz_stream_context *str_ctx; + struct img_enc_context *enc; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + enc = str_ctx->enc_ctx; + + enc->video->vid_ctx_num = 0; + + enc->ctx_num++; + + return topaz_video_setup_mtx_context(enc); +} + +/* + * Store the encoder and MTX context + */ +int topaz_store_context(void *topaz_str_ctx) +{ + struct img_enc_context *enc; + struct topaz_stream_context *str_ctx; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + enc = str_ctx->enc_ctx; + + /* Update Globals */ + if (enc->codec != IMG_CODEC_NONE && enc->codec != IMG_CODEC_JPEG) { + struct img_video_context *video_context; + + video_context = enc->video; + + if (!topaz_insert_mem_command_with_sync(enc, (enum mtx_cmd_id) + (MTX_CMDID_GETVIDEO | + MTX_CMDID_WB_INTERRUPT), + enc->base_pipe, &video_context->mtx_enc_ctx_mem)) { + pr_err("MTX message for GETVIDEO failed\n"); + return IMG_ERROR_UNDEFINED; + } + } + + return IMG_SUCCESS; +} + +/* + * Flush video stream + */ +int topaz_flush_stream(void *topaz_str_ctx, unsigned int frame_cnt) +{ + struct topaz_stream_context *str_ctx; + struct img_enc_context *enc; + int index; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + + enc = str_ctx->enc_ctx; + + if (enc->video->aborted) + return IMG_ERROR_UNDEFINED; + + /* flush the internal queues */ + /* Check source slots */ + for (index = 0; index < enc->video->slots_in_use; index++) { + if (enc->video->source_slot_buff[index]) { + /* Found a valid src_frame, so signal callback for the same. */ + global_topaz_core_context->vxe_str_processed_cb(str_ctx->vxe_ctx, + VXE_CB_SRC_FRAME_RELEASE, + (void *)(enc->video->source_slot_buff[index]), + 0, 0, 0); + enc->video->source_slot_buff[index] = NULL; + } + } + + /* Check coded package slots */ + for (index = 0; index < enc->video->coded_package_max_num; index++) { + if (enc->video->coded_package[index]->busy) { + /* Found a valid coded package, so, signal callback for the same */ + global_topaz_core_context->vxe_str_processed_cb(str_ctx->vxe_ctx, + VXE_CB_CODED_BUFF_READY, + (void *)(enc->video->coded_package[index]->coded_buffer[0]), + 0, 0, 0); + enc->video->coded_package[index]->busy = FALSE; + } + } + + return IMG_SUCCESS; +} + +/* + * Destroy the Video Encoder context + */ +static int topaz_video_destroy_context(struct topaz_stream_context *str_ctx) +{ + struct img_enc_context *enc; + struct img_video_context *video; + int i; + unsigned int max_cores; + + max_cores = topazdd_get_num_pipes(str_ctx->core_ctx->dev_handle); + enc = str_ctx->enc_ctx; + video = enc->video; + + for (i = 0; i < enc->pipes_to_use; i++) + if (topaz_get_pipe_usage(enc->base_pipe + i, NULL) == enc->ctx_num) + topaz_set_pipe_usage(enc->base_pipe + i, 0); + + if (video->standard == IMG_STANDARD_H264 && video->weighted_prediction) { + for (i = 0; i < video->slots_in_use; i++) { + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, + &video->weighted_prediction_mem[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + } + } + + for (i = 0; i < video->coded_package_max_num; i++) { + if (topaz_mmu_stream_free + (str_ctx->mmu_ctx, + &video->coded_package[i]->mtx_info.code_package_fw_buffer->mem_info)) + IMG_DBG_ASSERT("Free failed" == NULL); + + kfree(video->coded_package[i]->mtx_info.code_package_fw_buffer); + video->coded_package[i]->mtx_info.code_package_fw_buffer = NULL; + + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, + &video->coded_package[i]->header_buffer->mem_info)) + IMG_DBG_ASSERT("Free failed" == NULL); + + kfree(video->coded_package[i]->header_buffer); + video->coded_package[i]->header_buffer = NULL; + + kfree(video->coded_package[i]); + video->coded_package[i] = NULL; + } + + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->flat_gop_struct)) + IMG_DBG_ASSERT("Free failed" == NULL); + + if (video->rc_params.hierarchical) + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->hierar_gop_struct)) + IMG_DBG_ASSERT("Free failed" == NULL); + + for (i = 0; i < video->slots_in_use; i++) { + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->slice_map[i].mem_info)) + IMG_DBG_ASSERT("slice map free failed" == NULL); + } + + for (i = 0; i < (int)max_cores; i++) { + if (str_ctx->vxe_ctx->above_mb_params_sgt[i].sgl) { + topaz_mmu_stream_free_sg(str_ctx->mmu_ctx, &video->above_params[i]); + } else { + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->above_params[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + } + } + + for (i = 0; i < video->pic_nodes; i++) + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->colocated[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + + for (i = 0; i < video->pic_nodes; i++) + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->recon_pictures[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + + for (i = 0; i < video->mv_stores; i++) + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->mv[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + + if (video->enable_mvc) { + for (i = 0; i < 2; i++) { + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->inter_view_mv[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + } + } + + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->mtx_enc_ctx_mem)) + IMG_DBG_ASSERT("Free failed" == NULL); + + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->mv_settings_btable)) + IMG_DBG_ASSERT("Free failed" == NULL); + + if (video->mv_settings_hierarchical.cpu_virt) + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->mv_settings_hierarchical)) + IMG_DBG_ASSERT("Free failed" == NULL); + + /* partially coded headers supplied to HW */ + /* SEI_INSERTION */ + if (video->insert_hrd_params) { + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->aud_header_mem)) + IMG_DBG_ASSERT("Free failed" == NULL); + + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, + &video->sei_buffering_period_header_mem)) + IMG_DBG_ASSERT("Free failed" == NULL); + + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->sei_picture_timing_header_mem)) + IMG_DBG_ASSERT("Free failed" == NULL); + } + + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->seq_header_mem)) + IMG_DBG_ASSERT("Free failed" == NULL); + + /* FREE subset sequence parameter header */ + if (video->enable_mvc) + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->subset_seq_header_mem)) + IMG_DBG_ASSERT("Free failed" == NULL); + + for (i = 0; i < ARRAY_SIZE(video->pichdr_template_mem); i++) { + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->pichdr_template_mem[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + } + + for (i = 0; i < ARRAY_SIZE(video->slice_params_template_mem); i++) { + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->slice_params_template_mem[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + } + + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->src_phys_addr)) + IMG_DBG_ASSERT("Free failed" == NULL); + + /* de-allocate memory corresponding to the output parameters */ + for (i = 0; i < video->slots_in_use; i++) { + if (video->firstpass_out_param_buf[i].mem_info.cpu_virt) + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, + &video->firstpass_out_param_buf[i].mem_info)) + IMG_DBG_ASSERT("Free failed" == NULL); + + if (video->mb_ctrl_in_params_buf[i].mem_info.cpu_virt) + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, + &video->mb_ctrl_in_params_buf[i].mem_info)) + IMG_DBG_ASSERT("Free failed" == NULL); + } + + /* de-allocate memory corresponding to the selectable best MV parameters */ + for (i = 0; i < video->slots_in_use; i++) { + if (video->firstpass_out_best_multipass_param_buf[i].mem_info.cpu_virt) + if (topaz_mmu_stream_free + (str_ctx->mmu_ctx, + &video->firstpass_out_best_multipass_param_buf[i].mem_info)) + IMG_DBG_ASSERT("Free failed" == NULL); + } + + for (i = 0; i < video->slots_in_use; i++) { + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->ltref_header[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + } + + if (video->custom_scaling) { + for (i = 0; i < 2; i++) { + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, &video->custom_quant[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, + &video->custom_quant_regs4x4_sp[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, + &video->custom_quant_regs8x8_sp[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, + &video->custom_quant_regs4x4_q[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + + if (topaz_mmu_stream_free(str_ctx->mmu_ctx, + &video->custom_quant_regs8x8_q[i])) + IMG_DBG_ASSERT("Free failed" == NULL); + } + } + + topazdd_destroy_stream_ctx(video->dd_str_ctx); + + topaz_mmu_stream_destroy(&global_topaz_core_context->dev_handle->topaz_mmu_ctx, + str_ctx->mmu_ctx); + + /* free the video encoder structure itself */ + kfree(video); + + return IMG_SUCCESS; +} + +/* + * Destroy an Encoder Context + */ +int topaz_stream_destroy(void *str_context) +{ + struct img_enc_context *enc; + struct topaz_stream_context *str_ctx; + int ret; + + str_ctx = (struct topaz_stream_context *)str_context; + if (!str_ctx) + return IMG_ERROR_INVALID_PARAMETERS; + + enc = str_ctx->enc_ctx; + + ret = topaz_video_destroy_context(str_ctx); + + kfree(enc->debug_settings); + enc->debug_settings = NULL; + + kfree(enc); + kfree(str_context); + + return ret; +} + +/* + * Get the capabilities of the encoder for the given codec + */ +int topaz_get_encoder_caps(enum img_standard standard, + unsigned short width, unsigned short height, + struct img_enc_caps *caps) +{ + unsigned int width_in_mbs, height_in_mbs, kick_size, kicks_per_bu, min_slice_height, mbs; + + /* get the actual number of cores */ + caps->num_cores = topazdd_get_num_pipes(global_topaz_core_context->dev_handle); + + if (caps->num_cores < 3) + caps->max_bu_per_frame = TOPAZHP_MAX_BU_SUPPORT_HD; + else + caps->max_bu_per_frame = TOPAZHP_MAX_BU_SUPPORT_4K; + + caps->core_features = topazdd_get_core_des1(); + caps->core_revision = topazdd_get_core_rev(); + + width_in_mbs = (width + 15) / 16; + height_in_mbs = (height + 15) / 16; + + switch (standard) { + case IMG_STANDARD_H264: + /* Assume progressive video for now as we don't know either way */ + calculate_kick_and_bu_size(width_in_mbs, height_in_mbs, FALSE, + caps->max_bu_per_frame, &kick_size, &kicks_per_bu, + &min_slice_height); + caps->max_slices = height_in_mbs / min_slice_height; + + /* + * Limit for number of MBs in slices is 32K-2 = 32766 + * Here we will limit it to 16K per slice = 16384 + */ + caps->min_slices = 1; + mbs = width_in_mbs * height_in_mbs; + if (mbs >= 32768) + caps->min_slices = 3; + else if (mbs >= 16384) + caps->min_slices = 2; + + /* if height is bigger or equal to 4000, use at least two slices */ + if (height_in_mbs >= 250 && caps->min_slices == 1) + caps->min_slices = 2; + + caps->recommended_slices = min(caps->num_cores, caps->max_slices); + caps->min_slice_height = min_slice_height; + + caps->max_height = 2048; + caps->max_width = 2048; + caps->min_height = 48; + caps->min_width = 144; + caps->max_mb_num = (2048 * 2048) >> 8; + break; + default: + IMG_DBG_ASSERT("Only H264 encoder is supported" == NULL); + } + + if (caps->recommended_slices < caps->min_slices) + caps->recommended_slices = caps->min_slices; + if (caps->recommended_slices > caps->max_slices) + caps->recommended_slices = caps->max_slices; + + return IMG_SUCCESS; +} + +/* + * Supply a source frame to the encode process + */ +int topaz_send_source_frame(void *topaz_str_ctx, struct img_frame *src_frame, + unsigned int frame_num, unsigned long long ctx) +{ + struct topaz_stream_context *str_ctx; + struct img_source_buffer_params *buffer_params; + + struct img_enc_context *enc; + struct img_video_context *video; + unsigned char slot_number; + void *data; + unsigned int y_plane_base = 0; + unsigned int u_plane_base = 0; + unsigned int v_plane_base = 0; + struct vidio_ddbufinfo *cmd_data_mem_info = NULL; + unsigned char *slice_map_addr = NULL; + unsigned char index; + unsigned char round; + unsigned char slice_number; + unsigned char first_bu_in_slice; + unsigned char size_in_bus; + unsigned int slice_height; + unsigned char halfway_slice; + unsigned int halfway_bu; + unsigned char slices_per_picture; + unsigned int picture_height_remaining; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + /* if source slot is NULL then it's just a next portion of slices */ + if (!src_frame) + return IMG_ERROR_UNEXPECTED_STATE; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + + enc = str_ctx->enc_ctx; + video = enc->video; + + if (video->aborted) + return IMG_ERROR_UNEXPECTED_STATE; + + slot_number = video->source_slot_reserved; + + /* mark the appropriate slot as filled */ + video->source_slot_buff[slot_number] = src_frame; + video->source_slot_poc[slot_number] = frame_num; + + topaz_get_cmd_data_buffer(&cmd_data_mem_info); + + if (!cmd_data_mem_info) + return IMG_ERROR_UNEXPECTED_STATE; + + data = cmd_data_mem_info->cpu_virt; + buffer_params = (struct img_source_buffer_params *)data; + + /* Prepare data */ + if (src_frame->y_plane_buffer) { + populate_firmware_message(&video->src_phys_addr, 0, + &src_frame->y_plane_buffer->mem_info, 0); + + data = video->src_phys_addr.cpu_virt; + y_plane_base = *((unsigned int *)data); + } + + if (src_frame->u_plane_buffer) { + populate_firmware_message(&video->src_phys_addr, 0, + &src_frame->u_plane_buffer->mem_info, 0); + + data = video->src_phys_addr.cpu_virt; + u_plane_base = *((unsigned int *)data); + } else { + u_plane_base = y_plane_base; + } + + if (src_frame->v_plane_buffer) { + populate_firmware_message(&video->src_phys_addr, 0, + &src_frame->v_plane_buffer->mem_info, 0); + + data = video->src_phys_addr.cpu_virt; + v_plane_base = *((unsigned int *)data); + } else { + v_plane_base = u_plane_base; + } + + buffer_params->slot_num = slot_number; + buffer_params->display_order_num = (unsigned char)(frame_num & 0xFF); + buffer_params->host_context = ctx; + + buffer_params->phys_addr_y_plane_field_0 = y_plane_base + src_frame->y_component_offset + + src_frame->field0_y_offset; + buffer_params->phys_addr_u_plane_field_0 = u_plane_base + src_frame->u_component_offset + + src_frame->field0_u_offset; + buffer_params->phys_addr_v_plane_field_0 = v_plane_base + src_frame->v_component_offset + + src_frame->field0_v_offset; + + buffer_params->phys_addr_y_plane_field_1 = y_plane_base + src_frame->y_component_offset + + src_frame->field1_y_offset; + buffer_params->phys_addr_u_plane_field_1 = u_plane_base + src_frame->u_component_offset + + src_frame->field1_u_offset; + buffer_params->phys_addr_v_plane_field_1 = v_plane_base + src_frame->v_component_offset + + src_frame->field1_v_offset; + + topaz_update_device_mem(str_ctx->vxe_ctx, cmd_data_mem_info); + + topaz_get_buffer(str_ctx, &video->slice_map[slot_number], (void **)&slice_map_addr, + FALSE); + + /* Fill standard Slice Map (non arbitrary) */ + halfway_bu = 0; + first_bu_in_slice = 0; + slice_number = 0; + slices_per_picture = video->slices_per_picture; + picture_height_remaining = video->picture_height; + halfway_slice = slices_per_picture / 2; + *slice_map_addr = slices_per_picture; + slice_map_addr++; + round = 16 * enc->caps.min_slice_height - 1; + + for (index = 0; index < slices_per_picture - 1; index++) { + if (index == halfway_slice) + halfway_bu = first_bu_in_slice; + + slice_height = (picture_height_remaining / (video->slices_per_picture - index)) & + ~round; + picture_height_remaining -= slice_height; + size_in_bus = ((slice_height / 16) * (video->width / 16)) / + video->rc_params.bu_size; + + /* slice number */ + *slice_map_addr = slice_number; + slice_map_addr++; + + /* SizeInKicks BU */ + *slice_map_addr = size_in_bus; + slice_map_addr++; + + slice_number++; + + first_bu_in_slice += (unsigned int)size_in_bus; + } + + slice_height = picture_height_remaining; + if (index == halfway_slice) + halfway_bu = first_bu_in_slice; + + /* round up for case where the last BU is smaller */ + size_in_bus = ((slice_height / 16) * (video->width / 16) + video->rc_params.bu_size - 1) / + video->rc_params.bu_size; + + /* slice number */ + *slice_map_addr = slice_number; + slice_map_addr++; + + /* last BU */ + *slice_map_addr = size_in_bus; + slice_map_addr++; + + topaz_release_buffer(str_ctx, &video->slice_map[slot_number], TRUE); + +#ifdef DEBUG_ENCODER_DRIVER + pr_info("\n\nAPI - IMG_V_SendSourceFrame - Sending a source slot %i to FW\n\n", + slot_number); +#endif + + /* Send command */ + topaz_insert_mem_command(enc, MTX_CMDID_PROVIDE_SOURCE_BUFFER, 0, cmd_data_mem_info); + + video->encode_requested++; + + return IMG_SUCCESS; +} + +/* + * Supply a header buffer and an optional number of coded data buffers as part of a package + */ +int topaz_send_coded_package(void *topaz_str_ctx, struct img_coded_buffer *coded_buffer) +{ + struct img_enc_context *enc; + struct img_video_context *video; + struct topaz_stream_context *str_ctx; + unsigned char coded_buffer_idx; + unsigned int *address = NULL; + struct coded_package_dma_info *this_coded_header_node; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + if (!coded_buffer) + return IMG_ERROR_INVALID_PARAMETERS; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + + enc = str_ctx->enc_ctx; + video = enc->video; + + if (video->aborted) + return IMG_ERROR_UNEXPECTED_STATE; + + video->coded_package[video->coded_package_slot_reserved]->coded_buffer[0] = coded_buffer; + +#ifdef DEBUG_ENCODER_DRIVER + pr_info("\n\nEncode Context [%i] sending coded package [%i]\n", enc->ctx_num, + video->coded_package_slot_reserved); +#endif + + /* Get the FW buffer */ + topaz_get_buffer + (str_ctx, + video->coded_package[video->coded_package_slot_reserved]->mtx_info.code_package_fw_buffer, + (void **)&address, FALSE); + + this_coded_header_node = + video->coded_package[video->coded_package_slot_reserved]->mtx_info.coded_package_fw = + (struct coded_package_dma_info *)address; + + this_coded_header_node->coded_buffer_info = + F_ENCODE + (video->coded_package[video->coded_package_slot_reserved]->num_coded_buffers, + MTX_MSG_NUM_CODED_BUFFERS_PER_HEADER); + + /* Inverted function: From host to MTX */ + populate_firmware_message(&(video->coded_package + [video->coded_package_slot_reserved]->mtx_info.code_package_fw_buffer->mem_info), + (unsigned char *)&this_coded_header_node->coded_header_addr - + (unsigned char *)this_coded_header_node, + (struct vidio_ddbufinfo *) + (&(video->coded_package[video->coded_package_slot_reserved]->header_buffer->mem_info + )), 0); + + /* Normal mode - An array of consecutive memory addresses */ + for (coded_buffer_idx = 0; coded_buffer_idx < + video->coded_package[video->coded_package_slot_reserved]->num_coded_buffers; + coded_buffer_idx++) { + if (video->coded_package[video->coded_package_slot_reserved]->coded_buffer + [coded_buffer_idx]) { + /* Write coded buffer memory address into the structure (host to MTX) */ + populate_firmware_message(&(video->coded_package + [video->coded_package_slot_reserved]->mtx_info.code_package_fw_buffer->mem_info), + (unsigned char *)&this_coded_header_node->coded_mem_addr[coded_buffer_idx] - + (unsigned char *)this_coded_header_node, (struct vidio_ddbufinfo *) + (&(video->coded_package + [video->coded_package_slot_reserved]->coded_buffer[coded_buffer_idx]->mem_info)), + 0); + } else { + this_coded_header_node->coded_mem_addr[coded_buffer_idx] = 0; + break; + } + } + + /* Release the FW buffer */ + topaz_release_buffer(str_ctx, video->coded_package + [video->coded_package_slot_reserved]->mtx_info.code_package_fw_buffer, TRUE); + + /* Send header buffers to the MTX */ + topaz_insert_mem_command(enc, (enum mtx_cmd_id)(MTX_CMDID_PROVIDE_CODEDPACKAGE_BUFFER | + MTX_CMDID_WB_INTERRUPT), + F_ENCODE(video->coded_package[video->coded_package_slot_reserved]->coded_buffer[0]->size >> + 10, MTX_MSG_PROVIDE_CODED_BUFFER_SIZE) | + F_ENCODE(video->coded_package_slot_reserved, MTX_MSG_PROVIDE_CODEDPACKAGE_BUFFER_SLOT), + &(video->coded_package + [video->coded_package_slot_reserved]->mtx_info.code_package_fw_buffer->mem_info)); + + return IMG_SUCCESS; +} + +unsigned int topaz_get_coded_buffer_max_size(void *topaz_str_ctx, enum img_standard standard, + unsigned short width, unsigned short height, + struct img_rc_params *rc_params) +{ + /* TODO: Determine if we want to make this api str_ctx dependent + * struct topaz_stream_context *str_ctx; + * if (!topaz_str_ctx) + * return IMG_ERROR_INVALID_CONTEXT; + */ + /* Worst-case coded buffer size: All MBs maximum size, + * and a coded buffer header for each row + */ + return topaz_get_max_coded_data_size(standard, width, height, rc_params->initial_qp_i) + + ((height >> 4) * CODED_BUFFER_INFO_SECTION_SIZE); +} + +unsigned int topaz_get_coded_package_max_num(void *topaz_str_ctx, enum img_standard standard, + unsigned short width, unsigned short height, + struct img_rc_params *rc_params) +{ + struct topaz_stream_context *str_ctx; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + + return str_ctx->enc_ctx->video->coded_package_max_num; +} + +/* + * Get a source slot to fill + */ +int topaz_reserve_source_slot(void *topaz_str_ctx, unsigned char *src_slot_num) +{ + struct img_enc_context *enc; + struct img_video_context *video; + struct topaz_stream_context *str_ctx; + signed char index; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + enc = str_ctx->enc_ctx; + video = enc->video; + + if (video->aborted) + return IMG_ERROR_UNEXPECTED_STATE; + + for (index = 0; index < video->slots_in_use; index++) { + if (!video->source_slot_buff[index]) { + /* Found an empty slot, Mark the slot as reserved */ + video->source_slot_reserved = index; + *src_slot_num = index; + return IMG_SUCCESS; + } + } + + return IMG_ERROR_UNEXPECTED_STATE; +} + +/* + * Get a coded slot to fill + */ +int topaz_reserve_coded_package_slot(void *topaz_str_ctx) +{ + struct img_enc_context *enc; + struct img_video_context *video; + struct topaz_stream_context *str_ctx; + signed char index; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + + enc = str_ctx->enc_ctx; + video = enc->video; + + if (video->aborted) + return IMG_ERROR_UNEXPECTED_STATE; + + for (index = 0; index < video->coded_package_max_num; index++) { + if (!video->coded_package[index]->busy) { + /* Found an empty slot, Mark the slot as reserved */ + video->coded_package_slot_reserved = index; + video->coded_package[index]->busy = TRUE; + return IMG_SUCCESS; + } + } + + return IMG_ERROR_UNEXPECTED_STATE; +} + +/* + * Returns number of empty source slots + */ +signed char topaz_query_empty_source_slots(void *topaz_str_ctx) +{ + struct topaz_stream_context *str_ctx; + struct img_enc_context *enc; + struct img_video_context *video; + + unsigned char slot_number; + unsigned char empty_source_slots = 0; + + if (!topaz_str_ctx) { + pr_err("ERROR: Invalid context handle provides to IMG_V_QueryEmptySourceSlots\n"); + return IMG_ERROR_INVALID_CONTEXT; + } + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + enc = str_ctx->enc_ctx; + video = enc->video; + + if (video->aborted) + return -2; + + for (slot_number = 0; slot_number < video->slots_in_use; slot_number++) { + if (!video->source_slot_buff[slot_number]) + empty_source_slots++; + } + + return empty_source_slots; +} + +/* + * Returns number of empty coded buffer slots + */ +signed char topaz_query_empty_coded_slots(void *topaz_str_ctx) +{ + struct topaz_stream_context *str_ctx; + struct img_enc_context *enc; + struct img_video_context *video; + + unsigned char slot_number; + unsigned char empty_coded_slots = 0; + + if (!topaz_str_ctx) { + pr_err("ERROR: Invalid context handle provides to IMG_V_QueryEmptyCodedSlots\n"); + return IMG_ERROR_INVALID_CONTEXT; + } + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + enc = str_ctx->enc_ctx; + video = enc->video; + + if (video->aborted) + return -2; + + for (slot_number = 0; slot_number < video->coded_package_max_num; slot_number++) { + if (!video->coded_package[slot_number]->busy) + empty_coded_slots++; + } + + return empty_coded_slots; +} + +/* + * topaz_stream_map_buf_sg + */ +int topaz_stream_map_buf_sg(void *topaz_str_ctx, enum venc_buf_type buf_type, + struct vidio_ddbufinfo *buf_info, void *sgt) +{ + int ret; + struct topaz_stream_context *str_ctx; + + /* + * Resource stream ID cannot be zero. If zero just warning and + * proceeding further will break the code. Return IMG_ERROR_INVALID_ID. + */ + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + IMG_DBG_ASSERT(buf_type < VENC_BUFTYPE_MAX); + IMG_DBG_ASSERT(buf_info); + IMG_DBG_ASSERT(sgt); + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + + /* Map heap from VENC to MMU. Currently only one heap is used for all buffer types */ + switch (buf_type) { + case VENC_BUFTYPE_BITSTREAM: + case VENC_BUFTYPE_PICTURE: + /* TODO: add logic to cache these buffers into str context list */ + break; + + default: + IMG_DBG_ASSERT(FALSE); + } + + /* Map this buffer into the MMU. */ + ret = topaz_mmu_stream_map_ext_sg(str_ctx->mmu_ctx, MMU_GENERAL_HEAP_ID, sgt, + buf_info->buf_size, 64, + (enum sys_emem_attrib)0, buf_info->cpu_virt, buf_info, + &buf_info->buff_id); + IMG_DBG_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return IMG_ERROR_OUT_OF_MEMORY; + + return IMG_SUCCESS; +} + +/* + * core_stream_unmap_buf_sg + */ +int topaz_stream_unmap_buf_sg(void *topaz_str_ctx, struct vidio_ddbufinfo *buf_info) +{ + int ret; + struct topaz_stream_context *str_ctx; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + + /* Unmap this buffer from the MMU. */ + ret = topaz_mmu_stream_free_sg(str_ctx->mmu_ctx, buf_info); + + IMG_DBG_ASSERT(ret == IMG_SUCCESS); + if (ret != IMG_SUCCESS) + return ret; + + return IMG_SUCCESS; +} + +/* + * End Of Video stream + */ +int topaz_end_of_stream(void *topaz_str_ctx, unsigned int frame_cnt) +{ + struct topaz_stream_context *str_ctx; + struct img_enc_context *enc; + + if (!topaz_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + str_ctx = (struct topaz_stream_context *)topaz_str_ctx; + enc = str_ctx->enc_ctx; + + if (enc->video->aborted) + return IMG_ERROR_UNDEFINED; + + enc->video->frame_count = frame_cnt; + + if (frame_cnt - enc->video->flushed_at_frame < enc->video->slots_in_use) + enc->video->slots_required = frame_cnt - enc->video->flushed_at_frame; + + /* Send PicMgmt Command */ + topaz_insert_command(enc, (enum mtx_cmd_id)(MTX_CMDID_PICMGMT | MTX_CMDID_PRIORITY), + F_ENCODE(IMG_PICMGMT_EOS, MTX_MSG_PICMGMT_SUBTYPE) | + F_ENCODE(frame_cnt, MTX_MSG_PICMGMT_DATA)); + + return IMG_SUCCESS; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_api.h b/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_api.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_api.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_api.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,1047 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Encoder core interface header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef __TOPAZ_API_H__ +#define __TOPAZ_API_H__ + +#include +#include +#include +#include +#include + +#include "fw_headers/topazscfwif.h" +#include "fw_headers/vxe_common.h" +#include "vid_buf.h" +#include "lst.h" + +#define MAX_MVC_VIEWS 2 +#define MVC_BASE_VIEW_IDX 0 +#define NON_MVC_VIEW (~0x0) + +#define MVC_SPS_ID 1 +#define MVC_PPS_ID 1 + +#define NUM_SLICE_TYPES 5 +#define MAX_PLANES 3 + +/* + * This type defines the buffer type categories. + * @brief Buffer Types + */ +enum venc_buf_type { + VENC_BUFTYPE_BITSTREAM = 0, + VENC_BUFTYPE_PICTURE, + VENC_BUFTYPE_ALL, + VENC_BUFTYPE_MAX, + VENC_BUFTYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * VXE callback type definitions + */ +enum vxe_cb_type { + VXE_CB_CODED_BUFF_READY, + VXE_CB_SRC_FRAME_RELEASE, + VXE_CB_STR_END, + VXE_CB_ERROR_FATAL, + VXE_CB_FORCE32BITS = 0x7FFFFFFFU +}; + +typedef void (*vxe_cb)(void *ctx, enum vxe_cb_type type, void *buf_ref, unsigned int size, + unsigned int coded_frm_cnt, enum img_frame_type frame_type); + +/* + * Enum specifying video encode profile + */ +enum img_video_enc_profile { + ENC_PROFILE_DEFAULT = 0, + ENC_PROFILE_LOWCOMPLEXITY, + ENC_PROFILE_HIGHCOMPLEXITY, + ENC_PROFILE_REDUCEDMODE, + ENC_PROFILE_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Enum describing smallest blocksize used during motion search + */ +enum img_ipe_minblock_size { + BLK_SZ_16x16 = 0, + BLK_SZ_8x8 = 1, + BLK_SZ_4x4 = 2, + BLK_SZ_DEFAULT = 3, + BLK_SZ_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * Struct specifying flags to enable/disable encode features. + * All boolean flags are FALSE by default + */ +struct img_encode_features { + unsigned short disable_intra4x4; + unsigned short disable_intra8x8; + unsigned short disable_intra16x16; + unsigned short disable_inter8x8; + unsigned short restrict_inter4x4; + unsigned short disable_bpic_ref1; + unsigned short disable_bpic_ref0; + unsigned short enable_8x16_mv_detect; + unsigned short enable_16x8_mv_detect; + unsigned short disable_bframes; + enum img_ipe_minblock_size min_blk_sz; + unsigned short restricted_intra_pred; +}; + +/* + * + * Struct describing Macro-block params generated by first stage. + * Refer T.R.M. for details + */ +struct img_first_stage_mb_params { + unsigned short ipe0_sad; + unsigned short ipe1_sad; + unsigned char ipe0_blks; + unsigned char ipe1_blks; + unsigned char carc_cmplx_val; + unsigned char reserved; +}; + +/* + * Size of Inter/Intra & Coded/Skipped tables + */ +#define TOPAZHP_SCALE_TBL_SZ (8) +#define DEFAULT_CABAC_DB_MARGIN (0x190) + +/* + *Struct describing params for video encoding + *@enable_sel_stats_flags: Flags to enable selective first-pass statistics gathering by the + *hardware. Bit 1 - First Stage Motion Search Data, Bit 2 - Best + * Multipass MB Decision Data, Bit 3 - Best Multipass Motion Vectors. + * (First stage Table 2 motion vectors are always switched on) + *@enable_inp_ctrl: Enable Macro-block input control + *@enable_air: Enable Adaptive Intra Refresh + *@num_air_mbs: n = Max number of AIR MBs per frame, 0 = _ALL_ MBs over threshold will be marked + * as AIR Intras, -1 = Auto 10% + *@air_threshold: n = SAD Threshold above which a MB is a AIR MB candidate, -1 = Auto adjusting + * threshold + *@air_skip_cnt: n = Number of MBs to skip in AIR Table between frames, -1 = Random + * (0 - NumAIRMbs) skip between frames in AIR table + *@disable_bit_stuffing: Disabling bitstuffing to maintain bitrate + *@mpeg2_intra_dc_precision: Only used in MPEG2, 2 bit field (0 = 8 bit, 1 = 9 bit, 2 = 10 bit + * and 3=11 bit precision). Set to zero for other encode standards. + *@enable_mvc: True if MVC is enabled. False by default + *@mvc_view_idx: MVC view index + *@disable_bh_rounding: True if we wish to disable the buffer height rounding to 16 pixels + * (enables contiguous YU memory for non-aligned image heights) + *@auto_expand_pipes: Automatically expand a context pipe allocations when new pipes become + * available + *@line_counter_enabled: + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#include +#include + +#include "fw_headers/defs.h" +#include "img_errors.h" +#include "reg_headers/topazhp_core_regs.h" +#include "reg_headers/topaz_coreext_regs.h" +#include "reg_headers/topazhp_multicore_regs_old.h" +#include "topaz_api.h" + +#define MV_OFFSET_IN_TABLE(distance, \ + position) ((distance) * MV_ROW_STRIDE + (position) * sizeof(struct img_mv_settings)) +#define DEFAULT_MVCALC_CONFIG ((0x00040303) | (MASK_TOPAZHP_CR_MVCALC_JITTER_POINTER_RST)) + +/* + * Calculates the correct number of macroblocks per kick and kicks per BU + */ +void calculate_kick_and_bu_size(unsigned int width_in_mbs, + unsigned int height_in_mbs, + unsigned char is_interlaced, + unsigned int max_bu_per_frame, + unsigned int *kick_size, + unsigned int *kicks_per_bu, + unsigned int *min_slice_height) +{ + unsigned int kick_size_local, kicks_per_bu_local, bu_per_frame, min_slice_height_local; + + /* + * Basic unit is either an integer number of rows or an integer number of + * basic units fit in a row We calculate the ideal kick size first then decide + * how many kicks there will be for each basic unit + */ + + /* Default to 1 kick per row */ + kick_size_local = width_in_mbs; + kicks_per_bu_local = 1; + min_slice_height_local = 1; + + /* See if we can use a smaller kick size */ + if (!(kick_size_local % 3) && kick_size_local > 30) { + kick_size_local /= 3; + kicks_per_bu_local = 3; + } else if (!(kick_size_local % 2) && (kick_size_local > 20)) { + kick_size_local /= 2; + kicks_per_bu_local = 2; + } + + IMG_DBG_ASSERT((kick_size_local < 256) && ("Kick Size can't be bigger than 255" != NULL)); + + /* Now calculate how many kicks we do per BU */ + bu_per_frame = height_in_mbs * (is_interlaced ? 2 : 1); + + while (bu_per_frame > max_bu_per_frame) { + /* we have too many BUs so double up the number + * of rows per BU so we can half the number of BUs + */ + kicks_per_bu_local *= 2; + /* if we had an odd number of rows then the last BU will be half height */ + bu_per_frame = (bu_per_frame + 1) / 2; + min_slice_height_local *= 2; + } + + /* if we can afford to have 2 BUs per row then do it */ + if ((bu_per_frame < (max_bu_per_frame / 2)) && kicks_per_bu_local == 2) { + kicks_per_bu_local = 1; + bu_per_frame *= 2; + } + + /* if we can afford to have 3 BUs per row then do it */ + if ((bu_per_frame < (max_bu_per_frame / 3)) && kicks_per_bu_local == 3) { + kicks_per_bu_local = 1; + bu_per_frame += 2; + } + + *kick_size = kick_size_local; + *kicks_per_bu = kicks_per_bu_local; + *min_slice_height = min_slice_height_local; +} + +/* + * Calculates the stride based on the input format and width + */ +unsigned int calculate_stride(enum img_format format, ushort requested_stride_bytes, ushort width) +{ + ushort stride_bytes; + + if (requested_stride_bytes) { + stride_bytes = requested_stride_bytes; + } else { + switch (format) { + case IMG_CODEC_Y0UY1V_8888: + case IMG_CODEC_Y0VY1U_8888: + case IMG_CODEC_UY0VY1_8888: + case IMG_CODEC_VY0UY1_8888: + stride_bytes = width << 1; + break; + case IMG_CODEC_ABCX: + case IMG_CODEC_XBCA: + stride_bytes = width << 2; + break; + case IMG_CODEC_ABC565: + stride_bytes = width << 1; + break; + default: + stride_bytes = width; + break; + } + } + + switch (format) { + case IMG_CODEC_420_YUV: + case IMG_CODEC_420_YV12: + case IMG_CODEC_420_PL8: + case IMG_CODEC_422_YUV: + case IMG_CODEC_422_YV12: + case IMG_CODEC_422_PL8: + /* although luma stride is same as chroma stride, + * start address is half the stride. so we need 128-byte alignment + */ + case IMG_CODEC_420_IMC2: + /* although luma stride is same as chroma stride, + * start address is half the stride. so we need 128-byte alignment + */ + case IMG_CODEC_422_IMC2: + + /* + * All strides need to be 64-byte aligned + * Chroma stride is half luma stride, so (luma) stride needs + * to be 64-byte aligned when divided by 2 + */ + return ALIGN_128(stride_bytes); + default: + /* Stride needs to be 64-byte aligned */ + return ALIGN_64(stride_bytes); + } +} + +/* + * Patch HW profile based on the profile specified by the user + */ +void patch_hw_profile(struct img_video_params *video_params, struct img_video_context *video) +{ + unsigned int ipe_control = 0; + unsigned int pred_comb_control = 0; + struct img_encode_features *enc_features = &video_params->enc_features; + + /* disable_intra4x4 */ + if (enc_features->disable_intra4x4) + pred_comb_control |= F_ENCODE(1, TOPAZHP_CR_INTRA4X4_DISABLE); + + /* disable_intra8x8 */ + if (enc_features->disable_intra8x8) + pred_comb_control |= F_ENCODE(1, TOPAZHP_CR_INTRA8X8_DISABLE); + + /* disable_intra16x16, check if at least one of the other Intra mode is enabled */ + if (enc_features->disable_intra16x16 && + (!(enc_features->disable_intra8x8) || !(enc_features->disable_intra4x4))) + pred_comb_control |= F_ENCODE(1, TOPAZHP_CR_INTRA16X16_DISABLE); + + if (video_params->mbps) + video->mbps = video_params->mbps; + + if (enc_features->restrict_inter4x4) + ipe_control |= F_ENCODE(1, TOPAZHP_CR_IPE_MV_NUMBER_RESTRICTION); + + if (enc_features->disable_inter8x8) + pred_comb_control |= F_ENCODE(1, TOPAZHP_CR_INTER8X8_DISABLE); + + if (enc_features->disable_bpic_ref1) + pred_comb_control |= F_ENCODE(1, TOPAZHP_CR_B_PIC1_DISABLE); + else if (enc_features->disable_bpic_ref0) + pred_comb_control |= F_ENCODE(1, TOPAZHP_CR_B_PIC0_DISABLE); + + /* save predictor combiner control in video encode parameter set */ + video->pred_comb_control = pred_comb_control; + + /* set blocksize */ + ipe_control |= F_ENCODE(enc_features->min_blk_sz, TOPAZHP_CR_IPE_BLOCKSIZE); + + if (enc_features->enable_8x16_mv_detect) + ipe_control |= F_ENCODE(1, TOPAZHP_CR_IPE_8X16_ENABLE); + + if (enc_features->enable_16x8_mv_detect) + ipe_control |= F_ENCODE(1, TOPAZHP_CR_IPE_16X8_ENABLE); + + if (enc_features->disable_bframes) + video->rc_params.bframes = 0; + + if (enc_features->restricted_intra_pred) + video->intra_pred_modes = 0xff0f; + + /* save IPE-control register */ + video->ipe_control = ipe_control; +} + +/* + * Set offsets and strides for YUV components of source picture + */ +int topaz_set_component_offsets(void *enc_ctx_handle, struct img_frame *frame) +{ + struct img_enc_context *enc; + struct img_video_context *video; + enum img_format format; + ushort stride_bytes; + ushort picture_height; + + if (!enc_ctx_handle) + return IMG_ERROR_INVALID_CONTEXT; + + /* if source slot is NULL then it's just a next portion of slices */ + if (!frame) + return IMG_ERROR_UNDEFINED; + + enc = (struct img_enc_context *)enc_ctx_handle; + video = enc->video; + + format = video->format; + picture_height = video->buffer_height >> (video->is_interlaced ? 1 : 0); + stride_bytes = video->buffer_stride_bytes; + + /* + * 3 Components: Y, U, V + * Y component is always at the beginning + */ + frame->y_component_offset = 0; + frame->src_y_stride_bytes = stride_bytes; + + /* Assume for now that field 0 comes first */ + frame->field0_y_offset = 0; + frame->field0_u_offset = 0; + frame->field0_v_offset = 0; + + switch (format) { + case IMG_CODEC_420_YUV: + frame->src_uv_stride_bytes = stride_bytes / 2; + + frame->u_component_offset = stride_bytes * picture_height; + frame->v_component_offset = stride_bytes * picture_height + (stride_bytes / 2) * + (picture_height / 2); + break; + + case IMG_CODEC_420_PL8: + frame->src_uv_stride_bytes = stride_bytes / 2; + + frame->u_component_offset = 0; + frame->v_component_offset = 0; + break; + + case IMG_CODEC_420_PL12: + case IMG_CODEC_420_PL21: + frame->src_uv_stride_bytes = stride_bytes; + + frame->u_component_offset = 0; + frame->v_component_offset = 0; + break; + + case IMG_CODEC_420_YV12: + frame->src_uv_stride_bytes = stride_bytes / 2; + frame->u_component_offset = stride_bytes * picture_height + (stride_bytes / 2) * + (picture_height / 2); + frame->v_component_offset = stride_bytes * picture_height; + break; + + case IMG_CODEC_420_PL12_PACKED: + case IMG_CODEC_420_PL21_PACKED: + frame->src_uv_stride_bytes = stride_bytes; + frame->u_component_offset = stride_bytes * picture_height; + frame->v_component_offset = stride_bytes * picture_height; + break; + + case IMG_CODEC_420_IMC2: /* IMC2 */ + frame->src_uv_stride_bytes = stride_bytes; + frame->u_component_offset = stride_bytes * picture_height + (stride_bytes / 2); + frame->v_component_offset = stride_bytes * picture_height; + break; + + case IMG_CODEC_422_YUV: + frame->src_uv_stride_bytes = stride_bytes / 2; + frame->u_component_offset = stride_bytes * picture_height; + frame->v_component_offset = stride_bytes * picture_height + (stride_bytes / 2) * + picture_height; + break; + + case IMG_CODEC_422_YV12: /* YV16 */ + frame->src_uv_stride_bytes = stride_bytes / 2; + frame->u_component_offset = stride_bytes * picture_height + (stride_bytes / 2) * + picture_height; + frame->v_component_offset = stride_bytes * picture_height; + break; + + case IMG_CODEC_422_PL8: + frame->src_uv_stride_bytes = stride_bytes / 2; + frame->u_component_offset = 0; + frame->v_component_offset = 0; + break; + + case IMG_CODEC_422_IMC2: /* IMC2 */ + frame->src_uv_stride_bytes = stride_bytes; + frame->u_component_offset = stride_bytes * picture_height + (stride_bytes / 2); + frame->v_component_offset = stride_bytes * picture_height; + break; + + case IMG_CODEC_422_PL12: + case IMG_CODEC_422_PL21: + frame->src_uv_stride_bytes = stride_bytes; + frame->u_component_offset = 0; + frame->v_component_offset = 0; + break; + + case IMG_CODEC_444_YUV: + frame->src_uv_stride_bytes = stride_bytes; + frame->u_component_offset = stride_bytes * picture_height; + frame->v_component_offset = stride_bytes * picture_height + stride_bytes * + picture_height; + break; + + case IMG_CODEC_444_YV12: /* YV16 */ + frame->src_uv_stride_bytes = stride_bytes; + frame->u_component_offset = stride_bytes * picture_height + stride_bytes * + picture_height; + frame->v_component_offset = stride_bytes * picture_height; + break; + + case IMG_CODEC_444_PL8: + frame->src_uv_stride_bytes = stride_bytes; + frame->u_component_offset = 0; + frame->v_component_offset = 0; + break; + + case IMG_CODEC_444_IMC2: /* IMC2 */ + frame->src_uv_stride_bytes = stride_bytes * 2; + frame->u_component_offset = stride_bytes * picture_height + stride_bytes; + frame->v_component_offset = stride_bytes * picture_height; + break; + + case IMG_CODEC_444_PL12: + case IMG_CODEC_444_PL21: + frame->src_uv_stride_bytes = stride_bytes * 2; + frame->u_component_offset = 0; + frame->v_component_offset = 0; + break; + + case IMG_CODEC_Y0UY1V_8888: + case IMG_CODEC_Y0VY1U_8888: + case IMG_CODEC_UY0VY1_8888: + case IMG_CODEC_VY0UY1_8888: + case IMG_CODEC_ABCX: + case IMG_CODEC_XBCA: + case IMG_CODEC_ABC565: + frame->src_uv_stride_bytes = stride_bytes; + frame->u_component_offset = 0; + frame->v_component_offset = 0; + break; + + default: + break; + } + + if (video->is_interlaced) { + if (video->is_interleaved) { + switch (format) { + case IMG_CODEC_420_IMC2: + case IMG_CODEC_422_IMC2: + frame->v_component_offset *= 2; + frame->u_component_offset = frame->v_component_offset + + (stride_bytes / 2); + break; + case IMG_CODEC_444_IMC2: + frame->v_component_offset *= 2; + frame->u_component_offset = frame->v_component_offset + + stride_bytes; + break; + + default: + frame->u_component_offset *= 2; + frame->v_component_offset *= 2; + break; + } + + frame->field1_y_offset = frame->field0_y_offset + frame->src_y_stride_bytes; + frame->field1_u_offset = frame->field0_u_offset + + frame->src_uv_stride_bytes; + frame->field1_v_offset = frame->field0_v_offset + + frame->src_uv_stride_bytes; + + frame->src_y_stride_bytes *= 2; + frame->src_uv_stride_bytes *= 2; + } else { + unsigned int y_field_size, c_field_size; + + switch (format) { + case IMG_CODEC_420_YUV: + case IMG_CODEC_420_YV12: + case IMG_CODEC_420_IMC2: + case IMG_CODEC_420_PL12_PACKED: + case IMG_CODEC_420_PL21_PACKED: + /* In Packed formats including PL12 packed the field offsets + * should be calculated in the following manner + */ + y_field_size = picture_height * stride_bytes * 3 / 2; + c_field_size = y_field_size; + break; + case IMG_CODEC_420_PL8: + y_field_size = picture_height * stride_bytes; + c_field_size = picture_height * stride_bytes / 4; + break; + case IMG_CODEC_420_PL12: + case IMG_CODEC_420_PL21: + y_field_size = picture_height * stride_bytes; + c_field_size = picture_height * stride_bytes / 2; + break; + case IMG_CODEC_422_YUV: + case IMG_CODEC_422_YV12: + case IMG_CODEC_422_IMC2: + y_field_size = picture_height * stride_bytes * 2; + c_field_size = y_field_size; + break; + case IMG_CODEC_422_PL8: + y_field_size = picture_height * stride_bytes; + c_field_size = picture_height * stride_bytes / 2; + break; + case IMG_CODEC_422_PL12: + case IMG_CODEC_422_PL21: + y_field_size = picture_height * stride_bytes; + c_field_size = picture_height * stride_bytes; + break; + case IMG_CODEC_Y0UY1V_8888: + case IMG_CODEC_UY0VY1_8888: + case IMG_CODEC_Y0VY1U_8888: + case IMG_CODEC_VY0UY1_8888: + y_field_size = picture_height * stride_bytes; + c_field_size = y_field_size; + break; + case IMG_CODEC_444_YUV: + case IMG_CODEC_444_YV12: + case IMG_CODEC_444_IMC2: + y_field_size = picture_height * stride_bytes * 3; + c_field_size = y_field_size; + break; + case IMG_CODEC_444_PL8: + y_field_size = picture_height * stride_bytes; + c_field_size = picture_height * stride_bytes; + break; + case IMG_CODEC_444_PL12: + case IMG_CODEC_444_PL21: + y_field_size = picture_height * stride_bytes; + c_field_size = picture_height * stride_bytes * 2; + break; + case IMG_CODEC_ABCX: + case IMG_CODEC_XBCA: + case IMG_CODEC_ABC565: + y_field_size = picture_height * stride_bytes; + c_field_size = y_field_size; + break; + default: + y_field_size = picture_height * stride_bytes * 3 / 2; + c_field_size = y_field_size; + break; + } + + frame->field1_y_offset = y_field_size; + frame->field1_u_offset = c_field_size; + frame->field1_v_offset = c_field_size; + } + } else { + frame->field1_y_offset = frame->field0_y_offset; + frame->field1_u_offset = frame->field0_u_offset; + frame->field1_v_offset = frame->field0_v_offset; + } + return IMG_SUCCESS; +} + +void topaz_setup_input_csc(struct img_video_context *video, + struct img_vxe_scaler_setup *scaler_setup, + struct img_vxe_csc_setup *csc_setup, + enum img_csc_preset csc_preset) +{ +#define CSC_MINUS_1_16(X) TOPAZHP_EXT_CR_CSC_SOURCE_MOD_0 ## X ## _MINUS_1_16 +#define CSC_MINUS_1_2(X) TOPAZHP_EXT_CR_CSC_SOURCE_MOD_0 ## X ## _MINUS_1_2 +#define CSC_UNSIGNED(X) TOPAZHP_EXT_CR_CSC_SOURCE_MOD_0 ## X ## _UNSIGNED + + if (csc_preset != IMG_CSC_NONE && + (video->format == IMG_CODEC_ABCX || + video->format == IMG_CODEC_XBCA || video->format == IMG_CODEC_ABC565)) { + unsigned char source_mode[IMG_CSC_PRESETS][3] = { + /* IMG_CSC_NONE - No colour-space conversion */ + {CSC_MINUS_1_16(0), CSC_MINUS_1_2(1), CSC_MINUS_1_16(2)}, + + /* IMG_CSC_709_TO_601 - ITU BT.709 YUV to be converted to ITU BT.601 YUV */ + {CSC_MINUS_1_16(0), CSC_MINUS_1_2(1), CSC_MINUS_1_16(2)}, + + /* IMG_CSC_601_TO_709 - ITU BT.601 YUV to be + * converted to ITU BT.709 YUV + */ + {CSC_MINUS_1_16(0), CSC_MINUS_1_2(1), CSC_MINUS_1_16(2)}, + + /* IMG_CSC_RGB_TO_601_ANALOG - RGB to be + * converted to ITU BT.601 YUV + */ + { CSC_UNSIGNED(0), CSC_UNSIGNED(1), CSC_UNSIGNED(2)}, + + /* IMG_CSC_RGB_TO_601_DIGITAL - RGB to be + * converted to ITU BT.601 YCbCr RS + */ + { CSC_UNSIGNED(0), CSC_UNSIGNED(1), CSC_UNSIGNED(2)}, + + /* IMG_CSC_RGB_TO_601_DIGITAL_FS - RGB to be + * converted to ITU BT.601 YCbCr FS + */ + { CSC_UNSIGNED(0), CSC_UNSIGNED(1), CSC_UNSIGNED(2)}, + + /* IMG_CSC_RGB_TO_709 - RGB to be converted to ITU BT.709 YUV */ + { CSC_UNSIGNED(0), CSC_UNSIGNED(1), CSC_UNSIGNED(2)}, + + /* IMG_CSC_YIQ_TO_601 - YIQ to be converted to ITU BT.601 YUV */ + {CSC_MINUS_1_16(0), CSC_MINUS_1_2(1), CSC_MINUS_1_16(2)}, + + /* IMG_CSC_YIQ_TO_709 - YIQ to be converted to ITU BT.709 YUV */ + {CSC_MINUS_1_16(0), CSC_MINUS_1_2(1), CSC_MINUS_1_16(2)}, + + /* IMG_CSC_BRG_TO_601 - RGB to be converted to ITU BT.601 YUV */ + {0, 0, 0}, + + /* IMG_CSC_RBG_TO_601 - RGB to be converted to ITU BT.709 YUV */ + {0, 0, 0}, + + /* IMG_CSC_BGR_TO_601 - RGB to be converted to ITU BT.601 YUV */ + {0, 0, 0}, + + /* IMG_CSC_UYV_TO_YUV - UYV to be converted to YUV */ + {CSC_MINUS_1_2(0), CSC_MINUS_1_16(1), CSC_MINUS_1_2(2)}, + /*{ CSC_UNSIGNED(0), CSC_UNSIGNED(1), CSC_UNSIGNED(2)}, */ + }; + + int coeffs[IMG_CSC_PRESETS][3][3] = { + /* IMG_CSC_NONE - No colour-space conversion */ + { + { 1024, 0, 0 }, + { 0, 1024, 0 }, + { 0, 0, 1024 } + }, + + /* IMG_CSC_709_TO_601 - ITU BT.709 YUV to be converted to ITU BT.601 YUV */ + { + { 1024, (int)(0.15941 * 1024), (int)(0.11649 * 1024) }, + { 0, (int)(-0.07844 * 1024), (int)(0.98985 * 1024) }, + { 0, (int)(0.9834 * 1024), (int)(-0.10219 * 1024) } + }, + + /* IMG_CSC_601_TO_709 - ITU BT.601 YUV to be converted to ITU BT.709 YUV */ + { + { 1024, (int)(-0.17292 * 1024), (int)(-0.13554 * 1024) }, + { 0, (int)(0.08125 * 1024), (int)(1.01864 * 1024) }, + { 0, (int)(1.02532 * 1024), (int)(0.10586 * 1024) } + }, + + /* IMG_CSC_RGB_TO_601_ANALOG - RGB to be converted to ITU BT.601 YUV */ + { /* R G B */ + { (int)(219 * 0.299 * 4.0157), + (int)(219 * 0.587 * 4.0157), + (int)(219 * 0.114 * 4.0157) }, + { (int)(224 * -0.14713 * 4.0157), + (int)(224 * -0.28886 * 4.0157), + (int)(224 * 0.446 * 4.0157) }, + { (int)(224 * 0.615 * 4.0157), + (int)(224 * -0.51499 * 4.0157), + (int)(224 * -0.10001 * 4.0157) } + }, /* A B C */ + + /* IMG_CSC_RGB_TO_601_DIGITAL - RGB to be + * converted to ITU BT.601 YCbCr reduced scale + */ + { /* R G B */ + { (int)(219 * 0.299 * 4.0157), + (int)(219 * 0.587 * 4.0157), + (int)(219 * 0.114 * 4.0157) }, + { (int)(224 * -0.172 * 4.0157), + (int)(224 * -0.339 * 4.0157), + (int)(224 * 0.511 * 4.0157) }, + { (int)(224 * 0.511 * 4.0157), + (int)(224 * -0.428 * 4.0157), + (int)(224 * -0.083 * 4.0157) } + }, /* A B C */ + + /* IMG_CSC_RGB_TO_601_DIGITAL_FS - RGB to be + * converted to ITU BT.601 YCbCr full scale + */ + { /* R G B */ + { (int)(219 * 0.257 * 4.0157), + (int)(219 * 0.504 * 4.0157), + (int)(219 * 0.098 * 4.0157) }, + { (int)(224 * -0.148 * 4.0157), + (int)(224 * -0.291 * 4.0157), + (int)(224 * 0.439 * 4.0157) }, + { (int)(224 * 0.439 * 4.0157), + (int)(224 * -0.368 * 4.0157), + (int)(224 * -0.071 * 4.0157) } + }, /* A B C */ + + /* IMG_CSC_RGB_TO_709 - RGB to be converted to ITU BT.709 YUV */ + { + { (int)(219 * 0.2215 * 4.0157), (int)(219 * 0.7154 * 4.0157), + (int)(219 * 0.0721 * 4.0157) }, + { (int)(224 * -0.1145 * 4.0157), (int)(224 * -0.3855 * 4.0157), + (int)(224 * 0.5 * 4.0157) }, + { (int)(224 * 0.5016 * 4.0157), (int)(224 * -0.4556 * 4.0157), + (int)(224 * -0.0459 * 4.0157) } + }, + + /* IMG_CSC_YIQ_TO_601 - YIQ to be converted to ITU BT.601 YUV */ + { + { 1024, 0, 0 }, + { 0, (int)(0.83885 * 1024), (int)(-0.54475 * 1024) }, + { 0, (int)(0.54484 * 1024), (int)(0.83896 * 1024) } + }, + + /* IMG_CSC_YIQ_TO_709 - YIQ to be converted to ITU BT.709 YUV */ + { + { 1024, (int)(-0.20792 * 1024), (int)(0.07122 * 1024) }, + { 0, (int)(0.89875 * 1024), (int)(-0.48675 * 1024) }, + { 0, (int)(0.64744 * 1024), (int)(0.80255 * 1024) } + }, + + /* + * IMG_CSC_BRG_TO_601 - RGB to be converted to ITU BT.601 YUV + * Entries have been reordered to provide support for xRGB format + */ + { /* B R G */ + { (int)(219 * 0.114 * 4.0157), + (int)(219 * 0.299 * 4.0157), + (int)(219 * 0.587 * 4.0157)}, + { (int)(224 * 0.446 * 4.0157), + (int)(224 * -0.14713 * 4.0157), + (int)(224 * -0.28886 * 4.0157)}, + { (int)(224 * -0.10001 * 4.0157), + (int)(224 * 0.615 * 4.0157), + (int)(224 * -0.51499 * 4.0157)} + }, /* A B C */ + + /* + * IMG_CSC_RBG_TO_601 - RGB to be converted to ITU BT.601 YUV + * Entries have been reordered to provide support for xBGR format + */ + { /* R B G */ + { (int)(219 * 0.299 * 4.0157), + (int)(219 * 0.114 * 4.0157), + (int)(219 * 0.587 * 4.0157)}, + { (int)(224 * -0.14713 * 4.0157), + (int)(224 * 0.446 * 4.0157), + (int)(224 * -0.28886 * 4.0157)}, + { (int)(224 * 0.615 * 4.0157), + (int)(224 * -0.10001 * 4.0157), + (int)(224 * -0.51499 * 4.0157)} + }, /* A B C */ + + /* + * IMG_CSC_BGR_TO_601 - RGB to be converted to ITU BT.601 YUV + * Entries have been reordered to provide support for BGRx format + */ + { /* B G R */ + { (int)(219 * 0.114 * 4.0157), + (int)(219 * 0.587 * 4.0157), + (int)(219 * 0.299 * 4.0157)}, + { (int)(224 * 0.446 * 4.0157), + (int)(224 * -0.28886 * 4.0157), + (int)(224 * -0.14713 * 4.0157)}, + { (int)(224 * -0.10001 * 4.0157), + (int)(224 * -0.51499 * 4.0157), + (int)(224 * 0.615 * 4.0157)}, + }, /* A B C */ + + /* IMG_CSC_UYV_TO_YUV - UYV to YUV */ + { + { 0, 1024, 0 }, + { 1024, 0, 0 }, + { 0, 0, 1024 } + }, + }; + + unsigned int index = csc_preset; + + IMG_DBG_ASSERT(index < IMG_CSC_PRESETS); + + if (index >= IMG_CSC_PRESETS) + return; + +#define SRC_MOD(X) TOPAZHP_EXT_CR_CSC_SOURCE_MOD_0 ## X +#define OUT_MOD(X) TOPAZHP_EXT_CR_CSC_OUTPUT_MOD_0 ## X + +#define SOURCE_Y_ARRAY csc_setup->csc_source_y +#define SRC_Y_PARAM(X) TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_Y + +#define SOURCE_CBCR_ARRAY csc_setup->csc_source_cbcr +#define SRC_CB_PARAM(X) TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_CB +#define SRC_CR_PARAM(X) TOPAZHP_EXT_CR_CSC_SOURCE_SRC_TO_CR + +#define CLIP_VALUE 255 + + scaler_setup->scaler_control |= F_ENCODE(1, + TOPAZHP_EXT_CR_ENABLE_COLOUR_SPACE_CONVERSION); + + csc_setup->csc_output_clip[0] = + F_ENCODE(TOPAZHP_EXT_CR_CSC_OUTPUT_MOD_00_ADD_1_16, OUT_MOD(0)) | + F_ENCODE(CLIP_VALUE, TOPAZHP_EXT_CR_CSC_OUTPUT_MAX_CLIP) | + F_ENCODE(0, TOPAZHP_EXT_CR_CSC_OUTPUT_MIN_CLIP); + + csc_setup->csc_output_clip[1] = + F_ENCODE(TOPAZHP_EXT_CR_CSC_OUTPUT_MOD_01_ADD_1_2, OUT_MOD(1)) | + F_ENCODE(CLIP_VALUE, TOPAZHP_EXT_CR_CSC_OUTPUT_MAX_CLIP) | + F_ENCODE(0, TOPAZHP_EXT_CR_CSC_OUTPUT_MIN_CLIP); + + SOURCE_Y_ARRAY[0] = F_ENCODE(source_mode[index][0], SRC_MOD(0)) | + F_ENCODE(coeffs[index][0][0], SRC_Y_PARAM(0)); + SOURCE_CBCR_ARRAY[0] = F_ENCODE(coeffs[index][1][0], SRC_CB_PARAM(0)) | + F_ENCODE(coeffs[index][2][0], SRC_CR_PARAM(0)); + + SOURCE_Y_ARRAY[1] = F_ENCODE(source_mode[index][1], SRC_MOD(1)) | + F_ENCODE(coeffs[index][0][1], SRC_Y_PARAM(1)); + SOURCE_CBCR_ARRAY[1] = F_ENCODE(coeffs[index][1][1], SRC_CB_PARAM(1)) | + F_ENCODE(coeffs[index][2][1], SRC_CR_PARAM(1)); + + SOURCE_Y_ARRAY[2] = F_ENCODE(source_mode[index][2], SRC_MOD(2)) | + F_ENCODE(coeffs[index][0][2], SRC_Y_PARAM(2)); + SOURCE_CBCR_ARRAY[2] = F_ENCODE(coeffs[index][1][2], SRC_CB_PARAM(2)) | + F_ENCODE(coeffs[index][2][2], SRC_CR_PARAM(2)); + } +} + +/* + * Calculate buffer strides + */ +unsigned int topaz_get_packed_buffer_strides(ushort buffer_stride_bytes, + enum img_format format, + unsigned char enable_scaler, + unsigned char is_interlaced, + unsigned char is_interleaved) +{ + ushort src_y_stride_bytes; + ushort src_uv_stride_bytes = 0; + + /* 3 Components: Y, U, V */ + src_y_stride_bytes = buffer_stride_bytes; + + switch (format) { + case IMG_CODEC_420_YUV: + case IMG_CODEC_420_PL8: + case IMG_CODEC_420_YV12: + src_uv_stride_bytes = src_y_stride_bytes / 2; + break; + + case IMG_CODEC_422_YUV: /* Odd-numbered chroma rows unused if scaler not present */ + case IMG_CODEC_422_YV12: /* Odd-numbered chroma rows unused if scaler not present */ + case IMG_CODEC_422_PL8: /* Odd-numbered chroma rows unused if scaler not present */ + if (!enable_scaler) + /* Skip alternate lines of chroma for 4:2:2 if scaler disabled/not present */ + src_uv_stride_bytes = src_y_stride_bytes; + else + src_uv_stride_bytes = src_y_stride_bytes / 2; + break; + /* Interleaved chroma pixels (and unused odd-numbered chroma rows if scaler not present) */ + case IMG_CODEC_422_IMC2: + /* Interleaved chroma rows (and unused odd-numbered chroma rows if scaler not present) */ + case IMG_CODEC_422_PL12: + /* Interleaved chroma rows (and unused odd-numbered chroma rows if scaler not present) */ + case IMG_CODEC_422_PL21: + if (!enable_scaler) + /* Skip alternate lines of chroma for 4:2:2 if scaler disabled/not present */ + src_uv_stride_bytes = src_y_stride_bytes * 2; + else + src_uv_stride_bytes = src_y_stride_bytes; + break; + + case IMG_CODEC_420_PL12: /* Interleaved chroma pixels */ + case IMG_CODEC_420_PL21: + + case IMG_CODEC_420_PL12_PACKED: /* Interleaved chroma pixels */ + case IMG_CODEC_420_PL21_PACKED: /* Interleaved chroma pixels */ + case IMG_CODEC_420_IMC2: /* Interleaved chroma rows */ + case IMG_CODEC_Y0UY1V_8888: /* Interleaved luma and chroma pixels */ + case IMG_CODEC_Y0VY1U_8888: /* Interleaved luma and chroma pixels */ + case IMG_CODEC_UY0VY1_8888: /* Interleaved luma and chroma pixels */ + case IMG_CODEC_VY0UY1_8888: /* Interleaved luma and chroma pixels */ + case IMG_CODEC_ABCX: /* Interleaved pixels of unknown colour space */ + case IMG_CODEC_XBCA: /* Interleaved pixels of unknown colour space */ + case IMG_CODEC_ABC565: /* Packed pixels of unknown coloour space */ + src_uv_stride_bytes = src_y_stride_bytes; + break; + + case IMG_CODEC_444_YUV: /* Unusable if scaler not present */ + case IMG_CODEC_444_YV12: /* Unusable if scaler not present */ + case IMG_CODEC_444_PL8: /* Unusable if scaler not present */ + src_uv_stride_bytes = src_y_stride_bytes; + break; + + /* Interleaved chroma pixels (unusable if scaler not present) */ + case IMG_CODEC_444_IMC2: + /* Interleaved chroma rows (unusable if scaler not present) */ + case IMG_CODEC_444_PL12: + /* Interleaved chroma rows (unusable if scaler not present) */ + case IMG_CODEC_444_PL21: + src_uv_stride_bytes = src_y_stride_bytes * 2; + break; + + default: + break; + } + + if (is_interlaced && is_interleaved) { + src_y_stride_bytes *= 2; + src_uv_stride_bytes *= 2; + } + return F_ENCODE(src_y_stride_bytes >> 6, MTX_MSG_PICMGMT_STRIDE_Y) | + F_ENCODE(src_uv_stride_bytes >> 6, MTX_MSG_PICMGMT_STRIDE_UV); +} + +/* + * Setup the registers for scaling candidate motion vectors to take into account + * how far away (temporally) the reference pictures are + */ +#define RESTRICT16x16_FLAGS (0x1) +#define RESTRICT8x8_FLAGS (0x2) + +void update_driver_mv_scaling(unsigned int frame_num, unsigned int ref0_num, unsigned int ref1_num, + unsigned int pic_flags, unsigned int *mv_calc_below_handle, + unsigned int *mv_calc_colocated_handle, + unsigned int *mv_calc_config_handle) +{ + unsigned int mv_calc_config = 0; + unsigned int mv_calc_colocated = F_ENCODE(0x10, TOPAZHP_CR_TEMPORAL_BLEND); + unsigned int mv_calc_below = 0; + + /* If b picture calculate scaling factor for colocated motion vectors */ + if (pic_flags & ISINTERB_FLAGS) { + int tb, td, tx; + int dist_scale; + + /* calculation taken from H264 spec */ + tb = (frame_num * 2) - (ref1_num * 2); + td = (ref0_num * 2) - (ref1_num * 2); + tx = (16384 + abs(td / 2)) / td; + dist_scale = (tb * tx + 32) >> 6; + if (dist_scale > 1023) + dist_scale = 1023; + + if (dist_scale < -1024) + dist_scale = -1024; + + mv_calc_colocated |= F_ENCODE(dist_scale, TOPAZHP_CR_COL_DIST_SCALE_FACT); + + /* + * We assume the below temporal mvs are from the latest reference frame + * rather then the most recently encoded B frame (as Bs aren't reference) + * Fwd temporal is same as colocated mv scale + */ + mv_calc_below |= F_ENCODE(dist_scale, TOPAZHP_CR_PIC0_DIST_SCALE_FACTOR); + + /* Bkwd temporal needs to be scaled by the recipricol + * amount in the other direction + */ + tb = (frame_num * 2) - (ref0_num * 2); + td = (ref0_num * 2) - (ref1_num * 2); + tx = (16384 + abs(td / 2)) / td; + dist_scale = (tb * tx + 32) >> 6; + if (dist_scale > 1023) + dist_scale = 1023; + + if (dist_scale < -1024) + dist_scale = -1024; + + mv_calc_below |= F_ENCODE(dist_scale, TOPAZHP_CR_PIC1_DIST_SCALE_FACTOR); + } else { + /* Don't scale the temporal below mvs */ + mv_calc_below |= F_ENCODE(1 << 8, TOPAZHP_CR_PIC0_DIST_SCALE_FACTOR); + + if (ref0_num != ref1_num) { + int ref0_dist, ref1_dist; + int scale; + + /* + * Distance to second reference picture may be different when + * using multiple reference frames on P. Scale based on difference + * in temporal distance to ref pic 1 compared to distance to ref pic 0 + */ + ref0_dist = (frame_num - ref0_num); + ref1_dist = (frame_num - ref1_num); + scale = (ref1_dist << 8) / ref0_dist; + + if (scale > 1023) + scale = 1023; + if (scale < -1024) + scale = -1024; + + mv_calc_below |= F_ENCODE(scale, TOPAZHP_CR_PIC1_DIST_SCALE_FACTOR); + } else { + mv_calc_below |= F_ENCODE(1 << 8, TOPAZHP_CR_PIC1_DIST_SCALE_FACTOR); + } + } + + if (frame_num > 0) { + int ref0_distance, ref1_distance; + int jitter0, jitter1; + + ref0_distance = abs((int)frame_num - (int)ref0_num); + ref1_distance = abs((int)frame_num - (int)ref1_num); + + if (!(pic_flags & ISINTERB_FLAGS)) { + jitter0 = ref0_distance * 1; + jitter1 = jitter0 > 1 ? 1 : 2; + } else { + jitter0 = ref1_distance * 1; + jitter1 = ref0_distance * 1; + } + + /* Hardware can only cope with 1 - 4 jitter factors */ + jitter0 = (jitter0 > 4) ? 4 : (jitter0 < 1) ? 1 : jitter0; + jitter1 = (jitter1 > 4) ? 4 : (jitter1 < 1) ? 1 : jitter1; + + /* Hardware can only cope with 1 - 4 jitter factors */ + IMG_DBG_ASSERT(jitter0 > 0 && jitter0 <= 4 && jitter1 > 0 && jitter1 <= 4); + + mv_calc_config |= F_ENCODE(jitter0 - 1, TOPAZHP_CR_MVCALC_IPE0_JITTER_FACTOR) | + F_ENCODE(jitter1 - 1, TOPAZHP_CR_MVCALC_IPE1_JITTER_FACTOR); + } + + mv_calc_config |= F_ENCODE(1, TOPAZHP_CR_MVCALC_DUP_VEC_MARGIN); + mv_calc_config |= F_ENCODE(7, TOPAZHP_CR_MVCALC_GRID_MB_X_STEP); + mv_calc_config |= F_ENCODE(13, TOPAZHP_CR_MVCALC_GRID_MB_Y_STEP); + mv_calc_config |= F_ENCODE(3, TOPAZHP_CR_MVCALC_GRID_SUB_STEP); + mv_calc_config |= F_ENCODE(1, TOPAZHP_CR_MVCALC_GRID_DISABLE); + + mv_calc_config |= F_ENCODE(1, TOPAZHP_CR_MVCALC_NO_PSEUDO_DUPLICATES); + + *mv_calc_below_handle = mv_calc_below; + *mv_calc_colocated_handle = mv_calc_colocated; + *mv_calc_config_handle = mv_calc_config; +} + +void prepare_mv_estimates(struct img_enc_context *enc) +{ + struct img_video_context *vid_ctx = enc->video; + unsigned int distance; + unsigned int distance_b; + unsigned int position; + struct img_mv_settings *host_mv_settings_b_table; + struct img_mv_settings *host_mv_settings_hierarchical; + unsigned char hierarchical; + + /* IDR */ + vid_ctx->mv_settings_idr.mv_calc_config = DEFAULT_MVCALC_CONFIG; /* default based on TRM */ + vid_ctx->mv_settings_idr.mv_calc_colocated = 0x00100100; /* default based on TRM */ + vid_ctx->mv_settings_idr.mv_calc_below = 0x01000100; /* default based on TRM */ + + update_driver_mv_scaling(0, 0, 0, 0, &vid_ctx->mv_settings_idr.mv_calc_below, + &vid_ctx->mv_settings_idr.mv_calc_colocated, + &vid_ctx->mv_settings_idr.mv_calc_config); + + /* NonB (I or P) */ + for (distance = 1; distance <= MAX_BFRAMES + 1; distance++) { + /* default based on TRM */ + vid_ctx->mv_settings_non_b[distance - 1].mv_calc_config = DEFAULT_MVCALC_CONFIG; + /* default based on TRM */ + vid_ctx->mv_settings_non_b[distance - 1].mv_calc_colocated = 0x00100100; + /* default based on TRM */ + vid_ctx->mv_settings_non_b[distance - 1].mv_calc_below = 0x01000100; + + update_driver_mv_scaling + (distance, 0, 0, 0, + &vid_ctx->mv_settings_non_b[distance - 1].mv_calc_below, + &vid_ctx->mv_settings_non_b[distance - 1].mv_calc_colocated, + &vid_ctx->mv_settings_non_b[distance - 1].mv_calc_config); + } + + hierarchical = (bool)(vid_ctx->mv_settings_hierarchical.cpu_virt); + + host_mv_settings_b_table = (struct img_mv_settings *)(vid_ctx->mv_settings_btable.cpu_virt); + + if (hierarchical) + host_mv_settings_hierarchical = + (struct img_mv_settings *)(vid_ctx->mv_settings_hierarchical.cpu_virt); + + for (distance_b = 0; distance_b < MAX_BFRAMES; distance_b++) { + for (position = 1; position <= distance_b + 1; position++) { + struct img_mv_settings *mv_element = + (struct img_mv_settings *)((unsigned char *)host_mv_settings_b_table + + MV_OFFSET_IN_TABLE(distance_b, position - 1)); + + mv_element->mv_calc_config = + /* default based on TRM */ + (DEFAULT_MVCALC_CONFIG | MASK_TOPAZHP_CR_MVCALC_GRID_DISABLE); + + mv_element->mv_calc_colocated = 0x00100100;/* default based on TRM */ + mv_element->mv_calc_below = 0x01000100; /* default based on TRM */ + + update_driver_mv_scaling(position, distance_b + 2, 0, ISINTERB_FLAGS, + &mv_element->mv_calc_below, + &mv_element->mv_calc_colocated, + &mv_element->mv_calc_config); + } + } + + if (hierarchical) { + for (distance_b = 0; distance_b < MAX_BFRAMES; distance_b++) + memcpy(host_mv_settings_hierarchical + distance_b, + (unsigned char *)host_mv_settings_b_table + + MV_OFFSET_IN_TABLE(distance_b, distance_b >> 1), + sizeof(struct img_mv_settings)); + } +} + +/* + * Generates the video pic params template + */ +void adjust_pic_flags(struct img_enc_context *enc, struct img_rc_params *rc_params, + unsigned char first_pic, unsigned int *flags) +{ + unsigned int flags_local; + struct pic_params *pic_params = &enc->video->pic_params; + + flags_local = pic_params->flags; + + if (!rc_params->rc_enable || !first_pic) + flags_local = 0; + + *flags = flags_local; +} + +/* + * Sets up RC Data + */ +void setup_rc_data(struct img_video_context *video, struct pic_params *pic_params, + struct img_rc_params *rc_params) +{ + int tmp_qp = 0; + int buffer_size_in_frames; + short max_qp = MAX_QP_H264; + short min_qp = 0; + int mul_of_8mbits; + int framerate, scale = 1; + int l1, l2, l3, l4, l5, scaled_bpp; + + /* If Bit Rate and Basic Units are not specified then set to default values. */ + if (rc_params->bits_per_second == 0 && !video->enable_mvc) + rc_params->bits_per_second = 640000; /* kbps */ + + if (!rc_params->bu_size) + /* BU = 1 Frame */ + rc_params->bu_size = (video->picture_height >> 4) * (video->width >> 4); + + if (!rc_params->frame_rate) + rc_params->frame_rate = 30; /* fps */ + + /* Calculate Bits per Pixel */ + if (video->width <= 176) + framerate = 30; + else + framerate = rc_params->frame_rate; + + mul_of_8mbits = rc_params->bits_per_second / 8000000; + + if (mul_of_8mbits == 0) + scale = 256; + else if (mul_of_8mbits > 127) + scale = 1; + else + scale = 128 / mul_of_8mbits; + + scaled_bpp = (scale * rc_params->bits_per_second) / + (framerate * video->width * video->frame_height); + + pic_params->in_params.se_init_qp_i = rc_params->initial_qp_i; + + pic_params->in_params.mb_per_row = (video->width >> 4); + pic_params->in_params.mb_per_bu = rc_params->bu_size; + pic_params->in_params.mb_per_frm = ((unsigned int)(video->width >> 4)) * + (video->frame_height >> 4); + pic_params->in_params.bu_per_frm = (pic_params->in_params.mb_per_frm) / + rc_params->bu_size; + + pic_params->in_params.intra_period = rc_params->intra_freq; + pic_params->in_params.bframes = rc_params->bframes; + pic_params->in_params.bit_rate = rc_params->bits_per_second; + + pic_params->in_params.frm_skip_disable = rc_params->disable_frame_skipping; + + pic_params->in_params.bits_per_frm = + (rc_params->bits_per_second + rc_params->frame_rate / 2) / rc_params->frame_rate; + + pic_params->in_params.bits_per_bu = pic_params->in_params.bits_per_frm / + (4 * pic_params->in_params.bu_per_frm); + + /*Disable Vcm Hardware*/ + pic_params->in_params.disable_vcm_hardware = rc_params->disable_vcm_hardware; + /* Codec-dependent fields */ + if (video->standard == IMG_STANDARD_H264) { + pic_params->in_params.mode.h264.transfer_rate = + (rc_params->transfer_bits_per_second + rc_params->frame_rate / 2) / + rc_params->frame_rate; + pic_params->in_params.mode.h264.hierarchical_mode = rc_params->hierarchical; + + pic_params->in_params.mode.h264.enable_slice_bob = + (unsigned char)rc_params->enable_slice_bob; + pic_params->in_params.mode.h264.max_slice_bob = + (unsigned char)rc_params->max_slice_bob; + pic_params->in_params.mode.h264.slice_bob_qp = + (unsigned char)rc_params->slice_bob_qp; + } + + if (pic_params->in_params.bits_per_frm) { + buffer_size_in_frames = + (rc_params->buffer_size + (pic_params->in_params.bits_per_frm / 2)) / + pic_params->in_params.bits_per_frm; + } else { + IMG_DBG_ASSERT(video->enable_mvc && ("Can happen only in MVC mode" != NULL)); + /* Asigning more or less `normal` value. To be overridden by MVC RC module */ + buffer_size_in_frames = 30; + } + + /* select thresholds and initial Qps etc that are codec dependent */ + switch (video->standard) { + case IMG_STANDARD_H264: + /* Setup MAX and MIN Quant Values */ + pic_params->in_params.max_qp = (rc_params->max_qp > 0) && + (rc_params->max_qp < max_qp) ? rc_params->max_qp : max_qp; + + if (rc_params->min_qp == 0) { + if (scaled_bpp >= (scale >> 1)) { + tmp_qp = 4; + } else if (scaled_bpp > ((scale << 1) / 15)) { + tmp_qp = (22 * scale) - (40 * scaled_bpp); + tmp_qp = tmp_qp / scale; + } else { + tmp_qp = (30 * scale) - (100 * scaled_bpp); + tmp_qp = tmp_qp / scale; + } + + /* Adjust minQp up for small buffer size and down for large buffer size */ + if (buffer_size_in_frames < 5) { + tmp_qp += 2; + } else if (buffer_size_in_frames > 40) { + if (tmp_qp >= 1) + tmp_qp -= 1; + } + /* for HD content allow a lower minQp as bitrate is + * more easily controlled in this case + */ + if (pic_params->in_params.mb_per_frm > 2000) + tmp_qp -= 6; + } else { + tmp_qp = rc_params->min_qp; + } + + min_qp = 2; + + if (tmp_qp < min_qp) + pic_params->in_params.min_qp = min_qp; + else + pic_params->in_params.min_qp = tmp_qp; + + /* Calculate Initial QP if it has not been specified */ + tmp_qp = pic_params->in_params.se_init_qp_i; + if (pic_params->in_params.se_init_qp_i == 0) { + l1 = scale / 20; + l2 = scale / 5; + l3 = (scale * 2) / 5; + l4 = (scale * 4) / 5; + l5 = (scale * 1011) / 1000; + + tmp_qp = pic_params->in_params.min_qp; + + pic_params->in_params.se_init_qp_i = tmp_qp; + if (scaled_bpp < l1) + tmp_qp = (45 * scale) - (78 * scaled_bpp); + else if (scaled_bpp < l2) + tmp_qp = (44 * scale) - (73 * scaled_bpp); + else if (scaled_bpp < l3) + tmp_qp = (34 * scale) - (25 * scaled_bpp); + else if (scaled_bpp < l4) + tmp_qp = (32 * scale) - (20 * scaled_bpp); + else if (scaled_bpp < l5) + tmp_qp = (25 * scale) - (10 * scaled_bpp); + else + tmp_qp = (18 * scale) - (5 * scaled_bpp); + + /* Adjust ui8SeInitQP up for small buffer size or small fps */ + /* Adjust ui8SeInitQP up for small gop size */ + if (buffer_size_in_frames < 20 || rc_params->intra_freq < 20) + tmp_qp += 2 * scale; + + /* for very small buffers increase initial Qp even more */ + if (buffer_size_in_frames < 5) + tmp_qp += 8 * scale; + + /* start on a lower initial Qp for HD content + * as the coding is more efficient + */ + if (pic_params->in_params.mb_per_frm > 2000) + tmp_qp -= 2 * scale; + + if (pic_params->in_params.intra_period == 1) { + /* for very small GOPS start with a much higher initial Qp */ + tmp_qp += 12 * scale; + } else if (pic_params->in_params.intra_period < 5) { + tmp_qp += 6 * scale; + } + + tmp_qp = tmp_qp / scale; + } + + max_qp = 49; + + if (tmp_qp > max_qp) + tmp_qp = max_qp; + + if (tmp_qp < pic_params->in_params.min_qp) + tmp_qp = pic_params->in_params.min_qp; + + pic_params->in_params.se_init_qp_i = tmp_qp; + + if (scaled_bpp <= ((3 * scale) / 10)) + pic_params->flags |= ISRC_I16BIAS; + break; + + default: + /* the NO RC cases will fall here */ + break; + } + + if (video->rc_params.rc_mode == IMG_RCMODE_VBR) { + pic_params->in_params.mb_per_bu = pic_params->in_params.mb_per_frm; + pic_params->in_params.bu_per_frm = 1; + + /* Initialize the parameters of fluid flow traffic model. */ + pic_params->in_params.buffer_size = rc_params->buffer_size; + + /* VBR shouldn't skip frames */ + pic_params->in_params.frm_skip_disable = TRUE; + + /* + * These scale factor are used only for rate control to avoid overflow + * in fixed-point calculation these scale factors are decided by bit rate + */ + if (rc_params->bits_per_second < 640000) + pic_params->in_params.scale_factor = 2; /* related to complexity */ + else if (rc_params->bits_per_second < 2000000) /* 2 Mbits */ + pic_params->in_params.scale_factor = 4; + else if (rc_params->bits_per_second < 8000000) /* 8 Mbits */ + pic_params->in_params.scale_factor = 6; + else + pic_params->in_params.scale_factor = 8; + } else { + /* Set up Input Parameters that are mode dependent */ + switch (video->standard) { + case IMG_STANDARD_H264: + /* + * H264 CBR RC: Initialize the parameters of fluid flow traffic model. + */ + pic_params->in_params.buffer_size = rc_params->buffer_size; + + /* HRD consideration - These values are used by H.264 reference code. */ + if (rc_params->bits_per_second < 1000000) /* 1 Mbits/s */ + pic_params->in_params.scale_factor = 0; + else if (rc_params->bits_per_second < 2000000) /* 2 Mbits/s */ + pic_params->in_params.scale_factor = 1; + else if (rc_params->bits_per_second < 4000000) /* 4 Mbits/s */ + pic_params->in_params.scale_factor = 2; + else if (rc_params->bits_per_second < 8000000) /* 8 Mbits/s */ + pic_params->in_params.scale_factor = 3; + else + pic_params->in_params.scale_factor = 4; + + if (video->rc_params.rc_mode == IMG_RCMODE_VCM) + pic_params->in_params.buffer_size_frames = buffer_size_in_frames; + break; + + default: + break; + } + } + + if (rc_params->sc_detect_disable) + pic_params->flags |= ISSCENE_DISABLED; + + pic_params->in_params.initial_delay = rc_params->initial_delay; + pic_params->in_params.initial_level = rc_params->initial_level; + rc_params->initial_qp_i = pic_params->in_params.se_init_qp_i; + + /* The rate control uses this value to adjust + * the reaction rate to larger than expected frames + */ + if (video->standard == IMG_STANDARD_H264) { + if (pic_params->in_params.bits_per_frm) { + const int bits_per_gop = + (rc_params->bits_per_second / rc_params->frame_rate) * + rc_params->intra_freq; + + pic_params->in_params.mode.h264.rc_scale_factor = (bits_per_gop * 256) / + (pic_params->in_params.buffer_size - + pic_params->in_params.initial_level); + } else { + pic_params->in_params.mode.h264.rc_scale_factor = 0; + } + } +} + +void topaz_setup_input_format(struct img_video_context *video, + struct img_vxe_scaler_setup *scaler_setup) +{ + const unsigned int scaler_coeff_regs_no_crop[] = {4261951490U, 4178589440U, + 4078580480U, 4045614080U}; + + if (video->enable_scaler) { + unsigned int pitch_x, pitch_y; + int phase; + + pitch_x = (((unsigned int)(video->source_width - video->crop_left - + video->crop_right)) << 13) / video->unrounded_width; + + pitch_y = (((unsigned int)(video->source_frame_height - video->crop_top - + video->crop_bottom)) << 13) / video->unrounded_frame_height; + + /* Input size */ + scaler_setup->scaler_input_size_reg = + F_ENCODE(video->source_width - 1, + TOPAZHP_EXT_CR_SCALER_INPUT_WIDTH_MIN1) | + F_ENCODE((video->source_frame_height >> + (video->is_interlaced ? 1 : 0)) - 1, + TOPAZHP_EXT_CR_SCALER_INPUT_HEIGHT_MIN1); + + scaler_setup->scaler_crop_reg = F_ENCODE(video->crop_left, + TOPAZHP_EXT_CR_SCALER_INPUT_CROP_HOR) | + F_ENCODE(video->crop_top, + TOPAZHP_EXT_CR_SCALER_INPUT_CROP_VER); + + /* Scale factors */ + scaler_setup->scaler_pitch_reg = 0; + + if (pitch_x > 0x7FFF) { + scaler_setup->scaler_pitch_reg |= F_ENCODE(1, + TOPAZHP_EXT_CR_SCALER_HOR_BILINEAR_FILTER); + pitch_x >>= 1; + } + + if (pitch_x > 0x7FFF) + pitch_x = 0x7FFF; + + if (pitch_y > 0x7FFF) { + scaler_setup->scaler_pitch_reg |= F_ENCODE(1U, + TOPAZHP_EXT_CR_SCALER_VER_BILINEAR_FILTER); + pitch_y >>= 1; + } + + if (pitch_y > 0x7FFF) + pitch_y = 0x7FFF; + + scaler_setup->scaler_pitch_reg |= + F_ENCODE(pitch_x, TOPAZHP_EXT_CR_SCALER_INPUT_HOR_PITCH) | + F_ENCODE(pitch_y, TOPAZHP_EXT_CR_SCALER_INPUT_VER_PITCH); + + /* + * Coefficients + * With no crop, the coefficients remain the same. + * If crop is desired, new values will need to be calculated. + */ + for (phase = 0; phase < 4; phase++) + scaler_setup->hor_scaler_coeff_regs[phase] = + scaler_coeff_regs_no_crop[phase]; + + for (phase = 0; phase < 4; phase++) + scaler_setup->ver_scaler_coeff_regs[phase] = + scaler_coeff_regs_no_crop[phase]; + + scaler_setup->scaler_control = F_ENCODE(1, TOPAZHP_EXT_CR_SCALER_ENABLE); + + switch (video->format) { + case IMG_CODEC_420_YUV: + case IMG_CODEC_420_PL8: + case IMG_CODEC_420_YV12: + case IMG_CODEC_420_IMC2: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_420PL111YCBCR8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_420_PL12: + case IMG_CODEC_420_PL12_PACKED: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_420PL12YCBCR8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_420_PL21: + case IMG_CODEC_420_PL21_PACKED: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_420PL12YCRCB8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_422_YUV: + case IMG_CODEC_422_PL8: + case IMG_CODEC_422_YV12: + case IMG_CODEC_422_IMC2: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422PL111YCBCR8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_422_PL12: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422PL12YCBCR8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_422_PL21: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422PL12YCRCB8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_Y0UY1V_8888: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422IL3YCBYCR8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_Y0VY1U_8888: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422IL3YCRYCB8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_UY0VY1_8888: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422IL3CBYCRY8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_VY0UY1_8888: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_422IL3CRYCBY8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_444_YUV: + case IMG_CODEC_444_PL8: + case IMG_CODEC_444_YV12: + case IMG_CODEC_444_IMC2: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_444PL111YCBCR8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_444_PL12: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_444PL12YCBCR8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_444_PL21: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_444PL12YCRCB8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_ABCX: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_444IL4ABCX8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_XBCA: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_444IL4XBCA8, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + case IMG_CODEC_ABC565: + scaler_setup->input_scaler_control = + F_ENCODE(TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT_444IL3RGB565, + TOPAZHP_EXT_CR_INPUT_FRAME_STORE_FORMAT); + break; + default: + break; + } + } else { + /* Disable Scaling */ + scaler_setup->scaler_control = 0; + } +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_api_utils.h b/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_api_utils.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_api_utils.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_api_utils.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * topaz utility header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#include +#include "topaz_api.h" + +/* + * Calculates the correct number of macroblocks per kick and kicks per BU + */ +void calculate_kick_and_bu_size(unsigned int width_in_mbs, + unsigned int height_in_mbs, + unsigned char is_interlaced, + unsigned int max_bu_per_frame, + unsigned int *kick_size, + unsigned int *kicks_per_bu, + unsigned int *min_slice_height); + +unsigned int calculate_stride(enum img_format format, + unsigned short requested_stride_bytes, + unsigned short width); + +void topaz_setup_input_format(struct img_video_context *video, + struct img_vxe_scaler_setup *scaler_setup); + +void topaz_setup_input_csc(struct img_video_context *video, + struct img_vxe_scaler_setup *scaler_setup, + struct img_vxe_csc_setup *csc_setup, + enum img_csc_preset csc_preset); + +unsigned int topaz_get_packed_buffer_strides(unsigned short buffer_stride_bytes, + enum img_format format, + unsigned char enable_scaler, + unsigned char is_interlaced, + unsigned char is_interleaved); + +void prepare_mv_estimates(struct img_enc_context *enc); + +void adjust_pic_flags(struct img_enc_context *enc, struct img_rc_params *prc_params, + unsigned char first_pic, unsigned int *flags); + +void setup_rc_data(struct img_video_context *video, struct pic_params *pic_params, + struct img_rc_params *rc_params); + +void patch_hw_profile(struct img_video_params *video_params, struct img_video_context *video); diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_color_formats.h b/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_color_formats.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_color_formats.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_color_formats.h 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * buffer sizes calculation + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#include "topaz_api.h" +#include "fw_headers/defs.h" + +void plane_size(enum img_format color_format, unsigned int stride, + unsigned int height, unsigned int *y_size, unsigned int *u_size, + unsigned int *v_size) +{ + *y_size = *u_size = *v_size = 0; + + switch (color_format) { + case IMG_CODEC_420_PL8: + /* allocate frame for 4:2:0 planar format */ + *y_size = stride * height; + *u_size = stride * height / 4; + *v_size = stride * height / 4; + break; + case IMG_CODEC_420_PL12: + /* allocate frame for 4:2:0 planar format (chroma interleaved) */ + *y_size = stride * height; + *u_size = stride * height / 2; + break; + case IMG_CODEC_422_YUV: + case IMG_CODEC_422_YV12: + case IMG_CODEC_422_IMC2: + /* allocate frame for 4:2:2 format */ + *y_size = stride * height * 2; + break; + case IMG_CODEC_422_PL8: + /* allocate frame for 4:2:2 planar format */ + *y_size = stride * height; + *u_size = stride * height / 2; + *v_size = stride * height / 2; + break; + case IMG_CODEC_422_PL12: + /* allocate frame for 4:2:2 planar format (chroma interleaved) */ + *y_size = stride * height; + *u_size = stride * height; + break; + case IMG_CODEC_Y0UY1V_8888: + case IMG_CODEC_UY0VY1_8888: + case IMG_CODEC_Y0VY1U_8888: + case IMG_CODEC_VY0UY1_8888: + /* allocate frame for 4:2:2 format */ + *y_size = stride * height; + break; + case IMG_CODEC_444_YUV: + case IMG_CODEC_444_YV12: + case IMG_CODEC_444_IMC2: + /* allocate frame for 4:2:2 format */ + *y_size = stride * height * 3; + break; + case IMG_CODEC_444_PL8: + /* allocate frame for 4:2:2 planar format */ + *y_size = stride * height; + *u_size = stride * height; + *v_size = stride * height; + break; + case IMG_CODEC_444_PL12: + /* allocate frame for 4:2:2 planar format (chroma interleaved) */ + *y_size = stride * height; + *u_size = stride * height * 2; + break; + case IMG_CODEC_ABCX: + case IMG_CODEC_XBCA: + case IMG_CODEC_ABC565: + /* allocate frame for RGB interleaved format */ + *y_size = stride * height; + break; + case IMG_CODEC_420_YUV: + case IMG_CODEC_420_YV12: + case IMG_CODEC_420_IMC2: + case IMG_CODEC_420_PL12_PACKED: + case IMG_CODEC_420_PL21_PACKED: + /* allocate frame for 4:2:0 format */ + *y_size = stride * height * 3 / 2; + break; + default: + *y_size = 0; + *u_size = 0; + *v_size = 0; + break; + } +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_device.c b/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_device.c --- a/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_device.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_device.c 2024-07-07 20:37:34.660306629 -0400 @@ -0,0 +1,1671 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Encoder device function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "work_queue.h" +#include "fw_headers/defs.h" +#include "fw_headers/vxe_common.h" +#include "target.h" +#include "target_config.h" +#include "topaz_device.h" +#include "topazmmu.h" +#include "vid_buf.h" +#include "vxe_public_regdefs.h" +#include "img_errors.h" + +#ifdef DEBUG_ENCODER_DRIVER +static char command_string[][38] = { + "MTX_CMDID_NULL", + "MTX_CMDID_SHUTDOWN", + "MTX_CMDID_DO_HEADER", + "MTX_CMDID_ENCODE_FRAME", + "MTX_CMDID_START_FRAME", + "MTX_CMDID_ENCODE_SLICE", + "MTX_CMDID_END_FRAME", + "MTX_CMDID_SETVIDEO", + "MTX_CMDID_GETVIDEO", + "MTX_CMDID_DO_CHANGE_PIPEWORK", +#if SECURE_IO_PORTS + "MTX_CMDID_SECUREIO", +#endif + "MTX_CMDID_PICMGMT", + "MTX_CMDID_RC_UPDATE", + "MTX_CMDID_PROVIDE_SOURCE_BUFFER", + "MTX_CMDID_PROVIDE_REF_BUFFER", + "MTX_CMDID_PROVIDE_CODEDPACKAGE_BUFFER", + "MTX_CMDID_ABORT", + "MTX_CMDID_SETQUANT", + "MTX_CMDID_SETUP_INTERFACE", + "MTX_CMDID_ISSUEBUFF", + "MTX_CMDID_SETUP", + "MTX_CMDID_UPDATE_SOURCE_FORMAT", + "MTX_CMDID_UPDATE_CSC", + "MTX_CMDID_ENDMARKER" +}; +#endif + +DECLARE_WAIT_QUEUE_HEAD(event_wait_queue); + +#define TOPAZ_DEV_SPIN_LOCK_NAME "topaz_dev" +/* max syncStatus value used (at least 4 * MAX_TOPAZ_CMDS_QUEUED) */ +#define MAX_TOPAZ_CMD_COUNT (0x1000) + +#define COMM_WB_DATA_BUF_SIZE (64) + +/* Sempahore locks */ +#define COMM_LOCK_TX 0x01 +#define COMM_LOCK_RX 0x02 +#define COMM_LOCK_BOTH (COMM_LOCK_TX | COMM_LOCK_RX) + +static unsigned int topaz_timeout_retries = 817000; + +#define TOPAZ_TIMEOUT_JPEG (50000) +#define TOPAZ_TIMEOUT_RETRIES (topaz_timeout_retries) + +unsigned short g_load_method = MTX_LOADMETHOD_DMA; /* This is the load method used */ + +unsigned int g_core_rev; +unsigned int g_core_des1; +void *g_lock; + +struct vidio_ddbufinfo *g_aps_wb_data_info; + +static unsigned char g_pipe_usage[TOPAZHP_MAX_NUM_PIPES] = { 0 }; + +/* Order MUST match with topaz_mem_space_idx enum */ +struct mem_space topaz_mem_space[] = { + /* Multicore sync RAM */ + { "REG_TOPAZHP_MULTICORE", MEMSPACE_REGISTER, + {{0x00000000, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_DMAC", MEMSPACE_REGISTER, + {{0x00000400, 0x000000ff, TARGET_NO_IRQ}}}, + { "REG_COMMS", MEMSPACE_REGISTER, + {{0x00000500, 0x000000ff, TARGET_NO_IRQ}}}, + { "REG_MTX", MEMSPACE_REGISTER, + {{0x00000800, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_MMU", MEMSPACE_REGISTER, + {{0x00000C00, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_TEST", MEMSPACE_REGISTER, + {{0xFFFF0000, 0x000001ff, TARGET_NO_IRQ}}}, + { "REGMTXRAM", MEMSPACE_REGISTER, + {{0x80000000, 0x0000ffff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_CORE_0", MEMSPACE_REGISTER, + {{0x00001000, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_VLC_CORE_0", MEMSPACE_REGISTER, + {{0x00001400, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_DEBLOCKER_CORE_0", MEMSPACE_REGISTER, + {{0x00001800, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_COREEXT_0", MEMSPACE_REGISTER, + {{0x00001C00, 0x000003ff, TARGET_NO_IRQ}}}, + + { "REG_TOPAZHP_CORE_1", MEMSPACE_REGISTER, + {{0x00002000, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_VLC_CORE_1", MEMSPACE_REGISTER, + {{0x00002400, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_DEBLOCKER_CORE_1", MEMSPACE_REGISTER, + {{0x00002800, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_COREEXT_1", MEMSPACE_REGISTER, + {{0x00002C00, 0x000003ff, TARGET_NO_IRQ}}}, + + { "REG_TOPAZHP_CORE_2", MEMSPACE_REGISTER, + {{0x00003000, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_VLC_CORE_2", MEMSPACE_REGISTER, + {{0x00003400, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_DEBLOCKER_CORE_2", MEMSPACE_REGISTER, + {{0x00003800, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_COREEXT_2", MEMSPACE_REGISTER, + {{0x00003C00, 0x000003ff, TARGET_NO_IRQ}}}, + + { "REG_TOPAZHP_CORE_3", MEMSPACE_REGISTER, + {{0x00004000, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_VLC_CORE_3", MEMSPACE_REGISTER, + {{0x00004400, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_DEBLOCKER_CORE_3", MEMSPACE_REGISTER, + {{0x00004800, 0x000003ff, TARGET_NO_IRQ}}}, + { "REG_TOPAZHP_COREEXT_3", MEMSPACE_REGISTER, + {{0x00004C00, 0x000003ff, TARGET_NO_IRQ}}}, + + { "FW", MEMSPACE_MEMORY, + {{0x00000000, 0x00800000, 0 }}}, + { "SYSMEM", MEMSPACE_MEMORY, + {{0x00000000, 0, 0 }}}, + { "MEMSYSMEM", MEMSPACE_MEMORY, + {{0x00000000, 0, 0 }}}, + { "MEM", MEMSPACE_MEMORY, + {{0x00000000, 0, 0 }}}, + { "FB", MEMSPACE_MEMORY, + {{0x00000000, 0, 0 }}}, + { "MEMDMAC_00", MEMSPACE_MEMORY, + {{0x00000000, 0, 0 }}}, + { "MEMDMAC_01", MEMSPACE_MEMORY, + {{0x00000000, 0, 0 }}}, + { "MEMDMAC_02", MEMSPACE_MEMORY, + {{0x00000000, 0, 0 }}}, +}; + +#define MEMORYSPACES_NUM (sizeof(topaz_mem_space) / sizeof(struct mem_space)) + +static struct target_config topaz_target_config = { + MEMORYSPACES_NUM, + &topaz_mem_space[0] +}; + +/* + * topazdd_int_enable + */ +static void topazdd_int_enable(struct topaz_dev_ctx *ctx, unsigned int mask) +{ + unsigned int reg; + unsigned long flags; + + spin_lock_irqsave(ctx->lock, flags); + + /* config interrupts on Topaz core */ + reg = VXE_RD_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_HOST_INT_ENAB); + + /* set enable interrupt bits */ + reg |= mask; + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_HOST_INT_ENAB, reg); + + spin_unlock_irqrestore(ctx->lock, (unsigned long)flags); +} + +/* + * topazdd_int_disable + */ +static void topazdd_int_disable(struct topaz_dev_ctx *ctx, unsigned int mask) +{ + unsigned int reg; + unsigned long flags; + + spin_lock_irqsave(ctx->lock, flags); + + /* config interrupts on Topaz core */ + reg = VXE_RD_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_HOST_INT_ENAB); + + /* clear enable interrupt bits */ + reg &= ~mask; + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_HOST_INT_ENAB, reg); + + spin_unlock_irqrestore(ctx->lock, (unsigned long)flags); +} + +/* + * Get the number of pipes present + */ +unsigned int topazdd_get_num_pipes(struct topaz_dev_ctx *ctx) +{ + static unsigned int g_pipes_avail; + + if (!ctx->multi_core_mem_addr) + return 0; + + if (g_pipes_avail == 0) { + /* get the actual number of cores */ + g_pipes_avail = VXE_RD_REG32(ctx->multi_core_mem_addr, + TOPAZHP_TOP_CR_MULTICORE_HW_CFG); + g_pipes_avail = (g_pipes_avail & MASK_TOPAZHP_TOP_CR_NUM_CORES_SUPPORTED); + IMG_DBG_ASSERT(g_pipes_avail != 0); + } + + return g_pipes_avail; +} + +unsigned int topazdd_get_core_rev(void) +{ + return g_core_rev; +} + +unsigned int topazdd_get_core_des1(void) +{ + return g_core_des1; +} + +static void wbfifo_clear(struct img_comm_socket *sock) +{ + sock->in_fifo_producer = 0; + sock->in_fifo_consumer = 0; +} + +static unsigned char wbfifo_add(struct img_comm_socket *sock, struct img_writeback_msg *msg) +{ + unsigned int new_producer = sock->in_fifo_producer + 1; + + if (new_producer == COMM_INCOMING_FIFO_SIZE) + new_producer = 0; + + if (new_producer == sock->in_fifo_consumer) + return FALSE; + + memcpy(&sock->in_fifo[sock->in_fifo_producer], msg, sizeof(struct img_writeback_msg)); + + sock->in_fifo_producer = new_producer; + + return TRUE; +} + +static unsigned char wbfifo_is_empty(struct img_comm_socket *sock) +{ + return (sock->in_fifo_producer == sock->in_fifo_consumer); +} + +static unsigned char wbfifo_get(struct img_comm_socket *sock, struct img_writeback_msg *msg) +{ + if (wbfifo_is_empty(sock)) + return FALSE; + + memcpy(msg, &sock->in_fifo[sock->in_fifo_consumer], sizeof(struct img_writeback_msg)); + + sock->in_fifo_consumer++; + + if (sock->in_fifo_consumer == COMM_INCOMING_FIFO_SIZE) + sock->in_fifo_consumer = 0; + + return TRUE; +} + +unsigned char topazdd_is_idle(struct img_comm_socket *sock) +{ + if (sock->msgs_sent == sock->ack_recv && wbfifo_is_empty(sock)) + return TRUE; + + return FALSE; +} + +static void set_auto_clock_gating(struct topaz_dev_ctx *ctx, struct img_fw_context *fw_ctx, + unsigned char gating) +{ + unsigned int reg; + + reg = F_ENCODE(1U, TOPAZHP_TOP_CR_WRITES_CORE_ALL); + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_CORE_SEL_0, reg); + + reg = F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_IPE0_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_IPE1_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_SPE0_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_SPE1_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_H264COMP4X4_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_H264COMP8X8_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_H264COMP16X16_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_JMCOMP_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_VLC_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_DEB_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_PC_DM_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_PC_DMS_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_CABAC_AUTO_CLK_GATE) | + F_ENCODE(gating, TOPAZHP_CR_TOPAZHP_INPUT_SCALER_AUTO_CLK_GATE); + + VXE_WR_REG32(ctx->hp_core_reg_addr[0], TOPAZHP_CR_TOPAZHP_AUTO_CLOCK_GATING, reg); + + reg = 0; + reg = VXE_RD_REG32(ctx->hp_core_reg_addr[0], TOPAZHP_CR_TOPAZHP_MAN_CLOCK_GATING); + + /* Disable LRITC clocks */ + reg = F_INSERT(reg, 1, TOPAZHP_CR_TOPAZHP_LRITC_MAN_CLK_GATE); + + VXE_WR_REG32(ctx->hp_core_reg_addr[0], TOPAZHP_CR_TOPAZHP_MAN_CLOCK_GATING, reg); + + reg = F_ENCODE(0, TOPAZHP_TOP_CR_WRITES_CORE_ALL); + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_CORE_SEL_0, reg); +} + +static void comm_lock(struct topaz_dev_ctx *ctx, unsigned int flags) +{ + if (flags & COMM_LOCK_TX) + mutex_lock_nested(ctx->comm_tx_mutex, SUBCLASS_TOPAZDD_TX); +} + +static void comm_unlock(struct topaz_dev_ctx *ctx, unsigned int flags) +{ + if (flags & COMM_LOCK_TX) + mutex_unlock((struct mutex *)ctx->comm_tx_mutex); +} + +int comm_prepare_fw(struct img_fw_context *fw_ctx, enum img_codec codec) +{ + if (fw_ctx->populated || fw_ctx->initialized) + return IMG_SUCCESS; + + return mtx_populate_fw_ctx(codec, fw_ctx); +} + +static unsigned int H264_RCCONFIG_TABLE_5[27] = { + 0x00000007, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000005, 0x00000005, + 0x00000005, 0x00000005, + 0x00000005, 0x00000005, 0x00000004, 0x00000004, + 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000005, + 0x00000005, 0x00000005, + 0x00000005, 0x00000005, 0x00000005, 0x00000006, + 0x00000006, +}; + +static unsigned int H264_RCCONFIG_TABLE_6[27] = { + 0x00000018, 0x00000018, 0x00000018, 0x00000018, 0x00000018, 0x00000018, 0x00000018, + 0x00000018, 0x00000024, + 0x00000030, 0x00000030, 0x0000003c, 0x0000003c, + 0x00000048, 0x00000048, 0x00000054, 0x00000060, 0x0000006c, 0x000000c8, 0x00000144, + 0x00000180, 0x00000210, + 0x000002a0, 0x00000324, 0x0000039c, 0x00000414, + 0x00000450, +}; + +static unsigned int H264_RCCONFIG_TABLE_7[27] = { + 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000032, + 0x00000064, 0x000000d2, + 0x000001a4, 0x000001a4, 0x000001bd, 0x000001d6, + 0x000001ef, 0x00000208, 0x00000217, 0x00000226, 0x0000023a, 0x000002cb, 0x0000035c, + 0x00000384, 0x000003e8, + 0x000004b0, 0x00000578, 0x00000640, 0x00000708, + 0x000007d0, +}; + +static unsigned int MPEG_RCCONFIG_TABLE_7[17] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000003c, + 0x000000b4, 0x0000012c, + 0x000001a4, 0x0000021c, 0x00000294, 0x0000030c, + 0x00000384, 0x000003fc, 0x00000474, 0x000004ec, +}; + +/* + * Load the tables for H.264 + */ +void comm_load_h264_tables(struct topaz_dev_ctx *ctx) +{ + int n; + unsigned int pipe, pipe_cnt; + + pipe_cnt = topazdd_get_num_pipes(ctx); + + for (n = 26; n >= 0; n--) { + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_RC_CONFIG_TABLE4, 0); + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_RC_CONFIG_TABLE5, + H264_RCCONFIG_TABLE_5[n]); + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_RC_CONFIG_TABLE6, + H264_RCCONFIG_TABLE_6[n]); + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_RC_CONFIG_TABLE7, + H264_RCCONFIG_TABLE_7[n]); + } + + for (pipe = 0; pipe < pipe_cnt; pipe++) { + VXE_WR_REG32(ctx->hp_core_reg_addr[pipe], TOPAZHP_CR_RC_CONFIG_REG8, 0x00000006); + VXE_WR_REG32(ctx->hp_core_reg_addr[pipe], TOPAZHP_CR_RC_CONFIG_REG9, 0x00000406); + } +} + +/* + * Load the tables for mpeg4 + */ +void comm_load_tables(struct topaz_dev_ctx *ctx) +{ + int n; + unsigned int pipe; + + for (n = 16; n > 0; n--) { + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_RC_CONFIG_TABLE4, 0); + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_RC_CONFIG_TABLE6, 0); + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_RC_CONFIG_TABLE7, + MPEG_RCCONFIG_TABLE_7[n]); + } + + for (pipe = 0; pipe < topazdd_get_num_pipes(ctx); pipe++) + VXE_WR_REG32(ctx->hp_core_reg_addr[pipe], TOPAZHP_CR_RC_CONFIG_REG8, 0x00000006); +} + +/* + * Load bias tables + */ +static int comm_load_bias(struct topaz_dev_ctx *ctx, unsigned int codec_mask) +{ + if ((codec_mask & CODEC_MASK_H263) || (codec_mask & CODEC_MASK_MPEG2) || + (codec_mask & CODEC_MASK_MPEG4)) + comm_load_tables(ctx); + + if ((codec_mask & CODEC_MASK_H264) || (codec_mask & CODEC_MASK_H264MVC)) + comm_load_h264_tables(ctx); + + return IMG_SUCCESS; +} + +/* + * Loads MTX firmware + */ +void topaz_setup_firmware(struct topaz_dev_ctx *ctx, + struct img_fw_context *fw_ctx, + enum mtx_load_method load_method, + enum img_codec codec, unsigned char num_pipes) +{ + unsigned int reg; + unsigned int secure_reg; + int ret; + + fw_ctx->initialized = FALSE; + + /* Reset the MTXs and Upload the code. */ + /* start each MTX in turn MUST start with master to enable comms to other cores */ + +#if SECURE_IO_PORTS + /* reset SECURE_CONFIG register to allow loading FW without security. + * Default option is secure. + */ + + secure_reg = 0x000F0F0F; + + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_SECURE_CONFIG, secure_reg); +#endif + + ret = comm_prepare_fw(fw_ctx, codec); + + if (ret != IMG_SUCCESS) { + pr_err("Failed to populate firmware context. Error code: %i\n", ret); + return; + } + + /* initialise the MTX */ + mtx_initialize(ctx, fw_ctx); + + /* clear TOHOST register now so that our ISR doesn't see any + * intermediate value before the FW has output anything + */ + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_FIRMWARE_REG_1 + + (MTX_SCRATCHREG_TOHOST << 2), 0); + + /* clear BOOTSTATUS register. Firmware will write to + * this to indicate firmware boot progress + */ + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_FIRMWARE_REG_1 + + (MTX_SCRATCHREG_BOOTSTATUS << 2), 0); + + /* Soft reset of MTX */ + reg = 0; + reg = F_ENCODE(1, TOPAZHP_TOP_CR_IMG_TOPAZ_MTX_SOFT_RESET) | + F_ENCODE(1, TOPAZHP_TOP_CR_IMG_TOPAZ_CORE_SOFT_RESET); + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_SRST, reg); + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_SRST, 0x0); + + if (fw_ctx->initialized) { + set_auto_clock_gating(ctx, fw_ctx, 1); + mtx_load(ctx, fw_ctx, load_method); + + /* flush the command FIFO */ + reg = 0; + reg = F_ENCODE(1, TOPAZHP_TOP_CR_CMD_FIFO_FLUSH); + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_TOPAZ_CMD_FIFO_FLUSH, reg); + + /* we do not want to run in secre FW mode so write a place holder + * to the FIFO that the firmware will know to ignore + */ + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE, + TOPAZHP_NON_SECURE_FW_MARKER); + + /* Clear FW_IDLE_STATUS register */ + VXE_WR_REG32(ctx->multi_core_mem_addr, MTX_SCRATCHREG_IDLE, 0); + + /* turn on MTX */ + mtx_start(fw_ctx); + /* get MTX Clk Freq */ + + mtx_kick(fw_ctx, 1); + + /* + * We do not need to do this POLL here as it is safe to continue without it. + * We do it because it serves to warn us that there is a problem if the + * firmware doesn't start for some reason + */ + VXE_POLL_REG32_ISEQ(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_FIRMWARE_REG_1 + + (MTX_SCRATCHREG_BOOTSTATUS << 2), TOPAZHP_FW_BOOT_SIGNAL, + 0xffffffff, TOPAZ_TIMEOUT_RETRIES); + } +} + +static int comm_send(struct img_comm_socket *sock, struct mtx_tomtx_msg *msg, unsigned int *wb_val) +{ + struct topaz_dev_ctx *ctx; + struct img_fw_context *fw_ctx; + unsigned int space_avail; + unsigned int cmd_word; + unsigned int writeback_val; + enum mtx_cmd_id cmd_id = (enum mtx_cmd_id)(msg->cmd_id & 0x7F); + + ctx = sock->ctx; + fw_ctx = &ctx->fw_ctx; + + /* mark the context as active in case we need to save its state later */ + fw_ctx->active_ctx_mask |= (1 << sock->id); + + space_avail = VXE_RD_REG32(ctx->multi_core_mem_addr, + TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE_SPACE); + + space_avail = F_DECODE(space_avail, TOPAZHP_TOP_CR_CMD_FIFO_SPACE); + + if (space_avail < 4) + return IMG_ERROR_RETRY; + + /* Write command to FIFO */ + cmd_word = F_ENCODE(sock->id, MTX_MSG_CORE) | msg->cmd_id; + + if (msg->cmd_id & MTX_CMDID_PRIORITY) { + /* increment the command counter */ + sock->high_cmd_cnt++; + + /* Prepare high priority command */ + cmd_word |= F_ENCODE(1, MTX_MSG_PRIORITY) | + F_ENCODE(((sock->low_cmd_cnt - 1) & 0xff) | (sock->high_cmd_cnt << 8), + MTX_MSG_COUNT); + } else { + /* Prepare low priority command */ + cmd_word |= F_ENCODE(sock->low_cmd_cnt & 0xff, MTX_MSG_COUNT); + } + + /* write command into FIFO */ + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE, cmd_word); + + /* Write data to FIFO */ + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE, msg->data); + + if (msg->command_data_buf) { + /* Write address */ + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE, + msg->command_data_buf->dev_virt); + } else { + /* Write nothing */ + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE, 0); + } + + /* Write writeback value to FIFO */ + + /* prepare Writeback value */ + + /* We don't actually use this value, but it may be useful to customers */ + if (msg->cmd_id & MTX_CMDID_PRIORITY) { + /* HIGH priority command */ + + writeback_val = sock->high_cmd_cnt << 24; + + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE, + writeback_val); + } else { + /* LOW priority command */ + writeback_val = sock->low_cmd_cnt << 16; + + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE, + writeback_val); + + /* increment the command counter */ + sock->low_cmd_cnt++; + } + + if (wb_val) + *wb_val = writeback_val; + + sock->last_sync = writeback_val; + + switch (cmd_id) { + case MTX_CMDID_PROVIDE_CODEDPACKAGE_BUFFER: + { +#ifdef DEBUG_ENCODER_DRIVER + unsigned int slot; + + slot = F_DECODE(msg->data, MTX_MSG_PROVIDE_CODEDPACKAGE_BUFFER_SLOT); + pr_debug("MSG_TX[%d]: %s(%d) %s %s cmd: %#08x cmd_word: %#08x data: %#08x: addr: 0x%p writeback_val: %#08x\n", + sock->id, command_string[cmd_id], slot, + (msg->cmd_id & MTX_CMDID_PRIORITY ? "(PRIORITY)" : "(NORMAL)"), + (msg->cmd_id & MTX_CMDID_WB_INTERRUPT ? "(Interrupt)" : "(NO Interrupt)"), + (msg->cmd_id), cmd_word, (msg->data), msg->command_data_buf, + writeback_val); +#endif + break; + } +#ifdef ENABLE_PROFILING + case MTX_CMDID_ENCODE_FRAME: + { + struct timespec64 time; + + ktime_get_real_ts64(&time); + + sock->fw_lat.start_time = timespec64_to_ns((const struct timespec64 *)&time); + } +#endif + default: +#ifdef DEBUG_ENCODER_DRIVER + pr_debug("MSG_TX[%d]: %s %s %s cmd: %#08x cmd_word: %#08x data: %#08x addr: 0x%p writeback_val: %#08x\n", + sock->id, command_string[cmd_id], + (msg->cmd_id & MTX_CMDID_PRIORITY ? "(PRIORITY)" : "(NORMAL)"), + (msg->cmd_id & MTX_CMDID_WB_INTERRUPT ? "(Interrupt)" : "(NO Interrupt)"), + (msg->cmd_id), cmd_word, (msg->data), msg->command_data_buf, + writeback_val); +#endif + break; + } +#ifdef DEBUG_ENCODER_DRIVER + if (msg->command_data_buf) { + int i; + + pr_debug("Has msg->command_data_buf cpu_virt=0x%p dev_virt=%#08x\n", + msg->command_data_buf->cpu_virt, msg->command_data_buf->dev_virt); + + for (i = 0; i < 350; i++) { + pr_debug("MSG_TX %03d %#08x\n", i, + ((unsigned int *)msg->command_data_buf->cpu_virt)[i]); + } + } +#endif + + /* kick the master MTX */ + mtx_kick(fw_ctx, 1); + + sock->msgs_sent++; + + return IMG_SUCCESS; +} + +int topazdd_send_msg(void *dd_str_ctx, enum mtx_cmd_id cmd_id, + unsigned int data, struct vidio_ddbufinfo *cmd_data_buf, + unsigned int *wb_val) +{ + struct mtx_tomtx_msg *msg; + struct img_comm_socket *sock; + int err; + + if (!dd_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + sock = (struct img_comm_socket *)dd_str_ctx; + + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + IMG_DBG_ASSERT(msg); + if (!msg) + return IMG_ERROR_UNDEFINED; + + msg->command_data_buf = cmd_data_buf; + msg->cmd_id = cmd_id; + msg->data = data; + + if (!wb_val) { + comm_lock(sock->ctx, COMM_LOCK_TX); + err = comm_send(sock, msg, NULL); + comm_unlock(sock->ctx, COMM_LOCK_TX); + } else { + unsigned int ret_wb_val; + + comm_lock(sock->ctx, COMM_LOCK_TX); + err = comm_send(sock, msg, &ret_wb_val); + comm_unlock(sock->ctx, COMM_LOCK_TX); + + if (err == IMG_SUCCESS) + *wb_val = ret_wb_val; + } + + kfree(msg); + return err; +} + +#define WAIT_FOR_SYNC_RETRIES 1200 +#define WAIT_FOR_SYNC_TIMEOUT 1 + +static int wait_event_obj(void *event, unsigned char uninterruptible, unsigned int timeout) +{ + struct event *p_event = (struct event *)event; + int ret; + + IMG_DBG_ASSERT(event); + if (!event) + return IMG_ERROR_GENERIC_FAILURE; + + if (uninterruptible) { + if (timeout == (unsigned int)(-1)) { + ret = 0; + wait_event(event_wait_queue, p_event->signalled); + } else { + ret = wait_event_timeout(event_wait_queue, p_event->signalled, timeout); + if (!ret) + return IMG_ERROR_TIMEOUT; + } + } else { + if (timeout == (unsigned int)(-1)) { + ret = wait_event_interruptible(event_wait_queue, p_event->signalled); + } else { + ret = wait_event_interruptible_timeout(event_wait_queue, + p_event->signalled, timeout); + if (!ret) + return IMG_ERROR_TIMEOUT; + } + } + + /* If there are signals pending... */ + if (ret == -ERESTARTSYS) + return IMG_ERROR_INTERRUPTED; + + /* If there was no signal...*/ + IMG_DBG_ASSERT(p_event->signalled); + + /* Clear signal pending...*/ + p_event->signalled = FALSE; + + return IMG_SUCCESS; +} + +static int topazdd_wait_on_sync(struct img_comm_socket *sock, unsigned int wb_val) +{ + unsigned int retries = 0; + + if (!sock) + return IMG_ERROR_INVALID_CONTEXT; + + while (wait_event_obj(sock->event, TRUE, WAIT_FOR_SYNC_TIMEOUT) != IMG_SUCCESS) { + if (retries == WAIT_FOR_SYNC_RETRIES) { + /* + * We shouldn't wait any longer than that! + * If the hardware locked up, we will get stuck otherwise. + */ + pr_err("TIMEOUT: %s timed out waiting for writeback 0x%08x.\n", + __func__, sock->sync_wb_val); + return IMG_ERROR_TIMEOUT; + } + + msleep(WAIT_FOR_SYNC_TIMEOUT); + retries++; + continue; + } + + return IMG_SUCCESS; +} + +int topazdd_send_msg_with_sync(void *dd_str_ctx, enum mtx_cmd_id cmd_id, + unsigned int data, + struct vidio_ddbufinfo *cmd_data_buf) +{ + struct img_comm_socket *sock; + unsigned int wb_val = 0; + + if (!dd_str_ctx) + return IMG_ERROR_INVALID_CONTEXT; + + sock = (struct img_comm_socket *)dd_str_ctx; + + mutex_lock_nested(sock->sync_wb_mutex, SUBCLASS_TOPAZDD); + topazdd_send_msg(dd_str_ctx, cmd_id, data, cmd_data_buf, &wb_val); + sock->sync_waiting = TRUE; + sock->sync_wb_val = wb_val; + mutex_unlock((struct mutex *)sock->sync_wb_mutex); + + return topazdd_wait_on_sync(sock, wb_val); +} + +static void stream_worker(void *work) +{ + struct img_comm_socket *sock = NULL; + struct img_writeback_msg msg; + struct event *p_event; + + work = get_work_buff(work, FALSE); + sock = container_of(work, struct img_comm_socket, work); + + while (wbfifo_get(sock, &msg)) { + if (F_DECODE(msg.cmd_word, MTX_MSG_MESSAGE_ID) == MTX_MESSAGE_ACK) + sock->ack_recv++; + + mutex_lock_nested(sock->sync_wb_mutex, SUBCLASS_TOPAZDD); + if (sock->sync_waiting && msg.writeback_val == sock->sync_wb_val) { + sock->sync_waiting = FALSE; + mutex_unlock((struct mutex *)sock->sync_wb_mutex); + /* signal the waiting sync event */ + p_event = (struct event *)sock->event; + + IMG_DBG_ASSERT(sock->event); + if (!sock->event) + return; + + p_event->signalled = TRUE; + wake_up(&event_wait_queue); + return; + } + mutex_unlock((struct mutex *)sock->sync_wb_mutex); + + if (sock->cb) + sock->cb(&msg, sock->str_ctx); + } +} + +int topazdd_create_stream_context(struct topaz_dev_ctx *ctx, enum img_codec codec, + enc_cb cb, void *cb_priv, + void **dd_str_ctx, struct vidio_ddbufinfo **wb_data_info) +{ + struct img_comm_socket *p_sock; + struct event *p_event; + + p_sock = kmalloc(sizeof(*p_sock), GFP_KERNEL); + IMG_DBG_ASSERT(p_sock); + if (!p_sock) + return IMG_ERROR_OUT_OF_MEMORY; + + p_sock->sync_wb_mutex = kzalloc(sizeof(*p_sock->sync_wb_mutex), GFP_KERNEL); + if (!p_sock->sync_wb_mutex) { + kfree(p_sock); + return IMG_ERROR_OUT_OF_MEMORY; + } + mutex_init(p_sock->sync_wb_mutex); + + /* Allocate a Sync structure...*/ + p_event = kmalloc(sizeof(struct event *), GFP_KERNEL); + IMG_DBG_ASSERT(p_event); + if (!p_event) + return IMG_ERROR_OUT_OF_MEMORY; + + memset(p_event, 0, sizeof(struct event)); + + p_sock->event = (void *)p_event; + + if (!p_sock->event) { + mutex_destroy(p_sock->sync_wb_mutex); + kfree(p_sock->sync_wb_mutex); + p_sock->sync_wb_mutex = NULL; + kfree(p_sock); + return IMG_ERROR_OUT_OF_MEMORY; + } + + p_sock->low_cmd_cnt = 0xa5a5a5a5 % MAX_TOPAZ_CMD_COUNT; + p_sock->high_cmd_cnt = 0; + p_sock->msgs_sent = 0; + p_sock->ack_recv = 0; + p_sock->codec = codec; + p_sock->ctx = ctx; + p_sock->cb = cb; + p_sock->str_ctx = (struct topaz_stream_context *)cb_priv; + + init_work(&p_sock->work, stream_worker, HWA_ENCODER); + if (!p_sock->work) { + mutex_destroy(p_sock->sync_wb_mutex); + kfree(p_sock->sync_wb_mutex); + p_sock->sync_wb_mutex = NULL; + kfree(p_sock); + return IMG_ERROR_OUT_OF_MEMORY; + } + + wbfifo_clear(p_sock); + + *wb_data_info = g_aps_wb_data_info; + + *dd_str_ctx = (void *)p_sock; + +#ifdef DEBUG_ENCODER_DRIVE + pr_info("topazdd context created with codec %d\n", codec); +#endif + + return IMG_SUCCESS; +} + +static int topaz_upload_firmware(struct topaz_dev_ctx *ctx, enum img_codec codec) +{ +#ifdef DEBUG_ENCODER_DRIVE + pr_info("Loading firmware.\n"); +#endif + /* Upload FW */ + /* load and start MTX cores */ + ctx->fw_ctx.load_method = (enum mtx_load_method)g_load_method; + + topaz_setup_firmware(ctx, &ctx->fw_ctx, ctx->fw_ctx.load_method, + codec, topazdd_get_num_pipes(ctx)); + + if (!ctx->fw_ctx.initialized) { + pr_err("\nERROR: Firmware cannot be loaded!\n"); + return IMG_ERROR_UNDEFINED; + } + + comm_load_bias(ctx, ctx->fw_ctx.supported_codecs); + /* initialise read offset of firmware output fifo */ + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_FIRMWARE_REG_1 + + (MTX_SCRATCHREG_TOMTX << 2), 0); + + ctx->fw_uploaded = codec; + +#ifdef DEBUG_ENCODER_DRIVE + pr_info("firmware uploaded!\n"); +#endif + return IMG_SUCCESS; +} + +int topazdd_setup_stream_ctx(void *dd_str_ctx, unsigned short height, + unsigned short width, unsigned char *ctx_num, + unsigned int *used_sock) +{ + unsigned char idx; + struct img_fw_context *fw_ctx; + struct img_comm_socket *sock; + int res = IMG_ERROR_UNDEFINED; + unsigned int codec_mask = 0; + + sock = (struct img_comm_socket *)dd_str_ctx; + + comm_lock(sock->ctx, COMM_LOCK_BOTH); + + fw_ctx = &sock->ctx->fw_ctx; + + switch (sock->codec) { + case IMG_CODEC_JPEG: + codec_mask = CODEC_MASK_JPEG; + break; + case IMG_CODEC_H264_NO_RC: + case IMG_CODEC_H264_VBR: + case IMG_CODEC_H264_CBR: + case IMG_CODEC_H264_VCM: + case IMG_CODEC_H264_ERC: + codec_mask = CODEC_MASK_H264; + break; + case IMG_CODEC_H263_NO_RC: + case IMG_CODEC_H263_VBR: + case IMG_CODEC_H263_CBR: + case IMG_CODEC_H263_ERC: + codec_mask = CODEC_MASK_H263; + break; + case IMG_CODEC_MPEG4_NO_RC: + case IMG_CODEC_MPEG4_VBR: + case IMG_CODEC_MPEG4_CBR: + case IMG_CODEC_MPEG4_ERC: + codec_mask = CODEC_MASK_MPEG4; + break; + case IMG_CODEC_MPEG2_NO_RC: + case IMG_CODEC_MPEG2_VBR: + case IMG_CODEC_MPEG2_CBR: + case IMG_CODEC_MPEG2_ERC: + codec_mask = CODEC_MASK_MPEG2; + break; + + case IMG_CODEC_H264MVC_NO_RC: + case IMG_CODEC_H264MVC_VBR: + case IMG_CODEC_H264MVC_CBR: + case IMG_CODEC_H264MVC_ERC: + codec_mask = CODEC_MASK_H264MVC; + break; + default: + IMG_DBG_ASSERT("Impossible use case!\n" == NULL); + break; + } + /* Only do the following checks if some other firmware is loaded */ + if (sock->ctx->fw_uploaded != IMG_CODEC_NONE && + (sock->ctx->fw_uploaded != sock->codec || /* Different firmware is uploaded */ + /* We currently only support one JPEG context to be encoded at the same time */ + (sock->ctx->fw_uploaded == IMG_CODEC_JPEG && sock->ctx->used_socks))) { + if (!(fw_ctx->supported_codecs & codec_mask)) { + comm_unlock(sock->ctx, COMM_LOCK_BOTH); + res = IMG_ERROR_UNDEFINED; + pr_err("\nERROR: Incompatible firmware context types!. Required codec: 0x%x Loaded FW : 0x%x\n", + codec_mask, fw_ctx->supported_codecs); + return res; + } + } + + if (fw_ctx->initialized && sock->ctx->used_socks >= fw_ctx->num_contexts) { + /* the firmware can't support any more contexts */ + comm_unlock(sock->ctx, COMM_LOCK_BOTH); + pr_err("\nERROR: Firmware context limit reached!\n"); + return IMG_ERROR_UNDEFINED; + } + + /* Search for an Available socket. */ + IMG_DBG_ASSERT(TOPAZHP_MAX_POSSIBLE_STREAMS < (1 << 8)); + for (idx = 0; idx < TOPAZHP_MAX_POSSIBLE_STREAMS; idx++) { + if (!(sock->ctx->socks[idx])) { + unsigned int index = idx; + + sock->id = idx; + *ctx_num = idx; + *used_sock = index; + sock->ctx->socks[idx] = sock; + sock->ctx->used_socks++; + break; + } + } + + if (idx == TOPAZHP_MAX_POSSIBLE_STREAMS) { + comm_unlock(sock->ctx, COMM_LOCK_BOTH); + return IMG_ERROR_INVALID_SIZE; + } + + if (sock->codec == IMG_CODEC_JPEG) { + topaz_timeout_retries = TOPAZ_TIMEOUT_JPEG; + } else { + unsigned int mbs_per_pic = (height * width) / 256; + + if (topaz_timeout_retries < (mbs_per_pic + 10) * 100) + topaz_timeout_retries = (mbs_per_pic + 10) * 100; + } + + if (sock->ctx->fw_uploaded == IMG_CODEC_NONE) { +#ifdef DEBUG_ENCODER_DRIVE + pr_info("Loading a different firmware.\n"); +#endif + res = topaz_upload_firmware(sock->ctx, (enum img_codec)sock->codec); + if (!res) { + comm_unlock(sock->ctx, COMM_LOCK_BOTH); + res = IMG_ERROR_UNDEFINED; + pr_err("\nERROR: Firmware cannot be loaded!\n"); + return res; + } + } + + res = IMG_SUCCESS; + + comm_unlock(sock->ctx, COMM_LOCK_BOTH); + + return res; +} + +void topazdd_destroy_stream_ctx(void *dd_str_ctx) +{ + unsigned int idx; + struct img_comm_socket *sock; + + sock = (struct img_comm_socket *)dd_str_ctx; + + WARN_ON((!sock)); + if (!sock) { + pr_err("topazdd_destroy_sock: invalid sock\n"); + return; + } + + flush_work(sock->work); + + mutex_lock_nested(sock->sync_wb_mutex, SUBCLASS_TOPAZDD); + comm_lock(sock->ctx, COMM_LOCK_BOTH); + for (idx = 0; idx < TOPAZHP_MAX_POSSIBLE_STREAMS; idx++) { + if (sock->ctx->socks[idx] == sock) { + sock->ctx->used_socks--; + break; + } + } + +#ifdef DEBUG_ENCODER_DRIVE + pr_info("topazdd sock context closed\n"); +#endif + + /* Flush the MMU table cache (so it we can't accidentally access + * the freed device memory due to cache/table mismatch.) + */ + topaz_core_mmu_flush_cache(); + + /* + * if nIndex == TOPAZHP_MAX_POSSIBLE_STREAMS then OpenSocket succeeded + * and SetupSocket failed (maybe incompatible firmware) + */ + if (idx != TOPAZHP_MAX_POSSIBLE_STREAMS) { + /* + * Abort the stream first. + * This function can be called as a result of abnormal process + * exit, and since the hardware might be encoding some frame it + * means that the hardware still needs the context resources + * (buffers mapped to the hardware, etc), so we need to make + * sure that hardware encoding is aborted first before releasing + * the resources. + * This is important if you're doing several encodes + * simultaneously because releasing the resources too early will + * cause a page-fault that will halt all simultaneous encodes + * not just the one that caused the page-fault. + */ + struct mtx_tomtx_msg msg; + unsigned int wb_val = 0; + + wbfifo_clear(sock); + + msg.cmd_id = (enum mtx_cmd_id)(MTX_CMDID_ABORT | MTX_CMDID_PRIORITY | + MTX_CMDID_WB_INTERRUPT); + msg.data = 0; + msg.command_data_buf = NULL; + comm_send(sock, &msg, &wb_val); + sock->sync_waiting = TRUE; + sock->sync_wb_val = wb_val; + mutex_unlock((struct mutex *)sock->sync_wb_mutex); + + topazdd_wait_on_sync(sock, wb_val); + /* + * Set it to NULL here -not any time sooner-, we need it in case + * we had to abort the stream. + */ + sock->ctx->socks[idx] = NULL; + } + + comm_unlock(sock->ctx, COMM_LOCK_BOTH); + kfree(sock->event); + mutex_destroy(sock->sync_wb_mutex); + kfree(sock->sync_wb_mutex); + sock->sync_wb_mutex = NULL; + kfree(sock->work); + kfree(sock); +} + +/* + * topazdd_int_clear + */ +static void topazdd_int_clear(struct topaz_dev_ctx *ctx, unsigned int mask) +{ + unsigned long flags; + + spin_lock_irqsave(ctx->lock, flags); + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_INT_CLEAR, mask); + + spin_unlock_irqrestore(ctx->lock, (unsigned long)flags); +} + +unsigned char topazdd_get_pipe_usage(unsigned char pipe) +{ + IMG_DBG_ASSERT(pipe < TOPAZHP_MAX_NUM_PIPES); + if (pipe >= TOPAZHP_MAX_NUM_PIPES) + return 0; + + return g_pipe_usage[pipe]; +} + +void topazdd_set_pipe_usage(unsigned char pipe, unsigned char val) +{ + IMG_DBG_ASSERT(pipe < TOPAZHP_MAX_NUM_PIPES); + if (pipe < TOPAZHP_MAX_NUM_PIPES) + g_pipe_usage[pipe] = val; +} + +static unsigned int comm_get_consumer(struct topaz_dev_ctx *ctx) +{ + unsigned int reg; + + reg = VXE_RD_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_FIRMWARE_REG_1 + + (MTX_SCRATCHREG_TOMTX << 2)); + + return F_DECODE(reg, WB_CONSUMER); +} + +static void comm_set_consumer(struct topaz_dev_ctx *ctx, unsigned int consumer) +{ + unsigned int reg; + + reg = VXE_RD_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_FIRMWARE_REG_1 + + (MTX_SCRATCHREG_TOMTX << 2)); + + reg = F_INSERT(reg, consumer, WB_CONSUMER); + + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_FIRMWARE_REG_1 + + (MTX_SCRATCHREG_TOMTX << 2), reg); +} + +static unsigned int comm_get_producer(struct topaz_dev_ctx *ctx) +{ + unsigned int reg; + + reg = VXE_RD_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_FIRMWARE_REG_1 + + (MTX_SCRATCHREG_TOHOST << 2)); + + return F_DECODE(reg, WB_PRODUCER); +} + +static void comm_set_producer(struct topaz_dev_ctx *ctx, unsigned int producer) +{ + unsigned int reg; + + reg = VXE_RD_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_FIRMWARE_REG_1 + + (MTX_SCRATCHREG_TOHOST << 2)); + + reg = F_INSERT(reg, producer, WB_PRODUCER); + + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_FIRMWARE_REG_1 + + (MTX_SCRATCHREG_TOHOST << 2), reg); +} + +static int topazdd_init_comms(struct topaz_dev_ctx *ctx, unsigned int mmu_flags) +{ + unsigned int num_cores; + unsigned int i; + unsigned int reg; + + num_cores = topazdd_get_num_pipes(ctx); + + for (i = 0; i < num_cores; i++) { + unsigned int offset = REG_TOPAZHP_CORE_0 + (i * 4); + + ctx->hp_core_reg_addr[i] = (void *)topaz_mem_space[offset].cpu_addr; + + offset = REG_TOPAZHP_VLC_CORE_0 + (i * 4); + ctx->vlc_reg_addr[i] = (void *)topaz_mem_space[offset].cpu_addr; + } + + if (topaz_mmu_device_create(&ctx->topaz_mmu_ctx, mmu_flags) != IMG_SUCCESS) { + pr_err("\nERROR: Could not initialize MMU with selected parameters!\n"); + return IMG_ERROR_OUT_OF_MEMORY; + } + + /* Start up MMU support for each core (if MMU is switched on) */ + reg = (F_ENCODE(1, TOPAZHP_TOP_CR_IMG_TOPAZ_MTX_SOFT_RESET) | + F_ENCODE(1, TOPAZHP_TOP_CR_IMG_TOPAZ_CORE_SOFT_RESET) | + F_ENCODE(1, TOPAZHP_TOP_CR_IMG_TOPAZ_IO_SOFT_RESET)); + + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_SRST, reg); + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_SRST, 0x0); + + for (i = 0; i < num_cores; i++) { + unsigned int reset_bits = F_ENCODE(1, TOPAZHP_CR_TOPAZHP_IPE_SOFT_RESET) | + F_ENCODE(1, TOPAZHP_CR_TOPAZHP_SPE_SOFT_RESET) | + F_ENCODE(1, TOPAZHP_CR_TOPAZHP_PC_SOFT_RESET) | + F_ENCODE(1, TOPAZHP_CR_TOPAZHP_H264COMP_SOFT_RESET) | + F_ENCODE(1, TOPAZHP_CR_TOPAZHP_JMCOMP_SOFT_RESET) | + F_ENCODE(1, TOPAZHP_CR_TOPAZHP_PREFETCH_SOFT_RESET) | + F_ENCODE(1, TOPAZHP_CR_TOPAZHP_VLC_SOFT_RESET) | + F_ENCODE(1, TOPAZHP_CR_TOPAZHP_LTRITC_SOFT_RESET) | + F_ENCODE(1, TOPAZHP_CR_TOPAZHP_DB_SOFT_RESET); + +#ifdef TOPAZHP // TODO: strangely, this doesn't seem defined in the build... but we ARE topazhp... + reset_bits |= F_ENCODE(1, MVEA_CR_IMG_MVEA_SPE_SOFT_RESET(1)) | + F_ENCODE(1, MVEA_CR_IMG_MVEA_IPE_SOFT_RESET(1)); +#endif + + VXE_WR_REG32(ctx->hp_core_reg_addr[i], TOPAZHP_CR_TOPAZHP_SRST, reset_bits); + + VXE_WR_REG32(ctx->hp_core_reg_addr[i], TOPAZHP_CR_TOPAZHP_SRST, 0); + } + + ctx->topaz_mmu_ctx.ptd_phys_addr = ctx->ptd; + topaz_core_mmu_hw_setup(&ctx->topaz_mmu_ctx, ctx->multi_core_mem_addr); + + ctx->fw_uploaded = IMG_CODEC_NONE; + + g_core_rev = VXE_RD_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_TOPAZHP_CORE_REV); + g_core_rev &= + (MASK_TOPAZHP_TOP_CR_TOPAZHP_MAINT_REV | MASK_TOPAZHP_TOP_CR_TOPAZHP_MINOR_REV | + MASK_TOPAZHP_TOP_CR_TOPAZHP_MAJOR_REV); + g_core_des1 = VXE_RD_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_TOPAZHP_CORE_DES1); + + ctx->comm_tx_mutex = kzalloc(sizeof(*ctx->comm_tx_mutex), GFP_KERNEL); + if (!(ctx->comm_tx_mutex)) + return IMG_ERROR_OUT_OF_MEMORY; + + mutex_init(ctx->comm_tx_mutex); + + ctx->comm_rx_mutex = kzalloc(sizeof(*ctx->comm_rx_mutex), GFP_KERNEL); + if (!ctx->comm_rx_mutex) { + mutex_destroy(ctx->comm_tx_mutex); + kfree(ctx->comm_tx_mutex); + ctx->comm_tx_mutex = NULL; + pr_err("Memory allocation failed for mutex\n"); + return IMG_ERROR_OUT_OF_MEMORY; + } + mutex_init(ctx->comm_rx_mutex); + + g_aps_wb_data_info = kmalloc(sizeof(*g_aps_wb_data_info) * WB_FIFO_SIZE, GFP_KERNEL); + if (!g_aps_wb_data_info) { + mutex_destroy(ctx->comm_rx_mutex); + kfree(ctx->comm_rx_mutex); + ctx->comm_rx_mutex = NULL; + + mutex_destroy(ctx->comm_tx_mutex); + kfree(ctx->comm_tx_mutex); + ctx->comm_tx_mutex = NULL; + return IMG_ERROR_OUT_OF_MEMORY; + } + + /* Allocate WB buffers */ + for (i = 0; i < WB_FIFO_SIZE; i++) { + struct vidio_ddbufinfo *mem_info = &g_aps_wb_data_info[i]; + + if (topaz_mmu_alloc(ctx->topaz_mmu_ctx.mmu_context_handle, + ctx->vxe_arg, MMU_GENERAL_HEAP_ID, 1, + (enum sys_emem_attrib)(SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE), + COMM_WB_DATA_BUF_SIZE, 64, mem_info)) { + pr_err("mmu_alloc failed!\n"); + kfree(g_aps_wb_data_info); + return IMG_ERROR_OUT_OF_MEMORY; + } + } + + /* Initialise the COMM registers */ + comm_set_producer(ctx, 0); + + /* Must reset the Consumer register too, + * otherwise the COMM stack may be initialised incorrectly + */ + comm_set_consumer(ctx, 0); + + for (i = 0; i < TOPAZHP_MAX_POSSIBLE_STREAMS; i++) + ctx->socks[i] = NULL; + + ctx->used_socks = 0; + ctx->initialized = TRUE; + + return 0; +} + +static void topazdd_deinit_comms(struct topaz_dev_ctx *ctx) +{ + unsigned int idx; + struct img_fw_context *fw_ctx; + + fw_ctx = &ctx->fw_ctx; + + if (fw_ctx && fw_ctx->initialized) { + /* Stop the MTX */ + mtx_stop(fw_ctx); + mtx_wait_for_completion(fw_ctx); + } + + if (g_aps_wb_data_info) { + for (idx = 0; idx < WB_FIFO_SIZE; idx++) { + struct vidio_ddbufinfo *mem_info = &g_aps_wb_data_info[idx]; + + topaz_mmu_free(ctx->vxe_arg, mem_info); + } + kfree(g_aps_wb_data_info); + } + + /* Close all of the opened sockets */ + for (idx = 0; idx < TOPAZHP_MAX_POSSIBLE_STREAMS; idx++) { + if (ctx->socks[idx]) + topazdd_destroy_stream_ctx(ctx->socks[idx]); + } + + mutex_destroy(ctx->comm_tx_mutex); + kfree(ctx->comm_tx_mutex); + ctx->comm_tx_mutex = NULL; + + mutex_destroy(ctx->comm_rx_mutex); + kfree(ctx->comm_rx_mutex); + ctx->comm_rx_mutex = NULL; + + if (fw_ctx && fw_ctx->initialized) + mtx_deinitialize(fw_ctx); + + topaz_mmu_device_destroy(&ctx->topaz_mmu_ctx); + + ctx->fw_uploaded = IMG_CODEC_NONE; + ctx->initialized = FALSE; +} + +static void setup_topaz_mem(unsigned long long reg_base, unsigned int reg_size) +{ + unsigned int idx; + + /* set up the kernel virtual address for mem space access */ + for (idx = 0; idx < topaz_target_config.num_mem_spaces; idx++) { + unsigned long long offset = topaz_target_config.mem_spaces[idx].reg.addr; + + topaz_target_config.mem_spaces[idx].cpu_addr = reg_base + offset; + } +} + +/* + * topazdd_init + */ +int topazdd_init(unsigned long long reg_base, unsigned int reg_size, unsigned int mmu_flags, + void *vxe_arg, unsigned int ptd, void **data) +{ + struct topaz_dev_ctx *ctx; + int ret; + spinlock_t **lock; /* spinlock */ + + setup_topaz_mem(reg_base, reg_size); + + /* Allocate device structure...*/ + ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); + IMG_DBG_ASSERT(ctx); + if (!ctx) + return IMG_ERROR_OUT_OF_MEMORY; + + memset(ctx, 0, sizeof(*ctx)); + + lock = (spinlock_t **)&ctx->lock; + *lock = kzalloc(sizeof(spinlock_t), GFP_KERNEL); + + if (!(*lock)) { + pr_err("Memory allocation failed for spin-lock\n"); + kfree(ctx); + return IMG_ERROR_OUT_OF_MEMORY; + } + spin_lock_init(*lock); + g_lock = ctx->lock; + + *data = ctx; + ctx->initialized = FALSE; + + ctx->multi_core_mem_addr = (void *)topaz_mem_space[REG_TOPAZHP_MULTICORE].cpu_addr; + + if (!ctx->multi_core_mem_addr) { + kfree(&ctx->lock); + kfree(ctx); + return IMG_ERROR_DEVICE_NOT_FOUND; + } + + /* Now enabled interrupts */ + topazdd_int_enable(ctx, (MASK_TOPAZHP_TOP_CR_HOST_INTEN_MTX | + MASK_TOPAZHP_TOP_CR_HOST_TOPAZHP_MAS_INTEN | + MASK_TOPAZHP_TOP_CR_HOST_INTEN_MMU_FAULT | + MASK_TOPAZHP_TOP_CR_HOST_INTEN_MMU_FAULT_B)); + + ctx->vxe_arg = vxe_arg; + ctx->ptd = ptd; + + ret = topazdd_init_comms(ctx, mmu_flags); + if (ret) { + topazdd_int_disable(ctx, ~0); + kfree(&ctx->lock); + kfree(ctx); + return ret; + } + + comm_lock(ctx, COMM_LOCK_BOTH); + ret = topaz_upload_firmware(ctx, IMG_CODEC_H264_NO_RC); + comm_unlock(ctx, COMM_LOCK_BOTH); + + if (ret) { + topazdd_deinit_comms(ctx); + topazdd_int_disable(ctx, ~0); + kfree(&ctx->lock); + kfree(ctx); + return ret; + } + + /* Device now initailised...*/ + ctx->initialized = TRUE; + + /* Return success...*/ + return IMG_SUCCESS; +} + +/* + * topazdd_deinit + */ +void topazdd_deinit(void *data) +{ + struct topaz_dev_ctx *ctx = data; + unsigned int reg; + + /* If the interrupt was defined then it is also safe to clear interrupts + * and reset the core.... + */ + if (ctx->initialized) { + topazdd_deinit_comms(ctx); + + /* Disable interrupts...*/ + topazdd_int_disable(ctx, ~0); + + /* disable interrupts on Topaz core */ + reg = + VXE_RD_REG32(ctx->multi_core_mem_addr, + TOPAZHP_TOP_CR_MULTICORE_HOST_INT_ENAB); + + reg &= ~MASK_TOPAZHP_TOP_CR_HOST_INTEN_MTX; + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_HOST_INT_ENAB, reg); + + /* clear interrupt - just in case */ + VXE_WR_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_INT_CLEAR, + MASK_TOPAZHP_TOP_CR_INTCLR_MTX); + + g_lock = NULL; + kfree(&ctx->lock); + } + + kfree(data); +} + +static int comm_dispatch_in_msg(struct topaz_dev_ctx *ctx) +{ + unsigned int hw_fifo_producer; + unsigned int hw_fifo_consumer; + + hw_fifo_consumer = comm_get_consumer(ctx); + hw_fifo_producer = comm_get_producer(ctx); + + while (hw_fifo_consumer != hw_fifo_producer) { + struct img_writeback_msg *wb_msg; + unsigned char conn_id; + struct vidio_ddbufinfo *mem_info = &g_aps_wb_data_info[hw_fifo_consumer]; + enum mtx_cmd_id cmd_id; + + /* Update corresponding memory region */ + topaz_update_host_mem(ctx->vxe_arg, mem_info); + wb_msg = (struct img_writeback_msg *)(mem_info->cpu_virt); + + /* Copy to the corresponding SW fifo */ + conn_id = F_DECODE(wb_msg->cmd_word, MTX_MSG_CORE); + + /* Find corresponding Buffer Addr */ + cmd_id = (enum mtx_cmd_id)F_DECODE(wb_msg->cmd_word, MTX_MSG_MESSAGE_ID); +#ifdef DEBUG_ENCODER_DRIVER + if ((unsigned int)cmd_id == (unsigned int)MTX_MESSAGE_ACK) { + pr_debug("MSG_RX[%d]: 0x%03X %s (ACK) cmd_word: %#08x data: %#08x extra_data: %#08x writeback_val: %#08x\n", + F_DECODE(wb_msg->cmd_word, MTX_MSG_CORE), + hw_fifo_producer & 0x1f, + command_string[wb_msg->cmd_word & 0x1f], + wb_msg->cmd_word, wb_msg->data, + wb_msg->extra_data, wb_msg->writeback_val); + } else { +#ifdef ENABLE_PROFILING + struct timespec64 time; + + ktime_get_real_ts64(&time); + ctx->socks[conn_id]->fw_lat.end_time = + timespec64_to_ns((const struct timespec64 *)&time); + pr_err("fw encode time is %llu us for msg_id x%0x\n", + div_s64(ctx->socks[conn_id]->fw_lat.end_time - + ctx->socks[conn_id]->fw_lat.start_time, 1000), + wb_msg->writeback_val); +#endif + pr_debug("MSG_RX[%d]: 0x%03X CODED_BUFFER cmd_word: %#08x coded_package_consumed: %d\n", + F_DECODE(wb_msg->cmd_word, MTX_MSG_CORE), + hw_fifo_producer & 0x1f, + wb_msg->cmd_word, + wb_msg->coded_package_consumed_idx); + } +#endif + + /* If corresponding socket still exists, call the callback */ + if (ctx->socks[conn_id]) { + wbfifo_add(ctx->socks[conn_id], wb_msg); + schedule_work(ctx->socks[conn_id]->work); + } + + /* Activate corresponding FIFO + * proceed to the next one + */ + hw_fifo_consumer++; + + if (hw_fifo_consumer == WB_FIFO_SIZE) + hw_fifo_consumer = 0; + + comm_set_consumer(ctx, hw_fifo_consumer); + + /* + * We need to update the producer because we might have received a new + * message meanwhile. This new message won't trigger an interrupt and + * consequently will be lost till another message arrives + */ + hw_fifo_producer = comm_get_producer(ctx); + } + + return IMG_SUCCESS; +} + +/* + * topazdd_threaded_isr + */ +unsigned char topazdd_threaded_isr(void *inst_data) +{ + struct topaz_dev_ctx *ctx = *(struct topaz_dev_ctx **)inst_data; + + /* If interrupts not defined then...*/ + if (!ctx || !ctx->initialized) + return FALSE; + + /* Now dispatch the messages */ + comm_dispatch_in_msg(ctx); + + /* Signal this interrupt has been handled...*/ + return TRUE; +} + +/* + * topazdd_isr + */ +irqreturn_t topazdd_isr(void *inst_data) +{ + unsigned int reg; + unsigned int mmu_fault_mask = MASK_TOPAZHP_TOP_CR_INT_STAT_MMU_FAULT; + + struct topaz_dev_ctx *ctx = *(struct topaz_dev_ctx **)inst_data; + + /* More requesters with topaz hp */ + mmu_fault_mask |= MASK_TOPAZHP_TOP_CR_INTCLR_MMU_FAULT_B; + + /* If interrupts not defined then...*/ + if (!ctx || !ctx->initialized) + return IRQ_NONE; + + /* read device interrupt status */ + reg = VXE_RD_REG32(ctx->multi_core_mem_addr, TOPAZHP_TOP_CR_MULTICORE_INT_STAT); + + /* if interrupts enabled and fired...*/ + if (((reg & MASK_TOPAZHP_TOP_CR_INT_STAT_MTX) == (MASK_TOPAZHP_TOP_CR_INT_STAT_MTX))) { + /* Clear interrupt source...*/ + topazdd_int_clear(ctx, MASK_TOPAZHP_TOP_CR_INTCLR_MTX); + + /* Signal this interrupt has been handled...*/ + return IRQ_WAKE_THREAD; + } + + /* if page fault ever happenned */ + if (reg & (mmu_fault_mask)) { + static unsigned char dump_once = TRUE; + + if (dump_once) { + VXE_WR_REG32(ctx->multi_core_mem_addr, + TOPAZHP_TOP_CR_MULTICORE_HOST_INT_ENAB, 0); + + dump_once = FALSE; /* only on first page fault for readability */ + } + + /* Clear interrupt source...*/ + topazdd_int_clear(ctx, mmu_fault_mask); + + /* IT served, we might never reach that point on kernel crashes */ + return IRQ_HANDLED; + } + + /* Signal not this device...*/ + return IRQ_NONE; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_device.h b/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_device.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_device.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/topaz_device.h 2024-07-07 20:37:34.664306649 -0400 @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * topaz driver data strcutures + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#if !defined(__TOPAZ_DEVICE_H__) +#define __TOPAZ_DEVICE_H__ + +#include + +#include "fw_headers/topazscfwif.h" +#include "fw_headers/mtx_fwif.h" +#include "topazmmu.h" +#include "vid_buf.h" +#include "topaz_api.h" + +# define CODEC_MASK_JPEG 0x0001 +# define CODEC_MASK_MPEG2 0x0002 +# define CODEC_MASK_MPEG4 0x0004 +# define CODEC_MASK_H263 0x0008 +# define CODEC_MASK_H264 0x0010 +# define CODEC_MASK_H264MVC 0x0020 +# define CODEC_MASK_VP8 0x0040 +# define CODEC_MASK_H265 0x0080 +# define CODEC_MASK_FAKE 0x007F + +struct img_comm_socket; + +/*! + **************************************************************************** + Event object structure + **************************************************************************** + */ +struct event { + unsigned char signalled; +}; + +/* prototype for callback for incoming message */ +typedef void (*enc_cb)(struct img_writeback_msg *msg, void *priv); + +#ifdef ENABLE_PROFILING +struct enc_fw_latency { + unsigned int start_time; + unsigned int end_time; +}; +#endif + +struct mtx_tohost_msg { + enum mtx_message_id cmd_id; + unsigned int input_cmd_word; + unsigned char coded_pkg_idx; + unsigned int wb_val; + unsigned int data; + struct vidio_ddbufinfo *command_data_buf; +}; + +struct mtx_tomtx_msg { + enum mtx_cmd_id cmd_id; + unsigned int data; + struct vidio_ddbufinfo *command_data_buf; +}; + +/* + * This structure contains the device context. + */ +struct topaz_dev_ctx { + /* Parent context, needed to pass to mmu_alloc */ + void *vxe_arg; + + /* KM addresses for mem spaces */ + void *multi_core_mem_addr; + void *hp_core_reg_addr[TOPAZHP_MAX_NUM_PIPES]; + void *vlc_reg_addr[TOPAZHP_MAX_NUM_PIPES]; + + unsigned char initialized; /*!< Indicates that the device driver has been initialised */ + + unsigned int used_socks; + struct img_comm_socket *socks[TOPAZHP_MAX_POSSIBLE_STREAMS]; + + unsigned int fw_uploaded; + struct img_fw_context fw_ctx; + + void *lock; /* basic device level spinlock */ + struct mutex *comm_tx_mutex; + struct mutex *comm_rx_mutex; + + unsigned int ptd; + struct topaz_mmu_context topaz_mmu_ctx; +}; + +#define COMM_INCOMING_FIFO_SIZE (WB_FIFO_SIZE * 2) +struct img_comm_socket { + unsigned char id; + unsigned int low_cmd_cnt; /* count of low-priority commands sent to TOPAZ */ + unsigned int high_cmd_cnt; /* count of high-priority commands sent to TOPAZ */ + unsigned int last_sync; /* Last sync value sent */ + struct img_writeback_msg in_fifo[COMM_INCOMING_FIFO_SIZE]; + unsigned int in_fifo_consumer; + unsigned int in_fifo_producer; + void *work; + + enc_cb cb; /* User-provided callback function */ + struct topaz_stream_context *str_ctx; /* User-provided callback data */ + + void *event; + unsigned char sync_waiting; + unsigned int sync_wb_val; + struct mutex *sync_wb_mutex; + + unsigned int msgs_sent; + unsigned int ack_recv; + unsigned char is_serialized; + + unsigned int codec; + + struct topaz_dev_ctx *ctx; +#ifdef ENABLE_PROFILING + struct enc_fw_latency fw_lat; +#endif +}; + +unsigned char topazdd_threaded_isr(void *data); +irqreturn_t topazdd_isr(void *data); + +int topazdd_init(unsigned long long reg_base, unsigned int reg_size, + unsigned int mmu_flags, + void *vxe_arg, unsigned int ptd, void **data); +void topazdd_deinit(void *data); +unsigned int topazdd_get_num_pipes(struct topaz_dev_ctx *ctx); +unsigned int topazdd_get_core_rev(void); +unsigned int topazdd_get_core_des1(void); +unsigned char topazdd_is_idle(struct img_comm_socket *sock); + +int topazdd_upload_firmware(struct topaz_dev_ctx *ctx, enum img_codec codec); +int topazdd_create_stream_context(struct topaz_dev_ctx *ctx, enum img_codec codec, enc_cb cb, + void *cb_priv, void **dd_str_ctx, + struct vidio_ddbufinfo **wb_data_info); +void topazdd_destroy_stream_ctx(void *dd_str_ctx); +int topazdd_setup_stream_ctx(void *dd_str_ctx, unsigned short height, + unsigned short width, unsigned char *ctx_num, + unsigned int *used_sock); +int topazdd_send_msg(void *dd_str_ctx, enum mtx_cmd_id cmd_id, + unsigned int data, struct vidio_ddbufinfo *cmd_data_buf, + unsigned int *wb_val); +int topazdd_send_msg_with_sync(void *dd_str_ctx, enum mtx_cmd_id cmd_id, + unsigned int data, + struct vidio_ddbufinfo *cmd_data_buf); + +extern unsigned int mmu_control_val; + +#endif /* __TOPAZ_DEVICE_H__ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/topazmmu.c b/drivers/media/platform/imagination/vxe-vxd/encoder/topazmmu.c --- a/drivers/media/platform/imagination/vxe-vxd/encoder/topazmmu.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/topazmmu.c 2024-07-07 20:37:34.664306649 -0400 @@ -0,0 +1,741 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * topaz mmu function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "fw_headers/defs.h" +#include "img_errors.h" +#include "img_mem.h" +#include "img_mem_man.h" +#include "talmmu_api.h" +#include "topazmmu.h" +#include "vxe_public_regdefs.h" + +int use_extended_addressing; +unsigned int mmu_control_val; +unsigned char device_initialized = FALSE; + +/* + * These determine the sizes of the MMU heaps we are using. + * The tiled heap is set arbitrarily large at present. + */ +#define GENERALMMUHEAPLENGTH 0x40000000 + +/* + * This describes the heaps - the separate areas mapped by the MMU + * Currently we only use a single large heap as Topaz Core has no + * MMU specific memory features. + */ +struct talmmu_heap_info mmu_heap_info[HEAP_ID_NO_OF_HEAPS] = { + { MMU_GENERAL_HEAP_ID, TALMMU_HEAP_PERCONTEXT, TALMMU_HEAPFLAGS_NONE, "MEMSYSMEM", + 0x00400000, GENERALMMUHEAPLENGTH } +}; + +/* This describes the memory being mapped by the MMU */ +struct talmmu_devmem_info mmu_device_memory_info = { + /* ui32DeviceId */ + 1, + /* eMMUType */ + TALMMU_MMUTYPE_4K_PAGES_32BIT_ADDR, + /* eDevFlags */ + TALMMU_DEVFLAGS_NONE, + /* pszPageDirMemSpaceName */ + "MEMSYSMEM", + /* pszPageTableMemSpaceName */ + "MEMSYSMEM", + /* ui32PageSize */ + 4096, + /* ui32PageTableDirAlignment */ + 0 +}; + +/* + * mmu template is global. so we don't need to worry about maintaining device + * context + */ +void *mmu_template; + +/* + * Stream context is global. Can be modified in future to handle list of streams. + */ +struct mmu_str_context *str_ctx; + +/* + * Called once during initialization to initialize the MMU hardware, create + * the template and define the MMU heap. + * This is where talmmu initialization and template will be created. + * + * NOTE : We are not taking care of alignment here, need to be updated in + * mmu_device_memory_info. + */ +int topaz_mmu_device_create(struct topaz_mmu_context *mmu_context, unsigned int mmu_flags) +{ + void *topaz_multi_core_regid; + unsigned int hw_rev; + int result, i; + + use_extended_addressing = (mmu_flags & MMU_EXTENDED_ADDR_FLAG); + + /* Initialize TALMMU API and create a template */ + result = talmmu_init(); + IMG_DBG_ASSERT(result == 0); + + if (result != 0) { + pr_err("talmmu_init failed!\n"); + return IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + } + + /* + * We are reading the register and finding the mmu type, if needed this + * can be passed from the upper layers directly. + */ + + topaz_multi_core_regid = (void *)topaz_mem_space[REG_TOPAZHP_MULTICORE].cpu_addr; + + hw_rev = VXE_RD_REG32(topaz_multi_core_regid, TOPAZHP_TOP_CR_TOPAZHP_CORE_REV); + hw_rev &= + (MASK_TOPAZHP_TOP_CR_TOPAZHP_MAINT_REV | MASK_TOPAZHP_TOP_CR_TOPAZHP_MINOR_REV | + MASK_TOPAZHP_TOP_CR_TOPAZHP_MAJOR_REV); + + if (use_extended_addressing) { + unsigned int reg_val; + + /* Versions 3.6 and above may be 32-bit, 36-bit or 40-bit */ + reg_val = VXE_RD_REG32(topaz_multi_core_regid, TOPAZHP_TOP_CR_MULTICORE_HW_CFG); + + switch (F_DECODE(reg_val, TOPAZHP_TOP_CR_EXTENDED_ADDR_RANGE)) { + case 0: + mmu_device_memory_info.mmu_type = TALMMU_MMUTYPE_4K_PAGES_32BIT_ADDR; + break; + case 4: + mmu_device_memory_info.mmu_type = TALMMU_MMUTYPE_4K_PAGES_36BIT_ADDR; + break; + case 8: + mmu_device_memory_info.mmu_type = TALMMU_MMUTYPE_4K_PAGES_40BIT_ADDR; + break; + default: + pr_err("Unsupported MMU mode requested\n"); + return IMG_ERROR_NOT_SUPPORTED; + } + } + + result = talmmu_devmem_template_create(&mmu_device_memory_info, &mmu_template); + IMG_DBG_ASSERT(result == 0); + if (result != 0) { + pr_err("talmmu_devmem_template_create failed!\n"); + talmmu_deinit(); + return IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + } + + /* Add heaps to the template */ + for (i = 0; i < HEAP_ID_NO_OF_HEAPS; i++) { + result = talmmu_devmem_heap_add(mmu_template, &mmu_heap_info[i]); + IMG_DBG_ASSERT(result == 0); + if (result != 0) { + pr_err("talmmu_devmem_heap_add failed!\n"); + talmmu_devmem_template_destroy(mmu_template); + talmmu_deinit(); + return IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + } + } + + /* Create a context from the template */ + /* (Template, User allocated user ID) */ + result = talmmu_devmem_ctx_create(mmu_template, 1, &mmu_context->mmu_context_handle); + IMG_DBG_ASSERT(result == 0); + if (result != 0) { + pr_err("talmmu_devmem_ctx_create failed!\n"); + talmmu_devmem_template_destroy(mmu_template); + talmmu_deinit(); + return IMG_ERROR_COULD_NOT_OBTAIN_RESOURCE; + } + + topaz_core_mmu_flush_cache(); + + /* Initialise stream list. */ + lst_init(&mmu_context->str_list); + + device_initialized = TRUE; + + return IMG_SUCCESS; +} + +/* + * This function is used to destroy the MMU device context. + * NOTE: Destroy device automatically destroys any streams and frees and + * memory allocated using MMU_StreamMalloc(). + */ +int topaz_mmu_device_destroy(struct topaz_mmu_context *mmu_context) +{ + unsigned int result = 0; + struct mmu_str_context *str_ctx; + + /* Destroy all streams associated with the device. */ + str_ctx = lst_first(&mmu_context->str_list); + while (str_ctx) { + /* remove stream to list. */ + lst_remove(&mmu_context->str_list, str_ctx); + topaz_mmu_stream_destroy(mmu_context, str_ctx); + + /* See if there are more streams. */ + str_ctx = lst_first(&mmu_context->str_list); + } + + /* Destroy the device context */ + result = talmmu_devmem_ctx_destroy(mmu_context->mmu_context_handle); + if (result != IMG_SUCCESS) + return result; + + /* Destroy the template. */ + return talmmu_devmem_template_destroy(mmu_template); +} + +/* + * This function is used to create and initialize the MMU stream context. + */ +int topaz_mmu_stream_create(struct topaz_mmu_context *mmu_context, unsigned int km_str_id, + void *vxe_enc_ctx_arg, void **mmu_str_ctx) +{ + struct mmu_str_context *str_ctx; + + /* Validate inputs. */ + if (!device_initialized) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Allocate a stream context structure */ + str_ctx = kzalloc(sizeof(*str_ctx), GFP_KERNEL); + if (!str_ctx) + return IMG_ERROR_OUT_OF_MEMORY; + + str_ctx->km_str_id = km_str_id; + str_ctx->int_reg_num = 32; + str_ctx->vxe_enc_context = (struct vxe_enc_ctx *)vxe_enc_ctx_arg; + + /* copy the mmu context created earlier */ + str_ctx->mmu_context_handle = mmu_context->mmu_context_handle; + + *mmu_str_ctx = str_ctx; + + /* Add stream to list. */ + lst_add(&mmu_context->str_list, str_ctx); + + return IMG_SUCCESS; +} + +/* + * This function is used to destroy the MMU stream context. + * NOTE: Destroy automatically frees and memory allocated using + * mmu_stream_malloc(). + */ +int topaz_mmu_stream_destroy(struct topaz_mmu_context *mmu_context, + struct mmu_str_context *str_ctx) +{ + /* Validate inputs. */ + if (!str_ctx) + return IMG_ERROR_INVALID_PARAMETERS; + + /* remove stream to list. */ + lst_remove(&mmu_context->str_list, str_ctx); + + kfree(str_ctx); + + return IMG_SUCCESS; +} + +static unsigned int set_attributes(enum sys_emem_attrib mem_attrib) +{ + unsigned int attrib = 0; + + if (mem_attrib & SYS_MEMATTRIB_CACHED) + attrib |= MEM_ATTR_CACHED; + + if (mem_attrib & SYS_MEMATTRIB_UNCACHED) + attrib |= MEM_ATTR_UNCACHED; + + if (mem_attrib & SYS_MEMATTRIB_WRITECOMBINE) + attrib |= MEM_ATTR_WRITECOMBINE; + + if (mem_attrib & SYS_MEMATTRIB_SECURE) + attrib |= MEM_ATTR_SECURE; + + return attrib; +} + +int topaz_mmu_alloc(void *mmu_context_handle, struct vxe_enc_ctx *vxe_enc_ctx_arg, + enum topaz_mmu_eheap_id heap_id, unsigned int mem_heap_id, + enum sys_emem_attrib mem_attrib, unsigned int size, unsigned int alignment, + struct vidio_ddbufinfo *ddbuf_info) +{ + int result = 0; + void *devmem_heap_hndl; + struct vxe_enc_ctx *ctx; + struct vxe_dev *vxe; + unsigned int flags = 0; + unsigned int attributes = 0; + + if (!mmu_context_handle) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Set buffer size. */ + ddbuf_info->buf_size = size; + + /* Round size up to next multiple of physical pages */ + if ((size % HOST_MMU_PAGE_SIZE) != 0) + size = ((size / HOST_MMU_PAGE_SIZE) + 1) * HOST_MMU_PAGE_SIZE; + + /* Allocate memory */ + ctx = vxe_enc_ctx_arg; + vxe = ctx->dev; + + attributes = set_attributes(mem_attrib); + + result = img_mem_alloc(vxe->dev, ctx->mem_ctx, mem_heap_id, + size, (enum mem_attr)attributes, (int *)&ddbuf_info->buff_id); + if (result != IMG_SUCCESS) + goto error_alloc; + + ddbuf_info->is_internal = 1; + + /* TODO need to check more on attributes from memmgr_km */ + if (mem_attrib & SYS_MEMATTRIB_SECURE) { + ddbuf_info->cpu_virt = NULL; + } else { + /* Map the buffer to CPU */ + result = img_mem_map_km(ctx->mem_ctx, ddbuf_info->buff_id); + if (result) { + dev_err(vxe->dev, "%s: failed to map buf to cpu!(%d)\n", + __func__, result); + goto error_get_heap_handle; + } + ddbuf_info->cpu_virt = img_mem_get_kptr(ctx->mem_ctx, ddbuf_info->buff_id); + } + + /* Get heap handle */ + result = talmmu_get_heap_handle(heap_id, mmu_context_handle, &devmem_heap_hndl); + if (result != IMG_SUCCESS) + goto error_get_heap_handle; + + /* Allocate device "virtual" memory. */ + result = talmmu_devmem_addr_alloc(mmu_context_handle, devmem_heap_hndl, + size, alignment, &ddbuf_info->hndl_memory); + if (result != IMG_SUCCESS) + goto error_mem_map_ext_mem; + + /* Get the device virtual address. */ + result = talmmu_get_dev_virt_addr(ddbuf_info->hndl_memory, &ddbuf_info->dev_virt); + if (result != IMG_SUCCESS) + goto error_get_dev_virt_addr; + + result = img_mmu_map(ctx->mmu_ctx, ctx->mem_ctx, ddbuf_info->buff_id, ddbuf_info->dev_virt, + flags); + if (result != IMG_SUCCESS) + goto error_map_dev; + + return IMG_SUCCESS; + +error_map_dev: +error_get_dev_virt_addr: + talmmu_devmem_addr_free(ddbuf_info->hndl_memory); + ddbuf_info->hndl_memory = NULL; +error_mem_map_ext_mem: +error_get_heap_handle: + img_mem_free(ctx->mem_ctx, ddbuf_info->buff_id); +error_alloc: + return result; +} + +/* + * mmu_stream_malloc + */ +int topaz_mmu_stream_alloc(void *mmu_str_hndl, enum topaz_mmu_eheap_id heap_id, + unsigned int mem_heap_id, enum sys_emem_attrib mem_attrib, + unsigned int size, unsigned int alignment, + struct vidio_ddbufinfo *ddbuf_info) +{ + struct mmu_str_context *str_ctx; + + /* Validate inputs. */ + if (!mmu_str_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + str_ctx = (struct mmu_str_context *)mmu_str_hndl; + + /* Check if device level heap. */ + switch (heap_id) { + case MMU_GENERAL_HEAP_ID: + break; + + default: + return IMG_ERROR_INVALID_PARAMETERS; + } + + ddbuf_info->kmstr_id = str_ctx->km_str_id; + + /* Allocate device memory. */ + return (topaz_mmu_alloc(str_ctx->mmu_context_handle, str_ctx->vxe_enc_context, + heap_id, mem_heap_id, mem_attrib, size, alignment, ddbuf_info)); +} + +/* + * mmu_stream_map_ext_sg + */ +int topaz_mmu_stream_map_ext_sg(void *mmu_str_hndl, enum topaz_mmu_eheap_id heap_id, + void *sgt, unsigned int size, unsigned int alignment, + enum sys_emem_attrib mem_attrib, void *cpu_linear_addr, + struct vidio_ddbufinfo *ddbuf_info, unsigned int *buff_id) +{ + int result; + void *devmem_heap_hndl; + struct mmu_str_context *str_ctx; + struct vxe_enc_ctx *ctx; + struct vxe_dev *vxe; + + if (!mmu_str_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + str_ctx = (struct mmu_str_context *)mmu_str_hndl; + + ctx = str_ctx->vxe_enc_context; + vxe = ctx->dev; + + /* Check if device level heap. */ + switch (heap_id) { + case MMU_GENERAL_HEAP_ID: + break; + + default: + return IMG_ERROR_INVALID_PARAMETERS; + } + + if (!str_ctx->mmu_context_handle) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Set buffer size. */ + ddbuf_info->buf_size = size; + + /* Round size up to next multiple of physical pages */ + if ((size % HOST_MMU_PAGE_SIZE) != 0) + size = ((size / HOST_MMU_PAGE_SIZE) + 1) * HOST_MMU_PAGE_SIZE; + + result = img_mem_import(vxe->dev, ctx->mem_ctx, ddbuf_info->buf_size, + (enum mem_attr)set_attributes(mem_attrib), (int *)buff_id); + if (result != IMG_SUCCESS) + return result; + + if (mem_attrib & SYS_MEMATTRIB_SECURE) + ddbuf_info->cpu_virt = NULL; + + ddbuf_info->buff_id = *buff_id; + ddbuf_info->is_internal = 0; + + ddbuf_info->kmstr_id = str_ctx->km_str_id; + + /* Set buffer size. */ + ddbuf_info->buf_size = size; + + /* Ensure the address of the buffer is at least page aligned. */ + ddbuf_info->cpu_virt = cpu_linear_addr; + + /* Get heap handle */ + result = talmmu_get_heap_handle(heap_id, str_ctx->mmu_context_handle, &devmem_heap_hndl); + if (result != IMG_SUCCESS) + return result; + + /* Allocate device "virtual" memory. */ + result = talmmu_devmem_addr_alloc(str_ctx->mmu_context_handle, devmem_heap_hndl, + size, alignment, &ddbuf_info->hndl_memory); + if (result != IMG_SUCCESS) + return result; + + /* Get the device virtual address. */ + result = talmmu_get_dev_virt_addr(ddbuf_info->hndl_memory, &ddbuf_info->dev_virt); + if (result != IMG_SUCCESS) + goto error_get_dev_virt_addr; + + result = img_mmu_map_sg(ctx->mmu_ctx, ctx->mem_ctx, ddbuf_info->buff_id, sgt, + ddbuf_info->dev_virt, mem_attrib); + if (result != IMG_SUCCESS) + goto error_map_dev; + + return IMG_SUCCESS; + +error_map_dev: +error_get_dev_virt_addr: + talmmu_devmem_addr_free(ddbuf_info->hndl_memory); + ddbuf_info->hndl_memory = NULL; + return result; +} + +/* + * topaz_mmu_stream_map_ext + */ +int topaz_mmu_stream_map_ext(void *mmu_str_hndl, enum topaz_mmu_eheap_id heap_id, + unsigned int buff_id, unsigned int size, unsigned int alignment, + enum sys_emem_attrib mem_attrib, void *cpu_linear_addr, + struct vidio_ddbufinfo *ddbuf_info) +{ + int result = 0; + void *devmem_heap_hndl; + struct vxe_enc_ctx *ctx; + struct mmu_str_context *str_ctx; + + if (!mmu_str_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + str_ctx = (struct mmu_str_context *)mmu_str_hndl; + + /* Check if device level heap. */ + switch (heap_id) { + case MMU_GENERAL_HEAP_ID: + break; + + default: + return IMG_ERROR_INVALID_PARAMETERS; + } + + /* Round size up to next multiple of physical pages */ + if ((size % HOST_MMU_PAGE_SIZE) != 0) + size = ((size / HOST_MMU_PAGE_SIZE) + 1) * HOST_MMU_PAGE_SIZE; + + ddbuf_info->buff_id = buff_id; + ddbuf_info->is_internal = 0; + + ddbuf_info->kmstr_id = str_ctx->km_str_id; + + /* Set buffer size. */ + ddbuf_info->buf_size = size; + + /* Ensure the address of the buffer is at least page aligned. */ + ddbuf_info->cpu_virt = cpu_linear_addr; + + /* Get heap handle */ + result = talmmu_get_heap_handle(heap_id, str_ctx->mmu_context_handle, + &devmem_heap_hndl); + if (result != IMG_SUCCESS) + return result; + + /* Allocate device "virtual" memory. */ + result = talmmu_devmem_addr_alloc(str_ctx->mmu_context_handle, + devmem_heap_hndl, size, alignment, + &ddbuf_info->hndl_memory); + if (result != IMG_SUCCESS) + return result; + + /* Get the device virtual address. */ + result = talmmu_get_dev_virt_addr(ddbuf_info->hndl_memory, &ddbuf_info->dev_virt); + if (result != IMG_SUCCESS) + return result; + + /* + * Map device memory (allocated from outside VDEC) + * into the stream PTD. + */ + ctx = str_ctx->vxe_enc_context; + + return img_mmu_map(ctx->mmu_ctx, ctx->mem_ctx, ddbuf_info->buff_id, ddbuf_info->dev_virt, + mem_attrib); +} + +/* + * topaz_mmu_free + */ +int topaz_mmu_free(struct vxe_enc_ctx *vxe_enc_ctx_arg, struct vidio_ddbufinfo *ddbuf_info) +{ + int result = 0; + struct vxe_enc_ctx *ctx; + + /* Validate inputs. */ + if (!ddbuf_info) + return IMG_ERROR_INVALID_PARAMETERS; + + /* Unmap the memory mapped to the device */ + ctx = vxe_enc_ctx_arg; + result = img_mmu_unmap(ctx->mmu_ctx, ctx->mem_ctx, ddbuf_info->buff_id); + + /* + * Unmapping the memory mapped to the device - done + * Free the memory. + */ + result = talmmu_devmem_addr_free(ddbuf_info->hndl_memory); + + if (ddbuf_info->is_internal) + img_mem_free(ctx->mem_ctx, ddbuf_info->buff_id); + + return result; +} + +/* + * topaz_mmu_free_mem. + * This should be used only to free the stream memory. + */ +int topaz_mmu_stream_free(void *mmu_str_hndl, struct vidio_ddbufinfo *ddbuf_info) +{ + struct mmu_str_context *str_ctx; + + if (!mmu_str_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + str_ctx = (struct mmu_str_context *)mmu_str_hndl; + + return topaz_mmu_free(str_ctx->vxe_enc_context, ddbuf_info); +} + +/* + * topaz_mmu_free_mem_sg. + * This should be used only to free the stream memory. + */ +int topaz_mmu_stream_free_sg(void *mmu_str_hndl, struct vidio_ddbufinfo *ddbuf_info) +{ + int result = 0; + struct vxe_enc_ctx *ctx; + struct mmu_str_context *str_ctx; + + /* Validate inputs. */ + if (!ddbuf_info || !mmu_str_hndl) + return IMG_ERROR_INVALID_PARAMETERS; + + str_ctx = (struct mmu_str_context *)mmu_str_hndl; + + /* Unmap the memory mapped to the device */ + ctx = str_ctx->vxe_enc_context; + + result = img_mmu_unmap(ctx->mmu_ctx, ctx->mem_ctx, ddbuf_info->buff_id); + + /* + * Unmapping the memory mapped to the device - done + * Free the memory. + */ + result = talmmu_devmem_addr_free(ddbuf_info->hndl_memory); + + /* + * for external mem manager buffers, just cleanup the idr list and + * buffer objects + */ + img_mem_free_bufid(ctx->mem_ctx, ddbuf_info->buff_id); + + return result; +} + +int topaz_update_device_mem(struct vxe_enc_ctx *vxe_enc_ctx_arg, + struct vidio_ddbufinfo *ddbuf_info) +{ + struct vxe_enc_ctx *ctx = vxe_enc_ctx_arg; + + return img_mem_sync_cpu_to_device(ctx->mem_ctx, + ddbuf_info->buff_id); +} + +int topaz_update_host_mem(struct vxe_enc_ctx *vxe_enc_ctx_arg, + struct vidio_ddbufinfo *ddbuf_info) +{ + struct vxe_enc_ctx *ctx = vxe_enc_ctx_arg; + + return img_mem_sync_device_to_cpu(ctx->mem_ctx, + ddbuf_info->buff_id); +} + +/* + * Called for each Topaz core when MMU support is activated, sets up the MMU + * hardware for the specified core. + */ +int topaz_core_mmu_hw_setup(struct topaz_mmu_context *mmu_context, void *core_reg) +{ + unsigned int cmd; + + /* Bypass all requesters while MMU is being configured */ + cmd = F_ENCODE(1, TOPAZHP_TOP_CR_MMU_BYPASS_TOPAZ); + VXE_WR_REG32(core_reg, TOPAZHP_TOP_CR_MMU_CONTROL0, cmd); + + VXE_WR_REG32(core_reg, TOPAZHP_TOP_CR_MMU_DIR_LIST_BASE(0), mmu_context->ptd_phys_addr); + + cmd = VXE_RD_REG32(core_reg, TOPAZHP_TOP_CR_MMU_DIR_LIST_BASE(0)); + +#ifdef DEBUG_ENCODER_DRIVER + pr_info("Page table directory at physical address 0x%08x\n", cmd); +#endif + /* + * Set up the Index Register (to point to the base register) + * We're setting all fields to zero (all flags pointing to directory bank 0) + */ + cmd = 0; + + /* Now enable MMU access for all requesters + * 36-bit actually means "not 32-bit" + */ + cmd = F_ENCODE(use_extended_addressing ? 1 : 0, TOPAZHP_TOP_CR_MMU_ENABLE_36BIT_ADDRESSING); + VXE_WR_REG32(core_reg, TOPAZHP_TOP_CR_MMU_CONTROL2, cmd); + + mmu_control_val = F_ENCODE(0, TOPAZHP_TOP_CR_MMU_BYPASS_TOPAZ); + cmd = F_ENCODE(0, TOPAZHP_TOP_CR_MMU_BYPASS_TOPAZ); + + VXE_WR_REG32(core_reg, TOPAZHP_TOP_CR_MMU_CONTROL0, cmd); + + return 0; +} + +/* + * topaz_core_mmu_flush_cache + */ +int topaz_core_mmu_flush_cache(void) +{ + static void *core_reg; + unsigned int reg_value; + unsigned long flags; + + if (!core_reg) + core_reg = (void *)topaz_mem_space[REG_TOPAZHP_MULTICORE].cpu_addr; + + /* TODO we can have global mutex or local based on need */ + spin_lock_irqsave(g_lock, flags); + + reg_value = VXE_RD_REG32(core_reg, TOPAZHP_TOP_CR_MMU_CONTROL0); + + /* PAUSE */ + reg_value |= F_ENCODE(1, TOPAZHP_TOP_CR_MMU_PAUSE); + VXE_WR_REG32(core_reg, TOPAZHP_TOP_CR_MMU_CONTROL0, reg_value); + + { + unsigned int i, mem_req_reg; + +wait_till_idle: + for (i = 0; i < 10; i++) { + mem_req_reg = VXE_RD_REG32(core_reg, TOPAZHP_TOP_CR_MMU_MEM_REQ); + if (mem_req_reg != 0) + goto wait_till_idle; + } + } + + /* Set invalidate */ + reg_value |= F_ENCODE(1, TOPAZHP_TOP_CR_MMU_INVALDC); + VXE_WR_REG32(core_reg, TOPAZHP_TOP_CR_MMU_CONTROL0, reg_value); + + /* Clear invalidate */ + reg_value &= ~((unsigned int)F_ENCODE(1, TOPAZHP_TOP_CR_MMU_INVALDC)); + VXE_WR_REG32(core_reg, TOPAZHP_TOP_CR_MMU_CONTROL0, reg_value); + + /* UNPAUSE */ + reg_value &= ~((unsigned int)F_ENCODE(1, TOPAZHP_TOP_CR_MMU_PAUSE)); + VXE_WR_REG32(core_reg, TOPAZHP_TOP_CR_MMU_CONTROL0, reg_value); + + /* TODO we can have global mutex or local based on need */ + spin_unlock_irqrestore(g_lock, flags); + + return 0; +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/topazmmu.h b/drivers/media/platform/imagination/vxe-vxd/encoder/topazmmu.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/topazmmu.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/topazmmu.h 2024-07-07 20:37:34.664306649 -0400 @@ -0,0 +1,199 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * topaz mmu header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef TOPAZZ_MMU_H_ +#define TOPAZZ_MMU_H_ + +#include +#include +#include +#include + +#include "talmmu_api.h" +#include "vxe_enc.h" +#include "img_mem.h" +#include "target_config.h" + +/* Page size of the device MMU */ +#define DEV_MMU_PAGE_SIZE (0x1000) +/* Page alignment of the device MMU */ +#define DEV_MMU_PAGE_ALIGNMENT (0x1000) + +#define HOST_MMU_PAGE_SIZE PAGE_SIZE + +/* + * This structure contains the stream context. + * @brief MMU Stream Context + * @devmem_ctx_hndl: Handle for MMU context. + * @dev_ctx: Pointer to device context. + * @ctx_id: MMU context Id. + * km_str_id: Stream ID used in communication with new KM interface + */ +struct mmu_str_context { + void **link; // to be able to maintain in single linked list. + void *mmu_context_handle; + unsigned int int_reg_num; + unsigned int km_str_id; + /* vxe encoder context. Need in stream context to access mem_ctx. */ + struct vxe_enc_ctx *vxe_enc_context; + struct lst_t ddbuf_list; +}; + +struct topaz_mmu_context { + void *mmu_context_handle; + unsigned int ptd_phys_addr; + struct lst_t str_list; +}; + +/* + * This type defines the MMU heaps. + * @0: General heap ID. + */ +enum topaz_mmu_eheap_id { + MMU_GENERAL_HEAP_ID = 0x00, + /* Do not remove - keeps count of size */ + HEAP_ID_NO_OF_HEAPS +}; + +/* Function definitions */ + +/* + * Called once during initialization to initialize the MMU hardware, create + * the template and define the MMU heap. + * This is where talmmu initialization and template will be created. + * + * NOTE : We are not taking care of alignment here, need to be updated in + * mmu_device_memory_info. + */ +int topaz_mmu_device_create(struct topaz_mmu_context *mmu_context, unsigned int mmu_flags); + +/* + * @Function mmu_device_destroy + * @Description + * This function is used to destroy the MMU device context. + * NOTE: Destroy device automatically destroys any streams and frees and + * memory allocated using MMU_StreamMalloc(). + * @Return IMG_SUCCESS or an error code. + */ +int topaz_mmu_device_destroy(struct topaz_mmu_context *mmu_context); + +/* + * @Function mmu_stream_create + * @Description + * This function is used to create and initialize the MMU stream context. + * @Input km_str_id : Stream Id used in communication with KM driver. + * @Return IMG_SUCCESS or an error code. + * + * Context ID is 1, since we are creating single stream. + */ +int topaz_mmu_stream_create(struct topaz_mmu_context *mmu_context, unsigned int km_str_id, + void *vxe_enc_ctx_arg, void **mmu_str_ctx); + +/* + * @Function mmu_stream_destroy + * @Description + * This function is used to destroy the MMU stream context. + * NOTE: Destroy automatically frees and memory allocated using + * mmu_stream_malloc(). + * @Input str_ctx : The MMU stream handle. + * @Return IMG_SUCCESS or an error code. + */ +int topaz_mmu_stream_destroy(struct topaz_mmu_context *mmu_context, + struct mmu_str_context *str_ctx); + +int topaz_mmu_alloc(void *mmu_context_handle, struct vxe_enc_ctx *vxe_enc_ctx_arg, + enum topaz_mmu_eheap_id heap_id, unsigned int mem_heap_id, + enum sys_emem_attrib mem_attrib, unsigned int size, unsigned int alignment, + struct vidio_ddbufinfo *ddbuf_info); +/* + * @Function mmu_stream_malloc + */ +int topaz_mmu_stream_alloc(void *mmu_str_hndl, enum topaz_mmu_eheap_id heap_id, + unsigned int mem_heap_id, + enum sys_emem_attrib mem_attrib, + unsigned int size, + unsigned int alignment, + struct vidio_ddbufinfo *ddbuf_info); + +/* + * @Function mmu_stream_map_ext_sg + */ +int topaz_mmu_stream_map_ext_sg(void *mmu_str_hndl, enum topaz_mmu_eheap_id heap_id, + void *sgt, + unsigned int size, + unsigned int alignment, + enum sys_emem_attrib mem_attrib, + void *cpu_linear_addr, + struct vidio_ddbufinfo *ddbuf_info, + unsigned int *buff_id); + +/* + * @Function mmu_stream_map_ext + */ +int topaz_mmu_stream_map_ext(void *mmu_str_hndl, enum topaz_mmu_eheap_id heap_id, + unsigned int buff_id, unsigned int size, + unsigned int alignment, + enum sys_emem_attrib mem_attrib, + void *cpu_linear_addr, + struct vidio_ddbufinfo *ddbuf_info); + +/* topaz core mmu hardware setup */ +int topaz_core_mmu_hw_setup(struct topaz_mmu_context *mmu_context, void *core_reg); + +/* topaz core mmu flush cache */ +int topaz_core_mmu_flush_cache(void); + +/* + * @Function mmu_free + * + * Free memory allocated with mmu_alloc + */ +int topaz_mmu_free(struct vxe_enc_ctx *vxe_enc_ctx_arg, + struct vidio_ddbufinfo *ddbuf_info); + +/* + * @Function mmu_free_mem. + * + * NOTE : This should be used only to free the stream memory. + */ +int topaz_mmu_stream_free(void *mmu_str_hndl, struct vidio_ddbufinfo *ddbuf_info); + +/* + * @Function mmu_free_mem_sg. + * + * NOTE : This should be used only to free the stream memory. + */ +int topaz_mmu_stream_free_sg(void *mmu_str_hndl, struct vidio_ddbufinfo *ddbuf_info); + +/* + * @Function update_device_mem + * + * Update the memory to the device + */ +int topaz_update_device_mem(struct vxe_enc_ctx *vxe_enc_ctx_arg, + struct vidio_ddbufinfo *ddbuf_info); + +/* + * @Function update_host_mem + * + * Update the memory to the host + */ +int topaz_update_host_mem(struct vxe_enc_ctx *vxe_enc_ctx_arg, + struct vidio_ddbufinfo *ddbuf_info); + +/* Global */ +extern struct mem_space topaz_mem_space[]; +extern void *g_lock; + +#endif /* TOPAZZ_MMU_H_ */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_enc.c b/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_enc.c --- a/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_enc.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_enc.c 2024-07-07 20:37:34.664306649 -0400 @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Encoder Interface API function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#include +#include +#include +#include +#include + +#include "img_mem_man.h" +#include "topazmmu.h" +#include "vxe_enc.h" + +#define MAX(a, b, type) ({ \ + type __a = a; \ + type __b = b; \ + (((__a) >= (__b)) ? (__a) : (__b)); }) + +void mmu_callback(enum mmu_callback_type callback_type, + int buff_id, void *data) +{ + topaz_core_mmu_flush_cache(); +} + +int vxe_init_mem(struct vxe_dev *vxe) +{ + int ret; + + /* Create memory management context for HW buffers */ + ret = img_mem_create_ctx(&vxe->drv_ctx.mem_ctx); + if (ret) { + dev_err(vxe->dev, "%s: failed to create mem context (err:%d)!\n", + __func__, ret); + goto create_mem_context_failed; + } + + ret = img_mmu_ctx_create(vxe->dev, 40 /* mmu_addr_width is 40 */, + vxe->drv_ctx.mem_ctx, vxe->drv_ctx.internal_heap_id, + mmu_callback, vxe, &vxe->drv_ctx.mmu_ctx); + if (ret) { + dev_err(vxe->dev, "%s:%d: failed to create mmu ctx\n", + __func__, __LINE__); + goto create_mmu_context_failed; + } + + ret = img_mmu_get_ptd(vxe->drv_ctx.mmu_ctx, &vxe->drv_ctx.ptd); + if (ret) { + dev_err(vxe->dev, "%s:%d: failed to get PTD\n", + __func__, __LINE__); + goto get_ptd_failed; + } + + return 0; + +get_ptd_failed: + img_mmu_ctx_destroy(vxe->drv_ctx.mmu_ctx); +create_mmu_context_failed: + img_mem_destroy_ctx(vxe->drv_ctx.mem_ctx); +create_mem_context_failed: + return ret; +} + +void vxe_deinit_mem(struct vxe_dev *vxe) +{ + if (vxe->drv_ctx.mmu_ctx) { + img_mmu_ctx_destroy(vxe->drv_ctx.mmu_ctx); + vxe->drv_ctx.mmu_ctx = NULL; + } + + if (vxe->drv_ctx.mem_ctx) { + img_mem_destroy_ctx(vxe->drv_ctx.mem_ctx); + vxe->drv_ctx.mem_ctx = NULL; + } + + /* Deinitialize memory management component */ + while (!list_empty(&vxe->drv_ctx.heaps)) { + struct vxe_heap *heap; + + heap = list_first_entry(&vxe->drv_ctx.heaps, struct vxe_heap, list); + __list_del_entry(&heap->list); + img_mem_del_heap(heap->id); + kfree(heap); + } + + vxe->drv_ctx.internal_heap_id = VXE_INVALID_ID; + + img_mem_exit(); +} + +void vxe_create_ctx(struct vxe_dev *vxe, struct vxe_enc_ctx *ctx) +{ + ctx->mem_ctx = vxe->drv_ctx.mem_ctx; + ctx->mmu_ctx = vxe->drv_ctx.mmu_ctx; +} + +int calculate_h264_level(unsigned int width, unsigned int height, unsigned int framerate, + unsigned char rc_enable, unsigned int bitrate, + unsigned char lossless, + enum sh_profile_type profile_type, + unsigned int max_num_ref_frames) +{ + unsigned int level = 0, mbf = 0, mbs = 0, temp_level = 0, dpb_mbs; + unsigned int num = 1, den = 1; + unsigned int lossless_min_level = 320; + + mbf = (width * height) / 256; + mbs = mbf * framerate; + + if (mbf > 36864) { + pr_warn("WARNING: Frame size is too high for maximum supported level!\n"); + level = 520; + } else if (mbf > 22080) { + level = 510; + } else if (mbf > 8704) { + level = 500; + } else if (mbf > 8192) { + level = 420; + } else if (mbf > 5120) { + level = 400; + } else if (mbf > 3600) { + level = 320; + } else if (mbf > 1620) { + level = 310; + } else if (mbf > 792) { + level = 220; + } else if (mbf > 396) { + level = 210; + } else if (mbf > 99) { + level = 110; + } else { + level = 100; + } + + dpb_mbs = mbf * max_num_ref_frames; + + if (dpb_mbs > 184320) { + pr_warn("ERROR: Decoded picture buffer is too high for supported level!\n"); + return -1; + } else if (dpb_mbs > 110400) { + temp_level = 510; + } else if (dpb_mbs > 34816) { + temp_level = 500; + } else if (dpb_mbs > 32768) { + temp_level = 420; + } else if (dpb_mbs > 20480) { + temp_level = 400; + } else if (dpb_mbs > 18000) { + temp_level = 320; + } else if (dpb_mbs > 8100) { + temp_level = 310; + } else if (dpb_mbs > 4752) { + temp_level = 220; + } else if (dpb_mbs > 2376) { + temp_level = 210; + } else if (dpb_mbs > 900) { + temp_level = 120; + } else if (dpb_mbs > 396) { + temp_level = 110; + } else { + temp_level = 100; + } + + level = MAX(level, temp_level, unsigned int); + + /* now restrict based on the number of macroblocks per second */ + if (mbs > 2073600) { + pr_err("ERROR: Macroblock processing rate is too high for supported level!\n"); + return -1; + } else if (mbs > 983040) { + temp_level = 520; + } else if (mbs > 589824) { + temp_level = 510; + } else if (mbs > 522240) { + temp_level = 500; + } else if (mbs > 245760) { + temp_level = 420; + } else if (mbs > 216000) { + temp_level = 400; + } else if (mbs > 108000) { + temp_level = 320; + } else if (mbs > 40500) { + temp_level = 310; + } else if (mbs > 20250) { + temp_level = 300; + } else if (mbs > 19800) { + temp_level = 220; + } else if (mbs > 11880) { + temp_level = 210; + } else if (mbs > 6000) { + temp_level = 130; + } else if (mbs > 3000) { + temp_level = 120; + } else if (mbs > 1485) { + temp_level = 110; + } else { + temp_level = 100; + } + + level = MAX(level, temp_level, unsigned int); + + if (rc_enable) { + /* + * SH_PROFILE_H10P and SH_PROFILE_H422P are + * not valid choices for HW_3_X, skipping + */ + if (profile_type == SH_PROFILE_HP) { + num = 5; + den = 4; + } else if (profile_type == SH_PROFILE_H444P) { + num = 4; + den = 1; + } + + if (bitrate > ((135000000 * num) / den)) + temp_level = 510; + else if (bitrate > ((50000000 * num) / den)) + temp_level = 500; + else if (bitrate > ((20000000 * num) / den)) + temp_level = 410; + else if (bitrate > ((14000000 * num) / den)) + temp_level = 320; + else if (bitrate > ((10000000 * num) / den)) + temp_level = 310; + else if (bitrate > ((4000000 * num) / den)) + temp_level = 300; + else if (bitrate > ((2000000 * num) / den)) + temp_level = 210; + else if (bitrate > ((768000 * num) / den)) + temp_level = 200; + else if (bitrate > ((384000 * num) / den)) + temp_level = 130; + else if (bitrate > ((192000 * num) / den)) + temp_level = 120; + else if (bitrate > ((128000 * num) / den)) + temp_level = 110; + else if (bitrate > ((64000 * num) / den)) + temp_level = 101; + else + temp_level = 100; + + level = MAX(level, temp_level, unsigned int); + } else { + level = 510; + } + + if (lossless) + level = MAX(level, lossless_min_level, unsigned int); + + return level; +} + +enum sh_profile_type find_h264_profile(unsigned char lossless, + unsigned char h264_use_default_scaling_list, + unsigned int custom_quant_mask, + unsigned char h264_8x8_transform, + unsigned char enable_mvc, + unsigned int b_frame_count, + unsigned char interlaced, + unsigned char h264_cabac, + unsigned int weighted_prediction_mode, + unsigned int weighted_implicit_bi_pred) +{ + enum sh_profile_type profile = SH_PROFILE_BP; + + if (lossless) + profile = SH_PROFILE_H444P; + else if (h264_use_default_scaling_list || custom_quant_mask || + h264_8x8_transform || enable_mvc) + profile = SH_PROFILE_HP; + else if ((b_frame_count > 0) || interlaced || h264_cabac || + weighted_prediction_mode || weighted_implicit_bi_pred) + profile = SH_PROFILE_MP; + + return profile; +} + +void vxe_fill_default_src_frame_params(struct vxe_buffer *buf) +{ + buf->src_frame.component_count = 0; /* Unset in IMG */ + buf->src_frame.format = IMG_CODEC_420_YUV; /* Unset in IMG */ + buf->src_frame.component_offset[0] = 0; + buf->src_frame.component_offset[1] = 0; + buf->src_frame.component_offset[2] = 0; + buf->src_frame.bottom_component_offset[0] = 0; /* Unset in IMG */ + buf->src_frame.bottom_component_offset[1] = 0; /* Unset in IMG */ + buf->src_frame.bottom_component_offset[2] = 0; /* Unset in IMG */ + buf->src_frame.component_info[0].step = 0; + buf->src_frame.component_info[0].width = 0; + buf->src_frame.component_info[0].height = 0; + buf->src_frame.component_info[0].phys_width = 0; + buf->src_frame.component_info[0].phys_height = 0; + buf->src_frame.component_info[1].step = 0; + buf->src_frame.component_info[1].width = 0; + buf->src_frame.component_info[1].height = 0; + buf->src_frame.component_info[1].phys_width = 0; + buf->src_frame.component_info[1].phys_height = 0; + buf->src_frame.component_info[2].step = 0; + buf->src_frame.component_info[2].width = 0; + buf->src_frame.component_info[2].height = 0; + buf->src_frame.component_info[2].phys_width = 0; + buf->src_frame.component_info[2].phys_height = 0; + buf->src_frame.field0_y_offset = 0; + buf->src_frame.field1_y_offset = 0; + buf->src_frame.field0_u_offset = 0; + buf->src_frame.field1_u_offset = 0; + buf->src_frame.field0_v_offset = 0; + buf->src_frame.field1_v_offset = 0; + buf->src_frame.imported = FALSE; +} + +void vxe_fill_default_params(struct vxe_enc_ctx *ctx) +{ + int i, j; + unsigned short h264_rounding_offsets[18][4] = { + {683, 683, 683, 683}, /* 0 I-Slice - INTRA4 LUMA */ + {683, 683, 683, 683}, /* 1 P-Slice - INTRA4 LUMA */ + {683, 683, 683, 683}, /* 2 B-Slice - INTRA4 LUMA */ + + {683, 683, 683, 683}, /* 3 I-Slice - INTRA8 LUMA */ + {683, 683, 683, 683}, /* 4 P-Slice - INTRA8 LUMA */ + {683, 683, 683, 683}, /* 5 B-Slice - INTRA8 LUMA */ + + {341, 341, 341, 341}, /* 6 P-Slice - INTER8 LUMA */ + {341, 341, 341, 341}, /* 7 B-Slice - INTER8 LUMA */ + + {683, 683, 683, 000}, /* 8 I-Slice - INTRA16 LUMA */ + {683, 683, 683, 000}, /* 9 P-Slice - INTRA16 LUMA */ + {683, 683, 683, 000}, /* 10 B-Slice - INTRA16 LUMA */ + + {341, 341, 341, 341}, /* 11 P-Slice - INTER16 LUMA */ + {341, 341, 341, 341}, /* 12 B-Slice - INTER16 LUMA */ + + {683, 683, 683, 000}, /* 13 I-Slice - INTRA16 CR */ + {683, 683, 683, 000}, /* 14 P-Slice - INTRA16 CR */ + {683, 683, 683, 000}, /* 15 B-Slice - INTRA16 CR */ + + {341, 341, 341, 000 }, /* 16 P-Slice - INTER16 CHROMA */ + {341, 341, 341, 000 } /* 17 B-Slice - INTER16 CHROMA */ + }; + + ctx->vparams.csc_preset = IMG_CSC_NONE; + ctx->vparams.slices_per_picture = 1; + ctx->vparams.is_interleaved = FALSE; + ctx->vparams.constrained_intra = FALSE; + ctx->vparams.h264_8x8 = TRUE; + ctx->vparams.bottom_field_first = FALSE; + ctx->vparams.arbitrary_so = FALSE; + ctx->vparams.cabac_enabled = TRUE; + ctx->vparams.cabac_bin_limit = 2800; + ctx->vparams.cabac_bin_flex = 2800; + ctx->vparams.deblock_idc = 0; + ctx->vparams.output_reconstructed = FALSE; + ctx->vparams.f_code = 4; + ctx->vparams.fine_y_search_size = 2; + ctx->vparams.no_offscreen_mv = FALSE; + ctx->vparams.idr_period = 1800; /* 60 * 30fps */ + ctx->vparams.intra_cnt = 30; + ctx->vparams.vop_time_resolution = 15; + ctx->vparams.enc_features.disable_bpic_ref1 = FALSE; + ctx->vparams.enc_features.disable_bpic_ref0 = FALSE; + ctx->vparams.enc_features.disable_bframes = FALSE; + ctx->vparams.enc_features.restricted_intra_pred = FALSE; + ctx->vparams.enable_sel_stats_flags = 0; + ctx->vparams.enable_inp_ctrl = FALSE; + ctx->vparams.enable_air = FALSE; + ctx->vparams.num_air_mbs = -1; + ctx->vparams.air_threshold = -1; + ctx->vparams.air_skip_cnt = -1; + ctx->vparams.enable_cumulative_biases = FALSE; + ctx->vparams.enable_host_bias = TRUE; + ctx->vparams.enable_host_qp = FALSE; + ctx->vparams.use_default_scaling_list = FALSE; + ctx->vparams.use_custom_scaling_lists = 0; + ctx->vparams.pps_scaling = 0; + ctx->vparams.disable_bit_stuffing = TRUE; + ctx->vparams.coded_skipped_index = 3; + ctx->vparams.inter_intra_index = 3; + ctx->vparams.mpeg2_intra_dc_precision = 0; + ctx->vparams.carc = 0; + ctx->vparams.carc_baseline = 0; + ctx->vparams.carc_threshold = 1; + ctx->vparams.carc_cutoff = 15; + ctx->vparams.carc_neg_range = 5; + ctx->vparams.carc_neg_scale = 12; + ctx->vparams.carc_pos_range = 5; + ctx->vparams.carc_pos_scale = 12; + ctx->vparams.carc_shift = 3; + ctx->vparams.weighted_prediction = FALSE; + ctx->vparams.vp_weighted_implicit_bi_pred = 0; + ctx->vparams.insert_hrd_params = FALSE; + ctx->vparams.intra_refresh = 0; + ctx->vparams.chunks_per_mb = 64; + ctx->vparams.max_chunks = 160; + ctx->vparams.priority_chunks = 64; + ctx->vparams.mbps = 0; + ctx->vparams.multi_reference_p = FALSE; + ctx->vparams.ref_spacing = 0; + ctx->vparams.spatial_direct = FALSE; + ctx->vparams.vp_adaptive_rounding_disable = 0; + + for (i = 0; i < 18; i++) { + for (j = 0; j < 4; j++) { + ctx->vparams.vp_adaptive_rounding_offsets[i][j] = + h264_rounding_offsets[i][j]; + } + } + + ctx->vparams.debug_crcs = 0; + ctx->vparams.enable_mvc = FALSE; + ctx->vparams.mvc_view_idx = 65535; + ctx->vparams.high_latency = TRUE; + ctx->vparams.disable_bh_rounding = FALSE; + ctx->vparams.no_sequence_headers = FALSE; + ctx->vparams.auto_encode = FALSE; + ctx->vparams.slice_level = FALSE; + ctx->vparams.coded_header_per_slice = FALSE; + ctx->vparams.auto_expand_pipes = FALSE; + ctx->vparams.enable_lossless = FALSE; + ctx->vparams.lossless_8x8_prefilter = FALSE; + ctx->vparams.enable_scaler = FALSE; + ctx->vparams.line_counter_enabled = FALSE; + + ctx->rc.intra_freq = 30; + ctx->rc.initial_qp_i = 0; + ctx->rc.initial_qp_p = 0; + ctx->rc.initial_qp_b = 0; + + ctx->rc.min_qp = 0; + ctx->rc.max_qp = 0; + ctx->rc.rc_enable = TRUE; + + ctx->rc.hierarchical = FALSE; + + ctx->rc.enable_slice_bob = FALSE; + ctx->rc.max_slice_bob = 2; + ctx->rc.slice_bob_qp = 44; + + ctx->rc.qcp_offset = 0; + ctx->rc.sc_detect_disable = FALSE; + ctx->rc.slice_byte_limit = 0; + ctx->rc.slice_mb_limit = 0; + ctx->rc.rc_mode = IMG_RCMODE_VBR; + ctx->rc.rc_vcm_mode = IMG_RC_VCM_MODE_DEFAULT; + ctx->rc.rc_cfs_max_margin_perc = 9; + ctx->rc.disable_frame_skipping = FALSE; + ctx->rc.disable_vcm_hardware = FALSE; + + ctx->s_fmt_flags = 0; + + ctx->above_mb_params_sgt[0].sgl = NULL; + ctx->above_mb_params_sgt[1].sgl = NULL; +} + +unsigned int vxe_get_sizeimage(int w, int h, struct vxe_enc_fmt *fmt, unsigned char plane_id) +{ + return (ALIGN_16(w) * ALIGN_16(h) * fmt->size_num[plane_id] / fmt->size_den[plane_id]); +} + +unsigned int vxe_get_stride(int w, struct vxe_enc_fmt *fmt) +{ + return ALIGN(w * fmt->bytes_pp, HW_ALIGN); +} diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_enc.h b/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_enc.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_enc.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_enc.h 2024-07-07 20:37:34.664306649 -0400 @@ -0,0 +1,255 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * encoder interface header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _VXE_ENC_H +#define _VXE_ENC_H + +#include +#include +#include +#include +#include "topaz_api.h" + +#define HW_ALIGN 64 +#define MB_SIZE 16 +#define VXE_INVALID_ID (-1) +#define OCM_RAM_POOL_CHUNK_SIZE (32 * 1024) + +enum { + Q_ENC_DATA_SRC = 0, + Q_ENC_DATA_DST = 1, + Q_ENC_DATA_FORCE32BITS = 0x7FFFFFFFU +}; + +enum { + IMG_ENC_FMT_TYPE_CAPTURE = 0x01, + IMG_ENC_FMT_TYPE_OUTPUT = 0x10, + IMG_ENC_FMT_TYPE_FORCE32BITS = 0x7FFFFFFFU +}; + +enum vxe_map_flags { + VXE_MAP_FLAG_NONE = 0x0, + VXE_MAP_FLAG_READ_ONLY = 0x1, + VXE_MAP_FLAG_WRITE_ONLY = 0x2, + VXE_MAP_FLAG_FORCE32BITS = 0x7FFFFFFFU +}; + +/* + * struct vxe_enc_fmt - contains info for each supported video format + */ +struct vxe_enc_fmt { + unsigned int fourcc; + unsigned int num_planes; + unsigned int type; + union { + enum img_standard std; + enum img_format fmt; + }; + unsigned int min_bufs; + unsigned int size_num[MAX_PLANES]; + unsigned int size_den[MAX_PLANES]; + unsigned int bytes_pp; + enum img_csc_preset csc_preset; +}; + +/* + * struct vxe_buffer - contains info for all buffers + */ +struct vxe_buffer { + struct v4l2_m2m_buffer buffer; + unsigned int index; + unsigned int buf_map_id; + struct vidio_ddbufinfo buf_info; + union { + struct img_frame src_frame; + struct img_coded_buffer coded_buffer; + }; + struct img_buffer y_buffer; + struct img_buffer u_buffer; + struct img_buffer v_buffer; + unsigned char src_slot_num; + unsigned char mapped; +}; + +/* + * struct vxe_heap - node for heaps list + * @id: heap id + * @list: Entry in + */ +struct vxe_heap { + int id; + struct list_head list; +}; + +/* Driver context */ +struct vxe_drv_ctx { + /* Available memory heaps. List of */ + struct list_head heaps; + /* heap id for all internal allocations */ + int internal_heap_id; + /* Memory Management context for driver */ + struct mem_ctx *mem_ctx; + /* MMU context for driver */ + struct mmu_ctx *mmu_ctx; + /* PTD */ + unsigned int ptd; +}; + +/* + * struct vxe_dev - The struct containing encoder driver internal parameters. + */ +struct vxe_dev { + void *dev; + struct video_device *vfd; + struct v4l2_device ti_vxe_dev; + struct platform_device *plat_dev; + struct v4l2_m2m_dev *m2m_dev; + struct mutex *mutex; + int module_irq; + struct idr *streams; + void __iomem *reg_base; + void *topaz_dev_ctx; + struct vxe_drv_ctx drv_ctx; + /* dummy context for MMU mappings and allocations */ + struct vxe_enc_ctx *ctx; + unsigned int num_pipes; + + /* The variables defined below are used in RTOS only. */ + /* This variable holds queue handler */ + void *vxe_worker_queue_handle; + void *vxe_worker_queue_sem_handle; + + /* On Chip Memory Pool for above MB params struct */ + /* Supporting only 2 max instances (upto 1080p resolutions) to make use of this */ + void *ocm_ram_chunk[2]; //each chunk of 32KB + void *ram_chunk_owner[2]; + +}; + +#define S_FMT_FLAG_OUT_RECV 0x1 +#define S_FMT_FLAG_CAP_RECV 0x2 +#define S_FMT_FLAG_STREAM_CREATED 0x4 + +#define VXE_ENCODER_MAX_WIDTH 1920 +#define VXE_ENCODER_MIN_WIDTH 64 +#define VXE_ENCODER_MAX_HEIGHT 1088 +#define VXE_ENCODER_MIN_HEIGHT 64 + +#define VXE_ENCODER_DEFAULT_HEIGHT 240 +#define VXE_ENCODER_DEFAULT_WIDTH 416 +#define VXE_ENCODER_INITIAL_QP_I 18 +#define VXE_ENCODER_DEFAULT_FRAMERATE 30 + +/* + * struct vxe_enc_q_data - contains queue data information + * + * @fmt: format info + * @width: frame width + * @height: frame height + * @bytesperline: bytes per line in memory + * @size_image: image size in memory + */ +struct vxe_enc_q_data { + struct vxe_enc_fmt *fmt; + unsigned int width; + unsigned int height; + unsigned int bytesperline[MAX_PLANES]; + unsigned int size_image[MAX_PLANES]; + unsigned char streaming; +}; + +#ifdef ENABLE_PROFILING +struct enc_drv_latency { + unsigned int start_time; + unsigned int end_time; +}; +#endif + +/* + * struct vxe_ctx - The struct containing stream context parameters. + */ +struct vxe_enc_ctx { + struct v4l2_fh fh; + struct vxe_dev *dev; + void **enc_context; + void *topaz_str_context; + struct mutex *mutex; + unsigned char core_streaming; + struct img_enc_caps caps; + struct img_rc_params rc; + struct img_video_params vparams; + struct vxe_enc_q_data out_queue; + struct vxe_enc_q_data cap_queue; + struct mem_ctx *mem_ctx; + struct mmu_ctx *mmu_ctx; + /* list open_slots*/ + unsigned char s_fmt_flags; + struct h264_vui_params vui_params; + struct h264_crop_params crop_params; + struct h264_sequence_header_params sh_params; + unsigned char eos; + unsigned char flag_last; + unsigned int coded_packages_per_frame; /* How many slices per frame */ + unsigned int available_coded_packages; + unsigned int available_source_frames; + unsigned int frames_encoding; + unsigned int frame_num; + unsigned int last_frame_num; + unsigned int cap_seq; /* sequence number on capture port */ + unsigned int out_seq; /* sequence number on output port */ + + enum v4l2_colorspace colorspace; + enum v4l2_xfer_func xfer_func; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_quantization quantization; + enum v4l2_hsv_encoding hsv_enc; + + /* The below variable used only in Rtos */ + void *mm_return_resource; /* Place holder for CB to application */ + void *stream_worker_queue_handle; + void *stream_worker_queue_sem_handle; + void *work; + struct vxe_enc_q_data q_data[2]; + struct v4l2_ctrl_handler v4l2_ctrl_hdl; + struct sg_table above_mb_params_sgt[2]; + +#ifdef ENABLE_PROFILING + struct enc_drv_latency drv_lat; +#endif +}; + +int vxe_init_mem(struct vxe_dev *vxe); +void vxe_deinit_mem(struct vxe_dev *vxe); +void vxe_create_ctx(struct vxe_dev *vxe, struct vxe_enc_ctx *ctx); +int calculate_h264_level(unsigned int width, unsigned int height, unsigned int framerate, + unsigned char rc_enable, unsigned int bitrate, + unsigned char lossless, + enum sh_profile_type profile_type, + unsigned int max_num_ref_frames); +enum sh_profile_type find_h264_profile(unsigned char lossless, + unsigned char h264_use_default_scaling_list, + unsigned int custom_quant_mask, + unsigned char h264_8x8_transform, + unsigned char enable_mvc, + unsigned int b_frame_count, + unsigned char interlaced, + unsigned char h264_cabac, + unsigned int weighted_prediction_mode, + unsigned int weighted_implicit_bi_pred); +void vxe_fill_default_src_frame_params(struct vxe_buffer *buf); +void vxe_fill_default_params(struct vxe_enc_ctx *ctx); +unsigned int vxe_get_sizeimage(int w, int h, struct vxe_enc_fmt *fmt, unsigned char plane_id); +unsigned int vxe_get_stride(int w, struct vxe_enc_fmt *fmt); + +#endif /* _VXE_ENC_H */ diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_public_regdefs.h b/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_public_regdefs.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_public_regdefs.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_public_regdefs.h 2024-07-07 20:37:34.664306649 -0400 @@ -0,0 +1,926 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * encoder public register definitions + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef __VXE_PUBLIC_REGDEFS_H__ +#define __VXE_PUBLIC_REGDEFS_H__ + +#include +#include +#include +#include + +/* Write to the register */ +#define VXE_WR_REG32(base, offs, val) \ + (iowrite32((val), (void *)((offs) + (unsigned long)(base)))) + +/* Read the register */ +#define VXE_RD_REG32(base, offs) \ + (ioread32((void *)((base) + (offs)))) + +#define VXE_POLL_REG32_ISEQ(base, offs, val, mask, cnt) \ + (ioreg32_poll_iseq((unsigned long)(base) + (offs), val, mask, cnt)) + +#define REG_BASE_HOST 0x00000000 +#define REG_OFFSET_TOPAZ_MTX 0x00000800 +#define REG_START_TOPAZ_MTX_HOST (REG_BASE_HOST + REG_OFFSET_TOPAZ_MTX) + +static inline int ioreg32_poll_iseq(unsigned long addr, + unsigned int req_val, unsigned int mask, unsigned int cnt) +{ + unsigned int count, val; + unsigned int res = 0; + + /* Add high-frequency poll loops. */ + cnt += 10; + + /* + * High-frequency loop (designed for shorter hardware latency such as + * reset). + */ + for (count = 0; count < cnt; count++) { + /* Read from the device */ + val = ioread32((void *)addr); + val = (val & mask); + + if (val == req_val) { + res = 0; + break; + } + + /* + * Sleep to wait for hardware. + * Period is selected to allow for high-frequency polling + * (5us, e.g. reset) over the first 10 iterations, then + * reverting to a lower-frequency (100us, e.g. DMA) for the + * remainder. + */ + if (count < 10) + usleep_range(5, 5); + else + usleep_range(100, 100); + } + + if (res || count >= cnt) { + pr_info("Poll failed!\n"); + res = -1; + } + + return res; +} + +/* + * DMAC configuration values: + */ +/*! The maximum number of channels in the SoC */ +#define DMAC_MAX_CHANNELS (1) + +/* Register CR_TOPAZHP_CORE_REV */ +#define TOPAZHP_TOP_CR_TOPAZHP_CORE_REV 0x03D0 +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_MAINT_REV 0x000000FF +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_MAINT_REV 0 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_MAINT_REV 0x03D0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_MAINT_REV 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_MINOR_REV 0x0000FF00 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_MINOR_REV 8 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_MINOR_REV 0x03D0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_MINOR_REV 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_MAJOR_REV 0x00FF0000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_MAJOR_REV 16 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_MAJOR_REV 0x03D0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_MAJOR_REV 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_DESIGNER 0xFF000000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_DESIGNER 24 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_DESIGNER 0x03D0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_DESIGNER 0 + +/* Register CR_TOPAZHP_CORE_DES1 */ +#define TOPAZHP_TOP_CR_TOPAZHP_CORE_DES1 0x03E0 + +/* Register CR_MULTICORE_HW_CFG */ +#define TOPAZHP_TOP_CR_MULTICORE_HW_CFG 0x0058 +#define MASK_TOPAZHP_TOP_CR_NUM_CORES_SUPPORTED 0x0000001F +#define SHIFT_TOPAZHP_TOP_CR_NUM_CORES_SUPPORTED 0 +#define REGNUM_TOPAZHP_TOP_CR_NUM_CORES_SUPPORTED 0x0058 +#define SIGNED_TOPAZHP_TOP_CR_NUM_CORES_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_NUM_MTX_SUPPORTED 0x00000700 +#define SHIFT_TOPAZHP_TOP_CR_NUM_MTX_SUPPORTED 8 +#define REGNUM_TOPAZHP_TOP_CR_NUM_MTX_SUPPORTED 0x0058 +#define SIGNED_TOPAZHP_TOP_CR_NUM_MTX_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_NUM_CORES_PER_MTX 0x00070000 +#define SHIFT_TOPAZHP_TOP_CR_NUM_CORES_PER_MTX 16 +#define REGNUM_TOPAZHP_TOP_CR_NUM_CORES_PER_MTX 0x0058 +#define SIGNED_TOPAZHP_TOP_CR_NUM_CORES_PER_MTX 0 + +#define MASK_TOPAZHP_TOP_CR_EXTENDED_ADDR_RANGE 0x0F000000 +#define SHIFT_TOPAZHP_TOP_CR_EXTENDED_ADDR_RANGE 24 +#define REGNUM_TOPAZHP_TOP_CR_EXTENDED_ADDR_RANGE 0x0058 +#define SIGNED_TOPAZHP_TOP_CR_EXTENDED_ADDR_RANGE 0 + +/* Register CR_MULTICORE_SRST */ +#define TOPAZHP_TOP_CR_MULTICORE_SRST 0x0000 +#define MASK_TOPAZHP_TOP_CR_IMG_TOPAZ_MTX_SOFT_RESET 0x00000001 +#define SHIFT_TOPAZHP_TOP_CR_IMG_TOPAZ_MTX_SOFT_RESET 0 +#define REGNUM_TOPAZHP_TOP_CR_IMG_TOPAZ_MTX_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_TOP_CR_IMG_TOPAZ_MTX_SOFT_RESET 0 + +#define MASK_TOPAZHP_TOP_CR_IMG_TOPAZ_IO_SOFT_RESET 0x00000002 +#define SHIFT_TOPAZHP_TOP_CR_IMG_TOPAZ_IO_SOFT_RESET 1 +#define REGNUM_TOPAZHP_TOP_CR_IMG_TOPAZ_IO_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_TOP_CR_IMG_TOPAZ_IO_SOFT_RESET 0 + +#define MASK_TOPAZHP_TOP_CR_IMG_TOPAZ_CORE_SOFT_RESET 0x00000004 +#define SHIFT_TOPAZHP_TOP_CR_IMG_TOPAZ_CORE_SOFT_RESET 2 +#define REGNUM_TOPAZHP_TOP_CR_IMG_TOPAZ_CORE_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_TOP_CR_IMG_TOPAZ_CORE_SOFT_RESET 0 + +/* Register CR_MULTICORE_INT_STAT */ +#define TOPAZHP_TOP_CR_MULTICORE_INT_STAT 0x0004 +#define MASK_TOPAZHP_TOP_CR_INT_STAT_DMAC 0x00000001 +#define SHIFT_TOPAZHP_TOP_CR_INT_STAT_DMAC 0 +#define REGNUM_TOPAZHP_TOP_CR_INT_STAT_DMAC 0x0004 +#define SIGNED_TOPAZHP_TOP_CR_INT_STAT_DMAC 0 + +#define MASK_TOPAZHP_TOP_CR_INT_STAT_MTX 0x00000002 +#define SHIFT_TOPAZHP_TOP_CR_INT_STAT_MTX 1 +#define REGNUM_TOPAZHP_TOP_CR_INT_STAT_MTX 0x0004 +#define SIGNED_TOPAZHP_TOP_CR_INT_STAT_MTX 0 + +#define MASK_TOPAZHP_TOP_CR_INT_STAT_MTX_HALT 0x00000004 +#define SHIFT_TOPAZHP_TOP_CR_INT_STAT_MTX_HALT 2 +#define REGNUM_TOPAZHP_TOP_CR_INT_STAT_MTX_HALT 0x0004 +#define SIGNED_TOPAZHP_TOP_CR_INT_STAT_MTX_HALT 0 + +#define MASK_TOPAZHP_TOP_CR_INT_STAT_MMU_FAULT 0x00000078 +#define SHIFT_TOPAZHP_TOP_CR_INT_STAT_MMU_FAULT 3 +#define REGNUM_TOPAZHP_TOP_CR_INT_STAT_MMU_FAULT 0x0004 +#define SIGNED_TOPAZHP_TOP_CR_INT_STAT_MMU_FAULT 0 + +#define MASK_TOPAZHP_TOP_CR_INT_STAT_MTX_CORES 0x0000FF00 +#define SHIFT_TOPAZHP_TOP_CR_INT_STAT_MTX_CORES 8 +#define REGNUM_TOPAZHP_TOP_CR_INT_STAT_MTX_CORES 0x0004 +#define SIGNED_TOPAZHP_TOP_CR_INT_STAT_MTX_CORES 0 + +#define MASK_TOPAZHP_TOP_CR_INT_STAT_HOST_CORES 0x00FF0000 +#define SHIFT_TOPAZHP_TOP_CR_INT_STAT_HOST_CORES 16 +#define REGNUM_TOPAZHP_TOP_CR_INT_STAT_HOST_CORES 0x0004 +#define SIGNED_TOPAZHP_TOP_CR_INT_STAT_HOST_CORES 0 + +#define MASK_TOPAZHP_TOP_CR_INT_STAT_MMU_FAULT_B 0x1E000000 +#define SHIFT_TOPAZHP_TOP_CR_INT_STAT_MMU_FAULT_B 25 +#define REGNUM_TOPAZHP_TOP_CR_INT_STAT_MMU_FAULT_B 0x0004 +#define SIGNED_TOPAZHP_TOP_CR_INT_STAT_MMU_FAULT_B 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_MAS_MTX_INTS 0x40000000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_MAS_MTX_INTS 30 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_MAS_MTX_INTS 0x0004 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_MAS_MTX_INTS 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_MAS_HOST_INTS 0x80000000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_MAS_HOST_INTS 31 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_MAS_HOST_INTS 0x0004 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_MAS_HOST_INTS 0 + +/* Register CR_MULTICORE_HOST_INT_ENAB */ +#define TOPAZHP_TOP_CR_MULTICORE_HOST_INT_ENAB 0x000C +#define MASK_TOPAZHP_TOP_CR_HOST_INTEN_DMAC 0x00000001 +#define SHIFT_TOPAZHP_TOP_CR_HOST_INTEN_DMAC 0 +#define REGNUM_TOPAZHP_TOP_CR_HOST_INTEN_DMAC 0x000C +#define SIGNED_TOPAZHP_TOP_CR_HOST_INTEN_DMAC 0 + +#define MASK_TOPAZHP_TOP_CR_HOST_INTEN_MTX 0x00000002 +#define SHIFT_TOPAZHP_TOP_CR_HOST_INTEN_MTX 1 +#define REGNUM_TOPAZHP_TOP_CR_HOST_INTEN_MTX 0x000C +#define SIGNED_TOPAZHP_TOP_CR_HOST_INTEN_MTX 0 + +#define MASK_TOPAZHP_TOP_CR_HOST_INTEN_MTX_HALT 0x00000004 +#define SHIFT_TOPAZHP_TOP_CR_HOST_INTEN_MTX_HALT 2 +#define REGNUM_TOPAZHP_TOP_CR_HOST_INTEN_MTX_HALT 0x000C +#define SIGNED_TOPAZHP_TOP_CR_HOST_INTEN_MTX_HALT 0 + +#define MASK_TOPAZHP_TOP_CR_HOST_INTEN_MMU_FAULT 0x00000078 +#define SHIFT_TOPAZHP_TOP_CR_HOST_INTEN_MMU_FAULT 3 +#define REGNUM_TOPAZHP_TOP_CR_HOST_INTEN_MMU_FAULT 0x000C +#define SIGNED_TOPAZHP_TOP_CR_HOST_INTEN_MMU_FAULT 0 + +#define MASK_TOPAZHP_TOP_CR_HOST_INTEN_MTX_CORES 0x0000FF00 +#define SHIFT_TOPAZHP_TOP_CR_HOST_INTEN_MTX_CORES 8 +#define REGNUM_TOPAZHP_TOP_CR_HOST_INTEN_MTX_CORES 0x000C +#define SIGNED_TOPAZHP_TOP_CR_HOST_INTEN_MTX_CORES 0 + +#define MASK_TOPAZHP_TOP_CR_HOST_INTEN_HOST_CORES 0x00FF0000 +#define SHIFT_TOPAZHP_TOP_CR_HOST_INTEN_HOST_CORES 16 +#define REGNUM_TOPAZHP_TOP_CR_HOST_INTEN_HOST_CORES 0x000C +#define SIGNED_TOPAZHP_TOP_CR_HOST_INTEN_HOST_CORES 0 + +#define MASK_TOPAZHP_TOP_CR_HOST_INTEN_MMU_FAULT_B 0x1E000000 +#define SHIFT_TOPAZHP_TOP_CR_HOST_INTEN_MMU_FAULT_B 25 +#define REGNUM_TOPAZHP_TOP_CR_HOST_INTEN_MMU_FAULT_B 0x000C +#define SIGNED_TOPAZHP_TOP_CR_HOST_INTEN_MMU_FAULT_B 0 + +#define MASK_TOPAZHP_TOP_CR_HOST_TOPAZHP_MAS_INTEN 0x80000000 +#define SHIFT_TOPAZHP_TOP_CR_HOST_TOPAZHP_MAS_INTEN 31 +#define REGNUM_TOPAZHP_TOP_CR_HOST_TOPAZHP_MAS_INTEN 0x000C +#define SIGNED_TOPAZHP_TOP_CR_HOST_TOPAZHP_MAS_INTEN 0 + +/* Register CR_MULTICORE_INT_CLEAR */ +#define TOPAZHP_TOP_CR_MULTICORE_INT_CLEAR 0x0010 +#define MASK_TOPAZHP_TOP_CR_INTCLR_DMAC 0x00000001 +#define SHIFT_TOPAZHP_TOP_CR_INTCLR_DMAC 0 +#define REGNUM_TOPAZHP_TOP_CR_INTCLR_DMAC 0x0010 +#define SIGNED_TOPAZHP_TOP_CR_INTCLR_DMAC 0 + +#define MASK_TOPAZHP_TOP_CR_INTCLR_MTX 0x00000002 +#define SHIFT_TOPAZHP_TOP_CR_INTCLR_MTX 1 +#define REGNUM_TOPAZHP_TOP_CR_INTCLR_MTX 0x0010 +#define SIGNED_TOPAZHP_TOP_CR_INTCLR_MTX 0 + +#define MASK_TOPAZHP_TOP_CR_INTCLR_MTX_HALT 0x00000004 +#define SHIFT_TOPAZHP_TOP_CR_INTCLR_MTX_HALT 2 +#define REGNUM_TOPAZHP_TOP_CR_INTCLR_MTX_HALT 0x0010 +#define SIGNED_TOPAZHP_TOP_CR_INTCLR_MTX_HALT 0 + +#define MASK_TOPAZHP_TOP_CR_INTCLR_MMU_FAULT 0x00000078 +#define SHIFT_TOPAZHP_TOP_CR_INTCLR_MMU_FAULT 3 +#define REGNUM_TOPAZHP_TOP_CR_INTCLR_MMU_FAULT 0x0010 +#define SIGNED_TOPAZHP_TOP_CR_INTCLR_MMU_FAULT 0 + +#define MASK_TOPAZHP_TOP_CR_INTCLR_MMU_FAULT_B 0x1E000000 +#define SHIFT_TOPAZHP_TOP_CR_INTCLR_MMU_FAULT_B 25 +#define REGNUM_TOPAZHP_TOP_CR_INTCLR_MMU_FAULT_B 0x0010 +#define SIGNED_TOPAZHP_TOP_CR_INTCLR_MMU_FAULT_B 0 + +/* Register CR_TOPAZ_CMD_FIFO_FLUSH */ +#define TOPAZHP_TOP_CR_TOPAZ_CMD_FIFO_FLUSH 0x0078 +#define MASK_TOPAZHP_TOP_CR_CMD_FIFO_FLUSH 0x00000001 +#define SHIFT_TOPAZHP_TOP_CR_CMD_FIFO_FLUSH 0 +#define REGNUM_TOPAZHP_TOP_CR_CMD_FIFO_FLUSH 0x0078 +#define SIGNED_TOPAZHP_TOP_CR_CMD_FIFO_FLUSH 0 + +/* Register CR_MULTICORE_CMD_FIFO_WRITE */ +#define TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE 0x0060 +#define MASK_TOPAZHP_TOP_CR_CMD_FIFO_WDATA 0xFFFFFFFF +#define SHIFT_TOPAZHP_TOP_CR_CMD_FIFO_WDATA 0 +#define REGNUM_TOPAZHP_TOP_CR_CMD_FIFO_WDATA 0x0060 +#define SIGNED_TOPAZHP_TOP_CR_CMD_FIFO_WDATA 0 + +/* Register CR_MULTICORE_CMD_FIFO_WRITE_SPACE */ +#define TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE_SPACE 0x0064 +#define MASK_TOPAZHP_TOP_CR_CMD_FIFO_SPACE 0x000000FF +#define SHIFT_TOPAZHP_TOP_CR_CMD_FIFO_SPACE 0 +#define REGNUM_TOPAZHP_TOP_CR_CMD_FIFO_SPACE 0x0064 +#define SIGNED_TOPAZHP_TOP_CR_CMD_FIFO_SPACE 0 + +#define MASK_TOPAZHP_TOP_CR_CMD_FIFO_FULL 0x00000100 +#define SHIFT_TOPAZHP_TOP_CR_CMD_FIFO_FULL 8 +#define REGNUM_TOPAZHP_TOP_CR_CMD_FIFO_FULL 0x0064 +#define SIGNED_TOPAZHP_TOP_CR_CMD_FIFO_FULL 0 + +/* Register CR_MULTICORE_IDLE_PWR_MAN */ +#define TOPAZHP_TOP_CR_MULTICORE_IDLE_PWR_MAN 0x0118 +#define MASK_TOPAZHP_TOP_CR_TOPAZ_IDLE_DISABLE 0x00000001 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZ_IDLE_DISABLE 0 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZ_IDLE_DISABLE 0x0118 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZ_IDLE_DISABLE 0 + +/* Register CR_FIRMWARE_REG_1 */ +#define TOPAZHP_TOP_CR_FIRMWARE_REG_1 0x0100 +#define MASK_TOPAZHP_TOP_CR_FIRMWARE_REG_1 0xFFFFFFFF +#define SHIFT_TOPAZHP_TOP_CR_FIRMWARE_REG_1 0 +#define REGNUM_TOPAZHP_TOP_CR_FIRMWARE_REG_1 0x0100 +#define SIGNED_TOPAZHP_TOP_CR_FIRMWARE_REG_1 0 + +/* Register CR_FIRMWARE_REG_2 */ +#define TOPAZHP_TOP_CR_FIRMWARE_REG_2 0x0104 +#define MASK_TOPAZHP_TOP_CR_FIRMWARE_REG_2 0xFFFFFFFF +#define SHIFT_TOPAZHP_TOP_CR_FIRMWARE_REG_2 0 +#define REGNUM_TOPAZHP_TOP_CR_FIRMWARE_REG_2 0x0104 +#define SIGNED_TOPAZHP_TOP_CR_FIRMWARE_REG_2 0 + +/* Register CR_FIRMWARE_REG_3 */ +#define TOPAZHP_TOP_CR_FIRMWARE_REG_3 0x0108 +#define MASK_TOPAZHP_TOP_CR_FIRMWARE_REG_3 0xFFFFFFFF +#define SHIFT_TOPAZHP_TOP_CR_FIRMWARE_REG_3 0 +#define REGNUM_TOPAZHP_TOP_CR_FIRMWARE_REG_3 0x0108 +#define SIGNED_TOPAZHP_TOP_CR_FIRMWARE_REG_3 0 + +/* Register CR_FIRMWARE_REG_4 */ +#define TOPAZHP_TOP_CR_FIRMWARE_REG_4 0x0300 +#define MASK_TOPAZHP_TOP_CR_FIRMWARE_REG_4 0xFFFFFFFF +#define SHIFT_TOPAZHP_TOP_CR_FIRMWARE_REG_4 0 +#define REGNUM_TOPAZHP_TOP_CR_FIRMWARE_REG_4 0x0300 +#define SIGNED_TOPAZHP_TOP_CR_FIRMWARE_REG_4 0 + +/* Register CR_FIRMWARE_REG_5 */ +#define TOPAZHP_TOP_CR_FIRMWARE_REG_5 0x0304 +#define MASK_TOPAZHP_TOP_CR_FIRMWARE_REG_5 0xFFFFFFFF +#define SHIFT_TOPAZHP_TOP_CR_FIRMWARE_REG_5 0 +#define REGNUM_TOPAZHP_TOP_CR_FIRMWARE_REG_5 0x0304 +#define SIGNED_TOPAZHP_TOP_CR_FIRMWARE_REG_5 0 + +/* Register CR_FIRMWARE_REG_6 */ +#define TOPAZHP_TOP_CR_FIRMWARE_REG_6 0x0308 +#define MASK_TOPAZHP_TOP_CR_FIRMWARE_REG_6 0xFFFFFFFF +#define SHIFT_TOPAZHP_TOP_CR_FIRMWARE_REG_6 0 +#define REGNUM_TOPAZHP_TOP_CR_FIRMWARE_REG_6 0x0308 +#define SIGNED_TOPAZHP_TOP_CR_FIRMWARE_REG_6 0 + +/* Register CR_FIRMWARE_REG_7 */ +#define TOPAZHP_TOP_CR_FIRMWARE_REG_7 0x030C +#define MASK_TOPAZHP_TOP_CR_FIRMWARE_REG_7 0xFFFFFFFF +#define SHIFT_TOPAZHP_TOP_CR_FIRMWARE_REG_7 0 +#define REGNUM_TOPAZHP_TOP_CR_FIRMWARE_REG_7 0x030C +#define SIGNED_TOPAZHP_TOP_CR_FIRMWARE_REG_7 0 + +/* Register CR_MTX_DEBUG_MSTR */ +#define TOPAZHP_TOP_CR_MTX_DEBUG_MSTR 0x0044 +#define MASK_TOPAZHP_TOP_CR_MTX_MSTR_DBG_GPIO_IN 0x00000003 +#define SHIFT_TOPAZHP_TOP_CR_MTX_MSTR_DBG_GPIO_IN 0 +#define REGNUM_TOPAZHP_TOP_CR_MTX_MSTR_DBG_GPIO_IN 0x0044 +#define SIGNED_TOPAZHP_TOP_CR_MTX_MSTR_DBG_GPIO_IN 0 + +#define MASK_TOPAZHP_TOP_CR_MTX_MSTR_DBG_IS_SLAVE 0x00000004 +#define SHIFT_TOPAZHP_TOP_CR_MTX_MSTR_DBG_IS_SLAVE 2 +#define REGNUM_TOPAZHP_TOP_CR_MTX_MSTR_DBG_IS_SLAVE 0x0044 +#define SIGNED_TOPAZHP_TOP_CR_MTX_MSTR_DBG_IS_SLAVE 0 + +#define MASK_TOPAZHP_TOP_CR_MTX_MSTR_DBG_GPIO_OUT 0x00000018 +#define SHIFT_TOPAZHP_TOP_CR_MTX_MSTR_DBG_GPIO_OUT 3 +#define REGNUM_TOPAZHP_TOP_CR_MTX_MSTR_DBG_GPIO_OUT 0x0044 +#define SIGNED_TOPAZHP_TOP_CR_MTX_MSTR_DBG_GPIO_OUT 0 + +#define MASK_TOPAZHP_TOP_CR_MTX_MSTR_RAM_BANKS 0x00000F00 +#define SHIFT_TOPAZHP_TOP_CR_MTX_MSTR_RAM_BANKS 8 +#define REGNUM_TOPAZHP_TOP_CR_MTX_MSTR_RAM_BANKS 0x0044 +#define SIGNED_TOPAZHP_TOP_CR_MTX_MSTR_RAM_BANKS 0 + +#define MASK_TOPAZHP_TOP_CR_MTX_MSTR_RAM_BANK_SIZE 0x000F0000 +#define SHIFT_TOPAZHP_TOP_CR_MTX_MSTR_RAM_BANK_SIZE 16 +#define REGNUM_TOPAZHP_TOP_CR_MTX_MSTR_RAM_BANK_SIZE 0x0044 +#define SIGNED_TOPAZHP_TOP_CR_MTX_MSTR_RAM_BANK_SIZE 0 + +#define MASK_TOPAZHP_TOP_CR_MTX_MSTR_LAST_RAM_BANK_SIZE 0x0F000000 +#define SHIFT_TOPAZHP_TOP_CR_MTX_MSTR_LAST_RAM_BANK_SIZE 24 +#define REGNUM_TOPAZHP_TOP_CR_MTX_MSTR_LAST_RAM_BANK_SIZE 0x0044 +#define SIGNED_TOPAZHP_TOP_CR_MTX_MSTR_LAST_RAM_BANK_SIZE 0 + +/* Register CR_MULTICORE_CORE_SEL_0 */ +#define TOPAZHP_TOP_CR_MULTICORE_CORE_SEL_0 0x0050 +#define MASK_TOPAZHP_TOP_CR_DMAC_MTX_SELECT 0x00000007 +#define SHIFT_TOPAZHP_TOP_CR_DMAC_MTX_SELECT 0 +#define REGNUM_TOPAZHP_TOP_CR_DMAC_MTX_SELECT 0x0050 +#define SIGNED_TOPAZHP_TOP_CR_DMAC_MTX_SELECT 0 + +#define MASK_TOPAZHP_TOP_CR_WRITES_MTX_ALL 0x40000000 +#define SHIFT_TOPAZHP_TOP_CR_WRITES_MTX_ALL 30 +#define REGNUM_TOPAZHP_TOP_CR_WRITES_MTX_ALL 0x0050 +#define SIGNED_TOPAZHP_TOP_CR_WRITES_MTX_ALL 0 + +#define MASK_TOPAZHP_TOP_CR_WRITES_CORE_ALL 0x80000000 +#define SHIFT_TOPAZHP_TOP_CR_WRITES_CORE_ALL 31 +#define REGNUM_TOPAZHP_TOP_CR_WRITES_CORE_ALL 0x0050 +#define SIGNED_TOPAZHP_TOP_CR_WRITES_CORE_ALL 0 + +/* Register CR_TOPAZHP_AUTO_CLOCK_GATING */ +#define TOPAZHP_CR_TOPAZHP_AUTO_CLOCK_GATING 0x0024 +#define MASK_TOPAZHP_CR_TOPAZHP_IPE0_AUTO_CLK_GATE 0x00000001 +#define SHIFT_TOPAZHP_CR_TOPAZHP_IPE0_AUTO_CLK_GATE 0 +#define REGNUM_TOPAZHP_CR_TOPAZHP_IPE0_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_IPE0_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_IPE1_AUTO_CLK_GATE 0x00000002 +#define SHIFT_TOPAZHP_CR_TOPAZHP_IPE1_AUTO_CLK_GATE 1 +#define REGNUM_TOPAZHP_CR_TOPAZHP_IPE1_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_IPE1_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_SPE0_AUTO_CLK_GATE 0x00000004 +#define SHIFT_TOPAZHP_CR_TOPAZHP_SPE0_AUTO_CLK_GATE 2 +#define REGNUM_TOPAZHP_CR_TOPAZHP_SPE0_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_SPE0_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_SPE1_AUTO_CLK_GATE 0x00000008 +#define SHIFT_TOPAZHP_CR_TOPAZHP_SPE1_AUTO_CLK_GATE 3 +#define REGNUM_TOPAZHP_CR_TOPAZHP_SPE1_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_SPE1_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_H264COMP4X4_AUTO_CLK_GATE 0x00000010 +#define SHIFT_TOPAZHP_CR_TOPAZHP_H264COMP4X4_AUTO_CLK_GATE 4 +#define REGNUM_TOPAZHP_CR_TOPAZHP_H264COMP4X4_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_H264COMP4X4_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_H264COMP8X8_AUTO_CLK_GATE 0x00000020 +#define SHIFT_TOPAZHP_CR_TOPAZHP_H264COMP8X8_AUTO_CLK_GATE 5 +#define REGNUM_TOPAZHP_CR_TOPAZHP_H264COMP8X8_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_H264COMP8X8_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_H264COMP16X16_AUTO_CLK_GATE 0x00000040 +#define SHIFT_TOPAZHP_CR_TOPAZHP_H264COMP16X16_AUTO_CLK_GATE 6 +#define REGNUM_TOPAZHP_CR_TOPAZHP_H264COMP16X16_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_H264COMP16X16_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_JMCOMP_AUTO_CLK_GATE 0x00000080 +#define SHIFT_TOPAZHP_CR_TOPAZHP_JMCOMP_AUTO_CLK_GATE 7 +#define REGNUM_TOPAZHP_CR_TOPAZHP_JMCOMP_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_JMCOMP_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_VLC_AUTO_CLK_GATE 0x00000200 +#define SHIFT_TOPAZHP_CR_TOPAZHP_VLC_AUTO_CLK_GATE 9 +#define REGNUM_TOPAZHP_CR_TOPAZHP_VLC_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_VLC_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_DEB_AUTO_CLK_GATE 0x00000400 +#define SHIFT_TOPAZHP_CR_TOPAZHP_DEB_AUTO_CLK_GATE 10 +#define REGNUM_TOPAZHP_CR_TOPAZHP_DEB_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_DEB_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_PC_DM_AUTO_CLK_GATE 0x00000800 +#define SHIFT_TOPAZHP_CR_TOPAZHP_PC_DM_AUTO_CLK_GATE 11 +#define REGNUM_TOPAZHP_CR_TOPAZHP_PC_DM_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_PC_DM_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_PC_DMS_AUTO_CLK_GATE 0x00001000 +#define SHIFT_TOPAZHP_CR_TOPAZHP_PC_DMS_AUTO_CLK_GATE 12 +#define REGNUM_TOPAZHP_CR_TOPAZHP_PC_DMS_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_PC_DMS_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_CABAC_AUTO_CLK_GATE 0x00002000 +#define SHIFT_TOPAZHP_CR_TOPAZHP_CABAC_AUTO_CLK_GATE 13 +#define REGNUM_TOPAZHP_CR_TOPAZHP_CABAC_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_CABAC_AUTO_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_INPUT_SCALER_AUTO_CLK_GATE 0x00008000 +#define SHIFT_TOPAZHP_CR_TOPAZHP_INPUT_SCALER_AUTO_CLK_GATE 15 +#define REGNUM_TOPAZHP_CR_TOPAZHP_INPUT_SCALER_AUTO_CLK_GATE 0x0024 +#define SIGNED_TOPAZHP_CR_TOPAZHP_INPUT_SCALER_AUTO_CLK_GATE 0 + +/* Register CR_TOPAZHP_MAN_CLOCK_GATING */ +#define TOPAZHP_CR_TOPAZHP_MAN_CLOCK_GATING 0x0028 +#define MASK_TOPAZHP_CR_TOPAZHP_IPE0_MAN_CLK_GATE 0x00000001 +#define SHIFT_TOPAZHP_CR_TOPAZHP_IPE0_MAN_CLK_GATE 0 +#define REGNUM_TOPAZHP_CR_TOPAZHP_IPE0_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_IPE0_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_IPE1_MAN_CLK_GATE 0x00000002 +#define SHIFT_TOPAZHP_CR_TOPAZHP_IPE1_MAN_CLK_GATE 1 +#define REGNUM_TOPAZHP_CR_TOPAZHP_IPE1_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_IPE1_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_SPE0_MAN_CLK_GATE 0x00000004 +#define SHIFT_TOPAZHP_CR_TOPAZHP_SPE0_MAN_CLK_GATE 2 +#define REGNUM_TOPAZHP_CR_TOPAZHP_SPE0_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_SPE0_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_SPE1_MAN_CLK_GATE 0x00000008 +#define SHIFT_TOPAZHP_CR_TOPAZHP_SPE1_MAN_CLK_GATE 3 +#define REGNUM_TOPAZHP_CR_TOPAZHP_SPE1_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_SPE1_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_H264COMP4X4_MAN_CLK_GATE 0x00000010 +#define SHIFT_TOPAZHP_CR_TOPAZHP_H264COMP4X4_MAN_CLK_GATE 4 +#define REGNUM_TOPAZHP_CR_TOPAZHP_H264COMP4X4_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_H264COMP4X4_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_H264COMP8X8_MAN_CLK_GATE 0x00000020 +#define SHIFT_TOPAZHP_CR_TOPAZHP_H264COMP8X8_MAN_CLK_GATE 5 +#define REGNUM_TOPAZHP_CR_TOPAZHP_H264COMP8X8_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_H264COMP8X8_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_H264COMP16X16_MAN_CLK_GATE 0x00000040 +#define SHIFT_TOPAZHP_CR_TOPAZHP_H264COMP16X16_MAN_CLK_GATE 6 +#define REGNUM_TOPAZHP_CR_TOPAZHP_H264COMP16X16_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_H264COMP16X16_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_JMCOMP_MAN_CLK_GATE 0x00000080 +#define SHIFT_TOPAZHP_CR_TOPAZHP_JMCOMP_MAN_CLK_GATE 7 +#define REGNUM_TOPAZHP_CR_TOPAZHP_JMCOMP_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_JMCOMP_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_PREFETCH_MAN_CLK_GATE 0x00000100 +#define SHIFT_TOPAZHP_CR_TOPAZHP_PREFETCH_MAN_CLK_GATE 8 +#define REGNUM_TOPAZHP_CR_TOPAZHP_PREFETCH_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_PREFETCH_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_VLC_MAN_CLK_GATE 0x00000200 +#define SHIFT_TOPAZHP_CR_TOPAZHP_VLC_MAN_CLK_GATE 9 +#define REGNUM_TOPAZHP_CR_TOPAZHP_VLC_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_VLC_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_DEB_MAN_CLK_GATE 0x00000400 +#define SHIFT_TOPAZHP_CR_TOPAZHP_DEB_MAN_CLK_GATE 10 +#define REGNUM_TOPAZHP_CR_TOPAZHP_DEB_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_DEB_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_PC_DM_MAN_CLK_GATE 0x00000800 +#define SHIFT_TOPAZHP_CR_TOPAZHP_PC_DM_MAN_CLK_GATE 11 +#define REGNUM_TOPAZHP_CR_TOPAZHP_PC_DM_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_PC_DM_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_PC_DMS_MAN_CLK_GATE 0x00001000 +#define SHIFT_TOPAZHP_CR_TOPAZHP_PC_DMS_MAN_CLK_GATE 12 +#define REGNUM_TOPAZHP_CR_TOPAZHP_PC_DMS_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_PC_DMS_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_CABAC_MAN_CLK_GATE 0x00002000 +#define SHIFT_TOPAZHP_CR_TOPAZHP_CABAC_MAN_CLK_GATE 13 +#define REGNUM_TOPAZHP_CR_TOPAZHP_CABAC_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_CABAC_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_LRITC_MAN_CLK_GATE 0x00004000 +#define SHIFT_TOPAZHP_CR_TOPAZHP_LRITC_MAN_CLK_GATE 14 +#define REGNUM_TOPAZHP_CR_TOPAZHP_LRITC_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_LRITC_MAN_CLK_GATE 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_INPUT_SCALER_MAN_CLK_GATE 0x00008000 +#define SHIFT_TOPAZHP_CR_TOPAZHP_INPUT_SCALER_MAN_CLK_GATE 15 +#define REGNUM_TOPAZHP_CR_TOPAZHP_INPUT_SCALER_MAN_CLK_GATE 0x0028 +#define SIGNED_TOPAZHP_CR_TOPAZHP_INPUT_SCALER_MAN_CLK_GATE 0 + +/* Register CR_TOPAZHP_SRST */ +#define TOPAZHP_CR_TOPAZHP_SRST 0x0000 +#define MASK_TOPAZHP_CR_TOPAZHP_IPE_SOFT_RESET 0x00000001 +#define SHIFT_TOPAZHP_CR_TOPAZHP_IPE_SOFT_RESET 0 +#define REGNUM_TOPAZHP_CR_TOPAZHP_IPE_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_CR_TOPAZHP_IPE_SOFT_RESET 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_SPE_SOFT_RESET 0x00000002 +#define SHIFT_TOPAZHP_CR_TOPAZHP_SPE_SOFT_RESET 1 +#define REGNUM_TOPAZHP_CR_TOPAZHP_SPE_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_CR_TOPAZHP_SPE_SOFT_RESET 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_PC_SOFT_RESET 0x00000004 +#define SHIFT_TOPAZHP_CR_TOPAZHP_PC_SOFT_RESET 2 +#define REGNUM_TOPAZHP_CR_TOPAZHP_PC_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_CR_TOPAZHP_PC_SOFT_RESET 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_H264COMP_SOFT_RESET 0x00000008 +#define SHIFT_TOPAZHP_CR_TOPAZHP_H264COMP_SOFT_RESET 3 +#define REGNUM_TOPAZHP_CR_TOPAZHP_H264COMP_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_CR_TOPAZHP_H264COMP_SOFT_RESET 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_JMCOMP_SOFT_RESET 0x00000010 +#define SHIFT_TOPAZHP_CR_TOPAZHP_JMCOMP_SOFT_RESET 4 +#define REGNUM_TOPAZHP_CR_TOPAZHP_JMCOMP_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_CR_TOPAZHP_JMCOMP_SOFT_RESET 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_PREFETCH_SOFT_RESET 0x00000020 +#define SHIFT_TOPAZHP_CR_TOPAZHP_PREFETCH_SOFT_RESET 5 +#define REGNUM_TOPAZHP_CR_TOPAZHP_PREFETCH_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_CR_TOPAZHP_PREFETCH_SOFT_RESET 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_VLC_SOFT_RESET 0x00000040 +#define SHIFT_TOPAZHP_CR_TOPAZHP_VLC_SOFT_RESET 6 +#define REGNUM_TOPAZHP_CR_TOPAZHP_VLC_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_CR_TOPAZHP_VLC_SOFT_RESET 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_DB_SOFT_RESET 0x00000080 +#define SHIFT_TOPAZHP_CR_TOPAZHP_DB_SOFT_RESET 7 +#define REGNUM_TOPAZHP_CR_TOPAZHP_DB_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_CR_TOPAZHP_DB_SOFT_RESET 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_LTRITC_SOFT_RESET 0x00000100 +#define SHIFT_TOPAZHP_CR_TOPAZHP_LTRITC_SOFT_RESET 8 +#define REGNUM_TOPAZHP_CR_TOPAZHP_LTRITC_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_CR_TOPAZHP_LTRITC_SOFT_RESET 0 + +#define MASK_TOPAZHP_CR_TOPAZHP_SCALER_SOFT_RESET 0x00000200 +#define SHIFT_TOPAZHP_CR_TOPAZHP_SCALER_SOFT_RESET 9 +#define REGNUM_TOPAZHP_CR_TOPAZHP_SCALER_SOFT_RESET 0x0000 +#define SIGNED_TOPAZHP_CR_TOPAZHP_SCALER_SOFT_RESET 0 + +/* Register CR_MMU_STATUS */ +#define TOPAZHP_TOP_CR_MMU_STATUS 0x001C +#define MASK_TOPAZHP_TOP_CR_MMU_PF_N_RW 0x00000001 +#define SHIFT_TOPAZHP_TOP_CR_MMU_PF_N_RW 0 +#define REGNUM_TOPAZHP_TOP_CR_MMU_PF_N_RW 0x001C +#define SIGNED_TOPAZHP_TOP_CR_MMU_PF_N_RW 0 + +#define MASK_TOPAZHP_TOP_CR_MMU_FAULT_ADDR 0xFFFFF000 +#define SHIFT_TOPAZHP_TOP_CR_MMU_FAULT_ADDR 12 +#define REGNUM_TOPAZHP_TOP_CR_MMU_FAULT_ADDR 0x001C +#define SIGNED_TOPAZHP_TOP_CR_MMU_FAULT_ADDR 0 + +/* Register CR_MMU_MEM_REQ */ +#define TOPAZHP_TOP_CR_MMU_MEM_REQ 0x0020 +#define MASK_TOPAZHP_TOP_CR_MEM_REQ_STAT_READS 0x000000FF +#define SHIFT_TOPAZHP_TOP_CR_MEM_REQ_STAT_READS 0 +#define REGNUM_TOPAZHP_TOP_CR_MEM_REQ_STAT_READS 0x0020 +#define SIGNED_TOPAZHP_TOP_CR_MEM_REQ_STAT_READS 0 + +/* Register CR_MMU_CONTROL0 */ +#define TOPAZHP_TOP_CR_MMU_CONTROL0 0x0024 +#define MASK_TOPAZHP_TOP_CR_MMU_NOREORDER 0x00000001 +#define SHIFT_TOPAZHP_TOP_CR_MMU_NOREORDER 0 +#define REGNUM_TOPAZHP_TOP_CR_MMU_NOREORDER 0x0024 +#define SIGNED_TOPAZHP_TOP_CR_MMU_NOREORDER 0 + +#define MASK_TOPAZHP_TOP_CR_MMU_PAUSE 0x00000002 +#define SHIFT_TOPAZHP_TOP_CR_MMU_PAUSE 1 +#define REGNUM_TOPAZHP_TOP_CR_MMU_PAUSE 0x0024 +#define SIGNED_TOPAZHP_TOP_CR_MMU_PAUSE 0 + +#define MASK_TOPAZHP_TOP_CR_MMU_FLUSH 0x00000004 +#define SHIFT_TOPAZHP_TOP_CR_MMU_FLUSH 2 +#define REGNUM_TOPAZHP_TOP_CR_MMU_FLUSH 0x0024 +#define SIGNED_TOPAZHP_TOP_CR_MMU_FLUSH 0 + +#define MASK_TOPAZHP_TOP_CR_MMU_INVALDC 0x00000008 +#define SHIFT_TOPAZHP_TOP_CR_MMU_INVALDC 3 +#define REGNUM_TOPAZHP_TOP_CR_MMU_INVALDC 0x0024 +#define SIGNED_TOPAZHP_TOP_CR_MMU_INVALDC 0 + +#define MASK_TOPAZHP_TOP_CR_FLOWRATE_TOPAZ 0x00000700 +#define SHIFT_TOPAZHP_TOP_CR_FLOWRATE_TOPAZ 8 +#define REGNUM_TOPAZHP_TOP_CR_FLOWRATE_TOPAZ 0x0024 +#define SIGNED_TOPAZHP_TOP_CR_FLOWRATE_TOPAZ 0 + +#define MASK_TOPAZHP_TOP_CR_MMU_BYPASS_TOPAZ 0x00010000 +#define SHIFT_TOPAZHP_TOP_CR_MMU_BYPASS_TOPAZ 16 +#define REGNUM_TOPAZHP_TOP_CR_MMU_BYPASS_TOPAZ 0x0024 +#define SIGNED_TOPAZHP_TOP_CR_MMU_BYPASS_TOPAZ 0 + +/* Register CR_MMU_CONTROL1 */ +#define TOPAZHP_TOP_CR_MMU_CONTROL1 0x0028 +#define MASK_TOPAZHP_TOP_CR_MMU_TTE_THRESHOLD 0x00000FFF +#define SHIFT_TOPAZHP_TOP_CR_MMU_TTE_THRESHOLD 0 +#define REGNUM_TOPAZHP_TOP_CR_MMU_TTE_THRESHOLD 0x0028 +#define SIGNED_TOPAZHP_TOP_CR_MMU_TTE_THRESHOLD 0 + +#define MASK_TOPAZHP_TOP_CR_MMU_ADT_TTE 0x000FF000 +#define SHIFT_TOPAZHP_TOP_CR_MMU_ADT_TTE 12 +#define REGNUM_TOPAZHP_TOP_CR_MMU_ADT_TTE 0x0028 +#define SIGNED_TOPAZHP_TOP_CR_MMU_ADT_TTE 0 + +#define MASK_TOPAZHP_TOP_CR_MMU_BEST_COUNT 0x0FF00000 +#define SHIFT_TOPAZHP_TOP_CR_MMU_BEST_COUNT 20 +#define REGNUM_TOPAZHP_TOP_CR_MMU_BEST_COUNT 0x0028 +#define SIGNED_TOPAZHP_TOP_CR_MMU_BEST_COUNT 0 + +#define MASK_TOPAZHP_TOP_CR_MMU_PAGE_SIZE 0xF0000000 +#define SHIFT_TOPAZHP_TOP_CR_MMU_PAGE_SIZE 28 +#define REGNUM_TOPAZHP_TOP_CR_MMU_PAGE_SIZE 0x0028 +#define SIGNED_TOPAZHP_TOP_CR_MMU_PAGE_SIZE 0 + +/* Register CR_MMU_CONTROL2 */ +#define TOPAZHP_TOP_CR_MMU_CONTROL2 0x002C +#define MASK_TOPAZHP_TOP_CR_MMU_ENABLE_36BIT_ADDRESSING 0x00000001 +#define SHIFT_TOPAZHP_TOP_CR_MMU_ENABLE_36BIT_ADDRESSING 0 +#define REGNUM_TOPAZHP_TOP_CR_MMU_ENABLE_36BIT_ADDRESSING 0x002C +#define SIGNED_TOPAZHP_TOP_CR_MMU_ENABLE_36BIT_ADDRESSING 0 + +#define MASK_TOPAZHP_TOP_CR_MMU_TILING_SCHEME 0x00000008 +#define SHIFT_TOPAZHP_TOP_CR_MMU_TILING_SCHEME 3 +#define REGNUM_TOPAZHP_TOP_CR_MMU_TILING_SCHEME 0x002C +#define SIGNED_TOPAZHP_TOP_CR_MMU_TILING_SCHEME 0 + +/* Table MMU_DIR_LIST_BASE */ + +/* Register CR_MMU_DIR_LIST_BASE */ +#define TOPAZHP_TOP_CR_MMU_DIR_LIST_BASE(X) (0x0030 + (4 * (X))) +#define MASK_TOPAZHP_TOP_CR_MMU_DIR_LIST_BASE_ADDR 0xFFFFFFF0 +#define SHIFT_TOPAZHP_TOP_CR_MMU_DIR_LIST_BASE_ADDR 4 +#define REGNUM_TOPAZHP_TOP_CR_MMU_DIR_LIST_BASE_ADDR 0x0030 +#define SIGNED_TOPAZHP_TOP_CR_MMU_DIR_LIST_BASE_ADDR 0 + +/* Number of entries in table MMU_DIR_LIST_BASE */ + +#define TOPAZHP_TOP_MMU_DIR_LIST_BASE_SIZE_UINT32 1 +#define TOPAZHP_TOP_MMU_DIR_LIST_BASE_NUM_ENTRIES 1 + +/* Table MMU_TILE */ + +/* Register CR_MMU_TILE */ +#define TOPAZHP_TOP_CR_MMU_TILE(X) (0x0038 + (4 * (X))) +#define MASK_TOPAZHP_TOP_CR_TILE_MIN_ADDR 0x00000FFF +#define SHIFT_TOPAZHP_TOP_CR_TILE_MIN_ADDR 0 +#define REGNUM_TOPAZHP_TOP_CR_TILE_MIN_ADDR 0x0038 +#define SIGNED_TOPAZHP_TOP_CR_TILE_MIN_ADDR 0 + +#define MASK_TOPAZHP_TOP_CR_TILE_MAX_ADDR 0x00FFF000 +#define SHIFT_TOPAZHP_TOP_CR_TILE_MAX_ADDR 12 +#define REGNUM_TOPAZHP_TOP_CR_TILE_MAX_ADDR 0x0038 +#define SIGNED_TOPAZHP_TOP_CR_TILE_MAX_ADDR 0 + +#define MASK_TOPAZHP_TOP_CR_TILE_STRIDE 0x07000000 +#define SHIFT_TOPAZHP_TOP_CR_TILE_STRIDE 24 +#define REGNUM_TOPAZHP_TOP_CR_TILE_STRIDE 0x0038 +#define SIGNED_TOPAZHP_TOP_CR_TILE_STRIDE 0 + +#define MASK_TOPAZHP_TOP_CR_TILE_ENABLE 0x10000000 +#define SHIFT_TOPAZHP_TOP_CR_TILE_ENABLE 28 +#define REGNUM_TOPAZHP_TOP_CR_TILE_ENABLE 0x0038 +#define SIGNED_TOPAZHP_TOP_CR_TILE_ENABLE 0 + +#define MASK_TOPAZHP_TOP_CR_TILE_128BYTE_INTERLEAVE 0x20000000 +#define SHIFT_TOPAZHP_TOP_CR_TILE_128BYTE_INTERLEAVE 29 +#define REGNUM_TOPAZHP_TOP_CR_TILE_128BYTE_INTERLEAVE 0x0038 +#define SIGNED_TOPAZHP_TOP_CR_TILE_128BYTE_INTERLEAVE 0 + +/* Number of entries in table MMU_TILE */ + +#define TOPAZHP_TOP_MMU_TILE_SIZE_UINT32 2 +#define TOPAZHP_TOP_MMU_TILE_NUM_ENTRIES 2 + +/* Table MMU_TILE_EXT */ + +/* Register CR_MMU_TILE_EXT */ +#define TOPAZHP_TOP_CR_MMU_TILE_EXT(X) (0x0080 + (4 * (X))) +#define MASK_TOPAZHP_TOP_CR_TILE_MIN_ADDR_EXT 0x000000FF +#define SHIFT_TOPAZHP_TOP_CR_TILE_MIN_ADDR_EXT 0 +#define REGNUM_TOPAZHP_TOP_CR_TILE_MIN_ADDR_EXT 0x0080 +#define SIGNED_TOPAZHP_TOP_CR_TILE_MIN_ADDR_EXT 0 + +#define MASK_TOPAZHP_TOP_CR_TILE_MAX_ADDR_EXT 0x0000FF00 +#define SHIFT_TOPAZHP_TOP_CR_TILE_MAX_ADDR_EXT 8 +#define REGNUM_TOPAZHP_TOP_CR_TILE_MAX_ADDR_EXT 0x0080 +#define SIGNED_TOPAZHP_TOP_CR_TILE_MAX_ADDR_EXT 0 + +/* Number of entries in table MMU_TILE_EXT */ + +#define TOPAZHP_TOP_MMU_TILE_EXT_SIZE_UINT32 2 +#define TOPAZHP_TOP_MMU_TILE_EXT_NUM_ENTRIES 2 + +#define TOPAZHP_CR_PROC_ESB_ACCESS_WORD0 0x00F0 + +/* Register CR_PROC_ESB_ACCESS_CONTROL */ +#define TOPAZHP_CR_PROC_ESB_ACCESS_CONTROL 0x00EC +#define MASK_TOPAZHP_CR_PROC_ESB_ADDR 0x00003FF0 +#define SHIFT_TOPAZHP_CR_PROC_ESB_ADDR 4 +#define REGNUM_TOPAZHP_CR_PROC_ESB_ADDR 0x00EC +#define SIGNED_TOPAZHP_CR_PROC_ESB_ADDR 0 + +#define MASK_TOPAZHP_CR_PROC_ESB_READ_N_WRITE 0x00010000 +#define SHIFT_TOPAZHP_CR_PROC_ESB_READ_N_WRITE 16 +#define REGNUM_TOPAZHP_CR_PROC_ESB_READ_N_WRITE 0x00EC +#define SIGNED_TOPAZHP_CR_PROC_ESB_READ_N_WRITE 0 + +#define MASK_TOPAZHP_CR_PROC_ESB_OP_VALID 0x00020000 +#define SHIFT_TOPAZHP_CR_PROC_ESB_OP_VALID 17 +#define REGNUM_TOPAZHP_CR_PROC_ESB_OP_VALID 0x00EC +#define SIGNED_TOPAZHP_CR_PROC_ESB_OP_VALID 0 + +#define MASK_TOPAZHP_CR_PROC_ACCESS_FLAG 0x03000000 +#define SHIFT_TOPAZHP_CR_PROC_ACCESS_FLAG 24 +#define REGNUM_TOPAZHP_CR_PROC_ACCESS_FLAG 0x00EC +#define SIGNED_TOPAZHP_CR_PROC_ACCESS_FLAG 0 + +/* Register CR_SECURE_CONFIG */ +#define TOPAZHP_TOP_CR_SECURE_CONFIG 0x0200 + +/* Register CR_VLC_MPEG4_CFG */ +#define TOPAZ_VLC_CR_VLC_MPEG4_CFG 0x0064 +#define MASK_TOPAZ_VLC_CR_RSIZE 0x00000007 +#define SHIFT_TOPAZ_VLC_CR_RSIZE 0 +#define REGNUM_TOPAZ_VLC_CR_RSIZE 0x0064 +#define SIGNED_TOPAZ_VLC_CR_RSIZE 0 + +/* RC Config registers and tables */ +#define TOPAZHP_TOP_CR_RC_CONFIG_TABLE7 0x012C +#define TOPAZHP_TOP_CR_RC_CONFIG_TABLE6 0x0124 +#define TOPAZHP_TOP_CR_RC_CONFIG_TABLE4 0x0128 +#define TOPAZHP_TOP_CR_RC_CONFIG_TABLE5 0x0130 +#define TOPAZHP_CR_RC_CONFIG_REG8 0x0344 +#define TOPAZHP_CR_RC_CONFIG_REG9 0x0184 +#define TOPAZHP_CR_JMCOMP_RC_STATS 0x0340 + +/* Register CR_TOPAZHP_CORE_DES1 */ +#define TOPAZHP_TOP_CR_TOPAZHP_CORE_DES1 0x03E0 +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_SCALER_SUPPORTED 0x00000080 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_SCALER_SUPPORTED 7 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_SCALER_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_SCALER_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_GENERATE_PERFORMANCE_STORE 0x00000100 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_GENERATE_PERFORMANCE_STORE 8 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_GENERATE_PERFORMANCE_STORE 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_GENERATE_PERFORMANCE_STORE 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_LOSSLESS_SUPPORTED 0x00000200 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_LOSSLESS_SUPPORTED 9 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_LOSSLESS_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_LOSSLESS_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_CUSTOM_QUANT_SUPPORTED 0x00000400 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_CUSTOM_QUANT_SUPPORTED 10 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_CUSTOM_QUANT_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_CUSTOM_QUANT_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_MPEG2_SUPPORTED 0x00000800 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_MPEG2_SUPPORTED 11 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_MPEG2_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_MPEG2_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_SIGNATURES_SUPPORTED_SUBSET 0x00001000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_SIGNATURES_SUPPORTED_SUBSET 12 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_SIGNATURES_SUPPORTED_SUBSET 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_SIGNATURES_SUPPORTED_SUBSET 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_SIGNATURES_SUPPORTED_ALL 0x00002000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_SIGNATURES_SUPPORTED_ALL 13 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_SIGNATURES_SUPPORTED_ALL 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_SIGNATURES_SUPPORTED_ALL 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_WEIGHTED_PRED_ME_SUPPORTED 0x00004000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_WEIGHTED_PRED_ME_SUPPORTED 14 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_WEIGHTED_PRED_ME_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_WEIGHTED_PRED_ME_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_WEIGHTED_PRED_SUPPORTED 0x00008000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_WEIGHTED_PRED_SUPPORTED 15 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_WEIGHTED_PRED_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_WEIGHTED_PRED_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_2_REF_ON_P_PIC_SUPPORTED 0x00010000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_2_REF_ON_P_PIC_SUPPORTED 16 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_2_REF_ON_P_PIC_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_2_REF_ON_P_PIC_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_SPATIAL_DIRECT_SUPPORTED 0x00020000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_SPATIAL_DIRECT_SUPPORTED 17 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_SPATIAL_DIRECT_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_SPATIAL_DIRECT_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_MULTIPASS_SUPPORTED 0x00040000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_MULTIPASS_SUPPORTED 18 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_MULTIPASS_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_MULTIPASS_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_DEFAULT_TABLES_SUPPORTED 0x00080000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_DEFAULT_TABLES_SUPPORTED 19 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_DEFAULT_TABLES_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_DEFAULT_TABLES_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_8X8_TRANSFORM_SUPPORTED 0x00100000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_8X8_TRANSFORM_SUPPORTED 20 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_8X8_TRANSFORM_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_8X8_TRANSFORM_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_INTERLACED_SUPPORTED 0x00200000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_INTERLACED_SUPPORTED 21 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_INTERLACED_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_INTERLACED_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_B_PIC_SUPPORTED 0x00400000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_B_PIC_SUPPORTED 22 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_B_PIC_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_B_PIC_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_16X8_8X16_SUPPORTED 0x00800000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_16X8_8X16_SUPPORTED 23 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_16X8_8X16_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_16X8_8X16_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_CABAC_SUPPORTED 0x01000000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_CABAC_SUPPORTED 24 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_CABAC_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_CABAC_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_SLAVE_JPEG_SUPPORTED 0x02000000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_SLAVE_JPEG_SUPPORTED 25 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_SLAVE_JPEG_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_SLAVE_JPEG_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_JPEG_SUPPORTED 0x04000000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_JPEG_SUPPORTED 26 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_JPEG_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_JPEG_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H263_SUPPORTED 0x08000000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H263_SUPPORTED 27 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H263_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H263_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_MPEG4_SUPPORTED 0x10000000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_MPEG4_SUPPORTED 28 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_MPEG4_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_MPEG4_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_H264_SUPPORTED 0x20000000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_H264_SUPPORTED 29 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_H264_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_H264_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_DMAC_SUPPORTED 0x40000000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_DMAC_SUPPORTED 30 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_DMAC_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_DMAC_SUPPORTED 0 + +#define MASK_TOPAZHP_TOP_CR_TOPAZHP_MMU_SUPPORTED 0x80000000 +#define SHIFT_TOPAZHP_TOP_CR_TOPAZHP_MMU_SUPPORTED 31 +#define REGNUM_TOPAZHP_TOP_CR_TOPAZHP_MMU_SUPPORTED 0x03E0 +#define SIGNED_TOPAZHP_TOP_CR_TOPAZHP_MMU_SUPPORTED 0 +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_v4l2.c b/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_v4l2.c --- a/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_v4l2.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_v4l2.c 2024-07-07 20:37:34.664306649 -0400 @@ -0,0 +1,1922 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMG Encoder v4l2 Driver Interface function implementations + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * David Huang + * + * Re-written for upstreaming + * Sidraya Jayagond + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fw_headers/vxe_common.h" +#include "img_mem_man.h" +#include "target_config.h" +#include "topaz_device.h" +#include "vxe_enc.h" +#include "vxe_v4l2.h" +#include "img_errors.h" + +#define IMG_VXE_ENC_MODULE_NAME "vxe-enc" + +static struct heap_config vxe_enc_heap_configs[] = { + { + .type = MEM_HEAP_TYPE_UNIFIED, + .options.unified = { + .gfp_type = __GFP_DMA32 | __GFP_ZERO, + }, + .to_dev_addr = NULL, + }, +}; + +static struct vxe_enc_fmt vxe_enc_formats[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .num_planes = 1, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .fmt = IMG_CODEC_420_PL12, + .min_bufs = 2, + .size_num[0] = 3, + .size_den[0] = 2, + .bytes_pp = 1, + .csc_preset = IMG_CSC_NONE, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB32, + .num_planes = 1, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .fmt = IMG_CODEC_XBCA, + .min_bufs = 2, + .size_num[0] = 1, + .size_den[0] = 1, + .bytes_pp = 4, + .csc_preset = IMG_CSC_RGB_TO_601_ANALOG, + }, + { + .fourcc = V4L2_PIX_FMT_H264, + .num_planes = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .std = IMG_STANDARD_H264, + .min_bufs = 1, + .size_num[0] = 1, + .size_den[0] = 1, + .bytes_pp = 1, + .csc_preset = IMG_CSC_NONE, + }, +}; + +static struct v4l2_fract frmivals[] = { + { + .numerator = 1, + .denominator = 960, + }, + { + .numerator = 1, + .denominator = 1, + }, +}; + +static struct vxe_enc_ctx *file2ctx(struct file *file) +{ + return container_of(file->private_data, struct vxe_enc_ctx, fh); +} + +static void vxe_eos(struct vxe_enc_ctx *ctx) +{ + struct v4l2_event event = {}; + struct vb2_v4l2_buffer *vb; + + event.type = V4L2_EVENT_EOS; + v4l2_event_queue_fh(&ctx->fh, &event); + /* + * If a capture buffer is available, dequeue with FLAG_LAST + * else, mark for next qbuf to handle + */ + if (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) > 0) { + vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + vb->flags |= V4L2_BUF_FLAG_LAST; + vb2_set_plane_payload(&vb->vb2_buf, 0, 0); + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE); + } else { + ctx->flag_last = TRUE; + } + + topaz_flush_stream(ctx->topaz_str_context, ctx->last_frame_num); +} + +static void vxe_return_resource(void *ctx_handle, enum vxe_cb_type type, + void *img_buf_ref, unsigned int size, + unsigned int coded_frm_cnt, enum img_frame_type frame_type) +{ + struct vxe_enc_ctx *ctx = ctx_handle; + struct device *dev = ctx->dev->dev; + struct vxe_buffer *buf; + +#ifdef ENABLE_PROFILING + struct timespec64 time; +#endif + + switch (type) { + case VXE_CB_CODED_BUFF_READY: + if (!img_buf_ref) + dev_err(dev, "VXE_CB_STRUNIT_PROCESSED had no buffer\n"); + + buf = container_of((struct img_coded_buffer *)img_buf_ref, + struct vxe_buffer, coded_buffer); + vb2_set_plane_payload(&buf->buffer.vb.vb2_buf, 0, size); +#ifdef ENABLE_PROFILING + ktime_get_real_ts64(&time); + ctx->drv_lat.end_time = timespec64_to_ns((const struct timespec64 *)&time); + + pr_err("driver encode time is %llu us\n", div_s64(ctx->drv_lat.end_time - + ctx->drv_lat.start_time, 1000)); +#endif + + if (frame_type == IMG_INTRA_FRAME) + buf->buffer.vb.flags |= V4L2_BUF_FLAG_KEYFRAME; + else if (frame_type == IMG_INTER_P) + buf->buffer.vb.flags |= V4L2_BUF_FLAG_PFRAME; + else if (frame_type == IMG_INTER_B) + buf->buffer.vb.flags |= V4L2_BUF_FLAG_BFRAME; + else + buf->buffer.vb.flags |= V4L2_BUF_FLAG_KEYFRAME; + + v4l2_m2m_buf_done(&buf->buffer.vb, VB2_BUF_STATE_DONE); + + if ((coded_frm_cnt == ctx->last_frame_num) && (coded_frm_cnt != 0)) { + vxe_eos(ctx); + ctx->eos = TRUE; + } + if (ctx->frames_encoding < 2) + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); + break; + case VXE_CB_SRC_FRAME_RELEASE: + if (!img_buf_ref) + dev_err(dev, "VXE_CB_PICT_RELEASE had no buffer\n"); + + buf = container_of((struct img_frame *)img_buf_ref, struct vxe_buffer, src_frame); + vb2_set_plane_payload(&buf->buffer.vb.vb2_buf, 0, size); + v4l2_m2m_buf_done(&buf->buffer.vb, VB2_BUF_STATE_DONE); + ctx->frames_encoding--; + break; + case VXE_CB_ERROR_FATAL: + break; + default: + break; + } +} + +static void device_run(void *priv) +{ + struct vxe_enc_ctx *ctx = priv; + struct device *dev = ctx->dev->dev; + struct vb2_v4l2_buffer *dst_vbuf, *src_vbuf; + struct vxe_buffer *buf; + int ret = 0; +#ifdef ENABLE_PROFILING + struct timespec64 time; +#endif + + mutex_lock_nested(ctx->mutex, SUBCLASS_VXE_V4L2); + while (((topaz_query_empty_coded_slots(ctx->topaz_str_context) > 0) && + (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) > 0)) && + ((topaz_query_empty_source_slots(ctx->topaz_str_context) > 0) && + (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0))) { +#ifdef ENABLE_PROFILING + ktime_get_real_ts64(&time); + ctx->drv_lat.start_time = timespec64_to_ns((const struct timespec64 *)&time); +#endif + /* + * Submit src and dst buffers one to one + * Note: Will have to revisit for B frame support + */ + dst_vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!dst_vbuf) + dev_err(dev, "Next src buffer is null\n"); + + src_vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + if (!src_vbuf) + dev_err(dev, "Next src buffer is null\n"); + + v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf, true); + dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp; + dst_vbuf->field = V4L2_FIELD_NONE; + src_vbuf->field = V4L2_FIELD_NONE; + + /* Handle EOS */ + if (ctx->eos && (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) == 0)) { + pr_debug("%s eos found\n", __func__); + ret = topaz_end_of_stream(ctx->topaz_str_context, ctx->frame_num + 1); + if (ret) + dev_err(dev, "Failed to send EOS to topaz %d\n", + ret); + ctx->last_frame_num = ctx->frame_num + 1; + } + + /* Submit coded package */ + buf = container_of(dst_vbuf, struct vxe_buffer, buffer.vb); + ret = topaz_reserve_coded_package_slot(ctx->topaz_str_context); + if (ret) + dev_err(dev, "Failed to reserve coded package slot %d\n", ret); + ret = topaz_send_coded_package(ctx->topaz_str_context, &buf->coded_buffer); + if (ret) + dev_err(dev, "Failed to send coded package %d\n", + ret); + if (!ret) + ctx->available_coded_packages++; + + /* Submit source frame */ + buf = container_of(src_vbuf, struct vxe_buffer, buffer.vb); + ret = topaz_reserve_source_slot(ctx->topaz_str_context, &buf->src_slot_num); + if (ret) + dev_err(dev, "Failed to reserve source slot %d\n", + ret); + ret = topaz_send_source_frame(ctx->topaz_str_context, &buf->src_frame, + ctx->frame_num, (unsigned long)ctx); + if (ret) + dev_err(dev, "Failed to send source frame %d\n", + ret); + ctx->frame_num++; + if (!ret) + ctx->available_source_frames++; + } + + while ((ctx->available_source_frames > 0) && (ctx->available_coded_packages > 0)) { + pr_debug("Calling topaz_encode_frame #src=%d #coded=%d frames_encoding=%d\n", + ctx->available_source_frames, + ctx->available_coded_packages, + ctx->frames_encoding); + ret = topaz_encode_frame(ctx->topaz_str_context); + if (ret) { + dev_err(dev, "Failed to send encode_frame command %d\n", + ret); + } else { + /* TODO: Account for scenarios where these are not 1 */ + ctx->available_source_frames--; + ctx->available_coded_packages--; + ctx->frames_encoding++; + } + } + + mutex_unlock((struct mutex *)ctx->mutex); +} + +static int job_ready(void *priv) +{ + struct vxe_enc_ctx *ctx = priv; + + /* + * In normal play, check if we can + * submit any source or coded buffers + */ + if (((topaz_query_empty_source_slots(ctx->topaz_str_context) > 0) && + (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0)) && + ((topaz_query_empty_coded_slots(ctx->topaz_str_context) > 0) && + (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) > 0)) && ctx->core_streaming) + return 1; + + /* + * In EOS state, we only need to know + * that coded buffers are available + */ + if (ctx->eos && (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) > 0) && + (topaz_query_empty_coded_slots(ctx->topaz_str_context) > 0) && ctx->core_streaming) + return 1; + + /* + * Since we're allowing device_run for both submissions and actual + * encodes, say job ready if buffers are ready in fw + */ + if (ctx->available_source_frames > 0 && ctx->available_coded_packages > 0 + && ctx->core_streaming) + return 1; + + return 0; +} + +static void job_abort(void *priv) +{ + /* TODO: stub */ + struct vxe_enc_ctx *ctx = priv; + + ctx->core_streaming = FALSE; +} + +static const struct v4l2_m2m_ops m2m_ops = { + .device_run = device_run, + .job_ready = job_ready, + .job_abort = job_abort, +}; + +static struct vxe_enc_q_data *get_queue(struct vxe_enc_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return &ctx->out_queue; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + return &ctx->cap_queue; + default: + return NULL; + } + return NULL; +} + +static int vxe_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + int i; + struct vxe_enc_ctx *ctx = vb2_get_drv_priv(vq); + struct vxe_enc_q_data *queue; + + queue = get_queue(ctx, vq->type); + if (!queue) + return -EINVAL; + + if (*nplanes) { + /* This is being called from CREATEBUFS, perform validation */ + if (*nplanes != queue->fmt->num_planes) + return -EINVAL; + + for (i = 0; i < *nplanes; i++) { + if (sizes[i] != queue->size_image[i]) + return -EINVAL; + } + + return 0; + } + + *nplanes = queue->fmt->num_planes; + + if (V4L2_TYPE_IS_OUTPUT(queue->fmt->type)) { + *nbuffers = max(*nbuffers, queue->fmt->min_bufs); + } else { + *nbuffers = topaz_get_coded_package_max_num(ctx->topaz_str_context, + queue->fmt->std, + queue->width, + queue->height, + &ctx->rc); + for (i = 0; i < *nplanes; i++) { + queue->size_image[i] = + topaz_get_coded_buffer_max_size(ctx->topaz_str_context, + queue->fmt->std, + queue->width, + queue->height, + &ctx->rc); + } + } + + for (i = 0; i < *nplanes; i++) + sizes[i] = queue->size_image[i]; + + return 0; +} + +static int vxe_buf_init(struct vb2_buffer *vb) +{ + struct vxe_enc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct device *dev = ctx->dev->dev; + struct vxe_enc_q_data *queue; + void *sgt; + int i, num_planes, ret; + struct vxe_buffer *buf = container_of(vb, struct vxe_buffer, + buffer.vb.vb2_buf); + + queue = get_queue(ctx, vb->vb2_queue->type); + if (!queue) { + dev_err(dev, "Invalid queue type %d\n", + vb->vb2_queue->type); + return -EINVAL; + } + + num_planes = queue->fmt->num_planes; + + for (i = 0; i < num_planes; i++) { + if (vb2_plane_size(vb, i) < queue->size_image[i]) { + dev_err(dev, "data will not fit into plane(%lu < %lu)\n", + vb2_plane_size(vb, i), + (long)queue->size_image[i]); + return -EINVAL; + } + } + + buf->buf_info.cpu_virt = vb2_plane_vaddr(vb, 0); + buf->buf_info.buf_size = vb2_plane_size(vb, 0); + + sgt = vb2_dma_sg_plane_desc(vb, 0); + if (!sgt) { + dev_err(dev, "Could not get sg_table from plane 0\n"); + return -EINVAL; + } + + if (V4L2_TYPE_IS_OUTPUT(vb->type)) { + ret = topaz_stream_map_buf_sg(ctx->topaz_str_context, VENC_BUFTYPE_PICTURE, + &buf->buf_info, sgt); + if (ret) { + dev_err(dev, "OUTPUT core_stream_map_buf_sg failed\n"); + return ret; + } + pr_debug("Picture buffer mapped successfully, buf_id[%d], dev_virt[%x]\n", + buf->buf_info.buff_id, buf->buf_info.dev_virt); + + vxe_fill_default_src_frame_params(buf); + + buf->y_buffer.mem_info = buf->buf_info; + buf->y_buffer.lock = BUFFER_FREE; + buf->y_buffer.size = 0; /* IMG has 0 */ + buf->y_buffer.bytes_written = 0; + + /* TODO Fill U/V img buffers if necessary */ + buf->src_frame.y_plane_buffer = &buf->y_buffer; + buf->src_frame.u_plane_buffer = NULL; + buf->src_frame.v_plane_buffer = NULL; + buf->src_frame.y_component_offset = 0; + buf->src_frame.u_component_offset = queue->bytesperline[0] * queue->height; + buf->src_frame.v_component_offset = queue->bytesperline[0] * queue->height; + + buf->src_frame.width_bytes = queue->bytesperline[0]; + buf->src_frame.height = queue->height; + buf->src_frame.src_y_stride_bytes = queue->bytesperline[0]; + buf->src_frame.src_uv_stride_bytes = queue->bytesperline[0]; + } else { + ret = topaz_stream_map_buf_sg(ctx->topaz_str_context, + VENC_BUFTYPE_BITSTREAM, + &buf->buf_info, sgt); + if (ret) { + dev_err(dev, "CAPTURE core_stream_map_buf_sg failed\n"); + return ret; + } + pr_debug("Bit-stream buffer mapped successfully, buf_id[%d], dev_virt[%x]\n", + buf->buf_info.buff_id, buf->buf_info.dev_virt); + + buf->coded_buffer.mem_info = buf->buf_info; + buf->coded_buffer.lock = BUFFER_FREE; + buf->coded_buffer.size = vb2_plane_size(vb, 0); + buf->coded_buffer.bytes_written = 0; + } + + return 0; +} + +static int vxe_buf_prepare(struct vb2_buffer *vb) +{ +#ifdef DEBUG_ENCODER_DRIVER + int i; + struct vxe_buffer *buf = container_of(vb, struct vxe_buffer, + buffer.vb.vb2_buf); + + pr_info("%s printing contents of buffer %d at 0x%p\n", + __func__, vb->index, buf->buf_info.cpu_virt); + for (i = 0; i < 1536; i = i + 8) { + pr_info("[%d] 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n", + ((i + 1) / 8), + ((char *)buf->buf_info.cpu_virt)[i + 0], + ((char *)buf->buf_info.cpu_virt)[i + 1], + ((char *)buf->buf_info.cpu_virt)[i + 2], + ((char *)buf->buf_info.cpu_virt)[i + 3], + ((char *)buf->buf_info.cpu_virt)[i + 4], + ((char *)buf->buf_info.cpu_virt)[i + 5], + ((char *)buf->buf_info.cpu_virt)[i + 6], + ((char *)buf->buf_info.cpu_virt)[i + 7]); + } +#endif + return 0; +} + +static void vxe_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vxe_enc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + mutex_lock_nested(ctx->mutex, SUBCLASS_VXE_V4L2); + if (ctx->flag_last && (!V4L2_TYPE_IS_OUTPUT(vb->type))) { + /* + * If EOS came and we did not have a buffer ready + * to service it, service now that we have a buffer + */ + vbuf->flags |= V4L2_BUF_FLAG_LAST; + vb2_set_plane_payload(&vbuf->vb2_buf, 0, 0); + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); + } else { + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + vbuf->sequence = ctx->out_seq++; + else + vbuf->sequence = ctx->cap_seq++; + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + } + mutex_unlock((struct mutex *)ctx->mutex); +} + +static void vxe_buf_cleanup(struct vb2_buffer *vb) +{ + struct vxe_enc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vxe_buffer *buf = container_of(vb, struct vxe_buffer, + buffer.vb.vb2_buf); + + pr_debug("%s Unmapping buffer %d\n", __func__, buf->index); + topaz_stream_unmap_buf_sg(ctx->topaz_str_context, &buf->buf_info); +} + +static int vxe_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vxe_enc_ctx *ctx = vb2_get_drv_priv(vq); + struct vxe_enc_q_data *queue; + ctx->core_streaming = TRUE; + + queue = get_queue(ctx, vq->type); + queue->streaming = TRUE; + + return 0; +} + +static void vxe_stop_streaming(struct vb2_queue *vq) +{ + struct vxe_enc_ctx *ctx = vb2_get_drv_priv(vq); + struct device *dev = ctx->dev->dev; + struct vb2_v4l2_buffer *vb; + struct vxe_enc_q_data *queue; + + queue = get_queue(ctx, vq->type); + /* Unmap all buffers in v4l2 from mmu */ + mutex_lock_nested(ctx->mutex, SUBCLASS_VXE_V4L2); + ctx->core_streaming = FALSE; + if (!V4L2_TYPE_IS_OUTPUT(queue->fmt->type)) { + while (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) { + vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!vb) + dev_err(dev, "Next dst buffer is null\n"); + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); + } + } else { + while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) { + vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + if (!vb) + dev_err(dev, "Next dst buffer is null\n"); + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); + } + } + mutex_unlock(ctx->mutex); +} + +static const struct vb2_ops vxe_video_ops = { + .queue_setup = vxe_queue_setup, + .buf_init = vxe_buf_init, + .buf_prepare = vxe_buf_prepare, + .buf_queue = vxe_buf_queue, + .buf_cleanup = vxe_buf_cleanup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = vxe_start_streaming, + .stop_streaming = vxe_stop_streaming, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct vxe_enc_ctx *ctx = priv; + struct vxe_dev *vxe = ctx->dev; + int ret = 0; + + /* src_vq */ + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct vxe_buffer); + src_vq->ops = &vxe_video_ops; + src_vq->mem_ops = &vb2_dma_sg_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = vxe->mutex; + src_vq->dev = vxe->ti_vxe_dev.dev; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + /* dst_vq */ + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct vxe_buffer); + dst_vq->ops = &vxe_video_ops; + dst_vq->mem_ops = &vb2_dma_sg_memops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = vxe->mutex; + dst_vq->dev = vxe->ti_vxe_dev.dev; + + ret = vb2_queue_init(dst_vq); + if (ret) { + vb2_queue_release(src_vq); + return ret; + } + + return 0; +} + +static inline struct vxe_enc_ctx *vxe_ctrl_to_ctx(struct v4l2_ctrl *vctrl) +{ + return container_of(vctrl->handler, struct vxe_enc_ctx, v4l2_ctrl_hdl); +} + +static int vxe_enc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vxe_enc_ctx *ctx = vxe_ctrl_to_ctx(ctrl); + +#ifdef DEBUG_ENCODER_DRIVER + pr_debug("%s: name: %s | value: %d | id 0x%x | ctx 0x%p\n", __func__, + ctrl->name, ctrl->val, ctrl->id, ctx); +#endif + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + ctx->vparams.idr_period = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + ctx->rc.bits_per_second = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: + ctx->rc.intra_freq = ctrl->val; + ctx->vparams.intra_cnt = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + /* only HP, MP and BP for now */ + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + ctx->sh_params.profile = SH_PROFILE_BP; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + ctx->sh_params.profile = SH_PROFILE_MP; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + ctx->sh_params.profile = SH_PROFILE_HP; + break; + default: + pr_info("not supported H264 profile requested\n"); + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + ctx->sh_params.level = 100; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + ctx->sh_params.level = 101; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + ctx->sh_params.level = 110; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + ctx->sh_params.level = 120; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + ctx->sh_params.level = 130; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + ctx->sh_params.level = 200; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + ctx->sh_params.level = 210; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + ctx->sh_params.level = 220; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + ctx->sh_params.level = 300; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + ctx->sh_params.level = 310; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + ctx->sh_params.level = 320; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + ctx->sh_params.level = 400; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + ctx->sh_params.level = 410; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + ctx->sh_params.level = 420; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + ctx->sh_params.level = 500; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + ctx->sh_params.level = 510; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_2: + ctx->sh_params.level = 520; + break; + default: + pr_info("requested h264 level is not supported\n"); + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: + ctx->vparams.h264_8x8 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + ctx->vparams.cabac_enabled = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC: + ctx->sh_params.max_num_ref_frames = ctrl->val; + break; + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops vxe_enc_ctrl_ops = { + .s_ctrl = vxe_enc_s_ctrl, +}; + +static int vxe_open(struct file *file) +{ + struct vxe_dev *vxe = video_drvdata(file); + struct vxe_enc_ctx *ctx; + int i, ret = 0; + struct v4l2_ctrl_handler *v4l2_ctrl_hdl; + + dev_dbg(vxe->dev, "%s:%d vxe %p\n", __func__, __LINE__, vxe); + + mutex_lock((struct mutex *)vxe->mutex); + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + mutex_unlock((struct mutex *)vxe->mutex); + return -ENOMEM; + } + + v4l2_ctrl_hdl = &ctx->v4l2_ctrl_hdl; + + ctx->mutex = kzalloc(sizeof(*ctx->mutex), GFP_KERNEL); + if (!ctx->mutex) + return -ENOMEM; + + mutex_init(ctx->mutex); + + ctx->dev = vxe; + ctx->s_fmt_flags = 0; + ctx->eos = FALSE; + ctx->flag_last = FALSE; + ctx->available_coded_packages = 0; + ctx->available_source_frames = 0; + ctx->frames_encoding = 0; + ctx->frame_num = 0; + ctx->rc.frame_rate = VXE_ENCODER_DEFAULT_FRAMERATE; + ctx->rc.initial_qp_i = VXE_ENCODER_INITIAL_QP_I; + ctx->out_queue.streaming = FALSE; + ctx->cap_queue.streaming = FALSE; + + /* set the sequence numbers to zero */ + ctx->cap_seq = 0; + ctx->out_seq = 0; + + /* set some default widths and heights */ + ctx->cap_queue.height = VXE_ENCODER_DEFAULT_HEIGHT; + ctx->cap_queue.width = VXE_ENCODER_DEFAULT_WIDTH; + ctx->out_queue.height = VXE_ENCODER_DEFAULT_HEIGHT; + ctx->out_queue.width = VXE_ENCODER_DEFAULT_WIDTH; + + ctx->colorspace = V4L2_COLORSPACE_REC709; + ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + ctx->hsv_enc = 0; + ctx->quantization = V4L2_QUANTIZATION_DEFAULT; + ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; + + /* + * set some sane defaults, some of which will get overridden + * latest when v4l2 starts setting up its s_ctrls + */ + vxe_fill_default_params(ctx); + + for (i = 0; i < ARRAY_SIZE(vxe_enc_formats); i++) { + if (vxe_enc_formats[i].type == + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ctx->out_queue.fmt = &vxe_enc_formats[i]; + break; + } + } + for (i = 0; i < ARRAY_SIZE(vxe_enc_formats); i++) { + if (vxe_enc_formats[i].type == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ctx->cap_queue.fmt = &vxe_enc_formats[i]; + break; + } + } + + for (i = 0; i < ctx->cap_queue.fmt->num_planes; i++) { + ctx->cap_queue.size_image[i] = topaz_get_coded_buffer_max_size(NULL, + (enum img_standard) ctx->cap_queue.fmt->fmt, + ctx->cap_queue.width, ctx->cap_queue.height, + &ctx->rc); + + ctx->cap_queue.bytesperline[i] = 0; + } + + for (i = 0; i < ctx->out_queue.fmt->num_planes; i++) { + ctx->out_queue.bytesperline[i] = vxe_get_stride(ctx->out_queue.width, + ctx->out_queue.fmt); + ctx->out_queue.size_image[i] = vxe_get_sizeimage(ctx->out_queue.bytesperline[i], + ctx->out_queue.height, ctx->out_queue.fmt, i); + } + + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vxe->m2m_dev, ctx, &queue_init); + if (IS_ERR_VALUE((unsigned long)ctx->fh.m2m_ctx)) { + ret = (long)(ctx->fh.m2m_ctx); + goto exit; + } + + v4l2_ctrl_handler_init(v4l2_ctrl_hdl, 15); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &vxe_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE, + 0, 700000000, 1, 100000); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &vxe_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + 0, 2047, 1, 30); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &vxe_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, + 0, 2047, 1, 30); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &vxe_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MAX_REF_PIC, + 1, 16, 1, 1); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &vxe_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + 0, + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &vxe_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + V4L2_MPEG_VIDEO_H264_LEVEL_5_1, 0, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &vxe_enc_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 2); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &vxe_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, 0, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &vxe_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + 0, 1, 1, 1); + + if (v4l2_ctrl_hdl->error) { + kfree(ctx->mutex); + kfree(ctx); + return -ENODEV; + } + + ctx->fh.ctrl_handler = v4l2_ctrl_hdl; + v4l2_ctrl_handler_setup(v4l2_ctrl_hdl); + + v4l2_fh_add(&ctx->fh); + + vxe_create_ctx(vxe, ctx); + + /* TODO: Add stream id creation */ +exit: + mutex_unlock((struct mutex *)vxe->mutex); + return ret; +} + +static int vxe_release(struct file *file) +{ + struct vxe_dev *vxe = video_drvdata(file); + struct vxe_enc_ctx *ctx = file2ctx(file); + /* TODO Need correct API */ + + mutex_lock((struct mutex *)vxe->mutex); + + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + + if (ctx->s_fmt_flags & S_FMT_FLAG_STREAM_CREATED) + topaz_stream_destroy(ctx->topaz_str_context); + ctx->topaz_str_context = NULL; + + mutex_destroy(ctx->mutex); + kfree(ctx->mutex); + ctx->mutex = NULL; + kfree(ctx); + + mutex_unlock((struct mutex *)vxe->mutex); + + return 0; +} + +static const struct v4l2_file_operations vxe_enc_fops = { + .owner = THIS_MODULE, + .open = vxe_open, + .release = vxe_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static int vxe_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strncpy(cap->driver, IMG_VXE_ENC_MODULE_NAME, sizeof(cap->driver) - 1); + strncpy(cap->card, IMG_VXE_ENC_MODULE_NAME, sizeof(cap->card) - 1); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", IMG_VXE_ENC_MODULE_NAME); + return 0; +} + +static struct vxe_enc_fmt *find_format(struct v4l2_format *f) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vxe_enc_formats); ++i) { + if (vxe_enc_formats[i].fourcc == f->fmt.pix_mp.pixelformat && + vxe_enc_formats[i].type == f->type) + return &vxe_enc_formats[i]; + } + return NULL; +} + +static int vxe_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) +{ + int i, index = 0; + struct vxe_enc_fmt *fmt = NULL; + + for (i = 0; i < ARRAY_SIZE(vxe_enc_formats); ++i) { + if (vxe_enc_formats[i].type == f->type) { + if (index == f->index) { + fmt = &vxe_enc_formats[i]; + break; + } + index++; + } + } + + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->fourcc; + f->flags = 0; + + return 0; +} + +static int vxe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct vxe_enc_ctx *ctx = file2ctx(file); + struct v4l2_pix_format_mplane *pix_mp; + struct vxe_enc_q_data *queue; + int i; + + pix_mp = &f->fmt.pix_mp; + + queue = get_queue(ctx, f->type); + if (!queue) + return -EINVAL; + + pix_mp->width = queue->width; + pix_mp->height = queue->height; + pix_mp->pixelformat = queue->fmt->fourcc; + pix_mp->field = V4L2_FIELD_NONE; + + for (i = 0; i < queue->fmt->num_planes; i++) { + pix_mp->plane_fmt[i].sizeimage = queue->size_image[i]; + pix_mp->plane_fmt[i].bytesperline = queue->bytesperline[i]; + } + pix_mp->num_planes = queue->fmt->num_planes; + + f->fmt.pix_mp.colorspace = ctx->colorspace; + f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; + f->fmt.pix_mp.hsv_enc = ctx->hsv_enc; + f->fmt.pix_mp.quantization = ctx->quantization; + f->fmt.pix_mp.xfer_func = ctx->xfer_func; + + return 0; +} + +static int vxe_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct vxe_enc_ctx *ctx = file2ctx(file); + struct vxe_enc_fmt *fmt; + struct vxe_enc_q_data *queue; + int i, width, height; + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt; + struct img_rc_params rc; + + /* spec ambiguity see: http://www.mail-archive.com/linux-media@vger.kernel.org/msg56550.html*/ + fmt = find_format(f); + if (!fmt) { + if (V4L2_TYPE_IS_OUTPUT(f->type)) + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12; + else + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; + /* try again now we have a default pixel type */ + fmt = find_format(f); + if (!fmt) + return -EINVAL; /* this should never happen */ + } + + width = clamp_t(u32, f->fmt.pix_mp.width, VXE_ENCODER_MIN_WIDTH, VXE_ENCODER_MAX_WIDTH); + height = clamp_t(u32, f->fmt.pix_mp.height, VXE_ENCODER_MIN_HEIGHT, VXE_ENCODER_MAX_HEIGHT); + + queue = get_queue(ctx, f->type); + if (!queue) + return -EINVAL; + + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + pix_mp->num_planes = fmt->num_planes; + pix_mp->width = width; + pix_mp->height = height; + + for (i = 0; i < fmt->num_planes; i++) { + plane_fmt[i].bytesperline = vxe_get_stride(pix_mp->width, fmt); + plane_fmt[i].sizeimage = vxe_get_sizeimage(plane_fmt[i].bytesperline, + pix_mp->height, fmt, i); + } + } else { + /* Worst case estimation of sizeimage + *plane_fmt[0].sizeimage = ALIGN(pix_mp->width, HW_ALIGN) * + * ALIGN(pix_mp->height, HW_ALIGN) * 2; + */ + pix_mp->num_planes = 1; + rc.initial_qp_i = 18; + plane_fmt[0].bytesperline = 0; + pix_mp->width = width; + pix_mp->height = height; + plane_fmt[0].sizeimage = topaz_get_coded_buffer_max_size(NULL, fmt->std, + pix_mp->width, + pix_mp->height, + &rc); + + f->fmt.pix_mp.colorspace = ctx->colorspace; + f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; + f->fmt.pix_mp.hsv_enc = ctx->hsv_enc; + f->fmt.pix_mp.quantization = ctx->quantization; + f->fmt.pix_mp.xfer_func = ctx->xfer_func; + } + + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->flags = 0; + pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; + memset(&f->fmt.pix_mp.reserved, 0, sizeof(f->fmt.pix_mp.reserved)); + + return 0; +} + +static int vxe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct vxe_enc_ctx *ctx = file2ctx(file); + struct v4l2_pix_format_mplane *pix_mp; + struct vxe_enc_fmt *fmt; + struct vxe_enc_q_data *queue; + int i, ret = 0; + unsigned int level_h264; + static int base_pipe; + unsigned int calculated_profile; + + pix_mp = &f->fmt.pix_mp; + +#ifdef DEBUG_ENCODER_DRIVER + pr_debug("entering %s with context %p\n", __func__, ctx); +#endif + + ret = vxe_try_fmt(file, priv, f); + if (ret) + return ret; + + fmt = find_format(f); + if (!fmt) + return -EINVAL; + + queue = get_queue(ctx, f->type); + if (!queue) + return -EINVAL; + + pix_mp = &f->fmt.pix_mp; + + queue->fmt = fmt; + queue->width = pix_mp->width; + queue->height = pix_mp->height; + + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + ctx->vparams.format = fmt->fmt; + ctx->vparams.source_width = pix_mp->width; + ctx->vparams.source_frame_height = pix_mp->height; + ctx->vparams.csc_preset = fmt->csc_preset; + if (ctx->vparams.csc_preset != IMG_CSC_NONE) + ctx->vparams.enable_scaler = TRUE; + + ctx->colorspace = f->fmt.pix_mp.colorspace; + ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + ctx->hsv_enc = f->fmt.pix_mp.hsv_enc; + ctx->quantization = f->fmt.pix_mp.quantization; + ctx->xfer_func = f->fmt.pix_mp.xfer_func; + + pr_debug("img_video_params: format=%d\n", ctx->vparams.format); + pr_debug("img_video_params: source_width=%d\n", ctx->vparams.source_width); + pr_debug("img_video_params: source_frame_height=%d\n", + ctx->vparams.source_frame_height); + pr_debug("img_video_params: csc_preset=%d\n", ctx->vparams.csc_preset); + pr_debug("img_video_params: enable_scaler=%s\n", + ctx->vparams.enable_scaler ? "true" : "false"); + + for (i = 0; i < fmt->num_planes; i++) { + queue->bytesperline[i] = vxe_get_stride(queue->width, fmt); + queue->size_image[i] = vxe_get_sizeimage(pix_mp->plane_fmt[i].bytesperline, + queue->height, fmt, i); + } + + /* Rate Control parameters */ + ctx->rc.transfer_bits_per_second = ctx->rc.bits_per_second; + ctx->rc.bu_size = -1414812757; /* Pretty sure uninitialized */ + ctx->rc.buffer_size = ctx->rc.transfer_bits_per_second; + + ctx->rc.initial_level = (3 * ctx->rc.buffer_size) >> 4; + ctx->rc.initial_level = ((ctx->rc.initial_level + + ((ctx->rc.bits_per_second / + ctx->rc.frame_rate) / 2)) / + (ctx->rc.bits_per_second / + ctx->rc.frame_rate)) * + (ctx->rc.bits_per_second / ctx->rc.frame_rate); + ctx->rc.initial_level = max((unsigned int)ctx->rc.initial_level, + (unsigned int)(ctx->rc.bits_per_second / + ctx->rc.frame_rate)); + ctx->rc.initial_delay = ctx->rc.buffer_size - ctx->rc.initial_level; + ctx->rc.bframes = 0; + + pr_debug("img_rc_params: initial_level=%d\n", ctx->rc.initial_level); + pr_debug("img_rc_params: initial_delay=%d\n", ctx->rc.initial_delay); + + pr_debug("requested profile: %d, ref frames: %d, cabac: %d, weighted pred: %d, 8x8trans: %d, level %d", + ctx->sh_params.profile, + ctx->sh_params.max_num_ref_frames, + ctx->vparams.cabac_enabled, + ctx->vparams.weighted_prediction, + ctx->vparams.h264_8x8, + ctx->sh_params.level); + + calculated_profile = find_h264_profile + (FALSE, + ctx->vparams.use_default_scaling_list, + FALSE, + ctx->vparams.h264_8x8, + ctx->vparams.enable_mvc, + ctx->rc.bframes, + ctx->vparams.is_interlaced, + ctx->vparams.cabac_enabled, + ctx->vparams.weighted_prediction, + ctx->vparams.vp_weighted_implicit_bi_pred); + + /* pick the higher of the requested profile and the calculated profile */ + ctx->sh_params.profile = max(calculated_profile, ctx->sh_params.profile); + + level_h264 = calculate_h264_level(pix_mp->width, pix_mp->height, + ctx->rc.frame_rate, + ctx->rc.rc_enable, + ctx->rc.bits_per_second, + /* TODO Figure out which lossless to use */ + FALSE, + ctx->sh_params.profile, + ctx->sh_params.max_num_ref_frames); + + /* pick the highest of the calculate or selected level */ + level_h264 = max(level_h264, ctx->sh_params.level); + + pr_debug("selected profile: %d, ref frames: %d, cabac: %d, weighted pred: %d, 8x8trans: %d, level %d", + ctx->sh_params.profile, + ctx->sh_params.max_num_ref_frames, + ctx->vparams.cabac_enabled, + ctx->vparams.weighted_prediction, + ctx->vparams.h264_8x8, + ctx->sh_params.level); + + ctx->vparams.vert_mv_limit = 255; + if (level_h264 >= 110) + ctx->vparams.vert_mv_limit = 511; + if (level_h264 >= 210) + ctx->vparams.vert_mv_limit = 1023; + if (level_h264 >= 310) + ctx->vparams.vert_mv_limit = 2047; + + if (level_h264 >= 300) + ctx->vparams.limit_num_vectors = TRUE; + else + ctx->vparams.limit_num_vectors = FALSE; + + pr_debug("ctx->vparams.vert_mv_limit=%d\n", ctx->vparams.vert_mv_limit); + pr_debug("ctx->vparams.limit_num_vectors=%d\n", ctx->vparams.limit_num_vectors); + + /* VUI parameters */ + ctx->vui_params.time_scale = ctx->rc.frame_rate * 2; + ctx->vui_params.bit_rate_value_minus1 = (ctx->rc.bits_per_second / 64) + - 1; + ctx->vui_params.cbp_size_value_minus1 = (ctx->rc.buffer_size / 64) - 1; + ctx->vui_params.aspect_ratio_info_present_flag = FALSE; //unset + ctx->vui_params.aspect_ratio_idc = 0; //unset + ctx->vui_params.sar_width = 0; //unset + ctx->vui_params.sar_height = 0; //unset + ctx->vui_params.cbr = (ctx->rc.rc_mode == IMG_RCMODE_CBR) ? + TRUE : FALSE; + ctx->vui_params.initial_cpb_removal_delay_length_minus1 = + BPH_SEI_NAL_INITIAL_CPB_REMOVAL_DELAY_SIZE - 1; + ctx->vui_params.cpb_removal_delay_length_minus1 = + PTH_SEI_NAL_CPB_REMOVAL_DELAY_SIZE - 1; + ctx->vui_params.dpb_output_delay_length_minus1 = + PTH_SEI_NAL_DPB_OUTPUT_DELAY_SIZE - 1; + ctx->vui_params.time_offset_length = 24; //hard coded + ctx->vui_params.num_reorder_frames = 0; //TODO + ctx->vui_params.max_dec_frame_buffering = 0; //unset + + pr_debug("h264_vui_params: time_scale=%d\n", ctx->vui_params.time_scale); + pr_debug("h264_vui_params: bit_rate_value_minus1=%d\n", + ctx->vui_params.bit_rate_value_minus1); + pr_debug("h264_vui_params: cbp_size_value_minus1=%d\n", + ctx->vui_params.cbp_size_value_minus1); + pr_debug("h264_vui_params: cbr=%d\n", ctx->vui_params.cbr); + pr_debug("h264_vui_params: initial_cpb_removal_delay_length_minus1=%d\n", + ctx->vui_params.initial_cpb_removal_delay_length_minus1); + pr_debug("h264_vui_params: cpb_removal_delay_length_minus1=%d\n", + ctx->vui_params.cpb_removal_delay_length_minus1); + pr_debug("h264_vui_params: dpb_output_delay_length_minus1=%d\n", + ctx->vui_params.dpb_output_delay_length_minus1); + + /* Sequence Header parameters */ + switch (level_h264) { + case 100: + ctx->sh_params.level = SH_LEVEL_1; + break; + case 101: + ctx->sh_params.level = SH_LEVEL_1B; + break; + case 110: + ctx->sh_params.level = SH_LEVEL_11; + break; + case 120: + ctx->sh_params.level = SH_LEVEL_12; + break; + case 130: + ctx->sh_params.level = SH_LEVEL_13; + break; + case 200: + ctx->sh_params.level = SH_LEVEL_2; + break; + case 210: + ctx->sh_params.level = SH_LEVEL_21; + break; + case 220: + ctx->sh_params.level = SH_LEVEL_22; + break; + case 300: + ctx->sh_params.level = SH_LEVEL_3; + break; + case 310: + ctx->sh_params.level = SH_LEVEL_31; + break; + case 320: + ctx->sh_params.level = SH_LEVEL_32; + break; + case 400: + ctx->sh_params.level = SH_LEVEL_4; + break; + case 410: + ctx->sh_params.level = SH_LEVEL_41; + break; + case 420: + ctx->sh_params.level = SH_LEVEL_42; + break; + case 500: + ctx->sh_params.level = SH_LEVEL_5; + break; + case 510: + ctx->sh_params.level = SH_LEVEL_51; + break; + case 520: + ctx->sh_params.level = SH_LEVEL_52; + break; + default: + pr_err("Error invalid h264 level %d\n", level_h264); + return -EINVAL; + } + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + ctx->sh_params.width_in_mbs_minus1 = ((ALIGN_16(queue->width) + + (MB_SIZE - 1))/MB_SIZE)-1; + ctx->sh_params.height_in_maps_units_minus1 = ((ALIGN_16(queue->height) + + (MB_SIZE - 1))/MB_SIZE) - 1; + pr_debug("h264_sequence_header_params: width_in_mbs_minus1=%d\n", + ctx->sh_params.width_in_mbs_minus1); + pr_debug("h264_sequence_header_params: height_in_maps_units_minus1=%d\n", + ctx->sh_params.height_in_maps_units_minus1); + } + ctx->sh_params.log2_max_pic_order_cnt = 6; //hard coded + ctx->sh_params.gaps_in_frame_num_value = FALSE; + ctx->sh_params.frame_mbs_only_flag = ctx->vparams.is_interlaced ? + FALSE : TRUE; + ctx->sh_params.vui_params_present = (ctx->rc.rc_mode == IMG_RCMODE_NONE) + ? FALSE : TRUE; + ctx->sh_params.seq_scaling_matrix_present_flag = FALSE; + ctx->sh_params.use_default_scaling_list = FALSE; + ctx->sh_params.is_lossless = FALSE; + ctx->sh_params.vui_params = ctx->vui_params; + + pr_debug("h264_sequence_header_params: frame_mbs_only_flag=%d\n", + ctx->sh_params.frame_mbs_only_flag); + pr_debug("h264_sequence_header_params: vui_params_present=%d\n", + ctx->sh_params.vui_params_present); + + ctx->s_fmt_flags |= S_FMT_FLAG_OUT_RECV; + } else { + for (i = 0; i < fmt->num_planes; i++) { + queue->bytesperline[i] = 0; + queue->size_image[i] = + topaz_get_coded_buffer_max_size(ctx->topaz_str_context, + queue->fmt->std, + queue->width, + queue->height, + &ctx->rc); + } + ctx->vparams.standard = fmt->std; + ctx->vparams.width = pix_mp->width; + /* + * Note: Do not halve height for interlaced. + * App should take care of this. + */ + ctx->vparams.frame_height = pix_mp->height; + + pr_debug("img_video_params: standard=%d\n", ctx->vparams.standard); + pr_debug("img_video_params: width=%d\n", ctx->vparams.width); + pr_debug("img_video_params: frame_height=%d\n", ctx->vparams.frame_height); + + ctx->s_fmt_flags |= S_FMT_FLAG_CAP_RECV; + } + ctx->vparams.is_interlaced = FALSE; + + ctx->vparams.intra_pred_modes = -1414812757; /* Pretty sure uninitialized */ + + ctx->vparams.buffer_stride_bytes = 0; + ctx->vparams.buffer_height = 0; + + ctx->vparams.crop_left = 0; + ctx->vparams.crop_right = 0; + ctx->vparams.crop_top = 0; + ctx->vparams.crop_bottom = 0; + + ctx->vparams.slices_per_picture = 1; + + /* Crop parameters */ + ctx->crop_params.clip = FALSE; + ctx->crop_params.left_crop_offset = 0; + ctx->crop_params.right_crop_offset = (((ctx->sh_params.width_in_mbs_minus1 + 1)*MB_SIZE) - + ctx->vparams.source_width)/2; + ctx->crop_params.top_crop_offset = 0; + ctx->crop_params.bottom_crop_offset = (((ctx->sh_params.height_in_maps_units_minus1 + 1) + *MB_SIZE) - ctx->vparams.source_frame_height)/2; + if (ctx->crop_params.right_crop_offset | ctx->crop_params.bottom_crop_offset) + ctx->crop_params.clip = TRUE; + + pr_debug("s_fmt_flags=%#08x\n", ctx->s_fmt_flags); + if ((ctx->s_fmt_flags & S_FMT_FLAG_OUT_RECV) && + (ctx->s_fmt_flags & S_FMT_FLAG_CAP_RECV)) { + /* if the stream has already been created for this context */ + /* better destroy the original, and create a new one */ + if (ctx->s_fmt_flags & S_FMT_FLAG_STREAM_CREATED) + topaz_stream_destroy(ctx->topaz_str_context); + + topaz_stream_create(ctx, &ctx->vparams, ((base_pipe++ % 2) ? 0 : 1), 2, + &ctx->rc, &ctx->topaz_str_context); + + topaz_h264_prepare_sequence_header(ctx->topaz_str_context, + ctx->sh_params.width_in_mbs_minus1 + 1, + ctx->sh_params.height_in_maps_units_minus1 + 1, + TRUE, &ctx->vui_params, + &ctx->crop_params, + &ctx->sh_params, FALSE); + /* Note: cqp_offset looks unset in img */ + topaz_h264_prepare_picture_header(ctx->topaz_str_context, 0); + + topaz_load_context(ctx->topaz_str_context); + + ctx->s_fmt_flags |= S_FMT_FLAG_STREAM_CREATED; + } + + return 0; +} + +static int vxe_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + return -EINVAL; + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + default: + return -EINVAL; + } +} + +static int vxe_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *cmd) +{ + struct vxe_enc_ctx *ctx = file2ctx(file); + + if (cmd->cmd != V4L2_DEC_CMD_STOP) + return -EINVAL; + + mutex_lock_nested(ctx->mutex, SUBCLASS_VXE_V4L2); + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0 || + !ctx->out_queue.streaming || !ctx->cap_queue.streaming) { + /* Buffers are still in queue for encode, set eos flag */ + ctx->eos = TRUE; + mutex_unlock((struct mutex *)ctx->mutex); + } else if ((ctx->available_source_frames > 0) || + (ctx->frames_encoding) > 0) { + /* + * Buffers are still in firmware for encode. Tell topaz + * that last frame sent is last frame in stream + */ + topaz_end_of_stream(ctx->topaz_str_context, ctx->frame_num); + ctx->last_frame_num = ctx->frame_num; + mutex_unlock((struct mutex *)ctx->mutex); + } else { + /* All buffers are encoded, so issue dummy stream end */ + mutex_unlock((struct mutex *)ctx->mutex); + vxe_eos(ctx); + } + return 0; +} + + + +static int vxe_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + int i, found = 0; + + if (fsize->index != 0) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(vxe_enc_formats); ++i) { + if (vxe_enc_formats[i].fourcc == fsize->pixel_format) { + found = 1; + break; + } + } + if (!found) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = VXE_ENCODER_MIN_WIDTH; + fsize->stepwise.max_width = VXE_ENCODER_MAX_WIDTH; + fsize->stepwise.step_width = 1; + fsize->stepwise.min_height = VXE_ENCODER_MIN_HEIGHT; + fsize->stepwise.max_height = VXE_ENCODER_MAX_HEIGHT; + fsize->stepwise.step_height = 1; + + fsize->reserved[0] = 0; + fsize->reserved[1] = 0; + + return 0; +} + +static int vxe_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *fival) +{ + int i, found = 0; + if (fival->index) + return -EINVAL; + + if (fival->width > VXE_ENCODER_MAX_WIDTH || + fival->width < VXE_ENCODER_MIN_WIDTH || + fival->height > VXE_ENCODER_MAX_HEIGHT || + fival->height < VXE_ENCODER_MIN_HEIGHT) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(vxe_enc_formats); ++i) { + if (vxe_enc_formats[i].fourcc == fival->pixel_format) { + found = 1; + break; + } + } + if (!found) + return -EINVAL; + + fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; + fival->stepwise.min = frmivals[0]; + fival->stepwise.max = frmivals[1]; + fival->stepwise.step = frmivals[1]; + + fival->reserved[0] = 0; + fival->reserved[1] = 0; + + return 0; +} + +static int vxe_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct vxe_enc_ctx *ctx = file2ctx(file); + + if (V4L2_TYPE_IS_OUTPUT(parm->type)) { + parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.output.timeperframe.numerator = 1; + parm->parm.output.timeperframe.denominator = ctx->rc.frame_rate; + } else { + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.timeperframe.numerator = 1; + parm->parm.capture.timeperframe.denominator = ctx->rc.frame_rate; + } + + return 0; +} + +static int vxe_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct vxe_enc_ctx *ctx = file2ctx(file); + unsigned int num, den; + + /* Cannot change values once context is created */ + /* TODO: Handle controls after stream is created but before streamon */ + if (ctx->s_fmt_flags & S_FMT_FLAG_STREAM_CREATED) + return -EBUSY; + + if (V4L2_TYPE_IS_OUTPUT(parm->type)) { + parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + num = parm->parm.output.timeperframe.numerator; + den = parm->parm.output.timeperframe.denominator; + } else { + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + num = parm->parm.capture.timeperframe.numerator; + den = parm->parm.capture.timeperframe.denominator; + } + + if (parm->parm.output.timeperframe.denominator && + parm->parm.output.timeperframe.numerator) { + ctx->rc.frame_rate = den / num; + } + + if (V4L2_TYPE_IS_OUTPUT(parm->type)) { + parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.output.timeperframe.numerator = 1; + parm->parm.output.timeperframe.denominator = ctx->rc.frame_rate; + } else { + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.timeperframe.numerator = 1; + parm->parm.capture.timeperframe.denominator = ctx->rc.frame_rate; + } + + return 0; +} + +static const struct v4l2_ioctl_ops vxe_enc_ioctl_ops = { + .vidioc_querycap = vxe_querycap, + + .vidioc_enum_fmt_vid_cap = vxe_enum_fmt, + .vidioc_g_fmt_vid_cap_mplane = vxe_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = vxe_try_fmt, + .vidioc_s_fmt_vid_cap_mplane = vxe_s_fmt, + + .vidioc_enum_fmt_vid_out = vxe_enum_fmt, + .vidioc_g_fmt_vid_out_mplane = vxe_g_fmt, + .vidioc_try_fmt_vid_out_mplane = vxe_try_fmt, + .vidioc_s_fmt_vid_out_mplane = vxe_s_fmt, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_log_status = v4l2_ctrl_log_status, + + .vidioc_subscribe_event = vxe_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = vxe_cmd, + + .vidioc_enum_framesizes = vxe_enum_framesizes, + .vidioc_enum_frameintervals = vxe_enum_frameintervals, + + .vidioc_g_parm = vxe_g_parm, + .vidioc_s_parm = vxe_s_parm, +}; + +static const struct of_device_id vxe_enc_of_match[] = { + {.compatible = "img,vxe384"}, { /* end */}, +}; +MODULE_DEVICE_TABLE(of, vxe_enc_of_match); + +static irqreturn_t soft_thread_irq(int irq, void *dev_data) +{ + unsigned char handled; + + if (!dev_data) + return IRQ_NONE; + + handled = topazdd_threaded_isr(dev_data); + if (handled) + return IRQ_HANDLED; + + return IRQ_NONE; +} + +static irqreturn_t hard_isrcb(int irq, void *dev_data) +{ + if (!dev_data) + return IRQ_NONE; + + return topazdd_isr(dev_data); +} + +static int vxe_enc_probe(struct platform_device *pdev) +{ + struct vxe_dev *vxe; + struct resource *res; + const struct of_device_id *of_dev_id; + struct video_device *vfd; + int ret; + int module_irq; + struct vxe_enc_ctx *ctx; + struct heap_config *heap_configs = vxe_enc_heap_configs; + int num_heaps = ARRAY_SIZE(vxe_enc_heap_configs); + unsigned int i; + + of_dev_id = of_match_device(vxe_enc_of_match, &pdev->dev); + if (!of_dev_id) { + dev_err(&pdev->dev, "%s: Unable to match device\n", __func__); + return -ENODEV; + } + + dma_set_mask(&pdev->dev, DMA_BIT_MASK(40)); + + vxe = devm_kzalloc(&pdev->dev, sizeof(*vxe), GFP_KERNEL); + if (!vxe) + return -ENOMEM; + + vxe->dev = &pdev->dev; + vxe->plat_dev = pdev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + vxe->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(vxe->reg_base)) + return PTR_ERR(vxe->reg_base); + + module_irq = platform_get_irq(pdev, 0); + if (module_irq < 0) + return -ENXIO; + vxe->module_irq = module_irq; + + ret = img_mem_init(vxe->dev); + if (ret) { + dev_err(vxe->dev, "Failed to initialize memory\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&vxe->drv_ctx.heaps); + vxe->drv_ctx.internal_heap_id = VXE_INVALID_ID; + + /* Initialise memory management component */ + for (i = 0; i < num_heaps; i++) { + struct vxe_heap *heap; +#ifdef DEBUG_ENCODER_DRIVER + dev_info(vxe->dev, "%s: adding heap of type %d\n", + __func__, heap_configs[i].type); +#endif + + heap = kzalloc(sizeof(*heap), GFP_KERNEL); + if (!heap) { + ret = -ENOMEM; + goto heap_add_failed; + } + + ret = img_mem_add_heap(&heap_configs[i], &heap->id); + if (ret < 0) { + dev_err(vxe->dev, "%s: failed to init heap (type %d)!\n", + __func__, heap_configs[i].type); + kfree(heap); + goto heap_add_failed; + } + list_add(&heap->list, &vxe->drv_ctx.heaps); + + /* Implicitly, first heap is used for internal allocations */ + if (vxe->drv_ctx.internal_heap_id < 0) { + vxe->drv_ctx.internal_heap_id = heap->id; + dev_err(vxe->dev, "%s: using heap %d for internal alloc\n", + __func__, vxe->drv_ctx.internal_heap_id); + } + } + + /* Do not proceed if internal heap not defined */ + if (vxe->drv_ctx.internal_heap_id < 0) { + dev_err(vxe->dev, "%s: failed to locate heap for internal alloc\n", + __func__); + ret = -EINVAL; + /* Loop registered heaps just for sanity */ + goto heap_add_failed; + } + + ret = vxe_init_mem(vxe); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize memory\n"); + return -ENOMEM; + } + + vxe->mutex = kzalloc(sizeof(*vxe->mutex), GFP_KERNEL); + if (!vxe->mutex) + return -ENOMEM; + + mutex_init(vxe->mutex); + + platform_set_drvdata(pdev, vxe); + + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "%s: failed to enable clock, status = %d\n", + __func__, ret); + goto exit; + } + + ret = devm_request_threaded_irq(&pdev->dev, module_irq, (irq_handler_t)hard_isrcb, + (irq_handler_t)soft_thread_irq, IRQF_SHARED, + IMG_VXE_ENC_MODULE_NAME, &vxe->topaz_dev_ctx); + if (ret) { + dev_err(&pdev->dev, "Failed to get IRQ\n"); + goto out_put_sync; + } + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + free_irq(module_irq, &vxe->topaz_dev_ctx); + return -ENOMEM; + } + ctx->dev = vxe; + + vxe_fill_default_params(ctx); + + ctx->mem_ctx = vxe->drv_ctx.mem_ctx; + ctx->mmu_ctx = vxe->drv_ctx.mmu_ctx; + + vxe->ctx = ctx; + + ret = topazdd_init((unsigned long)vxe->reg_base, res->end - res->start + 1, + (MMU_USE_MMU_FLAG | MMU_EXTENDED_ADDR_FLAG), + ctx, vxe->drv_ctx.ptd, &vxe->topaz_dev_ctx); + if (ret) + goto out_free_irq; + + vxe->streams = kzalloc(sizeof(*vxe->streams), GFP_KERNEL); + if (!vxe->streams) { + ret = -ENOMEM; + goto topazdd_deinit; + } + idr_init(vxe->streams); + + ret = init_topaz_core(vxe->topaz_dev_ctx, &vxe->num_pipes, + (MMU_USE_MMU_FLAG | MMU_EXTENDED_ADDR_FLAG), + vxe_return_resource); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize topaz core\n"); + goto topazdd_deinit; + } + + ret = v4l2_device_register(&pdev->dev, &vxe->ti_vxe_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to register v4l2 device\n"); + goto topaz_core_deinit; + } + + vfd = video_device_alloc(); + if (!vfd) { + dev_err(&pdev->dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto out_v4l2_device; + } + + snprintf(vfd->name, sizeof(vfd->name), "%s", IMG_VXE_ENC_MODULE_NAME); + vfd->fops = &vxe_enc_fops; + vfd->ioctl_ops = &vxe_enc_ioctl_ops; + vfd->minor = -1; + vfd->release = video_device_release; + vfd->vfl_dir = VFL_DIR_M2M; + vfd->v4l2_dev = &vxe->ti_vxe_dev; + vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + vfd->lock = vxe->mutex; + + vxe->vfd = vfd; + video_set_drvdata(vfd, vxe); + + vxe->m2m_dev = v4l2_m2m_init(&m2m_ops); + if (IS_ERR_VALUE((unsigned long)vxe->m2m_dev)) { + dev_err(&pdev->dev, "Failed to init mem2mem device\n"); + ret = -EINVAL; + goto out_vid_dev; + } + + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 1); + if (ret) { + dev_err(&pdev->dev, "Failed to register video device\n"); + goto out_vid_reg; + } + v4l2_info(&vxe->ti_vxe_dev, "encoder registered as /dev/video%d\n", + vfd->num); + + return 0; + +out_vid_reg: + v4l2_m2m_release(vxe->m2m_dev); +out_vid_dev: + video_device_release(vfd); +out_v4l2_device: + v4l2_device_unregister(&vxe->ti_vxe_dev); +topaz_core_deinit: + deinit_topaz_core(); +topazdd_deinit: + topazdd_deinit(vxe->topaz_dev_ctx); +out_free_irq: + kfree(vxe->ctx); + free_irq(module_irq, &vxe->topaz_dev_ctx); +out_put_sync: + pm_runtime_put_sync(&pdev->dev); +heap_add_failed: + while (!list_empty(&vxe->drv_ctx.heaps)) { + struct vxe_heap *heap; + + heap = list_first_entry(&vxe->drv_ctx.heaps, struct vxe_heap, list); + __list_del_entry(&heap->list); + img_mem_del_heap(heap->id); + kfree(heap); + } + vxe->drv_ctx.internal_heap_id = VXE_INVALID_ID; + +exit: + pm_runtime_disable(&pdev->dev); + vxe_deinit_mem(vxe); + + return ret; +} + +static int vxe_enc_remove(struct platform_device *pdev) +{ + struct vxe_dev *vxe = platform_get_drvdata(pdev); + + topazdd_deinit(vxe->topaz_dev_ctx); + + kfree(vxe->ctx); + vxe_deinit_mem(vxe); + + free_irq(vxe->module_irq, &vxe->topaz_dev_ctx); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static struct platform_driver vxe_enc_driver = { + .probe = vxe_enc_probe, + .remove = vxe_enc_remove, + .driver = { + .name = "img_enc", + .of_match_table = vxe_enc_of_match, + }, +}; +module_platform_driver(vxe_enc_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("IMG VXE384 video encoder driver"); diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_v4l2.h b/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_v4l2.h --- a/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_v4l2.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/encoder/vxe_v4l2.h 2024-07-07 20:37:34.664306649 -0400 @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * V4L2 interface header + * + * Copyright (c) Imagination Technologies Ltd. + * Copyright (c) 2021 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Sunita Nadampalli + * + * Re-written for upstreming + * Sidraya Jayagond + */ + +#ifndef _VXE_V4L2_H +#define _VXE_V4L2_H + +#include +#include +#include +#include + +/* + * struct vxe_ctrl - contains info for each supported v4l2 control + */ +struct vxe_ctrl { + unsigned int cid; + enum v4l2_ctrl_type type; + unsigned char name[32]; + int minimum; + int maximum; + int step; + int default_value; + unsigned char compound; +}; + +extern struct mem_space topaz_mem_space[]; + +#endif diff -Naur --no-dereference a/drivers/media/platform/imagination/vxe-vxd/Makefile b/drivers/media/platform/imagination/vxe-vxd/Makefile --- a/drivers/media/platform/imagination/vxe-vxd/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/imagination/vxe-vxd/Makefile 2024-07-07 20:37:34.652306589 -0400 @@ -0,0 +1,163 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Optional Video feature configuration control + +# (1) +# This config allows enabling or disabling of HEVC/H265 video +# decoding functionality with IMG VXD Video decoder. If you +# do not want HEVC decode capability, select N. +# If unsure, select Y +HAS_HEVC ?=y + +# (2) +# This config enables error concealment with gray pattern. +# Disable if you do not want error concealment capability. +# If unsure, say Y +ERROR_CONCEALMENT ?=y + +# (3) +# This config, if enabled, configures H264 video decoder to +# output frames in the decode order with no buffering and +# picture reordering inside codec. +# If unsure, say N +REDUCED_DPB_NO_PIC_REORDERING ?=n + +# (4) +# This config, if enabled, enables all the debug traces in +# decoder driver. Enable it only for debug purpose +# Keep it always disabled for release codebase +DEBUG_DECODER_DRIVER ?=n + +# (5) +# This config allows enabling or disabling of MJPEG video +# decoding functionality with IMG VXD Video decoder. If you +# do not want MJPEG decode capability, select N. +# If unsure, select Y +HAS_JPEG ?=y + +# (6) +# This config allows simulation of Error recovery. +# This config is only for testing, never enable it for release build. +ERROR_RECOVERY_SIMULATION ?=n + +# (7) +# This config enables allocation of capture buffers from +# dma contiguous memory. +# If unsure, say Y +CAPTURE_CONTIG_ALLOC ?=y + +vxd-dec-y += common/img_mem_man.o \ + common/img_mem_unified.o \ + common/imgmmu.o \ + common/pool_api.o \ + common/idgen_api.o \ + common/talmmu_api.o \ + common/pool.o \ + common/hash.o \ + common/ra.o \ + common/addr_alloc.o \ + common/work_queue.o \ + common/lst.o \ + common/dq.o \ + common/resource.o \ + common/rman_api.o \ + +vxd-dec-y += decoder/vxd_core.o \ + decoder/vxd_pvdec.o \ + decoder/dec_resources.o \ + decoder/pixel_api.o \ + decoder/vdecdd_utils_buf.o \ + decoder/vdecdd_utils.o \ + decoder/vdec_mmu_wrapper.o \ + decoder/hw_control.o \ + decoder/vxd_int.o \ + decoder/translation_api.o \ + decoder/decoder.o \ + decoder/core.o \ + decoder/swsr.o \ + decoder/h264_secure_parser.o \ + decoder/bspp.o \ + decoder/vxd_dec.o \ + decoder/vxd_v4l2.o \ + + +ifeq ($(HAS_HEVC),y) +ccflags-y += -DHAS_HEVC +vxd-dec-y += decoder/hevc_secure_parser.o +endif + +ifeq ($(HAS_JPEG),y) +ccflags-y += -DHAS_JPEG +vxd-dec-y += decoder/jpeg_secure_parser.o +endif + +ifeq ($(DEBUG_DECODER_DRIVER), y) +ccflags-y += -DDEBUG_DECODER_DRIVER +ccflags-y += -DDEBUG +endif + +ifeq ($(ERROR_CONCEALMENT),y) +ccflags-y += -DERROR_CONCEALMENT +endif + +ifeq ($(REDUCED_DPB_NO_PIC_REORDERING),y) +ccflags-y += -DREDUCED_DPB_NO_PIC_REORDERING +endif + +ifeq ($(ERROR_RECOVERY_SIMULATION),y) +ccflags-y += -DERROR_RECOVERY_SIMULATION +endif + +ifeq ($(CAPTURE_CONTIG_ALLOC),y) +ccflags-y += -DCAPTURE_CONTIG_ALLOC +endif + +obj-$(CONFIG_VIDEO_IMG_VXD_DEC) += vxd-dec.o + +# (1) +# This config, if enabled, enables all the debug traces in +# encoder driver. Enable it only for debug purpose +# Keep it always disabled for release codebase +DEBUG_ENCODER_DRIVER ?=n + +# (3) +# This config enables encoder performance profiling +# keep it always disabled. Enable it only for profiling in development +# environments. +ENABLE_PROFILING ?=n + +vxe-enc-y += common/img_mem_man.o \ + common/img_mem_unified.o \ + common/talmmu_api.o \ + common/addr_alloc.o \ + common/lst.o \ + common/hash.o \ + common/ra.o \ + common/pool.o \ + common/rman_api.o \ + common/dq.o \ + common/idgen_api.o \ + common/imgmmu.o \ + common/work_queue.o \ + +vxe-enc-y += encoder/vxe_v4l2.o \ + encoder/vxe_enc.o \ + encoder/topaz_device.o \ + encoder/topazmmu.o \ + encoder/topaz_api.o \ + encoder/topaz_api_utils.o \ + encoder/header_gen.o \ + encoder/mtx_fwif.o \ + +obj-$(CONFIG_VIDEO_IMG_VXE_ENC) += vxe-enc.o + +ifeq ($(DEBUG_ENCODER_DRIVER), y) +ccflags-y += -DDEBUG_ENCODER_DRIVER +ccflags-y += -DDEBUG +endif + +ifeq ($(ENABLE_PROFILING),y) +ccflags-y += -DENABLE_PROFILING +endif + +ccflags-y += -I$(srctree)/drivers/media/platform/imagination/vxe-vxd/common/ diff -Naur --no-dereference a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig --- a/drivers/media/platform/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/Kconfig 2024-07-07 20:37:34.648306569 -0400 @@ -69,6 +69,7 @@ source "drivers/media/platform/atmel/Kconfig" source "drivers/media/platform/cadence/Kconfig" source "drivers/media/platform/chips-media/Kconfig" +source "drivers/media/platform/imagination/Kconfig" source "drivers/media/platform/intel/Kconfig" source "drivers/media/platform/marvell/Kconfig" source "drivers/media/platform/mediatek/Kconfig" diff -Naur --no-dereference a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile --- a/drivers/media/platform/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/Makefile 2024-07-07 20:37:34.648306569 -0400 @@ -12,6 +12,7 @@ obj-y += atmel/ obj-y += cadence/ obj-y += chips-media/ +obj-y += imagination/ obj-y += intel/ obj-y += marvell/ obj-y += mediatek/ diff -Naur --no-dereference a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c 2024-07-07 20:37:34.664306649 -0400 @@ -0,0 +1,1845 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * TI CSI2RX Shim Wrapper Driver + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + * Author: Pratyush Yadav + * Author: Jai Luthra + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define TI_CSI2RX_MODULE_NAME "j721e-csi2rx" + +#define SHIM_CNTL 0x10 +#define SHIM_CNTL_PIX_RST BIT(0) + +#define SHIM_DMACNTX(i) (0x20 + ((i) * 0x20)) +#define SHIM_DMACNTX_EN BIT(31) +#define SHIM_DMACNTX_YUV422 GENMASK(27, 26) +#define SHIM_DMACNTX_SIZE GENMASK(21, 20) +#define SHIM_DMACNTX_VC GENMASK(9, 6) +#define SHIM_DMACNTX_FMT GENMASK(5, 0) +#define SHIM_DMACNTX_YUV422_MODE_11 3 +#define SHIM_DMACNTX_SIZE_8 0 +#define SHIM_DMACNTX_SIZE_16 1 +#define SHIM_DMACNTX_SIZE_32 2 + +#define SHIM_PSI_CFG0(i) (0x24 + ((i) * 0x20)) +#define SHIM_PSI_CFG0_SRC_TAG GENMASK(15, 0) +#define SHIM_PSI_CFG0_DST_TAG GENMASK(31, 16) + +#define PSIL_WORD_SIZE_BYTES 16 +#define TI_CSI2RX_MAX_CTX 32 + +/* + * There are no hard limits on the width or height. The DMA engine can handle + * all sizes. The max width and height are arbitrary numbers for this driver. + * Use 16K * 16K as the arbitrary limit. It is large enough that it is unlikely + * the limit will be hit in practice. + */ +#define MAX_WIDTH_BYTES SZ_16K +#define MAX_HEIGHT_LINES SZ_16K + +#define TI_CSI2RX_PAD_SINK 0 +#define TI_CSI2RX_PAD_FIRST_SOURCE 1 +#define TI_CSI2RX_MAX_SOURCE_PADS TI_CSI2RX_MAX_CTX +#define TI_CSI2RX_MAX_PADS (1 + TI_CSI2RX_MAX_SOURCE_PADS) + +#define DRAIN_TIMEOUT_MS 50 +#define DRAIN_BUFFER_SIZE SZ_32K + +struct ti_csi2rx_fmt { + u32 fourcc; /* Four character code. */ + u32 code; /* Mbus code. */ + u32 csi_dt; /* CSI Data type. */ + u8 bpp; /* Bits per pixel. */ + u8 size; /* Data size shift when unpacking. */ +}; + +struct ti_csi2rx_buffer { + /* Common v4l2 buffer. Must be first. */ + struct vb2_v4l2_buffer vb; + struct list_head list; + struct ti_csi2rx_ctx *ctx; +}; + +enum ti_csi2rx_dma_state { + TI_CSI2RX_DMA_STOPPED, /* Streaming not started yet. */ + TI_CSI2RX_DMA_IDLE, /* Streaming but no pending DMA operation. */ + TI_CSI2RX_DMA_ACTIVE, /* Streaming and pending DMA operation. */ +}; + +struct ti_csi2rx_dma { + /* Protects all fields in this struct. */ + spinlock_t lock; + struct dma_chan *chan; + /* Buffers queued to the driver, waiting to be processed by DMA. */ + struct list_head queue; + enum ti_csi2rx_dma_state state; + /* + * Queue of buffers submitted to DMA engine. + */ + struct list_head submitted; +}; + +struct ti_csi2rx_dev; + +struct ti_csi2rx_ctx { + struct ti_csi2rx_dev *csi; + struct video_device vdev; + struct vb2_queue vidq; + struct mutex mutex; /* To serialize ioctls. */ + struct v4l2_format v_fmt; + struct ti_csi2rx_dma dma; + struct media_pad pad; + u32 sequence; + u32 idx; + u32 vc; + u32 stream; +}; + +struct ti_csi2rx_dev { + struct device *dev; + void __iomem *shim; + struct mutex mutex; /* To serialize ioctls. */ + unsigned int enable_count; + unsigned int num_ctx; + struct v4l2_device v4l2_dev; + struct media_device mdev; + struct media_pipeline pipe; + struct media_pad pads[TI_CSI2RX_MAX_PADS]; + struct v4l2_async_notifier notifier; + struct v4l2_subdev *source; + struct v4l2_subdev subdev; + struct ti_csi2rx_ctx ctx[TI_CSI2RX_MAX_CTX]; + u64 enabled_streams_mask; + /* Buffer to drain stale data from PSI-L endpoint */ + struct { + void *vaddr; + dma_addr_t paddr; + size_t len; + } drain; +}; + +static const struct ti_csi2rx_fmt ti_csi2rx_formats[] = { + { + .fourcc = V4L2_PIX_FMT_YUYV, + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_YVYU, + .code = MEDIA_BUS_FMT_YVYU8_1X16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, + .code = MEDIA_BUS_FMT_VYUY8_1X16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_GREY, + .code = MEDIA_BUS_FMT_Y8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SRGGI10, + .code = MEDIA_BUS_FMT_SRGGI10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGRIG10, + .code = MEDIA_BUS_FMT_SGRIG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SBGGI10, + .code = MEDIA_BUS_FMT_SBGGI10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGBIG10, + .code = MEDIA_BUS_FMT_SGBIG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGIRG10, + .code = MEDIA_BUS_FMT_SGIRG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SIGGR10, + .code = MEDIA_BUS_FMT_SIGGR10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGIBG10, + .code = MEDIA_BUS_FMT_SGIBG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SIGGB10, + .code = MEDIA_BUS_FMT_SIGGB10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_RGB565X, + .code = MEDIA_BUS_FMT_RGB565_1X16, + .csi_dt = MIPI_CSI2_DT_RGB565, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_XBGR32, + .code = MEDIA_BUS_FMT_RGB888_1X24, + .csi_dt = MIPI_CSI2_DT_RGB888, + .bpp = 32, + .size = SHIM_DMACNTX_SIZE_32, + }, { + .fourcc = V4L2_PIX_FMT_RGBX32, + .code = MEDIA_BUS_FMT_BGR888_1X24, + .csi_dt = MIPI_CSI2_DT_RGB888, + .bpp = 32, + .size = SHIM_DMACNTX_SIZE_32, + }, + + /* More formats can be supported but they are not listed for now. */ +}; + +/* Forward declaration needed by ti_csi2rx_dma_callback. */ +static int ti_csi2rx_start_dma(struct ti_csi2rx_ctx *ctx, + struct ti_csi2rx_buffer *buf); + +static const struct ti_csi2rx_fmt *find_format_by_fourcc(u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ti_csi2rx_formats); i++) { + if (ti_csi2rx_formats[i].fourcc == pixelformat) + return &ti_csi2rx_formats[i]; + } + + return NULL; +} + +static const struct ti_csi2rx_fmt *find_format_by_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ti_csi2rx_formats); i++) { + if (ti_csi2rx_formats[i].code == code) + return &ti_csi2rx_formats[i]; + } + + return NULL; +} + +static void ti_csi2rx_fill_fmt(const struct ti_csi2rx_fmt *csi_fmt, + struct v4l2_format *v4l2_fmt) +{ + struct v4l2_pix_format *pix = &v4l2_fmt->fmt.pix; + unsigned int pixels_in_word; + + pixels_in_word = PSIL_WORD_SIZE_BYTES * 8 / csi_fmt->bpp; + + /* Clamp width and height to sensible maximums (16K x 16K) */ + pix->width = clamp_t(unsigned int, pix->width, + pixels_in_word, + MAX_WIDTH_BYTES * 8 / csi_fmt->bpp); + pix->height = clamp_t(unsigned int, pix->height, 1, MAX_HEIGHT_LINES); + + /* Width should be a multiple of transfer word-size */ + pix->width = rounddown(pix->width, pixels_in_word); + + v4l2_fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + pix->pixelformat = csi_fmt->fourcc; + pix->bytesperline = pix->width * (csi_fmt->bpp / 8); + pix->sizeimage = pix->bytesperline * pix->height; +} + +static int ti_csi2rx_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, TI_CSI2RX_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, TI_CSI2RX_MODULE_NAME, sizeof(cap->card)); + + return 0; +} + +static int ti_csi2rx_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + const struct ti_csi2rx_fmt *fmt = NULL; + + if (f->mbus_code) { + /* 1-to-1 mapping between bus formats and pixel formats */ + if (f->index > 0) + return -EINVAL; + + fmt = find_format_by_code(f->mbus_code); + } else { + if (f->index >= ARRAY_SIZE(ti_csi2rx_formats)) + return -EINVAL; + + fmt = &ti_csi2rx_formats[f->index]; + } + + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->fourcc; + memset(f->reserved, 0, sizeof(f->reserved)); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int ti_csi2rx_g_fmt_vid_cap(struct file *file, void *prov, + struct v4l2_format *f) +{ + struct ti_csi2rx_ctx *csi = video_drvdata(file); + + *f = csi->v_fmt; + + return 0; +} + +static int ti_csi2rx_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + const struct ti_csi2rx_fmt *fmt; + + /* + * Default to the first format if the requested pixel format code isn't + * supported. + */ + fmt = find_format_by_fourcc(f->fmt.pix.pixelformat); + if (!fmt) + fmt = &ti_csi2rx_formats[0]; + + /* Interlaced formats are not supported. */ + f->fmt.pix.field = V4L2_FIELD_NONE; + + ti_csi2rx_fill_fmt(fmt, f); + + return 0; +} + +static int ti_csi2rx_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ti_csi2rx_ctx *csi = video_drvdata(file); + struct vb2_queue *q = &csi->vidq; + int ret; + + if (vb2_is_busy(q)) + return -EBUSY; + + ret = ti_csi2rx_try_fmt_vid_cap(file, priv, f); + if (ret < 0) + return ret; + + csi->v_fmt = *f; + + return 0; +} + +static int ti_csi2rx_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + const struct ti_csi2rx_fmt *fmt; + unsigned int pixels_in_word; + + fmt = find_format_by_fourcc(fsize->pixel_format); + if (!fmt || fsize->index != 0) + return -EINVAL; + + /* + * Number of pixels in one PSI-L word. The transfer happens in multiples + * of PSI-L word sizes. + */ + pixels_in_word = PSIL_WORD_SIZE_BYTES * 8 / fmt->bpp; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = pixels_in_word; + fsize->stepwise.max_width = rounddown(MAX_WIDTH_BYTES * 8 / fmt->bpp, + pixels_in_word); + fsize->stepwise.step_width = pixels_in_word; + fsize->stepwise.min_height = 1; + fsize->stepwise.max_height = MAX_HEIGHT_LINES; + fsize->stepwise.step_height = 1; + + return 0; +} + +static const struct v4l2_ioctl_ops csi_ioctl_ops = { + .vidioc_querycap = ti_csi2rx_querycap, + .vidioc_enum_fmt_vid_cap = ti_csi2rx_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = ti_csi2rx_try_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = ti_csi2rx_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = ti_csi2rx_s_fmt_vid_cap, + .vidioc_enum_framesizes = ti_csi2rx_enum_framesizes, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static const struct v4l2_file_operations csi_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +static int csi_async_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asc) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(notifier->v4l2_dev->dev); + + csi->source = subdev; + + return 0; +} + +static int csi_async_notifier_complete(struct v4l2_async_notifier *notifier) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(notifier->v4l2_dev->dev); + int ret, i; + + /* Create link from source to subdev */ + ret = v4l2_create_fwnode_links_to_pad(csi->source, + &csi->pads[TI_CSI2RX_PAD_SINK], + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + + /* Create and link video nodes for all DMA contexts */ + for (i = 0; i < csi->num_ctx; i++) { + struct ti_csi2rx_ctx *ctx = &csi->ctx[i]; + struct video_device *vdev = &ctx->vdev; + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) + goto unregister_dev; + + ret = media_create_pad_link(&csi->subdev.entity, + TI_CSI2RX_PAD_FIRST_SOURCE + ctx->idx, + &vdev->entity, 0, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) { + video_unregister_device(vdev); + goto unregister_dev; + } + } + + ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); + if (ret) + goto unregister_dev; + + return 0; + +unregister_dev: + i--; + for (; i >= 0; i--) + video_unregister_device(&csi->ctx[i].vdev); + return ret; +} + +static const struct v4l2_async_notifier_operations csi_async_notifier_ops = { + .bound = csi_async_notifier_bound, + .complete = csi_async_notifier_complete, +}; + +static int ti_csi2rx_notifier_register(struct ti_csi2rx_dev *csi) +{ + struct fwnode_handle *fwnode; + struct v4l2_async_connection *asc; + struct device_node *node; + int ret; + + node = of_get_child_by_name(csi->dev->of_node, "csi-bridge"); + if (!node) + return -EINVAL; + + fwnode = of_fwnode_handle(node); + if (!fwnode) { + of_node_put(node); + return -EINVAL; + } + + v4l2_async_nf_init(&csi->notifier, &csi->v4l2_dev); + csi->notifier.ops = &csi_async_notifier_ops; + + asc = v4l2_async_nf_add_fwnode(&csi->notifier, fwnode, + struct v4l2_async_connection); + of_node_put(node); + if (IS_ERR(asc)) { + v4l2_async_nf_cleanup(&csi->notifier); + return PTR_ERR(asc); + } + + ret = v4l2_async_nf_register(&csi->notifier); + if (ret) { + v4l2_async_nf_cleanup(&csi->notifier); + return ret; + } + + return 0; +} + +static void ti_csi2rx_setup_shim(struct ti_csi2rx_ctx *ctx) +{ + struct ti_csi2rx_dev *csi = ctx->csi; + const struct ti_csi2rx_fmt *fmt; + unsigned int reg; + + fmt = find_format_by_fourcc(ctx->v_fmt.fmt.pix.pixelformat); + + /* De-assert the pixel interface reset. */ + if (!csi->enable_count) { + reg = SHIM_CNTL_PIX_RST; + writel(reg, csi->shim + SHIM_CNTL); + } + + reg = SHIM_DMACNTX_EN; + reg |= FIELD_PREP(SHIM_DMACNTX_FMT, fmt->csi_dt); + + /* + * The hardware assumes incoming YUV422 8-bit data on MIPI CSI2 bus + * follows the spec and is packed in the order U0 -> Y0 -> V0 -> Y1 -> + * ... + * + * There is an option to swap the bytes around before storing in + * memory, to achieve different pixel formats: + * + * Byte3 <----------- Byte0 + * [ Y1 ][ V0 ][ Y0 ][ U0 ] MODE 11 + * [ Y1 ][ U0 ][ Y0 ][ V0 ] MODE 10 + * [ V0 ][ Y1 ][ U0 ][ Y0 ] MODE 01 + * [ U0 ][ Y1 ][ V0 ][ Y0 ] MODE 00 + * + * We don't have any requirement to change pixelformat from what is + * coming from the source, so we keep it in MODE 11, which does not + * swap any bytes when storing in memory. + */ + switch (fmt->fourcc) { + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + reg |= FIELD_PREP(SHIM_DMACNTX_YUV422, + SHIM_DMACNTX_YUV422_MODE_11); + break; + default: + /* Ignore if not YUV 4:2:2 */ + break; + } + + reg |= FIELD_PREP(SHIM_DMACNTX_SIZE, fmt->size); + reg |= FIELD_PREP(SHIM_DMACNTX_VC, ctx->vc); + + writel(reg, csi->shim + SHIM_DMACNTX(ctx->idx)); + + reg = FIELD_PREP(SHIM_PSI_CFG0_SRC_TAG, 0) | + FIELD_PREP(SHIM_PSI_CFG0_DST_TAG, 0); + writel(reg, csi->shim + SHIM_PSI_CFG0(ctx->idx)); +} + +static void ti_csi2rx_drain_callback(void *param) +{ + struct completion *drain_complete = param; + + complete(drain_complete); +} + +/* + * Drain the stale data left at the PSI-L endpoint. + * + * This might happen if no buffers are queued in time but source is still + * streaming. In multi-stream scenarios this can happen when one stream is + * stopped but other is still streaming, and thus module-level pixel reset is + * not asserted. + * + * To prevent that stale data corrupting the subsequent transactions, it is + * required to issue DMA requests to drain it out. + */ +static int ti_csi2rx_drain_dma(struct ti_csi2rx_ctx *ctx) +{ + struct ti_csi2rx_dev *csi = ctx->csi; + struct dma_async_tx_descriptor *desc; + struct completion drain_complete; + dma_cookie_t cookie; + int ret; + + init_completion(&drain_complete); + + desc = dmaengine_prep_slave_single(ctx->dma.chan, csi->drain.paddr, + csi->drain.len, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + ret = -EIO; + goto out; + } + + desc->callback = ti_csi2rx_drain_callback; + desc->callback_param = &drain_complete; + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) + goto out; + + dma_async_issue_pending(ctx->dma.chan); + + if (!wait_for_completion_timeout(&drain_complete, + msecs_to_jiffies(DRAIN_TIMEOUT_MS))) { + dmaengine_terminate_sync(ctx->dma.chan); + dev_dbg(csi->dev, "DMA transfer timed out for drain buffer\n"); + ret = -ETIMEDOUT; + goto out; + } +out: + return ret; +} + +static int ti_csi2rx_dma_submit_pending(struct ti_csi2rx_ctx *ctx) +{ + struct ti_csi2rx_dma *dma = &ctx->dma; + struct ti_csi2rx_buffer *buf; + int ret = 0; + + /* If there are more buffers to process then start their transfer. */ + while (!list_empty(&dma->queue)) { + buf = list_entry(dma->queue.next, struct ti_csi2rx_buffer, list); + ret = ti_csi2rx_start_dma(ctx, buf); + if (ret) { + dev_err(ctx->csi->dev, + "Failed to queue the next buffer for DMA\n"); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + break; + } + list_move_tail(&buf->list, &dma->submitted); + } + return ret; +} + +static void ti_csi2rx_dma_callback(void *param) +{ + struct ti_csi2rx_buffer *buf = param; + struct ti_csi2rx_ctx *ctx = buf->ctx; + struct ti_csi2rx_dma *dma = &ctx->dma; + unsigned long flags; + + /* + * TODO: Derive the sequence number from the CSI2RX frame number + * hardware monitor registers. + */ + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.sequence = ctx->sequence++; + + spin_lock_irqsave(&dma->lock, flags); + + WARN_ON(!list_is_first(&buf->list, &dma->submitted)); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + list_del(&buf->list); + + ti_csi2rx_dma_submit_pending(ctx); + + if (list_empty(&dma->submitted)) + dma->state = TI_CSI2RX_DMA_IDLE; + + spin_unlock_irqrestore(&dma->lock, flags); +} + +static int ti_csi2rx_start_dma(struct ti_csi2rx_ctx *ctx, + struct ti_csi2rx_buffer *buf) +{ + unsigned long addr; + struct dma_async_tx_descriptor *desc; + size_t len = ctx->v_fmt.fmt.pix.sizeimage; + dma_cookie_t cookie; + int ret = 0; + + addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + desc = dmaengine_prep_slave_single(ctx->dma.chan, addr, len, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + return -EIO; + + desc->callback = ti_csi2rx_dma_callback; + desc->callback_param = buf; + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) + return ret; + + dma_async_issue_pending(ctx->dma.chan); + + return 0; +} + +static void ti_csi2rx_stop_dma(struct ti_csi2rx_ctx *ctx) +{ + struct ti_csi2rx_dma *dma = &ctx->dma; + enum ti_csi2rx_dma_state state; + unsigned long flags; + int ret; + + spin_lock_irqsave(&dma->lock, flags); + state = ctx->dma.state; + dma->state = TI_CSI2RX_DMA_STOPPED; + spin_unlock_irqrestore(&dma->lock, flags); + + if (state != TI_CSI2RX_DMA_STOPPED) { + /* + * Normal DMA termination does not clean up pending data on + * the endpoint if multiple streams are running and only one + * is stopped, as the module-level pixel reset cannot be + * enforced before terminating DMA. + */ + ret = ti_csi2rx_drain_dma(ctx); + if (ret && ret != -ETIMEDOUT) + dev_warn(ctx->csi->dev, + "Failed to drain DMA. Next frame might be bogus\n"); + } + + ret = dmaengine_terminate_sync(ctx->dma.chan); + if (ret) + dev_err(ctx->csi->dev, "Failed to stop DMA: %d\n", ret); +} + +static void ti_csi2rx_cleanup_buffers(struct ti_csi2rx_ctx *ctx, + enum vb2_buffer_state state) +{ + struct ti_csi2rx_dma *dma = &ctx->dma; + struct ti_csi2rx_buffer *buf, *tmp; + unsigned long flags; + + spin_lock_irqsave(&dma->lock, flags); + list_for_each_entry_safe(buf, tmp, &ctx->dma.queue, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + list_for_each_entry_safe(buf, tmp, &ctx->dma.submitted, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + spin_unlock_irqrestore(&dma->lock, flags); +} + +static int ti_csi2rx_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(q); + unsigned int size = ctx->v_fmt.fmt.pix.sizeimage; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + size = sizes[0]; + } + + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int ti_csi2rx_buffer_prepare(struct vb2_buffer *vb) +{ + struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size = ctx->v_fmt.fmt.pix.sizeimage; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(ctx->csi->dev, "Data will not fit into plane\n"); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + return 0; +} + +static void ti_csi2rx_buffer_queue(struct vb2_buffer *vb) +{ + struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct ti_csi2rx_buffer *buf; + struct ti_csi2rx_dma *dma = &ctx->dma; + bool restart_dma = false; + unsigned long flags = 0; + int ret; + + buf = container_of(vb, struct ti_csi2rx_buffer, vb.vb2_buf); + buf->ctx = ctx; + + spin_lock_irqsave(&dma->lock, flags); + /* + * Usually the DMA callback takes care of queueing the pending buffers. + * But if DMA has stalled due to lack of buffers, restart it now. + */ + if (dma->state == TI_CSI2RX_DMA_IDLE) { + /* + * Do not restart DMA with the lock held because + * ti_csi2rx_drain_dma() might block for completion. + * There won't be a race on queueing DMA anyway since the + * callback is not being fired. + */ + restart_dma = true; + dma->state = TI_CSI2RX_DMA_ACTIVE; + } else { + list_add_tail(&buf->list, &dma->queue); + } + spin_unlock_irqrestore(&dma->lock, flags); + + if (restart_dma) { + /* + * Once frames start dropping, some data gets stuck in the DMA + * pipeline somewhere. So the first DMA transfer after frame + * drops gives a partial frame. This is obviously not useful to + * the application and will only confuse it. Issue a DMA + * transaction to drain that up. + */ + ret = ti_csi2rx_drain_dma(ctx); + if (ret && ret != -ETIMEDOUT) + dev_warn(ctx->csi->dev, + "Failed to drain DMA. Next frame might be bogus\n"); + + spin_lock_irqsave(&dma->lock, flags); + ret = ti_csi2rx_start_dma(ctx, buf); + if (ret) { + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dma->state = TI_CSI2RX_DMA_IDLE; + spin_unlock_irqrestore(&dma->lock, flags); + dev_err(ctx->csi->dev, "Failed to start DMA: %d\n", ret); + } else { + list_add_tail(&buf->list, &dma->submitted); + spin_unlock_irqrestore(&dma->lock, flags); + } + } +} + +static int ti_csi2rx_get_vc(struct ti_csi2rx_ctx *ctx) +{ + struct ti_csi2rx_dev *csi = ctx->csi; + struct v4l2_mbus_frame_desc fd; + struct media_pad *pad; + int ret, i; + + pad = media_entity_remote_pad_unique(&csi->subdev.entity, MEDIA_PAD_FL_SOURCE); + if (!pad) + return -ENODEV; + + ret = v4l2_subdev_call(csi->source, pad, get_frame_desc, pad->index, + &fd); + if (ret) + return ret; + + if (fd.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) + return -EINVAL; + + for (i = 0; i < fd.num_entries; i++) { + if (ctx->stream == fd.entry[i].stream) + return fd.entry[i].bus.csi2.vc; + } + + return -ENODEV; +} + +static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(vq); + struct ti_csi2rx_dev *csi = ctx->csi; + struct ti_csi2rx_dma *dma = &ctx->dma; + struct v4l2_subdev_krouting *routing; + struct v4l2_subdev_route *route = NULL; + struct media_pad *remote_pad; + unsigned long flags; + int ret = 0, i; + struct v4l2_subdev_state *state; + + ret = pm_runtime_resume_and_get(csi->dev); + if (ret) + return ret; + + spin_lock_irqsave(&dma->lock, flags); + if (list_empty(&dma->queue)) + ret = -EIO; + spin_unlock_irqrestore(&dma->lock, flags); + if (ret) + return ret; + + ret = video_device_pipeline_start(&ctx->vdev, &csi->pipe); + if (ret) + goto err; + + remote_pad = media_entity_remote_source_pad_unique(ctx->pad.entity); + if (!remote_pad) { + ret = -ENODEV; + goto err; + } + + state = v4l2_subdev_lock_and_get_active_state(&csi->subdev); + + routing = &state->routing; + + /* Find the stream to process. */ + for (i = 0; i < routing->num_routes; i++) { + struct v4l2_subdev_route *r = &routing->routes[i]; + + if (!(r->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE)) + continue; + + if (r->source_pad != remote_pad->index) + continue; + + route = r; + break; + } + + if (!route) { + ret = -ENODEV; + v4l2_subdev_unlock_state(state); + goto err; + } + + ctx->stream = route->sink_stream; + + v4l2_subdev_unlock_state(state); + + ret = ti_csi2rx_get_vc(ctx); + if (ret == -ENOIOCTLCMD) + ctx->vc = 0; + else if (ret < 0) + goto err; + else + ctx->vc = ret; + + ti_csi2rx_setup_shim(ctx); + + ctx->sequence = 0; + + spin_lock_irqsave(&dma->lock, flags); + + ret = ti_csi2rx_dma_submit_pending(ctx); + if (ret) { + spin_unlock_irqrestore(&dma->lock, flags); + goto err_dma; + } + + dma->state = TI_CSI2RX_DMA_ACTIVE; + spin_unlock_irqrestore(&dma->lock, flags); + + ret = v4l2_subdev_enable_streams(&csi->subdev, + TI_CSI2RX_PAD_FIRST_SOURCE + ctx->idx, + BIT(0)); + if (ret) + goto err_dma; + + return 0; + +err_dma: + ti_csi2rx_stop_dma(ctx); + video_device_pipeline_stop(&ctx->vdev); + writel(0, csi->shim + SHIM_CNTL); + writel(0, csi->shim + SHIM_DMACNTX(ctx->idx)); +err: + ti_csi2rx_cleanup_buffers(ctx, VB2_BUF_STATE_QUEUED); + pm_runtime_put(csi->dev); + + return ret; +} + +static void ti_csi2rx_stop_streaming(struct vb2_queue *vq) +{ + struct ti_csi2rx_ctx *ctx = vb2_get_drv_priv(vq); + struct ti_csi2rx_dev *csi = ctx->csi; + int ret; + + /* assert pixel reset to prevent stale data on stopping last stream */ + if (csi->enable_count == 1) + writel(0, csi->shim + SHIM_CNTL); + + video_device_pipeline_stop(&ctx->vdev); + writel(0, csi->shim + SHIM_DMACNTX(ctx->idx)); + + ret = v4l2_subdev_disable_streams(&csi->subdev, + TI_CSI2RX_PAD_FIRST_SOURCE + ctx->idx, + BIT(0)); + + if (ret) + dev_err(csi->dev, "Failed to stop subdev stream\n"); + + ti_csi2rx_stop_dma(ctx); + ti_csi2rx_cleanup_buffers(ctx, VB2_BUF_STATE_ERROR); + pm_runtime_put(csi->dev); +} + +static const struct vb2_ops csi_vb2_qops = { + .queue_setup = ti_csi2rx_queue_setup, + .buf_prepare = ti_csi2rx_buffer_prepare, + .buf_queue = ti_csi2rx_buffer_queue, + .start_streaming = ti_csi2rx_start_streaming, + .stop_streaming = ti_csi2rx_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static inline struct ti_csi2rx_dev *to_csi2rx_dev(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ti_csi2rx_dev, subdev); +} + +static int ti_csi2rx_sd_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt; + int ret = 0; + + /* No transcoding, don't allow setting source fmt */ + if (format->pad >= TI_CSI2RX_PAD_FIRST_SOURCE) + return v4l2_subdev_get_fmt(sd, state, format); + + if (!find_format_by_code(format->format.code)) + format->format.code = ti_csi2rx_formats[0].code; + + format->format.field = V4L2_FIELD_NONE; + + fmt = v4l2_subdev_state_get_stream_format(state, format->pad, format->stream); + if (!fmt) { + ret = -EINVAL; + goto out; + } + *fmt = format->format; + + fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad, + format->stream); + if (!fmt) { + ret = -EINVAL; + goto out; + } + *fmt = format->format; + +out: + return ret; +} + +static int _ti_csi2rx_sd_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_krouting *routing) +{ + int ret; + + const struct v4l2_mbus_framefmt format = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, + }; + + ret = v4l2_subdev_routing_validate(sd, routing, + V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 | + V4L2_SUBDEV_ROUTING_NO_SOURCE_MULTIPLEXING); + + if (ret) + return ret; + + ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format); + + return ret; +} + +static int ti_csi2rx_sd_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + return _ti_csi2rx_sd_set_routing(sd, state, routing); +} + +static int ti_csi2rx_sd_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route routes[] = { { + .sink_pad = 0, + .sink_stream = 0, + .source_pad = TI_CSI2RX_PAD_FIRST_SOURCE, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + } }; + + struct v4l2_subdev_krouting routing = { + .num_routes = 1, + .routes = routes, + }; + + /* Initialize routing to single route to the fist source pad */ + return _ti_csi2rx_sd_set_routing(sd, state, &routing); +} + +static int ti_csi2rx_sd_all_sink_streams(struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_krouting *routing = &state->routing; + u64 sink_streams = 0; + int i; + + for (i = 0; i < routing->num_routes; i++) { + struct v4l2_subdev_route *r = &routing->routes[i]; + + if (r->sink_pad == TI_CSI2RX_PAD_SINK) + sink_streams |= BIT(r->sink_stream); + } + + return sink_streams; +} + +static int ti_csi2rx_sd_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct ti_csi2rx_dev *csi = to_csi2rx_dev(sd); + struct media_pad *remote_pad; + int ret = 0; + + remote_pad = media_entity_remote_source_pad_unique(&csi->subdev.entity); + if (!remote_pad) + return -ENODEV; + + mutex_lock(&csi->mutex); + if (!csi->enable_count) { + u64 sink_streams; + + sink_streams = ti_csi2rx_sd_all_sink_streams(state); + dev_dbg(csi->dev, "Enabling all streams (%llx) on sink.\n", + sink_streams); + ret = v4l2_subdev_enable_streams(csi->source, remote_pad->index, + sink_streams); + if (ret) + goto out; + csi->enabled_streams_mask = sink_streams; + } + + csi->enable_count++; +out: + mutex_unlock(&csi->mutex); + return ret; +} + +static int ti_csi2rx_sd_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct ti_csi2rx_dev *csi = to_csi2rx_dev(sd); + struct media_pad *remote_pad; + int ret = 0; + + remote_pad = media_entity_remote_source_pad_unique(&csi->subdev.entity); + if (!remote_pad) + return -ENODEV; + + mutex_lock(&csi->mutex); + if (csi->enable_count == 0) { + ret = -EINVAL; + goto out; + } + + if (csi->enable_count == 1) { + u64 sink_streams; + + sink_streams = ti_csi2rx_sd_all_sink_streams(state); + dev_dbg(csi->dev, "Disabling all streams (%llx) on sink.\n", + sink_streams); + ret = v4l2_subdev_disable_streams(csi->source, remote_pad->index, + sink_streams); + if (ret) + goto out; + csi->enabled_streams_mask = 0; + } + + --csi->enable_count; +out: + mutex_unlock(&csi->mutex); + return ret; +} + +static const struct v4l2_subdev_pad_ops ti_csi2rx_subdev_pad_ops = { + .init_cfg = ti_csi2rx_sd_init_cfg, + .set_routing = ti_csi2rx_sd_set_routing, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ti_csi2rx_sd_set_fmt, + .enable_streams = ti_csi2rx_sd_enable_streams, + .disable_streams = ti_csi2rx_sd_disable_streams, +}; + +static const struct v4l2_subdev_ops ti_csi2rx_subdev_ops = { + .pad = &ti_csi2rx_subdev_pad_ops, +}; + +static void ti_csi2rx_cleanup_dma(struct ti_csi2rx_ctx *ctx) +{ + dma_release_channel(ctx->dma.chan); +} + +static void ti_csi2rx_cleanup_v4l2(struct ti_csi2rx_dev *csi) +{ + v4l2_subdev_cleanup(&csi->subdev); + media_device_unregister(&csi->mdev); + v4l2_device_unregister(&csi->v4l2_dev); + media_device_cleanup(&csi->mdev); +} + +static void ti_csi2rx_cleanup_notifier(struct ti_csi2rx_dev *csi) +{ + v4l2_async_nf_unregister(&csi->notifier); + v4l2_async_nf_cleanup(&csi->notifier); +} + +static void ti_csi2rx_cleanup_vb2q(struct ti_csi2rx_ctx *ctx) +{ + vb2_queue_release(&ctx->vidq); +} + +static void ti_csi2rx_cleanup_ctx(struct ti_csi2rx_ctx *ctx) +{ + if (!pm_runtime_status_suspended(ctx->csi->dev)) + ti_csi2rx_cleanup_dma(ctx); + + ti_csi2rx_cleanup_vb2q(ctx); + + video_unregister_device(&ctx->vdev); + + mutex_destroy(&ctx->mutex); +} + +static int ti_csi2rx_init_vb2q(struct ti_csi2rx_ctx *ctx) +{ + struct vb2_queue *q = &ctx->vidq; + int ret; + + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = ctx; + q->buf_struct_size = sizeof(struct ti_csi2rx_buffer); + q->ops = &csi_vb2_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->dev = dmaengine_get_dma_device(ctx->dma.chan); + q->lock = &ctx->mutex; + q->min_buffers_needed = 1; + + ret = vb2_queue_init(q); + if (ret) + return ret; + + ctx->vdev.queue = q; + + return 0; +} + +static int ti_csi2rx_link_validate(struct media_link *link) +{ + struct media_entity *entity = link->sink->entity; + struct video_device *vdev = media_entity_to_video_device(entity); + struct ti_csi2rx_ctx *ctx = container_of(vdev, struct ti_csi2rx_ctx, vdev); + struct ti_csi2rx_dev *csi = ctx->csi; + struct v4l2_pix_format *csi_fmt = &ctx->v_fmt.fmt.pix; + struct v4l2_subdev_format source_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .pad = link->source->index, + .stream = 0, + }; + struct v4l2_subdev_state *state; + const struct ti_csi2rx_fmt *ti_fmt; + int ret; + + state = v4l2_subdev_lock_and_get_active_state(&csi->subdev); + ret = v4l2_subdev_call(&csi->subdev, pad, get_fmt, state, &source_fmt); + v4l2_subdev_unlock_state(state); + + if (ret) { + dev_dbg(csi->dev, + "Skipping validation as no format present on \"%s\":%u:0\n", + link->source->entity->name, link->source->index); + return 0; + } + + if (source_fmt.format.width != csi_fmt->width) { + dev_err(csi->dev, "Width does not match (source %u, sink %u)\n", + source_fmt.format.width, csi_fmt->width); + return -EPIPE; + } + + if (source_fmt.format.height != csi_fmt->height) { + dev_err(csi->dev, "Height does not match (source %u, sink %u)\n", + source_fmt.format.height, csi_fmt->height); + return -EPIPE; + } + + if (source_fmt.format.field != csi_fmt->field && + csi_fmt->field != V4L2_FIELD_NONE) { + dev_err(csi->dev, "Field does not match (source %u, sink %u)\n", + source_fmt.format.field, csi_fmt->field); + return -EPIPE; + } + + ti_fmt = find_format_by_code(source_fmt.format.code); + if (!ti_fmt) { + dev_err(csi->dev, "Media bus format 0x%x not supported\n", + source_fmt.format.code); + return -EPIPE; + } + + if (ti_fmt->fourcc != csi_fmt->pixelformat) { + dev_err(csi->dev, + "Cannot transform \"%s\":%u format %p4cc to %p4cc\n", + link->source->entity->name, link->source->index, + &ti_fmt->fourcc, &csi_fmt->pixelformat); + return -EPIPE; + } + + return 0; +} + +static const struct media_entity_operations ti_csi2rx_video_entity_ops = { + .link_validate = ti_csi2rx_link_validate, +}; + +static const struct media_entity_operations ti_csi2rx_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int ti_csi2rx_init_dma(struct ti_csi2rx_ctx *ctx) +{ + struct dma_slave_config cfg = { + .src_addr_width = DMA_SLAVE_BUSWIDTH_16_BYTES, + }; + char name[32]; + int ret; + + snprintf(name, sizeof(name), "rx%u", ctx->idx); + ctx->dma.chan = dma_request_chan(ctx->csi->dev, name); + if (IS_ERR(ctx->dma.chan)) + return PTR_ERR(ctx->dma.chan); + + ret = dmaengine_slave_config(ctx->dma.chan, &cfg); + if (ret) { + dma_release_channel(ctx->dma.chan); + return ret; + } + + return 0; +} + +static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) +{ + struct media_device *mdev = &csi->mdev; + struct v4l2_subdev *sd = &csi->subdev; + int ret, i; + + mdev->dev = csi->dev; + mdev->hw_revision = 1; + strscpy(mdev->model, "TI-CSI2RX", sizeof(mdev->model)); + + media_device_init(mdev); + + csi->v4l2_dev.mdev = mdev; + + ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); + if (ret) + goto cleanup_media; + + ret = media_device_register(mdev); + if (ret) + goto unregister_v4l2; + + v4l2_subdev_init(sd, &ti_csi2rx_subdev_ops); + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS; + strscpy(sd->name, dev_name(csi->dev), sizeof(sd->name)); + sd->dev = csi->dev; + sd->entity.ops = &ti_csi2rx_subdev_entity_ops; + + csi->pads[TI_CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + + for (i = TI_CSI2RX_PAD_FIRST_SOURCE; + i < TI_CSI2RX_PAD_FIRST_SOURCE + csi->num_ctx; i++) + csi->pads[i].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&sd->entity, + TI_CSI2RX_PAD_FIRST_SOURCE + csi->num_ctx, + csi->pads); + if (ret) + goto unregister_media; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto unregister_media; + + ret = v4l2_device_register_subdev(&csi->v4l2_dev, sd); + if (ret) + goto cleanup_subdev; + + return 0; + +cleanup_subdev: + v4l2_subdev_cleanup(sd); +unregister_media: + media_device_unregister(mdev); +unregister_v4l2: + v4l2_device_unregister(&csi->v4l2_dev); +cleanup_media: + media_device_cleanup(mdev); + + return ret; +} + +static int ti_csi2rx_init_ctx(struct ti_csi2rx_ctx *ctx) +{ + struct ti_csi2rx_dev *csi = ctx->csi; + struct video_device *vdev = &ctx->vdev; + const struct ti_csi2rx_fmt *fmt; + struct v4l2_pix_format *pix_fmt = &ctx->v_fmt.fmt.pix; + int ret; + + mutex_init(&ctx->mutex); + + fmt = find_format_by_fourcc(V4L2_PIX_FMT_UYVY); + if (!fmt) + return -EINVAL; + + pix_fmt->width = 640; + pix_fmt->height = 480; + pix_fmt->field = V4L2_FIELD_NONE; + pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; + pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601, + pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE, + pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB, + + ti_csi2rx_fill_fmt(fmt, &ctx->v_fmt); + + ctx->pad.flags = MEDIA_PAD_FL_SINK; + vdev->entity.ops = &ti_csi2rx_video_entity_ops; + ret = media_entity_pads_init(&ctx->vdev.entity, 1, &ctx->pad); + if (ret) + return ret; + + snprintf(vdev->name, sizeof(vdev->name), "%s context %u", + dev_name(csi->dev), ctx->idx); + vdev->v4l2_dev = &csi->v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + vdev->fops = &csi_fops; + vdev->ioctl_ops = &csi_ioctl_ops; + vdev->release = video_device_release_empty; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_IO_MC; + vdev->lock = &ctx->mutex; + video_set_drvdata(vdev, ctx); + + INIT_LIST_HEAD(&ctx->dma.queue); + INIT_LIST_HEAD(&ctx->dma.submitted); + spin_lock_init(&ctx->dma.lock); + ctx->dma.state = TI_CSI2RX_DMA_STOPPED; + + ret = ti_csi2rx_init_dma(ctx); + if (ret) + return ret; + + ret = ti_csi2rx_init_vb2q(ctx); + if (ret) + goto cleanup_dma; + + return 0; + +cleanup_dma: + ti_csi2rx_cleanup_dma(ctx); + return ret; +} + +#ifdef CONFIG_PM +static int ti_csi2rx_suspend(struct device *dev) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(dev); + enum ti_csi2rx_dma_state state; + struct ti_csi2rx_ctx *ctx; + struct ti_csi2rx_dma *dma; + unsigned long flags = 0; + int i, ret = 0; + + /* If device was not in use we can simply suspend */ + if (pm_runtime_status_suspended(dev)) + return 0; + + /* + * If device is running, assert the pixel reset to cleanly stop any + * on-going streams before we suspend. + */ + writel(0, csi->shim + SHIM_CNTL); + + for (i = 0; i < csi->num_ctx; i++) { + ctx = &csi->ctx[i]; + dma = &ctx->dma; + + spin_lock_irqsave(&dma->lock, flags); + state = dma->state; + spin_unlock_irqrestore(&dma->lock, flags); + + if (state != TI_CSI2RX_DMA_STOPPED) { + /* Disable source */ + ret = v4l2_subdev_disable_streams(&csi->subdev, + TI_CSI2RX_PAD_FIRST_SOURCE + ctx->idx, + BIT(0)); + if (ret) + dev_err(csi->dev, "Failed to stop subdev stream\n"); + } + + /* Stop any on-going streams */ + writel(0, csi->shim + SHIM_DMACNTX(ctx->idx)); + + /* Drain DMA */ + ti_csi2rx_drain_dma(ctx); + + /* Terminate DMA */ + ret = dmaengine_terminate_sync(ctx->dma.chan); + if (ret) + dev_err(csi->dev, "Failed to stop DMA\n"); + } + + return ret; +} + +static int ti_csi2rx_resume(struct device *dev) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(dev); + struct ti_csi2rx_ctx *ctx; + struct ti_csi2rx_dma *dma; + struct ti_csi2rx_buffer *buf; + unsigned long flags = 0; + unsigned int reg; + int i, ret = 0; + + /* If device was not in use, we can simply wakeup */ + if (pm_runtime_status_suspended(dev)) + return 0; + + /* If device was in use before, restore all the running streams */ + reg = SHIM_CNTL_PIX_RST; + writel(reg, csi->shim + SHIM_CNTL); + + for (i = 0; i < csi->num_ctx; i++) { + ctx = &csi->ctx[i]; + dma = &ctx->dma; + spin_lock_irqsave(&dma->lock, flags); + if (dma->state != TI_CSI2RX_DMA_STOPPED) { + /* Re-submit all previously submitted buffers to DMA */ + list_for_each_entry(buf, &ctx->dma.submitted, list) { + ti_csi2rx_start_dma(ctx, buf); + } + spin_unlock_irqrestore(&dma->lock, flags); + + /* Restore stream config */ + ti_csi2rx_setup_shim(ctx); + + ret = v4l2_subdev_enable_streams(&csi->subdev, + TI_CSI2RX_PAD_FIRST_SOURCE + ctx->idx, + BIT(0)); + if (ret) + dev_err(ctx->csi->dev, "Failed to start subdev\n"); + } else { + spin_unlock_irqrestore(&dma->lock, flags); + } + } + + return ret; +} + +static int ti_csi2rx_runtime_suspend(struct device *dev) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(dev); + int i; + + if (csi->enable_count != 0) + return -EBUSY; + + for (i = 0; i < csi->num_ctx; i++) + ti_csi2rx_cleanup_dma(&csi->ctx[i]); + + return 0; +} + +static int ti_csi2rx_runtime_resume(struct device *dev) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(dev); + int ret, i; + + for (i = 0; i < csi->num_ctx; i++) { + ret = ti_csi2rx_init_dma(&csi->ctx[i]); + if (ret) + return ret; + } + + return 0; +} + +static const struct dev_pm_ops ti_csi2rx_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ti_csi2rx_suspend, ti_csi2rx_resume) + SET_RUNTIME_PM_OPS(ti_csi2rx_runtime_suspend, ti_csi2rx_runtime_resume, + NULL) +}; +#endif /* CONFIG_PM */ + +static int ti_csi2rx_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct ti_csi2rx_dev *csi; + int ret, i, count; + + csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); + if (!csi) + return -ENOMEM; + + csi->dev = &pdev->dev; + platform_set_drvdata(pdev, csi); + + csi->shim = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(csi->shim)) { + ret = PTR_ERR(csi->shim); + return ret; + } + + csi->drain.len = DRAIN_BUFFER_SIZE; + csi->drain.vaddr = dma_alloc_coherent(csi->dev, csi->drain.len, + &csi->drain.paddr, + GFP_KERNEL); + if (!csi->drain.vaddr) + return -ENOMEM; + + /* Only use as many contexts as the number of DMA channels allocated. */ + count = of_property_count_strings(np, "dma-names"); + if (count < 0) { + dev_err(csi->dev, "Failed to get DMA channel count: %d\n", + count); + return count; + } + + csi->num_ctx = count; + if (csi->num_ctx > TI_CSI2RX_MAX_CTX) { + dev_warn(csi->dev, + "%u DMA channels passed. Maximum is %u. Ignoring the rest.\n", + csi->num_ctx, TI_CSI2RX_MAX_CTX); + csi->num_ctx = TI_CSI2RX_MAX_CTX; + } + + mutex_init(&csi->mutex); + + ret = ti_csi2rx_v4l2_init(csi); + if (ret) + goto err_v4l2; + + for (i = 0; i < csi->num_ctx; i++) { + csi->ctx[i].idx = i; + csi->ctx[i].csi = csi; + ret = ti_csi2rx_init_ctx(&csi->ctx[i]); + if (ret) + goto err_ctx; + } + + ret = ti_csi2rx_notifier_register(csi); + if (ret) + goto err_ctx; + + ret = of_platform_populate(csi->dev->of_node, NULL, NULL, csi->dev); + if (ret) { + dev_err(csi->dev, "Failed to create children: %d\n", ret); + goto err_notifier; + } + + pm_runtime_set_active(csi->dev); + pm_runtime_enable(csi->dev); + pm_request_idle(csi->dev); + + return 0; + +err_notifier: + ti_csi2rx_cleanup_notifier(csi); +err_ctx: + i--; + for (; i >= 0; i--) + ti_csi2rx_cleanup_ctx(&csi->ctx[i]); + ti_csi2rx_cleanup_v4l2(csi); +err_v4l2: + mutex_destroy(&csi->mutex); + dma_free_coherent(csi->dev, csi->drain.len, csi->drain.vaddr, + csi->drain.paddr); + return ret; +} + +static int ti_csi2rx_remove(struct platform_device *pdev) +{ + struct ti_csi2rx_dev *csi = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < csi->num_ctx; i++) { + if (vb2_is_busy(&csi->ctx[i].vidq)) + dev_err(csi->dev, + "Failed to remove as queue busy for ctx %u\n", + i); + } + + for (i = 0; i < csi->num_ctx; i++) + ti_csi2rx_cleanup_ctx(&csi->ctx[i]); + + ti_csi2rx_cleanup_notifier(csi); + ti_csi2rx_cleanup_v4l2(csi); + mutex_destroy(&csi->mutex); + dma_free_coherent(csi->dev, csi->drain.len, csi->drain.vaddr, + csi->drain.paddr); + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + + return 0; +} + +static const struct of_device_id ti_csi2rx_of_match[] = { + { .compatible = "ti,j721e-csi2rx-shim", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ti_csi2rx_of_match); + +static struct platform_driver ti_csi2rx_pdrv = { + .probe = ti_csi2rx_probe, + .remove = ti_csi2rx_remove, + .driver = { + .name = TI_CSI2RX_MODULE_NAME, + .of_match_table = ti_csi2rx_of_match, +#ifdef CONFIG_PM + .pm = &ti_csi2rx_pm_ops, +#endif + }, +}; + +module_platform_driver(ti_csi2rx_pdrv); + +MODULE_DESCRIPTION("TI J721E CSI2 RX Driver"); +MODULE_AUTHOR("Jai Luthra "); +MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/drivers/media/platform/ti/j721e-csi2rx/Makefile b/drivers/media/platform/ti/j721e-csi2rx/Makefile --- a/drivers/media/platform/ti/j721e-csi2rx/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/media/platform/ti/j721e-csi2rx/Makefile 2024-07-07 20:37:34.664306649 -0400 @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_VIDEO_TI_J721E_CSI2RX) += j721e-csi2rx.o diff -Naur --no-dereference a/drivers/media/platform/ti/Kconfig b/drivers/media/platform/ti/Kconfig --- a/drivers/media/platform/ti/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/ti/Kconfig 2024-07-07 20:37:34.664306649 -0400 @@ -63,6 +63,18 @@ help Enable debug messages on VPE driver. +config VIDEO_TI_J721E_CSI2RX + tristate "TI J721E CSI2RX wrapper layer driver" + depends on VIDEO_DEV && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_SUPPORT && MEDIA_CONTROLLER + depends on (PHY_CADENCE_DPHY_RX && VIDEO_CADENCE_CSI2RX) || COMPILE_TEST + depends on ARCH_K3 || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + help + Support for TI CSI2RX wrapper layer. This just enables the wrapper driver. + The Cadence CSI2RX bridge driver needs to be enabled separately. + source "drivers/media/platform/ti/am437x/Kconfig" source "drivers/media/platform/ti/davinci/Kconfig" source "drivers/media/platform/ti/omap/Kconfig" diff -Naur --no-dereference a/drivers/media/platform/ti/Makefile b/drivers/media/platform/ti/Makefile --- a/drivers/media/platform/ti/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/ti/Makefile 2024-07-07 20:37:34.664306649 -0400 @@ -3,5 +3,6 @@ obj-y += cal/ obj-y += vpe/ obj-y += davinci/ +obj-y += j721e-csi2rx/ obj-y += omap/ obj-y += omap3isp/ diff -Naur --no-dereference a/drivers/media/platform/verisilicon/hantro_jpeg.c b/drivers/media/platform/verisilicon/hantro_jpeg.c --- a/drivers/media/platform/verisilicon/hantro_jpeg.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/verisilicon/hantro_jpeg.c 2024-07-07 20:37:34.664306649 -0400 @@ -11,6 +11,7 @@ #include #include #include +#include #include "hantro_jpeg.h" #include "hantro.h" @@ -24,42 +25,6 @@ #define HUFF_CHROMA_DC_OFF 394 #define HUFF_CHROMA_AC_OFF 427 -/* Default tables from JPEG ITU-T.81 - * (ISO/IEC 10918-1) Annex K, tables K.1 and K.2 - */ -static const unsigned char luma_q_table[] = { - 0x10, 0x0b, 0x0a, 0x10, 0x18, 0x28, 0x33, 0x3d, - 0x0c, 0x0c, 0x0e, 0x13, 0x1a, 0x3a, 0x3c, 0x37, - 0x0e, 0x0d, 0x10, 0x18, 0x28, 0x39, 0x45, 0x38, - 0x0e, 0x11, 0x16, 0x1d, 0x33, 0x57, 0x50, 0x3e, - 0x12, 0x16, 0x25, 0x38, 0x44, 0x6d, 0x67, 0x4d, - 0x18, 0x23, 0x37, 0x40, 0x51, 0x68, 0x71, 0x5c, - 0x31, 0x40, 0x4e, 0x57, 0x67, 0x79, 0x78, 0x65, - 0x48, 0x5c, 0x5f, 0x62, 0x70, 0x64, 0x67, 0x63 -}; - -static const unsigned char chroma_q_table[] = { - 0x11, 0x12, 0x18, 0x2f, 0x63, 0x63, 0x63, 0x63, - 0x12, 0x15, 0x1a, 0x42, 0x63, 0x63, 0x63, 0x63, - 0x18, 0x1a, 0x38, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x2f, 0x42, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 -}; - -static const unsigned char zigzag[] = { - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63 -}; - static const u32 hw_reorder[] = { 0, 8, 16, 24, 1, 9, 17, 25, 32, 40, 48, 56, 33, 41, 49, 57, @@ -71,73 +36,6 @@ 38, 46, 54, 62, 39, 47, 55, 63 }; -/* Huffman tables are shared with CODA */ -static const unsigned char luma_dc_table[] = { - 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, -}; - -static const unsigned char chroma_dc_table[] = { - 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, -}; - -static const unsigned char luma_ac_table[] = { - 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, - 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, - 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, - 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, - 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, - 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, - 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, - 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, -}; - -static const unsigned char chroma_ac_table[] = { - 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, - 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, - 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, - 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, - 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, - 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, - 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, - 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, - 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, - 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, - 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, - 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, - 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, - 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, -}; - /* For simplicity, we keep a pre-formatted JPEG header, * and we'll use fixed offsets to change the width, height * quantization tables, etc. @@ -291,10 +189,11 @@ const unsigned char *tab, int scale) { int i; + const u8 *zigzag; - BUILD_BUG_ON(ARRAY_SIZE(zigzag) != JPEG_QUANT_SIZE); BUILD_BUG_ON(ARRAY_SIZE(hw_reorder) != JPEG_QUANT_SIZE); + v4l2_jpeg_get_zig_zag_scan(&zigzag); for (i = 0; i < JPEG_QUANT_SIZE; i++) { file_q_tab[i] = jpeg_scale_qp(tab[zigzag[i]], scale); reordered_q_tab[i] = jpeg_scale_qp(tab[hw_reorder[i]], scale); @@ -304,6 +203,7 @@ static void jpeg_set_quality(struct hantro_jpeg_ctx *ctx) { int scale; + const u8 *luma_q_table, *chroma_q_table; /* * Non-linear scaling factor: @@ -314,21 +214,23 @@ else scale = 200 - 2 * ctx->quality; - BUILD_BUG_ON(ARRAY_SIZE(luma_q_table) != JPEG_QUANT_SIZE); - BUILD_BUG_ON(ARRAY_SIZE(chroma_q_table) != JPEG_QUANT_SIZE); BUILD_BUG_ON(ARRAY_SIZE(ctx->hw_luma_qtable) != JPEG_QUANT_SIZE); BUILD_BUG_ON(ARRAY_SIZE(ctx->hw_chroma_qtable) != JPEG_QUANT_SIZE); + v4l2_jpeg_get_reference_quantization_tables(&luma_q_table, &chroma_q_table); jpeg_scale_quant_table(ctx->buffer + LUMA_QUANT_OFF, - ctx->hw_luma_qtable, luma_q_table, scale); + ctx->hw_luma_qtable, (const unsigned char *)luma_q_table, scale); jpeg_scale_quant_table(ctx->buffer + CHROMA_QUANT_OFF, - ctx->hw_chroma_qtable, chroma_q_table, scale); + ctx->hw_chroma_qtable, (const unsigned char *)chroma_q_table, scale); } void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx) { char *buf = ctx->buffer; + const u8 *luma_dc_table, *chroma_dc_table, *luma_ac_table, *chroma_ac_table; + v4l2_jpeg_get_reference_huffman_tables(&luma_dc_table, &luma_ac_table, &chroma_dc_table, + &chroma_ac_table); memcpy(buf, hantro_jpeg_header, sizeof(hantro_jpeg_header)); @@ -337,12 +239,10 @@ buf[WIDTH_OFF + 0] = ctx->width >> 8; buf[WIDTH_OFF + 1] = ctx->width; - memcpy(buf + HUFF_LUMA_DC_OFF, luma_dc_table, sizeof(luma_dc_table)); - memcpy(buf + HUFF_LUMA_AC_OFF, luma_ac_table, sizeof(luma_ac_table)); - memcpy(buf + HUFF_CHROMA_DC_OFF, chroma_dc_table, - sizeof(chroma_dc_table)); - memcpy(buf + HUFF_CHROMA_AC_OFF, chroma_ac_table, - sizeof(chroma_ac_table)); + memcpy(buf + HUFF_LUMA_DC_OFF, luma_dc_table, V4L2_JPEG_REF_HT_DC_LEN); + memcpy(buf + HUFF_LUMA_AC_OFF, luma_ac_table, V4L2_JPEG_REF_HT_AC_LEN); + memcpy(buf + HUFF_CHROMA_DC_OFF, chroma_dc_table, V4L2_JPEG_REF_HT_DC_LEN); + memcpy(buf + HUFF_CHROMA_AC_OFF, chroma_ac_table, V4L2_JPEG_REF_HT_AC_LEN); jpeg_set_quality(ctx); } diff -Naur --no-dereference a/drivers/media/platform/verisilicon/Kconfig b/drivers/media/platform/verisilicon/Kconfig --- a/drivers/media/platform/verisilicon/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/platform/verisilicon/Kconfig 2024-07-07 20:37:34.664306649 -0400 @@ -13,6 +13,7 @@ select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV select V4L2_H264 + select V4L2_JPEG_HELPER select V4L2_VP9 help Support for the Hantro IP based Video Processing Units present on diff -Naur --no-dereference a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c 2024-07-07 20:37:34.664306649 -0400 @@ -831,6 +831,7 @@ case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component"; case V4L2_CID_COLORFX_CBCR: return "Color Effects, CbCr"; case V4L2_CID_COLORFX_RGB: return "Color Effects, RGB"; + case V4L2_CID_IR_EXPOSURE: return "Exposure, IR"; /* * Codec controls @@ -1154,6 +1155,7 @@ case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value"; case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value"; case V4L2_CID_NOTIFY_GAINS: return "Notify Gains"; + case V4L2_CID_IR_ANALOGUE_GAIN: return "Analogue Gain, IR"; /* Image processing controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ @@ -1163,6 +1165,7 @@ case V4L2_CID_TEST_PATTERN: return "Test Pattern"; case V4L2_CID_DEINTERLACING_MODE: return "Deinterlacing Mode"; case V4L2_CID_DIGITAL_GAIN: return "Digital Gain"; + case V4L2_CID_IR_DIGITAL_GAIN: return "Digital Gain, IR"; /* DV controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ diff -Naur --no-dereference a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c --- a/drivers/media/v4l2-core/v4l2-ioctl.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/v4l2-core/v4l2-ioctl.c 2024-07-07 20:37:34.664306649 -0400 @@ -1415,6 +1415,14 @@ case V4L2_PIX_FMT_SGBRG16: descr = "16-bit Bayer GBGB/RGRG"; break; case V4L2_PIX_FMT_SGRBG16: descr = "16-bit Bayer GRGR/BGBG"; break; case V4L2_PIX_FMT_SRGGB16: descr = "16-bit Bayer RGRG/GBGB"; break; + case V4L2_PIX_FMT_SRGGI10: descr = "10-bit Bayer RGBG/GIrGIr"; break; + case V4L2_PIX_FMT_SGRIG10: descr = "10-bit Bayer GRGB/IrGIrG"; break; + case V4L2_PIX_FMT_SBGGI10: descr = "10-bit Bayer BGRG/GIrGIr"; break; + case V4L2_PIX_FMT_SGBIG10: descr = "10-bit Bayer GBGR/IrGIrG"; break; + case V4L2_PIX_FMT_SGIRG10: descr = "10-bit Bayer GIrGIr/RGBG"; break; + case V4L2_PIX_FMT_SIGGR10: descr = "10-bit Bayer IrGIrG/GRGB"; break; + case V4L2_PIX_FMT_SGIBG10: descr = "10-bit Bayer GIrGIr/BGRG"; break; + case V4L2_PIX_FMT_SIGGB10: descr = "10-bit Bayer IrGIrG/GBGR"; break; case V4L2_PIX_FMT_SN9C20X_I420: descr = "GSPCA SN9C20X I420"; break; case V4L2_PIX_FMT_SPCA501: descr = "GSPCA SPCA501"; break; case V4L2_PIX_FMT_SPCA505: descr = "GSPCA SPCA505"; break; @@ -1452,6 +1460,8 @@ case V4L2_PIX_FMT_Y210: descr = "10-bit YUYV Packed"; break; case V4L2_PIX_FMT_Y212: descr = "12-bit YUYV Packed"; break; case V4L2_PIX_FMT_Y216: descr = "16-bit YUYV Packed"; break; + case V4L2_PIX_FMT_TI1210: descr = "10-bit YUV 4:2:0 (NV12)"; break; + case V4L2_PIX_FMT_TI1610: descr = "10-bit YUV 4:2:2 (NV16)"; break; default: /* Compressed formats */ diff -Naur --no-dereference a/drivers/media/v4l2-core/v4l2-jpeg.c b/drivers/media/v4l2-core/v4l2-jpeg.c --- a/drivers/media/v4l2-core/v4l2-jpeg.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/v4l2-core/v4l2-jpeg.c 2024-07-07 20:37:34.664306649 -0400 @@ -16,7 +16,7 @@ #include #include -MODULE_DESCRIPTION("V4L2 JPEG header parser helpers"); +MODULE_DESCRIPTION("V4L2 JPEG helpers"); MODULE_AUTHOR("Philipp Zabel "); MODULE_LICENSE("GPL"); @@ -52,6 +52,115 @@ #define COM 0xfffe /* comment */ #define TEM 0xff01 /* temporary */ +/* Luma and chroma qp tables to achieve 50% compression quality + * This is as per example in Annex K.1 of ITU-T.81 + */ +static const u8 luma_qt[] = { + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 +}; + +static const u8 chroma_qt[] = { + 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; + +/* Zigzag scan pattern */ +static const u8 zigzag[] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +/* + * Contains the data that needs to be sent in the marker segment of an + * interchange format JPEG stream or an abbreviated format table specification + * data stream. Specifies the huffman table used for encoding the luminance DC + * coefficient differences. The table represents Table K.3 of ITU-T.81 + */ +static const u8 luma_dc_ht[] = { + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B +}; + +/* + * Contains the data that needs to be sent in the marker segment of an + * interchange format JPEG stream or an abbreviated format table specification + * data stream. Specifies the huffman table used for encoding the luminance AC + * coefficients. The table represents Table K.5 of ITU-T.81 + */ +static const u8 luma_ac_ht[] = { + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, + 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, + 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, + 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, + 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, + 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, + 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA +}; + +/* + * Contains the data that needs to be sent in the marker segment of an interchange format JPEG + * stream or an abbreviated format table specification data stream. + * Specifies the huffman table used for encoding the chrominance DC coefficient differences. + * The table represents Table K.4 of ITU-T.81 + */ +static const u8 chroma_dc_ht[] = { + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B +}; + +/* + * Contains the data that needs to be sent in the marker segment of an + * interchange format JPEG stream or an abbreviated format table specification + * data stream. Specifies the huffman table used for encoding the chrominance + * AC coefficients. The table represents Table K.6 of ITU-T.81 + */ +static const u8 chroma_ac_ht[] = { + 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, + 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, + 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, + 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, + 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, + 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, + 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, + 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA +}; + /** * struct jpeg_stream - JPEG byte stream * @curr: current position in stream @@ -675,3 +784,54 @@ return jpeg_parse_huffman_tables(&stream, huffman_tables); } EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_huffman_tables); + +/** + * v4l2_jpeg_get_reference_quantization_tables - Get reference quantization + * tables as defined in ITU-T.81 + * @ref_luma_qt: Output variable pointing to luma quantization table + * @ref_chroma_qt: Output variable pointing to chroma quantization table + */ +void v4l2_jpeg_get_reference_quantization_tables(const u8 **ref_luma_qt, const + u8 **ref_chroma_qt) +{ + if (ref_luma_qt) + *ref_luma_qt = luma_qt; + if (ref_chroma_qt) + *ref_chroma_qt = chroma_qt; +} +EXPORT_SYMBOL_GPL(v4l2_jpeg_get_reference_quantization_tables); + +/** + * v4l2_jpeg_get_zig_zag_scan - Get zigzag scan table as defined in ITU-T.81 + * @ref_zigzag: Output variable pointing to zigzag scan table + */ +void v4l2_jpeg_get_zig_zag_scan(const u8 **ref_zigzag) +{ + if (ref_zigzag) + *ref_zigzag = zigzag; +} +EXPORT_SYMBOL_GPL(v4l2_jpeg_get_zig_zag_scan); + +/** + * v4l2_jpeg_get_reference_huffman_tables - Get reference huffman tables as + * defined in ITU-T.81 + * @ref_luma_dc_ht : Output variable pointing to huffman table for luma DC + * @ref_luma_ac_ht : Output variable pointing to huffman table for luma AC + * @ref_chroma_dc_ht : Output variable pointing to huffman table for chroma DC + * @ref_chroma_ac_ht : Output variable pointing to huffman table for chroma AC + */ +void v4l2_jpeg_get_reference_huffman_tables(const u8 **ref_luma_dc_ht, + const u8 **ref_luma_ac_ht, + const u8 **ref_chroma_dc_ht, + const u8 **ref_chroma_ac_ht) +{ + if (ref_luma_dc_ht) + *ref_luma_dc_ht = luma_dc_ht; + if (ref_luma_ac_ht) + *ref_luma_ac_ht = luma_ac_ht; + if (ref_chroma_dc_ht) + *ref_chroma_dc_ht = chroma_dc_ht; + if (ref_chroma_ac_ht) + *ref_chroma_ac_ht = chroma_ac_ht; +} +EXPORT_SYMBOL_GPL(v4l2_jpeg_get_reference_huffman_tables); diff -Naur --no-dereference a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c --- a/drivers/media/v4l2-core/v4l2-mem2mem.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c 2024-07-07 20:37:34.664306649 -0400 @@ -301,9 +301,12 @@ dprintk("Trying to schedule a job for m2m_ctx: %p\n", m2m_ctx); - if (!m2m_ctx->out_q_ctx.q.streaming - || !m2m_ctx->cap_q_ctx.q.streaming) { - dprintk("Streaming needs to be on for both queues\n"); + if (!m2m_ctx->out_q_ctx.q.streaming || + (!m2m_ctx->cap_q_ctx.q.streaming && !m2m_ctx->ignore_cap_streaming)) { + if (!m2m_ctx->ignore_cap_streaming) + dprintk("Streaming needs to be on for both queues\n"); + else + dprintk("Streaming needs to be on for the OUTPUT queue\n"); return; } diff -Naur --no-dereference a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c --- a/drivers/media/v4l2-core/v4l2-subdev.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/media/v4l2-core/v4l2-subdev.c 2024-07-07 20:37:34.664306649 -0400 @@ -31,7 +31,7 @@ * 'v4l2_subdev_enable_streams_api' to 1 below. */ -static bool v4l2_subdev_enable_streams_api; +static bool v4l2_subdev_enable_streams_api = 1; #endif /* diff -Naur --no-dereference a/drivers/misc/Kconfig b/drivers/misc/Kconfig --- a/drivers/misc/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/misc/Kconfig 2024-07-07 20:37:34.664306649 -0400 @@ -448,6 +448,13 @@ config SRAM_EXEC bool +config SRAM_DMA_HEAP + bool "Export on-chip SRAM pools using DMA-Heaps" + depends on DMABUF_HEAPS && SRAM + help + This driver allows the export of on-chip SRAM marked as both pool + and exportable to userspace using the DMA-Heaps interface. + config DW_XDATA_PCIE depends on PCI tristate "Synopsys DesignWare xData PCIe driver" diff -Naur --no-dereference a/drivers/misc/Makefile b/drivers/misc/Makefile --- a/drivers/misc/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/misc/Makefile 2024-07-07 20:37:34.664306649 -0400 @@ -47,6 +47,7 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o obj-$(CONFIG_SRAM_EXEC) += sram-exec.o +obj-$(CONFIG_SRAM_DMA_HEAP) += sram-dma-heap.o obj-$(CONFIG_GENWQE) += genwqe/ obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_CXL_BASE) += cxl/ diff -Naur --no-dereference a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c --- a/drivers/misc/pci_endpoint_test.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/misc/pci_endpoint_test.c 2024-07-07 20:37:34.664306649 -0400 @@ -263,6 +263,15 @@ return false; } +static const u32 bar_test_pattern[] = { + 0xA0A0A0A0, + 0xA1A1A1A1, + 0xA2A2A2A2, + 0xA3A3A3A3, + 0xA4A4A4A4, + 0xA5A5A5A5, +}; + static bool pci_endpoint_test_bar(struct pci_endpoint_test *test, enum pci_barno barno) { @@ -280,11 +289,12 @@ size = 0x4; for (j = 0; j < size; j += 4) - pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0); + pci_endpoint_test_bar_writel(test, barno, j, + bar_test_pattern[barno]); for (j = 0; j < size; j += 4) { val = pci_endpoint_test_bar_readl(test, barno, j); - if (val != 0xA0A0A0A0) + if (val != bar_test_pattern[barno]) return false; } diff -Naur --no-dereference a/drivers/misc/sram.c b/drivers/misc/sram.c --- a/drivers/misc/sram.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/misc/sram.c 2024-07-07 20:37:34.664306649 -0400 @@ -120,6 +120,12 @@ ret = sram_add_pool(sram, block, start, part); if (ret) return ret; + + if (block->export) { + ret = sram_add_dma_heap(sram, block, start, part); + if (ret) + return ret; + } } if (block->export) { ret = sram_add_export(sram, block, start, part); diff -Naur --no-dereference a/drivers/misc/sram-dma-heap.c b/drivers/misc/sram-dma-heap.c --- a/drivers/misc/sram-dma-heap.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/misc/sram-dma-heap.c 2024-07-07 20:37:34.664306649 -0400 @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SRAM DMA-Heap userspace exporter + * + * Copyright (C) 2019-2023 Texas Instruments Incorporated - https://www.ti.com/ + * Andrew Davis + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sram.h" + +struct sram_dma_heap { + struct dma_heap *heap; + struct gen_pool *pool; +}; + +struct sram_dma_heap_buffer { + struct gen_pool *pool; + struct list_head attachments; + struct mutex attachments_lock; + unsigned long len; + void *vaddr; + phys_addr_t paddr; +}; + +struct dma_heap_attachment { + struct device *dev; + struct sg_table *table; + struct list_head list; +}; + +static int dma_heap_attach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct sram_dma_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + struct sg_table *table; + + a = kzalloc(sizeof(*a), GFP_KERNEL); + if (!a) + return -ENOMEM; + + table = kmalloc(sizeof(*table), GFP_KERNEL); + if (!table) { + kfree(a); + return -ENOMEM; + } + if (sg_alloc_table(table, 1, GFP_KERNEL)) { + kfree(table); + kfree(a); + return -ENOMEM; + } + sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(buffer->paddr)), buffer->len, 0); + + a->table = table; + a->dev = attachment->dev; + INIT_LIST_HEAD(&a->list); + + attachment->priv = a; + + mutex_lock(&buffer->attachments_lock); + list_add(&a->list, &buffer->attachments); + mutex_unlock(&buffer->attachments_lock); + + return 0; +} + +static void dma_heap_detatch(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct sram_dma_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a = attachment->priv; + + mutex_lock(&buffer->attachments_lock); + list_del(&a->list); + mutex_unlock(&buffer->attachments_lock); + + sg_free_table(a->table); + kfree(a->table); + kfree(a); +} + +static struct sg_table *dma_heap_map_dma_buf(struct dma_buf_attachment *attachment, + enum dma_data_direction direction) +{ + struct dma_heap_attachment *a = attachment->priv; + struct sg_table *table = a->table; + + /* + * As this heap is backed by uncached SRAM memory we do not need to + * perform any sync operations on the buffer before allowing device + * domain access. For this reason we use SKIP_CPU_SYNC and also do + * not use or provide begin/end_cpu_access() dma-buf functions. + */ + if (!dma_map_sg_attrs(attachment->dev, table->sgl, table->nents, + direction, DMA_ATTR_SKIP_CPU_SYNC)) + return ERR_PTR(-ENOMEM); + + return table; +} + +static void dma_heap_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *table, + enum dma_data_direction direction) +{ + dma_unmap_sg_attrs(attachment->dev, table->sgl, table->nents, + direction, DMA_ATTR_SKIP_CPU_SYNC); +} + +static void dma_heap_dma_buf_release(struct dma_buf *dmabuf) +{ + struct sram_dma_heap_buffer *buffer = dmabuf->priv; + + gen_pool_free(buffer->pool, (unsigned long)buffer->vaddr, buffer->len); + kfree(buffer); +} + +static int dma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) +{ + struct sram_dma_heap_buffer *buffer = dmabuf->priv; + int ret; + + /* SRAM mappings are not cached */ + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + ret = vm_iomap_memory(vma, buffer->paddr, buffer->len); + if (ret) + pr_err("Could not map buffer to userspace\n"); + + return ret; +} + +static int dma_heap_vmap(struct dma_buf *dmabuf, struct iosys_map *map) +{ + struct sram_dma_heap_buffer *buffer = dmabuf->priv; + + iosys_map_set_vaddr(map, buffer->vaddr); + + return 0; +} + +static const struct dma_buf_ops sram_dma_heap_buf_ops = { + .attach = dma_heap_attach, + .detach = dma_heap_detatch, + .map_dma_buf = dma_heap_map_dma_buf, + .unmap_dma_buf = dma_heap_unmap_dma_buf, + .release = dma_heap_dma_buf_release, + .mmap = dma_heap_mmap, + .vmap = dma_heap_vmap, +}; + +static struct dma_buf *sram_dma_heap_allocate(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + struct sram_dma_heap *sram_dma_heap = dma_heap_get_drvdata(heap); + struct sram_dma_heap_buffer *buffer; + + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + struct dma_buf *dmabuf; + int ret = 0; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return ERR_PTR(-ENOMEM); + buffer->pool = sram_dma_heap->pool; + INIT_LIST_HEAD(&buffer->attachments); + mutex_init(&buffer->attachments_lock); + buffer->len = len; + + buffer->vaddr = (void *)gen_pool_alloc(buffer->pool, buffer->len); + if (!buffer->vaddr) { + ret = -ENOMEM; + goto free_buffer; + } + + buffer->paddr = gen_pool_virt_to_phys(buffer->pool, (unsigned long)buffer->vaddr); + if (buffer->paddr == -1) { + ret = -ENOMEM; + goto free_pool; + } + + /* create the dmabuf */ + exp_info.exp_name = dma_heap_get_name(heap); + exp_info.ops = &sram_dma_heap_buf_ops; + exp_info.size = buffer->len; + exp_info.flags = fd_flags; + exp_info.priv = buffer; + dmabuf = dma_buf_export(&exp_info); + if (IS_ERR(dmabuf)) { + ret = PTR_ERR(dmabuf); + goto free_pool; + } + + return dmabuf; + +free_pool: + gen_pool_free(buffer->pool, (unsigned long)buffer->vaddr, buffer->len); +free_buffer: + kfree(buffer); + + return ERR_PTR(ret); +} + +static struct dma_heap_ops sram_dma_heap_ops = { + .allocate = sram_dma_heap_allocate, +}; + +int sram_add_dma_heap(struct sram_dev *sram, + struct sram_reserve *block, + phys_addr_t start, + struct sram_partition *part) +{ + struct sram_dma_heap *sram_dma_heap; + struct dma_heap_export_info exp_info; + + dev_dbg(sram->dev, "Exporting SRAM Heap '%s'\n", block->label); + + sram_dma_heap = kzalloc(sizeof(*sram_dma_heap), GFP_KERNEL); + if (!sram_dma_heap) + return -ENOMEM; + sram_dma_heap->pool = part->pool; + + exp_info.name = kasprintf(GFP_KERNEL, "sram_%s", block->label); + exp_info.ops = &sram_dma_heap_ops; + exp_info.priv = sram_dma_heap; + sram_dma_heap->heap = dma_heap_add(&exp_info); + if (IS_ERR(sram_dma_heap->heap)) { + int ret = PTR_ERR(sram_dma_heap->heap); + kfree(sram_dma_heap); + return ret; + } + + return 0; +} diff -Naur --no-dereference a/drivers/misc/sram.h b/drivers/misc/sram.h --- a/drivers/misc/sram.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/misc/sram.h 2024-07-07 20:37:34.664306649 -0400 @@ -60,4 +60,20 @@ return -ENODEV; } #endif /* CONFIG_SRAM_EXEC */ + +#ifdef CONFIG_SRAM_DMA_HEAP +int sram_add_dma_heap(struct sram_dev *sram, + struct sram_reserve *block, + phys_addr_t start, + struct sram_partition *part); +#else +static inline int sram_add_dma_heap(struct sram_dev *sram, + struct sram_reserve *block, + phys_addr_t start, + struct sram_partition *part) +{ + return 0; +} +#endif /* CONFIG_SRAM_DMA_HEAP */ + #endif /* __SRAM_H */ diff -Naur --no-dereference a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c --- a/drivers/mmc/host/sdhci_am654.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/mmc/host/sdhci_am654.c 2024-07-07 20:37:34.664306649 -0400 @@ -141,19 +141,26 @@ struct sdhci_am654_data { struct regmap *base; - bool legacy_otapdly; - int otap_del_sel[ARRAY_SIZE(td)]; - int itap_del_sel[ARRAY_SIZE(td)]; + u32 otap_del_sel[ARRAY_SIZE(td)]; + u32 itap_del_sel[ARRAY_SIZE(td)]; + u32 itap_del_ena[ARRAY_SIZE(td)]; int clkbuf_sel; int trm_icp; int drv_strength; int strb_sel; u32 flags; u32 quirks; + bool dll_enable; #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) }; +struct window { + u8 start; + u8 end; + u8 length; +}; + struct sdhci_am654_driver_data { const struct sdhci_pltfm_data *pdata; u32 flags; @@ -233,11 +240,13 @@ } static void sdhci_am654_write_itapdly(struct sdhci_am654_data *sdhci_am654, - u32 itapdly) + u32 itapdly, u32 enable) { /* Set ITAPCHGWIN before writing to ITAPDLY */ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 1 << ITAPCHGWIN_SHIFT); + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK, + enable << ITAPDLYENA_SHIFT); regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYSEL_MASK, itapdly << ITAPDLYSEL_SHIFT); regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0); @@ -254,8 +263,8 @@ mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK; regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask, val); - sdhci_am654_write_itapdly(sdhci_am654, - sdhci_am654->itap_del_sel[timing]); + sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654->itap_del_sel[timing], + sdhci_am654->itap_del_ena[timing]); } static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) @@ -264,23 +273,17 @@ struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); unsigned char timing = host->mmc->ios.timing; u32 otap_del_sel; - u32 otap_del_ena; u32 mask, val; regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0); sdhci_set_clock(host, clock); - /* Setup DLL Output TAP delay */ - if (sdhci_am654->legacy_otapdly) - otap_del_sel = sdhci_am654->otap_del_sel[0]; - else - otap_del_sel = sdhci_am654->otap_del_sel[timing]; - - otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0; + /* Setup Output TAP delay */ + otap_del_sel = sdhci_am654->otap_del_sel[timing]; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; - val = (otap_del_ena << OTAPDLYENA_SHIFT) | + val = (0x1 << OTAPDLYENA_SHIFT) | (otap_del_sel << OTAPDLYSEL_SHIFT); /* Write to STRBSEL for HS400 speed mode */ @@ -295,10 +298,21 @@ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); - if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) + if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) { sdhci_am654_setup_dll(host, clock); - else + sdhci_am654->dll_enable = true; + + if (timing == MMC_TIMING_MMC_HS400) { + sdhci_am654->itap_del_ena[timing] = 0x1; + sdhci_am654->itap_del_sel[timing] = sdhci_am654->itap_del_sel[timing - 1]; + } + + sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654->itap_del_sel[timing], + sdhci_am654->itap_del_ena[timing]); + } else { sdhci_am654_setup_delay_chain(sdhci_am654, timing); + sdhci_am654->dll_enable = false; + } regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, sdhci_am654->clkbuf_sel); @@ -311,19 +325,29 @@ struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); unsigned char timing = host->mmc->ios.timing; u32 otap_del_sel; + u32 itap_del_ena; + u32 itap_del_sel; u32 mask, val; - /* Setup DLL Output TAP delay */ - if (sdhci_am654->legacy_otapdly) - otap_del_sel = sdhci_am654->otap_del_sel[0]; - else - otap_del_sel = sdhci_am654->otap_del_sel[timing]; + /* Setup Output TAP delay */ + otap_del_sel = sdhci_am654->otap_del_sel[timing]; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; val = (0x1 << OTAPDLYENA_SHIFT) | (otap_del_sel << OTAPDLYSEL_SHIFT); - regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); + /* Setup Input TAP delay */ + itap_del_ena = sdhci_am654->itap_del_ena[timing]; + itap_del_sel = sdhci_am654->itap_del_sel[timing]; + + mask |= ITAPDLYENA_MASK | ITAPDLYSEL_MASK; + val |= (itap_del_ena << ITAPDLYENA_SHIFT) | + (itap_del_sel << ITAPDLYSEL_SHIFT); + + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, + 1 << ITAPCHGWIN_SHIFT); + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0); regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, sdhci_am654->clkbuf_sel); @@ -416,40 +440,105 @@ return 0; } -#define ITAP_MAX 32 +#define ITAPDLY_LENGTH 32 +#define ITAPDLY_LAST_INDEX (ITAPDLY_LENGTH - 1) + +static u32 sdhci_am654_calculate_itap(struct sdhci_host *host, struct window + *fail_window, u8 num_fails, bool circular_buffer) +{ + u8 itap = 0, start_fail = 0, end_fail = 0, pass_length = 0; + u8 first_fail_start = 0, last_fail_end = 0; + struct device *dev = mmc_dev(host->mmc); + struct window pass_window = {0, 0, 0}; + int prev_fail_end = -1; + u8 i; + + if (!num_fails) + return ITAPDLY_LAST_INDEX >> 1; + + if (fail_window->length == ITAPDLY_LENGTH) { + dev_err(dev, "No passing ITAPDLY, return 0\n"); + return 0; + } + + first_fail_start = fail_window->start; + last_fail_end = fail_window[num_fails - 1].end; + + for (i = 0; i < num_fails; i++) { + start_fail = fail_window[i].start; + end_fail = fail_window[i].end; + pass_length = start_fail - (prev_fail_end + 1); + + if (pass_length > pass_window.length) { + pass_window.start = prev_fail_end + 1; + pass_window.length = pass_length; + } + prev_fail_end = end_fail; + } + + if (!circular_buffer) + pass_length = ITAPDLY_LAST_INDEX - last_fail_end; + else + pass_length = ITAPDLY_LAST_INDEX - last_fail_end + first_fail_start; + + if (pass_length > pass_window.length) { + pass_window.start = last_fail_end + 1; + pass_window.length = pass_length; + } + + if (!circular_buffer) + itap = pass_window.start + (pass_window.length >> 1); + else + itap = (pass_window.start + (pass_window.length >> 1)) % ITAPDLY_LENGTH; + + return (itap > ITAPDLY_LAST_INDEX) ? ITAPDLY_LAST_INDEX >> 1 : itap; +} + static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host, u32 opcode) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); - int cur_val, prev_val = 1, fail_len = 0, pass_window = 0, pass_len; - u32 itap; + unsigned char timing = host->mmc->ios.timing; + struct window fail_window[ITAPDLY_LENGTH]; + u8 curr_pass, itap; + u8 fail_index = 0; + u8 prev_pass = 1; + + memset(fail_window, 0, sizeof(fail_window)); /* Enable ITAPDLY */ - regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK, - 1 << ITAPDLYENA_SHIFT); + sdhci_am654->itap_del_ena[timing] = 0x1; + + for (itap = 0; itap < ITAPDLY_LENGTH; itap++) { + sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]); + + curr_pass = !mmc_send_tuning(host->mmc, opcode, NULL); - for (itap = 0; itap < ITAP_MAX; itap++) { - sdhci_am654_write_itapdly(sdhci_am654, itap); + if (!curr_pass && prev_pass) + fail_window[fail_index].start = itap; - cur_val = !mmc_send_tuning(host->mmc, opcode, NULL); - if (cur_val && !prev_val) - pass_window = itap; + if (!curr_pass) { + fail_window[fail_index].end = itap; + fail_window[fail_index].length++; + } - if (!cur_val) - fail_len++; + if (curr_pass && !prev_pass) + fail_index++; - prev_val = cur_val; + prev_pass = curr_pass; } - /* - * Having determined the length of the failing window and start of - * the passing window calculate the length of the passing window and - * set the final value halfway through it considering the range as a - * circular buffer - */ - pass_len = ITAP_MAX - fail_len; - itap = (pass_window + (pass_len >> 1)) % ITAP_MAX; - sdhci_am654_write_itapdly(sdhci_am654, itap); + + if (fail_window[fail_index].length != 0) + fail_index++; + + itap = sdhci_am654_calculate_itap(host, fail_window, fail_index, + sdhci_am654->dll_enable); + + sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]); + + /* Save ITAPDLY */ + sdhci_am654->itap_del_sel[timing] = itap; return 0; } @@ -577,32 +666,15 @@ int i; int ret; - ret = device_property_read_u32(dev, td[MMC_TIMING_LEGACY].otap_binding, - &sdhci_am654->otap_del_sel[MMC_TIMING_LEGACY]); - if (ret) { - /* - * ti,otap-del-sel-legacy is mandatory, look for old binding - * if not found. - */ - ret = device_property_read_u32(dev, "ti,otap-del-sel", - &sdhci_am654->otap_del_sel[0]); - if (ret) { - dev_err(dev, "Couldn't find otap-del-sel\n"); - - return ret; - } - - dev_info(dev, "Using legacy binding ti,otap-del-sel\n"); - sdhci_am654->legacy_otapdly = true; - - return 0; - } - for (i = MMC_TIMING_LEGACY; i <= MMC_TIMING_MMC_HS400; i++) { ret = device_property_read_u32(dev, td[i].otap_binding, &sdhci_am654->otap_del_sel[i]); if (ret) { + if (i == MMC_TIMING_LEGACY) { + dev_err(dev, "Couldn't find mandatory ti,otap-del-sel-legacy\n"); + return ret; + } dev_dbg(dev, "Couldn't find %s\n", td[i].otap_binding); /* @@ -615,9 +687,12 @@ host->mmc->caps2 &= ~td[i].capability; } - if (td[i].itap_binding) - device_property_read_u32(dev, td[i].itap_binding, - &sdhci_am654->itap_del_sel[i]); + if (td[i].itap_binding) { + ret = device_property_read_u32(dev, td[i].itap_binding, + &sdhci_am654->itap_del_sel[i]); + if (!ret) + sdhci_am654->itap_del_ena[i] = 0x1; + } } return 0; diff -Naur --no-dereference a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c --- a/drivers/mtd/nand/spi/winbond.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/mtd/nand/spi/winbond.c 2024-07-07 20:37:34.664306649 -0400 @@ -31,6 +31,19 @@ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), SPINAND_PROG_LOAD(false, 0, NULL, 0)); +static SPINAND_OP_VARIANTS(octalio_read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_OP(0, 16, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + +static SPINAND_OP_VARIANTS(x8_write_cache_variants, + SPINAND_PROG_LOAD_OCTALIO(true, 0, NULL, 0), + SPINAND_PROG_LOAD(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(x8_update_cache_variants, + SPINAND_PROG_LOAD_OCTALIO(false, 0, NULL, 0), + SPINAND_PROG_LOAD(false, 0, NULL, 0)); + static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) { @@ -55,11 +68,40 @@ return 0; } +static int w35n01jw_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 7) + return -ERANGE; + + region->offset = (16 * section) + 12; + region->length = 4; + + return 0; +} + +static int w35n01jw_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 7) + return -ERANGE; + + region->offset = (16 * section) + 2; + region->length = 10; + + return 0; +} + static const struct mtd_ooblayout_ops w25m02gv_ooblayout = { .ecc = w25m02gv_ooblayout_ecc, .free = w25m02gv_ooblayout_free, }; +static const struct mtd_ooblayout_ops w35n01jw_ooblayout = { + .ecc = w35n01jw_ooblayout_ecc, + .free = w35n01jw_ooblayout_free, +}; + static int w25m02gv_select_target(struct spinand_device *spinand, unsigned int target) { @@ -169,6 +211,15 @@ &update_cache_variants), 0, SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), + SPINAND_INFO("W35N01JW", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc, 0x21), + NAND_MEMORG(1, 4096, 128, 64, 512, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&octalio_read_cache_variants, + &x8_write_cache_variants, + &x8_update_cache_variants), + SPINAND_HAS_CR_FEAT_BIT, + SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL)), }; static int winbond_spinand_init(struct spinand_device *spinand) diff -Naur --no-dereference a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c --- a/drivers/mtd/spi-nor/core.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/mtd/spi-nor/core.c 2024-07-07 20:37:34.664306649 -0400 @@ -184,6 +184,33 @@ } /** + * spi_nor_spimem_get_read_op() - return a template for the spi_mem_op used for + * reading data from the flash via spi-mem. + * @nor: pointer to 'struct spi_nor' + * + * Return: A template of the 'struct spi_mem_op' for used for reading data from + * the flash. The caller is expected to fill in the address, data length, and + * the data buffer. + */ +static struct spi_mem_op spi_nor_spimem_get_read_op(struct spi_nor *nor) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), + SPI_MEM_OP_DUMMY(nor->read_dummy, 0), + SPI_MEM_OP_DATA_IN(1, NULL, 0)); + + spi_nor_spimem_setup_op(nor, &op, nor->read_proto); + + /* convert the dummy cycles to the number of bytes */ + op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8; + if (spi_nor_protocol_is_dtr(nor->read_proto)) + op.dummy.nbytes *= 2; + + return op; +} + +/** * spi_nor_spimem_read_data() - read data from flash's memory region via * spi-mem * @nor: pointer to 'struct spi_nor' @@ -196,21 +223,14 @@ static ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t from, size_t len, u8 *buf) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_nbytes, from, 0), - SPI_MEM_OP_DUMMY(nor->read_dummy, 0), - SPI_MEM_OP_DATA_IN(len, buf, 0)); + struct spi_mem_op op = spi_nor_spimem_get_read_op(nor); bool usebouncebuf; ssize_t nbytes; int error; - spi_nor_spimem_setup_op(nor, &op, nor->read_proto); - - /* convert the dummy cycles to the number of bytes */ - op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8; - if (spi_nor_protocol_is_dtr(nor->read_proto)) - op.dummy.nbytes *= 2; + op.addr.val = from; + op.data.nbytes = len; + op.data.buf.in = buf; usebouncebuf = spi_nor_spimem_bounce(nor, &op); @@ -3559,28 +3579,10 @@ static int spi_nor_create_read_dirmap(struct spi_nor *nor) { struct spi_mem_dirmap_info info = { - .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), - SPI_MEM_OP_DUMMY(nor->read_dummy, 0), - SPI_MEM_OP_DATA_IN(0, NULL, 0)), + .op_tmpl = spi_nor_spimem_get_read_op(nor), .offset = 0, .length = nor->params->size, }; - struct spi_mem_op *op = &info.op_tmpl; - - spi_nor_spimem_setup_op(nor, op, nor->read_proto); - - /* convert the dummy cycles to the number of bytes */ - op->dummy.nbytes = (nor->read_dummy * op->dummy.buswidth) / 8; - if (spi_nor_protocol_is_dtr(nor->read_proto)) - op->dummy.nbytes *= 2; - - /* - * Since spi_nor_spimem_setup_op() only sets buswidth when the number - * of data bytes is non-zero, the data buswidth won't be set here. So, - * do it explicitly. - */ - op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto); nor->dirmap.rdesc = devm_spi_mem_dirmap_create(nor->dev, nor->spimem, &info); @@ -3626,6 +3628,7 @@ * checking what's really supported using spi_mem_supports_op(). */ const struct spi_nor_hwcaps hwcaps = { .mask = SNOR_HWCAPS_ALL }; + struct mtd_part *part; char *flash_name; int ret; @@ -3687,8 +3690,25 @@ if (ret) return ret; - return mtd_device_register(&nor->mtd, data ? data->parts : NULL, - data ? data->nr_parts : 0); + ret = mtd_device_register(&nor->mtd, data ? data->parts : NULL, + data ? data->nr_parts : 0); + if (ret) + return ret; + + list_for_each_entry(part, &nor->mtd.partitions, node) { + struct spi_mem_op op; + struct mtd_info *part_info = container_of(part, + struct mtd_info, part); + + if (part_info->name && + !strcmp(part_info->name, "ospi.phypattern")) { + op = spi_nor_spimem_get_read_op(nor); + op.addr.val = part->offset; + spi_mem_do_calibration(nor->spimem, &op); + } + } + + return 0; } static int spi_nor_remove(struct spi_mem *spimem) diff -Naur --no-dereference a/drivers/mux/core.c b/drivers/mux/core.c --- a/drivers/mux/core.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/mux/core.c 2024-07-07 20:37:34.664306649 -0400 @@ -215,6 +215,35 @@ } EXPORT_SYMBOL_GPL(mux_chip_free); +/** + * mux_chip_resume() - restores the mux-chip state + * @mux_chip: The mux-chip to resume. + * + * Restores the mux-chip state. + * + * Return: Zero on success or a negative errno on error. + */ +int mux_chip_resume(struct mux_chip *mux_chip) +{ + int ret, i; + + for (i = 0; i < mux_chip->controllers; ++i) { + struct mux_control *mux = &mux_chip->mux[i]; + + if (mux->cached_state == MUX_CACHE_UNKNOWN) + continue; + + ret = mux_control_set(mux, mux->cached_state); + if (ret < 0) { + dev_err(&mux_chip->dev, "unable to restore state\n"); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(mux_chip_resume); + static void devm_mux_chip_release(struct device *dev, void *res) { struct mux_chip *mux_chip = *(struct mux_chip **)res; diff -Naur --no-dereference a/drivers/mux/mmio.c b/drivers/mux/mmio.c --- a/drivers/mux/mmio.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/mux/mmio.c 2024-07-07 20:37:34.664306649 -0400 @@ -44,15 +44,20 @@ int ret; int i; - if (of_device_is_compatible(np, "mmio-mux")) + if (of_device_is_compatible(np, "mmio-mux")) { regmap = syscon_node_to_regmap(np->parent); - else - regmap = dev_get_regmap(dev->parent, NULL) ?: ERR_PTR(-ENODEV); - if (IS_ERR(regmap)) { - ret = PTR_ERR(regmap); - dev_err(dev, "failed to get regmap: %d\n", ret); - return ret; + } else { + regmap = device_node_to_regmap(np); + /* Fallback to checking the parent node on "real" errors. */ + if (IS_ERR(regmap) && regmap != ERR_PTR(-EPROBE_DEFER)) { + regmap = dev_get_regmap(dev->parent, NULL); + if (!regmap) + regmap = ERR_PTR(-ENODEV); + } } + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "failed to get regmap\n"); ret = of_property_count_u32_elems(np, "mux-reg-masks"); if (ret == 0 || ret % 2) @@ -125,13 +130,25 @@ mux_chip->ops = &mux_mmio_ops; + dev_set_drvdata(dev, mux_chip); + return devm_mux_chip_register(dev, mux_chip); } +static int mux_mmio_resume_noirq(struct device *dev) +{ + struct mux_chip *mux_chip = dev_get_drvdata(dev); + + return mux_chip_resume(mux_chip); +} + +static DEFINE_NOIRQ_DEV_PM_OPS(mux_mmio_pm_ops, NULL, mux_mmio_resume_noirq); + static struct platform_driver mux_mmio_driver = { .driver = { .name = "mmio-mux", .of_match_table = mux_mmio_dt_ids, + .pm = pm_sleep_ptr(&mux_mmio_pm_ops), }, .probe = mux_mmio_probe, }; diff -Naur --no-dereference a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c --- a/drivers/net/can/m_can/m_can.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/can/m_can/m_can.c 2024-07-07 20:37:34.664306649 -0400 @@ -1901,8 +1901,40 @@ .ndo_change_mtu = can_change_mtu, }; +static void m_can_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct m_can_classdev *cdev = netdev_priv(dev); + + wol->supported = device_can_wakeup(cdev->dev) ? WAKE_PHY : 0; + wol->wolopts = device_may_wakeup(cdev->dev) ? WAKE_PHY : 0; +} + +static int m_can_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct m_can_classdev *cdev = netdev_priv(dev); + struct pinctrl_state *new_pinctrl_state = NULL; + bool wol_enable = !!wol->wolopts & WAKE_PHY; + + if ((wol->wolopts & WAKE_PHY) != wol->wolopts) + return -EINVAL; + + if (wol_enable) + new_pinctrl_state = cdev->pinctrl_state_wakeup; + else + new_pinctrl_state = cdev->pinctrl_state_default; + + if (!IS_ERR_OR_NULL(new_pinctrl_state)) + pinctrl_select_state(cdev->pinctrl, new_pinctrl_state); + + device_set_wakeup_enable(cdev->dev, wol_enable); + + return 0; +} + static const struct ethtool_ops m_can_ethtool_ops = { .get_ts_info = ethtool_op_get_ts_info, + .get_wol = m_can_get_wol, + .set_wol = m_can_set_wol, }; static int register_m_can_dev(struct net_device *dev) @@ -2024,6 +2056,9 @@ goto out; } + if (dev->of_node && of_property_read_bool(dev->of_node, "wakeup-source")) + device_set_wakeup_capable(dev, true); + /* Get TX FIFO size * Defines the total amount of echo buffers for loopback */ @@ -2042,6 +2077,14 @@ SET_NETDEV_DEV(net_dev, dev); m_can_of_parse_mram(class_dev, mram_config_vals); + + class_dev->pinctrl = devm_pinctrl_get(dev); + if (!IS_ERR_OR_NULL(class_dev->pinctrl)) { + class_dev->pinctrl_state_default = + pinctrl_lookup_state(class_dev->pinctrl, "default"); + class_dev->pinctrl_state_wakeup = + pinctrl_lookup_state(class_dev->pinctrl, "wakeup"); + } out: return class_dev; } diff -Naur --no-dereference a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h --- a/drivers/net/can/m_can/m_can.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/can/m_can/m_can.h 2024-07-07 20:37:34.664306649 -0400 @@ -95,6 +95,10 @@ struct mram_cfg mcfg[MRAM_CFG_NUM]; struct hrtimer hrtimer; + + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_state_default; + struct pinctrl_state *pinctrl_state_wakeup; }; struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, int sizeof_priv); diff -Naur --no-dereference a/drivers/net/ethernet/altera/altera_tse.h b/drivers/net/ethernet/altera/altera_tse.h --- a/drivers/net/ethernet/altera/altera_tse.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/altera/altera_tse.h 2024-07-07 20:37:34.664306649 -0400 @@ -472,7 +472,7 @@ /* ethtool msglvl option */ u32 msg_enable; - struct altera_dmaops *dmaops; + const struct altera_dmaops *dmaops; struct phylink *phylink; struct phylink_config phylink_config; diff -Naur --no-dereference a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c --- a/drivers/net/ethernet/altera/altera_tse_main.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/altera/altera_tse_main.c 2024-07-07 20:37:34.664306649 -0400 @@ -29,13 +29,13 @@ #include #include #include -#include +#include #include #include -#include #include #include #include +#include #include #include #include @@ -82,8 +82,6 @@ #define TXQUEUESTOP_THRESHHOLD 2 -static const struct of_device_id altera_tse_ids[]; - static inline u32 tse_tx_avail(struct altera_tse_private *priv) { return priv->tx_cons + priv->tx_ring_size - priv->tx_prod - 1; @@ -1133,7 +1131,6 @@ */ static int altera_tse_probe(struct platform_device *pdev) { - const struct of_device_id *of_id = NULL; struct regmap_config pcs_regmap_cfg; struct altera_tse_private *priv; struct mdio_regmap_config mrc; @@ -1159,11 +1156,7 @@ priv->dev = ndev; priv->msg_enable = netif_msg_init(debug, default_msg_level); - of_id = of_match_device(altera_tse_ids, &pdev->dev); - - if (of_id) - priv->dmaops = (struct altera_dmaops *)of_id->data; - + priv->dmaops = device_get_match_data(&pdev->dev); if (priv->dmaops && priv->dmaops->altera_dtype == ALTERA_DTYPE_SGDMA) { diff -Naur --no-dereference a/drivers/net/ethernet/amd/xgbe/xgbe-platform.c b/drivers/net/ethernet/amd/xgbe/xgbe-platform.c --- a/drivers/net/ethernet/amd/xgbe/xgbe-platform.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/amd/xgbe/xgbe-platform.c 2024-07-07 20:37:34.664306649 -0400 @@ -123,9 +123,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -135,17 +133,6 @@ #include "xgbe-common.h" #ifdef CONFIG_ACPI -static const struct acpi_device_id xgbe_acpi_match[]; - -static struct xgbe_version_data *xgbe_acpi_vdata(struct xgbe_prv_data *pdata) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(xgbe_acpi_match, pdata->dev); - - return id ? (struct xgbe_version_data *)id->driver_data : NULL; -} - static int xgbe_acpi_support(struct xgbe_prv_data *pdata) { struct device *dev = pdata->dev; @@ -173,11 +160,6 @@ return 0; } #else /* CONFIG_ACPI */ -static struct xgbe_version_data *xgbe_acpi_vdata(struct xgbe_prv_data *pdata) -{ - return NULL; -} - static int xgbe_acpi_support(struct xgbe_prv_data *pdata) { return -EINVAL; @@ -185,17 +167,6 @@ #endif /* CONFIG_ACPI */ #ifdef CONFIG_OF -static const struct of_device_id xgbe_of_match[]; - -static struct xgbe_version_data *xgbe_of_vdata(struct xgbe_prv_data *pdata) -{ - const struct of_device_id *id; - - id = of_match_device(xgbe_of_match, pdata->dev); - - return id ? (struct xgbe_version_data *)id->data : NULL; -} - static int xgbe_of_support(struct xgbe_prv_data *pdata) { struct device *dev = pdata->dev; @@ -244,11 +215,6 @@ return phy_pdev; } #else /* CONFIG_OF */ -static struct xgbe_version_data *xgbe_of_vdata(struct xgbe_prv_data *pdata) -{ - return NULL; -} - static int xgbe_of_support(struct xgbe_prv_data *pdata) { return -EINVAL; @@ -290,12 +256,6 @@ return phy_pdev; } -static struct xgbe_version_data *xgbe_get_vdata(struct xgbe_prv_data *pdata) -{ - return pdata->use_acpi ? xgbe_acpi_vdata(pdata) - : xgbe_of_vdata(pdata); -} - static int xgbe_platform_probe(struct platform_device *pdev) { struct xgbe_prv_data *pdata; @@ -321,7 +281,7 @@ pdata->use_acpi = dev->of_node ? 0 : 1; /* Get the version data */ - pdata->vdata = xgbe_get_vdata(pdata); + pdata->vdata = (struct xgbe_version_data *)device_get_match_data(dev); phy_pdev = xgbe_get_phy_pdev(pdata); if (!phy_pdev) { diff -Naur --no-dereference a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c 2024-07-07 20:37:34.664306649 -0400 @@ -2018,7 +2018,6 @@ struct xgene_enet_pdata *pdata; struct device *dev = &pdev->dev; void (*link_state)(struct work_struct *); - const struct of_device_id *of_id; int ret; ndev = alloc_etherdev_mqs(sizeof(struct xgene_enet_pdata), @@ -2039,19 +2038,7 @@ NETIF_F_GRO | NETIF_F_SG; - of_id = of_match_device(xgene_enet_of_match, &pdev->dev); - if (of_id) { - pdata->enet_id = (uintptr_t)of_id->data; - } -#ifdef CONFIG_ACPI - else { - const struct acpi_device_id *acpi_id; - - acpi_id = acpi_match_device(xgene_enet_acpi_match, &pdev->dev); - if (acpi_id) - pdata->enet_id = (enum xgene_enet_id) acpi_id->driver_data; - } -#endif + pdata->enet_id = (enum xgene_enet_id)device_get_match_data(&pdev->dev); if (!pdata->enet_id) { ret = -ENODEV; goto err; diff -Naur --no-dereference a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h 2024-07-07 20:37:34.664306649 -0400 @@ -15,9 +15,10 @@ #include #include #include -#include +#include #include #include +#include #include #include #include diff -Naur --no-dereference a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c --- a/drivers/net/ethernet/freescale/fec_main.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/freescale/fec_main.c 2024-07-07 20:37:34.668306669 -0400 @@ -52,11 +52,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -4296,14 +4296,13 @@ phy_interface_t interface; struct net_device *ndev; int i, irq, ret = 0; - const struct of_device_id *of_id; static int dev_id; struct device_node *np = pdev->dev.of_node, *phy_node; int num_tx_qs; int num_rx_qs; char irq_name[8]; int irq_cnt; - struct fec_devinfo *dev_info; + const struct fec_devinfo *dev_info; fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs); @@ -4318,10 +4317,9 @@ /* setup board info structure */ fep = netdev_priv(ndev); - of_id = of_match_device(fec_dt_ids, &pdev->dev); - if (of_id) - pdev->id_entry = of_id->data; - dev_info = (struct fec_devinfo *)pdev->id_entry->driver_data; + dev_info = device_get_match_data(&pdev->dev); + if (!dev_info) + dev_info = (const struct fec_devinfo *)pdev->id_entry->driver_data; if (dev_info) fep->quirks = dev_info->quirks; diff -Naur --no-dereference a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c 2024-07-07 20:37:34.668306669 -0400 @@ -35,10 +35,9 @@ #include #include #include +#include #include #include -#include -#include #include #include @@ -884,9 +883,9 @@ /**************************************************************************************/ #ifdef CONFIG_FS_ENET_HAS_FEC -#define IS_FEC(match) ((match)->data == &fs_fec_ops) +#define IS_FEC(ops) ((ops) == &fs_fec_ops) #else -#define IS_FEC(match) 0 +#define IS_FEC(ops) 0 #endif static const struct net_device_ops fs_enet_netdev_ops = { @@ -903,10 +902,9 @@ #endif }; -static const struct of_device_id fs_enet_match[]; static int fs_enet_probe(struct platform_device *ofdev) { - const struct of_device_id *match; + const struct fs_ops *ops; struct net_device *ndev; struct fs_enet_private *fep; struct fs_platform_info *fpi; @@ -916,15 +914,15 @@ const char *phy_connection_type; int privsize, len, ret = -ENODEV; - match = of_match_device(fs_enet_match, &ofdev->dev); - if (!match) + ops = device_get_match_data(&ofdev->dev); + if (!ops) return -EINVAL; fpi = kzalloc(sizeof(*fpi), GFP_KERNEL); if (!fpi) return -ENOMEM; - if (!IS_FEC(match)) { + if (!IS_FEC(ops)) { data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len); if (!data || len != 4) goto out_free_fpi; @@ -986,7 +984,7 @@ fep->dev = &ofdev->dev; fep->ndev = ndev; fep->fpi = fpi; - fep->ops = match->data; + fep->ops = ops; ret = fep->ops->setup_data(ndev); if (ret) diff -Naur --no-dereference a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c --- a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c 2024-07-07 20:37:34.668306669 -0400 @@ -30,9 +30,10 @@ #include #include #include +#include +#include #include #include -#include #include #include @@ -96,20 +97,15 @@ } -static const struct of_device_id fs_enet_mdio_fec_match[]; static int fs_enet_mdio_probe(struct platform_device *ofdev) { - const struct of_device_id *match; struct resource res; struct mii_bus *new_bus; struct fec_info *fec; int (*get_bus_freq)(struct device *); int ret = -ENOMEM, clock, speed; - match = of_match_device(fs_enet_mdio_fec_match, &ofdev->dev); - if (!match) - return -EINVAL; - get_bus_freq = match->data; + get_bus_freq = device_get_match_data(&ofdev->dev); new_bus = mdiobus_alloc(); if (!new_bus) diff -Naur --no-dereference a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c 2024-07-07 20:37:34.668306669 -0400 @@ -19,9 +19,10 @@ #include #include #include +#include #include #include -#include +#include #include #if IS_ENABLED(CONFIG_UCC_GETH) @@ -407,8 +408,6 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev) { - const struct of_device_id *id = - of_match_device(fsl_pq_mdio_match, &pdev->dev); const struct fsl_pq_mdio_data *data; struct device_node *np = pdev->dev.of_node; struct resource res; @@ -417,15 +416,12 @@ struct mii_bus *new_bus; int err; - if (!id) { + data = device_get_match_data(&pdev->dev); + if (!data) { dev_err(&pdev->dev, "Failed to match device\n"); return -ENODEV; } - data = id->data; - - dev_dbg(&pdev->dev, "found %s compatible node\n", id->compatible); - new_bus = mdiobus_alloc_size(sizeof(*priv)); if (!new_bus) return -ENOMEM; diff -Naur --no-dereference a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c --- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c 2024-07-07 20:37:34.668306669 -0400 @@ -7,7 +7,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -1094,7 +1095,6 @@ { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; - const struct of_device_id *of_id = NULL; struct net_device *ndev; struct hix5hd2_priv *priv; struct mii_bus *bus; @@ -1110,12 +1110,7 @@ priv->dev = dev; priv->netdev = ndev; - of_id = of_match_device(hix5hd2_of_match, dev); - if (!of_id) { - ret = -EINVAL; - goto out_free_netdev; - } - priv->hw_cap = (unsigned long)of_id->data; + priv->hw_cap = (unsigned long)device_get_match_data(dev); priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) { diff -Naur --no-dereference a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c 2024-07-07 20:37:34.668306669 -0400 @@ -7,8 +7,8 @@ #include #include #include -#include #include +#include #include #include "dwmac4.h" @@ -76,7 +76,6 @@ { struct plat_stmmacenet_data *plat_dat; struct stmmac_resources stmmac_res; - const struct of_device_id *match; struct intel_dwmac *dwmac; unsigned long rate; int ret; @@ -100,10 +99,8 @@ dwmac->dev = &pdev->dev; dwmac->tx_clk = NULL; - match = of_match_device(intel_eth_plat_match, &pdev->dev); - if (match && match->data) { - dwmac->data = (const struct intel_dwmac_data *)match->data; - + dwmac->data = device_get_match_data(&pdev->dev); + if (dwmac->data) { if (dwmac->data->fix_mac_speed) plat_dat->fix_mac_speed = dwmac->data->fix_mac_speed; diff -Naur --no-dereference a/drivers/net/ethernet/ti/am65-cpsw-ethtool.c b/drivers/net/ethernet/ti/am65-cpsw-ethtool.c --- a/drivers/net/ethernet/ti/am65-cpsw-ethtool.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/am65-cpsw-ethtool.c 2024-07-07 20:37:34.668306669 -0400 @@ -11,6 +11,7 @@ #include #include "am65-cpsw-nuss.h" +#include "am65-cpsw-qos.h" #include "cpsw_ale.h" #include "am65-cpts.h" @@ -373,6 +374,8 @@ static const char am65_cpsw_ethtool_priv_flags[][ETH_GSTRING_LEN] = { #define AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN BIT(0) "p0-rx-ptype-rrobin", +#define AM65_CPSW_PRIV_CUT_THRU BIT(1) + "cut-thru", }; static int am65_cpsw_ethtool_op_begin(struct net_device *ndev) @@ -662,10 +665,49 @@ hw_stats[i].offset); } +static void am65_cpsw_get_eth_mac_stats(struct net_device *ndev, + struct ethtool_eth_mac_stats *s) +{ + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + struct am65_cpsw_stats_regs __iomem *stats; + + stats = port->stat_base; + + if (s->src != ETHTOOL_MAC_STATS_SRC_AGGREGATE) + return; + + s->FramesTransmittedOK = readl_relaxed(&stats->tx_good_frames); + s->SingleCollisionFrames = readl_relaxed(&stats->tx_single_coll_frames); + s->MultipleCollisionFrames = readl_relaxed(&stats->tx_mult_coll_frames); + s->FramesReceivedOK = readl_relaxed(&stats->rx_good_frames); + s->FrameCheckSequenceErrors = readl_relaxed(&stats->rx_crc_errors); + s->AlignmentErrors = readl_relaxed(&stats->rx_align_code_errors); + s->OctetsTransmittedOK = readl_relaxed(&stats->tx_octets); + s->FramesWithDeferredXmissions = readl_relaxed(&stats->tx_deferred_frames); + s->LateCollisions = readl_relaxed(&stats->tx_late_collisions); + s->CarrierSenseErrors = readl_relaxed(&stats->tx_carrier_sense_errors); + s->OctetsReceivedOK = readl_relaxed(&stats->rx_octets); + s->MulticastFramesXmittedOK = readl_relaxed(&stats->tx_multicast_frames); + s->BroadcastFramesXmittedOK = readl_relaxed(&stats->tx_broadcast_frames); + s->MulticastFramesReceivedOK = readl_relaxed(&stats->rx_multicast_frames); + s->BroadcastFramesReceivedOK = readl_relaxed(&stats->rx_broadcast_frames); +}; + static int am65_cpsw_get_ethtool_ts_info(struct net_device *ndev, struct ethtool_ts_info *info) { struct am65_cpsw_common *common = am65_ndev_to_common(ndev); + unsigned int ptp_v2_filter; + + ptp_v2_filter = BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | + BIT(HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | + BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | + BIT(HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | + BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_SYNC) | + BIT(HWTSTAMP_FILTER_PTP_V2_DELAY_REQ); if (!IS_ENABLED(CONFIG_TI_K3_AM65_CPTS)) return ethtool_op_get_ts_info(ndev, info); @@ -679,27 +721,32 @@ SOF_TIMESTAMPING_RAW_HARDWARE; info->phc_index = am65_cpts_phc_index(common->cpts); info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON); - info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL); + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | ptp_v2_filter; return 0; } static u32 am65_cpsw_get_ethtool_priv_flags(struct net_device *ndev) { struct am65_cpsw_common *common = am65_ndev_to_common(ndev); + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); u32 priv_flags = 0; if (common->pf_p0_rx_ptype_rrobin) priv_flags |= AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN; + if (port->qos.cut_thru.enable) + priv_flags |= AM65_CPSW_PRIV_CUT_THRU; return priv_flags; } static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags) { struct am65_cpsw_common *common = am65_ndev_to_common(ndev); - int rrobin; + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + int rrobin, cut_thru; rrobin = !!(flags & AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN); + cut_thru = !!(flags & AM65_CPSW_PRIV_CUT_THRU); if (common->usage_count) return -EBUSY; @@ -710,7 +757,252 @@ return -EINVAL; } + if (cut_thru && !(common->pdata.quirks & AM64_CPSW_QUIRK_CUT_THRU)) { + netdev_err(ndev, "Cut-Thru not supported\n"); + return -EOPNOTSUPP; + } + + if (cut_thru && common->is_emac_mode) { + netdev_err(ndev, "Enable switch mode for cut-thru\n"); + return -EINVAL; + } + common->pf_p0_rx_ptype_rrobin = rrobin; + port->qos.cut_thru.enable = cut_thru; + + return 0; +} + +static void am65_cpsw_port_iet_rx_enable(struct am65_cpsw_port *port, bool enable) +{ + u32 val; + + val = readl(port->port_base + AM65_CPSW_PN_REG_CTL); + if (enable) + val |= AM65_CPSW_PN_CTL_IET_PORT_EN; + else + val &= ~AM65_CPSW_PN_CTL_IET_PORT_EN; + + writel(val, port->port_base + AM65_CPSW_PN_REG_CTL); + am65_cpsw_iet_common_enable(port->common); +} + +static void am65_cpsw_port_iet_tx_enable(struct am65_cpsw_port *port, bool enable) +{ + u32 val; + + val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL); + if (enable) + val |= AM65_CPSW_PN_IET_MAC_PENABLE; + else + val &= ~AM65_CPSW_PN_IET_MAC_PENABLE; + + writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL); +} + +static int am65_cpsw_get_mm(struct net_device *ndev, struct ethtool_mm_state *state) +{ + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + struct am65_cpsw_ndev_priv *priv = netdev_priv(ndev); + u32 port_ctrl, iet_ctrl, iet_status; + u32 add_frag_size; + + if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS)) + return -EOPNOTSUPP; + + mutex_lock(&priv->mm_lock); + + iet_ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL); + port_ctrl = readl(port->port_base + AM65_CPSW_PN_REG_CTL); + + state->tx_enabled = !!(iet_ctrl & AM65_CPSW_PN_IET_MAC_PENABLE); + state->pmac_enabled = !!(port_ctrl & AM65_CPSW_PN_CTL_IET_PORT_EN); + + iet_status = readl(port->port_base + AM65_CPSW_PN_REG_IET_STATUS); + + if (iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY) + state->verify_status = ETHTOOL_MM_VERIFY_STATUS_DISABLED; + else if (iet_status & AM65_CPSW_PN_MAC_VERIFIED) + state->verify_status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED; + else if (iet_status & AM65_CPSW_PN_MAC_VERIFY_FAIL) + state->verify_status = ETHTOOL_MM_VERIFY_STATUS_FAILED; + else + state->verify_status = ETHTOOL_MM_VERIFY_STATUS_UNKNOWN; + + add_frag_size = AM65_CPSW_PN_IET_MAC_GET_ADDFRAGSIZE(iet_ctrl); + state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(add_frag_size); + + /* Errata i2208: RX min fragment size cannot be less than 124 */ + state->rx_min_frag_size = 124; + + /* FPE active if common tx_enabled and verification success or disabled (forced) */ + state->tx_active = state->tx_enabled && + (state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED || + state->verify_status == ETHTOOL_MM_VERIFY_STATUS_DISABLED); + state->verify_enabled = !(iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY); + + state->verify_time = port->qos.iet.verify_time_ms; + + /* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime + * variable has a range between 1 and 128 ms inclusive. Limit to that. + */ + state->max_verify_time = 128; + + mutex_unlock(&priv->mm_lock); + + return 0; +} + +static int am65_cpsw_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg, + struct netlink_ext_ack *extack) +{ + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + struct am65_cpsw_ndev_priv *priv = netdev_priv(ndev); + struct am65_cpsw_iet *iet = &port->qos.iet; + u32 val, add_frag_size; + int err; + + if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS)) + return -EOPNOTSUPP; + + err = ethtool_mm_frag_size_min_to_add(cfg->tx_min_frag_size, &add_frag_size, extack); + if (err) + return err; + + mutex_lock(&priv->mm_lock); + + if (cfg->pmac_enabled) { + /* change TX & RX FIFO MAX_BLKS as per TRM recommendation */ + if (!iet->original_max_blks) + iet->original_max_blks = readl(port->port_base + AM65_CPSW_PN_REG_MAX_BLKS); + + writel(AM65_CPSW_PN_TX_RX_MAX_BLKS_IET, + port->port_base + AM65_CPSW_PN_REG_MAX_BLKS); + } else if (iet->original_max_blks) { + /* restore RX & TX FIFO MAX_BLKS */ + writel(iet->original_max_blks, + port->port_base + AM65_CPSW_PN_REG_MAX_BLKS); + } + + am65_cpsw_port_iet_rx_enable(port, cfg->pmac_enabled); + am65_cpsw_port_iet_tx_enable(port, cfg->tx_enabled); + + val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL); + if (cfg->verify_enabled) { + val &= ~AM65_CPSW_PN_IET_MAC_DISABLEVERIFY; + /* Reset Verify state machine. Verification won't start here. + * Verification will be done once link-up. + */ + val |= AM65_CPSW_PN_IET_MAC_LINKFAIL; + } else { + val |= AM65_CPSW_PN_IET_MAC_DISABLEVERIFY; + /* Clear LINKFAIL to allow verify/response packets */ + val &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL; + } + + val &= ~AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK; + val |= AM65_CPSW_PN_IET_MAC_SET_ADDFRAGSIZE(add_frag_size); + writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL); + + /* verify_timeout_count can only be set at valid link */ + port->qos.iet.verify_time_ms = cfg->verify_time; + + /* enable/disable preemption based on link status */ + am65_cpsw_iet_commit_preemptible_tcs(port); + + mutex_unlock(&priv->mm_lock); + + return 0; +} + +static void am65_cpsw_get_mm_stats(struct net_device *ndev, + struct ethtool_mm_stats *s) +{ + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + void __iomem *base = port->stat_base; + + s->MACMergeFrameAssOkCount = readl(base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_OK); + s->MACMergeFrameAssErrorCount = readl(base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_ERROR); + s->MACMergeFrameSmdErrorCount = readl(base + AM65_CPSW_STATN_IET_RX_SMD_ERROR); + /* CPSW Functional Spec states: + * "The IET stat aMACMergeFragCountRx is derived by adding the + * Receive Assembly Error count to this value. i.e. AM65_CPSW_STATN_IET_RX_FRAG" + */ + s->MACMergeFragCountRx = readl(base + AM65_CPSW_STATN_IET_RX_FRAG) + s->MACMergeFrameAssErrorCount; + s->MACMergeFragCountTx = readl(base + AM65_CPSW_STATN_IET_TX_FRAG); + s->MACMergeHoldCount = readl(base + AM65_CPSW_STATN_IET_TX_HOLD); +} + +static int am65_cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct am65_cpsw_common *common = am65_ndev_to_common(ndev); + struct am65_cpsw_tx_chn *tx_chn; + + tx_chn = &common->tx_chns[0]; + + coal->rx_coalesce_usecs = common->rx_pace_timeout / 1000; + coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000; + + return 0; +} + +static int am65_cpsw_get_per_queue_coalesce(struct net_device *ndev, u32 queue, + struct ethtool_coalesce *coal) +{ + struct am65_cpsw_common *common = am65_ndev_to_common(ndev); + struct am65_cpsw_tx_chn *tx_chn; + + if (queue >= AM65_CPSW_MAX_TX_QUEUES) + return -EINVAL; + + tx_chn = &common->tx_chns[queue]; + + coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000; + + return 0; +} + +static int am65_cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct am65_cpsw_common *common = am65_ndev_to_common(ndev); + struct am65_cpsw_tx_chn *tx_chn; + + tx_chn = &common->tx_chns[0]; + + if (coal->rx_coalesce_usecs && coal->rx_coalesce_usecs < 20) + return -EINVAL; + + if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20) + return -EINVAL; + + common->rx_pace_timeout = coal->rx_coalesce_usecs * 1000; + tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000; + + return 0; +} + +static int am65_cpsw_set_per_queue_coalesce(struct net_device *ndev, u32 queue, + struct ethtool_coalesce *coal) +{ + struct am65_cpsw_common *common = am65_ndev_to_common(ndev); + struct am65_cpsw_tx_chn *tx_chn; + + if (queue >= AM65_CPSW_MAX_TX_QUEUES) + return -EINVAL; + + tx_chn = &common->tx_chns[queue]; + + if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20) { + dev_info(common->dev, "defaulting to min value of 20us for tx-usecs for tx-%u\n", + queue); + coal->tx_coalesce_usecs = 20; + } + + tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000; return 0; } @@ -729,9 +1021,15 @@ .get_sset_count = am65_cpsw_get_sset_count, .get_strings = am65_cpsw_get_strings, .get_ethtool_stats = am65_cpsw_get_ethtool_stats, + .get_eth_mac_stats = am65_cpsw_get_eth_mac_stats, .get_ts_info = am65_cpsw_get_ethtool_ts_info, .get_priv_flags = am65_cpsw_get_ethtool_priv_flags, .set_priv_flags = am65_cpsw_set_ethtool_priv_flags, + .supported_coalesce_params = ETHTOOL_COALESCE_USECS, + .get_coalesce = am65_cpsw_get_coalesce, + .set_coalesce = am65_cpsw_set_coalesce, + .get_per_queue_coalesce = am65_cpsw_get_per_queue_coalesce, + .set_per_queue_coalesce = am65_cpsw_set_per_queue_coalesce, .get_link = ethtool_op_get_link, .get_link_ksettings = am65_cpsw_get_link_ksettings, @@ -743,4 +1041,7 @@ .get_eee = am65_cpsw_get_eee, .set_eee = am65_cpsw_set_eee, .nway_reset = am65_cpsw_nway_reset, + .get_mm = am65_cpsw_get_mm, + .set_mm = am65_cpsw_set_mm, + .get_mm_stats = am65_cpsw_get_mm_stats, }; diff -Naur --no-dereference a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c 2024-07-07 20:37:34.668306669 -0400 @@ -5,6 +5,7 @@ * */ +#include #include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #include #include "cpsw_ale.h" @@ -101,6 +103,12 @@ #define AM65_CPSW_PN_TS_CTL_TX_HOST_TS_EN BIT(11) #define AM65_CPSW_PN_TS_CTL_MSG_TYPE_EN_SHIFT 16 +#define AM65_CPSW_PN_TS_CTL_RX_ANX_F_EN BIT(0) +#define AM65_CPSW_PN_TS_CTL_RX_VLAN_LT1_EN BIT(1) +#define AM65_CPSW_PN_TS_CTL_RX_VLAN_LT2_EN BIT(2) +#define AM65_CPSW_PN_TS_CTL_RX_ANX_D_EN BIT(3) +#define AM65_CPSW_PN_TS_CTL_RX_ANX_E_EN BIT(9) + /* AM65_CPSW_PORTN_REG_TS_SEQ_LTYPE_REG register fields */ #define AM65_CPSW_PN_TS_SEQ_ID_OFFSET_SHIFT 16 @@ -124,6 +132,11 @@ AM65_CPSW_PN_TS_CTL_TX_ANX_E_EN | \ AM65_CPSW_PN_TS_CTL_TX_ANX_F_EN) +#define AM65_CPSW_TS_RX_ANX_ALL_EN \ + (AM65_CPSW_PN_TS_CTL_RX_ANX_D_EN | \ + AM65_CPSW_PN_TS_CTL_RX_ANX_E_EN | \ + AM65_CPSW_PN_TS_CTL_RX_ANX_F_EN) + #define AM65_CPSW_ALE_AGEOUT_DEFAULT 30 /* Number of TX/RX descriptors */ #define AM65_CPSW_MAX_TX_DESC 500 @@ -136,6 +149,20 @@ NETIF_MSG_IFUP | NETIF_MSG_PROBE | NETIF_MSG_IFDOWN | \ NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) +#define AM65_CPSW_DEFAULT_TX_CHNS 8 + +/* CPPI streaming packet interface */ +#define AM65_CPSW_CPPI_TX_FLOW_ID 0x3FFF +#define AM65_CPSW_CPPI_TX_PKT_TYPE 0x7 + +/* XDP */ +#define AM65_CPSW_XDP_CONSUMED 2 +#define AM65_CPSW_XDP_REDIRECT 1 +#define AM65_CPSW_XDP_PASS 0 + +/* Include headroom compatible with both skb and xdpf */ +#define AM65_CPSW_HEADROOM (max(NET_SKB_PAD, XDP_PACKET_HEADROOM) + NET_IP_ALIGN) + static void am65_cpsw_port_set_sl_mac(struct am65_cpsw_port *slave, const u8 *dev_addr) { @@ -303,12 +330,11 @@ } static int am65_cpsw_nuss_rx_push(struct am65_cpsw_common *common, - struct sk_buff *skb) + struct page *page) { struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns; struct cppi5_host_desc_t *desc_rx; struct device *dev = common->dev; - u32 pkt_len = skb_tailroom(skb); dma_addr_t desc_dma; dma_addr_t buf_dma; void *swdata; @@ -320,20 +346,22 @@ } desc_dma = k3_cppi_desc_pool_virt2dma(rx_chn->desc_pool, desc_rx); - buf_dma = dma_map_single(rx_chn->dma_dev, skb->data, pkt_len, - DMA_FROM_DEVICE); + buf_dma = dma_map_single(rx_chn->dma_dev, + page_address(page) + AM65_CPSW_HEADROOM, + AM65_CPSW_MAX_PACKET_SIZE, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(rx_chn->dma_dev, buf_dma))) { k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); - dev_err(dev, "Failed to map rx skb buffer\n"); + dev_err(dev, "Failed to map rx buffer\n"); return -EINVAL; } cppi5_hdesc_init(desc_rx, CPPI5_INFO0_HDESC_EPIB_PRESENT, AM65_CPSW_NAV_PS_DATA_SIZE); k3_udma_glue_rx_dma_to_cppi5_addr(rx_chn->rx_chn, &buf_dma); - cppi5_hdesc_attach_buf(desc_rx, buf_dma, skb_tailroom(skb), buf_dma, skb_tailroom(skb)); + cppi5_hdesc_attach_buf(desc_rx, buf_dma, AM65_CPSW_MAX_PACKET_SIZE, + buf_dma, AM65_CPSW_MAX_PACKET_SIZE); swdata = cppi5_hdesc_get_swdata(desc_rx); - *((void **)swdata) = skb; + *((void **)swdata) = page_address(page); return k3_udma_glue_push_rx_chn(rx_chn->rx_chn, 0, desc_rx, desc_dma); } @@ -367,12 +395,215 @@ static void am65_cpsw_init_port_switch_ale(struct am65_cpsw_port *port); static void am65_cpsw_init_port_emac_ale(struct am65_cpsw_port *port); +static void am65_cpsw_destroy_xdp_rxqs(struct am65_cpsw_common *common) +{ + struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns; + struct xdp_rxq_info *rxq; + int i; + + for (i = 0; i < common->port_num; i++) { + if (!common->ports[i].ndev) + continue; + + rxq = &common->ports[i].xdp_rxq; + + if (xdp_rxq_info_is_reg(rxq)) + xdp_rxq_info_unreg(rxq); + } + + if (rx_chn->page_pool) { + page_pool_destroy(rx_chn->page_pool); + rx_chn->page_pool = NULL; + } +} + +static int am65_cpsw_create_xdp_rxqs(struct am65_cpsw_common *common) +{ + struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns; + struct page_pool_params pp_params = { + .flags = PP_FLAG_DMA_MAP, + .order = 0, + .pool_size = AM65_CPSW_MAX_RX_DESC, + .nid = dev_to_node(common->dev), + .dev = common->dev, + .dma_dir = DMA_BIDIRECTIONAL, + .napi = &common->napi_rx, + }; + struct xdp_rxq_info *rxq; + struct page_pool *pool; + int i, ret; + + pool = page_pool_create(&pp_params); + if (IS_ERR(pool)) + return PTR_ERR(pool); + + rx_chn->page_pool = pool; + + for (i = 0; i < common->port_num; i++) { + if (!common->ports[i].ndev) + continue; + + rxq = &common->ports[i].xdp_rxq; + + ret = xdp_rxq_info_reg(rxq, common->ports[i].ndev, i, 0); + if (ret) + goto err; + + ret = xdp_rxq_info_reg_mem_model(rxq, MEM_TYPE_PAGE_POOL, pool); + if (ret) + goto err; + } + + return 0; + +err: + am65_cpsw_destroy_xdp_rxqs(common); + return ret; +} + +static int am65_cpsw_nuss_desc_idx(struct k3_cppi_desc_pool *desc_pool, + void *desc, + unsigned char dsize_log2) +{ + void *pool_addr = k3_cppi_desc_pool_cpuaddr(desc_pool); + + return (desc - pool_addr) >> dsize_log2; +} + +static void am65_cpsw_nuss_set_buf_type(struct am65_cpsw_tx_chn *tx_chn, + struct cppi5_host_desc_t *desc, + enum am65_cpsw_tx_buf_type buf_type) +{ + int desc_idx; + + desc_idx = am65_cpsw_nuss_desc_idx(tx_chn->desc_pool, desc, + tx_chn->dsize_log2); + k3_cppi_desc_pool_desc_info_set(tx_chn->desc_pool, desc_idx, + (void *)buf_type); +} + +static enum am65_cpsw_tx_buf_type am65_cpsw_nuss_buf_type(struct am65_cpsw_tx_chn *tx_chn, + dma_addr_t desc_dma) +{ + struct cppi5_host_desc_t *desc_tx; + int desc_idx; + + desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma); + desc_idx = am65_cpsw_nuss_desc_idx(tx_chn->desc_pool, desc_tx, + tx_chn->dsize_log2); + + return (enum am65_cpsw_tx_buf_type)k3_cppi_desc_pool_desc_info(tx_chn->desc_pool, + desc_idx); +} + +static inline void am65_cpsw_put_page(struct am65_cpsw_rx_chn *rx_chn, + struct page *page, + bool allow_direct, + int desc_idx) +{ + page_pool_put_full_page(rx_chn->page_pool, page, allow_direct); + rx_chn->pages[desc_idx] = NULL; +} + +static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma) +{ + struct am65_cpsw_rx_chn *rx_chn = data; + struct cppi5_host_desc_t *desc_rx; + dma_addr_t buf_dma; + u32 buf_dma_len; + void *page_addr; + void **swdata; + int desc_idx; + + desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); + swdata = cppi5_hdesc_get_swdata(desc_rx); + page_addr = *swdata; + cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); + k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma); + dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE); + k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); + + desc_idx = am65_cpsw_nuss_desc_idx(rx_chn->desc_pool, desc_rx, + rx_chn->dsize_log2); + am65_cpsw_put_page(rx_chn, virt_to_page(page_addr), false, desc_idx); +} + +static void am65_cpsw_nuss_xmit_free(struct am65_cpsw_tx_chn *tx_chn, + struct cppi5_host_desc_t *desc) +{ + struct cppi5_host_desc_t *first_desc, *next_desc; + dma_addr_t buf_dma, next_desc_dma; + u32 buf_dma_len; + + first_desc = desc; + next_desc = first_desc; + + cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); + + dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len, DMA_TO_DEVICE); + + next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); + while (next_desc_dma) { + next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, + next_desc_dma); + cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); + + dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len, + DMA_TO_DEVICE); + + next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); + + k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); + } + + k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc); +} + +static void am65_cpsw_nuss_tx_cleanup(void *data, dma_addr_t desc_dma) +{ + struct am65_cpsw_tx_chn *tx_chn = data; + struct cppi5_host_desc_t *desc_tx; + struct sk_buff *skb; + void **swdata; + + desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma); + swdata = cppi5_hdesc_get_swdata(desc_tx); + skb = *(swdata); + am65_cpsw_nuss_xmit_free(tx_chn, desc_tx); + + dev_kfree_skb_any(skb); +} + +static struct sk_buff *am65_cpsw_build_skb(void *page_addr, + struct net_device *ndev, + unsigned int len) +{ + struct sk_buff *skb; + + len += AM65_CPSW_HEADROOM; + + skb = build_skb(page_addr, len); + if (unlikely(!skb)) + return NULL; + + skb_reserve(skb, AM65_CPSW_HEADROOM); + skb->dev = ndev; + + return skb; +} + static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common) { struct am65_cpsw_host *host_p = am65_common_get_host(common); - int port_idx, i, ret; - struct sk_buff *skb; + struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns; + struct am65_cpsw_tx_chn *tx_chn = common->tx_chns; + int port_idx, i, ret, tx; u32 val, port_mask; + struct page *page; if (common->usage_count) return 0; @@ -432,49 +663,81 @@ am65_cpsw_qos_tx_p0_rate_init(common); - for (i = 0; i < common->rx_chns.descs_num; i++) { - skb = __netdev_alloc_skb_ip_align(NULL, - AM65_CPSW_MAX_PACKET_SIZE, - GFP_KERNEL); - if (!skb) { - dev_err(common->dev, "cannot allocate skb\n"); - return -ENOMEM; + ret = am65_cpsw_create_xdp_rxqs(common); + if (ret) { + dev_err(common->dev, "Failed to create XDP rx queues\n"); + return ret; + } + + for (i = 0; i < rx_chn->descs_num; i++) { + page = page_pool_dev_alloc_pages(rx_chn->page_pool); + if (!page) { + ret = -ENOMEM; + if (i) + goto fail_rx; + + return ret; } + rx_chn->pages[i] = page; - ret = am65_cpsw_nuss_rx_push(common, skb); + ret = am65_cpsw_nuss_rx_push(common, page); if (ret < 0) { dev_err(common->dev, - "cannot submit skb to channel rx, error %d\n", + "cannot submit page to channel rx: %d\n", ret); - kfree_skb(skb); + am65_cpsw_put_page(rx_chn, page, false, i); + if (i) + goto fail_rx; + return ret; } - kmemleak_not_leak(skb); } - k3_udma_glue_enable_rx_chn(common->rx_chns.rx_chn); - for (i = 0; i < common->tx_ch_num; i++) { - ret = k3_udma_glue_enable_tx_chn(common->tx_chns[i].tx_chn); - if (ret) - return ret; - napi_enable(&common->tx_chns[i].napi_tx); + ret = k3_udma_glue_enable_rx_chn(rx_chn->rx_chn); + if (ret) { + dev_err(common->dev, "couldn't enable rx chn: %d\n", ret); + goto fail_rx; + } + + for (tx = 0; tx < common->tx_ch_num; tx++) { + ret = k3_udma_glue_enable_tx_chn(tx_chn[tx].tx_chn); + if (ret) { + dev_err(common->dev, "couldn't enable tx chn %d: %d\n", + tx, ret); + tx--; + goto fail_tx; + } + napi_enable(&tx_chn[tx].napi_tx); } napi_enable(&common->napi_rx); if (common->rx_irq_disabled) { common->rx_irq_disabled = false; - enable_irq(common->rx_chns.irq); + enable_irq(rx_chn->irq); } dev_dbg(common->dev, "cpsw_nuss started\n"); return 0; -} -static void am65_cpsw_nuss_tx_cleanup(void *data, dma_addr_t desc_dma); -static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma); +fail_tx: + while (tx >= 0) { + napi_disable(&tx_chn[tx].napi_tx); + k3_udma_glue_disable_tx_chn(tx_chn[tx].tx_chn); + tx--; + } + + k3_udma_glue_disable_rx_chn(rx_chn->rx_chn); + +fail_rx: + k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, 0, rx_chn, + am65_cpsw_nuss_rx_cleanup, 0); + return ret; +} static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common) { + struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns; + struct am65_cpsw_tx_chn *tx_chn = common->tx_chns; int i; if (common->usage_count != 1) @@ -490,24 +753,25 @@ reinit_completion(&common->tdown_complete); for (i = 0; i < common->tx_ch_num; i++) - k3_udma_glue_tdown_tx_chn(common->tx_chns[i].tx_chn, false); + k3_udma_glue_tdown_tx_chn(tx_chn[i].tx_chn, false); i = wait_for_completion_timeout(&common->tdown_complete, msecs_to_jiffies(1000)); if (!i) dev_err(common->dev, "tx timeout\n"); - for (i = 0; i < common->tx_ch_num; i++) - napi_disable(&common->tx_chns[i].napi_tx); + for (i = 0; i < common->tx_ch_num; i++) { + napi_disable(&tx_chn[i].napi_tx); + hrtimer_cancel(&tx_chn[i].tx_hrtimer); + } for (i = 0; i < common->tx_ch_num; i++) { - k3_udma_glue_reset_tx_chn(common->tx_chns[i].tx_chn, - &common->tx_chns[i], + k3_udma_glue_reset_tx_chn(tx_chn[i].tx_chn, &tx_chn[i], am65_cpsw_nuss_tx_cleanup); - k3_udma_glue_disable_tx_chn(common->tx_chns[i].tx_chn); + k3_udma_glue_disable_tx_chn(tx_chn[i].tx_chn); } reinit_completion(&common->tdown_complete); - k3_udma_glue_tdown_rx_chn(common->rx_chns.rx_chn, true); + k3_udma_glue_tdown_rx_chn(rx_chn->rx_chn, true); if (common->pdata.quirks & AM64_CPSW_QUIRK_DMA_RX_TDOWN_IRQ) { i = wait_for_completion_timeout(&common->tdown_complete, msecs_to_jiffies(1000)); @@ -516,19 +780,25 @@ } napi_disable(&common->napi_rx); + hrtimer_cancel(&common->rx_hrtimer); for (i = 0; i < AM65_CPSW_MAX_RX_FLOWS; i++) - k3_udma_glue_reset_rx_chn(common->rx_chns.rx_chn, i, - &common->rx_chns, + k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, i, rx_chn, am65_cpsw_nuss_rx_cleanup, !!i); - k3_udma_glue_disable_rx_chn(common->rx_chns.rx_chn); + k3_udma_glue_disable_rx_chn(rx_chn->rx_chn); cpsw_ale_stop(common->ale); writel(0, common->cpsw_base + AM65_CPSW_REG_CTL); writel(0, common->cpsw_base + AM65_CPSW_REG_STAT_PORT_EN); + for (i = 0; i < rx_chn->descs_num; i++) { + if (rx_chn->pages[i]) + am65_cpsw_put_page(rx_chn, rx_chn->pages[i], false, i); + } + am65_cpsw_destroy_xdp_rxqs(common); + dev_dbg(common->dev, "cpsw_nuss stopped\n"); return 0; } @@ -545,6 +815,7 @@ phylink_disconnect_phy(port->slave.phylink); + am65_cpsw_qos_cut_thru_cleanup(port); ret = am65_cpsw_nuss_common_stop(common); if (ret) return ret; @@ -633,6 +904,7 @@ /* restore vlan configurations */ vlan_for_each(ndev, cpsw_restore_vlans, port); + am65_cpsw_qos_cut_thru_init(port); phylink_start(port->slave.phylink); return 0; @@ -646,37 +918,149 @@ return ret; } -static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma) +static int am65_cpsw_xdp_tx_frame(struct net_device *ndev, + struct am65_cpsw_tx_chn *tx_chn, + struct xdp_frame *xdpf, + enum am65_cpsw_tx_buf_type buf_type) { - struct am65_cpsw_rx_chn *rx_chn = data; - struct cppi5_host_desc_t *desc_rx; - struct sk_buff *skb; - dma_addr_t buf_dma; - u32 buf_dma_len; + struct am65_cpsw_common *common = am65_ndev_to_common(ndev); + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + struct cppi5_host_desc_t *host_desc; + struct netdev_queue *netif_txq; + dma_addr_t dma_desc, dma_buf; + u32 pkt_len = xdpf->len; void **swdata; + int ret; - desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); - swdata = cppi5_hdesc_get_swdata(desc_rx); - skb = *swdata; - cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); - k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma); + host_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool); + if (unlikely(!host_desc)) { + ndev->stats.tx_dropped++; + return -ENOMEM; + } - dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE); - k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); + am65_cpsw_nuss_set_buf_type(tx_chn, host_desc, buf_type); - dev_kfree_skb_any(skb); + dma_buf = dma_map_single(tx_chn->dma_dev, xdpf->data, + pkt_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(tx_chn->dma_dev, dma_buf))) { + ndev->stats.tx_dropped++; + ret = -ENOMEM; + goto pool_free; + } + + cppi5_hdesc_init(host_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT, + AM65_CPSW_NAV_PS_DATA_SIZE); + cppi5_hdesc_set_pkttype(host_desc, AM65_CPSW_CPPI_TX_PKT_TYPE); + cppi5_hdesc_set_pktlen(host_desc, pkt_len); + cppi5_desc_set_pktids(&host_desc->hdr, 0, AM65_CPSW_CPPI_TX_FLOW_ID); + cppi5_desc_set_tags_ids(&host_desc->hdr, 0, port->port_id); + + k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &dma_buf); + cppi5_hdesc_attach_buf(host_desc, dma_buf, pkt_len, dma_buf, pkt_len); + + swdata = cppi5_hdesc_get_swdata(host_desc); + *(swdata) = xdpf; + + /* Report BQL before sending the packet */ + netif_txq = netdev_get_tx_queue(ndev, tx_chn->id); + netdev_tx_sent_queue(netif_txq, pkt_len); + + dma_desc = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, host_desc); + if (AM65_CPSW_IS_CPSW2G(common)) { + ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, host_desc, + dma_desc); + } else { + spin_lock_bh(&tx_chn->lock); + ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, host_desc, + dma_desc); + spin_unlock_bh(&tx_chn->lock); + } + if (ret) { + /* Inform BQL */ + netdev_tx_completed_queue(netif_txq, 1, pkt_len); + ndev->stats.tx_errors++; + goto dma_unmap; + } + + return 0; + +dma_unmap: + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &dma_buf); + dma_unmap_single(tx_chn->dma_dev, dma_buf, pkt_len, DMA_TO_DEVICE); +pool_free: + k3_cppi_desc_pool_free(tx_chn->desc_pool, host_desc); + return ret; } -static void am65_cpsw_nuss_rx_ts(struct sk_buff *skb, u32 *psdata) +static int am65_cpsw_run_xdp(struct am65_cpsw_common *common, + struct am65_cpsw_port *port, + struct xdp_buff *xdp, + int desc_idx, int cpu, int *len) { - struct skb_shared_hwtstamps *ssh; - u64 ns; + struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns; + struct net_device *ndev = port->ndev; + int ret = AM65_CPSW_XDP_CONSUMED; + struct am65_cpsw_tx_chn *tx_chn; + struct netdev_queue *netif_txq; + struct xdp_frame *xdpf; + struct bpf_prog *prog; + struct page *page; + u32 act; + + prog = READ_ONCE(port->xdp_prog); + if (!prog) + return AM65_CPSW_XDP_PASS; + + act = bpf_prog_run_xdp(prog, xdp); + /* XDP prog might have changed packet data and boundaries */ + *len = xdp->data_end - xdp->data; + + switch (act) { + case XDP_PASS: + ret = AM65_CPSW_XDP_PASS; + goto out; + case XDP_TX: + tx_chn = &common->tx_chns[cpu % AM65_CPSW_MAX_TX_QUEUES]; + netif_txq = netdev_get_tx_queue(ndev, tx_chn->id); - ns = ((u64)psdata[1] << 32) | psdata[0]; + xdpf = xdp_convert_buff_to_frame(xdp); + if (unlikely(!xdpf)) + break; + + __netif_tx_lock(netif_txq, cpu); + ret = am65_cpsw_xdp_tx_frame(ndev, tx_chn, xdpf, + AM65_CPSW_TX_BUF_TYPE_XDP_TX); + __netif_tx_unlock(netif_txq); + if (ret) + break; + + ndev->stats.rx_bytes += *len; + ndev->stats.rx_packets++; + ret = AM65_CPSW_XDP_CONSUMED; + goto out; + case XDP_REDIRECT: + if (unlikely(xdp_do_redirect(ndev, xdp, prog))) + break; - ssh = skb_hwtstamps(skb); - memset(ssh, 0, sizeof(*ssh)); - ssh->hwtstamp = ns_to_ktime(ns); + ndev->stats.rx_bytes += *len; + ndev->stats.rx_packets++; + ret = AM65_CPSW_XDP_REDIRECT; + goto out; + default: + bpf_warn_invalid_xdp_action(ndev, prog, act); + fallthrough; + case XDP_ABORTED: + trace_xdp_exception(ndev, prog, act); + fallthrough; + case XDP_DROP: + ndev->stats.rx_dropped++; + } + + page = virt_to_head_page(xdp->data); + am65_cpsw_put_page(rx_chn, page, true, desc_idx); + +out: + return ret; } /* RX psdata[2] word format - checksum information */ @@ -713,7 +1097,7 @@ } static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_common *common, - u32 flow_idx) + u32 flow_idx, int cpu) { struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns; u32 buf_dma_len, pkt_len, port_id = 0, csum_info; @@ -721,13 +1105,16 @@ struct am65_cpsw_ndev_stats *stats; struct cppi5_host_desc_t *desc_rx; struct device *dev = common->dev; - struct sk_buff *skb, *new_skb; + struct page *page, *new_page; dma_addr_t desc_dma, buf_dma; struct am65_cpsw_port *port; + int headroom, desc_idx, ret; struct net_device *ndev; + struct sk_buff *skb; + struct xdp_buff xdp; + void *page_addr; void **swdata; u32 *psdata; - int ret = 0; ret = k3_udma_glue_pop_rx_chn(rx_chn->rx_chn, flow_idx, &desc_dma); if (ret) { @@ -748,7 +1135,8 @@ __func__, flow_idx, &desc_dma); swdata = cppi5_hdesc_get_swdata(desc_rx); - skb = *swdata; + page_addr = *swdata; + page = virt_to_page(page_addr); cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma); pkt_len = cppi5_hdesc_get_pktlen(desc_rx); @@ -756,12 +1144,7 @@ dev_dbg(dev, "%s rx port_id:%d\n", __func__, port_id); port = am65_common_get_port(common, port_id); ndev = port->ndev; - skb->dev = ndev; - psdata = cppi5_hdesc_get_psdata(desc_rx); - /* add RX timestamp */ - if (port->rx_ts_enabled) - am65_cpsw_nuss_rx_ts(skb, psdata); csum_info = psdata[2]; dev_dbg(dev, "%s rx csum_info:%#x\n", __func__, csum_info); @@ -769,36 +1152,64 @@ k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); - new_skb = netdev_alloc_skb_ip_align(ndev, AM65_CPSW_MAX_PACKET_SIZE); - if (new_skb) { - ndev_priv = netdev_priv(ndev); - am65_cpsw_nuss_set_offload_fwd_mark(skb, ndev_priv->offload_fwd_mark); - skb_put(skb, pkt_len); - skb->protocol = eth_type_trans(skb, ndev); - am65_cpsw_nuss_rx_csum(skb, csum_info); - napi_gro_receive(&common->napi_rx, skb); - - stats = this_cpu_ptr(ndev_priv->stats); - - u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += pkt_len; - u64_stats_update_end(&stats->syncp); - kmemleak_not_leak(new_skb); - } else { - ndev->stats.rx_dropped++; - new_skb = skb; + desc_idx = am65_cpsw_nuss_desc_idx(rx_chn->desc_pool, desc_rx, + rx_chn->dsize_log2); + + skb = am65_cpsw_build_skb(page_addr, ndev, + AM65_CPSW_MAX_PACKET_SIZE); + if (unlikely(!skb)) { + new_page = page; + goto requeue; + } + + if (port->xdp_prog) { + xdp_init_buff(&xdp, AM65_CPSW_MAX_PACKET_SIZE, &port->xdp_rxq); + + xdp_prepare_buff(&xdp, page_addr, skb_headroom(skb), + pkt_len, false); + + ret = am65_cpsw_run_xdp(common, port, &xdp, desc_idx, + cpu, &pkt_len); + if (ret != AM65_CPSW_XDP_PASS) + return ret; + + /* Compute additional headroom to be reserved */ + headroom = (xdp.data - xdp.data_hard_start) - skb_headroom(skb); + skb_reserve(skb, headroom); } + ndev_priv = netdev_priv(ndev); + am65_cpsw_nuss_set_offload_fwd_mark(skb, ndev_priv->offload_fwd_mark); + skb_put(skb, pkt_len); + if (port->rx_ts_enabled) + am65_cpts_rx_timestamp(common->cpts, skb); + skb_mark_for_recycle(skb); + skb->protocol = eth_type_trans(skb, ndev); + am65_cpsw_nuss_rx_csum(skb, csum_info); + napi_gro_receive(&common->napi_rx, skb); + + stats = this_cpu_ptr(ndev_priv->stats); + + u64_stats_update_begin(&stats->syncp); + stats->rx_packets++; + stats->rx_bytes += pkt_len; + u64_stats_update_end(&stats->syncp); + + new_page = page_pool_dev_alloc_pages(rx_chn->page_pool); + if (unlikely(!new_page)) + return -ENOMEM; + rx_chn->pages[desc_idx] = new_page; + if (netif_dormant(ndev)) { - dev_kfree_skb_any(new_skb); + am65_cpsw_put_page(rx_chn, new_page, true, desc_idx); ndev->stats.rx_dropped++; return 0; } - ret = am65_cpsw_nuss_rx_push(common, new_skb); +requeue: + ret = am65_cpsw_nuss_rx_push(common, new_page); if (WARN_ON(ret < 0)) { - dev_kfree_skb_any(new_skb); + am65_cpsw_put_page(rx_chn, new_page, true, desc_idx); ndev->stats.rx_errors++; ndev->stats.rx_dropped++; } @@ -806,10 +1217,21 @@ return ret; } +static enum hrtimer_restart am65_cpsw_nuss_rx_timer_callback(struct hrtimer *timer) +{ + struct am65_cpsw_common *common = + container_of(timer, struct am65_cpsw_common, rx_hrtimer); + + enable_irq(common->rx_chns.irq); + return HRTIMER_NORESTART; +} + static int am65_cpsw_nuss_rx_poll(struct napi_struct *napi_rx, int budget) { struct am65_cpsw_common *common = am65_cpsw_napi_to_common(napi_rx); int flow = AM65_CPSW_MAX_RX_FLOWS; + int cpu = smp_processor_id(); + bool xdp_redirect = false; int cur_budget, ret; int num_rx = 0; @@ -818,9 +1240,12 @@ cur_budget = budget - num_rx; while (cur_budget--) { - ret = am65_cpsw_nuss_rx_packets(common, flow); - if (ret) + ret = am65_cpsw_nuss_rx_packets(common, flow, cpu); + if (ret) { + if (ret == AM65_CPSW_XDP_REDIRECT) + xdp_redirect = true; break; + } num_rx++; } @@ -828,71 +1253,30 @@ break; } + if (xdp_redirect) + xdp_do_flush(); + dev_dbg(common->dev, "%s num_rx:%d %d\n", __func__, num_rx, budget); if (num_rx < budget && napi_complete_done(napi_rx, num_rx)) { if (common->rx_irq_disabled) { common->rx_irq_disabled = false; - enable_irq(common->rx_chns.irq); + if (unlikely(common->rx_pace_timeout)) { + hrtimer_start(&common->rx_hrtimer, + ns_to_ktime(common->rx_pace_timeout), + HRTIMER_MODE_REL_PINNED); + } else { + enable_irq(common->rx_chns.irq); + } } } return num_rx; } -static void am65_cpsw_nuss_xmit_free(struct am65_cpsw_tx_chn *tx_chn, - struct cppi5_host_desc_t *desc) -{ - struct cppi5_host_desc_t *first_desc, *next_desc; - dma_addr_t buf_dma, next_desc_dma; - u32 buf_dma_len; - - first_desc = desc; - next_desc = first_desc; - - cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len); - k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); - - dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len, DMA_TO_DEVICE); - - next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc); - k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); - while (next_desc_dma) { - next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, - next_desc_dma); - cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len); - k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); - - dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len, - DMA_TO_DEVICE); - - next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc); - k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); - - k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); - } - - k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc); -} - -static void am65_cpsw_nuss_tx_cleanup(void *data, dma_addr_t desc_dma) -{ - struct am65_cpsw_tx_chn *tx_chn = data; - struct cppi5_host_desc_t *desc_tx; - struct sk_buff *skb; - void **swdata; - - desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma); - swdata = cppi5_hdesc_get_swdata(desc_tx); - skb = *(swdata); - am65_cpsw_nuss_xmit_free(tx_chn, desc_tx); - - dev_kfree_skb_any(skb); -} - static struct sk_buff * -am65_cpsw_nuss_tx_compl_packet(struct am65_cpsw_tx_chn *tx_chn, - dma_addr_t desc_dma) +am65_cpsw_nuss_tx_compl_packet_skb(struct am65_cpsw_tx_chn *tx_chn, + dma_addr_t desc_dma) { struct am65_cpsw_ndev_priv *ndev_priv; struct am65_cpsw_ndev_stats *stats; @@ -921,6 +1305,39 @@ return skb; } +static struct xdp_frame * +am65_cpsw_nuss_tx_compl_packet_xdp(struct am65_cpsw_common *common, + struct am65_cpsw_tx_chn *tx_chn, + dma_addr_t desc_dma, + struct net_device **ndev) +{ + struct am65_cpsw_ndev_priv *ndev_priv; + struct am65_cpsw_ndev_stats *stats; + struct cppi5_host_desc_t *desc_tx; + struct am65_cpsw_port *port; + struct xdp_frame *xdpf; + u32 port_id = 0; + void **swdata; + + desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma); + cppi5_desc_get_tags_ids(&desc_tx->hdr, NULL, &port_id); + swdata = cppi5_hdesc_get_swdata(desc_tx); + xdpf = *(swdata); + am65_cpsw_nuss_xmit_free(tx_chn, desc_tx); + + port = am65_common_get_port(common, port_id); + *ndev = port->ndev; + + ndev_priv = netdev_priv(*ndev); + stats = this_cpu_ptr(ndev_priv->stats); + u64_stats_update_begin(&stats->syncp); + stats->tx_packets++; + stats->tx_bytes += xdpf->len; + u64_stats_update_end(&stats->syncp); + + return xdpf; +} + static void am65_cpsw_nuss_tx_wake(struct am65_cpsw_tx_chn *tx_chn, struct net_device *ndev, struct netdev_queue *netif_txq) { @@ -939,13 +1356,15 @@ } static int am65_cpsw_nuss_tx_compl_packets(struct am65_cpsw_common *common, - int chn, unsigned int budget) + int chn, unsigned int budget, bool *tdown) { + enum am65_cpsw_tx_buf_type buf_type; struct device *dev = common->dev; struct am65_cpsw_tx_chn *tx_chn; struct netdev_queue *netif_txq; unsigned int total_bytes = 0; struct net_device *ndev; + struct xdp_frame *xdpf; struct sk_buff *skb; dma_addr_t desc_dma; int res, num_tx = 0; @@ -962,13 +1381,25 @@ if (cppi5_desc_is_tdcm(desc_dma)) { if (atomic_dec_and_test(&common->tdown_cnt)) complete(&common->tdown_complete); + *tdown = true; break; } - skb = am65_cpsw_nuss_tx_compl_packet(tx_chn, desc_dma); - total_bytes = skb->len; - ndev = skb->dev; - napi_consume_skb(skb, budget); + buf_type = am65_cpsw_nuss_buf_type(tx_chn, desc_dma); + if (buf_type == AM65_CPSW_TX_BUF_TYPE_SKB) { + skb = am65_cpsw_nuss_tx_compl_packet_skb(tx_chn, desc_dma); + ndev = skb->dev; + total_bytes = skb->len; + napi_consume_skb(skb, budget); + } else { + xdpf = am65_cpsw_nuss_tx_compl_packet_xdp(common, tx_chn, + desc_dma, &ndev); + total_bytes = xdpf->len; + if (buf_type == AM65_CPSW_TX_BUF_TYPE_XDP_TX) + xdp_return_frame_rx_napi(xdpf); + else + xdp_return_frame(xdpf); + } num_tx++; netif_txq = netdev_get_tx_queue(ndev, chn); @@ -984,13 +1415,15 @@ } static int am65_cpsw_nuss_tx_compl_packets_2g(struct am65_cpsw_common *common, - int chn, unsigned int budget) + int chn, unsigned int budget, bool *tdown) { + enum am65_cpsw_tx_buf_type buf_type; struct device *dev = common->dev; struct am65_cpsw_tx_chn *tx_chn; struct netdev_queue *netif_txq; unsigned int total_bytes = 0; struct net_device *ndev; + struct xdp_frame *xdpf; struct sk_buff *skb; dma_addr_t desc_dma; int res, num_tx = 0; @@ -1005,14 +1438,25 @@ if (cppi5_desc_is_tdcm(desc_dma)) { if (atomic_dec_and_test(&common->tdown_cnt)) complete(&common->tdown_complete); + *tdown = true; break; } - skb = am65_cpsw_nuss_tx_compl_packet(tx_chn, desc_dma); - - ndev = skb->dev; - total_bytes += skb->len; - napi_consume_skb(skb, budget); + buf_type = am65_cpsw_nuss_buf_type(tx_chn, desc_dma); + if (buf_type == AM65_CPSW_TX_BUF_TYPE_SKB) { + skb = am65_cpsw_nuss_tx_compl_packet_skb(tx_chn, desc_dma); + ndev = skb->dev; + total_bytes += skb->len; + napi_consume_skb(skb, budget); + } else { + xdpf = am65_cpsw_nuss_tx_compl_packet_xdp(common, tx_chn, + desc_dma, &ndev); + total_bytes += xdpf->len; + if (buf_type == AM65_CPSW_TX_BUF_TYPE_XDP_TX) + xdp_return_frame_rx_napi(xdpf); + else + xdp_return_frame(xdpf); + } num_tx++; } @@ -1030,21 +1474,40 @@ return num_tx; } +static enum hrtimer_restart am65_cpsw_nuss_tx_timer_callback(struct hrtimer *timer) +{ + struct am65_cpsw_tx_chn *tx_chns = + container_of(timer, struct am65_cpsw_tx_chn, tx_hrtimer); + + enable_irq(tx_chns->irq); + return HRTIMER_NORESTART; +} + static int am65_cpsw_nuss_tx_poll(struct napi_struct *napi_tx, int budget) { struct am65_cpsw_tx_chn *tx_chn = am65_cpsw_napi_to_tx_chn(napi_tx); + bool tdown = false; int num_tx; if (AM65_CPSW_IS_CPSW2G(tx_chn->common)) - num_tx = am65_cpsw_nuss_tx_compl_packets_2g(tx_chn->common, tx_chn->id, budget); + num_tx = am65_cpsw_nuss_tx_compl_packets_2g(tx_chn->common, tx_chn->id, + budget, &tdown); else - num_tx = am65_cpsw_nuss_tx_compl_packets(tx_chn->common, tx_chn->id, budget); + num_tx = am65_cpsw_nuss_tx_compl_packets(tx_chn->common, + tx_chn->id, budget, &tdown); if (num_tx >= budget) return budget; - if (napi_complete_done(napi_tx, num_tx)) - enable_irq(tx_chn->irq); + if (napi_complete_done(napi_tx, num_tx)) { + if (unlikely(tx_chn->tx_pace_timeout && !tdown)) { + hrtimer_start(&tx_chn->tx_hrtimer, + ns_to_ktime(tx_chn->tx_pace_timeout), + HRTIMER_MODE_REL_PINNED); + } else { + enable_irq(tx_chn->irq); + } + } return 0; } @@ -1115,10 +1578,13 @@ goto busy_stop_q; } + am65_cpsw_nuss_set_buf_type(tx_chn, first_desc, + AM65_CPSW_TX_BUF_TYPE_SKB); + cppi5_hdesc_init(first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT, AM65_CPSW_NAV_PS_DATA_SIZE); - cppi5_desc_set_pktids(&first_desc->hdr, 0, 0x3FFF); - cppi5_hdesc_set_pkttype(first_desc, 0x7); + cppi5_desc_set_pktids(&first_desc->hdr, 0, AM65_CPSW_CPPI_TX_FLOW_ID); + cppi5_hdesc_set_pkttype(first_desc, AM65_CPSW_CPPI_TX_PKT_TYPE); cppi5_desc_set_tags_ids(&first_desc->hdr, 0, port->port_id); k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); @@ -1157,6 +1623,9 @@ goto busy_free_descs; } + am65_cpsw_nuss_set_buf_type(tx_chn, next_desc, + AM65_CPSW_TX_BUF_TYPE_SKB); + buf_dma = skb_frag_dma_map(tx_chn->dma_dev, frag, 0, frag_size, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(tx_chn->dma_dev, buf_dma))) { @@ -1266,7 +1735,6 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr) { - struct am65_cpsw_common *common = am65_ndev_to_common(ndev); struct am65_cpsw_port *port = am65_ndev_to_port(ndev); u32 ts_ctrl, seq_id, ts_ctrl_ltype2, ts_vlan_ltype; struct hwtstamp_config cfg; @@ -1290,11 +1758,6 @@ case HWTSTAMP_FILTER_NONE: port->rx_ts_enabled = false; break; - case HWTSTAMP_FILTER_ALL: - case HWTSTAMP_FILTER_SOME: - case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: - case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: - case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: @@ -1304,10 +1767,13 @@ case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - case HWTSTAMP_FILTER_NTP_ALL: port->rx_ts_enabled = true; - cfg.rx_filter = HWTSTAMP_FILTER_ALL; + cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break; + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_SOME: + case HWTSTAMP_FILTER_NTP_ALL: + return -EOPNOTSUPP; default: return -ERANGE; } @@ -1337,6 +1803,10 @@ ts_ctrl |= AM65_CPSW_TS_TX_ANX_ALL_EN | AM65_CPSW_PN_TS_CTL_TX_VLAN_LT1_EN; + if (port->rx_ts_enabled) + ts_ctrl |= AM65_CPSW_TS_RX_ANX_ALL_EN | + AM65_CPSW_PN_TS_CTL_RX_VLAN_LT1_EN; + writel(seq_id, port->port_base + AM65_CPSW_PORTN_REG_TS_SEQ_LTYPE_REG); writel(ts_vlan_ltype, port->port_base + AM65_CPSW_PORTN_REG_TS_VLAN_LTYPE_REG); @@ -1344,9 +1814,6 @@ AM65_CPSW_PORTN_REG_TS_CTL_LTYPE2); writel(ts_ctrl, port->port_base + AM65_CPSW_PORTN_REG_TS_CTL); - /* en/dis RX timestamp */ - am65_cpts_rx_enable(common->cpts, port->rx_ts_enabled); - return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; } @@ -1363,7 +1830,7 @@ cfg.tx_type = port->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; cfg.rx_filter = port->rx_ts_enabled ? - HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE; + HWTSTAMP_FILTER_PTP_V2_EVENT : HWTSTAMP_FILTER_NONE; return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; } @@ -1420,6 +1887,59 @@ stats->tx_dropped = dev->stats.tx_dropped; } +static int am65_cpsw_xdp_prog_setup(struct net_device *ndev, + struct bpf_prog *prog) +{ + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + bool running = netif_running(ndev); + struct bpf_prog *old_prog; + + if (running) + am65_cpsw_nuss_ndo_slave_stop(ndev); + + old_prog = xchg(&port->xdp_prog, prog); + if (old_prog) + bpf_prog_put(old_prog); + + if (running) + return am65_cpsw_nuss_ndo_slave_open(ndev); + + return 0; +} + +static int am65_cpsw_ndo_bpf(struct net_device *ndev, struct netdev_bpf *bpf) +{ + switch (bpf->command) { + case XDP_SETUP_PROG: + return am65_cpsw_xdp_prog_setup(ndev, bpf->prog); + default: + return -EINVAL; + } +} + +static int am65_cpsw_ndo_xdp_xmit(struct net_device *ndev, int n, + struct xdp_frame **frames, u32 flags) +{ + struct am65_cpsw_tx_chn *tx_chn; + struct netdev_queue *netif_txq; + int cpu = smp_processor_id(); + int i, nxmit = 0; + + tx_chn = &am65_ndev_to_common(ndev)->tx_chns[cpu % AM65_CPSW_MAX_TX_QUEUES]; + netif_txq = netdev_get_tx_queue(ndev, tx_chn->id); + + __netif_tx_lock(netif_txq, cpu); + for (i = 0; i < n; i++) { + if (am65_cpsw_xdp_tx_frame(ndev, tx_chn, frames[i], + AM65_CPSW_TX_BUF_TYPE_XDP_NDO)) + break; + nxmit++; + } + __netif_tx_unlock(netif_txq); + + return nxmit; +} + static const struct net_device_ops am65_cpsw_nuss_netdev_ops = { .ndo_open = am65_cpsw_nuss_ndo_slave_open, .ndo_stop = am65_cpsw_nuss_ndo_slave_stop, @@ -1434,6 +1954,8 @@ .ndo_eth_ioctl = am65_cpsw_nuss_ndo_slave_ioctl, .ndo_setup_tc = am65_cpsw_qos_ndo_setup_tc, .ndo_set_tx_maxrate = am65_cpsw_qos_ndo_tx_p0_set_maxrate, + .ndo_bpf = am65_cpsw_ndo_bpf, + .ndo_xdp_xmit = am65_cpsw_ndo_xdp_xmit, }; static void am65_cpsw_disable_phy(struct phy *phy) @@ -1588,17 +2110,17 @@ /* rx_pause/tx_pause */ if (rx_pause) - mac_control |= CPSW_SL_CTL_RX_FLOW_EN; + mac_control |= CPSW_SL_CTL_TX_FLOW_EN; if (tx_pause) - mac_control |= CPSW_SL_CTL_TX_FLOW_EN; + mac_control |= CPSW_SL_CTL_RX_FLOW_EN; cpsw_sl_ctl_set(port->slave.mac_sl, mac_control); /* enable forwarding */ cpsw_ale_control_set(common->ale, port->port_id, ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); - am65_cpsw_qos_link_up(ndev, speed); + am65_cpsw_qos_link_up(ndev, speed, duplex); netif_tx_wake_all_queues(ndev); } @@ -1630,6 +2152,8 @@ for (i = 0; i < common->tx_ch_num; i++) { struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i]; + irq_set_affinity_hint(tx_chn->irq, NULL); + if (!IS_ERR_OR_NULL(tx_chn->desc_pool)) k3_cppi_desc_pool_destroy(tx_chn->desc_pool); @@ -1651,8 +2175,10 @@ for (i = 0; i < common->tx_ch_num; i++) { struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i]; - if (tx_chn->irq) + if (tx_chn->irq) { + irq_set_affinity_hint(tx_chn->irq, NULL); devm_free_irq(dev, tx_chn->irq, tx_chn); + } netif_napi_del(&tx_chn->napi_tx); @@ -1676,6 +2202,8 @@ netif_napi_add_tx(common->dma_ndev, &tx_chn->napi_tx, am65_cpsw_nuss_tx_poll); + hrtimer_init(&tx_chn->tx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); + tx_chn->tx_hrtimer.function = &am65_cpsw_nuss_tx_timer_callback; ret = devm_request_irq(dev, tx_chn->irq, am65_cpsw_nuss_tx_irq, @@ -1686,6 +2214,7 @@ tx_chn->id, tx_chn->irq, ret); goto err; } + irq_set_affinity_hint(tx_chn->irq, get_cpu_mask(i % num_online_cpus())); } err: @@ -1702,7 +2231,7 @@ .mode = K3_RINGACC_RING_MODE_RING, .flags = 0 }; - u32 hdesc_size; + u32 hdesc_size, hdesc_size_out; int i, ret = 0; hdesc_size = cppi5_hdesc_calc_size(true, AM65_CPSW_NAV_PS_DATA_SIZE, @@ -1746,6 +2275,10 @@ goto err; } + hdesc_size_out = k3_cppi_desc_pool_desc_size(tx_chn->desc_pool); + tx_chn->dsize_log2 = __fls(hdesc_size_out); + WARN_ON(hdesc_size_out != (1 << tx_chn->dsize_log2)); + tx_chn->irq = k3_udma_glue_tx_get_irq(tx_chn->tx_chn); if (tx_chn->irq < 0) { dev_err(dev, "Failed to get tx dma irq %d\n", @@ -1782,6 +2315,8 @@ rx_chn = &common->rx_chns; + irq_set_affinity_hint(rx_chn->irq, NULL); + if (!IS_ERR_OR_NULL(rx_chn->desc_pool)) k3_cppi_desc_pool_destroy(rx_chn->desc_pool); @@ -1792,22 +2327,20 @@ static void am65_cpsw_nuss_remove_rx_chns(void *data) { struct am65_cpsw_common *common = data; - struct am65_cpsw_rx_chn *rx_chn; struct device *dev = common->dev; + struct am65_cpsw_rx_chn *rx_chn; rx_chn = &common->rx_chns; devm_remove_action(dev, am65_cpsw_nuss_free_rx_chns, common); - if (!(rx_chn->irq < 0)) + if (!(rx_chn->irq < 0)) { + irq_set_affinity_hint(rx_chn->irq, NULL); devm_free_irq(dev, rx_chn->irq, common); + } netif_napi_del(&common->napi_rx); - if (!IS_ERR_OR_NULL(rx_chn->desc_pool)) - k3_cppi_desc_pool_destroy(rx_chn->desc_pool); - - if (!IS_ERR_OR_NULL(rx_chn->rx_chn)) - k3_udma_glue_release_rx_chn(rx_chn->rx_chn); + am65_cpsw_nuss_free_rx_chns(common); common->rx_flow_id_base = -1; } @@ -1818,7 +2351,7 @@ struct k3_udma_glue_rx_channel_cfg rx_cfg = { 0 }; u32 max_desc_num = AM65_CPSW_MAX_RX_DESC; struct device *dev = common->dev; - u32 hdesc_size; + u32 hdesc_size, hdesc_size_out; u32 fdqring_id; int i, ret = 0; @@ -1850,6 +2383,17 @@ goto err; } + hdesc_size_out = k3_cppi_desc_pool_desc_size(rx_chn->desc_pool); + rx_chn->dsize_log2 = __fls(hdesc_size_out); + WARN_ON(hdesc_size_out != (1 << rx_chn->dsize_log2)); + + rx_chn->page_pool = NULL; + + rx_chn->pages = devm_kcalloc(dev, rx_chn->descs_num, + sizeof(*rx_chn->pages), GFP_KERNEL); + if (!rx_chn->pages) + return -ENOMEM; + common->rx_flow_id_base = k3_udma_glue_rx_get_flow_id_base(rx_chn->rx_chn); dev_info(dev, "set new flow-id-base %u\n", common->rx_flow_id_base); @@ -1901,6 +2445,8 @@ netif_napi_add(common->dma_ndev, &common->napi_rx, am65_cpsw_nuss_rx_poll); + hrtimer_init(&common->rx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); + common->rx_hrtimer.function = &am65_cpsw_nuss_rx_timer_callback; ret = devm_request_irq(dev, rx_chn->irq, am65_cpsw_nuss_rx_irq, @@ -1910,6 +2456,7 @@ rx_chn->irq, ret); goto err; } + irq_set_affinity_hint(rx_chn->irq, get_cpu_mask(cpumask_first(cpu_present_mask))); err: i = devm_add_action(dev, am65_cpsw_nuss_free_rx_chns, common); @@ -2098,6 +2645,9 @@ dev_err(dev, "Use random MAC address\n"); } } + + /* Reset all Queue priorities to 0 */ + writel(0, port->port_base + AM65_CPSW_PN_REG_TX_PRI_MAP); } of_node_put(node); @@ -2162,6 +2712,8 @@ ndev_priv = netdev_priv(port->ndev); ndev_priv->port = port; ndev_priv->msg_enable = AM65_CPSW_DEBUG; + mutex_init(&ndev_priv->mm_lock); + port->qos.link_speed = SPEED_UNKNOWN; SET_NETDEV_DEV(port->ndev, dev); eth_hw_addr_set(port->ndev, port->slave.mac_addr); @@ -2175,6 +2727,9 @@ NETIF_F_HW_TC; port->ndev->features = port->ndev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER; + port->ndev->xdp_features = NETDEV_XDP_ACT_BASIC | + NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_NDO_XMIT; port->ndev->vlan_features |= NETIF_F_SG; port->ndev->netdev_ops = &am65_cpsw_nuss_netdev_ops; port->ndev->ethtool_ops = &am65_cpsw_ethtool_ops_slave; @@ -2238,6 +2793,8 @@ if (ret) dev_err(dev, "failed to add percpu stat free action %d\n", ret); + port->xdp_prog = NULL; + if (!common->dma_ndev) common->dma_ndev = port->ndev; @@ -2604,8 +3161,10 @@ port = am65_ndev_to_port(sl_ndev); port->slave.port_vlan = 0; - if (netif_running(sl_ndev)) + if (netif_running(sl_ndev)) { am65_cpsw_init_port_emac_ale(port); + am65_cpsw_qos_cut_thru_cleanup(port); + } } } cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_BYPASS, 0); @@ -2753,6 +3312,10 @@ for (i = 0; i < common->port_num; i++) { port = &common->ports[i]; + ret = am65_cpsw_nuss_register_port_debugfs(port); + if (ret) + goto err_cleanup_ndev; + if (!port->ndev) continue; @@ -2822,7 +3385,7 @@ }; static const struct am65_cpsw_pdata am64x_cpswxg_pdata = { - .quirks = AM64_CPSW_QUIRK_DMA_RX_TDOWN_IRQ, + .quirks = AM64_CPSW_QUIRK_DMA_RX_TDOWN_IRQ | AM64_CPSW_QUIRK_CUT_THRU, .ale_dev_id = "am64-cpswxg", .fdqring_mode = K3_RINGACC_RING_MODE_RING, }; @@ -2845,7 +3408,8 @@ .quirks = 0, .ale_dev_id = "am64-cpswxg", .fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE, - .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_USXGMII), + .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII) | + BIT(PHY_INTERFACE_MODE_USXGMII), }; static const struct of_device_id am65_cpsw_nuss_of_mtable[] = { @@ -2881,9 +3445,9 @@ struct device_node *node; struct resource *res; struct clk *clk; + int ale_entries; u64 id_temp; int ret, i; - int ale_entries; common = devm_kzalloc(dev, sizeof(struct am65_cpsw_common), GFP_KERNEL); if (!common) @@ -2916,7 +3480,7 @@ common->rx_flow_id_base = -1; init_completion(&common->tdown_complete); - common->tx_ch_num = 1; + common->tx_ch_num = AM65_CPSW_DEFAULT_TX_CHNS; common->pf_p0_rx_ptype_rrobin = false; common->default_vlan = 1; @@ -2999,10 +3563,16 @@ if (ret) goto err_free_phylink; - ret = am65_cpsw_nuss_register_ndevs(common); + ret = am65_cpsw_nuss_register_debugfs(common); if (ret) goto err_free_phylink; + ret = am65_cpsw_nuss_register_ndevs(common); + if (ret) { + am65_cpsw_nuss_unregister_debugfs(common); + goto err_free_phylink; + } + pm_runtime_put(dev); return 0; @@ -3018,7 +3588,7 @@ return ret; } -static int am65_cpsw_nuss_remove(struct platform_device *pdev) +static void am65_cpsw_nuss_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct am65_cpsw_common *common; @@ -3027,8 +3597,14 @@ common = dev_get_drvdata(dev); ret = pm_runtime_resume_and_get(&pdev->dev); - if (ret < 0) - return ret; + if (ret < 0) { + /* Note, if this error path is taken, we're leaking some + * resources. + */ + dev_err(&pdev->dev, "Failed to resume device (%pe)\n", + ERR_PTR(ret)); + return; + } am65_cpsw_unregister_devlink(common); am65_cpsw_unregister_notifiers(common); @@ -3046,7 +3622,6 @@ pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - return 0; } static int am65_cpsw_nuss_suspend(struct device *dev) @@ -3090,10 +3665,10 @@ static int am65_cpsw_nuss_resume(struct device *dev) { struct am65_cpsw_common *common = dev_get_drvdata(dev); + struct am65_cpsw_host *host_p = am65_common_get_host(common); struct am65_cpsw_port *port; struct net_device *ndev; int i, ret; - struct am65_cpsw_host *host_p = am65_common_get_host(common); ret = am65_cpsw_nuss_init_tx_chns(common); if (ret) @@ -3146,7 +3721,7 @@ .pm = &am65_cpsw_nuss_dev_pm_ops, }, .probe = am65_cpsw_nuss_probe, - .remove = am65_cpsw_nuss_remove, + .remove_new = am65_cpsw_nuss_remove, }; module_platform_driver(am65_cpsw_nuss_driver); diff -Naur --no-dereference a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h 2024-07-07 20:37:34.668306669 -0400 @@ -6,6 +6,7 @@ #ifndef AM65_CPSW_NUSS_H_ #define AM65_CPSW_NUSS_H_ +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include "am65-cpsw-qos.h" struct am65_cpts; @@ -56,10 +58,19 @@ bool rx_ts_enabled; struct am65_cpsw_qos qos; struct devlink_port devlink_port; + struct dentry *debugfs_port; + struct bpf_prog *xdp_prog; + struct xdp_rxq_info xdp_rxq; /* Only for suspend resume context */ u32 vid_context; }; +enum am65_cpsw_tx_buf_type { + AM65_CPSW_TX_BUF_TYPE_SKB, + AM65_CPSW_TX_BUF_TYPE_XDP_TX, + AM65_CPSW_TX_BUF_TYPE_XDP_NDO, +}; + struct am65_cpsw_host { struct am65_cpsw_common *common; void __iomem *port_base; @@ -75,9 +86,12 @@ struct k3_cppi_desc_pool *desc_pool; struct k3_udma_glue_tx_channel *tx_chn; spinlock_t lock; /* protect TX rings in multi-port mode */ + struct hrtimer tx_hrtimer; + unsigned long tx_pace_timeout; int irq; u32 id; u32 descs_num; + unsigned char dsize_log2; char tx_chn_name[128]; u32 rate_mbps; }; @@ -87,12 +101,16 @@ struct device *dma_dev; struct k3_cppi_desc_pool *desc_pool; struct k3_udma_glue_rx_channel *rx_chn; + struct page_pool *page_pool; + struct page **pages; u32 descs_num; + unsigned char dsize_log2; int irq; }; #define AM65_CPSW_QUIRK_I2027_NO_TX_CSUM BIT(0) #define AM64_CPSW_QUIRK_DMA_RX_TDOWN_IRQ BIT(1) +#define AM64_CPSW_QUIRK_CUT_THRU BIT(2) struct am65_cpsw_pdata { u32 quirks; @@ -138,6 +156,8 @@ struct napi_struct napi_rx; bool rx_irq_disabled; + struct hrtimer rx_hrtimer; + unsigned long rx_pace_timeout; u32 nuss_ver; u32 cpsw_ver; @@ -145,6 +165,8 @@ bool pf_p0_rx_ptype_rrobin; struct am65_cpts *cpts; int est_enabled; + bool iet_enabled; + unsigned int cut_thru_enabled; bool is_emac_mode; u16 br_members; @@ -153,6 +175,8 @@ struct net_device *hw_bridge_dev; struct notifier_block am65_cpsw_netdevice_nb; unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN]; + + struct dentry *debugfs_root; /* only for suspend/resume context restore */ u32 *ale_context; }; @@ -170,6 +194,10 @@ struct am65_cpsw_port *port; struct am65_cpsw_ndev_stats __percpu *stats; bool offload_fwd_mark; + /* Serialize access to MAC Merge state between ethtool requests + * and link state updates + */ + struct mutex mm_lock; }; #define am65_ndev_to_priv(ndev) \ @@ -198,4 +226,8 @@ bool am65_cpsw_port_dev_check(const struct net_device *dev); +int am65_cpsw_nuss_register_port_debugfs(struct am65_cpsw_port *port); +int am65_cpsw_nuss_register_debugfs(struct am65_cpsw_common *common); +void am65_cpsw_nuss_unregister_debugfs(struct am65_cpsw_common *common); + #endif /* AM65_CPSW_NUSS_H_ */ diff -Naur --no-dereference a/drivers/net/ethernet/ti/am65-cpsw-qos.c b/drivers/net/ethernet/ti/am65-cpsw-qos.c --- a/drivers/net/ethernet/ti/am65-cpsw-qos.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/am65-cpsw-qos.c 2024-07-07 20:37:34.668306669 -0400 @@ -4,10 +4,15 @@ * * quality of service module includes: * Enhanced Scheduler Traffic (EST - P802.1Qbv/D2.2) + * Interspersed Express Traffic (IET - P802.3br/D2.0) */ +#include #include +#include +#include #include +#include #include #include "am65-cpsw-nuss.h" @@ -15,40 +20,24 @@ #include "am65-cpts.h" #include "cpsw_ale.h" -#define AM65_CPSW_REG_CTL 0x004 -#define AM65_CPSW_PN_REG_CTL 0x004 -#define AM65_CPSW_PN_REG_FIFO_STATUS 0x050 -#define AM65_CPSW_PN_REG_EST_CTL 0x060 -#define AM65_CPSW_PN_REG_PRI_CIR(pri) (0x140 + 4 * (pri)) +#define AM65_CPSW_REG_FREQ 0x05c + +#define AM64_CPSW_PN_CUT_THRU 0x3C0 +#define AM64_CPSW_PN_SPEED 0x3C4 /* AM65_CPSW_REG_CTL register fields */ -#define AM65_CPSW_CTL_EST_EN BIT(18) +#define AM64_CPSW_CTL_CUT_THRU_EN BIT(19) -/* AM65_CPSW_PN_REG_CTL register fields */ -#define AM65_CPSW_PN_CTL_EST_PORT_EN BIT(17) +/* Cut-Thru AM64_CPSW_PN_CUT_THRU */ +#define AM64_PN_CUT_THRU_TX_PRI GENMASK(7, 0) +#define AM64_PN_CUT_THRU_RX_PRI GENMASK(15, 8) + +/* Cut-Thru AM64_CPSW_PN_SPEED */ +#define AM64_PN_SPEED_VAL GENMASK(3, 0) +#define AM64_PN_SPEED_AUTO_EN BIT(8) +#define AM64_PN_AUTO_SPEED GENMASK(15, 12) -/* AM65_CPSW_PN_REG_EST_CTL register fields */ -#define AM65_CPSW_PN_EST_ONEBUF BIT(0) -#define AM65_CPSW_PN_EST_BUFSEL BIT(1) -#define AM65_CPSW_PN_EST_TS_EN BIT(2) -#define AM65_CPSW_PN_EST_TS_FIRST BIT(3) -#define AM65_CPSW_PN_EST_ONEPRI BIT(4) -#define AM65_CPSW_PN_EST_TS_PRI_MSK GENMASK(7, 5) - -/* AM65_CPSW_PN_REG_FIFO_STATUS register fields */ -#define AM65_CPSW_PN_FST_TX_PRI_ACTIVE_MSK GENMASK(7, 0) -#define AM65_CPSW_PN_FST_TX_E_MAC_ALLOW_MSK GENMASK(15, 8) -#define AM65_CPSW_PN_FST_EST_CNT_ERR BIT(16) -#define AM65_CPSW_PN_FST_EST_ADD_ERR BIT(17) -#define AM65_CPSW_PN_FST_EST_BUFACT BIT(18) - -/* EST FETCH COMMAND RAM */ -#define AM65_CPSW_FETCH_RAM_CMD_NUM 0x80 -#define AM65_CPSW_FETCH_CNT_MSK GENMASK(21, 8) -#define AM65_CPSW_FETCH_CNT_MAX (AM65_CPSW_FETCH_CNT_MSK >> 8) -#define AM65_CPSW_FETCH_CNT_OFFSET 8 -#define AM65_CPSW_FETCH_ALLOW_MSK GENMASK(7, 0) -#define AM65_CPSW_FETCH_ALLOW_MAX AM65_CPSW_FETCH_ALLOW_MSK +#define TO_MBPS(x) DIV_ROUND_UP((x), BYTES_PER_MBIT) enum timer_act { TACT_PROG, /* need program timer */ @@ -56,6 +45,415 @@ TACT_SKIP_PROG, /* just buffer can be updated */ }; +/* number of traffic classes (fifos) per port */ +#define AM65_CPSW_PN_TC_NUM 8 + +static void am65_cpsw_iet_change_preemptible_tcs(struct am65_cpsw_port *port, u8 preemptible_tcs); + +static u32 +am65_cpsw_qos_tx_rate_calc(u32 rate_mbps, unsigned long bus_freq) +{ + u32 ir; + + bus_freq /= 1000000; + ir = DIV_ROUND_UP(((u64)rate_mbps * 32768), bus_freq); + return ir; +} + +static void am65_cpsw_tx_pn_shaper_reset(struct am65_cpsw_port *port) +{ + int prio; + + for (prio = 0; prio < AM65_CPSW_PN_FIFO_PRIO_NUM; prio++) { + writel(0, port->port_base + AM65_CPSW_PN_REG_PRI_CIR(prio)); + writel(0, port->port_base + AM65_CPSW_PN_REG_PRI_EIR(prio)); + } +} + +static void am65_cpsw_tx_pn_shaper_apply(struct am65_cpsw_port *port) +{ + struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio; + struct am65_cpsw_common *common = port->common; + struct tc_mqprio_qopt_offload *mqprio; + bool enable, shaper_susp = false; + u32 rate_mbps; + int tc, prio; + + mqprio = &p_mqprio->mqprio_hw; + /* takes care of no link case as well */ + if (p_mqprio->max_rate_total > port->qos.link_speed) + shaper_susp = true; + + am65_cpsw_tx_pn_shaper_reset(port); + + enable = p_mqprio->shaper_en && !shaper_susp; + if (!enable) + return; + + /* Rate limit is specified per Traffic Class but + * for CPSW, rate limit can be applied per priority + * at port FIFO. + * + * We have assigned the same priority (TCn) to all queues + * of a Traffic Class so they share the same shaper + * bandwidth. + */ + for (tc = 0; tc < mqprio->qopt.num_tc; tc++) { + prio = tc; + + rate_mbps = TO_MBPS(mqprio->min_rate[tc]); + rate_mbps = am65_cpsw_qos_tx_rate_calc(rate_mbps, + common->bus_freq); + writel(rate_mbps, + port->port_base + AM65_CPSW_PN_REG_PRI_CIR(prio)); + + rate_mbps = 0; + + if (mqprio->max_rate[tc]) { + rate_mbps = mqprio->max_rate[tc] - mqprio->min_rate[tc]; + rate_mbps = TO_MBPS(rate_mbps); + rate_mbps = am65_cpsw_qos_tx_rate_calc(rate_mbps, + common->bus_freq); + } + + writel(rate_mbps, + port->port_base + AM65_CPSW_PN_REG_PRI_EIR(prio)); + } +} + +static int am65_cpsw_mqprio_verify_shaper(struct am65_cpsw_port *port, + struct tc_mqprio_qopt_offload *mqprio) +{ + struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio; + struct netlink_ext_ack *extack = mqprio->extack; + u64 min_rate_total = 0, max_rate_total = 0; + u32 min_rate_msk = 0, max_rate_msk = 0; + bool has_min_rate, has_max_rate; + int num_tc, i; + + if (!(mqprio->flags & TC_MQPRIO_F_SHAPER)) + return 0; + + if (mqprio->shaper != TC_MQPRIO_SHAPER_BW_RATE) + return 0; + + has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE); + has_max_rate = !!(mqprio->flags & TC_MQPRIO_F_MAX_RATE); + + if (!has_min_rate && has_max_rate) { + NL_SET_ERR_MSG_MOD(extack, "min_rate is required with max_rate"); + return -EOPNOTSUPP; + } + + if (!has_min_rate) + return 0; + + num_tc = mqprio->qopt.num_tc; + + for (i = num_tc - 1; i >= 0; i--) { + u32 ch_msk; + + if (mqprio->min_rate[i]) + min_rate_msk |= BIT(i); + min_rate_total += mqprio->min_rate[i]; + + if (has_max_rate) { + if (mqprio->max_rate[i]) + max_rate_msk |= BIT(i); + max_rate_total += mqprio->max_rate[i]; + + if (!mqprio->min_rate[i] && mqprio->max_rate[i]) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "TX tc%d rate max>0 but min=0", + i); + return -EINVAL; + } + + if (mqprio->max_rate[i] && + mqprio->max_rate[i] < mqprio->min_rate[i]) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "TX tc%d rate min(%llu)>max(%llu)", + i, mqprio->min_rate[i], + mqprio->max_rate[i]); + return -EINVAL; + } + } + + ch_msk = GENMASK(num_tc - 1, i); + if ((min_rate_msk & BIT(i)) && (min_rate_msk ^ ch_msk)) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "Min rate must be set sequentially hi->lo tx_rate_msk%x", + min_rate_msk); + return -EINVAL; + } + + if ((max_rate_msk & BIT(i)) && (max_rate_msk ^ ch_msk)) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "Max rate must be set sequentially hi->lo tx_rate_msk%x", + max_rate_msk); + return -EINVAL; + } + } + + min_rate_total = TO_MBPS(min_rate_total); + max_rate_total = TO_MBPS(max_rate_total); + + p_mqprio->shaper_en = true; + p_mqprio->max_rate_total = max_t(u64, min_rate_total, max_rate_total); + + return 0; +} + +static void am65_cpsw_reset_tc_mqprio(struct net_device *ndev) +{ + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio; + + p_mqprio->shaper_en = false; + p_mqprio->max_rate_total = 0; + + am65_cpsw_tx_pn_shaper_reset(port); + netdev_reset_tc(ndev); + + /* Reset all Queue priorities to 0 */ + writel(0, port->port_base + AM65_CPSW_PN_REG_TX_PRI_MAP); + + am65_cpsw_iet_change_preemptible_tcs(port, 0); +} + +static int am65_cpsw_setup_mqprio(struct net_device *ndev, void *type_data) +{ + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio; + struct tc_mqprio_qopt_offload *mqprio = type_data; + struct am65_cpsw_common *common = port->common; + struct tc_mqprio_qopt *qopt = &mqprio->qopt; + int i, tc, offset, count, prio, ret; + u8 num_tc = qopt->num_tc; + u32 tx_prio_map = 0; + + memcpy(&p_mqprio->mqprio_hw, mqprio, sizeof(*mqprio)); + + ret = pm_runtime_get_sync(common->dev); + if (ret < 0) { + pm_runtime_put_noidle(common->dev); + return ret; + } + + if (!num_tc) { + am65_cpsw_reset_tc_mqprio(ndev); + ret = 0; + goto exit_put; + } + + ret = am65_cpsw_mqprio_verify_shaper(port, mqprio); + if (ret) + goto exit_put; + + netdev_set_num_tc(ndev, num_tc); + + /* Multiple Linux priorities can map to a Traffic Class + * A Traffic Class can have multiple contiguous Queues, + * Queues get mapped to Channels (thread_id), + * if not VLAN tagged, thread_id is used as packet_priority + * if VLAN tagged. VLAN priority is used as packet_priority + * packet_priority gets mapped to header_priority in p0_rx_pri_map, + * header_priority gets mapped to switch_priority in pn_tx_pri_map. + * As p0_rx_pri_map is left at defaults (0x76543210), we can + * assume that Queue_n gets mapped to header_priority_n. We can then + * set the switch priority in pn_tx_pri_map. + */ + + for (tc = 0; tc < num_tc; tc++) { + prio = tc; + + /* For simplicity we assign the same priority (TCn) to + * all queues of a Traffic Class. + */ + for (i = qopt->offset[tc]; i < qopt->offset[tc] + qopt->count[tc]; i++) + tx_prio_map |= prio << (4 * i); + + count = qopt->count[tc]; + offset = qopt->offset[tc]; + netdev_set_tc_queue(ndev, tc, count, offset); + } + + writel(tx_prio_map, port->port_base + AM65_CPSW_PN_REG_TX_PRI_MAP); + + am65_cpsw_tx_pn_shaper_apply(port); + am65_cpsw_iet_change_preemptible_tcs(port, mqprio->preemptible_tcs); + +exit_put: + pm_runtime_put(common->dev); + + return ret; +} + +static int am65_cpsw_iet_set_verify_timeout_count(struct am65_cpsw_port *port) +{ + int verify_time_ms = port->qos.iet.verify_time_ms; + u32 val; + + /* The number of wireside clocks contained in the verify + * timeout counter. The default is 0x1312d0 + * (10ms at 125Mhz in 1G mode). + */ + val = 125 * HZ_PER_MHZ; /* assuming 125MHz wireside clock */ + + val /= MILLIHZ_PER_HZ; /* count per ms timeout */ + val *= verify_time_ms; /* count for timeout ms */ + + if (val > AM65_CPSW_PN_MAC_VERIFY_CNT_MASK) + return -EINVAL; + + writel(val, port->port_base + AM65_CPSW_PN_REG_IET_VERIFY); + + return 0; +} + +static int am65_cpsw_iet_verify_wait(struct am65_cpsw_port *port) +{ + u32 ctrl, status; + int try; + + try = 20; + do { + /* Reset the verify state machine by writing 1 + * to LINKFAIL + */ + ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL); + ctrl |= AM65_CPSW_PN_IET_MAC_LINKFAIL; + writel(ctrl, port->port_base + AM65_CPSW_PN_REG_IET_CTRL); + + /* Clear MAC_LINKFAIL bit to start Verify. */ + ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL); + ctrl &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL; + writel(ctrl, port->port_base + AM65_CPSW_PN_REG_IET_CTRL); + + msleep(port->qos.iet.verify_time_ms); + + status = readl(port->port_base + AM65_CPSW_PN_REG_IET_STATUS); + if (status & AM65_CPSW_PN_MAC_VERIFIED) + return 0; + + if (status & AM65_CPSW_PN_MAC_VERIFY_FAIL) { + netdev_dbg(port->ndev, + "MAC Merge verify failed, trying again\n"); + continue; + } + + if (status & AM65_CPSW_PN_MAC_RESPOND_ERR) { + netdev_dbg(port->ndev, "MAC Merge respond error\n"); + return -ENODEV; + } + + if (status & AM65_CPSW_PN_MAC_VERIFY_ERR) { + netdev_dbg(port->ndev, "MAC Merge verify error\n"); + return -ENODEV; + } + } while (try-- > 0); + + netdev_dbg(port->ndev, "MAC Merge verify timeout\n"); + return -ETIMEDOUT; +} + +static void am65_cpsw_iet_set_preempt_mask(struct am65_cpsw_port *port, u8 preemptible_tcs) +{ + u32 val; + + val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL); + val &= ~AM65_CPSW_PN_IET_MAC_PREMPT_MASK; + val |= AM65_CPSW_PN_IET_MAC_SET_PREEMPT(preemptible_tcs); + writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL); +} + +/* enable common IET_ENABLE only if at least 1 port has rx IET enabled. + * UAPI doesn't allow tx enable without rx enable. + */ +void am65_cpsw_iet_common_enable(struct am65_cpsw_common *common) +{ + struct am65_cpsw_port *port; + bool rx_enable = false; + u32 val; + int i; + + for (i = 0; i < common->port_num; i++) { + port = &common->ports[i]; + val = readl(port->port_base + AM65_CPSW_PN_REG_CTL); + rx_enable = !!(val & AM65_CPSW_PN_CTL_IET_PORT_EN); + if (rx_enable) + break; + } + + val = readl(common->cpsw_base + AM65_CPSW_REG_CTL); + + if (rx_enable) + val |= AM65_CPSW_CTL_IET_EN; + else + val &= ~AM65_CPSW_CTL_IET_EN; + + writel(val, common->cpsw_base + AM65_CPSW_REG_CTL); + common->iet_enabled = rx_enable; +} + +/* CPSW does not have an IRQ to notify changes to the MAC Merge TX status + * (active/inactive), but the preemptible traffic classes should only be + * committed to hardware once TX is active. Resort to polling. + */ +void am65_cpsw_iet_commit_preemptible_tcs(struct am65_cpsw_port *port) +{ + u8 preemptible_tcs; + int err; + u32 val; + + if (port->qos.link_speed == SPEED_UNKNOWN) + return; + + val = readl(port->port_base + AM65_CPSW_PN_REG_CTL); + if (!(val & AM65_CPSW_PN_CTL_IET_PORT_EN)) + return; + + /* update common IET enable */ + am65_cpsw_iet_common_enable(port->common); + + /* update verify count */ + err = am65_cpsw_iet_set_verify_timeout_count(port); + if (err) { + netdev_err(port->ndev, "couldn't set verify count: %d\n", err); + return; + } + + val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL); + if (!(val & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY)) { + err = am65_cpsw_iet_verify_wait(port); + if (err) + return; + } + + preemptible_tcs = port->qos.iet.preemptible_tcs; + am65_cpsw_iet_set_preempt_mask(port, preemptible_tcs); +} + +static void am65_cpsw_iet_change_preemptible_tcs(struct am65_cpsw_port *port, u8 preemptible_tcs) +{ + struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(port->ndev); + + port->qos.iet.preemptible_tcs = preemptible_tcs; + mutex_lock(&priv->mm_lock); + am65_cpsw_iet_commit_preemptible_tcs(port); + mutex_unlock(&priv->mm_lock); +} + +static void am65_cpsw_iet_link_state_update(struct net_device *ndev) +{ + struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev); + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + + mutex_lock(&priv->mm_lock); + am65_cpsw_iet_commit_preemptible_tcs(port); + mutex_unlock(&priv->mm_lock); +} + static int am65_cpsw_port_est_enabled(struct am65_cpsw_port *port) { return port->qos.est_oper || port->qos.est_admin; @@ -428,7 +826,7 @@ am65_cpsw_timer_stop(ndev); } -static void am65_cpsw_purge_est(struct net_device *ndev) +static void am65_cpsw_taprio_destroy(struct net_device *ndev) { struct am65_cpsw_port *port = am65_ndev_to_port(ndev); @@ -439,54 +837,8 @@ port->qos.est_oper = NULL; port->qos.est_admin = NULL; -} - -static int am65_cpsw_configure_taprio(struct net_device *ndev, - struct am65_cpsw_est *est_new) -{ - struct am65_cpsw_common *common = am65_ndev_to_common(ndev); - struct am65_cpts *cpts = common->cpts; - int ret = 0, tact = TACT_PROG; - - am65_cpsw_est_update_state(ndev); - - if (est_new->taprio.cmd == TAPRIO_CMD_DESTROY) { - am65_cpsw_stop_est(ndev); - return ret; - } - - ret = am65_cpsw_est_check_scheds(ndev, est_new); - if (ret < 0) - return ret; - tact = am65_cpsw_timer_act(ndev, est_new); - if (tact == TACT_NEED_STOP) { - dev_err(&ndev->dev, - "Can't toggle estf timer, stop taprio first"); - return -EINVAL; - } - - if (tact == TACT_PROG) - am65_cpsw_timer_stop(ndev); - - if (!est_new->taprio.base_time) - est_new->taprio.base_time = am65_cpts_ns_gettime(cpts); - - am65_cpsw_port_est_get_buf_num(ndev, est_new); - am65_cpsw_est_set_sched_list(ndev, est_new); - am65_cpsw_port_est_assign_buf_num(ndev, est_new->buf); - - am65_cpsw_est_set(ndev, est_new->taprio.cmd == TAPRIO_CMD_REPLACE); - - if (tact == TACT_PROG) { - ret = am65_cpsw_timer_set(ndev, est_new); - if (ret) { - dev_err(&ndev->dev, "Failed to set cycle time"); - return ret; - } - } - - return ret; + am65_cpsw_reset_tc_mqprio(ndev); } static void am65_cpsw_cp_taprio(struct tc_taprio_qopt_offload *from, @@ -499,15 +851,34 @@ to->entries[i] = from->entries[i]; } -static int am65_cpsw_set_taprio(struct net_device *ndev, void *type_data) +static int am65_cpsw_taprio_replace(struct net_device *ndev, + struct tc_taprio_qopt_offload *taprio) { + struct am65_cpsw_common *common = am65_ndev_to_common(ndev); + struct netlink_ext_ack *extack = taprio->mqprio.extack; struct am65_cpsw_port *port = am65_ndev_to_port(ndev); - struct tc_taprio_qopt_offload *taprio = type_data; + struct am65_cpts *cpts = common->cpts; struct am65_cpsw_est *est_new; - int ret = 0; + int ret, tact; + u64 cur_time, n; + + if (!netif_running(ndev)) { + NL_SET_ERR_MSG_MOD(extack, "interface is down, link speed unknown"); + return -ENETDOWN; + } + + if (common->pf_p0_rx_ptype_rrobin) { + NL_SET_ERR_MSG_MOD(extack, + "p0-rx-ptype-rrobin flag conflicts with taprio qdisc"); + return -EINVAL; + } + + if (port->qos.link_speed == SPEED_UNKNOWN) + return -ENOLINK; if (taprio->cycle_time_extension) { - dev_err(&ndev->dev, "Failed to set cycle time extension"); + NL_SET_ERR_MSG_MOD(extack, + "cycle time extension not supported"); return -EOPNOTSUPP; } @@ -517,21 +888,64 @@ if (!est_new) return -ENOMEM; + ret = am65_cpsw_setup_mqprio(ndev, &taprio->mqprio); + if (ret) + return ret; + am65_cpsw_cp_taprio(taprio, &est_new->taprio); - ret = am65_cpsw_configure_taprio(ndev, est_new); - if (!ret) { - if (taprio->cmd == TAPRIO_CMD_REPLACE) { - devm_kfree(&ndev->dev, port->qos.est_admin); - port->qos.est_admin = est_new; - } else { - devm_kfree(&ndev->dev, est_new); - am65_cpsw_purge_est(ndev); + am65_cpsw_est_update_state(ndev); + + ret = am65_cpsw_est_check_scheds(ndev, est_new); + if (ret < 0) + goto fail; + + tact = am65_cpsw_timer_act(ndev, est_new); + if (tact == TACT_NEED_STOP) { + NL_SET_ERR_MSG_MOD(extack, + "Can't toggle estf timer, stop taprio first"); + ret = -EINVAL; + goto fail; + } + + if (tact == TACT_PROG) + am65_cpsw_timer_stop(ndev); + + am65_cpsw_port_est_get_buf_num(ndev, est_new); + am65_cpsw_est_set_sched_list(ndev, est_new); + am65_cpsw_port_est_assign_buf_num(ndev, est_new->buf); + + /* If the base-time is in the past, start schedule from the time: + * base_time + (N*cycle_time) + * where N is the smallest possible integer such that the above + * time is in the future. + */ + cur_time = am65_cpts_ns_gettime(cpts); + if (est_new->taprio.base_time < cur_time) { + n = div64_u64(cur_time - est_new->taprio.base_time, est_new->taprio.cycle_time); + est_new->taprio.base_time += (n + 1) * est_new->taprio.cycle_time; + } + + am65_cpsw_est_set(ndev, 1); + + if (tact == TACT_PROG) { + ret = am65_cpsw_timer_set(ndev, est_new); + if (ret) { + NL_SET_ERR_MSG_MOD(extack, + "Failed to set cycle time"); + goto fail; } - } else { - devm_kfree(&ndev->dev, est_new); } + devm_kfree(&ndev->dev, port->qos.est_admin); + port->qos.est_admin = est_new; + am65_cpsw_iet_change_preemptible_tcs(port, taprio->mqprio.preemptible_tcs); + + return 0; + +fail: + am65_cpsw_reset_tc_mqprio(ndev); + devm_kfree(&ndev->dev, est_new); return ret; } @@ -541,7 +955,6 @@ ktime_t cur_time; s64 delta; - port->qos.link_speed = link_speed; if (!am65_cpsw_port_est_enabled(port)) return; @@ -558,37 +971,26 @@ return; purge_est: - am65_cpsw_purge_est(ndev); + am65_cpsw_taprio_destroy(ndev); } static int am65_cpsw_setup_taprio(struct net_device *ndev, void *type_data) { - struct am65_cpsw_port *port = am65_ndev_to_port(ndev); struct tc_taprio_qopt_offload *taprio = type_data; - struct am65_cpsw_common *common = port->common; - - if (taprio->cmd != TAPRIO_CMD_REPLACE && - taprio->cmd != TAPRIO_CMD_DESTROY) - return -EOPNOTSUPP; - - if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS)) - return -ENODEV; + int err = 0; - if (!netif_running(ndev)) { - dev_err(&ndev->dev, "interface is down, link speed unknown\n"); - return -ENETDOWN; - } - - if (common->pf_p0_rx_ptype_rrobin) { - dev_err(&ndev->dev, - "p0-rx-ptype-rrobin flag conflicts with taprio qdisc\n"); - return -EINVAL; + switch (taprio->cmd) { + case TAPRIO_CMD_REPLACE: + err = am65_cpsw_taprio_replace(ndev, taprio); + break; + case TAPRIO_CMD_DESTROY: + am65_cpsw_taprio_destroy(ndev); + break; + default: + err = -EOPNOTSUPP; } - if (port->qos.link_speed == SPEED_UNKNOWN) - return -ENOLINK; - - return am65_cpsw_set_taprio(ndev, type_data); + return err; } static int am65_cpsw_tc_query_caps(struct net_device *ndev, void *type_data) @@ -596,12 +998,17 @@ struct tc_query_caps_base *base = type_data; switch (base->type) { + case TC_SETUP_QDISC_MQPRIO: { + struct tc_mqprio_caps *caps = base->caps; + + caps->validate_queue_counts = true; + + return 0; + } + case TC_SETUP_QDISC_TAPRIO: { struct tc_taprio_caps *caps = base->caps; - if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS)) - return -EOPNOTSUPP; - caps->gate_mask_per_txq = true; return 0; @@ -787,55 +1194,6 @@ port, port, true); } -int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, - void *type_data) -{ - switch (type) { - case TC_QUERY_CAPS: - return am65_cpsw_tc_query_caps(ndev, type_data); - case TC_SETUP_QDISC_TAPRIO: - return am65_cpsw_setup_taprio(ndev, type_data); - case TC_SETUP_BLOCK: - return am65_cpsw_qos_setup_tc_block(ndev, type_data); - default: - return -EOPNOTSUPP; - } -} - -void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed) -{ - struct am65_cpsw_port *port = am65_ndev_to_port(ndev); - - if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS)) - return; - - am65_cpsw_est_link_up(ndev, link_speed); - port->qos.link_down_time = 0; -} - -void am65_cpsw_qos_link_down(struct net_device *ndev) -{ - struct am65_cpsw_port *port = am65_ndev_to_port(ndev); - - if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS)) - return; - - if (!port->qos.link_down_time) - port->qos.link_down_time = ktime_get(); - - port->qos.link_speed = SPEED_UNKNOWN; -} - -static u32 -am65_cpsw_qos_tx_rate_calc(u32 rate_mbps, unsigned long bus_freq) -{ - u32 ir; - - bus_freq /= 1000000; - ir = DIV_ROUND_UP(((u64)rate_mbps * 32768), bus_freq); - return ir; -} - static void am65_cpsw_qos_tx_p0_rate_apply(struct am65_cpsw_common *common, int tx_ch, u32 rate_mbps) @@ -937,3 +1295,193 @@ host->port_base + AM65_CPSW_PN_REG_PRI_CIR(tx_ch)); } } + +int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, + void *type_data) +{ + switch (type) { + case TC_QUERY_CAPS: + return am65_cpsw_tc_query_caps(ndev, type_data); + case TC_SETUP_QDISC_TAPRIO: + return am65_cpsw_setup_taprio(ndev, type_data); + case TC_SETUP_QDISC_MQPRIO: + return am65_cpsw_setup_mqprio(ndev, type_data); + case TC_SETUP_BLOCK: + return am65_cpsw_qos_setup_tc_block(ndev, type_data); + default: + return -EOPNOTSUPP; + } +} + +static void am65_cpsw_cut_thru_dump(struct am65_cpsw_port *port) +{ + struct am65_cpsw_common *common = port->common; + u32 contro, cut_thru, speed; + + contro = readl(common->cpsw_base + AM65_CPSW_REG_CTL); + cut_thru = readl(port->port_base + AM64_CPSW_PN_CUT_THRU); + speed = readl(port->port_base + AM64_CPSW_PN_SPEED); + dev_dbg(common->dev, + "Port%u: cut_thru dump control:%08x cut_thru:%08x hwspeed:%08x\n", + port->port_id, contro, cut_thru, speed); +} + +static u32 am65_cpsw_cut_thru_speed2hw(int link_speed) +{ + switch (link_speed) { + case SPEED_10: + return 1; + case SPEED_100: + return 2; + case SPEED_1000: + return 3; + default: + return 0; + } +} + +static void am65_cpsw_cut_thru_link_up(struct am65_cpsw_port *port) +{ + struct am65_cpsw_cut_thru *cut_thru = &port->qos.cut_thru; + struct am65_cpsw_common *common = port->common; + u32 val, speed; + + if (!cut_thru->enable) + return; + + writel(AM64_PN_SPEED_AUTO_EN, port->port_base + AM64_CPSW_PN_SPEED); + /* barrier */ + readl(port->port_base + AM64_CPSW_PN_SPEED); + /* HW need 15us in 10/100 mode and 3us in 1G mode auto speed detection + * add delay with some margin + */ + usleep_range(40, 50); + val = readl(port->port_base + AM64_CPSW_PN_SPEED); + speed = FIELD_GET(AM64_PN_AUTO_SPEED, val); + if (!speed) { + dev_warn(common->dev, + "Port%u: cut_thru no speed auto detected switch to manual\n", + port->port_id); + speed = am65_cpsw_cut_thru_speed2hw(port->qos.link_speed); + if (!speed) { + dev_err(common->dev, + "Port%u: cut_thru speed configuration failed\n", + port->port_id); + return; + } + val = FIELD_PREP(AM64_PN_SPEED_VAL, speed); + writel(val, port->port_base + AM64_CPSW_PN_SPEED); + } + + val = FIELD_PREP(AM64_PN_CUT_THRU_TX_PRI, cut_thru->tx_pri_mask) | + FIELD_PREP(AM64_PN_CUT_THRU_RX_PRI, cut_thru->rx_pri_mask); + + if (port->qos.duplex) { + writel(val, port->port_base + AM64_CPSW_PN_CUT_THRU); + dev_info(common->dev, "Port%u: Enable cut_thru rx:%08x tx:%08x hwspeed:%u (%08x)\n", + port->port_id, + cut_thru->rx_pri_mask, cut_thru->tx_pri_mask, + speed, val); + } else { + writel(0, port->port_base + AM64_CPSW_PN_CUT_THRU); + dev_info(common->dev, "Port%u: Disable cut_thru duplex=%d\n", + port->port_id, port->qos.duplex); + } + am65_cpsw_cut_thru_dump(port); +} + +void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed, int duplex) +{ + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + + port->qos.link_speed = link_speed; + port->qos.duplex = duplex; + am65_cpsw_tx_pn_shaper_apply(port); + am65_cpsw_iet_link_state_update(ndev); + am65_cpsw_cut_thru_link_up(port); + + am65_cpsw_est_link_up(ndev, link_speed); + port->qos.link_down_time = 0; +} + +void am65_cpsw_qos_link_down(struct net_device *ndev) +{ + struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + + port->qos.link_speed = SPEED_UNKNOWN; + am65_cpsw_tx_pn_shaper_apply(port); + am65_cpsw_iet_link_state_update(ndev); + + if (!port->qos.link_down_time) + port->qos.link_down_time = ktime_get(); +} + +static void am65_cpsw_cut_thru_enable(struct am65_cpsw_common *common) +{ + u32 val; + + if (common->cut_thru_enabled) { + common->cut_thru_enabled++; + return; + } + + /* Populate CPSW VBUS freq for auto speed detection */ + writel(common->bus_freq / 1000000, + common->cpsw_base + AM65_CPSW_REG_FREQ); + + val = readl(common->cpsw_base + AM65_CPSW_REG_CTL); + val |= AM64_CPSW_CTL_CUT_THRU_EN; + writel(val, common->cpsw_base + AM65_CPSW_REG_CTL); + common->cut_thru_enabled++; +} + +void am65_cpsw_qos_cut_thru_init(struct am65_cpsw_port *port) +{ + struct am65_cpsw_cut_thru *cut_thru = &port->qos.cut_thru; + struct am65_cpsw_common *common = port->common; + + /* Enable cut_thr only if user has enabled priv flag */ + if (!cut_thru->enable) + return; + + if (common->is_emac_mode) { + cut_thru->enable = false; + dev_info(common->dev, "Disable cut-thru, need Switch mode\n"); + return; + } + + am65_cpsw_cut_thru_enable(common); + + /* en auto speed */ + writel(AM64_PN_SPEED_AUTO_EN, port->port_base + AM64_CPSW_PN_SPEED); + dev_info(common->dev, "Init cut_thru\n"); + am65_cpsw_cut_thru_dump(port); +} + +static void am65_cpsw_cut_thru_disable(struct am65_cpsw_common *common) +{ + u32 val; + + if (--common->cut_thru_enabled) + return; + + val = readl(common->cpsw_base + AM65_CPSW_REG_CTL); + val &= ~AM64_CPSW_CTL_CUT_THRU_EN; + writel(val, common->cpsw_base + AM65_CPSW_REG_CTL); +} + +void am65_cpsw_qos_cut_thru_cleanup(struct am65_cpsw_port *port) +{ + struct am65_cpsw_cut_thru *cut_thru = &port->qos.cut_thru; + struct am65_cpsw_common *common = port->common; + + if (!cut_thru->enable) + return; + + writel(0, port->port_base + AM64_CPSW_PN_CUT_THRU); + writel(0, port->port_base + AM64_CPSW_PN_SPEED); + + am65_cpsw_cut_thru_disable(common); + dev_info(common->dev, "Cleanup cut_thru\n"); + am65_cpsw_cut_thru_dump(port); +} diff -Naur --no-dereference a/drivers/net/ethernet/ti/am65-cpsw-qos.h b/drivers/net/ethernet/ti/am65-cpsw-qos.h --- a/drivers/net/ethernet/ti/am65-cpsw-qos.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/am65-cpsw-qos.h 2024-07-07 20:37:34.668306669 -0400 @@ -9,6 +9,7 @@ #include struct am65_cpsw_common; +struct am65_cpsw_port; struct am65_cpsw_est { int buf; @@ -16,26 +17,227 @@ struct tc_taprio_qopt_offload taprio; }; +struct am65_cpsw_mqprio { + struct tc_mqprio_qopt_offload mqprio_hw; + u64 max_rate_total; + bool shaper_en; +}; + +struct am65_cpsw_iet { + u8 preemptible_tcs; + u32 original_max_blks; + int verify_time_ms; +}; + struct am65_cpsw_ale_ratelimit { unsigned long cookie; u64 rate_packet_ps; }; +struct am65_cpsw_cut_thru { + unsigned int rx_pri_mask; + unsigned int tx_pri_mask; + bool enable; +}; + struct am65_cpsw_qos { struct am65_cpsw_est *est_admin; struct am65_cpsw_est *est_oper; ktime_t link_down_time; int link_speed; + int duplex; + struct am65_cpsw_mqprio mqprio; + struct am65_cpsw_iet iet; + struct am65_cpsw_cut_thru cut_thru; struct am65_cpsw_ale_ratelimit ale_bc_ratelimit; struct am65_cpsw_ale_ratelimit ale_mc_ratelimit; }; +#define AM65_CPSW_REG_CTL 0x004 +#define AM65_CPSW_PN_REG_CTL 0x004 +#define AM65_CPSW_PN_REG_FIFO_STATUS 0x050 +#define AM65_CPSW_PN_REG_EST_CTL 0x060 +#define AM65_CPSW_PN_REG_PRI_CIR(pri) (0x140 + 4 * (pri)) +#define AM65_CPSW_P0_REG_PRI_EIR(pri) (0x160 + 4 * (pri)) + +#define AM65_CPSW_PN_REG_CTL 0x004 +#define AM65_CPSW_PN_REG_TX_PRI_MAP 0x018 +#define AM65_CPSW_PN_REG_RX_PRI_MAP 0x020 +#define AM65_CPSW_PN_REG_FIFO_STATUS 0x050 +#define AM65_CPSW_PN_REG_EST_CTL 0x060 +#define AM65_CPSW_PN_REG_PRI_CIR(pri) (0x140 + 4 * (pri)) +#define AM65_CPSW_PN_REG_PRI_EIR(pri) (0x160 + 4 * (pri)) + +/* AM65_CPSW_REG_CTL register fields */ +#define AM65_CPSW_CTL_EST_EN BIT(18) + +/* AM65_CPSW_PN_REG_CTL register fields */ +#define AM65_CPSW_PN_CTL_EST_PORT_EN BIT(17) + +/* AM65_CPSW_PN_REG_EST_CTL register fields */ +#define AM65_CPSW_PN_EST_ONEBUF BIT(0) +#define AM65_CPSW_PN_EST_BUFSEL BIT(1) +#define AM65_CPSW_PN_EST_TS_EN BIT(2) +#define AM65_CPSW_PN_EST_TS_FIRST BIT(3) +#define AM65_CPSW_PN_EST_ONEPRI BIT(4) +#define AM65_CPSW_PN_EST_TS_PRI_MSK GENMASK(7, 5) + +/* AM65_CPSW_PN_REG_FIFO_STATUS register fields */ +#define AM65_CPSW_PN_FST_TX_PRI_ACTIVE_MSK GENMASK(7, 0) +#define AM65_CPSW_PN_FST_TX_E_MAC_ALLOW_MSK GENMASK(15, 8) +#define AM65_CPSW_PN_FST_EST_CNT_ERR BIT(16) +#define AM65_CPSW_PN_FST_EST_ADD_ERR BIT(17) +#define AM65_CPSW_PN_FST_EST_BUFACT BIT(18) + +/* EST FETCH COMMAND RAM */ +#define AM65_CPSW_FETCH_RAM_CMD_NUM 0x80 +#define AM65_CPSW_FETCH_CNT_MSK GENMASK(21, 8) +#define AM65_CPSW_FETCH_CNT_MAX (AM65_CPSW_FETCH_CNT_MSK >> 8) +#define AM65_CPSW_FETCH_CNT_OFFSET 8 +#define AM65_CPSW_FETCH_ALLOW_MSK GENMASK(7, 0) +#define AM65_CPSW_FETCH_ALLOW_MAX AM65_CPSW_FETCH_ALLOW_MSK + +/* number of priority queues per port FIFO */ +#define AM65_CPSW_PN_FIFO_PRIO_NUM 8 + +#if IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS) int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, void *type_data); -void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed); +void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed, int duplex); void am65_cpsw_qos_link_down(struct net_device *ndev); +void am65_cpsw_qos_cut_thru_init(struct am65_cpsw_port *port); +void am65_cpsw_qos_cut_thru_cleanup(struct am65_cpsw_port *port); int am65_cpsw_qos_ndo_tx_p0_set_maxrate(struct net_device *ndev, int queue, u32 rate_mbps); void am65_cpsw_qos_tx_p0_rate_init(struct am65_cpsw_common *common); +void am65_cpsw_iet_commit_preemptible_tcs(struct am65_cpsw_port *port); +void am65_cpsw_iet_common_enable(struct am65_cpsw_common *common); +#else +static inline int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, + enum tc_setup_type type, + void *type_data) +{ + return -EOPNOTSUPP; +} + +static inline void am65_cpsw_qos_link_up(struct net_device *ndev, + int link_speed, int duplex) +{ } + +static inline void am65_cpsw_qos_link_down(struct net_device *ndev) +{ } + +static inline void am65_cpsw_qos_cut_thru_init(struct am65_cpsw_port *port) +{ } + +static inline void am65_cpsw_qos_cut_thru_cleanup(struct am65_cpsw_port *port) +{ } + +static inline int am65_cpsw_qos_ndo_tx_p0_set_maxrate(struct net_device *ndev, + int queue, + u32 rate_mbps) +{ + return 0; +} + +static inline void am65_cpsw_qos_tx_p0_rate_init(struct am65_cpsw_common *common) +{ } +static inline void am65_cpsw_iet_commit_preemptible_tcs(struct am65_cpsw_port *port) +{ } +static inline void am65_cpsw_iet_common_enable(struct am65_cpsw_common *common) +{ } +#endif + +#define AM65_CPSW_REG_CTL 0x004 +#define AM65_CPSW_PN_REG_CTL 0x004 +#define AM65_CPSW_PN_REG_MAX_BLKS 0x008 +#define AM65_CPSW_PN_REG_TX_PRI_MAP 0x018 +#define AM65_CPSW_PN_REG_RX_PRI_MAP 0x020 +#define AM65_CPSW_PN_REG_IET_CTRL 0x040 +#define AM65_CPSW_PN_REG_IET_STATUS 0x044 +#define AM65_CPSW_PN_REG_IET_VERIFY 0x048 +#define AM65_CPSW_PN_REG_FIFO_STATUS 0x050 +#define AM65_CPSW_PN_REG_EST_CTL 0x060 +#define AM65_CPSW_PN_REG_PRI_CIR(pri) (0x140 + 4 * (pri)) +#define AM65_CPSW_PN_REG_PRI_EIR(pri) (0x160 + 4 * (pri)) + +/* AM65_CPSW_REG_CTL register fields */ +#define AM65_CPSW_CTL_IET_EN BIT(17) +#define AM65_CPSW_CTL_EST_EN BIT(18) + +/* AM65_CPSW_PN_REG_CTL register fields */ +#define AM65_CPSW_PN_CTL_IET_PORT_EN BIT(16) +#define AM65_CPSW_PN_CTL_EST_PORT_EN BIT(17) + +/* AM65_CPSW_PN_REG_EST_CTL register fields */ +#define AM65_CPSW_PN_EST_ONEBUF BIT(0) +#define AM65_CPSW_PN_EST_BUFSEL BIT(1) +#define AM65_CPSW_PN_EST_TS_EN BIT(2) +#define AM65_CPSW_PN_EST_TS_FIRST BIT(3) +#define AM65_CPSW_PN_EST_ONEPRI BIT(4) +#define AM65_CPSW_PN_EST_TS_PRI_MSK GENMASK(7, 5) + +/* AM65_CPSW_PN_REG_IET_CTRL register fields */ +#define AM65_CPSW_PN_IET_MAC_PENABLE BIT(0) +#define AM65_CPSW_PN_IET_MAC_DISABLEVERIFY BIT(2) +#define AM65_CPSW_PN_IET_MAC_LINKFAIL BIT(3) +#define AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK GENMASK(10, 8) +#define AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_OFFSET 8 +#define AM65_CPSW_PN_IET_MAC_PREMPT_MASK GENMASK(23, 16) +#define AM65_CPSW_PN_IET_MAC_PREMPT_OFFSET 16 + +#define AM65_CPSW_PN_IET_MAC_SET_ADDFRAGSIZE(n) (((n) << AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_OFFSET) & \ + AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK) +#define AM65_CPSW_PN_IET_MAC_GET_ADDFRAGSIZE(n) (((n) & AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK) >> \ + AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_OFFSET) +#define AM65_CPSW_PN_IET_MAC_SET_PREEMPT(n) (((n) << AM65_CPSW_PN_IET_MAC_PREMPT_OFFSET) & \ + AM65_CPSW_PN_IET_MAC_PREMPT_MASK) +#define AM65_CPSW_PN_IET_MAC_GET_PREEMPT(n) (((n) & AM65_CPSW_PN_IET_MAC_PREMPT_MASK) >> \ + AM65_CPSW_PN_IET_MAC_PREMPT_OFFSET) + +/* AM65_CPSW_PN_REG_IET_STATUS register fields */ +#define AM65_CPSW_PN_MAC_STATUS GENMASK(3, 0) +#define AM65_CPSW_PN_MAC_VERIFIED BIT(0) +#define AM65_CPSW_PN_MAC_VERIFY_FAIL BIT(1) +#define AM65_CPSW_PN_MAC_RESPOND_ERR BIT(2) +#define AM65_CPSW_PN_MAC_VERIFY_ERR BIT(3) + +/* AM65_CPSW_PN_REG_IET_VERIFY register fields */ +#define AM65_CPSW_PN_MAC_VERIFY_CNT_MASK GENMASK(23, 0) +#define AM65_CPSW_PN_MAC_GET_VERIFY_CNT(n) ((n) & AM65_CPSW_PN_MAC_VERIFY_CNT_MASK) +/* 10 msec converted to NSEC */ +#define AM65_CPSW_IET_VERIFY_CNT_MS (10) +#define AM65_CPSW_IET_VERIFY_CNT_NS (AM65_CPSW_IET_VERIFY_CNT_MS * \ + NSEC_PER_MSEC) + +/* AM65_CPSW_PN_REG_FIFO_STATUS register fields */ +#define AM65_CPSW_PN_FST_TX_PRI_ACTIVE_MSK GENMASK(7, 0) +#define AM65_CPSW_PN_FST_TX_E_MAC_ALLOW_MSK GENMASK(15, 8) +#define AM65_CPSW_PN_FST_EST_CNT_ERR BIT(16) +#define AM65_CPSW_PN_FST_EST_ADD_ERR BIT(17) +#define AM65_CPSW_PN_FST_EST_BUFACT BIT(18) + +/* EST FETCH COMMAND RAM */ +#define AM65_CPSW_FETCH_RAM_CMD_NUM 0x80 +#define AM65_CPSW_FETCH_CNT_MSK GENMASK(21, 8) +#define AM65_CPSW_FETCH_CNT_MAX (AM65_CPSW_FETCH_CNT_MSK >> 8) +#define AM65_CPSW_FETCH_CNT_OFFSET 8 +#define AM65_CPSW_FETCH_ALLOW_MSK GENMASK(7, 0) +#define AM65_CPSW_FETCH_ALLOW_MAX AM65_CPSW_FETCH_ALLOW_MSK + +/* AM65_CPSW_PN_REG_MAX_BLKS fields for IET and No IET cases */ +/* 7 blocks for pn_rx_max_blks, 13 for pn_tx_max_blks*/ +#define AM65_CPSW_PN_TX_RX_MAX_BLKS_IET 0xD07 + +/* Slave IET Stats. register offsets */ +#define AM65_CPSW_STATN_IET_RX_ASSEMBLY_ERROR 0x140 +#define AM65_CPSW_STATN_IET_RX_ASSEMBLY_OK 0x144 +#define AM65_CPSW_STATN_IET_RX_SMD_ERROR 0x148 +#define AM65_CPSW_STATN_IET_RX_FRAG 0x14c +#define AM65_CPSW_STATN_IET_TX_HOLD 0x150 +#define AM65_CPSW_STATN_IET_TX_FRAG 0x154 + +/* number of priority queues per port FIFO */ +#define AM65_CPSW_PN_FIFO_PRIO_NUM 8 #endif /* AM65_CPSW_QOS_H_ */ diff -Naur --no-dereference a/drivers/net/ethernet/ti/am65-cpts.c b/drivers/net/ethernet/ti/am65-cpts.c --- a/drivers/net/ethernet/ti/am65-cpts.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/am65-cpts.c 2024-07-07 20:37:34.668306669 -0400 @@ -275,15 +275,13 @@ return true; } -static int am65_cpts_fifo_read(struct am65_cpts *cpts) +static int __am65_cpts_fifo_read(struct am65_cpts *cpts) { struct ptp_clock_event pevent; struct am65_cpts_event *event; bool schedule = false; int i, type, ret = 0; - unsigned long flags; - spin_lock_irqsave(&cpts->lock, flags); for (i = 0; i < AM65_CPTS_FIFO_DEPTH; i++) { event = list_first_entry_or_null(&cpts->pool, struct am65_cpts_event, list); @@ -312,8 +310,7 @@ event->tmo = jiffies + msecs_to_jiffies(AM65_CPTS_EVENT_RX_TX_TIMEOUT); - list_del_init(&event->list); - list_add_tail(&event->list, &cpts->events); + list_move_tail(&event->list, &cpts->events); dev_dbg(cpts->dev, "AM65_CPTS_EV_TX e1:%08x e2:%08x t:%lld\n", @@ -356,14 +353,24 @@ } out: - spin_unlock_irqrestore(&cpts->lock, flags); - if (schedule) ptp_schedule_worker(cpts->ptp_clock, 0); return ret; } +static int am65_cpts_fifo_read(struct am65_cpts *cpts) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&cpts->lock, flags); + ret = __am65_cpts_fifo_read(cpts); + spin_unlock_irqrestore(&cpts->lock, flags); + + return ret; +} + static u64 am65_cpts_gettime(struct am65_cpts *cpts, struct ptp_system_timestamp *sts) { @@ -864,29 +871,6 @@ return delay; } -/** - * am65_cpts_rx_enable - enable rx timestamping - * @cpts: cpts handle - * @en: enable - * - * This functions enables rx packets timestamping. The CPTS can timestamp all - * rx packets. - */ -void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en) -{ - u32 val; - - mutex_lock(&cpts->ptp_clk_lock); - val = am65_cpts_read32(cpts, control); - if (en) - val |= AM65_CPTS_CONTROL_TSTAMP_EN; - else - val &= ~AM65_CPTS_CONTROL_TSTAMP_EN; - am65_cpts_write32(cpts, val, control); - mutex_unlock(&cpts->ptp_clk_lock); -} -EXPORT_SYMBOL_GPL(am65_cpts_rx_enable); - static int am65_skb_get_mtype_seqid(struct sk_buff *skb, u32 *mtype_seqid) { unsigned int ptp_class = ptp_classify_raw(skb); @@ -911,6 +895,69 @@ return 1; } +static u64 am65_cpts_find_rx_ts(struct am65_cpts *cpts, u32 skb_mtype_seqid) +{ + struct list_head *this, *next; + struct am65_cpts_event *event; + unsigned long flags; + u32 mtype_seqid; + u64 ns = 0; + + spin_lock_irqsave(&cpts->lock, flags); + __am65_cpts_fifo_read(cpts); + list_for_each_safe(this, next, &cpts->events) { + event = list_entry(this, struct am65_cpts_event, list); + if (time_after(jiffies, event->tmo)) { + list_move(&event->list, &cpts->pool); + continue; + } + + mtype_seqid = event->event1 & + (AM65_CPTS_EVENT_1_MESSAGE_TYPE_MASK | + AM65_CPTS_EVENT_1_SEQUENCE_ID_MASK | + AM65_CPTS_EVENT_1_EVENT_TYPE_MASK); + + if (mtype_seqid == skb_mtype_seqid) { + ns = event->timestamp; + list_move(&event->list, &cpts->pool); + break; + } + } + spin_unlock_irqrestore(&cpts->lock, flags); + + return ns; +} + +void am65_cpts_rx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb) +{ + struct am65_cpts_skb_cb_data *skb_cb = (struct am65_cpts_skb_cb_data *)skb->cb; + struct skb_shared_hwtstamps *ssh; + int ret; + u64 ns; + + /* am65_cpts_rx_timestamp() is called before eth_type_trans(), so + * skb MAC Hdr properties are not configured yet. Hence need to + * reset skb MAC header here + */ + skb_reset_mac_header(skb); + ret = am65_skb_get_mtype_seqid(skb, &skb_cb->skb_mtype_seqid); + if (!ret) + return; /* if not PTP class packet */ + + skb_cb->skb_mtype_seqid |= (AM65_CPTS_EV_RX << AM65_CPTS_EVENT_1_EVENT_TYPE_SHIFT); + + dev_dbg(cpts->dev, "%s mtype seqid %08x\n", __func__, skb_cb->skb_mtype_seqid); + + ns = am65_cpts_find_rx_ts(cpts, skb_cb->skb_mtype_seqid); + if (!ns) + return; + + ssh = skb_hwtstamps(skb); + memset(ssh, 0, sizeof(*ssh)); + ssh->hwtstamp = ns_to_ktime(ns); +} +EXPORT_SYMBOL_GPL(am65_cpts_rx_timestamp); + /** * am65_cpts_tx_timestamp - save tx packet for timestamping * @cpts: cpts handle diff -Naur --no-dereference a/drivers/net/ethernet/ti/am65-cpts.h b/drivers/net/ethernet/ti/am65-cpts.h --- a/drivers/net/ethernet/ti/am65-cpts.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/am65-cpts.h 2024-07-07 20:37:34.668306669 -0400 @@ -22,9 +22,9 @@ struct am65_cpts *am65_cpts_create(struct device *dev, void __iomem *regs, struct device_node *node); int am65_cpts_phc_index(struct am65_cpts *cpts); +void am65_cpts_rx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb); void am65_cpts_tx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb); void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb); -void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en); u64 am65_cpts_ns_gettime(struct am65_cpts *cpts); int am65_cpts_estf_enable(struct am65_cpts *cpts, int idx, struct am65_cpts_estf_cfg *cfg); @@ -48,17 +48,18 @@ return -1; } -static inline void am65_cpts_tx_timestamp(struct am65_cpts *cpts, +static inline void am65_cpts_rx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb) { } -static inline void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts, - struct sk_buff *skb) +static inline void am65_cpts_tx_timestamp(struct am65_cpts *cpts, + struct sk_buff *skb) { } -static inline void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en) +static inline void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts, + struct sk_buff *skb) { } diff -Naur --no-dereference a/drivers/net/ethernet/ti/am65-debugfs.c b/drivers/net/ethernet/ti/am65-debugfs.c --- a/drivers/net/ethernet/ti/am65-debugfs.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/ethernet/ti/am65-debugfs.c 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Texas Instruments K3 AM65 Ethernet debugfs submodule + * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +#include +#include + +#include "am65-cpsw-nuss.h" + +int am65_cpsw_nuss_register_debugfs(struct am65_cpsw_common *common) +{ + common->debugfs_root = debugfs_create_dir(dev_name(common->dev), NULL); + if (IS_ERR(common->debugfs_root)) + return PTR_ERR(common->debugfs_root); + + return 0; +} + +void am65_cpsw_nuss_unregister_debugfs(struct am65_cpsw_common *common) +{ + debugfs_remove_recursive(common->debugfs_root); +} + +static int +cut_thru_tx_pri_mask_get(void *data, u64 *val) +{ + struct am65_cpsw_port *port = data; + struct am65_cpsw_cut_thru *cut_thru; + int ret = -EINVAL; + + read_lock(&dev_base_lock); + cut_thru = &port->qos.cut_thru; + if (port->ndev->reg_state == NETREG_REGISTERED) { + *val = cut_thru->tx_pri_mask; + ret = 0; + } + read_unlock(&dev_base_lock); + + return ret; +} + +static int +cut_thru_tx_pri_mask_set(void *data, u64 val) +{ + struct am65_cpsw_cut_thru *cut_thru; + struct am65_cpsw_port *port = data; + struct am65_cpsw_common *common; + int ret = 0; + + if (val & ~GENMASK(7, 0)) + return -EINVAL; + + if (!rtnl_trylock()) + return restart_syscall(); + + common = port->common; + cut_thru = &port->qos.cut_thru; + + if (cut_thru->enable) { + dev_err(common->dev, "Port%u: can't set cut-thru tx_pri_mask while cut-thru enabled\n", + port->port_id); + ret = -EINVAL; + goto err; + } + cut_thru->tx_pri_mask = val; + +err: + rtnl_unlock(); + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_cut_thru_tx_pri_mask, cut_thru_tx_pri_mask_get, + cut_thru_tx_pri_mask_set, "%llx\n"); + +static int +cut_thru_rx_pri_mask_get(void *data, u64 *val) +{ + struct am65_cpsw_port *port = data; + struct am65_cpsw_cut_thru *cut_thru; + int ret = -EINVAL; + + read_lock(&dev_base_lock); + cut_thru = &port->qos.cut_thru; + if (port->ndev->reg_state == NETREG_REGISTERED) { + *val = cut_thru->rx_pri_mask; + ret = 0; + } + read_unlock(&dev_base_lock); + + return ret; +} + +static int +cut_thru_rx_pri_mask_set(void *data, u64 val) +{ + struct am65_cpsw_cut_thru *cut_thru; + struct am65_cpsw_port *port = data; + struct am65_cpsw_common *common; + int ret = 0; + + if (val & ~GENMASK(7, 0)) + return -EINVAL; + + if (!rtnl_trylock()) + return restart_syscall(); + + common = port->common; + cut_thru = &port->qos.cut_thru; + + if (cut_thru->enable) { + dev_err(common->dev, "Port%u: can't set cut-thru rx_pri_mask while cut-thru enabled\n", + port->port_id); + ret = -EINVAL; + goto err; + } + cut_thru->rx_pri_mask = val; + +err: + rtnl_unlock(); + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_cut_thru_rx_pri_mask, cut_thru_rx_pri_mask_get, + cut_thru_rx_pri_mask_set, "%llx\n"); + +int am65_cpsw_nuss_register_port_debugfs(struct am65_cpsw_port *port) +{ + struct am65_cpsw_common *common = port->common; + char dirn[32]; + + scnprintf(dirn, sizeof(dirn), "Port%x", port->port_id); + port->debugfs_port = debugfs_create_dir(dirn, common->debugfs_root); + if (IS_ERR(port->debugfs_port)) + return PTR_ERR(port->debugfs_port); + + debugfs_create_bool("disabled", 0400, + port->debugfs_port, &port->disabled); + if (port->disabled) + return 0; + + if (common->pdata.quirks & AM64_CPSW_QUIRK_CUT_THRU) { + debugfs_create_file("cut_thru_tx_pri_mask", 0600, + port->debugfs_port, + port, &fops_cut_thru_tx_pri_mask); + debugfs_create_file("cut_thru_rx_pri_mask", 0600, + port->debugfs_port, + port, &fops_cut_thru_rx_pri_mask); + } + + return 0; +} diff -Naur --no-dereference a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c --- a/drivers/net/ethernet/ti/cpsw.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/cpsw.c 2024-07-07 20:37:34.668306669 -0400 @@ -1724,14 +1724,20 @@ return ret; } -static int cpsw_remove(struct platform_device *pdev) +static void cpsw_remove(struct platform_device *pdev) { struct cpsw_common *cpsw = platform_get_drvdata(pdev); int i, ret; ret = pm_runtime_resume_and_get(&pdev->dev); - if (ret < 0) - return ret; + if (ret < 0) { + /* Note, if this error path is taken, we're leaking some + * resources. + */ + dev_err(&pdev->dev, "Failed to resume device (%pe)\n", + ERR_PTR(ret)); + return; + } for (i = 0; i < cpsw->data.slaves; i++) if (cpsw->slaves[i].ndev) @@ -1742,7 +1748,6 @@ cpsw_remove_dt(pdev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -1797,7 +1802,7 @@ .of_match_table = cpsw_of_mtable, }, .probe = cpsw_probe, - .remove = cpsw_remove, + .remove_new = cpsw_remove, }; module_platform_driver(cpsw_driver); diff -Naur --no-dereference a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c --- a/drivers/net/ethernet/ti/cpsw_new.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/cpsw_new.c 2024-07-07 20:37:34.668306669 -0400 @@ -2040,14 +2040,20 @@ return ret; } -static int cpsw_remove(struct platform_device *pdev) +static void cpsw_remove(struct platform_device *pdev) { struct cpsw_common *cpsw = platform_get_drvdata(pdev); int ret; ret = pm_runtime_resume_and_get(&pdev->dev); - if (ret < 0) - return ret; + if (ret < 0) { + /* Note, if this error path is taken, we're leaking some + * resources. + */ + dev_err(&pdev->dev, "Failed to resume device (%pe)\n", + ERR_PTR(ret)); + return; + } cpsw_unregister_notifiers(cpsw); cpsw_unregister_devlink(cpsw); @@ -2058,7 +2064,6 @@ cpsw_remove_dt(cpsw); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - return 0; } static int __maybe_unused cpsw_suspend(struct device *dev) @@ -2119,7 +2124,7 @@ .of_match_table = cpsw_of_mtable, }, .probe = cpsw_probe, - .remove = cpsw_remove, + .remove_new = cpsw_remove, }; module_platform_driver(cpsw_driver); diff -Naur --no-dereference a/drivers/net/ethernet/ti/cpsw-proxy-client.c b/drivers/net/ethernet/ti/cpsw-proxy-client.c --- a/drivers/net/ethernet/ti/cpsw-proxy-client.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/ethernet/ti/cpsw-proxy-client.c 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,2464 @@ +// SPDX-License-Identifier: GPL-2.0-only or MIT +/* Texas Instruments CPSW Proxy Client Driver + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ethfw_abi.h" +#include "k3-cppi-desc-pool.h" + +#define ETHFW_RESPONSE_TIMEOUT_MS 500 + +#define PS_DATA_SIZE 16 +#define SW_DATA_SIZE 16 + +#define MAX_TX_DESC 500 +#define MAX_RX_DESC 500 +#define MAX_RX_FLOWS 1 + +#define MIN_PACKET_SIZE ETH_ZLEN +#define MAX_PACKET_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) + +#define CHAN_NAME_LEN 128 + +enum virtual_port_type { + VIRT_SWITCH_PORT, + VIRT_MAC_ONLY_PORT, +}; + +struct cpsw_proxy_req_params { + struct message req_msg; /* Request message to be filled */ + u32 token; + u32 client_id; + u32 request_id; + u32 request_type; + u32 rx_tx_idx; /* RX or TX Channel index */ + u32 rx_flow_base; /* RX DMA Flow base */ + u32 rx_flow_offset; /* RX DMA Flow offset */ + u32 tx_thread_id; /* PSI-L Thread ID of TX Channel */ + u32 port_id; /* Virtual Port ID */ + u16 vlan_id; + u8 mac_addr[ETH_ALEN]; + u8 ipv4_addr[ETHFW_IPV4ADDRLEN]; +}; + +struct rx_dma_chan { + struct virtual_port *vport; + struct device *dev; + struct k3_cppi_desc_pool *desc_pool; + struct k3_udma_glue_rx_channel *rx_chan; + struct napi_struct napi_rx; + struct hrtimer rx_hrtimer; + u32 rel_chan_idx; + u32 flow_base; + u32 flow_offset; + u32 thread_id; + u32 num_descs; + unsigned int irq; + unsigned long rx_pace_timeout; + char rx_chan_name[CHAN_NAME_LEN]; + bool rx_irq_disabled; + bool in_use; +}; + +struct tx_dma_chan { + struct virtual_port *vport; + struct device *dev; + struct k3_cppi_desc_pool *desc_pool; + struct k3_udma_glue_tx_channel *tx_chan; + struct napi_struct napi_tx; + struct hrtimer tx_hrtimer; + u32 rel_chan_idx; + u32 thread_id; + u32 num_descs; + unsigned int irq; + unsigned long tx_pace_timeout; + char tx_chan_name[CHAN_NAME_LEN]; + bool in_use; +}; + +struct vport_netdev_stats { + u64 tx_packets; + u64 tx_bytes; + u64 rx_packets; + u64 rx_bytes; + struct u64_stats_sync syncp; +}; + +struct vport_netdev_priv { + struct vport_netdev_stats __percpu *stats; + struct virtual_port *vport; +}; + +struct virtual_port { + struct cpsw_proxy_priv *proxy_priv; + struct net_device *ndev; + struct rx_dma_chan *rx_chans; + struct tx_dma_chan *tx_chans; + struct netdev_hw_addr_list mcast_list; + struct workqueue_struct *vport_wq; + struct work_struct rx_mode_work; + struct completion tdown_complete; + struct notifier_block inetaddr_nb; + enum virtual_port_type port_type; + atomic_t tdown_cnt; + u32 port_id; + u32 port_token; + u32 port_features; + u32 num_rx_chan; + u32 num_tx_chan; + u8 ipv4_addr[ETHFW_IPV4ADDRLEN]; + u8 mac_addr[ETH_ALEN]; + bool mac_in_use; +}; + +struct cpsw_proxy_priv { + struct rpmsg_device *rpdev; + struct device *dev; + struct device_node *dma_node; + struct virtual_port *virt_ports; + struct cpsw_proxy_req_params req_params; + struct mutex req_params_mutex; /* Request params mutex */ + struct message resp_msg; + struct completion wait_for_response; + int resp_msg_len; + u32 vswitch_ports; /* Bitmask of Virtual Switch Port IDs */ + u32 vmac_ports /* Bitmask of Virtual MAC Only Port IDs */; + u32 num_switch_ports; + u32 num_mac_ports; + u32 num_virt_ports; + u32 num_active_tx_chans; + u32 num_active_rx_chans; +}; + +#define vport_netdev_to_priv(ndev) \ + ((struct vport_netdev_priv *)netdev_priv(ndev)) +#define vport_ndev_to_vport(ndev) \ + (vport_netdev_to_priv(ndev)->vport) + +static int send_request_get_response(struct cpsw_proxy_priv *proxy_priv, + struct message *response); +static int server_recovery_handler(void *data) +{ + struct virtual_port *vport = (struct virtual_port *)data; + struct net_device *ndev; + + ndev = vport->ndev; + netif_device_attach(ndev); + if (!netif_running(ndev)) { + rtnl_lock(); + dev_open(ndev, NULL); + rtnl_unlock(); + } + + return 0; +} + +static int server_error_handler(void *data) +{ + struct virtual_port *vport = (struct virtual_port *)data; + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct cpsw_proxy_req_params *req_p; + struct net_device *ndev; + struct message resp_msg; + int ret; + + ndev = vport->ndev; + netif_device_detach(ndev); + if (netif_running(ndev)) { + rtnl_lock(); + dev_close(ndev); + rtnl_unlock(); + } + + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_TEARDOWN_COMPLETE; + req_p->token = vport->port_token; + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + + if (ret) { + dev_err(proxy_priv->dev, + "Virt Port: %u teardown completion notify err: %d\n", + vport->port_id, ret); + return ret; + } + + return 0; +} + +static struct virtual_port *vport_from_token(struct cpsw_proxy_priv *proxy_priv, u32 token) +{ + struct virtual_port *vport; + u32 i; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + + if (vport->port_token == token) + return vport; + } + + return NULL; +} + +static int cpsw_proxy_client_cb(struct rpmsg_device *rpdev, void *data, + int len, void *priv, u32 src) +{ + struct cpsw_proxy_priv *proxy_priv = dev_get_drvdata(&rpdev->dev); + struct response_message_header *resp_msg_hdr; + struct notify_message_header *notify_msg_hdr; + struct message *msg = (struct message *)data; + struct task_struct *server_notify_handler; + struct cpsw_proxy_req_params *req_params; + struct device *dev = &rpdev->dev; + struct virtual_port *vport; + u32 notify_type, token; + u32 msg_type, resp_id; + + dev_dbg(dev, "callback invoked\n"); + msg_type = msg->msg_hdr.msg_type; + switch (msg_type) { + case ETHFW_MSG_NOTIFY: + notify_msg_hdr = (struct notify_message_header *)msg; + notify_type = notify_msg_hdr->notify_type; + token = notify_msg_hdr->msg_hdr.token; + vport = vport_from_token(proxy_priv, token); + if (!vport) { + dev_err(dev, "invalid notification received\n"); + return -EIO; + } + + switch (notify_type) { + case ETHFW_NOTIFYCLIENT_HWERROR: + server_notify_handler = kthread_run(&server_error_handler, vport, + "hwerr_handler"); + if (IS_ERR(server_notify_handler)) + return PTR_ERR(server_notify_handler); + return 0; + + case ETHFW_NOTIFYCLIENT_RECOVERED: + server_notify_handler = kthread_run(&server_recovery_handler, vport, + "recovery_handler"); + if (IS_ERR(server_notify_handler)) + return PTR_ERR(server_notify_handler); + return 0; + + default: + dev_err(dev, "invalid notification received\n"); + return -EIO; + } + + case ETHFW_MSG_RESPONSE: + resp_msg_hdr = (struct response_message_header *)msg; + resp_id = resp_msg_hdr->response_id; + req_params = &proxy_priv->req_params; + + if (unlikely(resp_id == req_params->request_id - 1)) { + dev_info(dev, "ignoring late response for request: %u\n", + resp_id); + return 0; + } else if (unlikely(resp_id != req_params->request_id)) { + dev_err(dev, "expected response id: %u but received %u\n", + req_params->request_id, resp_id); + return -EINVAL; + } + + /* Share response */ + memcpy(&proxy_priv->resp_msg, msg, len); + proxy_priv->resp_msg_len = len; + complete(&proxy_priv->wait_for_response); + return 0; + + default: + dev_err(dev, "unsupported message received from EthFw\n"); + return -EOPNOTSUPP; + } +} + +static int create_request_message(struct cpsw_proxy_req_params *req_params) +{ + struct mac_register_deregister_request *mac_reg_dereg_req; + struct ipv4_deregister_request *ipv4_dereg_req; + struct common_request_message *common_req_msg; + struct tx_thread_release_request *tx_free_req; + struct tx_thread_alloc_request *tx_alloc_req; + struct add_multicast_request *mcast_add_req; + struct del_multicast_request *mcast_del_req; + struct rx_flow_release_request *rx_free_req; + struct ipv4_register_request *ipv4_reg_req; + struct request_message_header *req_msg_hdr; + struct rx_flow_alloc_request *rx_alloc_req; + struct message *msg = &req_params->req_msg; + struct mac_release_request *mac_free_req; + struct attach_request *attach_req; + u32 req_type; + + /* Set message header fields */ + msg->msg_hdr.token = req_params->token; + msg->msg_hdr.client_id = req_params->client_id; + msg->msg_hdr.msg_type = ETHFW_MSG_REQUEST; + + req_type = req_params->request_type; + + switch (req_type) { + case ETHFW_ALLOC_RX: + rx_alloc_req = (struct rx_flow_alloc_request *)msg; + req_msg_hdr = &rx_alloc_req->request_msg_hdr; + rx_alloc_req->rx_flow_idx = req_params->rx_tx_idx; + break; + + case ETHFW_ALLOC_TX: + tx_alloc_req = (struct tx_thread_alloc_request *)msg; + req_msg_hdr = &tx_alloc_req->request_msg_hdr; + tx_alloc_req->tx_chan_idx = req_params->rx_tx_idx; + break; + + case ETHFW_VIRT_PORT_ATTACH: + attach_req = (struct attach_request *)msg; + req_msg_hdr = &attach_req->request_msg_hdr; + attach_req->virt_port = req_params->port_id; + break; + + case ETHFW_FREE_MAC: + mac_free_req = (struct mac_release_request *)msg; + req_msg_hdr = &mac_free_req->request_msg_hdr; + ether_addr_copy(mac_free_req->mac_addr, req_params->mac_addr); + break; + + case ETHFW_FREE_RX: + rx_free_req = (struct rx_flow_release_request *)msg; + req_msg_hdr = &rx_free_req->request_msg_hdr; + rx_free_req->rx_flow_idx_base = req_params->rx_flow_base; + rx_free_req->rx_flow_idx_offset = req_params->rx_flow_offset; + break; + + case ETHFW_FREE_TX: + tx_free_req = (struct tx_thread_release_request *)msg; + req_msg_hdr = &tx_free_req->request_msg_hdr; + tx_free_req->tx_psil_dest_id = req_params->tx_thread_id; + break; + + case ETHFW_IPv4_DEREGISTER: + ipv4_dereg_req = (struct ipv4_deregister_request *)msg; + req_msg_hdr = &ipv4_dereg_req->request_msg_hdr; + memcpy(&ipv4_dereg_req->ipv4_addr, req_params->ipv4_addr, + ETHFW_IPV4ADDRLEN); + break; + + case ETHFW_IPv4_REGISTER: + ipv4_reg_req = (struct ipv4_register_request *)msg; + req_msg_hdr = &ipv4_reg_req->request_msg_hdr; + memcpy(&ipv4_reg_req->ipv4_addr, req_params->ipv4_addr, + ETHFW_IPV4ADDRLEN); + ether_addr_copy(ipv4_reg_req->mac_addr, + req_params->mac_addr); + break; + + case ETHFW_MAC_DEREGISTER: + case ETHFW_MAC_REGISTER: + mac_reg_dereg_req = (struct mac_register_deregister_request *)msg; + req_msg_hdr = &mac_reg_dereg_req->request_msg_hdr; + ether_addr_copy(mac_reg_dereg_req->mac_addr, + req_params->mac_addr); + mac_reg_dereg_req->rx_flow_idx_base = req_params->rx_flow_base; + mac_reg_dereg_req->rx_flow_idx_offset = req_params->rx_flow_offset; + break; + + case ETHFW_MCAST_FILTER_ADD: + mcast_add_req = (struct add_multicast_request *)msg; + req_msg_hdr = &mcast_add_req->request_msg_hdr; + ether_addr_copy(mcast_add_req->mac_addr, req_params->mac_addr); + mcast_add_req->vlan_id = req_params->vlan_id; + mcast_add_req->rx_flow_idx_base = req_params->rx_flow_base; + mcast_add_req->rx_flow_idx_offset = req_params->rx_flow_offset; + break; + + case ETHFW_MCAST_FILTER_DEL: + mcast_del_req = (struct del_multicast_request *)msg; + req_msg_hdr = &mcast_del_req->request_msg_hdr; + ether_addr_copy(mcast_del_req->mac_addr, req_params->mac_addr); + mcast_del_req->vlan_id = req_params->vlan_id; + break; + + case ETHFW_ALLOC_MAC: + case ETHFW_TEARDOWN_COMPLETE: + case ETHFW_VIRT_PORT_DETACH: + case ETHFW_VIRT_PORT_INFO: + case ETHFW_VIRT_PORT_LINK_STATUS: + common_req_msg = (struct common_request_message *)msg; + req_msg_hdr = &common_req_msg->request_msg_hdr; + break; + + default: + return -EOPNOTSUPP; + } + + /* Set request message header fields */ + req_msg_hdr->request_id = req_params->request_id; + req_msg_hdr->request_type = req_params->request_type; + + return 0; +} + +/* Send a request to EthFw and receive the response for request. + * Since the response is received by the callback function, it is + * copied to "resp_msg" member of "struct cpsw_proxy_priv" to + * allow sharing it with the following function. + * + * The request parameters within proxy_priv are expected to be set + * correctly by the caller. The caller is also expected to acquire + * lock before invoking this function, since requests and responses + * to/from EthFw are serialized. + */ +static int send_request_get_response(struct cpsw_proxy_priv *proxy_priv, + struct message *response) +{ + struct cpsw_proxy_req_params *req_params = &proxy_priv->req_params; + struct message *send_msg = &req_params->req_msg; + struct rpmsg_device *rpdev = proxy_priv->rpdev; + struct response_message_header *resp_msg_hdr; + struct device *dev = proxy_priv->dev; + unsigned long timeout; + u32 resp_status; + int ret; + + ret = create_request_message(req_params); + if (ret) { + dev_err(dev, "failed to create request %d\n", ret); + goto err; + } + + /* Send request and wait for callback function to acknowledge + * receiving the response. + */ + reinit_completion(&proxy_priv->wait_for_response); + ret = rpmsg_send(rpdev->ept, (void *)(send_msg), + sizeof(struct message)); + if (ret) { + dev_err(dev, "failed to send rpmsg\n"); + goto err; + } + timeout = msecs_to_jiffies(ETHFW_RESPONSE_TIMEOUT_MS); + ret = wait_for_completion_timeout(&proxy_priv->wait_for_response, + timeout); + if (!ret) { + dev_err(dev, "response timedout\n"); + ret = -ETIMEDOUT; + goto err; + } + + /* Store response shared by callback function */ + memcpy(response, &proxy_priv->resp_msg, proxy_priv->resp_msg_len); + resp_msg_hdr = (struct response_message_header *)response; + resp_status = resp_msg_hdr->response_status; + ret = resp_status; + + /* For all return values other than ETHFW_RES_EFAIL, the caller + * is expected to check the return value to deal with the failure + * accordingly. + */ + if (unlikely(resp_status == ETHFW_RES_EFAIL)) { + dev_err(dev, "bad response status: %d\n", resp_status); + ret = -EIO; + } + +err: + req_params->request_id++; + return ret; +} + +static int get_virtual_port_info(struct cpsw_proxy_priv *proxy_priv) +{ + struct virt_port_info_response *vpi_resp; + struct cpsw_proxy_req_params *req_p; + struct virtual_port *vport; + struct message resp_msg; + unsigned int vp_id, i; + int ret; + + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_VIRT_PORT_INFO; + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + + if (ret) { + dev_err(proxy_priv->dev, "failed to get virtual port info\n"); + return ret; + } + + vpi_resp = (struct virt_port_info_response *)&resp_msg; + proxy_priv->vswitch_ports = vpi_resp->switch_port_mask; + proxy_priv->vmac_ports = vpi_resp->mac_port_mask; + /* Number of 1s set in vswitch_ports is the count of switch ports */ + proxy_priv->num_switch_ports = hweight32(proxy_priv->vswitch_ports); + proxy_priv->num_virt_ports = proxy_priv->num_switch_ports; + /* Number of 1s set in vmac_ports is the count of mac ports */ + proxy_priv->num_mac_ports = hweight32(proxy_priv->vmac_ports); + proxy_priv->num_virt_ports += proxy_priv->num_mac_ports; + + proxy_priv->virt_ports = devm_kcalloc(proxy_priv->dev, + proxy_priv->num_virt_ports, + sizeof(*proxy_priv->virt_ports), + GFP_KERNEL); + + vp_id = 0; + for (i = 0; i < proxy_priv->num_switch_ports; i++) { + vport = &proxy_priv->virt_ports[vp_id]; + vport->proxy_priv = proxy_priv; + vport->port_type = VIRT_SWITCH_PORT; + /* Port ID is derived from the bit set in the bitmask */ + vport->port_id = fns(proxy_priv->vswitch_ports, i); + vp_id++; + } + + for (i = 0; i < proxy_priv->num_mac_ports; i++) { + vport = &proxy_priv->virt_ports[vp_id]; + vport->proxy_priv = proxy_priv; + vport->port_type = VIRT_MAC_ONLY_PORT; + /* Port ID is derived from the bit set in the bitmask */ + vport->port_id = fns(proxy_priv->vmac_ports, i); + vp_id++; + } + + return 0; +} + +static int attach_virtual_ports(struct cpsw_proxy_priv *proxy_priv) +{ + struct cpsw_proxy_req_params *req_p; + struct attach_response *att_resp; + struct rx_dma_chan *rx_chn; + struct tx_dma_chan *tx_chn; + struct virtual_port *vport; + struct message resp_msg; + unsigned int i, j; + u32 port_id; + int ret; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + port_id = vport->port_id; + + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->port_id = port_id; + req_p->request_type = ETHFW_VIRT_PORT_ATTACH; + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + + if (ret) { + dev_err(proxy_priv->dev, "attaching virtual port failed\n"); + goto err; + } + + att_resp = (struct attach_response *)&resp_msg; + vport->port_token = att_resp->response_msg_hdr.msg_hdr.token; + vport->port_features = att_resp->features; + vport->num_tx_chan = att_resp->num_tx_chan; + vport->num_rx_chan = att_resp->num_rx_flow; + + vport->rx_chans = devm_kcalloc(proxy_priv->dev, + vport->num_rx_chan, + sizeof(*vport->rx_chans), + GFP_KERNEL); + for (j = 0; j < vport->num_rx_chan; j++) { + rx_chn = &vport->rx_chans[j]; + rx_chn->vport = vport; + rx_chn->rel_chan_idx = j; + } + + vport->tx_chans = devm_kcalloc(proxy_priv->dev, + vport->num_tx_chan, + sizeof(*vport->tx_chans), + GFP_KERNEL); + for (j = 0; j < vport->num_tx_chan; j++) { + tx_chn = &vport->tx_chans[j]; + tx_chn->vport = vport; + tx_chn->rel_chan_idx = j; + } + } + + return 0; + +err: + /* Detach virtual ports which were successfully attached */ + while (i--) { + vport = &proxy_priv->virt_ports[i]; + port_id = vport->port_id; + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_VIRT_PORT_DETACH; + req_p->token = vport->port_token; + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + if (ret) + dev_err(proxy_priv->dev, "detaching virtual port %u failed\n", port_id); + } + return -EIO; +} + +static void free_port_resources(struct cpsw_proxy_priv *proxy_priv) +{ + struct cpsw_proxy_req_params *req_p; + struct rx_dma_chan *rx_chn; + struct tx_dma_chan *tx_chn; + struct virtual_port *vport; + struct message resp_msg; + u32 port_id, i, j; + int ret; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + port_id = vport->port_id; + + /* Free allocated MAC */ + if (vport->mac_in_use) { + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_FREE_MAC; + req_p->token = vport->port_token; + ether_addr_copy(req_p->mac_addr, vport->mac_addr); + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + if (ret) { + dev_err(proxy_priv->dev, + "failed to free MAC Address for port %u err: %d\n", + port_id, ret); + return; + } + } + + /* Free TX DMA Channels */ + for (j = 0; j < vport->num_tx_chan; j++) { + tx_chn = &vport->tx_chans[j]; + if (!tx_chn->in_use) + continue; + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_FREE_TX; + req_p->token = vport->port_token; + req_p->tx_thread_id = tx_chn->thread_id; + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + if (ret) { + dev_err(proxy_priv->dev, + "failed to free TX Channel for port %u err: %d\n", + port_id, ret); + return; + } + } + + /* Free RX DMA Channels */ + for (j = 0; j < vport->num_rx_chan; j++) { + rx_chn = &vport->rx_chans[j]; + if (!rx_chn->in_use) + continue; + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_FREE_RX; + req_p->token = vport->port_token; + req_p->rx_flow_base = rx_chn->flow_base; + req_p->rx_flow_offset = rx_chn->flow_offset; + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + if (ret) { + dev_err(proxy_priv->dev, + "failed to free RX Channel for port %u err: %d\n", + port_id, ret); + return; + } + } + } +} + +static int allocate_port_resources(struct cpsw_proxy_priv *proxy_priv) +{ + struct tx_thread_alloc_response *tta_resp; + struct rx_flow_alloc_response *rfa_resp; + struct cpsw_proxy_req_params *req_p; + struct mac_alloc_response *ma_resp; + struct rx_dma_chan *rx_chn; + struct tx_dma_chan *tx_chn; + struct virtual_port *vport; + struct message resp_msg; + u32 port_id, i, j; + int ret; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + port_id = vport->port_id; + + /* Request RX DMA Flow allocation */ + for (j = 0; j < vport->num_rx_chan; j++) { + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_ALLOC_RX; + req_p->token = vport->port_token; + req_p->rx_tx_idx = j; + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + if (ret) { + dev_err(proxy_priv->dev, "RX Alloc for port %u failed\n", port_id); + goto err; + } + + rfa_resp = (struct rx_flow_alloc_response *)&resp_msg; + rx_chn = &vport->rx_chans[j]; + rx_chn->flow_base = rfa_resp->rx_flow_idx_base; + rx_chn->flow_offset = rfa_resp->rx_flow_idx_offset; + rx_chn->thread_id = rfa_resp->rx_psil_src_id; + rx_chn->in_use = 1; + } + + /* Request TX DMA Channel allocation */ + for (j = 0; j < vport->num_tx_chan; j++) { + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_ALLOC_TX; + req_p->token = vport->port_token; + req_p->rx_tx_idx = j; + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + if (ret) { + dev_err(proxy_priv->dev, "TX Alloc for port %u failed\n", port_id); + goto err; + } + + tta_resp = (struct tx_thread_alloc_response *)&resp_msg; + tx_chn = &vport->tx_chans[j]; + tx_chn->thread_id = tta_resp->tx_psil_dest_id; + tx_chn->in_use = 1; + } + + /* Request MAC allocation */ + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_ALLOC_MAC; + req_p->token = vport->port_token; + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + if (ret) { + dev_err(proxy_priv->dev, "MAC Alloc for port %u failed\n", port_id); + goto err; + } + + ma_resp = (struct mac_alloc_response *)&resp_msg; + ether_addr_copy(vport->mac_addr, ma_resp->mac_addr); + vport->mac_in_use = 1; + } + + return 0; + +err: + free_port_resources(proxy_priv); + return -EIO; +} + +static void detach_virtual_ports(struct cpsw_proxy_priv *proxy_priv) +{ + struct cpsw_proxy_req_params *req_p; + struct virtual_port *vport; + struct message resp_msg; + u32 port_id, i; + int ret; + + free_port_resources(proxy_priv); + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + port_id = vport->port_id; + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_VIRT_PORT_DETACH; + req_p->token = vport->port_token; + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + if (ret) + dev_err(proxy_priv->dev, "detaching virtual port %u failed\n", port_id); + } +} + +static void free_tx_chns(void *data) +{ + struct cpsw_proxy_priv *proxy_priv = data; + struct tx_dma_chan *tx_chn; + struct virtual_port *vport; + u32 i, j; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + for (j = 0; j < vport->num_tx_chan; j++) { + tx_chn = &vport->tx_chans[j]; + + if (!IS_ERR_OR_NULL(tx_chn->desc_pool)) + k3_cppi_desc_pool_destroy(tx_chn->desc_pool); + + if (!IS_ERR_OR_NULL(tx_chn->tx_chan)) + k3_udma_glue_release_tx_chn(tx_chn->tx_chan); + + memset(tx_chn, 0, sizeof(*tx_chn)); + } + } +} + +static int init_tx_chans(struct cpsw_proxy_priv *proxy_priv) +{ + u32 max_desc_num = ALIGN(MAX_TX_DESC, MAX_SKB_FRAGS); + struct k3_udma_glue_tx_channel_cfg tx_cfg = { 0 }; + struct device *dev = proxy_priv->dev; + u32 hdesc_size, tx_chn_num, i, j; + char tx_chn_name[CHAN_NAME_LEN]; + struct k3_ring_cfg ring_cfg = { + .elm_size = K3_RINGACC_RING_ELSIZE_8, + .mode = K3_RINGACC_RING_MODE_RING, + .flags = 0 + }; + struct tx_dma_chan *tx_chn; + struct virtual_port *vport; + int ret = 0, ret1; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + init_completion(&vport->tdown_complete); + + for (j = 0; j < vport->num_tx_chan; j++) { + tx_chn = &vport->tx_chans[j]; + + tx_chn_num = proxy_priv->num_active_tx_chans++; + snprintf(tx_chn_name, sizeof(tx_chn_name), "tx%u-virt-port-%u", + tx_chn_num, vport->port_id); + strscpy(tx_chn->tx_chan_name, tx_chn_name, sizeof(tx_chn->tx_chan_name)); + + hdesc_size = cppi5_hdesc_calc_size(true, PS_DATA_SIZE, SW_DATA_SIZE); + + tx_cfg.swdata_size = SW_DATA_SIZE; + tx_cfg.tx_cfg = ring_cfg; + tx_cfg.txcq_cfg = ring_cfg; + tx_cfg.tx_cfg.size = max_desc_num; + tx_cfg.txcq_cfg.size = max_desc_num; + + tx_chn->dev = dev; + tx_chn->num_descs = max_desc_num; + tx_chn->desc_pool = k3_cppi_desc_pool_create_name(dev, + tx_chn->num_descs, + hdesc_size, + tx_chn_name); + if (IS_ERR(tx_chn->desc_pool)) { + ret = PTR_ERR(tx_chn->desc_pool); + dev_err(dev, "failed to create tx pool %d\n", ret); + goto err; + } + + tx_chn->tx_chan = + k3_udma_glue_request_tx_chn_for_thread_id(dev, &tx_cfg, + proxy_priv->dma_node, + tx_chn->thread_id); + if (IS_ERR(tx_chn->tx_chan)) { + ret = PTR_ERR(tx_chn->tx_chan); + dev_err(dev, "Failed to request tx dma channel %d\n", ret); + goto err; + } + + tx_chn->irq = k3_udma_glue_tx_get_irq(tx_chn->tx_chan); + if (tx_chn->irq <= 0) { + dev_err(dev, "Failed to get tx dma irq %d\n", tx_chn->irq); + ret = -ENXIO; + } + } + } + +err: + ret1 = devm_add_action(dev, free_tx_chns, proxy_priv); + if (ret1) { + dev_err(dev, "failed to add free_tx_chns action %d", ret1); + return ret1; + } + + return ret; +} + +static void free_rx_chns(void *data) +{ + struct cpsw_proxy_priv *proxy_priv = data; + struct rx_dma_chan *rx_chn; + struct virtual_port *vport; + u32 i, j; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + + for (j = 0; j < vport->num_rx_chan; j++) { + rx_chn = &vport->rx_chans[j]; + + if (!IS_ERR_OR_NULL(rx_chn->desc_pool)) + k3_cppi_desc_pool_destroy(rx_chn->desc_pool); + + if (!IS_ERR_OR_NULL(rx_chn->rx_chan)) + k3_udma_glue_release_rx_chn(rx_chn->rx_chan); + } + } +} + +static int init_rx_chans(struct cpsw_proxy_priv *proxy_priv) +{ + struct k3_udma_glue_rx_channel_cfg rx_cfg = {0}; + struct device *dev = proxy_priv->dev; + u32 hdesc_size, rx_chn_num, i, j; + u32 max_desc_num = MAX_RX_DESC; + char rx_chn_name[CHAN_NAME_LEN]; + struct rx_dma_chan *rx_chn; + struct virtual_port *vport; + struct k3_ring_cfg rxring_cfg = { + .elm_size = K3_RINGACC_RING_ELSIZE_8, + .mode = K3_RINGACC_RING_MODE_MESSAGE, + .flags = 0, + }; + struct k3_ring_cfg fdqring_cfg = { + .elm_size = K3_RINGACC_RING_ELSIZE_8, + .mode = K3_RINGACC_RING_MODE_MESSAGE, + .flags = 0, + }; + struct k3_udma_glue_rx_flow_cfg rx_flow_cfg = { + .rx_cfg = rxring_cfg, + .rxfdq_cfg = fdqring_cfg, + .ring_rxq_id = K3_RINGACC_RING_ID_ANY, + .ring_rxfdq0_id = K3_RINGACC_RING_ID_ANY, + .src_tag_lo_sel = K3_UDMA_GLUE_SRC_TAG_LO_USE_REMOTE_SRC_TAG, + }; + int ret = 0, ret1; + + hdesc_size = cppi5_hdesc_calc_size(true, PS_DATA_SIZE, SW_DATA_SIZE); + + rx_cfg.swdata_size = SW_DATA_SIZE; + rx_cfg.flow_id_num = MAX_RX_FLOWS; + rx_cfg.remote = true; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + + for (j = 0; j < vport->num_rx_chan; j++) { + rx_chn = &vport->rx_chans[j]; + + rx_chn_num = proxy_priv->num_active_rx_chans++; + snprintf(rx_chn_name, sizeof(rx_chn_name), "rx%u-virt-port-%u", rx_chn_num, + vport->port_id); + strscpy(rx_chn->rx_chan_name, rx_chn_name, sizeof(rx_chn->rx_chan_name)); + + rx_cfg.flow_id_base = rx_chn->flow_base + rx_chn->flow_offset; + + /* init all flows */ + rx_chn->dev = dev; + rx_chn->num_descs = max_desc_num; + rx_chn->desc_pool = k3_cppi_desc_pool_create_name(dev, + rx_chn->num_descs, + hdesc_size, + rx_chn_name); + if (IS_ERR(rx_chn->desc_pool)) { + ret = PTR_ERR(rx_chn->desc_pool); + dev_err(dev, "Failed to create rx pool %d\n", ret); + goto err; + } + + rx_chn->rx_chan = + k3_udma_glue_request_remote_rx_chn_for_thread_id(dev, &rx_cfg, + proxy_priv->dma_node, + rx_chn->thread_id); + if (IS_ERR(rx_chn->rx_chan)) { + ret = PTR_ERR(rx_chn->rx_chan); + dev_err(dev, "Failed to request rx dma channel %d\n", ret); + goto err; + } + + rx_flow_cfg.rx_cfg.size = max_desc_num; + rx_flow_cfg.rxfdq_cfg.size = max_desc_num; + ret = k3_udma_glue_rx_flow_init(rx_chn->rx_chan, + 0, &rx_flow_cfg); + if (ret) { + dev_err(dev, "Failed to init rx flow %d\n", ret); + goto err; + } + + rx_chn->irq = k3_udma_glue_rx_get_irq(rx_chn->rx_chan, 0); + if (rx_chn->irq <= 0) { + ret = -ENXIO; + dev_err(dev, "Failed to get rx dma irq %d\n", rx_chn->irq); + } + } + } + +err: + ret1 = devm_add_action(dev, free_rx_chns, proxy_priv); + if (ret1) { + dev_err(dev, "failed to add free_rx_chns action %d", ret1); + return ret1; + } + + return ret; +} + +static void vport_xmit_free(struct tx_dma_chan *tx_chn, struct device *dev, + struct cppi5_host_desc_t *desc) +{ + struct cppi5_host_desc_t *first_desc, *next_desc; + dma_addr_t buf_dma, next_desc_dma; + u32 buf_dma_len; + + first_desc = desc; + next_desc = first_desc; + + cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len); + + dma_unmap_single(dev, buf_dma, buf_dma_len, + DMA_TO_DEVICE); + + next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc); + while (next_desc_dma) { + next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, + next_desc_dma); + cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len); + + dma_unmap_page(dev, buf_dma, buf_dma_len, + DMA_TO_DEVICE); + + next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc); + + k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); + } + + k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc); +} + +static int tx_compl_packets(struct virtual_port *vport, unsigned int tx_chan_idx, + unsigned int budget, bool *tdown) +{ + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct device *dev = proxy_priv->dev; + struct cppi5_host_desc_t *desc_tx; + struct netdev_queue *netif_txq; + unsigned int total_bytes = 0; + struct tx_dma_chan *tx_chn; + struct net_device *ndev; + struct sk_buff *skb; + dma_addr_t desc_dma; + int res, num_tx = 0; + void **swdata; + + tx_chn = &vport->tx_chans[tx_chan_idx]; + + while (budget--) { + struct vport_netdev_priv *ndev_priv; + struct vport_netdev_stats *stats; + + res = k3_udma_glue_pop_tx_chn(tx_chn->tx_chan, &desc_dma); + if (res == -ENODATA) + break; + + if (desc_dma & 0x1) { + if (atomic_dec_and_test(&vport->tdown_cnt)) + complete(&vport->tdown_complete); + *tdown = true; + break; + } + + desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, + desc_dma); + swdata = cppi5_hdesc_get_swdata(desc_tx); + skb = *(swdata); + vport_xmit_free(tx_chn, dev, desc_tx); + + ndev = skb->dev; + + ndev_priv = netdev_priv(ndev); + stats = this_cpu_ptr(ndev_priv->stats); + u64_stats_update_begin(&stats->syncp); + stats->tx_packets++; + stats->tx_bytes += skb->len; + u64_stats_update_end(&stats->syncp); + + total_bytes += skb->len; + napi_consume_skb(skb, budget); + num_tx++; + } + + if (!num_tx) + return 0; + + netif_txq = netdev_get_tx_queue(ndev, tx_chan_idx); + netdev_tx_completed_queue(netif_txq, num_tx, total_bytes); + + if (netif_tx_queue_stopped(netif_txq)) { + __netif_tx_lock(netif_txq, smp_processor_id()); + if (netif_running(ndev) && + (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >= + MAX_SKB_FRAGS)) + netif_tx_wake_queue(netif_txq); + + __netif_tx_unlock(netif_txq); + } + + return num_tx; +} + +static int vport_tx_poll(struct napi_struct *napi_tx, int budget) +{ + struct tx_dma_chan *tx_chn = container_of(napi_tx, struct tx_dma_chan, + napi_tx); + struct virtual_port *vport = tx_chn->vport; + bool tdown = false; + int num_tx; + + /* process every unprocessed channel */ + num_tx = tx_compl_packets(vport, tx_chn->rel_chan_idx, budget, &tdown); + + if (num_tx >= budget) + return budget; + + if (napi_complete_done(napi_tx, num_tx)) { + if (unlikely(tx_chn->tx_pace_timeout && !tdown)) { + hrtimer_start(&tx_chn->tx_hrtimer, + ns_to_ktime(tx_chn->tx_pace_timeout), + HRTIMER_MODE_REL_PINNED); + } else { + enable_irq(tx_chn->irq); + } + } + + return 0; +} + +/* RX psdata[2] word format - checksum information */ +#define RX_PSD_CSUM_ERR BIT(16) +#define RX_PSD_IS_FRAGMENT BIT(17) +#define RX_PSD_IPV6_VALID BIT(19) +#define RX_PSD_IPV4_VALID BIT(20) + +static void vport_rx_csum(struct sk_buff *skb, u32 csum_info) +{ + /* HW can verify IPv4/IPv6 TCP/UDP packets checksum + * csum information provides in psdata[2] word: + * RX_PSD_CSUM_ERR bit - indicates csum error + * RX_PSD_IPV6_VALID and CPSW_RX_PSD_IPV4_VALID + * bits - indicates IPv4/IPv6 packet + * RX_PSD_IS_FRAGMENT bit - indicates fragmented packet + * RX_PSD_CSUM_ADD has value 0xFFFF for non fragmented packets + * or csum value for fragmented packets if !RX_PSD_CSUM_ERR + */ + skb_checksum_none_assert(skb); + + if (unlikely(!(skb->dev->features & NETIF_F_RXCSUM))) + return; + + if ((csum_info & (RX_PSD_IPV6_VALID | + RX_PSD_IPV4_VALID)) && + !(csum_info & RX_PSD_CSUM_ERR)) { + /* csum for fragmented packets is unsupported */ + if (!(csum_info & RX_PSD_IS_FRAGMENT)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } +} + +static int vport_rx_push(struct virtual_port *vport, struct sk_buff *skb, + u32 rx_chan_idx) +{ + struct rx_dma_chan *rx_chn = &vport->rx_chans[rx_chan_idx]; + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct device *dev = proxy_priv->dev; + struct cppi5_host_desc_t *desc_rx; + u32 pkt_len = skb_tailroom(skb); + dma_addr_t desc_dma; + dma_addr_t buf_dma; + void *swdata; + + desc_rx = k3_cppi_desc_pool_alloc(rx_chn->desc_pool); + if (!desc_rx) { + dev_err(dev, "Failed to allocate RXFDQ descriptor\n"); + return -ENOMEM; + } + desc_dma = k3_cppi_desc_pool_virt2dma(rx_chn->desc_pool, desc_rx); + + buf_dma = dma_map_single(dev, skb->data, pkt_len, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(dev, buf_dma))) { + k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); + dev_err(dev, "Failed to map rx skb buffer\n"); + return -EINVAL; + } + + cppi5_hdesc_init(desc_rx, CPPI5_INFO0_HDESC_EPIB_PRESENT, + PS_DATA_SIZE); + cppi5_hdesc_attach_buf(desc_rx, 0, 0, buf_dma, skb_tailroom(skb)); + swdata = cppi5_hdesc_get_swdata(desc_rx); + *((void **)swdata) = skb; + + return k3_udma_glue_push_rx_chn(rx_chn->rx_chan, 0, desc_rx, desc_dma); +} + +static int vport_rx_packets(struct virtual_port *vport, u32 rx_chan_idx) +{ + struct rx_dma_chan *rx_chn = &vport->rx_chans[rx_chan_idx]; + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + u32 buf_dma_len, pkt_len, port_id = 0, csum_info; + struct device *dev = proxy_priv->dev; + struct vport_netdev_priv *ndev_priv; + struct cppi5_host_desc_t *desc_rx; + struct vport_netdev_stats *stats; + struct sk_buff *skb, *new_skb; + dma_addr_t desc_dma, buf_dma; + struct net_device *ndev; + u32 flow_idx = 0; + void **swdata; + int ret = 0; + u32 *psdata; + + ret = k3_udma_glue_pop_rx_chn(rx_chn->rx_chan, flow_idx, &desc_dma); + if (ret) { + if (ret != -ENODATA) + dev_err(dev, "RX: pop chn fail %d\n", ret); + return ret; + } + + if (desc_dma & 0x1) { + dev_dbg(dev, "%s RX tdown flow: %u\n", __func__, flow_idx); + return 0; + } + + desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); + dev_dbg(dev, "%s flow_idx: %u desc %pad\n", + __func__, flow_idx, &desc_dma); + + swdata = cppi5_hdesc_get_swdata(desc_rx); + skb = *swdata; + cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); + pkt_len = cppi5_hdesc_get_pktlen(desc_rx); + cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL); + /* read port for dbg */ + dev_dbg(dev, "%s rx port_id:%d\n", __func__, port_id); + ndev = vport->ndev; + skb->dev = ndev; + + psdata = cppi5_hdesc_get_psdata(desc_rx); + csum_info = psdata[2]; + dev_dbg(dev, "%s rx csum_info:%#x\n", __func__, csum_info); + + dma_unmap_single(dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE); + + k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); + + if (unlikely(!netif_running(skb->dev))) { + dev_kfree_skb_any(skb); + return -ENODEV; + } + + new_skb = netdev_alloc_skb_ip_align(ndev, MAX_PACKET_SIZE); + if (new_skb) { + skb_put(skb, pkt_len); + skb->protocol = eth_type_trans(skb, ndev); + vport_rx_csum(skb, csum_info); + napi_gro_receive(&rx_chn->napi_rx, skb); + + ndev_priv = netdev_priv(ndev); + stats = this_cpu_ptr(ndev_priv->stats); + + u64_stats_update_begin(&stats->syncp); + stats->rx_packets++; + stats->rx_bytes += pkt_len; + u64_stats_update_end(&stats->syncp); + kmemleak_not_leak(new_skb); + } else { + ndev->stats.rx_dropped++; + new_skb = skb; + } + + if (netif_dormant(ndev)) { + dev_kfree_skb_any(new_skb); + ndev->stats.rx_dropped++; + return -ENODEV; + } + + ret = vport_rx_push(vport, new_skb, rx_chn->rel_chan_idx); + if (WARN_ON(ret < 0)) { + dev_kfree_skb_any(new_skb); + ndev->stats.rx_errors++; + ndev->stats.rx_dropped++; + } + + return ret; +} + +static int vport_rx_poll(struct napi_struct *napi_rx, int budget) +{ + struct rx_dma_chan *rx_chn = container_of(napi_rx, struct rx_dma_chan, + napi_rx); + struct virtual_port *vport = rx_chn->vport; + int num_rx = 0; + int cur_budget; + int ret; + + /* process every flow */ + cur_budget = budget; + + while (cur_budget--) { + ret = vport_rx_packets(vport, rx_chn->rel_chan_idx); + if (ret) + break; + num_rx++; + } + + if (num_rx < budget && napi_complete_done(napi_rx, num_rx)) { + if (rx_chn->rx_irq_disabled) { + rx_chn->rx_irq_disabled = false; + if (unlikely(rx_chn->rx_pace_timeout)) { + hrtimer_start(&rx_chn->rx_hrtimer, + ns_to_ktime(rx_chn->rx_pace_timeout), + HRTIMER_MODE_REL_PINNED); + } else { + enable_irq(rx_chn->irq); + } + } + } + + return num_rx; +} + +static enum hrtimer_restart vport_tx_timer_cb(struct hrtimer *timer) +{ + struct tx_dma_chan *tx_chn = container_of(timer, struct tx_dma_chan, tx_hrtimer); + + enable_irq(tx_chn->irq); + return HRTIMER_NORESTART; +} + +static enum hrtimer_restart vport_rx_timer_cb(struct hrtimer *timer) +{ + struct rx_dma_chan *rx_chn = container_of(timer, struct rx_dma_chan, rx_hrtimer); + + enable_irq(rx_chn->irq); + return HRTIMER_NORESTART; +} + +static u32 vport_get_link(struct net_device *ndev) +{ + struct virtual_port *vport = vport_ndev_to_vport(ndev); + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct port_link_status_response *pls_resp; + struct cpsw_proxy_req_params *req_p; + struct message resp_msg; + bool link_up; + int ret; + + if (vport->port_type != VIRT_MAC_ONLY_PORT) + return ethtool_op_get_link(ndev); + + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_VIRT_PORT_LINK_STATUS; + req_p->token = vport->port_token; + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + if (ret) { + netdev_err(ndev, "failed to get link status\n"); + /* Assume that link is down if status is unknown */ + return 0; + } + pls_resp = (struct port_link_status_response *)&resp_msg; + link_up = pls_resp->link_up; + + return link_up; +} + +static int vport_get_coal(struct net_device *ndev, struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct virtual_port *vport = vport_ndev_to_vport(ndev); + + coal->tx_coalesce_usecs = vport->tx_chans[0].tx_pace_timeout / 1000; + coal->rx_coalesce_usecs = vport->rx_chans[0].rx_pace_timeout / 1000; + return 0; +} + +static int vport_set_coal(struct net_device *ndev, struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct virtual_port *vport = vport_ndev_to_vport(ndev); + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct device *dev = proxy_priv->dev; + u32 i; + + if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20) { + dev_err(dev, "TX coalesce must be at least 20 usecs. Defaulting to 20 usecs\n"); + coal->tx_coalesce_usecs = 20; + } + + if (coal->rx_coalesce_usecs && coal->rx_coalesce_usecs < 20) { + dev_err(dev, "RX coalesce must be at least 20 usecs. Defaulting to 20 usecs\n"); + coal->rx_coalesce_usecs = 20; + } + + /* Since it is possible to set pacing values per TX and RX queue, if per queue value is + * not specified, apply it to all available TX and RX queues. + */ + + for (i = 0; i < vport->num_tx_chan; i++) + vport->tx_chans[i].tx_pace_timeout = coal->tx_coalesce_usecs * 1000; + + for (i = 0; i < vport->num_rx_chan; i++) + vport->rx_chans[i].rx_pace_timeout = coal->rx_coalesce_usecs * 1000; + + return 0; +} + +static int vport_get_per_q_coal(struct net_device *ndev, u32 q, + struct ethtool_coalesce *coal) +{ + struct virtual_port *vport = vport_ndev_to_vport(ndev); + + if (q >= vport->num_tx_chan || q >= vport->num_rx_chan) + return -EINVAL; + + coal->tx_coalesce_usecs = vport->tx_chans[q].tx_pace_timeout / 1000; + coal->rx_coalesce_usecs = vport->rx_chans[q].rx_pace_timeout / 1000; + + return 0; +} + +static int vport_set_per_q_coal(struct net_device *ndev, u32 q, + struct ethtool_coalesce *coal) +{ struct virtual_port *vport = vport_ndev_to_vport(ndev); + struct device *dev = vport->proxy_priv->dev; + + if (q >= vport->num_tx_chan || q >= vport->num_rx_chan) + return -EINVAL; + + if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20) { + dev_err(dev, "TX coalesce must be at least 20 usecs. Defaulting to 20 usecs\n"); + coal->tx_coalesce_usecs = 20; + } + + if (coal->rx_coalesce_usecs && coal->rx_coalesce_usecs < 20) { + dev_err(dev, "RX coalesce must be at least 20 usecs. Defaulting to 20 usecs\n"); + coal->rx_coalesce_usecs = 20; + } + + vport->tx_chans[q].tx_pace_timeout = coal->tx_coalesce_usecs * 1000; + vport->rx_chans[q].rx_pace_timeout = coal->rx_coalesce_usecs * 1000; + + return 0; +} + +const struct ethtool_ops cpsw_proxy_client_ethtool_ops = { + .get_link = vport_get_link, + .supported_coalesce_params = ETHTOOL_COALESCE_USECS, + .get_coalesce = vport_get_coal, + .set_coalesce = vport_set_coal, + .get_per_queue_coalesce = vport_get_per_q_coal, + .set_per_queue_coalesce = vport_set_per_q_coal, +}; + +static int register_mac(struct virtual_port *vport) +{ + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct rx_dma_chan *rx_chn = &vport->rx_chans[0]; + struct cpsw_proxy_req_params *req_p; + struct message resp_msg; + int ret; + + /* Register MAC Address only for RX DMA Channel 0 */ + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_MAC_REGISTER; + req_p->token = vport->port_token; + req_p->rx_flow_base = rx_chn->flow_base; + req_p->rx_flow_offset = rx_chn->flow_offset; + ether_addr_copy(req_p->mac_addr, vport->mac_addr); + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + if (ret) + dev_err(proxy_priv->dev, "failed to register MAC Address\n"); + + return ret; +} + +static int deregister_mac(struct virtual_port *vport) +{ + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct rx_dma_chan *rx_chn = &vport->rx_chans[0]; + struct cpsw_proxy_req_params *req_p; + struct message resp_msg; + int ret; + + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_MAC_DEREGISTER; + req_p->token = vport->port_token; + req_p->rx_flow_base = rx_chn->flow_base; + req_p->rx_flow_offset = rx_chn->flow_offset; + ether_addr_copy(req_p->mac_addr, vport->mac_addr); + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + if (ret) + dev_err(proxy_priv->dev, "failed to deregister MAC Address\n"); + + return ret; +} + +static void vport_tx_cleanup(void *data, dma_addr_t desc_dma) +{ + struct tx_dma_chan *tx_chn = data; + struct cppi5_host_desc_t *desc_tx; + struct sk_buff *skb; + void **swdata; + + desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma); + swdata = cppi5_hdesc_get_swdata(desc_tx); + skb = *(swdata); + vport_xmit_free(tx_chn, tx_chn->dev, desc_tx); + + dev_kfree_skb_any(skb); +} + +static void vport_rx_cleanup(void *data, dma_addr_t desc_dma) +{ + struct rx_dma_chan *rx_chn = data; + struct cppi5_host_desc_t *desc_rx; + struct sk_buff *skb; + dma_addr_t buf_dma; + u32 buf_dma_len; + void **swdata; + + desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); + swdata = cppi5_hdesc_get_swdata(desc_rx); + skb = *swdata; + cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); + + dma_unmap_single(rx_chn->dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE); + k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); + + dev_kfree_skb_any(skb); +} + +static int vport_add_mcast(struct net_device *ndev, const u8 *addr) +{ + struct virtual_port *vport = vport_ndev_to_vport(ndev); + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct rx_dma_chan *rx_chn = &vport->rx_chans[0]; + struct cpsw_proxy_req_params *req_p; + struct message resp_msg; + int ret; + + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_MCAST_FILTER_ADD; + req_p->token = vport->port_token; + req_p->vlan_id = ETHFW_DFLT_VLAN; + req_p->rx_flow_base = rx_chn->flow_base; + req_p->rx_flow_offset = rx_chn->flow_offset; + ether_addr_copy(req_p->mac_addr, addr); + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + + if (ret == ETHFW_RES_EBADARGS) { + dev_info(proxy_priv->dev, "%02x:%02x:%02x:%02x:%02x:%02x is reserved for EthFw\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + + return 0; + } else if (ret) { + dev_err(proxy_priv->dev, "adding %02x:%02x:%02x:%02x:%02x:%02x failed: %d\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], ret); + return -EIO; + } + + return 0; +} + +static int vport_del_mcast(struct net_device *ndev, const u8 *addr) +{ + struct virtual_port *vport = vport_ndev_to_vport(ndev); + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct cpsw_proxy_req_params *req_p; + struct message resp_msg; + int ret; + + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_MCAST_FILTER_DEL; + req_p->token = vport->port_token; + req_p->vlan_id = ETHFW_DFLT_VLAN; + ether_addr_copy(req_p->mac_addr, addr); + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + + if (ret == ETHFW_RES_EBADARGS) { + dev_info(proxy_priv->dev, "%02x:%02x:%02x:%02x:%02x:%02x is reserved for EthFw\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + return 0; + } else if (ret) { + dev_err(proxy_priv->dev, "deleting %02x:%02x:%02x:%02x:%02x:%02x failed: %d\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], ret); + return -EIO; + } + + return 0; +} + +static void vport_stop(struct virtual_port *vport) +{ + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct rx_dma_chan *rx_chn; + struct tx_dma_chan *tx_chn; + int i; + + /* shutdown tx channels */ + atomic_set(&vport->tdown_cnt, vport->num_tx_chan); + /* ensure new tdown_cnt value is visible */ + smp_mb__after_atomic(); + reinit_completion(&vport->tdown_complete); + + for (i = 0; i < vport->num_tx_chan; i++) + k3_udma_glue_tdown_tx_chn(vport->tx_chans[i].tx_chan, false); + + i = wait_for_completion_timeout(&vport->tdown_complete, msecs_to_jiffies(1000)); + if (!i) + dev_err(proxy_priv->dev, "tx teardown timeout\n"); + + for (i = 0; i < vport->num_tx_chan; i++) { + tx_chn = &vport->tx_chans[i]; + k3_udma_glue_reset_tx_chn(tx_chn->tx_chan, tx_chn, vport_tx_cleanup); + k3_udma_glue_disable_tx_chn(tx_chn->tx_chan); + napi_disable(&tx_chn->napi_tx); + hrtimer_cancel(&tx_chn->tx_hrtimer); + } + + for (i = 0; i < vport->num_rx_chan; i++) { + rx_chn = &vport->rx_chans[i]; + k3_udma_glue_rx_flow_disable(rx_chn->rx_chan, 0); + /* Need some delay to process RX ring before reset */ + msleep(100); + k3_udma_glue_reset_rx_chn(rx_chn->rx_chan, 0, rx_chn, vport_rx_cleanup, + false); + napi_disable(&rx_chn->napi_rx); + hrtimer_cancel(&rx_chn->rx_hrtimer); + } + + if (vport->port_features & ETHFW_MCAST_FILTERING) + cancel_work_sync(&vport->rx_mode_work); +} + +static int vport_open(struct virtual_port *vport, netdev_features_t features) +{ + struct rx_dma_chan *rx_chn; + struct tx_dma_chan *tx_chn; + struct sk_buff *skb; + u32 i, j; + int ret; + + for (i = 0; i < vport->num_rx_chan; i++) { + rx_chn = &vport->rx_chans[i]; + + for (j = 0; j < rx_chn->num_descs; j++) { + skb = __netdev_alloc_skb_ip_align(NULL, MAX_PACKET_SIZE, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + ret = vport_rx_push(vport, skb, i); + if (ret < 0) { + netdev_err(vport->ndev, + "cannot submit skb to rx channel\n"); + kfree_skb(skb); + return ret; + } + kmemleak_not_leak(skb); + } + + ret = k3_udma_glue_rx_flow_enable(rx_chn->rx_chan, 0); + if (ret) + return ret; + } + + for (i = 0; i < vport->num_tx_chan; i++) { + tx_chn = &vport->tx_chans[i]; + ret = k3_udma_glue_enable_tx_chn(tx_chn->tx_chan); + if (ret) + return ret; + napi_enable(&tx_chn->napi_tx); + } + + for (i = 0; i < vport->num_rx_chan; i++) { + rx_chn = &vport->rx_chans[i]; + napi_enable(&rx_chn->napi_rx); + if (rx_chn->rx_irq_disabled) { + rx_chn->rx_irq_disabled = false; + enable_irq(rx_chn->irq); + } + } + + return 0; +} + +static int vport_ndo_stop(struct net_device *ndev) +{ + struct virtual_port *vport = vport_ndev_to_vport(ndev); + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + int ret; + + netif_tx_stop_all_queues(ndev); + netif_carrier_off(ndev); + + ret = deregister_mac(vport); + if (ret) + netdev_err(ndev, "failed to deregister MAC for port %u\n", + vport->port_id); + + __dev_mc_unsync(ndev, vport_del_mcast); + __hw_addr_init(&vport->mcast_list); + vport_stop(vport); + + dev_info(proxy_priv->dev, "stopped port %u on interface %s\n", + vport->port_id, ndev->name); + + return 0; +} + +static int vport_ndo_open(struct net_device *ndev) +{ + struct virtual_port *vport = vport_ndev_to_vport(ndev); + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + int ret; + u32 i; + + ret = netif_set_real_num_tx_queues(ndev, vport->num_tx_chan); + if (ret) + return ret; + + for (i = 0; i < vport->num_tx_chan; i++) + netdev_tx_reset_queue(netdev_get_tx_queue(ndev, i)); + + ret = vport_open(vport, ndev->features); + if (ret) + return ret; + + ret = register_mac(vport); + if (ret) { + netdev_err(ndev, "failed to register MAC for port: %u\n", + vport->port_id); + vport_stop(vport); + return -EIO; + } + + netif_tx_wake_all_queues(ndev); + netif_carrier_on(ndev); + + dev_info(proxy_priv->dev, "started port %u on interface %s\n", + vport->port_id, ndev->name); + + return 0; +} + +static netdev_tx_t vport_ndo_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct virtual_port *vport = vport_ndev_to_vport(ndev); + struct cppi5_host_desc_t *first_desc, *next_desc, *cur_desc; + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct device *dev = proxy_priv->dev; + struct netdev_queue *netif_txq; + dma_addr_t desc_dma, buf_dma; + struct tx_dma_chan *tx_chn; + void **swdata; + int ret, i, q; + u32 pkt_len; + u32 *psdata; + + /* padding enabled in hw */ + pkt_len = skb_headlen(skb); + + /* Get Queue / TX DMA Channel for the SKB */ + q = skb_get_queue_mapping(skb); + tx_chn = &vport->tx_chans[q]; + netif_txq = netdev_get_tx_queue(ndev, q); + + /* Map the linear buffer */ + buf_dma = dma_map_single(dev, skb->data, pkt_len, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(dev, buf_dma))) { + dev_err(dev, "Failed to map tx skb buffer\n"); + ndev->stats.tx_errors++; + goto drop_free_skb; + } + + first_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool); + if (!first_desc) { + dev_dbg(dev, "Failed to allocate descriptor\n"); + dma_unmap_single(dev, buf_dma, pkt_len, DMA_TO_DEVICE); + goto busy_stop_q; + } + + cppi5_hdesc_init(first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT, + PS_DATA_SIZE); + cppi5_desc_set_pktids(&first_desc->hdr, 0, 0x3FFF); + cppi5_hdesc_set_pkttype(first_desc, 0x7); + /* target port has to be 0 */ + cppi5_desc_set_tags_ids(&first_desc->hdr, 0, vport->port_type); + + cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len); + swdata = cppi5_hdesc_get_swdata(first_desc); + *(swdata) = skb; + psdata = cppi5_hdesc_get_psdata(first_desc); + + /* HW csum offload if enabled */ + psdata[2] = 0; + if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { + unsigned int cs_start, cs_offset; + + cs_start = skb_transport_offset(skb); + cs_offset = cs_start + skb->csum_offset; + /* HW numerates bytes starting from 1 */ + psdata[2] = ((cs_offset + 1) << 24) | + ((cs_start + 1) << 16) | (skb->len - cs_start); + dev_dbg(dev, "%s tx psdata:%#x\n", __func__, psdata[2]); + } + + if (!skb_is_nonlinear(skb)) + goto done_tx; + + dev_dbg(dev, "fragmented SKB\n"); + + /* Handle the case where skb is fragmented in pages */ + cur_desc = first_desc; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + u32 frag_size = skb_frag_size(frag); + + next_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool); + if (!next_desc) { + dev_err(dev, "Failed to allocate descriptor\n"); + goto busy_free_descs; + } + + buf_dma = skb_frag_dma_map(dev, frag, 0, frag_size, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(dev, buf_dma))) { + dev_err(dev, "Failed to map tx skb page\n"); + k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); + ndev->stats.tx_errors++; + goto drop_free_descs; + } + + cppi5_hdesc_reset_hbdesc(next_desc); + cppi5_hdesc_attach_buf(next_desc, + buf_dma, frag_size, buf_dma, frag_size); + + desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, + next_desc); + cppi5_hdesc_link_hbdesc(cur_desc, desc_dma); + + pkt_len += frag_size; + cur_desc = next_desc; + } + WARN_ON(pkt_len != skb->len); + +done_tx: + skb_tx_timestamp(skb); + + /* report bql before sending packet */ + dev_dbg(dev, "push 0 %d Bytes\n", pkt_len); + + netdev_tx_sent_queue(netif_txq, pkt_len); + + cppi5_hdesc_set_pktlen(first_desc, pkt_len); + desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, first_desc); + ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chan, first_desc, desc_dma); + if (ret) { + dev_err(dev, "can't push desc %d\n", ret); + /* inform bql */ + netdev_tx_completed_queue(netif_txq, 1, pkt_len); + ndev->stats.tx_errors++; + goto drop_free_descs; + } + + if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) < MAX_SKB_FRAGS) { + netif_tx_stop_queue(netif_txq); + /* Barrier, so that stop_queue visible to other cpus */ + smp_mb__after_atomic(); + dev_dbg(dev, "netif_tx_stop_queue %d\n", q); + + /* re-check for smp */ + if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >= + MAX_SKB_FRAGS) { + netif_tx_wake_queue(netif_txq); + dev_dbg(dev, "netif_tx_wake_queue %d\n", q); + } + } + + return NETDEV_TX_OK; + +drop_free_descs: + vport_xmit_free(tx_chn, dev, first_desc); +drop_free_skb: + ndev->stats.tx_dropped++; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + +busy_free_descs: + vport_xmit_free(tx_chn, dev, first_desc); +busy_stop_q: + netif_tx_stop_queue(netif_txq); + return NETDEV_TX_BUSY; +} + +static void vport_ndo_get_stats(struct net_device *ndev, + struct rtnl_link_stats64 *stats) +{ + struct vport_netdev_priv *ndev_priv = netdev_priv(ndev); + unsigned int start; + int cpu; + + for_each_possible_cpu(cpu) { + struct vport_netdev_stats *cpu_stats; + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + + cpu_stats = per_cpu_ptr(ndev_priv->stats, cpu); + do { + start = u64_stats_fetch_begin(&cpu_stats->syncp); + rx_packets = cpu_stats->rx_packets; + rx_bytes = cpu_stats->rx_bytes; + tx_packets = cpu_stats->tx_packets; + tx_bytes = cpu_stats->tx_bytes; + } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; + stats->tx_packets += tx_packets; + stats->tx_bytes += tx_bytes; + } + + stats->rx_errors = ndev->stats.rx_errors; + stats->rx_dropped = ndev->stats.rx_dropped; + stats->tx_dropped = ndev->stats.tx_dropped; +} + +static void vport_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue) +{ + struct virtual_port *vport = vport_ndev_to_vport(ndev); + struct netdev_queue *netif_txq; + struct tx_dma_chan *tx_chn; + unsigned long trans_start; + + /* process every txq */ + netif_txq = netdev_get_tx_queue(ndev, txqueue); + tx_chn = &vport->tx_chans[txqueue]; + trans_start = READ_ONCE(netif_txq->trans_start); + + netdev_err(ndev, "txq:%d DRV_XOFF: %d tmo: %u dql_avail:%d free_desc:%zu\n", + txqueue, netif_tx_queue_stopped(netif_txq), + jiffies_to_msecs(jiffies - trans_start), + dql_avail(&netif_txq->dql), + k3_cppi_desc_pool_avail(tx_chn->desc_pool)); + + if (netif_tx_queue_stopped(netif_txq)) { + /* try to recover if it was stopped by driver */ + txq_trans_update(netif_txq); + netif_tx_wake_queue(netif_txq); + } +} + +static void vport_set_rx_mode_work(struct work_struct *work) +{ + struct virtual_port *vport = container_of(work, struct virtual_port, rx_mode_work); + struct net_device *ndev; + + if (likely(vport->port_features & ETHFW_MCAST_FILTERING)) { + ndev = vport->ndev; + + netif_addr_lock_bh(ndev); + __hw_addr_sync(&vport->mcast_list, &ndev->mc, ndev->addr_len); + netif_addr_unlock_bh(ndev); + + __hw_addr_sync_dev(&vport->mcast_list, ndev, + vport_add_mcast, vport_del_mcast); + } +} + +static void vport_set_rx_mode(struct net_device *ndev) +{ + struct virtual_port *vport = vport_ndev_to_vport(ndev); + + if (vport->port_features & ETHFW_MCAST_FILTERING) + queue_work(vport->vport_wq, &vport->rx_mode_work); +} + +static const struct net_device_ops cpsw_proxy_client_netdev_ops = { + .ndo_open = vport_ndo_open, + .ndo_stop = vport_ndo_stop, + .ndo_start_xmit = vport_ndo_xmit, + .ndo_get_stats64 = vport_ndo_get_stats, + .ndo_tx_timeout = vport_ndo_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_set_rx_mode = vport_set_rx_mode, +}; + +static int init_netdev(struct cpsw_proxy_priv *proxy_priv, struct virtual_port *vport) +{ + struct device *dev = proxy_priv->dev; + struct vport_netdev_priv *ndev_priv; + struct rx_dma_chan *rx_chn; + struct tx_dma_chan *tx_chn; + int ret = 0; + u32 i; + + vport->ndev = devm_alloc_etherdev_mqs(dev, sizeof(struct vport_netdev_priv), + vport->num_tx_chan, vport->num_rx_chan); + + if (!vport->ndev) { + dev_err(dev, "error allocating netdev for port %u\n", vport->port_id); + return -ENOMEM; + } + + ndev_priv = netdev_priv(vport->ndev); + ndev_priv->vport = vport; + SET_NETDEV_DEV(vport->ndev, dev); + + if (is_valid_ether_addr(vport->mac_addr)) + eth_hw_addr_set(vport->ndev, vport->mac_addr); + + vport->ndev->min_mtu = MIN_PACKET_SIZE; + vport->ndev->max_mtu = MAX_PACKET_SIZE; + vport->ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM; + vport->ndev->features = vport->ndev->hw_features; + vport->ndev->vlan_features |= NETIF_F_SG; + vport->ndev->netdev_ops = &cpsw_proxy_client_netdev_ops; + vport->ndev->ethtool_ops = &cpsw_proxy_client_ethtool_ops; + + ndev_priv->stats = netdev_alloc_pcpu_stats(struct vport_netdev_stats); + if (!ndev_priv->stats) + return -ENOMEM; + + ret = devm_add_action_or_reset(dev, (void(*)(void *))free_percpu, ndev_priv->stats); + if (ret) { + dev_err(dev, "failed to add free_percpu action, err: %d\n", ret); + return ret; + } + + for (i = 0; i < vport->num_tx_chan; i++) { + tx_chn = &vport->tx_chans[i]; + netif_napi_add_tx(vport->ndev, &tx_chn->napi_tx, vport_tx_poll); + hrtimer_init(&tx_chn->tx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); + tx_chn->tx_hrtimer.function = &vport_tx_timer_cb; + } + + for (i = 0; i < vport->num_rx_chan; i++) { + rx_chn = &vport->rx_chans[i]; + netif_napi_add(vport->ndev, &rx_chn->napi_rx, vport_rx_poll); + hrtimer_init(&rx_chn->rx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); + rx_chn->rx_hrtimer.function = &vport_rx_timer_cb; + } + + ret = register_netdev(vport->ndev); + if (ret) + dev_err(dev, "error registering net device, err: %d\n", ret); + + return ret; +} + +static void unreg_netdevs(struct cpsw_proxy_priv *proxy_priv) +{ + struct virtual_port *vport; + u32 i; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + if (vport->ndev) + unregister_netdev(vport->ndev); + } +} + +static void destroy_vport_wqs(struct cpsw_proxy_priv *proxy_priv) +{ + struct virtual_port *vport; + u32 i; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + if (vport->vport_wq) + destroy_workqueue(vport->vport_wq); + } +} + +static int create_vport_wqs(struct cpsw_proxy_priv *proxy_priv) +{ + struct virtual_port *vport; + char wq_name[IFNAMSIZ]; + u32 i; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + if (!(vport->port_features & ETHFW_MCAST_FILTERING)) + continue; + + snprintf(wq_name, sizeof(wq_name), "vport_%d", vport->port_id); + __hw_addr_init(&vport->mcast_list); + INIT_WORK(&vport->rx_mode_work, vport_set_rx_mode_work); + vport->vport_wq = create_singlethread_workqueue(wq_name); + if (!vport->vport_wq) { + dev_err(proxy_priv->dev, "failed to create wq %s\n", wq_name); + goto err; + } + } + + return 0; + +err: + destroy_vport_wqs(proxy_priv); + return -ENOMEM; +} + +static int init_netdevs(struct cpsw_proxy_priv *proxy_priv) +{ + struct virtual_port *vport; + int ret; + u32 i; + + ret = create_vport_wqs(proxy_priv); + if (ret) + return ret; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + ret = init_netdev(proxy_priv, vport); + if (ret) { + dev_err(proxy_priv->dev, "failed to initialize ndev for port %u\n", + vport->port_id); + goto err; + } + } + + return 0; + +err: + unreg_netdevs(proxy_priv); + return ret; +} + +static irqreturn_t tx_irq_handler(int irq, void *dev_id) +{ + struct tx_dma_chan *tx_chn = dev_id; + + disable_irq_nosync(irq); + napi_schedule(&tx_chn->napi_tx); + + return IRQ_HANDLED; +} + +static irqreturn_t rx_irq_handler(int irq, void *dev_id) +{ + struct rx_dma_chan *rx_chn = dev_id; + + rx_chn->rx_irq_disabled = true; + disable_irq_nosync(irq); + napi_schedule(&rx_chn->napi_rx); + + return IRQ_HANDLED; +} + +static int register_dma_irq_handlers(struct cpsw_proxy_priv *proxy_priv) +{ + struct device *dev = proxy_priv->dev; + struct rx_dma_chan *rx_chn; + struct tx_dma_chan *tx_chn; + struct virtual_port *vport; + u32 i, j; + int ret; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + + for (j = 0; j < vport->num_tx_chan; j++) { + tx_chn = &vport->tx_chans[j]; + + ret = devm_request_irq(dev, tx_chn->irq, tx_irq_handler, + IRQF_TRIGGER_HIGH, tx_chn->tx_chan_name, tx_chn); + if (ret) { + dev_err(dev, "failed to request tx irq: %u, err: %d\n", + tx_chn->irq, ret); + return ret; + } + } + + for (j = 0; j < vport->num_rx_chan; j++) { + rx_chn = &vport->rx_chans[j]; + + ret = devm_request_irq(dev, rx_chn->irq, rx_irq_handler, + IRQF_TRIGGER_HIGH, rx_chn->rx_chan_name, rx_chn); + if (ret) { + dev_err(dev, "failed to request rx irq: %u, err: %d\n", + rx_chn->irq, ret); + return ret; + } + } + } + + return 0; +} + +static int register_ipv4(struct virtual_port *vport) +{ + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct device *dev = proxy_priv->dev; + struct cpsw_proxy_req_params *req_p; + struct message resp_msg; + int ret; + + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_IPv4_REGISTER; + req_p->token = vport->port_token; + memcpy(req_p->ipv4_addr, vport->ipv4_addr, ETHFW_IPV4ADDRLEN); + ether_addr_copy(req_p->mac_addr, vport->mac_addr); + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + + if (ret) { + dev_err(dev, "failed to register IPv4 Address err: %d\n", ret); + return -EIO; + } + + return 0; +} + +static int deregister_ipv4(struct virtual_port *vport) +{ + struct cpsw_proxy_priv *proxy_priv = vport->proxy_priv; + struct device *dev = proxy_priv->dev; + struct cpsw_proxy_req_params *req_p; + struct message resp_msg; + int ret; + + mutex_lock(&proxy_priv->req_params_mutex); + req_p = &proxy_priv->req_params; + req_p->request_type = ETHFW_IPv4_DEREGISTER; + req_p->token = vport->port_token; + memcpy(req_p->ipv4_addr, vport->ipv4_addr, ETHFW_IPV4ADDRLEN); + ret = send_request_get_response(proxy_priv, &resp_msg); + mutex_unlock(&proxy_priv->req_params_mutex); + + if (ret) { + dev_err(dev, "failed to deregister IPv4 Address err: %d\n", ret); + return -EIO; + } + + return 0; +} + +static bool cpsw_proxy_client_check(const struct net_device *ndev) +{ + struct virtual_port *vport = vport_ndev_to_vport(ndev); + + return ndev->netdev_ops == &cpsw_proxy_client_netdev_ops && + vport->port_type == VIRT_SWITCH_PORT; +} + +static int cpsw_proxy_client_inetaddr(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; + struct virtual_port *vport; + struct net_device *ndev; + int ret = 0; + + ndev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL; + if (!ndev) + return NOTIFY_DONE; + + if (!cpsw_proxy_client_check(ndev)) + return NOTIFY_DONE; + + vport = vport_ndev_to_vport(ndev); + memcpy(vport->ipv4_addr, &ifa->ifa_address, ETHFW_IPV4ADDRLEN); + + switch (event) { + case NETDEV_UP: + case NETDEV_CHANGEADDR: + ret = register_ipv4(vport); + if (ret) + netdev_err(ndev, "IPv4 register failed: %d\n", ret); + break; + + case NETDEV_DOWN: + case NETDEV_PRE_CHANGEADDR: + ret = deregister_ipv4(vport); + if (ret) + netdev_err(ndev, "IPv4 deregister failed: %d\n", ret); + break; + } + + return notifier_from_errno(ret); +} + +static void unregister_notifiers(struct cpsw_proxy_priv *proxy_priv) +{ + struct virtual_port *vport; + u32 i; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + if (vport->port_type == VIRT_SWITCH_PORT) + unregister_inetaddr_notifier(&vport->inetaddr_nb); + } +} + +static void register_notifiers(struct cpsw_proxy_priv *proxy_priv) +{ + struct virtual_port *vport; + u32 i; + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + if (vport->port_type == VIRT_SWITCH_PORT) { + vport->inetaddr_nb.notifier_call = cpsw_proxy_client_inetaddr; + register_inetaddr_notifier(&vport->inetaddr_nb); + } + } +} + +static void show_info(struct cpsw_proxy_priv *proxy_priv) +{ + struct device *dev = proxy_priv->dev; + struct virtual_port *vport; + u32 i; + + dev_info(dev, "%u Virtual Switch Port(s), %u Virtual MAC Only Port(s)\n", + proxy_priv->num_switch_ports, proxy_priv->num_mac_ports); + + for (i = 0; i < proxy_priv->num_virt_ports; i++) { + vport = &proxy_priv->virt_ports[i]; + + if (vport->port_type == VIRT_SWITCH_PORT) + dev_info(dev, "Virt Port: %u, Type: Switch Port, Iface: %s, Num TX: %u, Num RX: %u, Token: %u\n", + vport->port_id, vport->ndev->name, vport->num_tx_chan, + vport->num_rx_chan, vport->port_token); + else + dev_info(dev, "Virt Port: %u, Type: MAC Port, Iface: %s, Num TX: %u, Num RX: %u, Token: %u\n", + vport->port_id, vport->ndev->name, vport->num_tx_chan, + vport->num_rx_chan, vport->port_token); + } +} + +static int cpsw_proxy_client_probe(struct rpmsg_device *rpdev) +{ + struct cpsw_proxy_priv *proxy_priv; + int ret; + + proxy_priv = devm_kzalloc(&rpdev->dev, sizeof(struct cpsw_proxy_priv), GFP_KERNEL); + if (!proxy_priv) + return -ENOMEM; + + proxy_priv->rpdev = rpdev; + proxy_priv->dev = &rpdev->dev; + proxy_priv->dma_node = of_find_compatible_node(NULL, NULL, + (const char *)rpdev->id.driver_data); + dev_set_drvdata(proxy_priv->dev, proxy_priv); + dev_dbg(proxy_priv->dev, "driver probed\n"); + + proxy_priv->req_params.token = ETHFW_TOKEN_NONE; + proxy_priv->req_params.client_id = ETHFW_LINUX_CLIENT_TOKEN; + mutex_init(&proxy_priv->req_params_mutex); + init_completion(&proxy_priv->wait_for_response); + + ret = get_virtual_port_info(proxy_priv); + if (ret) + return -EIO; + + ret = attach_virtual_ports(proxy_priv); + if (ret) + return -EIO; + + ret = allocate_port_resources(proxy_priv); + if (ret) + goto err_attach; + + ret = dma_coerce_mask_and_coherent(proxy_priv->dev, DMA_BIT_MASK(48)); + if (ret) { + dev_err(proxy_priv->dev, "error setting dma mask: %d\n", ret); + goto err_attach; + } + + ret = init_tx_chans(proxy_priv); + if (ret) + goto err_attach; + + ret = init_rx_chans(proxy_priv); + if (ret) + goto err_attach; + + ret = init_netdevs(proxy_priv); + if (ret) + goto err_attach; + + ret = register_dma_irq_handlers(proxy_priv); + if (ret) + goto err_netdevs; + + register_notifiers(proxy_priv); + show_info(proxy_priv); + + return 0; + +err_netdevs: + unreg_netdevs(proxy_priv); +err_attach: + detach_virtual_ports(proxy_priv); + return ret; +} + +static void cpsw_proxy_client_remove(struct rpmsg_device *rpdev) +{ + struct cpsw_proxy_priv *proxy_priv; + struct device *dev = &rpdev->dev; + + dev_dbg(dev, "driver removed\n"); + proxy_priv = dev_get_drvdata(&rpdev->dev); + unregister_notifiers(proxy_priv); + unreg_netdevs(proxy_priv); + destroy_vport_wqs(proxy_priv); + detach_virtual_ports(proxy_priv); +} + +static struct rpmsg_device_id cpsw_proxy_client_id_table[] = { + { + .name = ETHFW_SERVICE_EP_NAME, + .driver_data = (kernel_ulong_t)"ti,j721e-navss-main-udmap", + }, + {}, +}; +MODULE_DEVICE_TABLE(rpmsg, cpsw_proxy_client_id_table); + +static struct rpmsg_driver cpsw_proxy_client_driver = { + .drv.name = KBUILD_MODNAME, + .id_table = cpsw_proxy_client_id_table, + .probe = cpsw_proxy_client_probe, + .callback = cpsw_proxy_client_cb, + .remove = cpsw_proxy_client_remove, +}; +module_rpmsg_driver(cpsw_proxy_client_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CPSW Proxy Client Driver"); +MODULE_AUTHOR("Siddharth Vadapalli "); diff -Naur --no-dereference a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c --- a/drivers/net/ethernet/ti/davinci_emac.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/davinci_emac.c 2024-07-07 20:37:34.668306669 -0400 @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -47,10 +48,7 @@ #include #include #include -#include -#include #include -#include #include #include @@ -1726,13 +1724,10 @@ #endif }; -static const struct of_device_id davinci_emac_of_match[]; - static struct emac_platform_data * davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv) { struct device_node *np; - const struct of_device_id *match; const struct emac_platform_data *auxdata; struct emac_platform_data *pdata = NULL; @@ -1779,9 +1774,8 @@ pdata->interrupt_disable = auxdata->interrupt_disable; } - match = of_match_device(davinci_emac_of_match, &pdev->dev); - if (match && match->data) { - auxdata = match->data; + auxdata = device_get_match_data(&pdev->dev); + if (auxdata) { pdata->version = auxdata->version; pdata->hw_ram_addr = auxdata->hw_ram_addr; } @@ -1934,18 +1928,20 @@ goto err_free_rxchan; ndev->irq = rc; - rc = davinci_emac_try_get_mac(pdev, res_ctrl ? 0 : 1, priv->mac_addr); - if (!rc) - eth_hw_addr_set(ndev, priv->mac_addr); - + /* If the MAC address is not present, read the registers from the SoC */ if (!is_valid_ether_addr(priv->mac_addr)) { - /* Use random MAC if still none obtained. */ - eth_hw_addr_random(ndev); - memcpy(priv->mac_addr, ndev->dev_addr, ndev->addr_len); - dev_warn(&pdev->dev, "using random MAC addr: %pM\n", - priv->mac_addr); + rc = davinci_emac_try_get_mac(pdev, res_ctrl ? 0 : 1, priv->mac_addr); + if (!rc) + eth_hw_addr_set(ndev, priv->mac_addr); + + if (!is_valid_ether_addr(priv->mac_addr)) { + /* Use random MAC if still none obtained. */ + eth_hw_addr_random(ndev); + memcpy(priv->mac_addr, ndev->dev_addr, ndev->addr_len); + dev_warn(&pdev->dev, "using random MAC addr: %pM\n", + priv->mac_addr); + } } - ndev->netdev_ops = &emac_netdev_ops; ndev->ethtool_ops = ðtool_ops; netif_napi_add(ndev, &priv->napi, emac_poll); diff -Naur --no-dereference a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c --- a/drivers/net/ethernet/ti/davinci_mdio.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/davinci_mdio.c 2024-07-07 20:37:34.668306669 -0400 @@ -511,16 +511,12 @@ }; static const struct soc_device_attribute k3_mdio_socinfo[] = { - { .family = "AM62X", .revision = "SR1.0", .data = &am65_mdio_soc_data }, - { .family = "AM64X", .revision = "SR1.0", .data = &am65_mdio_soc_data }, - { .family = "AM64X", .revision = "SR2.0", .data = &am65_mdio_soc_data }, - { .family = "AM65X", .revision = "SR1.0", .data = &am65_mdio_soc_data }, - { .family = "AM65X", .revision = "SR2.0", .data = &am65_mdio_soc_data }, - { .family = "J7200", .revision = "SR1.0", .data = &am65_mdio_soc_data }, - { .family = "J7200", .revision = "SR2.0", .data = &am65_mdio_soc_data }, - { .family = "J721E", .revision = "SR1.0", .data = &am65_mdio_soc_data }, - { .family = "J721E", .revision = "SR2.0", .data = &am65_mdio_soc_data }, - { .family = "J721S2", .revision = "SR1.0", .data = &am65_mdio_soc_data}, + { .family = "AM62X", .data = &am65_mdio_soc_data }, + { .family = "AM64X", .data = &am65_mdio_soc_data }, + { .family = "AM65X", .data = &am65_mdio_soc_data }, + { .family = "J7200", .data = &am65_mdio_soc_data }, + { .family = "J721E", .data = &am65_mdio_soc_data }, + { .family = "J721S2", .data = &am65_mdio_soc_data }, { /* sentinel */ }, }; diff -Naur --no-dereference a/drivers/net/ethernet/ti/ethfw_abi.h b/drivers/net/ethernet/ti/ethfw_abi.h --- a/drivers/net/ethernet/ti/ethfw_abi.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/ethernet/ti/ethfw_abi.h 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,394 @@ +/* SPDX-License-Identifier: GPL-2.0-only or MIT */ +/* Texas Instruments Ethernet Switch Firmware (EthFw) ABIs + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +#ifndef __ETHFW_ABI_H_ +#define __ETHFW_ABI_H_ + +/* Name of the RPMsg Endpoint announced by EthFw on the RPMsg-Bus */ +#define ETHFW_SERVICE_EP_NAME "ti.ethfw.ethdevice" + +/* Response status set by EthFw on the Success of a Request */ +#define ETHFW_RES_OK (0) + +/* Response status set by EthFw when an operation is in progress */ +#define ETHFW_RES_SINPROGRESS (1) + +/* Response status set by EthFw on the Failure of a Request */ +#define ETHFW_RES_EFAIL (-1) + +/* Response status set by EthFw when Client passes wrong arguments */ +#define ETHFW_RES_EBADARGS (-2) + +/* Default VLAN ID for a Virtual Port */ +#define ETHFW_DFLT_VLAN 0xFFFF + +/* EthFw TX Checksum Offload Capability */ +#define ETHFW_TX_CSUM_OFFLOAD BIT(0) + +/* EthFw Multicast Filtering Capability */ +#define ETHFW_MCAST_FILTERING BIT(1) + +/* Token corresponding to the Linux CPSW Proxy Client assigned by EthFw */ +#define ETHFW_LINUX_CLIENT_TOKEN 3 + +/* Default token used by Virtual Port to communicate with EthFw */ +#define ETHFW_TOKEN_NONE 0xFFFFFFFF + +/* MAC Address length in octets */ +#define ETHFW_MACADDRLEN 6 + +/* IPV4 Address length in octets */ +#define ETHFW_IPV4ADDRLEN 4 + +/* Types of request messages sent to EthFw from CPSW Proxy Client */ +enum request_msg_type { + /* Request details of Virtual Ports allocated to the Client. + * Two types of Virtual Ports exist: + * 1. MAC Only Port: + * The Physical MAC Port corresponding to this type of Virtual + * Port does not belong to the group of MAC Ports which Switch + * traffic among themselves. The Physical MAC Port is dedicated + * solely to the Client which has been allocated this type of + * Virtual Port. + * + * 2. Switch Port: + * The Physical MAC Port corresponding to this type of Virtual + * Port belongs to the group of MAC Ports which Switch traffic + * among themselves. The Physical MAC Port is shared with other + * Clients in terms of the traffic that is sent out of or received + * on this port. + * + * EthFw responds to this request by providing a bitmask of the + * Virtual Port IDs for each type of Virtual Port allocated to + * the Client. + */ + ETHFW_VIRT_PORT_INFO, + + /* Request usage of a Virtual Port that has been allocated to the + * Client. + * + * EthFw responds with details of the supported MTU size, the number + * of TX DMA Channels and the number of RX DMA Flows for the specified + * Virtual Port. + */ + ETHFW_VIRT_PORT_ATTACH, + + ETHFW_UNUSED_REQUEST_1, + + /* Request disuse of a Virtual Port that was in use prior to the + * generation of this request. + */ + ETHFW_VIRT_PORT_DETACH, + + /* Request to get link status */ + ETHFW_VIRT_PORT_LINK_STATUS, + + /* Request for allocation of a TX DMA Channel for a Virtual Port. + * Client can request as many TX DMA Channels as have been allocated + * by EthFw for the specified Virtual Port. + * + * EthFw responds with the TX PSI-L Thread ID corresponding to + * the TX DMA Channel for the Virtual Port to transmit traffic + * to CPSW. + */ + ETHFW_ALLOC_TX, + + /* Request for allocation of an RX DMA Flow for a Virtual Port. + * Client can request as many RX DMA Flows as have been allocated + * by EthFw for the specified Virtual Port. + * + * EthFw responds with the RX PSI-L Thread ID, the base of the RX + * Flow index and the offset from the base of the allocated RX Flow + * index. The RX Flow/Channel is used to receive traffic from CPSW. + */ + ETHFW_ALLOC_RX, + + /* Request for allocation of the MAC Address for a Virtual Port. + * + * EthFw responds with the MAC Address corresponding to the + * specified Virtual Port. + */ + ETHFW_ALLOC_MAC, + + /* Request for release of a TX DMA Channel that had been allocated + * to the specified Virtual Port. + */ + ETHFW_FREE_TX, + + /* Request for release of an RX DMA Flow that had been allocated to + * the specified Virtual Port. + */ + ETHFW_FREE_RX, + + /* Request for release of the MAC Address that had been allocated to + * the specified Virtual Port. + */ + ETHFW_FREE_MAC, + + /* Request for usage of the specified MAC Address for the traffic + * sent or received on the Virtual Port for which the MAC Address + * has been allocated. + */ + ETHFW_MAC_REGISTER, + + /* Request for disuse of the specified MAC Address for the traffic + * sent or received on the Virtual Port for which the MAC Address + * had been allocated. + */ + ETHFW_MAC_DEREGISTER, + + /* Request for setting the default RX DMA Flow for a Virtual Port. */ + ETHFW_SET_DEFAULT_RX_FLOW, + + /* Request for deleting the default RX DMA Flow for a Virtual Port. */ + ETHFW_DEL_DEFAULT_RX_FLOW, + + /* Request for registering the IPv4 Address of the Network Interface + * in Linux corresponding to the specified Virtual Port. + */ + ETHFW_IPv4_REGISTER, + + /* Request for deregistering the IPv4 Address of the Network Interface + * in Linux corresponding to the specified Virtual Port that had been + * registered prior to this request. + */ + ETHFW_IPv4_DEREGISTER, + + /* Request for joining a VLAN */ + ETHFW_JOIN_VLAN, + + /* Request for leaving a VLAN */ + ETHFW_LEAVE_VLAN, + + /* Request for joining a Multicast Address group */ + ETHFW_MCAST_FILTER_ADD, + + /* Request for leaving a Multicast Address group */ + ETHFW_MCAST_FILTER_DEL, + + ETHFW_UNUSED_REQUEST_2, + ETHFW_UNUSED_REQUEST_3, + ETHFW_UNUSED_REQUEST_4, + ETHFW_UNUSED_REQUEST_5, + ETHFW_UNUSED_REQUEST_6, + + /* Request for notifying teardown completion status */ + ETHFW_TEARDOWN_COMPLETE, +}; + +enum notify_msg_type { + ETHFW_NOTIFYCLIENT_FWINFO, + ETHFW_NOTIFYCLIENT_HWPUSH, + ETHFW_NOTIFYCLIENT_HWERROR, + ETHFW_NOTIFYCLIENT_RECOVERED, + ETHFW_NOTIFYCLIENT_CUSTOM, + ETHFW_NOTIFYCLIENT_LAST, +}; + +enum ethfw_status { + ETHFW_UNINIT, + ETHFW_READY, + ETHFW_RECOVERY, + ETHFW_BAD, +}; + +enum message_type { + ETHFW_MSG_REQUEST, + ETHFW_MSG_NOTIFY, + ETHFW_MSG_RESPONSE, +}; + +struct message_header { + u32 token; + u32 client_id; + u32 msg_type; +} __packed; + +struct message { + struct message_header msg_hdr; + u32 message_data[120]; +} __packed; + +struct request_message_header { + struct message_header msg_hdr; + u32 request_type; + u32 request_id; +} __packed; + +struct response_message_header { + struct message_header msg_hdr; + u32 response_type; /* Same as request_type */ + u32 response_id; + int response_status; +} __packed; + +struct notify_message_header { + struct message_header msg_hdr; + u32 notify_type; +} __packed; + +struct common_response_message { + struct response_message_header response_msg_hdr; +} __packed; + +struct common_request_message { + struct request_message_header request_msg_hdr; +} __packed; + +struct common_notify_message { + struct notify_message_header notify_msg_hdr; +} __packed; + +struct virt_port_info_response { + struct response_message_header response_msg_hdr; + /* Port mask denoting absolute virtual switch ports allocated */ + u32 switch_port_mask; + /* Port mask denoting absolute virtual MAC ports allocated */ + u32 mac_port_mask; +} __packed; + +struct attach_request { + struct request_message_header request_msg_hdr; + /* Virtual port which needs core attach */ + u32 virt_port; +} __packed; + +struct attach_response { + struct response_message_header response_msg_hdr; + /* MTU of RX packet */ + u32 rx_mtu; + /* MTU of TX packet */ + u32 tx_mtu; + /* Feature bitmask */ + u32 features; + /* Number of TX DMA Channels available for the virtual port */ + u32 num_tx_chan; + /* Number of RX DMA Flows available for the virtual port */ + u32 num_rx_flow; +} __packed; + +struct rx_flow_alloc_request { + struct request_message_header request_msg_hdr; + /* Relative index of RX flow among available num_rx_flow flows */ + u32 rx_flow_idx; +} __packed; + +struct rx_flow_alloc_response { + struct response_message_header response_msg_hdr; + /* Allocated RX flow index base */ + u32 rx_flow_idx_base; + /* Allocated flow index offset */ + u32 rx_flow_idx_offset; + /* RX PSIL Peer source thread id */ + u32 rx_psil_src_id; +} __packed; + +struct tx_thread_alloc_request { + struct request_message_header request_msg_hdr; + /* Relative index of TX channel among available num_tx_chan channels */ + u32 tx_chan_idx; +} __packed; + +struct tx_thread_alloc_response { + struct response_message_header response_msg_hdr; + /* TX PSIL peer destination thread id which should be paired with the TX UDMA channel */ + u32 tx_psil_dest_id; +} __packed; + +struct mac_alloc_response { + struct response_message_header response_msg_hdr; + /* Allocated MAC address */ + u8 mac_addr[ETHFW_MACADDRLEN]; +} __packed; + +struct rx_flow_release_request { + struct request_message_header request_msg_hdr; + /* RX flow index base */ + u32 rx_flow_idx_base; + /* RX flow index offset */ + u32 rx_flow_idx_offset; +} __packed; + +struct tx_thread_release_request { + struct request_message_header request_msg_hdr; + /* TX PSIL Peer destination thread id to be freed */ + u32 tx_psil_dest_id; +} __packed; + +struct mac_release_request { + struct request_message_header request_msg_hdr; + /* MAC address to be freed */ + u8 mac_addr[ETHFW_MACADDRLEN]; +} __packed; + +struct mac_register_deregister_request { + struct request_message_header request_msg_hdr; + /* MAC address which needs to be registered/deregistered */ + u8 mac_addr[ETHFW_MACADDRLEN]; + /* RX flow index Base */ + u32 rx_flow_idx_base; + /* RX flow index offset */ + u32 rx_flow_idx_offset; +} __packed; + +struct ipv4_register_request { + struct request_message_header request_msg_hdr; + /* IPv4 Address */ + u8 ipv4_addr[ETHFW_IPV4ADDRLEN]; + /* MAC address associated with the IP address which should be added to + * the ARP table + */ + u8 mac_addr[ETHFW_MACADDRLEN]; +} __packed; + +struct ipv4_deregister_request { + struct request_message_header request_msg_hdr; + /* IPv4 Address */ + u8 ipv4_addr[ETHFW_IPV4ADDRLEN]; +} __packed; + +struct default_rx_flow_register_request { + struct request_message_header request_msg_hdr; + /* RX flow index Base */ + u32 rx_flow_idx_base; + /* RX flow index offset */ + u32 rx_flow_idx_offset; +} __packed; + +struct port_link_status_response { + struct response_message_header response_msg_hdr; + /* Link status of the port */ + bool link_up; + /* Link speed */ + u32 speed; + /* Duplex mode */ + u32 duplex; +} __packed; + +struct add_multicast_request { + struct request_message_header request_msg_hdr; + /* Multicast MAC address to be added */ + u8 mac_addr[ETHFW_MACADDRLEN]; + /* VLAN id */ + u16 vlan_id; + /* RX flow index from which the MAC_address association will be added. + * It's applicable only for _exclusive multicast traffic_ + */ + u32 rx_flow_idx_base; + /* RX flow index offset */ + u32 rx_flow_idx_offset; +} __packed; + +struct del_multicast_request { + struct request_message_header request_msg_hdr; + /* Multicast MAC address to be added */ + u8 mac_addr[ETHFW_MACADDRLEN]; + /* VLAN id */ + u16 vlan_id; +} __packed; + +#endif /* __ETHFW_ABI_H_ */ diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_classifier.c b/drivers/net/ethernet/ti/icssg/icssg_classifier.c --- a/drivers/net/ethernet/ti/icssg/icssg_classifier.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/icssg/icssg_classifier.c 2024-07-07 20:37:34.668306669 -0400 @@ -274,6 +274,16 @@ regmap_write(miig_rt, offset, data); } +static u32 rx_class_get_or(struct regmap *miig_rt, int slice, int n) +{ + u32 offset, val; + + offset = RX_CLASS_N_REG(slice, n, RX_CLASS_OR_EN); + regmap_read(miig_rt, offset, &val); + + return val; +} + void icssg_class_set_host_mac_addr(struct regmap *miig_rt, const u8 *mac) { regmap_write(miig_rt, MAC_INTERFACE_0, (u32)(mac[0] | mac[1] << 8 | @@ -288,6 +298,26 @@ regmap_write(miig_rt, offs[slice].mac1, (u32)(mac[4] | mac[5] << 8)); } +static void icssg_class_ft1_add_mcast(struct regmap *miig_rt, int slice, + int slot, const u8 *addr, const u8 *mask) +{ + u32 val; + int i; + + WARN(slot >= FT1_NUM_SLOTS, "invalid slot: %d\n", slot); + + rx_class_ft1_set_da(miig_rt, slice, slot, addr); + rx_class_ft1_set_da_mask(miig_rt, slice, slot, mask); + rx_class_ft1_cfg_set_type(miig_rt, slice, slot, FT1_CFG_TYPE_EQ); + + /* Enable the FT1 slot in OR enable for all classifiers */ + for (i = 0; i < ICSSG_NUM_CLASSIFIERS_IN_USE; i++) { + val = rx_class_get_or(miig_rt, slice, i); + val |= RX_CLASS_FT_FT1_MATCH(slot); + rx_class_set_or(miig_rt, slice, i, val); + } +} + /* disable all RX traffic */ void icssg_class_disable(struct regmap *miig_rt, int slice) { @@ -331,28 +361,93 @@ regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0); } -void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti) +void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti, + bool is_sr1) { + int num_classifiers = is_sr1 ? ICSSG_NUM_CLASSIFIERS_IN_USE : 1; u32 data; + int n; /* defaults */ icssg_class_disable(miig_rt, slice); /* Setup Classifier */ - /* match on Broadcast or MAC_PRU address */ - data = RX_CLASS_FT_BC | RX_CLASS_FT_DA_P; + for (n = 0; n < num_classifiers; n++) { + /* match on Broadcast or MAC_PRU address */ + data = RX_CLASS_FT_BC | RX_CLASS_FT_DA_P; + + /* multicast */ + if (allmulti) + data |= RX_CLASS_FT_MC; + + rx_class_set_or(miig_rt, slice, n, data); + + /* set CFG1 for OR_OR_AND for classifier */ + rx_class_sel_set_type(miig_rt, slice, n, + RX_CLASS_SEL_TYPE_OR_OR_AND); + } - /* multicast */ - if (allmulti) - data |= RX_CLASS_FT_MC; + /* clear CFG2 */ + regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0); +} - rx_class_set_or(miig_rt, slice, 0, data); +void icssg_class_promiscuous_sr1(struct regmap *miig_rt, int slice) +{ + u32 data, offset; + int n; - /* set CFG1 for OR_OR_AND for classifier */ - rx_class_sel_set_type(miig_rt, slice, 0, RX_CLASS_SEL_TYPE_OR_OR_AND); + /* defaults */ + icssg_class_disable(miig_rt, slice); - /* clear CFG2 */ - regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0); + /* Setup Classifier */ + for (n = 0; n < ICSSG_NUM_CLASSIFIERS_IN_USE; n++) { + /* set RAW_MASK to bypass filters */ + offset = RX_CLASS_GATES_N_REG(slice, n); + regmap_read(miig_rt, offset, &data); + data |= RX_CLASS_GATES_RAW_MASK; + regmap_write(miig_rt, offset, data); + } +} + +void icssg_class_add_mcast_sr1(struct regmap *miig_rt, int slice, + struct net_device *ndev) +{ + u8 mask_addr[6] = { 0, 0, 0, 0, 0, 0xff }; + struct netdev_hw_addr *ha; + int slot = 2; + + rx_class_ft1_set_start_len(miig_rt, slice, 0, 6); + /* reserve first 2 slots for + * 1) 01-80-C2-00-00-XX Known Service Ethernet Multicast addresses + * 2) 01-00-5e-00-00-XX Local Network Control Block + * (224.0.0.0 - 224.0.0.255 (224.0.0/24)) + */ + icssg_class_ft1_add_mcast(miig_rt, slice, 0, + eth_reserved_addr_base, mask_addr); + icssg_class_ft1_add_mcast(miig_rt, slice, 1, + eth_ipv4_mcast_addr_base, mask_addr); + mask_addr[5] = 0; + netdev_for_each_mc_addr(ha, ndev) { + /* skip addresses matching reserved slots */ + if (!memcmp(eth_reserved_addr_base, ha->addr, 5) || + !memcmp(eth_ipv4_mcast_addr_base, ha->addr, 5)) { + netdev_dbg(ndev, "mcast skip %pM\n", ha->addr); + continue; + } + + if (slot >= FT1_NUM_SLOTS) { + netdev_dbg(ndev, + "can't add more than %d MC addresses, enabling allmulti\n", + FT1_NUM_SLOTS); + icssg_class_default(miig_rt, slice, 1, true); + break; + } + + netdev_dbg(ndev, "mcast add %pM\n", ha->addr); + icssg_class_ft1_add_mcast(miig_rt, slice, slot, + ha->addr, mask_addr); + slot++; + } } /* required for SAV check */ @@ -360,7 +455,7 @@ { const u8 mask_addr[] = { 0, 0, 0, 0, 0, 0, }; - rx_class_ft1_set_start_len(miig_rt, slice, 0, 6); + rx_class_ft1_set_start_len(miig_rt, slice, 6, 6); rx_class_ft1_set_da(miig_rt, slice, 0, mac_addr); rx_class_ft1_set_da_mask(miig_rt, slice, 0, mask_addr); rx_class_ft1_cfg_set_type(miig_rt, slice, 0, FT1_CFG_TYPE_EQ); diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c --- a/drivers/net/ethernet/ti/icssg/icssg_common.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/ethernet/ti/icssg/icssg_common.c 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,1381 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* Texas Instruments ICSSG Ethernet Driver + * + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) Siemens AG, 2024 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "icssg_prueth.h" +#include "../k3-cppi-desc-pool.h" + +/* Netif debug messages possible */ +#define PRUETH_EMAC_DEBUG (NETIF_MSG_DRV | \ + NETIF_MSG_PROBE | \ + NETIF_MSG_LINK | \ + NETIF_MSG_TIMER | \ + NETIF_MSG_IFDOWN | \ + NETIF_MSG_IFUP | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR | \ + NETIF_MSG_TX_QUEUED | \ + NETIF_MSG_INTR | \ + NETIF_MSG_TX_DONE | \ + NETIF_MSG_RX_STATUS | \ + NETIF_MSG_PKTDATA | \ + NETIF_MSG_HW | \ + NETIF_MSG_WOL) + +#define prueth_napi_to_emac(napi) container_of(napi, struct prueth_emac, napi_rx) + +void prueth_cleanup_rx_chns(struct prueth_emac *emac, + struct prueth_rx_chn *rx_chn, + int max_rflows) +{ + if (rx_chn->pg_pool) { + page_pool_destroy(rx_chn->pg_pool); + rx_chn->pg_pool = NULL; + } + + if (rx_chn->desc_pool) + k3_cppi_desc_pool_destroy(rx_chn->desc_pool); + + if (rx_chn->rx_chn) + k3_udma_glue_release_rx_chn(rx_chn->rx_chn); +} + +void prueth_cleanup_tx_chns(struct prueth_emac *emac) +{ + int i; + + for (i = 0; i < emac->tx_ch_num; i++) { + struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; + + if (tx_chn->desc_pool) + k3_cppi_desc_pool_destroy(tx_chn->desc_pool); + + if (tx_chn->tx_chn) + k3_udma_glue_release_tx_chn(tx_chn->tx_chn); + + /* Assume prueth_cleanup_tx_chns() is called at the + * end after all channel resources are freed + */ + memset(tx_chn, 0, sizeof(*tx_chn)); + } +} + +void prueth_ndev_del_tx_napi(struct prueth_emac *emac, int num) +{ + int i; + + for (i = 0; i < num; i++) { + struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; + + if (tx_chn->irq) + free_irq(tx_chn->irq, tx_chn); + netif_napi_del(&tx_chn->napi_tx); + } +} + +void prueth_xmit_free(struct prueth_tx_chn *tx_chn, + struct cppi5_host_desc_t *desc) +{ + struct cppi5_host_desc_t *first_desc, *next_desc; + dma_addr_t buf_dma, next_desc_dma; + struct prueth_swdata *swdata; + u32 buf_dma_len; + + first_desc = desc; + next_desc = first_desc; + + swdata = cppi5_hdesc_get_swdata(desc); + if (swdata->type == PRUETH_SWDATA_PAGE) { + page_pool_recycle_direct(swdata->rx_chn->pg_pool, + swdata->data.page); + goto free_desc; + } + + cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); + + dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len, + DMA_TO_DEVICE); + + next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); + while (next_desc_dma) { + next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, + next_desc_dma); + cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); + + dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len, + DMA_TO_DEVICE); + + next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); + + k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); + } + +free_desc: + k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc); +} + +int emac_tx_complete_packets(struct prueth_emac *emac, int chn, + int budget, bool *tdown) +{ + struct net_device *ndev = emac->ndev; + struct cppi5_host_desc_t *desc_tx; + struct netdev_queue *netif_txq; + struct prueth_swdata *swdata; + struct prueth_tx_chn *tx_chn; + unsigned int total_bytes = 0; + struct xdp_frame *xdpf; + struct sk_buff *skb; + dma_addr_t desc_dma; + int res, num_tx = 0; + + tx_chn = &emac->tx_chns[chn]; + + while (true) { + res = k3_udma_glue_pop_tx_chn(tx_chn->tx_chn, &desc_dma); + if (res == -ENODATA) + break; + + /* teardown completion */ + if (cppi5_desc_is_tdcm(desc_dma)) { + if (atomic_dec_and_test(&emac->tdown_cnt)) + complete(&emac->tdown_complete); + *tdown = true; + break; + } + + desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, + desc_dma); + swdata = cppi5_hdesc_get_swdata(desc_tx); + + /* was this command's TX complete? */ + if (emac->is_sr1 && (void *)(swdata) == emac->cmd_data) { + prueth_xmit_free(tx_chn, desc_tx); + continue; + } + + switch (swdata->type) { + case PRUETH_SWDATA_SKB: + skb = swdata->data.skb; + ndev->stats.tx_bytes += skb->len; + ndev->stats.tx_packets++; + total_bytes += skb->len; + napi_consume_skb(skb, budget); + break; + case PRUETH_SWDATA_XDPF: + xdpf = swdata->data.xdpf; + ndev->stats.tx_bytes += xdpf->len; + ndev->stats.tx_packets++; + total_bytes += xdpf->len; + xdp_return_frame(xdpf); + break; + default: + netdev_err(ndev, "tx_complete: invalid swdata type %d\n", swdata->type); + prueth_xmit_free(tx_chn, desc_tx); + budget++; + continue; + } + + prueth_xmit_free(tx_chn, desc_tx); + num_tx++; + } + + if (!num_tx) + return 0; + + netif_txq = netdev_get_tx_queue(ndev, chn); + netdev_tx_completed_queue(netif_txq, num_tx, total_bytes); + + if (netif_tx_queue_stopped(netif_txq)) { + /* If the TX queue was stopped, wake it now + * if we have enough room. + */ + __netif_tx_lock(netif_txq, smp_processor_id()); + if (netif_running(ndev) && + (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >= + MAX_SKB_FRAGS)) + netif_tx_wake_queue(netif_txq); + __netif_tx_unlock(netif_txq); + } + + return num_tx; +} + +static enum hrtimer_restart emac_tx_timer_callback(struct hrtimer *timer) +{ + struct prueth_tx_chn *tx_chns = + container_of(timer, struct prueth_tx_chn, tx_hrtimer); + + enable_irq(tx_chns->irq); + return HRTIMER_NORESTART; +} + +static int emac_napi_tx_poll(struct napi_struct *napi_tx, int budget) +{ + struct prueth_tx_chn *tx_chn = prueth_napi_to_tx_chn(napi_tx); + struct prueth_emac *emac = tx_chn->emac; + bool tdown = false; + int num_tx_packets; + + num_tx_packets = emac_tx_complete_packets(emac, tx_chn->id, budget, + &tdown); + + if (num_tx_packets >= budget) + return budget; + + if (napi_complete_done(napi_tx, num_tx_packets)) { + if (unlikely(tx_chn->tx_pace_timeout_ns && !tdown)) { + hrtimer_start(&tx_chn->tx_hrtimer, + ns_to_ktime(tx_chn->tx_pace_timeout_ns), + HRTIMER_MODE_REL_PINNED); + } else { + enable_irq(tx_chn->irq); + } + } + + return num_tx_packets; +} + +static irqreturn_t prueth_tx_irq(int irq, void *dev_id) +{ + struct prueth_tx_chn *tx_chn = dev_id; + + disable_irq_nosync(irq); + napi_schedule(&tx_chn->napi_tx); + + return IRQ_HANDLED; +} + +int prueth_ndev_add_tx_napi(struct prueth_emac *emac) +{ + struct prueth *prueth = emac->prueth; + int i, ret; + + for (i = 0; i < emac->tx_ch_num; i++) { + struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; + + netif_napi_add_tx(emac->ndev, &tx_chn->napi_tx, emac_napi_tx_poll); + hrtimer_init(&tx_chn->tx_hrtimer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL_PINNED); + tx_chn->tx_hrtimer.function = &emac_tx_timer_callback; + ret = request_irq(tx_chn->irq, prueth_tx_irq, + IRQF_TRIGGER_HIGH, tx_chn->name, + tx_chn); + if (ret) { + netif_napi_del(&tx_chn->napi_tx); + dev_err(prueth->dev, "unable to request TX IRQ %d\n", + tx_chn->irq); + goto fail; + } + } + + return 0; +fail: + prueth_ndev_del_tx_napi(emac, i); + return ret; +} + +int prueth_init_tx_chns(struct prueth_emac *emac) +{ + static const struct k3_ring_cfg ring_cfg = { + .elm_size = K3_RINGACC_RING_ELSIZE_8, + .mode = K3_RINGACC_RING_MODE_RING, + .flags = 0, + .size = PRUETH_MAX_TX_DESC, + }; + struct k3_udma_glue_tx_channel_cfg tx_cfg; + struct device *dev = emac->prueth->dev; + struct net_device *ndev = emac->ndev; + int ret, slice, i; + u32 hdesc_size; + + slice = prueth_emac_slice(emac); + if (slice < 0) + return slice; + + init_completion(&emac->tdown_complete); + + hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE, + PRUETH_NAV_SW_DATA_SIZE); + memset(&tx_cfg, 0, sizeof(tx_cfg)); + tx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE; + tx_cfg.tx_cfg = ring_cfg; + tx_cfg.txcq_cfg = ring_cfg; + + for (i = 0; i < emac->tx_ch_num; i++) { + struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; + + /* To differentiate channels for SLICE0 vs SLICE1 */ + snprintf(tx_chn->name, sizeof(tx_chn->name), + "tx%d-%d", slice, i); + + tx_chn->emac = emac; + tx_chn->id = i; + tx_chn->descs_num = PRUETH_MAX_TX_DESC; + + tx_chn->tx_chn = + k3_udma_glue_request_tx_chn(dev, tx_chn->name, + &tx_cfg); + if (IS_ERR(tx_chn->tx_chn)) { + ret = PTR_ERR(tx_chn->tx_chn); + tx_chn->tx_chn = NULL; + netdev_err(ndev, + "Failed to request tx dma ch: %d\n", ret); + goto fail; + } + + tx_chn->dma_dev = k3_udma_glue_tx_get_dma_device(tx_chn->tx_chn); + tx_chn->desc_pool = + k3_cppi_desc_pool_create_name(tx_chn->dma_dev, + tx_chn->descs_num, + hdesc_size, + tx_chn->name); + if (IS_ERR(tx_chn->desc_pool)) { + ret = PTR_ERR(tx_chn->desc_pool); + tx_chn->desc_pool = NULL; + netdev_err(ndev, "Failed to create tx pool: %d\n", ret); + goto fail; + } + + ret = k3_udma_glue_tx_get_irq(tx_chn->tx_chn); + if (ret < 0) { + netdev_err(ndev, "failed to get tx irq\n"); + goto fail; + } + tx_chn->irq = ret; + + snprintf(tx_chn->name, sizeof(tx_chn->name), "%s-tx%d", + dev_name(dev), tx_chn->id); + } + + return 0; + +fail: + prueth_cleanup_tx_chns(emac); + return ret; +} + +int prueth_init_rx_chns(struct prueth_emac *emac, + struct prueth_rx_chn *rx_chn, + char *name, u32 max_rflows, + u32 max_desc_num) +{ + struct k3_udma_glue_rx_channel_cfg rx_cfg; + struct device *dev = emac->prueth->dev; + struct net_device *ndev = emac->ndev; + u32 fdqring_id, hdesc_size; + int i, ret = 0, slice; + int flow_id_base; + + slice = prueth_emac_slice(emac); + if (slice < 0) + return slice; + + /* To differentiate channels for SLICE0 vs SLICE1 */ + snprintf(rx_chn->name, sizeof(rx_chn->name), "%s%d", name, slice); + + hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE, + PRUETH_NAV_SW_DATA_SIZE); + memset(&rx_cfg, 0, sizeof(rx_cfg)); + rx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE; + rx_cfg.flow_id_num = max_rflows; + rx_cfg.flow_id_base = -1; /* udmax will auto select flow id base */ + + /* init all flows */ + rx_chn->dev = dev; + rx_chn->descs_num = max_desc_num; + + rx_chn->rx_chn = k3_udma_glue_request_rx_chn(dev, rx_chn->name, + &rx_cfg); + if (IS_ERR(rx_chn->rx_chn)) { + ret = PTR_ERR(rx_chn->rx_chn); + rx_chn->rx_chn = NULL; + netdev_err(ndev, "Failed to request rx dma ch: %d\n", ret); + goto fail; + } + + rx_chn->dma_dev = k3_udma_glue_rx_get_dma_device(rx_chn->rx_chn); + rx_chn->desc_pool = k3_cppi_desc_pool_create_name(rx_chn->dma_dev, + rx_chn->descs_num, + hdesc_size, + rx_chn->name); + if (IS_ERR(rx_chn->desc_pool)) { + ret = PTR_ERR(rx_chn->desc_pool); + rx_chn->desc_pool = NULL; + netdev_err(ndev, "Failed to create rx pool: %d\n", ret); + goto fail; + } + + flow_id_base = k3_udma_glue_rx_get_flow_id_base(rx_chn->rx_chn); + if (emac->is_sr1 && !strcmp(name, "rxmgm")) { + emac->rx_mgm_flow_id_base = flow_id_base; + netdev_dbg(ndev, "mgm flow id base = %d\n", flow_id_base); + } else { + emac->rx_flow_id_base = flow_id_base; + netdev_dbg(ndev, "flow id base = %d\n", flow_id_base); + } + + fdqring_id = K3_RINGACC_RING_ID_ANY; + for (i = 0; i < rx_cfg.flow_id_num; i++) { + struct k3_ring_cfg rxring_cfg = { + .elm_size = K3_RINGACC_RING_ELSIZE_8, + .mode = K3_RINGACC_RING_MODE_RING, + .flags = 0, + }; + struct k3_ring_cfg fdqring_cfg = { + .elm_size = K3_RINGACC_RING_ELSIZE_8, + .flags = K3_RINGACC_RING_SHARED, + }; + struct k3_udma_glue_rx_flow_cfg rx_flow_cfg = { + .rx_cfg = rxring_cfg, + .rxfdq_cfg = fdqring_cfg, + .ring_rxq_id = K3_RINGACC_RING_ID_ANY, + .src_tag_lo_sel = + K3_UDMA_GLUE_SRC_TAG_LO_USE_REMOTE_SRC_TAG, + }; + + rx_flow_cfg.ring_rxfdq0_id = fdqring_id; + rx_flow_cfg.rx_cfg.size = max_desc_num; + rx_flow_cfg.rxfdq_cfg.size = max_desc_num; + rx_flow_cfg.rxfdq_cfg.mode = emac->prueth->pdata.fdqring_mode; + + ret = k3_udma_glue_rx_flow_init(rx_chn->rx_chn, + i, &rx_flow_cfg); + if (ret) { + netdev_err(ndev, "Failed to init rx flow%d %d\n", + i, ret); + goto fail; + } + if (!i) + fdqring_id = k3_udma_glue_rx_flow_get_fdq_id(rx_chn->rx_chn, + i); + rx_chn->irq[i] = k3_udma_glue_rx_get_irq(rx_chn->rx_chn, i); + if (rx_chn->irq[i] <= 0) { + ret = rx_chn->irq[i]; + netdev_err(ndev, "Failed to get rx dma irq"); + goto fail; + } + } + + return 0; + +fail: + prueth_cleanup_rx_chns(emac, rx_chn, max_rflows); + return ret; +} + +static int prueth_dma_rx_push_mapped(struct prueth_emac *emac, + struct prueth_rx_chn *rx_chn, + struct page *page, u32 buf_len) +{ + struct net_device *ndev = emac->ndev; + struct cppi5_host_desc_t *desc_rx; + struct prueth_swdata *swdata; + dma_addr_t desc_dma; + dma_addr_t buf_dma; + + buf_dma = page_pool_get_dma_addr(page) + PRUETH_HEADROOM; + desc_rx = k3_cppi_desc_pool_alloc(rx_chn->desc_pool); + if (!desc_rx) { + netdev_err(ndev, "rx push: failed to allocate descriptor\n"); + return -ENOMEM; + } + desc_dma = k3_cppi_desc_pool_virt2dma(rx_chn->desc_pool, desc_rx); + + cppi5_hdesc_init(desc_rx, CPPI5_INFO0_HDESC_EPIB_PRESENT, + PRUETH_NAV_PS_DATA_SIZE); + k3_udma_glue_rx_dma_to_cppi5_addr(rx_chn->rx_chn, &buf_dma); + cppi5_hdesc_attach_buf(desc_rx, buf_dma, buf_len, buf_dma, buf_len); + + swdata = cppi5_hdesc_get_swdata(desc_rx); + swdata->type = PRUETH_SWDATA_PAGE; + swdata->data.page = page; + swdata->rx_chn = rx_chn; + + return k3_udma_glue_push_rx_chn(rx_chn->rx_chn, 0, + desc_rx, desc_dma); +} + +u64 icssg_ts_to_ns(u32 hi_sw, u32 hi, u32 lo, u32 cycle_time_ns) +{ + u32 iepcount_lo, iepcount_hi, hi_rollover_count; + u64 ns; + + iepcount_lo = lo & GENMASK(19, 0); + iepcount_hi = (hi & GENMASK(11, 0)) << 12 | lo >> 20; + hi_rollover_count = hi >> 11; + + ns = ((u64)hi_rollover_count) << 23 | (iepcount_hi + hi_sw); + ns = ns * cycle_time_ns + iepcount_lo; + + return ns; +} + +void emac_rx_timestamp(struct prueth_emac *emac, + struct sk_buff *skb, u32 *psdata) +{ + struct skb_shared_hwtstamps *ssh; + u64 ns; + + if (emac->is_sr1) { + ns = (u64)psdata[1] << 32 | psdata[0]; + } else { + u32 hi_sw = readl(emac->prueth->shram.va + + TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET); + ns = icssg_ts_to_ns(hi_sw, psdata[1], psdata[0], + IEP_DEFAULT_CYCLE_TIME_NS); + } + + ssh = skb_hwtstamps(skb); + memset(ssh, 0, sizeof(*ssh)); + ssh->hwtstamp = ns_to_ktime(ns); +} + +static unsigned int prueth_rxbuf_total_len(unsigned int len) +{ + len += PRUETH_HEADROOM; + len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + + return SKB_DATA_ALIGN(len); +} + +static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id, int *xdp_state) +{ + struct prueth_rx_chn *rx_chn = &emac->rx_chns; + u32 buf_dma_len, pkt_len, port_id = 0; + struct net_device *ndev = emac->ndev; + struct cppi5_host_desc_t *desc_rx; + struct prueth_swdata *swdata; + dma_addr_t desc_dma, buf_dma; + struct page *page, *new_page; + struct page_pool *pool; + struct sk_buff *skb; + struct xdp_buff xdp; + u32 *psdata; + void *pa; + int ret; + + *xdp_state = 0; + pool = rx_chn->pg_pool; + ret = k3_udma_glue_pop_rx_chn(rx_chn->rx_chn, flow_id, &desc_dma); + if (ret) { + if (ret != -ENODATA) + netdev_err(ndev, "rx pop: failed: %d\n", ret); + return ret; + } + + if (cppi5_desc_is_tdcm(desc_dma)) /* Teardown ? */ + return 0; + + desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); + + swdata = cppi5_hdesc_get_swdata(desc_rx); + if (swdata->type != PRUETH_SWDATA_PAGE) { + netdev_err(ndev, "rx_pkt: invliad swdata->type %d\n", swdata->type); + return 0; + } + page = swdata->data.page; + + cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); + k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma); + pkt_len = cppi5_hdesc_get_pktlen(desc_rx); + /* firmware adds 4 CRC bytes, strip them */ + pkt_len -= 4; + cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL); + + k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); + + /* if allocation fails we drop the packet but push the + * descriptor back to the ring with old page to prevent a stall + */ + new_page = page_pool_dev_alloc_pages(pool); + if (unlikely(!new_page)) { + new_page = page; + ndev->stats.rx_dropped++; + goto requeue; + } + + pa = page_address(page); + if (emac->xdp_prog) { + xdp_init_buff(&xdp, PAGE_SIZE, &rx_chn->xdp_rxq); + xdp_prepare_buff(&xdp, pa, PRUETH_HEADROOM, pkt_len, false); + + *xdp_state = emac_run_xdp(emac, &xdp, page); + if (*xdp_state != ICSSG_XDP_PASS) + goto requeue; + } + + /* prepare skb and send to n/w stack */ + skb = build_skb(pa, prueth_rxbuf_total_len(pkt_len)); + if (!skb) { + ndev->stats.rx_dropped++; + page_pool_recycle_direct(pool, page); + goto requeue; + } + + skb_reserve(skb, PRUETH_HEADROOM); + skb_put(skb, pkt_len); + skb->dev = ndev; + + psdata = cppi5_hdesc_get_psdata(desc_rx); + /* RX HW timestamp */ + if (emac->rx_ts_enabled) + emac_rx_timestamp(emac, skb, psdata); + + if (emac->prueth->is_switch_mode) + skb->offload_fwd_mark = emac->offload_fwd_mark; + skb->protocol = eth_type_trans(skb, ndev); + + netif_receive_skb(skb); + ndev->stats.rx_bytes += pkt_len; + ndev->stats.rx_packets++; + +requeue: + /* queue another RX DMA */ + ret = prueth_dma_rx_push_mapped(emac, &emac->rx_chns, new_page, + PRUETH_MAX_PKT_SIZE); + if (WARN_ON(ret < 0)) { + page_pool_recycle_direct(pool, new_page); + ndev->stats.rx_errors++; + ndev->stats.rx_dropped++; + } + + return ret; +} + +static void prueth_rx_cleanup(void *data, dma_addr_t desc_dma) +{ + struct prueth_rx_chn *rx_chn = data; + struct cppi5_host_desc_t *desc_rx; + struct prueth_swdata *swdata; + struct page_pool *pool; + struct page *page; + + pool = rx_chn->pg_pool; + + desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); + swdata = cppi5_hdesc_get_swdata(desc_rx); + if (swdata->type == PRUETH_SWDATA_PAGE) { + page = swdata->data.page; + page_pool_recycle_direct(pool, page); + } + k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); +} + +static int prueth_tx_ts_cookie_get(struct prueth_emac *emac) +{ + int i; + + /* search and get the next free slot */ + for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) { + if (!emac->tx_ts_skb[i]) { + emac->tx_ts_skb[i] = ERR_PTR(-EBUSY); /* reserve slot */ + return i; + } + } + + return -EBUSY; +} + +/** + * emac_ndo_start_xmit - EMAC Transmit function + * @skb: SKB pointer + * @ndev: EMAC network adapter + * + * Called by the system to transmit a packet - we queue the packet in + * EMAC hardware transmit queue + * Doesn't wait for completion we'll check for TX completion in + * emac_tx_complete_packets(). + * + * Return: enum netdev_tx + */ +enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct cppi5_host_desc_t *first_desc, *next_desc, *cur_desc; + struct prueth_emac *emac = netdev_priv(ndev); + struct netdev_queue *netif_txq; + struct prueth_swdata *swdata; + struct prueth_tx_chn *tx_chn; + dma_addr_t desc_dma, buf_dma; + int i, ret = 0, q_idx; + bool in_tx_ts = 0; + int tx_ts_cookie; + u32 pkt_len; + u32 *epib; + + pkt_len = skb_headlen(skb); + q_idx = skb_get_queue_mapping(skb); + + tx_chn = &emac->tx_chns[q_idx]; + netif_txq = netdev_get_tx_queue(ndev, q_idx); + + /* Map the linear buffer */ + buf_dma = dma_map_single(tx_chn->dma_dev, skb->data, pkt_len, DMA_TO_DEVICE); + if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) { + netdev_err(ndev, "tx: failed to map skb buffer\n"); + ret = NETDEV_TX_OK; + goto drop_free_skb; + } + + first_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool); + if (!first_desc) { + netdev_dbg(ndev, "tx: failed to allocate descriptor\n"); + dma_unmap_single(tx_chn->dma_dev, buf_dma, pkt_len, DMA_TO_DEVICE); + goto drop_stop_q_busy; + } + + cppi5_hdesc_init(first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT, + PRUETH_NAV_PS_DATA_SIZE); + cppi5_hdesc_set_pkttype(first_desc, 0); + epib = first_desc->epib; + epib[0] = 0; + epib[1] = 0; + if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && + emac->tx_ts_enabled) { + tx_ts_cookie = prueth_tx_ts_cookie_get(emac); + if (tx_ts_cookie >= 0) { + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + /* Request TX timestamp */ + epib[0] = (u32)tx_ts_cookie; + epib[1] = 0x80000000; /* TX TS request */ + emac->tx_ts_skb[tx_ts_cookie] = skb_get(skb); + in_tx_ts = 1; + } + } + + /* set dst tag to indicate internal qid at the firmware which is at + * bit8..bit15. bit0..bit7 indicates port num for directed + * packets in case of switch mode operation + */ + cppi5_desc_set_tags_ids(&first_desc->hdr, 0, (emac->port_id | (q_idx << 8))); + k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); + cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len); + swdata = cppi5_hdesc_get_swdata(first_desc); + swdata->type = PRUETH_SWDATA_SKB; + swdata->data.skb = skb; + + /* Handle the case where skb is fragmented in pages */ + cur_desc = first_desc; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + u32 frag_size = skb_frag_size(frag); + + next_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool); + if (!next_desc) { + netdev_err(ndev, + "tx: failed to allocate frag. descriptor\n"); + goto free_desc_stop_q_busy_cleanup_tx_ts; + } + + buf_dma = skb_frag_dma_map(tx_chn->dma_dev, frag, 0, frag_size, + DMA_TO_DEVICE); + if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) { + netdev_err(ndev, "tx: Failed to map skb page\n"); + k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); + ret = NETDEV_TX_OK; + goto cleanup_tx_ts; + } + + cppi5_hdesc_reset_hbdesc(next_desc); + k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); + cppi5_hdesc_attach_buf(next_desc, + buf_dma, frag_size, buf_dma, frag_size); + + desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, + next_desc); + k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &desc_dma); + cppi5_hdesc_link_hbdesc(cur_desc, desc_dma); + + pkt_len += frag_size; + cur_desc = next_desc; + } + WARN_ON_ONCE(pkt_len != skb->len); + + /* report bql before sending packet */ + netdev_tx_sent_queue(netif_txq, pkt_len); + + cppi5_hdesc_set_pktlen(first_desc, pkt_len); + desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, first_desc); + /* cppi5_desc_dump(first_desc, 64); */ + + skb_tx_timestamp(skb); /* SW timestamp if SKBTX_IN_PROGRESS not set */ + ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma); + if (ret) { + netdev_err(ndev, "tx: push failed: %d\n", ret); + goto drop_free_descs; + } + + if (in_tx_ts) + atomic_inc(&emac->tx_ts_pending); + + if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) < MAX_SKB_FRAGS) { + netif_tx_stop_queue(netif_txq); + /* Barrier, so that stop_queue visible to other cpus */ + smp_mb__after_atomic(); + + if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >= + MAX_SKB_FRAGS) + netif_tx_wake_queue(netif_txq); + } + + return NETDEV_TX_OK; + +cleanup_tx_ts: + if (in_tx_ts) { + dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]); + emac->tx_ts_skb[tx_ts_cookie] = NULL; + } + +drop_free_descs: + prueth_xmit_free(tx_chn, first_desc); + +drop_free_skb: + dev_kfree_skb_any(skb); + + /* error */ + ndev->stats.tx_dropped++; + netdev_err(ndev, "tx: error: %d\n", ret); + + return ret; + +free_desc_stop_q_busy_cleanup_tx_ts: + if (in_tx_ts) { + dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]); + emac->tx_ts_skb[tx_ts_cookie] = NULL; + } + prueth_xmit_free(tx_chn, first_desc); + +drop_stop_q_busy: + netif_tx_stop_queue(netif_txq); + return NETDEV_TX_BUSY; +} + +static void prueth_tx_cleanup(void *data, dma_addr_t desc_dma) +{ + struct prueth_tx_chn *tx_chn = data; + struct cppi5_host_desc_t *desc_tx; + struct prueth_swdata *swdata; + struct xdp_frame *xdpf; + struct sk_buff *skb; + + desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma); + swdata = cppi5_hdesc_get_swdata(desc_tx); + + switch (swdata->type) { + case PRUETH_SWDATA_SKB: + skb = swdata->data.skb; + dev_kfree_skb_any(skb); + break; + case PRUETH_SWDATA_XDPF: + xdpf = swdata->data.xdpf; + xdp_return_frame(xdpf); + break; + default: + break; + } + + prueth_xmit_free(tx_chn, desc_tx); +} + +irqreturn_t prueth_rx_irq(int irq, void *dev_id) +{ + struct prueth_emac *emac = dev_id; + + disable_irq_nosync(irq); + napi_schedule(&emac->napi_rx); + + return IRQ_HANDLED; +} + +void prueth_emac_stop(struct prueth_emac *emac) +{ + struct prueth *prueth = emac->prueth; + int slice; + + switch (emac->port_id) { + case PRUETH_PORT_MII0: + slice = ICSS_SLICE0; + break; + case PRUETH_PORT_MII1: + slice = ICSS_SLICE1; + break; + default: + netdev_err(emac->ndev, "invalid port\n"); + return; + } + + emac->fw_running = 0; + if (!emac->is_sr1) + rproc_shutdown(prueth->txpru[slice]); + rproc_shutdown(prueth->rtu[slice]); + rproc_shutdown(prueth->pru[slice]); +} + +void prueth_cleanup_tx_ts(struct prueth_emac *emac) +{ + int i; + + for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) { + if (emac->tx_ts_skb[i]) { + dev_kfree_skb_any(emac->tx_ts_skb[i]); + emac->tx_ts_skb[i] = NULL; + } + } +} + +int emac_napi_rx_poll(struct napi_struct *napi_rx, int budget) +{ + struct prueth_emac *emac = prueth_napi_to_emac(napi_rx); + int rx_flow = emac->is_sr1 ? + PRUETH_RX_FLOW_DATA_SR1 : PRUETH_RX_FLOW_DATA; + int flow = emac->is_sr1 ? + PRUETH_MAX_RX_FLOWS_SR1 : PRUETH_MAX_RX_FLOWS; + int xdp_state_or = 0; + int num_rx = 0; + int cur_budget; + int xdp_state; + int ret; + + while (flow--) { + cur_budget = budget - num_rx; + + while (cur_budget--) { + ret = emac_rx_packet(emac, flow, &xdp_state); + xdp_state_or |= xdp_state; + if (ret) + break; + num_rx++; + } + + if (num_rx >= budget) + break; + } + + if (xdp_state_or & ICSSG_XDP_REDIR) + xdp_do_flush(); + + if (num_rx < budget && napi_complete_done(napi_rx, num_rx)) { + if (unlikely(emac->rx_pace_timeout_ns)) { + hrtimer_start(&emac->rx_hrtimer, + ns_to_ktime(emac->rx_pace_timeout_ns), + HRTIMER_MODE_REL_PINNED); + } else { + enable_irq(emac->rx_chns.irq[rx_flow]); + } + } + + return num_rx; +} + +static struct page_pool *prueth_create_page_pool(struct prueth_emac *emac, + struct device *dma_dev, + int size) +{ + struct page_pool_params pp_params = { 0 }; + struct page_pool *pool; + + pp_params.order = 0; + pp_params.flags = PP_FLAG_DMA_MAP; + pp_params.pool_size = size; + pp_params.nid = dev_to_node(emac->prueth->dev); + pp_params.dma_dir = DMA_BIDIRECTIONAL; + pp_params.dev = dma_dev; + pp_params.napi = &emac->napi_rx; + + pool = page_pool_create(&pp_params); + if (IS_ERR(pool)) + netdev_err(emac->ndev, "cannot create rx page pool\n"); + + return pool; +} + +static struct page *prueth_get_page_from_rx_chn(struct prueth_rx_chn *chn) +{ + struct cppi5_host_desc_t *desc_rx; + struct prueth_swdata *swdata; + dma_addr_t desc_dma; + struct page *page; + + k3_udma_glue_pop_rx_chn(chn->rx_chn, 0, &desc_dma); + desc_rx = k3_cppi_desc_pool_dma2virt(chn->desc_pool, desc_dma); + swdata = cppi5_hdesc_get_swdata(desc_rx); + page = swdata->data.page; + + return page; +} + +int prueth_prepare_rx_chan(struct prueth_emac *emac, + struct prueth_rx_chn *chn, + int buf_size) +{ + struct page_pool *pool; + struct page *page; + int i, ret, j; + + pool = prueth_create_page_pool(emac, chn->dma_dev, chn->descs_num); + if (IS_ERR(pool)) + return PTR_ERR(pool); + + chn->pg_pool = pool; + + for (i = 0; i < chn->descs_num; i++) { + /* NOTE: we're not using memory efficiently here. + * 1 full page (4KB?) used here instead of + * PRUETH_MAX_PKT_SIZE (~1.5KB?) + */ + page = page_pool_dev_alloc_pages(pool); + if (!page) { + netdev_err(emac->ndev, "couldn't allocate rx page\n"); + ret = -ENOMEM; + goto recycle_alloc_pg; + } + + ret = prueth_dma_rx_push_mapped(emac, chn, page, buf_size); + if (ret < 0) { + netdev_err(emac->ndev, + "cannot submit skb for rx chan %s ret %d\n", + chn->name, ret); + page_pool_recycle_direct(pool, page); + goto recycle_alloc_pg; + } + } + + return 0; + +recycle_alloc_pg: + for (j = 0; j < i; j++) { + page = prueth_get_page_from_rx_chn(chn); + page_pool_recycle_direct(pool, page); + } + page_pool_destroy(pool); + chn->pg_pool = NULL; + + return ret; +} + +void prueth_reset_tx_chan(struct prueth_emac *emac, int ch_num, + bool free_skb) +{ + int i; + + for (i = 0; i < ch_num; i++) { + if (free_skb) + k3_udma_glue_reset_tx_chn(emac->tx_chns[i].tx_chn, + &emac->tx_chns[i], + prueth_tx_cleanup); + k3_udma_glue_disable_tx_chn(emac->tx_chns[i].tx_chn); + } +} + +void prueth_reset_rx_chan(struct prueth_rx_chn *chn, + int num_flows, bool disable) +{ + int i; + + for (i = 0; i < num_flows; i++) + k3_udma_glue_reset_rx_chn(chn->rx_chn, i, chn, + prueth_rx_cleanup, !!i); + if (disable) + k3_udma_glue_disable_rx_chn(chn->rx_chn); +} + +void emac_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue) +{ + ndev->stats.tx_errors++; +} + +static int emac_set_ts_config(struct net_device *ndev, struct ifreq *ifr) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct hwtstamp_config config; + + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) + return -EFAULT; + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + emac->tx_ts_enabled = 0; + break; + case HWTSTAMP_TX_ON: + emac->tx_ts_enabled = 1; + break; + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + emac->rx_ts_enabled = 0; + break; + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_SOME: + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: + emac->rx_ts_enabled = 1; + config.rx_filter = HWTSTAMP_FILTER_ALL; + break; + default: + return -ERANGE; + } + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + +static int emac_get_ts_config(struct net_device *ndev, struct ifreq *ifr) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct hwtstamp_config config; + + config.flags = 0; + config.tx_type = emac->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + config.rx_filter = emac->rx_ts_enabled ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + +int emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCGHWTSTAMP: + return emac_get_ts_config(ndev, ifr); + case SIOCSHWTSTAMP: + return emac_set_ts_config(ndev, ifr); + default: + break; + } + + return phy_do_ioctl(ndev, ifr, cmd); +} + +void emac_ndo_get_stats64(struct net_device *ndev, + struct rtnl_link_stats64 *stats) +{ + struct prueth_emac *emac = netdev_priv(ndev); + + emac_update_hardware_stats(emac); + + stats->rx_packets = emac_get_stat_by_name(emac, "rx_packets"); + stats->rx_bytes = emac_get_stat_by_name(emac, "rx_bytes"); + stats->tx_packets = emac_get_stat_by_name(emac, "tx_packets"); + stats->tx_bytes = emac_get_stat_by_name(emac, "tx_bytes"); + stats->rx_crc_errors = emac_get_stat_by_name(emac, "rx_crc_errors"); + stats->rx_over_errors = emac_get_stat_by_name(emac, "rx_over_errors"); + stats->multicast = emac_get_stat_by_name(emac, "rx_multicast_frames"); + + stats->rx_errors = ndev->stats.rx_errors; + stats->rx_dropped = ndev->stats.rx_dropped; + stats->tx_errors = ndev->stats.tx_errors; + stats->tx_dropped = ndev->stats.tx_dropped; +} + +/* get emac_port corresponding to eth_node name */ +int prueth_node_port(struct device_node *eth_node) +{ + u32 port_id; + int ret; + + ret = of_property_read_u32(eth_node, "reg", &port_id); + if (ret) + return ret; + + if (port_id == 0) + return PRUETH_PORT_MII0; + else if (port_id == 1) + return PRUETH_PORT_MII1; + else + return PRUETH_PORT_INVALID; +} + +/* get MAC instance corresponding to eth_node name */ +int prueth_node_mac(struct device_node *eth_node) +{ + u32 port_id; + int ret; + + ret = of_property_read_u32(eth_node, "reg", &port_id); + if (ret) + return ret; + + if (port_id == 0) + return PRUETH_MAC0; + else if (port_id == 1) + return PRUETH_MAC1; + else + return PRUETH_MAC_INVALID; +} + +void prueth_netdev_exit(struct prueth *prueth, + struct device_node *eth_node) +{ + struct prueth_emac *emac; + enum prueth_mac mac; + + mac = prueth_node_mac(eth_node); + if (mac == PRUETH_MAC_INVALID) + return; + + emac = prueth->emac[mac]; + if (!emac) + return; + + if (of_phy_is_fixed_link(emac->phy_node)) + of_phy_deregister_fixed_link(emac->phy_node); + + netif_napi_del(&emac->napi_rx); + + pruss_release_mem_region(prueth->pruss, &emac->dram); + destroy_workqueue(emac->cmd_wq); + free_netdev(emac->ndev); + prueth->emac[mac] = NULL; +} + +int prueth_get_cores(struct prueth *prueth, int slice, bool is_sr1) +{ + struct device *dev = prueth->dev; + enum pruss_pru_id pruss_id; + struct device_node *np; + int idx = -1, ret; + + np = dev->of_node; + + switch (slice) { + case ICSS_SLICE0: + idx = 0; + break; + case ICSS_SLICE1: + idx = is_sr1 ? 2 : 3; + break; + default: + return -EINVAL; + } + + prueth->pru[slice] = pru_rproc_get(np, idx, &pruss_id); + if (IS_ERR(prueth->pru[slice])) { + ret = PTR_ERR(prueth->pru[slice]); + prueth->pru[slice] = NULL; + return dev_err_probe(dev, ret, "unable to get PRU%d\n", slice); + } + prueth->pru_id[slice] = pruss_id; + + idx++; + prueth->rtu[slice] = pru_rproc_get(np, idx, NULL); + if (IS_ERR(prueth->rtu[slice])) { + ret = PTR_ERR(prueth->rtu[slice]); + prueth->rtu[slice] = NULL; + return dev_err_probe(dev, ret, "unable to get RTU%d\n", slice); + } + + if (is_sr1) + return 0; + + idx++; + prueth->txpru[slice] = pru_rproc_get(np, idx, NULL); + if (IS_ERR(prueth->txpru[slice])) { + ret = PTR_ERR(prueth->txpru[slice]); + prueth->txpru[slice] = NULL; + return dev_err_probe(dev, ret, "unable to get TX_PRU%d\n", slice); + } + + return 0; +} + +void prueth_put_cores(struct prueth *prueth, int slice) +{ + if (prueth->txpru[slice]) + pru_rproc_put(prueth->txpru[slice]); + + if (prueth->rtu[slice]) + pru_rproc_put(prueth->rtu[slice]); + + if (prueth->pru[slice]) + pru_rproc_put(prueth->pru[slice]); +} + +#ifdef CONFIG_PM_SLEEP +static int prueth_suspend(struct device *dev) +{ + struct prueth *prueth = dev_get_drvdata(dev); + struct net_device *ndev; + int i, ret; + + for (i = 0; i < PRUETH_NUM_MACS; i++) { + ndev = prueth->registered_netdevs[i]; + + if (!ndev) + continue; + + if (netif_running(ndev)) { + netif_device_detach(ndev); + ret = ndev->netdev_ops->ndo_stop(ndev); + if (ret < 0) { + netdev_err(ndev, "failed to stop: %d", ret); + return ret; + } + } + } + + return 0; +} + +static int prueth_resume(struct device *dev) +{ + struct prueth *prueth = dev_get_drvdata(dev); + struct net_device *ndev; + int i, ret; + + for (i = 0; i < PRUETH_NUM_MACS; i++) { + ndev = prueth->registered_netdevs[i]; + + if (!ndev) + continue; + + if (netif_running(ndev)) { + ret = ndev->netdev_ops->ndo_open(ndev); + if (ret < 0) { + netdev_err(ndev, "failed to start: %d", ret); + return ret; + } + netif_device_attach(ndev); + } + } + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +const struct dev_pm_ops prueth_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(prueth_suspend, prueth_resume) +}; diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c --- a/drivers/net/ethernet/ti/icssg/icssg_config.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/icssg/icssg_config.c 2024-07-07 20:37:34.668306669 -0400 @@ -20,6 +20,8 @@ /* IPG is in core_clk cycles */ #define MII_RT_TX_IPG_100M 0x17 #define MII_RT_TX_IPG_1G 0xb +#define MII_RT_TX_IPG_100M_SR1 0x166 +#define MII_RT_TX_IPG_1G_SR1 0x1a #define ICSSG_QUEUES_MAX 64 #define ICSSG_QUEUE_OFFSET 0xd00 @@ -105,28 +107,49 @@ }, }; +static void icssg_config_mii_init_switch(struct prueth_emac *emac) +{ + struct prueth *prueth = emac->prueth; + int mii = prueth_emac_slice(emac); + u32 txcfg_reg, pcnt_reg, txcfg; + struct regmap *mii_rt; + + mii_rt = prueth->mii_rt; + + txcfg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 : + PRUSS_MII_RT_TXCFG1; + pcnt_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 : + PRUSS_MII_RT_RX_PCNT1; + + txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE | + PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE | + PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN; + + if (emac->phy_if == PHY_INTERFACE_MODE_MII && mii == ICSS_MII1) + txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL; + else if (emac->phy_if != PHY_INTERFACE_MODE_MII && mii == ICSS_MII0) + txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL; + + regmap_write(mii_rt, txcfg_reg, txcfg); + regmap_write(mii_rt, pcnt_reg, 0x1); +} + static void icssg_config_mii_init(struct prueth_emac *emac) { - u32 rxcfg, txcfg, rxcfg_reg, txcfg_reg, pcnt_reg; struct prueth *prueth = emac->prueth; int slice = prueth_emac_slice(emac); + u32 txcfg, txcfg_reg, pcnt_reg; struct regmap *mii_rt; mii_rt = prueth->mii_rt; - rxcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RXCFG0 : - PRUSS_MII_RT_RXCFG1; txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 : PRUSS_MII_RT_TXCFG1; pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 : PRUSS_MII_RT_RX_PCNT1; - rxcfg = MII_RXCFG_DEFAULT; txcfg = MII_TXCFG_DEFAULT; - if (slice == ICSS_MII1) - rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL; - /* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need * to be swapped also comparing to RGMII mode. */ @@ -135,7 +158,6 @@ else if (emac->phy_if != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1) txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL; - regmap_write(mii_rt, rxcfg_reg, rxcfg); regmap_write(mii_rt, txcfg_reg, txcfg); regmap_write(mii_rt, pcnt_reg, 0x1); } @@ -198,27 +220,52 @@ } } +static void icssg_config_cut_thru(struct prueth_emac *emac) +{ + void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET; + u8 mask = BIT(7); + u8 val; + int i; + + for (i = 0; i < PRUETH_MAX_TX_QUEUES * PRUETH_NUM_MACS; i++) { + val = readb(config + EXPRESS_PRE_EMPTIVE_Q_MAP + i); + val &= ~mask; + if (emac->cut_thru_queue_map & BIT(i)) { + val |= mask; + netdev_info(emac->ndev, "cut-thru enabled for q%d\n", i); + } + + writeb(val, config + EXPRESS_PRE_EMPTIVE_Q_MAP + i); + } +} + void icssg_config_ipg(struct prueth_emac *emac) { struct prueth *prueth = emac->prueth; int slice = prueth_emac_slice(emac); + u32 ipg; switch (emac->speed) { case SPEED_1000: - icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_1G); + ipg = emac->is_sr1 ? MII_RT_TX_IPG_1G_SR1 : MII_RT_TX_IPG_1G; break; case SPEED_100: - icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M); + ipg = emac->is_sr1 ? MII_RT_TX_IPG_100M_SR1 : MII_RT_TX_IPG_100M; break; case SPEED_10: + /* Firmware hardcodes IPG for SR1.0 */ + if (emac->is_sr1) + return; /* IPG for 10M is same as 100M */ - icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M); + ipg = MII_RT_TX_IPG_100M; break; default: /* Other links speeds not supported */ netdev_err(emac->ndev, "Unsupported link speed\n"); return; } + + icssg_mii_update_ipg(prueth->mii_rt, slice, ipg); } static void emac_r30_cmd_init(struct prueth_emac *emac) @@ -249,6 +296,75 @@ return 1; } +static int prueth_switch_buffer_setup(struct prueth_emac *emac) +{ + struct icssg_buffer_pool_cfg __iomem *bpool_cfg; + struct icssg_rxq_ctx __iomem *rxq_ctx; + struct prueth *prueth = emac->prueth; + int slice = prueth_emac_slice(emac); + u32 addr; + int i; + + addr = lower_32_bits(prueth->msmcram.pa); + if (slice) + addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE; + + if (addr % SZ_64K) { + dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n"); + return -EINVAL; + } + + bpool_cfg = emac->dram.va + BUFFER_POOL_0_ADDR_OFFSET; + /* workaround for f/w bug. bpool 0 needs to be initialized */ + for (i = 0; i < PRUETH_NUM_BUF_POOLS; i++) { + writel(addr, &bpool_cfg[i].addr); + writel(PRUETH_EMAC_BUF_POOL_SIZE, &bpool_cfg[i].len); + addr += PRUETH_EMAC_BUF_POOL_SIZE; + } + + if (!slice) + addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE; + else + addr += PRUETH_SW_NUM_BUF_POOLS_HOST * PRUETH_SW_BUF_POOL_SIZE_HOST; + + for (i = PRUETH_NUM_BUF_POOLS; + i < 2 * PRUETH_SW_NUM_BUF_POOLS_HOST + PRUETH_NUM_BUF_POOLS; + i++) { + /* The driver only uses first 4 queues per PRU so only initialize them */ + if (i % PRUETH_SW_NUM_BUF_POOLS_HOST < PRUETH_SW_NUM_BUF_POOLS_PER_PRU) { + writel(addr, &bpool_cfg[i].addr); + writel(PRUETH_SW_BUF_POOL_SIZE_HOST, &bpool_cfg[i].len); + addr += PRUETH_SW_BUF_POOL_SIZE_HOST; + } else { + writel(0, &bpool_cfg[i].addr); + writel(0, &bpool_cfg[i].len); + } + } + + if (!slice) + addr += PRUETH_SW_NUM_BUF_POOLS_HOST * PRUETH_SW_BUF_POOL_SIZE_HOST; + else + addr += PRUETH_EMAC_RX_CTX_BUF_SIZE * 2; + + /* Pre-emptible RX buffer queue */ + rxq_ctx = emac->dram.va + HOST_RX_Q_PRE_CONTEXT_OFFSET; + for (i = 0; i < 3; i++) + writel(addr, &rxq_ctx->start[i]); + + addr += PRUETH_EMAC_RX_CTX_BUF_SIZE; + writel(addr, &rxq_ctx->end); + + /* Express RX buffer queue */ + rxq_ctx = emac->dram.va + HOST_RX_Q_EXP_CONTEXT_OFFSET; + for (i = 0; i < 3; i++) + writel(addr, &rxq_ctx->start[i]); + + addr += PRUETH_EMAC_RX_CTX_BUF_SIZE; + writel(addr, &rxq_ctx->end); + + return 0; +} + static int prueth_emac_buffer_setup(struct prueth_emac *emac) { struct icssg_buffer_pool_cfg __iomem *bpool_cfg; @@ -313,25 +429,63 @@ /* When the device is configured as a bridge and it is being brought * back to the emac mode, the host mac address has to be set as 0. */ + u32 addr = prueth->shram.pa + EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET; + int i; u8 mac[ETH_ALEN] = { 0 }; if (prueth->emacs_initialized) return; - regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, - SMEM_VLAN_OFFSET_MASK, 0); - regmap_write(prueth->miig_rt, FDB_GEN_CFG2, 0); + /* Set VLAN TABLE address base */ + regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK, + addr << SMEM_VLAN_OFFSET); + /* Set enable VLAN aware mode, and FDBs for all PRUs */ + regmap_write(prueth->miig_rt, FDB_GEN_CFG2, (FDB_PRU0_EN | FDB_PRU1_EN | FDB_HOST_EN)); + prueth->vlan_tbl = (struct prueth_vlan_tbl __force *)(prueth->shram.va + + EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET); + for (i = 0; i < SZ_4K - 1; i++) { + prueth->vlan_tbl[i].fid = i; + prueth->vlan_tbl[i].fid_c1 = 0; + } /* Clear host MAC address */ icssg_class_set_host_mac_addr(prueth->miig_rt, mac); } +static void icssg_init_switch_mode(struct prueth *prueth) +{ + u32 addr = prueth->shram.pa + EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET; + int i; + + if (prueth->emacs_initialized) + return; + + /* Set VLAN TABLE address base */ + regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK, + addr << SMEM_VLAN_OFFSET); + /* Set enable VLAN aware mode, and FDBs for all PRUs */ + regmap_write(prueth->miig_rt, FDB_GEN_CFG2, FDB_EN_ALL); + prueth->vlan_tbl = (struct prueth_vlan_tbl __force *)(prueth->shram.va + + EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET); + for (i = 0; i < SZ_4K - 1; i++) { + prueth->vlan_tbl[i].fid = i; + prueth->vlan_tbl[i].fid_c1 = 0; + } + + if (prueth->hw_bridge_dev) + icssg_class_set_host_mac_addr(prueth->miig_rt, prueth->hw_bridge_dev->dev_addr); + icssg_set_pvid(prueth, prueth->default_vlan, PRUETH_PORT_HOST); +} + int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice) { void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET; struct icssg_flow_cfg __iomem *flow_cfg; int ret; - icssg_init_emac_mode(prueth); + if (prueth->is_switch_mode) + icssg_init_switch_mode(prueth); + else + icssg_init_emac_mode(prueth); memset_io(config, 0, TAS_GATE_MASK_LIST0); icssg_miig_queues_init(prueth, slice); @@ -345,7 +499,10 @@ regmap_update_bits(prueth->miig_rt, ICSSG_CFG_OFFSET, ICSSG_CFG_DEFAULT, ICSSG_CFG_DEFAULT); icssg_miig_set_interface_mode(prueth->miig_rt, slice, emac->phy_if); - icssg_config_mii_init(emac); + if (prueth->is_switch_mode) + icssg_config_mii_init_switch(emac); + else + icssg_config_mii_init(emac); icssg_config_ipg(emac); icssg_update_rgmii_cfg(prueth->miig_rt, emac); @@ -368,7 +525,13 @@ writeb(0, config + SPL_PKT_DEFAULT_PRIORITY); writeb(0, config + QUEUE_NUM_UNTAGGED); - ret = prueth_emac_buffer_setup(emac); + if (prueth->is_switch_mode) { + icssg_config_cut_thru(emac); + ret = prueth_switch_buffer_setup(emac); + } else { + ret = prueth_emac_buffer_setup(emac); + } + if (ret) return ret; @@ -433,6 +596,17 @@ return ret; } +void icssg_config_half_duplex(struct prueth_emac *emac) +{ + u32 val; + + if (!emac->half_duplex) + return; + + val = get_random_u32(); + writel(val, emac->dram.va + HD_RAND_SEED_OFFSET); +} + void icssg_config_set_speed(struct prueth_emac *emac) { u8 fw_speed; @@ -453,5 +627,205 @@ return; } + if (emac->duplex == DUPLEX_HALF) + fw_speed |= FW_LINK_SPEED_HD; + writeb(fw_speed, emac->dram.va + PORT_LINK_SPEED_OFFSET); } + +int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd, + struct mgmt_cmd_rsp *rsp) +{ + struct prueth *prueth = emac->prueth; + int slice = prueth_emac_slice(emac); + int addr, ret; + + addr = icssg_queue_pop(prueth, slice == 0 ? + ICSSG_CMD_POP_SLICE0 : ICSSG_CMD_POP_SLICE1); + if (addr < 0) + return addr; + + /* First 4 bytes have FW owned buffer linking info which should + * not be touched + */ + memcpy_toio(prueth->shram.va + addr + 4, cmd, sizeof(*cmd)); + icssg_queue_push(prueth, slice == 0 ? + ICSSG_CMD_PUSH_SLICE0 : ICSSG_CMD_PUSH_SLICE1, addr); + ret = read_poll_timeout(icssg_queue_pop, addr, addr >= 0, + 2000, 20000000, false, prueth, slice == 0 ? + ICSSG_RSP_POP_SLICE0 : ICSSG_RSP_POP_SLICE1); + if (ret) { + netdev_err(emac->ndev, "Timedout sending HWQ message\n"); + return ret; + } + + memcpy_fromio(rsp, prueth->shram.va + addr, sizeof(*rsp)); + /* Return buffer back for to pool */ + icssg_queue_push(prueth, slice == 0 ? + ICSSG_RSP_PUSH_SLICE0 : ICSSG_RSP_PUSH_SLICE1, addr); + + return 0; +} + +static void icssg_fdb_setup(struct prueth_emac *emac, struct mgmt_cmd *fdb_cmd, + const unsigned char *addr, u8 fid, int cmd) +{ + int slice = prueth_emac_slice(emac); + u8 mac_fid[ETH_ALEN + 2]; + u16 fdb_slot; + + ether_addr_copy(mac_fid, addr); + + /* 1-1 VID-FID mapping is already setup */ + mac_fid[ETH_ALEN] = fid; + mac_fid[ETH_ALEN + 1] = 0; + + fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK; + + fdb_cmd->header = ICSSG_FW_MGMT_CMD_HEADER; + fdb_cmd->type = ICSSG_FW_MGMT_FDB_CMD_TYPE; + fdb_cmd->seqnum = ++(emac->prueth->icssg_hwcmdseq); + fdb_cmd->param = cmd; + fdb_cmd->param |= (slice << 4); + + memcpy(&fdb_cmd->cmd_args[0], addr, 4); + memcpy(&fdb_cmd->cmd_args[1], &addr[4], 2); + fdb_cmd->cmd_args[2] = fdb_slot; + + netdev_dbg(emac->ndev, "MAC %pM slot %X FID %X\n", addr, fdb_slot, fid); +} + +int icssg_fdb_add_del(struct prueth_emac *emac, const unsigned char *addr, + u8 vid, u8 fid_c2, bool add) +{ + struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 }; + struct mgmt_cmd fdb_cmd = { 0 }; + u8 fid = vid; + int ret; + + icssg_fdb_setup(emac, &fdb_cmd, addr, fid, add ? ICSS_CMD_ADD_FDB : ICSS_CMD_DEL_FDB); + + fid_c2 |= ICSSG_FDB_ENTRY_VALID; + fdb_cmd.cmd_args[1] |= ((fid << 16) | (fid_c2 << 24)); + + ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp); + if (ret) + return ret; + + WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum); + if (fdb_cmd_rsp.status == 1) + return 0; + + return -EINVAL; +} + +int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr, + u8 vid) +{ + struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 }; + struct mgmt_cmd fdb_cmd = { 0 }; + struct prueth_fdb_slot *slot; + u8 fid = vid; + int ret, i; + + icssg_fdb_setup(emac, &fdb_cmd, addr, fid, ICSS_CMD_GET_FDB_SLOT); + + fdb_cmd.cmd_args[1] |= fid << 16; + + ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp); + if (ret) + return ret; + + WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum); + + slot = (struct prueth_fdb_slot __force *)(emac->dram.va + FDB_CMD_BUFFER); + for (i = 0; i < 4; i++) { + if (ether_addr_equal(addr, slot->mac) && vid == slot->fid) + return (slot->fid_c2 & ~ICSSG_FDB_ENTRY_VALID); + slot++; + } + + return 0; +} + +void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask, + u8 untag_mask, bool add) +{ + struct prueth *prueth = emac->prueth; + struct prueth_vlan_tbl *tbl; + u8 fid_c1; + + tbl = prueth->vlan_tbl; + fid_c1 = tbl[vid].fid_c1; + + /* FID_C1: bit0..2 port membership mask, + * bit3..5 tagging mask for each port + * bit6 Stream VID (not handled currently) + * bit7 MC flood (not handled currently) + */ + if (add) { + fid_c1 |= (port_mask | port_mask << 3); + fid_c1 &= ~(untag_mask << 3); + } else { + fid_c1 &= ~(port_mask | port_mask << 3); + } + + tbl[vid].fid_c1 = fid_c1; +} + +u16 icssg_get_pvid(struct prueth_emac *emac) +{ + struct prueth *prueth = emac->prueth; + u32 pvid; + + if (emac->port_id == PRUETH_PORT_MII0) + pvid = readl(prueth->shram.va + EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET); + else + pvid = readl(prueth->shram.va + EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET); + + pvid = pvid >> 24; + + return pvid; +} + +void icssg_set_pvid(struct prueth *prueth, u8 vid, u8 port) +{ + u32 pvid; + + /* only 256 VLANs are supported */ + pvid = (u32 __force)cpu_to_be32((ETH_P_8021Q << 16) | (vid & 0xff)); + + if (port == PRUETH_PORT_MII0) + writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET); + else if (port == PRUETH_PORT_MII1) + writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET); + else + writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT0_DEFAULT_VLAN_OFFSET); +} + +int emac_fdb_flow_id_updated(struct prueth_emac *emac) +{ + struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 }; + int slice = prueth_emac_slice(emac); + struct mgmt_cmd fdb_cmd = { 0 }; + int ret = 0; + + fdb_cmd.header = ICSSG_FW_MGMT_CMD_HEADER; + fdb_cmd.type = ICSSG_FW_MGMT_FDB_CMD_TYPE_RX_FLOW; + fdb_cmd.seqnum = ++(emac->prueth->icssg_hwcmdseq); + fdb_cmd.param = 0; + + fdb_cmd.param |= (slice << 4); + fdb_cmd.cmd_args[0] = 0; + + ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp); + + if (ret) + return ret; + + WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum); + if (fdb_cmd_rsp.status == 1) + return 0; + + return -EINVAL; +} diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_config.h b/drivers/net/ethernet/ti/icssg/icssg_config.h --- a/drivers/net/ethernet/ti/icssg/icssg_config.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/icssg/icssg_config.h 2024-07-07 20:37:34.668306669 -0400 @@ -20,7 +20,7 @@ #define PRUETH_PKT_TYPE_CMD 0x10 #define PRUETH_NAV_PS_DATA_SIZE 16 /* Protocol specific data size */ -#define PRUETH_NAV_SW_DATA_SIZE 16 /* SW related data size */ +#define PRUETH_NAV_SW_DATA_SIZE 48 /* SW related data size */ #define PRUETH_MAX_TX_DESC 512 #define PRUETH_MAX_RX_DESC 512 #define PRUETH_MAX_RX_FLOWS 1 /* excluding default flow */ @@ -35,6 +35,15 @@ (2 * (PRUETH_EMAC_BUF_POOL_SIZE * PRUETH_NUM_BUF_POOLS + \ PRUETH_EMAC_RX_CTX_BUF_SIZE * 2)) +#define PRUETH_SW_BUF_POOL_SIZE_HOST SZ_4K +#define PRUETH_SW_NUM_BUF_POOLS_HOST 8 +#define PRUETH_SW_NUM_BUF_POOLS_PER_PRU 4 +#define MSMC_RAM_SIZE_SWITCH_MODE \ + (MSMC_RAM_SIZE + \ + (2 * PRUETH_SW_BUF_POOL_SIZE_HOST * PRUETH_SW_NUM_BUF_POOLS_HOST)) + +#define PRUETH_SWITCH_FDB_MASK ((SIZE_OF_FDB / NUMBER_OF_FDB_BUCKET_ENTRIES) - 1) + struct icssg_rxq_ctx { __le32 start[3]; __le32 end; @@ -46,6 +55,7 @@ #define ICSSG_FW_MGMT_FDB_CMD_TYPE 0x03 #define ICSSG_FW_MGMT_CMD_TYPE 0x04 #define ICSSG_FW_MGMT_PKT 0x80000000 +#define ICSSG_FW_MGMT_FDB_CMD_TYPE_RX_FLOW 0x05 struct icssg_r30_cmd { u32 cmd[4]; @@ -109,6 +119,62 @@ #define ICSSG_FLAG_MASK 0xff00ffff +/* SR1.0-specific bits */ +#define PRUETH_MAX_RX_FLOWS_SR1 4 /* excluding default flow */ +#define PRUETH_RX_FLOW_DATA_SR1 3 /* highest priority flow */ +#define PRUETH_MAX_RX_MGM_DESC_SR1 8 +#define PRUETH_MAX_RX_MGM_FLOWS_SR1 2 /* excluding default flow */ +#define PRUETH_RX_MGM_FLOW_RESPONSE_SR1 0 +#define PRUETH_RX_MGM_FLOW_TIMESTAMP_SR1 1 + +#define PRUETH_NUM_BUF_POOLS_SR1 16 +#define PRUETH_EMAC_BUF_POOL_START_SR1 8 +#define PRUETH_EMAC_BUF_POOL_MIN_SIZE_SR1 128 +#define PRUETH_EMAC_BUF_SIZE_SR1 1536 +#define PRUETH_EMAC_NUM_BUF_SR1 4 +#define PRUETH_EMAC_BUF_POOL_SIZE_SR1 (PRUETH_EMAC_NUM_BUF_SR1 * \ + PRUETH_EMAC_BUF_SIZE_SR1) +#define MSMC_RAM_SIZE_SR1 (SZ_64K + SZ_32K + SZ_2K) /* 0x1880 x 8 x 2 */ + +struct icssg_sr1_config { + __le32 status; /* Firmware status */ + __le32 addr_lo; /* MSMC Buffer pool base address low. */ + __le32 addr_hi; /* MSMC Buffer pool base address high. Must be 0 */ + __le32 tx_buf_sz[16]; /* Array of buffer pool sizes */ + __le32 num_tx_threads; /* Number of active egress threads, 1 to 4 */ + __le32 tx_rate_lim_en; /* Bitmask: Egress rate limit en per thread */ + __le32 rx_flow_id; /* RX flow id for first rx ring */ + __le32 rx_mgr_flow_id; /* RX flow id for the first management ring */ + __le32 flags; /* TBD */ + __le32 n_burst; /* for debug */ + __le32 rtu_status; /* RTU status */ + __le32 info; /* reserved */ + __le32 reserve; + __le32 rand_seed; /* Used for the random number generation at fw */ +} __packed; + +/* SR1.0 shutdown command to stop processing at firmware. + * Command format: 0x8101ss00, where + * - ss: sequence number. Currently not used by driver. + */ +#define ICSSG_SHUTDOWN_CMD_SR1 0x81010000 + +/* SR1.0 pstate speed/duplex command to set speed and duplex settings + * in firmware. + * Command format: 0x8102ssPN, where + * - ss: sequence number. Currently not used by driver. + * - P: port number (for switch mode). + * - N: Speed/Duplex state: + * 0x0 - 10Mbps/Half duplex; + * 0x8 - 10Mbps/Full duplex; + * 0x2 - 100Mbps/Half duplex; + * 0xa - 100Mbps/Full duplex; + * 0xc - 1Gbps/Full duplex; + * NOTE: The above are the same value as bits [3..1](slice 0) + * or bits [7..5](slice 1) of RGMII CFG register. + */ +#define ICSSG_PSTATE_SPEED_DUPLEX_CMD_SR1 0x81020000 + struct icssg_setclock_desc { u8 request; u8 restore; @@ -146,6 +212,23 @@ #define ICSSG_TS_PUSH_SLICE0 40 #define ICSSG_TS_PUSH_SLICE1 41 +struct mgmt_cmd { + u8 param; + u8 seqnum; + u8 type; + u8 header; + u32 cmd_args[3]; +}; + +struct mgmt_cmd_rsp { + u32 reserved; + u8 status; + u8 seqnum; + u8 type; + u8 header; + u32 cmd_args[3]; +}; + /* FDB FID_C2 flag definitions */ /* Indicates host port membership.*/ #define ICSSG_FDB_ENTRY_P0_MEMBERSHIP BIT(0) diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c --- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c 2024-07-07 20:37:34.668306669 -0400 @@ -142,6 +142,9 @@ emac->tx_ch_num = ch->tx_count; + if (emac->is_sr1) + emac->tx_ch_num++; + return 0; } @@ -152,8 +155,17 @@ ch->max_rx = 1; ch->max_tx = PRUETH_MAX_TX_QUEUES; + + /* Disable multiple TX channels due to timeouts + * when using more than one queue */ + if (emac->is_sr1) + ch->max_tx = 1; + ch->rx_count = 1; ch->tx_count = emac->tx_ch_num; + + if (emac->is_sr1) + ch->tx_count--; } static const struct ethtool_rmon_hist_range emac_rmon_ranges[] = { @@ -189,6 +201,148 @@ rmon_stats->hist_tx[4] = emac_get_stat_by_name(emac, "tx_bucket5_frames"); } +static int emac_get_coalesce(struct net_device *ndev, + struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_tx_chn *tx_chn; + + tx_chn = &emac->tx_chns[0]; + + coal->rx_coalesce_usecs = emac->rx_pace_timeout_ns / 1000; + coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout_ns / 1000; + + return 0; +} + +static int emac_get_per_queue_coalesce(struct net_device *ndev, u32 queue, + struct ethtool_coalesce *coal) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_tx_chn *tx_chn; + + if (queue >= PRUETH_MAX_TX_QUEUES) + return -EINVAL; + + tx_chn = &emac->tx_chns[queue]; + + coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout_ns / 1000; + + return 0; +} + +static int emac_set_coalesce(struct net_device *ndev, + struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; + struct prueth_tx_chn *tx_chn; + + tx_chn = &emac->tx_chns[0]; + + if (coal->rx_coalesce_usecs && + coal->rx_coalesce_usecs < ICSSG_MIN_COALESCE_USECS) { + dev_info(prueth->dev, "defaulting to min value of %dus for rx-usecs\n", + ICSSG_MIN_COALESCE_USECS); + coal->rx_coalesce_usecs = ICSSG_MIN_COALESCE_USECS; + } + + if (coal->tx_coalesce_usecs && + coal->tx_coalesce_usecs < ICSSG_MIN_COALESCE_USECS) { + dev_info(prueth->dev, "defaulting to min value of %dus for tx-usecs\n", + ICSSG_MIN_COALESCE_USECS); + coal->tx_coalesce_usecs = ICSSG_MIN_COALESCE_USECS; + } + + emac->rx_pace_timeout_ns = coal->rx_coalesce_usecs * 1000; + tx_chn->tx_pace_timeout_ns = coal->tx_coalesce_usecs * 1000; + + return 0; +} + +static int emac_set_per_queue_coalesce(struct net_device *ndev, u32 queue, + struct ethtool_coalesce *coal) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; + struct prueth_tx_chn *tx_chn; + + if (queue >= PRUETH_MAX_TX_QUEUES) + return -EINVAL; + + tx_chn = &emac->tx_chns[queue]; + + if (coal->tx_coalesce_usecs && + coal->tx_coalesce_usecs < ICSSG_MIN_COALESCE_USECS) { + dev_info(prueth->dev, "defaulting to min value of %dus for tx-usecs for tx-%u\n", + ICSSG_MIN_COALESCE_USECS, queue); + coal->tx_coalesce_usecs = ICSSG_MIN_COALESCE_USECS; + } + + tx_chn->tx_pace_timeout_ns = coal->tx_coalesce_usecs * 1000; + + return 0; +} + +static int emac_get_mm(struct net_device *ndev, struct ethtool_mm_state *state) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_qos_iet *iet = &emac->qos.iet; + void __iomem *config; + + config = emac->dram.va + ICSSG_CONFIG_OFFSET; + + state->tx_enabled = iet->fpe_enabled; + state->pmac_enabled = true; + state->verify_status = readb(config + PRE_EMPTION_VERIFY_STATUS); + state->tx_min_frag_size = iet->tx_min_frag_size; + state->rx_min_frag_size = 124; + state->tx_active = readb(config + PRE_EMPTION_ACTIVE_TX) ? true : false; + state->verify_enabled = readb(config + PRE_EMPTION_ENABLE_VERIFY) ? true : false; + state->verify_time = iet->verify_time_ms; + + /* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime + * variable has a range between 1 and 128 ms inclusive. Limit to that. + */ + state->max_verify_time = 128; + + return 0; +} + +static int emac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg, + struct netlink_ext_ack *extack) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_qos_iet *iet = &emac->qos.iet; + + if (!cfg->pmac_enabled) + netdev_err(ndev, "preemptible MAC is alway enabled"); + + iet->verify_time_ms = cfg->verify_time; + iet->tx_min_frag_size = cfg->tx_min_frag_size; + + iet->fpe_configured = cfg->tx_enabled; + iet->mac_verify_configured = cfg->verify_enabled; + + return 0; +} + +static void emac_get_mm_stats(struct net_device *ndev, + struct ethtool_mm_stats *s) +{ + struct prueth_emac *emac = netdev_priv(ndev); + + s->MACMergeFrameAssOkCount = emac_get_stat_by_name(emac, "iet_asm_ok"); + s->MACMergeFrameAssErrorCount = emac_get_stat_by_name(emac, "iet_asm_err"); + s->MACMergeFrameSmdErrorCount = emac_get_stat_by_name(emac, "iet_bad_frag"); + s->MACMergeFragCountRx = emac_get_stat_by_name(emac, "iet_rx_frag"); + s->MACMergeFragCountTx = emac_get_stat_by_name(emac, "iet_tx_frag"); +} + const struct ethtool_ops icssg_ethtool_ops = { .get_drvinfo = emac_get_drvinfo, .get_msglevel = emac_get_msglevel, @@ -197,6 +351,12 @@ .get_ethtool_stats = emac_get_ethtool_stats, .get_strings = emac_get_strings, .get_ts_info = emac_get_ts_info, + .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS | + ETHTOOL_COALESCE_TX_USECS, + .get_coalesce = emac_get_coalesce, + .set_coalesce = emac_set_coalesce, + .get_per_queue_coalesce = emac_get_per_queue_coalesce, + .set_per_queue_coalesce = emac_set_per_queue_coalesce, .get_channels = emac_get_channels, .set_channels = emac_set_channels, .get_link_ksettings = emac_get_link_ksettings, @@ -206,4 +366,7 @@ .set_eee = emac_set_eee, .nway_reset = emac_nway_reset, .get_rmon_stats = emac_get_rmon_stats, + .get_mm = emac_get_mm, + .set_mm = emac_set_mm, + .get_mm_stats = emac_get_mm_stats, }; diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c 2024-07-07 20:37:34.668306669 -0400 @@ -19,585 +19,30 @@ #include #include #include -#include #include #include -#include +#include #include +#include #include #include #include +#include #include "icssg_prueth.h" #include "icssg_mii_rt.h" +#include "icssg_switchdev.h" #include "../k3-cppi-desc-pool.h" #define PRUETH_MODULE_DESCRIPTION "PRUSS ICSSG Ethernet driver" -/* Netif debug messages possible */ -#define PRUETH_EMAC_DEBUG (NETIF_MSG_DRV | \ - NETIF_MSG_PROBE | \ - NETIF_MSG_LINK | \ - NETIF_MSG_TIMER | \ - NETIF_MSG_IFDOWN | \ - NETIF_MSG_IFUP | \ - NETIF_MSG_RX_ERR | \ - NETIF_MSG_TX_ERR | \ - NETIF_MSG_TX_QUEUED | \ - NETIF_MSG_INTR | \ - NETIF_MSG_TX_DONE | \ - NETIF_MSG_RX_STATUS | \ - NETIF_MSG_PKTDATA | \ - NETIF_MSG_HW | \ - NETIF_MSG_WOL) - -#define prueth_napi_to_emac(napi) container_of(napi, struct prueth_emac, napi_rx) +#define DEFAULT_VID 1 +#define DEFAULT_PORT_MASK 1 +#define DEFAULT_UNTAG_MASK 1 /* CTRLMMR_ICSSG_RGMII_CTRL register bits */ #define ICSSG_CTRL_RGMII_ID_MODE BIT(24) -#define IEP_DEFAULT_CYCLE_TIME_NS 1000000 /* 1 ms */ - -static void prueth_cleanup_rx_chns(struct prueth_emac *emac, - struct prueth_rx_chn *rx_chn, - int max_rflows) -{ - if (rx_chn->desc_pool) - k3_cppi_desc_pool_destroy(rx_chn->desc_pool); - - if (rx_chn->rx_chn) - k3_udma_glue_release_rx_chn(rx_chn->rx_chn); -} - -static void prueth_cleanup_tx_chns(struct prueth_emac *emac) -{ - int i; - - for (i = 0; i < emac->tx_ch_num; i++) { - struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; - - if (tx_chn->desc_pool) - k3_cppi_desc_pool_destroy(tx_chn->desc_pool); - - if (tx_chn->tx_chn) - k3_udma_glue_release_tx_chn(tx_chn->tx_chn); - - /* Assume prueth_cleanup_tx_chns() is called at the - * end after all channel resources are freed - */ - memset(tx_chn, 0, sizeof(*tx_chn)); - } -} - -static void prueth_ndev_del_tx_napi(struct prueth_emac *emac, int num) -{ - int i; - - for (i = 0; i < num; i++) { - struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; - - if (tx_chn->irq) - free_irq(tx_chn->irq, tx_chn); - netif_napi_del(&tx_chn->napi_tx); - } -} - -static void prueth_xmit_free(struct prueth_tx_chn *tx_chn, - struct cppi5_host_desc_t *desc) -{ - struct cppi5_host_desc_t *first_desc, *next_desc; - dma_addr_t buf_dma, next_desc_dma; - u32 buf_dma_len; - - first_desc = desc; - next_desc = first_desc; - - cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len); - k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); - - dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len, - DMA_TO_DEVICE); - - next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc); - k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); - while (next_desc_dma) { - next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, - next_desc_dma); - cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len); - k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); - - dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len, - DMA_TO_DEVICE); - - next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc); - k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); - - k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); - } - - k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc); -} - -static int emac_tx_complete_packets(struct prueth_emac *emac, int chn, - int budget) -{ - struct net_device *ndev = emac->ndev; - struct cppi5_host_desc_t *desc_tx; - struct netdev_queue *netif_txq; - struct prueth_tx_chn *tx_chn; - unsigned int total_bytes = 0; - struct sk_buff *skb; - dma_addr_t desc_dma; - int res, num_tx = 0; - void **swdata; - - tx_chn = &emac->tx_chns[chn]; - - while (true) { - res = k3_udma_glue_pop_tx_chn(tx_chn->tx_chn, &desc_dma); - if (res == -ENODATA) - break; - - /* teardown completion */ - if (cppi5_desc_is_tdcm(desc_dma)) { - if (atomic_dec_and_test(&emac->tdown_cnt)) - complete(&emac->tdown_complete); - break; - } - - desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, - desc_dma); - swdata = cppi5_hdesc_get_swdata(desc_tx); - - skb = *(swdata); - prueth_xmit_free(tx_chn, desc_tx); - - ndev = skb->dev; - ndev->stats.tx_packets++; - ndev->stats.tx_bytes += skb->len; - total_bytes += skb->len; - napi_consume_skb(skb, budget); - num_tx++; - } - - if (!num_tx) - return 0; - - netif_txq = netdev_get_tx_queue(ndev, chn); - netdev_tx_completed_queue(netif_txq, num_tx, total_bytes); - - if (netif_tx_queue_stopped(netif_txq)) { - /* If the TX queue was stopped, wake it now - * if we have enough room. - */ - __netif_tx_lock(netif_txq, smp_processor_id()); - if (netif_running(ndev) && - (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >= - MAX_SKB_FRAGS)) - netif_tx_wake_queue(netif_txq); - __netif_tx_unlock(netif_txq); - } - - return num_tx; -} - -static int emac_napi_tx_poll(struct napi_struct *napi_tx, int budget) -{ - struct prueth_tx_chn *tx_chn = prueth_napi_to_tx_chn(napi_tx); - struct prueth_emac *emac = tx_chn->emac; - int num_tx_packets; - - num_tx_packets = emac_tx_complete_packets(emac, tx_chn->id, budget); - - if (num_tx_packets >= budget) - return budget; - - if (napi_complete_done(napi_tx, num_tx_packets)) - enable_irq(tx_chn->irq); - - return num_tx_packets; -} - -static irqreturn_t prueth_tx_irq(int irq, void *dev_id) -{ - struct prueth_tx_chn *tx_chn = dev_id; - - disable_irq_nosync(irq); - napi_schedule(&tx_chn->napi_tx); - - return IRQ_HANDLED; -} - -static int prueth_ndev_add_tx_napi(struct prueth_emac *emac) -{ - struct prueth *prueth = emac->prueth; - int i, ret; - - for (i = 0; i < emac->tx_ch_num; i++) { - struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; - - netif_napi_add_tx(emac->ndev, &tx_chn->napi_tx, emac_napi_tx_poll); - ret = request_irq(tx_chn->irq, prueth_tx_irq, - IRQF_TRIGGER_HIGH, tx_chn->name, - tx_chn); - if (ret) { - netif_napi_del(&tx_chn->napi_tx); - dev_err(prueth->dev, "unable to request TX IRQ %d\n", - tx_chn->irq); - goto fail; - } - } - - return 0; -fail: - prueth_ndev_del_tx_napi(emac, i); - return ret; -} - -static int prueth_init_tx_chns(struct prueth_emac *emac) -{ - static const struct k3_ring_cfg ring_cfg = { - .elm_size = K3_RINGACC_RING_ELSIZE_8, - .mode = K3_RINGACC_RING_MODE_RING, - .flags = 0, - .size = PRUETH_MAX_TX_DESC, - }; - struct k3_udma_glue_tx_channel_cfg tx_cfg; - struct device *dev = emac->prueth->dev; - struct net_device *ndev = emac->ndev; - int ret, slice, i; - u32 hdesc_size; - - slice = prueth_emac_slice(emac); - if (slice < 0) - return slice; - - init_completion(&emac->tdown_complete); - - hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE, - PRUETH_NAV_SW_DATA_SIZE); - memset(&tx_cfg, 0, sizeof(tx_cfg)); - tx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE; - tx_cfg.tx_cfg = ring_cfg; - tx_cfg.txcq_cfg = ring_cfg; - - for (i = 0; i < emac->tx_ch_num; i++) { - struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; - - /* To differentiate channels for SLICE0 vs SLICE1 */ - snprintf(tx_chn->name, sizeof(tx_chn->name), - "tx%d-%d", slice, i); - - tx_chn->emac = emac; - tx_chn->id = i; - tx_chn->descs_num = PRUETH_MAX_TX_DESC; - - tx_chn->tx_chn = - k3_udma_glue_request_tx_chn(dev, tx_chn->name, - &tx_cfg); - if (IS_ERR(tx_chn->tx_chn)) { - ret = PTR_ERR(tx_chn->tx_chn); - tx_chn->tx_chn = NULL; - netdev_err(ndev, - "Failed to request tx dma ch: %d\n", ret); - goto fail; - } - - tx_chn->dma_dev = k3_udma_glue_tx_get_dma_device(tx_chn->tx_chn); - tx_chn->desc_pool = - k3_cppi_desc_pool_create_name(tx_chn->dma_dev, - tx_chn->descs_num, - hdesc_size, - tx_chn->name); - if (IS_ERR(tx_chn->desc_pool)) { - ret = PTR_ERR(tx_chn->desc_pool); - tx_chn->desc_pool = NULL; - netdev_err(ndev, "Failed to create tx pool: %d\n", ret); - goto fail; - } - - ret = k3_udma_glue_tx_get_irq(tx_chn->tx_chn); - if (ret < 0) { - netdev_err(ndev, "failed to get tx irq\n"); - goto fail; - } - tx_chn->irq = ret; - - snprintf(tx_chn->name, sizeof(tx_chn->name), "%s-tx%d", - dev_name(dev), tx_chn->id); - } - - return 0; - -fail: - prueth_cleanup_tx_chns(emac); - return ret; -} - -static int prueth_init_rx_chns(struct prueth_emac *emac, - struct prueth_rx_chn *rx_chn, - char *name, u32 max_rflows, - u32 max_desc_num) -{ - struct k3_udma_glue_rx_channel_cfg rx_cfg; - struct device *dev = emac->prueth->dev; - struct net_device *ndev = emac->ndev; - u32 fdqring_id, hdesc_size; - int i, ret = 0, slice; - - slice = prueth_emac_slice(emac); - if (slice < 0) - return slice; - - /* To differentiate channels for SLICE0 vs SLICE1 */ - snprintf(rx_chn->name, sizeof(rx_chn->name), "%s%d", name, slice); - - hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE, - PRUETH_NAV_SW_DATA_SIZE); - memset(&rx_cfg, 0, sizeof(rx_cfg)); - rx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE; - rx_cfg.flow_id_num = max_rflows; - rx_cfg.flow_id_base = -1; /* udmax will auto select flow id base */ - - /* init all flows */ - rx_chn->dev = dev; - rx_chn->descs_num = max_desc_num; - - rx_chn->rx_chn = k3_udma_glue_request_rx_chn(dev, rx_chn->name, - &rx_cfg); - if (IS_ERR(rx_chn->rx_chn)) { - ret = PTR_ERR(rx_chn->rx_chn); - rx_chn->rx_chn = NULL; - netdev_err(ndev, "Failed to request rx dma ch: %d\n", ret); - goto fail; - } - - rx_chn->dma_dev = k3_udma_glue_rx_get_dma_device(rx_chn->rx_chn); - rx_chn->desc_pool = k3_cppi_desc_pool_create_name(rx_chn->dma_dev, - rx_chn->descs_num, - hdesc_size, - rx_chn->name); - if (IS_ERR(rx_chn->desc_pool)) { - ret = PTR_ERR(rx_chn->desc_pool); - rx_chn->desc_pool = NULL; - netdev_err(ndev, "Failed to create rx pool: %d\n", ret); - goto fail; - } - - emac->rx_flow_id_base = k3_udma_glue_rx_get_flow_id_base(rx_chn->rx_chn); - netdev_dbg(ndev, "flow id base = %d\n", emac->rx_flow_id_base); - - fdqring_id = K3_RINGACC_RING_ID_ANY; - for (i = 0; i < rx_cfg.flow_id_num; i++) { - struct k3_ring_cfg rxring_cfg = { - .elm_size = K3_RINGACC_RING_ELSIZE_8, - .mode = K3_RINGACC_RING_MODE_RING, - .flags = 0, - }; - struct k3_ring_cfg fdqring_cfg = { - .elm_size = K3_RINGACC_RING_ELSIZE_8, - .flags = K3_RINGACC_RING_SHARED, - }; - struct k3_udma_glue_rx_flow_cfg rx_flow_cfg = { - .rx_cfg = rxring_cfg, - .rxfdq_cfg = fdqring_cfg, - .ring_rxq_id = K3_RINGACC_RING_ID_ANY, - .src_tag_lo_sel = - K3_UDMA_GLUE_SRC_TAG_LO_USE_REMOTE_SRC_TAG, - }; - - rx_flow_cfg.ring_rxfdq0_id = fdqring_id; - rx_flow_cfg.rx_cfg.size = max_desc_num; - rx_flow_cfg.rxfdq_cfg.size = max_desc_num; - rx_flow_cfg.rxfdq_cfg.mode = emac->prueth->pdata.fdqring_mode; - - ret = k3_udma_glue_rx_flow_init(rx_chn->rx_chn, - i, &rx_flow_cfg); - if (ret) { - netdev_err(ndev, "Failed to init rx flow%d %d\n", - i, ret); - goto fail; - } - if (!i) - fdqring_id = k3_udma_glue_rx_flow_get_fdq_id(rx_chn->rx_chn, - i); - ret = k3_udma_glue_rx_get_irq(rx_chn->rx_chn, i); - if (ret <= 0) { - if (!ret) - ret = -ENXIO; - netdev_err(ndev, "Failed to get rx dma irq"); - goto fail; - } - rx_chn->irq[i] = ret; - } - - return 0; - -fail: - prueth_cleanup_rx_chns(emac, rx_chn, max_rflows); - return ret; -} - -static int prueth_dma_rx_push(struct prueth_emac *emac, - struct sk_buff *skb, - struct prueth_rx_chn *rx_chn) -{ - struct net_device *ndev = emac->ndev; - struct cppi5_host_desc_t *desc_rx; - u32 pkt_len = skb_tailroom(skb); - dma_addr_t desc_dma; - dma_addr_t buf_dma; - void **swdata; - - desc_rx = k3_cppi_desc_pool_alloc(rx_chn->desc_pool); - if (!desc_rx) { - netdev_err(ndev, "rx push: failed to allocate descriptor\n"); - return -ENOMEM; - } - desc_dma = k3_cppi_desc_pool_virt2dma(rx_chn->desc_pool, desc_rx); - - buf_dma = dma_map_single(rx_chn->dma_dev, skb->data, pkt_len, DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(rx_chn->dma_dev, buf_dma))) { - k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); - netdev_err(ndev, "rx push: failed to map rx pkt buffer\n"); - return -EINVAL; - } - - cppi5_hdesc_init(desc_rx, CPPI5_INFO0_HDESC_EPIB_PRESENT, - PRUETH_NAV_PS_DATA_SIZE); - k3_udma_glue_rx_dma_to_cppi5_addr(rx_chn->rx_chn, &buf_dma); - cppi5_hdesc_attach_buf(desc_rx, buf_dma, skb_tailroom(skb), buf_dma, skb_tailroom(skb)); - - swdata = cppi5_hdesc_get_swdata(desc_rx); - *swdata = skb; - - return k3_udma_glue_push_rx_chn(rx_chn->rx_chn, 0, - desc_rx, desc_dma); -} - -static u64 icssg_ts_to_ns(u32 hi_sw, u32 hi, u32 lo, u32 cycle_time_ns) -{ - u32 iepcount_lo, iepcount_hi, hi_rollover_count; - u64 ns; - - iepcount_lo = lo & GENMASK(19, 0); - iepcount_hi = (hi & GENMASK(11, 0)) << 12 | lo >> 20; - hi_rollover_count = hi >> 11; - - ns = ((u64)hi_rollover_count) << 23 | (iepcount_hi + hi_sw); - ns = ns * cycle_time_ns + iepcount_lo; - - return ns; -} - -static void emac_rx_timestamp(struct prueth_emac *emac, - struct sk_buff *skb, u32 *psdata) -{ - struct skb_shared_hwtstamps *ssh; - u64 ns; - - u32 hi_sw = readl(emac->prueth->shram.va + - TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET); - ns = icssg_ts_to_ns(hi_sw, psdata[1], psdata[0], - IEP_DEFAULT_CYCLE_TIME_NS); - - ssh = skb_hwtstamps(skb); - memset(ssh, 0, sizeof(*ssh)); - ssh->hwtstamp = ns_to_ktime(ns); -} - -static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id) -{ - struct prueth_rx_chn *rx_chn = &emac->rx_chns; - u32 buf_dma_len, pkt_len, port_id = 0; - struct net_device *ndev = emac->ndev; - struct cppi5_host_desc_t *desc_rx; - struct sk_buff *skb, *new_skb; - dma_addr_t desc_dma, buf_dma; - void **swdata; - u32 *psdata; - int ret; - - ret = k3_udma_glue_pop_rx_chn(rx_chn->rx_chn, flow_id, &desc_dma); - if (ret) { - if (ret != -ENODATA) - netdev_err(ndev, "rx pop: failed: %d\n", ret); - return ret; - } - - if (cppi5_desc_is_tdcm(desc_dma)) /* Teardown ? */ - return 0; - - desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); - - swdata = cppi5_hdesc_get_swdata(desc_rx); - skb = *swdata; - - psdata = cppi5_hdesc_get_psdata(desc_rx); - /* RX HW timestamp */ - if (emac->rx_ts_enabled) - emac_rx_timestamp(emac, skb, psdata); - - cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); - k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma); - pkt_len = cppi5_hdesc_get_pktlen(desc_rx); - /* firmware adds 4 CRC bytes, strip them */ - pkt_len -= 4; - cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL); - - dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE); - k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); - - skb->dev = ndev; - new_skb = netdev_alloc_skb_ip_align(ndev, PRUETH_MAX_PKT_SIZE); - /* if allocation fails we drop the packet but push the - * descriptor back to the ring with old skb to prevent a stall - */ - if (!new_skb) { - ndev->stats.rx_dropped++; - new_skb = skb; - } else { - /* send the filled skb up the n/w stack */ - skb_put(skb, pkt_len); - skb->protocol = eth_type_trans(skb, ndev); - napi_gro_receive(&emac->napi_rx, skb); - ndev->stats.rx_bytes += pkt_len; - ndev->stats.rx_packets++; - } - - /* queue another RX DMA */ - ret = prueth_dma_rx_push(emac, new_skb, &emac->rx_chns); - if (WARN_ON(ret < 0)) { - dev_kfree_skb_any(new_skb); - ndev->stats.rx_errors++; - ndev->stats.rx_dropped++; - } - - return ret; -} - -static void prueth_rx_cleanup(void *data, dma_addr_t desc_dma) -{ - struct prueth_rx_chn *rx_chn = data; - struct cppi5_host_desc_t *desc_rx; - struct sk_buff *skb; - dma_addr_t buf_dma; - u32 buf_dma_len; - void **swdata; - - desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); - swdata = cppi5_hdesc_get_swdata(desc_rx); - skb = *swdata; - cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); - k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma); - - dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, - DMA_FROM_DEVICE); - k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); - - dev_kfree_skb_any(skb); -} - static int emac_get_tx_ts(struct prueth_emac *emac, struct emac_tx_ts_response *rsp) { @@ -663,208 +108,6 @@ } } -static int prueth_tx_ts_cookie_get(struct prueth_emac *emac) -{ - int i; - - /* search and get the next free slot */ - for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) { - if (!emac->tx_ts_skb[i]) { - emac->tx_ts_skb[i] = ERR_PTR(-EBUSY); /* reserve slot */ - return i; - } - } - - return -EBUSY; -} - -/** - * emac_ndo_start_xmit - EMAC Transmit function - * @skb: SKB pointer - * @ndev: EMAC network adapter - * - * Called by the system to transmit a packet - we queue the packet in - * EMAC hardware transmit queue - * Doesn't wait for completion we'll check for TX completion in - * emac_tx_complete_packets(). - * - * Return: enum netdev_tx - */ -static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - struct cppi5_host_desc_t *first_desc, *next_desc, *cur_desc; - struct prueth_emac *emac = netdev_priv(ndev); - struct netdev_queue *netif_txq; - struct prueth_tx_chn *tx_chn; - dma_addr_t desc_dma, buf_dma; - int i, ret = 0, q_idx; - bool in_tx_ts = 0; - int tx_ts_cookie; - void **swdata; - u32 pkt_len; - u32 *epib; - - pkt_len = skb_headlen(skb); - q_idx = skb_get_queue_mapping(skb); - - tx_chn = &emac->tx_chns[q_idx]; - netif_txq = netdev_get_tx_queue(ndev, q_idx); - - /* Map the linear buffer */ - buf_dma = dma_map_single(tx_chn->dma_dev, skb->data, pkt_len, DMA_TO_DEVICE); - if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) { - netdev_err(ndev, "tx: failed to map skb buffer\n"); - ret = NETDEV_TX_OK; - goto drop_free_skb; - } - - first_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool); - if (!first_desc) { - netdev_dbg(ndev, "tx: failed to allocate descriptor\n"); - dma_unmap_single(tx_chn->dma_dev, buf_dma, pkt_len, DMA_TO_DEVICE); - goto drop_stop_q_busy; - } - - cppi5_hdesc_init(first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT, - PRUETH_NAV_PS_DATA_SIZE); - cppi5_hdesc_set_pkttype(first_desc, 0); - epib = first_desc->epib; - epib[0] = 0; - epib[1] = 0; - if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && - emac->tx_ts_enabled) { - tx_ts_cookie = prueth_tx_ts_cookie_get(emac); - if (tx_ts_cookie >= 0) { - skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - /* Request TX timestamp */ - epib[0] = (u32)tx_ts_cookie; - epib[1] = 0x80000000; /* TX TS request */ - emac->tx_ts_skb[tx_ts_cookie] = skb_get(skb); - in_tx_ts = 1; - } - } - - /* set dst tag to indicate internal qid at the firmware which is at - * bit8..bit15. bit0..bit7 indicates port num for directed - * packets in case of switch mode operation - */ - cppi5_desc_set_tags_ids(&first_desc->hdr, 0, (emac->port_id | (q_idx << 8))); - k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); - cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len); - swdata = cppi5_hdesc_get_swdata(first_desc); - *swdata = skb; - - /* Handle the case where skb is fragmented in pages */ - cur_desc = first_desc; - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - u32 frag_size = skb_frag_size(frag); - - next_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool); - if (!next_desc) { - netdev_err(ndev, - "tx: failed to allocate frag. descriptor\n"); - goto free_desc_stop_q_busy_cleanup_tx_ts; - } - - buf_dma = skb_frag_dma_map(tx_chn->dma_dev, frag, 0, frag_size, - DMA_TO_DEVICE); - if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) { - netdev_err(ndev, "tx: Failed to map skb page\n"); - k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); - ret = NETDEV_TX_OK; - goto cleanup_tx_ts; - } - - cppi5_hdesc_reset_hbdesc(next_desc); - k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); - cppi5_hdesc_attach_buf(next_desc, - buf_dma, frag_size, buf_dma, frag_size); - - desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, - next_desc); - k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &desc_dma); - cppi5_hdesc_link_hbdesc(cur_desc, desc_dma); - - pkt_len += frag_size; - cur_desc = next_desc; - } - WARN_ON_ONCE(pkt_len != skb->len); - - /* report bql before sending packet */ - netdev_tx_sent_queue(netif_txq, pkt_len); - - cppi5_hdesc_set_pktlen(first_desc, pkt_len); - desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, first_desc); - /* cppi5_desc_dump(first_desc, 64); */ - - skb_tx_timestamp(skb); /* SW timestamp if SKBTX_IN_PROGRESS not set */ - ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma); - if (ret) { - netdev_err(ndev, "tx: push failed: %d\n", ret); - goto drop_free_descs; - } - - if (in_tx_ts) - atomic_inc(&emac->tx_ts_pending); - - if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) < MAX_SKB_FRAGS) { - netif_tx_stop_queue(netif_txq); - /* Barrier, so that stop_queue visible to other cpus */ - smp_mb__after_atomic(); - - if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >= - MAX_SKB_FRAGS) - netif_tx_wake_queue(netif_txq); - } - - return NETDEV_TX_OK; - -cleanup_tx_ts: - if (in_tx_ts) { - dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]); - emac->tx_ts_skb[tx_ts_cookie] = NULL; - } - -drop_free_descs: - prueth_xmit_free(tx_chn, first_desc); - -drop_free_skb: - dev_kfree_skb_any(skb); - - /* error */ - ndev->stats.tx_dropped++; - netdev_err(ndev, "tx: error: %d\n", ret); - - return ret; - -free_desc_stop_q_busy_cleanup_tx_ts: - if (in_tx_ts) { - dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]); - emac->tx_ts_skb[tx_ts_cookie] = NULL; - } - prueth_xmit_free(tx_chn, first_desc); - -drop_stop_q_busy: - netif_tx_stop_queue(netif_txq); - return NETDEV_TX_BUSY; -} - -static void prueth_tx_cleanup(void *data, dma_addr_t desc_dma) -{ - struct prueth_tx_chn *tx_chn = data; - struct cppi5_host_desc_t *desc_tx; - struct sk_buff *skb; - void **swdata; - - desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma); - swdata = cppi5_hdesc_get_swdata(desc_tx); - skb = *(swdata); - prueth_xmit_free(tx_chn, desc_tx); - - dev_kfree_skb_any(skb); -} - static irqreturn_t prueth_tx_ts_irq(int irq, void *dev_id) { struct prueth_emac *emac = dev_id; @@ -875,20 +118,17 @@ return IRQ_HANDLED; } -static irqreturn_t prueth_rx_irq(int irq, void *dev_id) -{ - struct prueth_emac *emac = dev_id; - - disable_irq_nosync(irq); - napi_schedule(&emac->napi_rx); - - return IRQ_HANDLED; -} - -struct icssg_firmwares { - char *pru; - char *rtu; - char *txpru; +static struct icssg_firmwares icssg_switch_firmwares[] = { + { + .pru = "ti-pruss/am65x-sr2-pru0-prusw-fw.elf", + .rtu = "ti-pruss/am65x-sr2-rtu0-prusw-fw.elf", + .txpru = "ti-pruss/am65x-sr2-txpru0-prusw-fw.elf", + }, + { + .pru = "ti-pruss/am65x-sr2-pru1-prusw-fw.elf", + .rtu = "ti-pruss/am65x-sr2-rtu1-prusw-fw.elf", + .txpru = "ti-pruss/am65x-sr2-txpru1-prusw-fw.elf", + } }; static struct icssg_firmwares icssg_emac_firmwares[] = { @@ -910,7 +150,10 @@ struct device *dev = prueth->dev; int slice, ret; - firmwares = icssg_emac_firmwares; + if (prueth->is_switch_mode) + firmwares = icssg_switch_firmwares; + else + firmwares = icssg_emac_firmwares; slice = prueth_emac_slice(emac); if (slice < 0) { @@ -955,41 +198,6 @@ return ret; } -static void prueth_emac_stop(struct prueth_emac *emac) -{ - struct prueth *prueth = emac->prueth; - int slice; - - switch (emac->port_id) { - case PRUETH_PORT_MII0: - slice = ICSS_SLICE0; - break; - case PRUETH_PORT_MII1: - slice = ICSS_SLICE1; - break; - default: - netdev_err(emac->ndev, "invalid port\n"); - return; - } - - emac->fw_running = 0; - rproc_shutdown(prueth->txpru[slice]); - rproc_shutdown(prueth->rtu[slice]); - rproc_shutdown(prueth->pru[slice]); -} - -static void prueth_cleanup_tx_ts(struct prueth_emac *emac) -{ - int i; - - for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) { - if (emac->tx_ts_skb[i]) { - dev_kfree_skb_any(emac->tx_ts_skb[i]); - emac->tx_ts_skb[i] = NULL; - } - } -} - /* called back by PHY layer if there is change in link state of hw port*/ static void emac_adjust_link(struct net_device *ndev) { @@ -1031,6 +239,8 @@ * values */ if (emac->link) { + if (emac->duplex == DUPLEX_HALF) + icssg_config_half_duplex(emac); /* Set the RGMII cfg for gig en and full duplex */ icssg_update_rgmii_cfg(prueth->miig_rt, emac); @@ -1044,6 +254,12 @@ } else { emac_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE); } + + if (emac->link) { + icssg_qos_link_up(ndev); + } else { + icssg_qos_link_down(ndev); + } } if (emac->link) { @@ -1055,84 +271,14 @@ } } -static int emac_napi_rx_poll(struct napi_struct *napi_rx, int budget) +static enum hrtimer_restart emac_rx_timer_callback(struct hrtimer *timer) { - struct prueth_emac *emac = prueth_napi_to_emac(napi_rx); + struct prueth_emac *emac = + container_of(timer, struct prueth_emac, rx_hrtimer); int rx_flow = PRUETH_RX_FLOW_DATA; - int flow = PRUETH_MAX_RX_FLOWS; - int num_rx = 0; - int cur_budget; - int ret; - - while (flow--) { - cur_budget = budget - num_rx; - while (cur_budget--) { - ret = emac_rx_packet(emac, flow); - if (ret) - break; - num_rx++; - } - - if (num_rx >= budget) - break; - } - - if (num_rx < budget && napi_complete_done(napi_rx, num_rx)) - enable_irq(emac->rx_chns.irq[rx_flow]); - - return num_rx; -} - -static int prueth_prepare_rx_chan(struct prueth_emac *emac, - struct prueth_rx_chn *chn, - int buf_size) -{ - struct sk_buff *skb; - int i, ret; - - for (i = 0; i < chn->descs_num; i++) { - skb = __netdev_alloc_skb_ip_align(NULL, buf_size, GFP_KERNEL); - if (!skb) - return -ENOMEM; - - ret = prueth_dma_rx_push(emac, skb, chn); - if (ret < 0) { - netdev_err(emac->ndev, - "cannot submit skb for rx chan %s ret %d\n", - chn->name, ret); - kfree_skb(skb); - return ret; - } - } - - return 0; -} - -static void prueth_reset_tx_chan(struct prueth_emac *emac, int ch_num, - bool free_skb) -{ - int i; - - for (i = 0; i < ch_num; i++) { - if (free_skb) - k3_udma_glue_reset_tx_chn(emac->tx_chns[i].tx_chn, - &emac->tx_chns[i], - prueth_tx_cleanup); - k3_udma_glue_disable_tx_chn(emac->tx_chns[i].tx_chn); - } -} - -static void prueth_reset_rx_chan(struct prueth_rx_chn *chn, - int num_flows, bool disable) -{ - int i; - - for (i = 0; i < num_flows; i++) - k3_udma_glue_reset_rx_chn(chn->rx_chn, i, chn, - prueth_rx_cleanup, !!i); - if (disable) - k3_udma_glue_disable_rx_chn(chn->rx_chn); + enable_irq(emac->rx_chns.irq[rx_flow]); + return HRTIMER_NORESTART; } static int emac_phy_connect(struct prueth_emac *emac) @@ -1149,9 +295,13 @@ return -ENODEV; } + if (!emac->half_duplex) { + dev_dbg(prueth->dev, "half duplex mode is not supported\n"); + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); + } + /* remove unsupported modes */ - phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); - phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Pause_BIT); phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT); @@ -1162,7 +312,7 @@ return 0; } -static u64 prueth_iep_gettime(void *clockops_data, struct ptp_system_timestamp *sts) +u64 prueth_iep_gettime(void *clockops_data, struct ptp_system_timestamp *sts) { u32 hi_rollover_count, hi_rollover_count_r; struct prueth_emac *emac = clockops_data; @@ -1295,6 +445,64 @@ .perout_enable = prueth_perout_enable, }; +static int prueth_create_xdp_rxqs(struct prueth_emac *emac) +{ + struct xdp_rxq_info *rxq = &emac->rx_chns.xdp_rxq; + struct page_pool *pool = emac->rx_chns.pg_pool; + int ret; + + ret = xdp_rxq_info_reg(rxq, emac->ndev, 0, rxq->napi_id); + if (ret) + return ret; + + ret = xdp_rxq_info_reg_mem_model(rxq, MEM_TYPE_PAGE_POOL, pool); + if (ret) + xdp_rxq_info_unreg(rxq); + + return ret; +} + +static void prueth_destroy_xdp_rxqs(struct prueth_emac *emac) +{ + struct xdp_rxq_info *rxq = &emac->rx_chns.xdp_rxq; + + if (!xdp_rxq_info_is_reg(rxq)) + return; + + xdp_rxq_info_unreg(rxq); +} + +static int icssg_prueth_add_mcast(struct net_device *ndev, const u8 *addr) +{ + struct prueth_emac *emac = netdev_priv(ndev); + int port_mask = BIT(emac->port_id); + + port_mask |= icssg_fdb_lookup(emac, addr, 0); + icssg_fdb_add_del(emac, addr, 0, port_mask, true); + icssg_vtbl_modify(emac, 0, port_mask, port_mask, true); + + return 0; +} + +static int icssg_prueth_del_mcast(struct net_device *ndev, const u8 *addr) +{ + struct prueth_emac *emac = netdev_priv(ndev); + int port_mask = BIT(emac->port_id); + int other_port_mask; + + other_port_mask = port_mask ^ icssg_fdb_lookup(emac, addr, 0); + + icssg_fdb_add_del(emac, addr, 0, port_mask, false); + icssg_vtbl_modify(emac, 0, port_mask, port_mask, false); + + if (other_port_mask) { + icssg_fdb_add_del(emac, addr, 0, other_port_mask, true); + icssg_vtbl_modify(emac, 0, other_port_mask, other_port_mask, true); + } + + return 0; +} + /** * emac_ndo_open - EMAC device open * @ndev: network adapter device @@ -1307,6 +515,7 @@ { struct prueth_emac *emac = netdev_priv(ndev); int ret, i, num_data_chn = emac->tx_ch_num; + struct icssg_flow_cfg __iomem *flow_cfg; struct prueth *prueth = emac->prueth; int slice = prueth_emac_slice(emac); struct device *dev = prueth->dev; @@ -1322,11 +531,14 @@ /* set h/w MAC as user might have re-configured */ ether_addr_copy(emac->mac_addr, ndev->dev_addr); + if (!prueth->emacs_initialized) { + icssg_class_default(prueth->miig_rt, ICSS_SLICE0, 0, false); + icssg_class_default(prueth->miig_rt, ICSS_SLICE1, 0, false); + } + icssg_class_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr); icssg_ft1_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr); - icssg_class_default(prueth->miig_rt, slice, 0); - /* Notify the stack of the actual queue counts. */ ret = netif_set_real_num_tx_queues(ndev, num_data_chn); if (ret) { @@ -1362,10 +574,31 @@ goto cleanup_napi; } - /* reset and start PRU firmware */ - ret = prueth_emac_start(prueth, emac); - if (ret) - goto free_rx_irq; + if (!prueth->emacs_initialized) { + if (prueth->emac[ICSS_SLICE0]) { + ret = prueth_emac_start(prueth, prueth->emac[ICSS_SLICE0]); + if (ret) { + netdev_err(ndev, "unable to start fw for slice %d", ICSS_SLICE0); + goto free_rx_irq; + } + } + if (prueth->emac[ICSS_SLICE1]) { + ret = prueth_emac_start(prueth, prueth->emac[ICSS_SLICE1]); + if (ret) { + netdev_err(ndev, "unable to start fw for slice %d", ICSS_SLICE1); + goto halt_slice0_prus; + } + } + } + + flow_cfg = emac->dram.va + ICSSG_CONFIG_OFFSET + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET; + writew(emac->rx_flow_id_base, &flow_cfg->rx_base_flow); + ret = emac_fdb_flow_id_updated(emac); + + if (ret) { + netdev_err(ndev, "Failed to update Rx Flow ID %d", ret); + goto stop; + } icssg_mii_update_mtu(prueth->mii_rt, slice, ndev->max_mtu); @@ -1382,6 +615,10 @@ /* Prepare RX */ ret = prueth_prepare_rx_chan(emac, &emac->rx_chns, PRUETH_MAX_PKT_SIZE); if (ret) + goto destroy_xdp_rxqs; + + ret = prueth_create_xdp_rxqs(emac); + if (ret) goto free_tx_ts_irq; ret = k3_udma_glue_enable_rx_chn(emac->rx_chns.rx_chn); @@ -1399,6 +636,8 @@ napi_enable(&emac->tx_chns[i].napi_tx); napi_enable(&emac->napi_rx); + icssg_qos_init(ndev); + /* start PHY */ phy_start(ndev->phydev); @@ -1415,10 +654,16 @@ prueth_reset_tx_chan(emac, i, false); reset_rx_chn: prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, false); +destroy_xdp_rxqs: + prueth_destroy_xdp_rxqs(emac); free_tx_ts_irq: free_irq(emac->tx_ts_irq, emac); stop: - prueth_emac_stop(emac); + if (prueth->emac[ICSS_SLICE1]) + prueth_emac_stop(prueth->emac[ICSS_SLICE1]); +halt_slice0_prus: + if (prueth->emac[ICSS_SLICE0]) + prueth_emac_stop(prueth->emac[ICSS_SLICE0]); free_rx_irq: free_irq(emac->rx_chns.irq[rx_flow], emac); cleanup_napi: @@ -1454,7 +699,12 @@ if (ndev->phydev) phy_stop(ndev->phydev); - icssg_class_disable(prueth->miig_rt, prueth_emac_slice(emac)); + if (prueth->emacs_initialized == 1) { + icssg_class_disable(prueth->miig_rt, ICSS_SLICE0); + icssg_class_disable(prueth->miig_rt, ICSS_SLICE1); + } + + __dev_mc_unsync(ndev, icssg_prueth_del_mcast); atomic_set(&emac->tdown_cnt, emac->tx_ch_num); /* ensure new tdown_cnt value is visible */ @@ -1470,29 +720,34 @@ netdev_err(ndev, "tx teardown timeout\n"); prueth_reset_tx_chan(emac, emac->tx_ch_num, true); - for (i = 0; i < emac->tx_ch_num; i++) + for (i = 0; i < emac->tx_ch_num; i++) { napi_disable(&emac->tx_chns[i].napi_tx); + hrtimer_cancel(&emac->tx_chns[i].tx_hrtimer); + } max_rx_flows = PRUETH_MAX_RX_FLOWS; k3_udma_glue_tdown_rx_chn(emac->rx_chns.rx_chn, true); prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, true); + prueth_destroy_xdp_rxqs(emac); + napi_disable(&emac->napi_rx); + hrtimer_cancel(&emac->rx_hrtimer); cancel_work_sync(&emac->rx_mode_work); /* Destroying the queued work in ndo_stop() */ cancel_delayed_work_sync(&emac->stats_work); - /* stop PRUs */ - prueth_emac_stop(emac); - - if (prueth->emacs_initialized == 1) + if (prueth->emacs_initialized == 1) { icss_iep_exit(emac->iep); - - /* stop PRUs */ - prueth_emac_stop(emac); + /* stop PRUs */ + if (prueth->emac[ICSS_SLICE0]) + prueth_emac_stop(prueth->emac[ICSS_SLICE0]); + if (prueth->emac[ICSS_SLICE1]) + prueth_emac_stop(prueth->emac[ICSS_SLICE1]); + } free_irq(emac->tx_ts_irq, emac); @@ -1508,11 +763,6 @@ return 0; } -static void emac_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue) -{ - ndev->stats.tx_errors++; -} - static void emac_ndo_set_rx_mode_work(struct work_struct *work) { struct prueth_emac *emac = container_of(work, struct prueth_emac, rx_mode_work); @@ -1538,10 +788,7 @@ return; } - if (!netdev_mc_empty(ndev)) { - emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE); - return; - } + __dev_mc_sync(ndev, icssg_prueth_add_mcast, icssg_prueth_del_mcast); } /** @@ -1558,101 +805,234 @@ queue_work(emac->cmd_wq, &emac->rx_mode_work); } -static int emac_set_ts_config(struct net_device *ndev, struct ifreq *ifr) +/** + * emac_xmit_xdp_frame - transmits an XDP frame + * @emac: emac device + * @xdpf: data to transmit + * @page: page from page pool if already DMA mapped + * @q_idx: queue id + * + * Return: XDP state + */ +static int emac_xmit_xdp_frame(struct prueth_emac *emac, + struct xdp_frame *xdpf, + struct page *page, + unsigned int q_idx) { - struct prueth_emac *emac = netdev_priv(ndev); - struct hwtstamp_config config; + struct cppi5_host_desc_t *first_desc; + struct net_device *ndev = emac->ndev; + struct prueth_tx_chn *tx_chn; + dma_addr_t desc_dma, buf_dma; + struct prueth_swdata *swdata; + u32 *epib; + int ret; - if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) - return -EFAULT; + void *data = xdpf->data; + u32 pkt_len = xdpf->len; - switch (config.tx_type) { - case HWTSTAMP_TX_OFF: - emac->tx_ts_enabled = 0; - break; - case HWTSTAMP_TX_ON: - emac->tx_ts_enabled = 1; - break; - default: - return -ERANGE; + if (q_idx >= PRUETH_MAX_TX_QUEUES) { + netdev_err(ndev, "xdp tx: invalid q_id %d\n", q_idx); + return ICSSG_XDP_CONSUMED; /* drop */ } - switch (config.rx_filter) { - case HWTSTAMP_FILTER_NONE: - emac->rx_ts_enabled = 0; - break; - case HWTSTAMP_FILTER_ALL: - case HWTSTAMP_FILTER_SOME: - case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: - case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: - case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: - case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: - case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: - case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: - case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: - case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: - case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: - case HWTSTAMP_FILTER_PTP_V2_EVENT: - case HWTSTAMP_FILTER_PTP_V2_SYNC: - case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - case HWTSTAMP_FILTER_NTP_ALL: - emac->rx_ts_enabled = 1; - config.rx_filter = HWTSTAMP_FILTER_ALL; - break; - default: - return -ERANGE; + tx_chn = &emac->tx_chns[q_idx]; + + if (page) { /* already DMA mapped by page_pool */ + buf_dma = page_pool_get_dma_addr(page); + buf_dma += xdpf->headroom + sizeof(struct xdp_frame); + } else { /* Map the linear buffer */ + buf_dma = dma_map_single(tx_chn->dma_dev, data, pkt_len, DMA_TO_DEVICE); + if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) { + netdev_err(ndev, "xdp tx: failed to map data buffer\n"); + return ICSSG_XDP_CONSUMED; /* drop */ + } + } + + first_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool); + if (!first_desc) { + netdev_dbg(ndev, "xdp tx: failed to allocate descriptor\n"); + if (!page) + dma_unmap_single(tx_chn->dma_dev, buf_dma, pkt_len, DMA_TO_DEVICE); + return ICSSG_XDP_CONSUMED; /* drop */ + } + + cppi5_hdesc_init(first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT, + PRUETH_NAV_PS_DATA_SIZE); + cppi5_hdesc_set_pkttype(first_desc, 0); + epib = first_desc->epib; + epib[0] = 0; + epib[1] = 0; + + /* set dst tag to indicate internal qid at the firmware which is at + * bit8..bit15. bit0..bit7 indicates port num for directed + * packets in case of switch mode operation + */ + cppi5_desc_set_tags_ids(&first_desc->hdr, 0, (emac->port_id | (q_idx << 8))); + k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); + cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len); + swdata = cppi5_hdesc_get_swdata(first_desc); + if (page) { + swdata->type = PRUETH_SWDATA_PAGE; + swdata->data.page = page; + /* we assume page came from RX channel page pool */ + swdata->rx_chn = &emac->rx_chns; + } else { + swdata->type = PRUETH_SWDATA_XDPF; + swdata->data.xdpf = xdpf; + } + + cppi5_hdesc_set_pktlen(first_desc, pkt_len); + desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, first_desc); + + ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma); + if (ret) { + netdev_err(ndev, "xdp tx: push failed: %d\n", ret); + goto drop_free_descs; } - return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? - -EFAULT : 0; + return ICSSG_XDP_TX; + +drop_free_descs: + prueth_xmit_free(tx_chn, first_desc); + return ICSSG_XDP_CONSUMED; } -static int emac_get_ts_config(struct net_device *ndev, struct ifreq *ifr) -{ - struct prueth_emac *emac = netdev_priv(ndev); - struct hwtstamp_config config; +/** + * emac_xdp_xmit - Implements ndo_xdp_xmit + * @dev: netdev + * @n: number of frames + * @frames: array of XDP buffer pointers + * @flags: XDP extra info + * + * Return: number of frames successfully sent. Failed frames + * will be free'ed by XDP core. + * + * For error cases, a negative errno code is returned and no-frames + * are transmitted (caller must handle freeing frames). + **/ +static int emac_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames, + u32 flags) +{ + struct prueth_emac *emac = netdev_priv(dev); + unsigned int q_idx; + int nxmit = 0; + int i; + + q_idx = smp_processor_id(); + + if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) + return -EINVAL; - config.flags = 0; - config.tx_type = emac->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; - config.rx_filter = emac->rx_ts_enabled ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE; + for (i = 0; i < n; i++) { + struct xdp_frame *xdpf = frames[i]; + int err; - return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? - -EFAULT : 0; + err = emac_xmit_xdp_frame(emac, xdpf, NULL, q_idx); + if (err != ICSSG_XDP_TX) + break; + nxmit++; + } + + return nxmit; } -static int emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) +/** + * emac_run_xdp - run an XDP program + * @emac: emac device + * @xdp: XDP buffer containing the frame + * @page: page with RX data if already DMA mapped + * + * Return: XDP state + */ +int emac_run_xdp(struct prueth_emac *emac, struct xdp_buff *xdp, + struct page *page) { - switch (cmd) { - case SIOCGHWTSTAMP: - return emac_get_ts_config(ndev, ifr); - case SIOCSHWTSTAMP: - return emac_set_ts_config(ndev, ifr); + int err, result = ICSSG_XDP_PASS; + struct bpf_prog *xdp_prog; + struct xdp_frame *xdpf; + int q_idx; + u32 act; + + xdp_prog = READ_ONCE(emac->xdp_prog); + + if (!xdp_prog) + return result; + + act = bpf_prog_run_xdp(xdp_prog, xdp); + switch (act) { + case XDP_PASS: + break; + case XDP_TX: + /* Send packet to TX ring for immediate transmission */ + xdpf = xdp_convert_buff_to_frame(xdp); + if (unlikely(!xdpf)) + goto drop; + + q_idx = smp_processor_id(); + result = emac_xmit_xdp_frame(emac, xdpf, page, q_idx); + if (result == ICSSG_XDP_CONSUMED) + goto drop; + break; + case XDP_REDIRECT: + err = xdp_do_redirect(emac->ndev, xdp, xdp_prog); + if (err) + goto drop; + result = ICSSG_XDP_REDIR; + break; default: + bpf_warn_invalid_xdp_action(emac->ndev, xdp_prog, act); + fallthrough; + case XDP_ABORTED: +drop: + trace_xdp_exception(emac->ndev, xdp_prog, act); + fallthrough; /* handle aborts by dropping packet */ + case XDP_DROP: + result = ICSSG_XDP_CONSUMED; + page_pool_recycle_direct(emac->rx_chns.pg_pool, page); break; } - return phy_do_ioctl(ndev, ifr, cmd); + return result; } -static void emac_ndo_get_stats64(struct net_device *ndev, - struct rtnl_link_stats64 *stats) +/** + * emac_xdp_setup - add/remove an XDP program + * @emac: emac device + * @bpf: XDP program + * + * Return: Always 0 (Success) + **/ +static int emac_xdp_setup(struct prueth_emac *emac, struct netdev_bpf *bpf) { - struct prueth_emac *emac = netdev_priv(ndev); + struct bpf_prog *prog = bpf->prog; + + if (!emac->xdpi.prog && !prog) + return 0; + + WRITE_ONCE(emac->xdp_prog, prog); + + xdp_attachment_setup(&emac->xdpi, bpf); + + return 0; +} - emac_update_hardware_stats(emac); +/** + * emac_ndo_bpf - implements ndo_bpf for icssg_prueth + * @ndev: network adapter device + * @bpf: XDP program + * + * Return: 0 on success, error code on failure. + **/ +static int emac_ndo_bpf(struct net_device *ndev, struct netdev_bpf *bpf) +{ + struct prueth_emac *emac = netdev_priv(ndev); - stats->rx_packets = emac_get_stat_by_name(emac, "rx_packets"); - stats->rx_bytes = emac_get_stat_by_name(emac, "rx_bytes"); - stats->tx_packets = emac_get_stat_by_name(emac, "tx_packets"); - stats->tx_bytes = emac_get_stat_by_name(emac, "tx_bytes"); - stats->rx_crc_errors = emac_get_stat_by_name(emac, "rx_crc_errors"); - stats->rx_over_errors = emac_get_stat_by_name(emac, "rx_over_errors"); - stats->multicast = emac_get_stat_by_name(emac, "rx_multicast_frames"); - - stats->rx_errors = ndev->stats.rx_errors; - stats->rx_dropped = ndev->stats.rx_dropped; - stats->tx_errors = ndev->stats.tx_errors; - stats->tx_dropped = ndev->stats.tx_dropped; + switch (bpf->command) { + case XDP_SETUP_PROG: + return emac_xdp_setup(emac, bpf); + default: + return -EINVAL; + } } static const struct net_device_ops emac_netdev_ops = { @@ -1665,44 +1045,11 @@ .ndo_set_rx_mode = emac_ndo_set_rx_mode, .ndo_eth_ioctl = emac_ndo_ioctl, .ndo_get_stats64 = emac_ndo_get_stats64, + .ndo_setup_tc = icssg_qos_ndo_setup_tc, + .ndo_bpf = emac_ndo_bpf, + .ndo_xdp_xmit = emac_xdp_xmit, }; -/* get emac_port corresponding to eth_node name */ -static int prueth_node_port(struct device_node *eth_node) -{ - u32 port_id; - int ret; - - ret = of_property_read_u32(eth_node, "reg", &port_id); - if (ret) - return ret; - - if (port_id == 0) - return PRUETH_PORT_MII0; - else if (port_id == 1) - return PRUETH_PORT_MII1; - else - return PRUETH_PORT_INVALID; -} - -/* get MAC instance corresponding to eth_node name */ -static int prueth_node_mac(struct device_node *eth_node) -{ - u32 port_id; - int ret; - - ret = of_property_read_u32(eth_node, "reg", &port_id); - if (ret) - return ret; - - if (port_id == 0) - return PRUETH_MAC0; - else if (port_id == 1) - return PRUETH_MAC1; - else - return PRUETH_MAC_INVALID; -} - static int prueth_netdev_init(struct prueth *prueth, struct device_node *eth_node) { @@ -1830,6 +1177,9 @@ ndev->features = ndev->hw_features; netif_napi_add(ndev, &emac->napi_rx, emac_napi_rx_poll); + hrtimer_init(&emac->rx_hrtimer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL_PINNED); + emac->rx_hrtimer.function = &emac_rx_timer_callback; prueth->emac[mac] = emac; return 0; @@ -1846,91 +1196,390 @@ return ret; } -static void prueth_netdev_exit(struct prueth *prueth, - struct device_node *eth_node) +bool prueth_dev_check(const struct net_device *ndev) +{ + if (ndev->netdev_ops == &emac_netdev_ops && netif_running(ndev)) { + struct prueth_emac *emac = netdev_priv(ndev); + + return emac->prueth->is_switch_mode; + } + + return false; +} + +static void prueth_offload_fwd_mark_update(struct prueth *prueth) +{ + int set_val = 0; + int i; + + if (prueth->br_members == (BIT(PRUETH_PORT_MII0) | BIT(PRUETH_PORT_MII1))) + set_val = 1; + + dev_dbg(prueth->dev, "set offload_fwd_mark %d\n", set_val); + + for (i = PRUETH_MAC0; i < PRUETH_NUM_MACS; i++) { + struct prueth_emac *emac = prueth->emac[i]; + + if (!emac || !emac->ndev) + continue; + + emac->offload_fwd_mark = set_val; + } +} + +static void prueth_emac_restart(struct prueth *prueth) +{ + struct prueth_emac *emac0 = prueth->emac[PRUETH_MAC0]; + struct prueth_emac *emac1 = prueth->emac[PRUETH_MAC1]; + + /* Detach the net_device for both PRUeth ports*/ + if (netif_running(emac0->ndev)) + netif_device_detach(emac0->ndev); + if (netif_running(emac1->ndev)) + netif_device_detach(emac1->ndev); + + /* Disable both PRUeth ports */ + emac_set_port_state(emac0, ICSSG_EMAC_PORT_DISABLE); + emac_set_port_state(emac1, ICSSG_EMAC_PORT_DISABLE); + + /* Stop both pru cores for both PRUeth ports*/ + prueth_emac_stop(emac0); + prueth->emacs_initialized--; + prueth_emac_stop(emac1); + prueth->emacs_initialized--; + + /* Start both pru cores for both PRUeth ports */ + prueth_emac_start(prueth, emac0); + prueth->emacs_initialized++; + prueth_emac_start(prueth, emac1); + prueth->emacs_initialized++; + + /* Enable forwarding for both PRUeth ports */ + emac_set_port_state(emac0, ICSSG_EMAC_PORT_FORWARD); + emac_set_port_state(emac1, ICSSG_EMAC_PORT_FORWARD); + + /* Attache net_device for both PRUeth ports */ + netif_device_attach(emac0->ndev); + netif_device_attach(emac1->ndev); +} + +static void icssg_enable_switch_mode(struct prueth *prueth) { struct prueth_emac *emac; - enum prueth_mac mac; + int mac; - mac = prueth_node_mac(eth_node); - if (mac == PRUETH_MAC_INVALID) - return; + prueth_emac_restart(prueth); - emac = prueth->emac[mac]; - if (!emac) - return; + for (mac = PRUETH_MAC0; mac < PRUETH_NUM_MACS; mac++) { + emac = prueth->emac[mac]; + if (netif_running(emac->ndev)) { + icssg_fdb_add_del(emac, eth_stp_addr, prueth->default_vlan, + ICSSG_FDB_ENTRY_P0_MEMBERSHIP | + ICSSG_FDB_ENTRY_P1_MEMBERSHIP | + ICSSG_FDB_ENTRY_P2_MEMBERSHIP | + ICSSG_FDB_ENTRY_BLOCK, + true); + icssg_vtbl_modify(emac, emac->port_vlan | DEFAULT_VID, + BIT(emac->port_id) | DEFAULT_PORT_MASK, + BIT(emac->port_id) | DEFAULT_UNTAG_MASK, + true); + icssg_set_pvid(prueth, emac->port_vlan, emac->port_id); + emac_set_port_state(emac, ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE); + } + } +} - if (of_phy_is_fixed_link(emac->phy_node)) - of_phy_deregister_fixed_link(emac->phy_node); +static int prueth_netdevice_port_link(struct net_device *ndev, + struct net_device *br_ndev, + struct netlink_ext_ack *extack) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; + int err; - netif_napi_del(&emac->napi_rx); + if (!prueth->br_members) { + prueth->hw_bridge_dev = br_ndev; + } else { + /* This is adding the port to a second bridge, this is + * unsupported + */ + if (prueth->hw_bridge_dev != br_ndev) + return -EOPNOTSUPP; + } - pruss_release_mem_region(prueth->pruss, &emac->dram); - destroy_workqueue(emac->cmd_wq); - free_netdev(emac->ndev); - prueth->emac[mac] = NULL; + err = switchdev_bridge_port_offload(br_ndev, ndev, emac, + &prueth->prueth_switchdev_nb, + &prueth->prueth_switchdev_bl_nb, + false, extack); + if (err) + return err; + + prueth->br_members |= BIT(emac->port_id); + + if (!prueth->is_switch_mode) { + if (prueth->br_members & BIT(PRUETH_PORT_MII0) && + prueth->br_members & BIT(PRUETH_PORT_MII1)) { + prueth->is_switch_mode = true; + prueth->default_vlan = 1; + emac->port_vlan = prueth->default_vlan; + icssg_enable_switch_mode(prueth); + } + } + + prueth_offload_fwd_mark_update(prueth); + + return NOTIFY_DONE; } -static int prueth_get_cores(struct prueth *prueth, int slice) +static void prueth_netdevice_port_unlink(struct net_device *ndev) { - struct device *dev = prueth->dev; - enum pruss_pru_id pruss_id; - struct device_node *np; - int idx = -1, ret; + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; - np = dev->of_node; + prueth->br_members &= ~BIT(emac->port_id); - switch (slice) { - case ICSS_SLICE0: - idx = 0; - break; - case ICSS_SLICE1: - idx = 3; + if (prueth->is_switch_mode) { + prueth->is_switch_mode = false; + emac->port_vlan = 0; + prueth_emac_restart(prueth); + } + + prueth_offload_fwd_mark_update(prueth); + + if (!prueth->br_members) + prueth->hw_bridge_dev = NULL; +} + +/* netdev notifier */ +static int prueth_netdevice_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr); + struct net_device *ndev = netdev_notifier_info_to_dev(ptr); + struct netdev_notifier_changeupper_info *info; + int ret = NOTIFY_DONE; + + if (ndev->netdev_ops != &emac_netdev_ops) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_CHANGEUPPER: + info = ptr; + + if (netif_is_bridge_master(info->upper_dev)) { + if (info->linking) + ret = prueth_netdevice_port_link(ndev, info->upper_dev, extack); + else + prueth_netdevice_port_unlink(ndev); + } break; default: - return -EINVAL; + return NOTIFY_DONE; } - prueth->pru[slice] = pru_rproc_get(np, idx, &pruss_id); - if (IS_ERR(prueth->pru[slice])) { - ret = PTR_ERR(prueth->pru[slice]); - prueth->pru[slice] = NULL; - return dev_err_probe(dev, ret, "unable to get PRU%d\n", slice); - } - prueth->pru_id[slice] = pruss_id; - - idx++; - prueth->rtu[slice] = pru_rproc_get(np, idx, NULL); - if (IS_ERR(prueth->rtu[slice])) { - ret = PTR_ERR(prueth->rtu[slice]); - prueth->rtu[slice] = NULL; - return dev_err_probe(dev, ret, "unable to get RTU%d\n", slice); - } - - idx++; - prueth->txpru[slice] = pru_rproc_get(np, idx, NULL); - if (IS_ERR(prueth->txpru[slice])) { - ret = PTR_ERR(prueth->txpru[slice]); - prueth->txpru[slice] = NULL; - return dev_err_probe(dev, ret, "unable to get TX_PRU%d\n", slice); + return notifier_from_errno(ret); +} + +static int prueth_register_notifiers(struct prueth *prueth) +{ + int ret = 0; + + prueth->prueth_netdevice_nb.notifier_call = &prueth_netdevice_event; + ret = register_netdevice_notifier(&prueth->prueth_netdevice_nb); + if (ret) { + dev_err(prueth->dev, "can't register netdevice notifier\n"); + return ret; + } + + ret = prueth_switchdev_register_notifiers(prueth); + if (ret) + unregister_netdevice_notifier(&prueth->prueth_netdevice_nb); + + return ret; +} + +static void prueth_unregister_notifiers(struct prueth *prueth) +{ + prueth_switchdev_unregister_notifiers(prueth); + unregister_netdevice_notifier(&prueth->prueth_netdevice_nb); +} + +static const struct devlink_ops prueth_devlink_ops = {}; + +static u8 prueth_dl_cut_thru_check(struct prueth_emac *emac) +{ + void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET; + u8 queue_map = 0U; + u8 cut_thru_val; + int i; + + for (i = 0; i < PRUETH_MAX_TX_QUEUES * PRUETH_NUM_MACS; i++) { + cut_thru_val = readb(config + EXPRESS_PRE_EMPTIVE_Q_MAP + i); + if (cut_thru_val & BIT(7)) + queue_map |= BIT(i); + } + + return queue_map; +} + +static int prueth_dl_cut_thru_en_get(struct devlink *dl, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct prueth_devlink *dl_priv = devlink_priv(dl); + struct prueth *prueth = dl_priv->prueth; + u16 tx_queues = 0U; + int i; + + dev_dbg(prueth->dev, "%s id:%u\n", __func__, id); + + if (id != PRUETH_DL_PARAM_CUT_THRU_EN) + return -EOPNOTSUPP; + + for (i = PRUETH_MAC0; i < PRUETH_NUM_MACS; i++) { + if (!(prueth->emac[i])) + return -EINVAL; + + tx_queues |= prueth_dl_cut_thru_check(prueth->emac[i]) << (8 * i); + } + + ctx->val.vu16 = tx_queues; + + return 0; +} + +static int prueth_dl_cut_thru_en_set(struct devlink *dl, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct prueth_devlink *dl_priv = devlink_priv(dl); + struct prueth *prueth = dl_priv->prueth; + u16 tx_queues = ctx->val.vu16; + struct prueth_emac *emac; + int i; + + if (id != PRUETH_DL_PARAM_CUT_THRU_EN) + return -EOPNOTSUPP; + + if (!prueth->is_switch_mode) { + dev_err(prueth->dev, "Cut-Thru not supported in MAC mode\n"); + return -EINVAL; } + for (i = PRUETH_MAC0; i < PRUETH_NUM_MACS; i++) { + emac = prueth->emac[i]; + if (netif_running(emac->ndev)) { + dev_err(prueth->dev, "Cannot enable cut-thru when i/f are up\n"); + return -EINVAL; + } + + emac->cut_thru_queue_map = tx_queues >> (8 * i); + } return 0; } -static void prueth_put_cores(struct prueth *prueth, int slice) +static const struct devlink_param prueth_devlink_params[] = { + DEVLINK_PARAM_DRIVER(PRUETH_DL_PARAM_CUT_THRU_EN, "cut_thru", + DEVLINK_PARAM_TYPE_U16, + BIT(DEVLINK_PARAM_CMODE_RUNTIME), + prueth_dl_cut_thru_en_get, + prueth_dl_cut_thru_en_set, NULL), +}; + +static void prueth_unregister_devlink_ports(struct prueth *prueth) { - if (prueth->txpru[slice]) - pru_rproc_put(prueth->txpru[slice]); + struct devlink_port *dl_port; + struct prueth_emac *emac; + int i; + + for (i = PRUETH_MAC0; i < PRUETH_NUM_MACS; i++) { + emac = prueth->emac[i]; + if (!emac) + continue; - if (prueth->rtu[slice]) - pru_rproc_put(prueth->rtu[slice]); + dl_port = &emac->devlink_port; - if (prueth->pru[slice]) - pru_rproc_put(prueth->pru[slice]); + if (dl_port->registered) + devlink_port_unregister(dl_port); + } } -static const struct of_device_id prueth_dt_match[]; +static int prueth_register_devlink(struct prueth *prueth) +{ + struct devlink_port_attrs attrs = {}; + struct device *dev = prueth->dev; + struct prueth_devlink *dl_priv; + struct devlink_port *dl_port; + struct prueth_emac *emac; + int i, ret = 0; + + prueth->devlink = + devlink_alloc(&prueth_devlink_ops, sizeof(*dl_priv), dev); + if (!prueth->devlink) + return -ENOMEM; + + dl_priv = devlink_priv(prueth->devlink); + dl_priv->prueth = prueth; + + /* Provide devlink hook to switch mode when multiple external ports + * are present NUSS switchdev driver is enabled. + */ + if (prueth->is_switchmode_supported) { + ret = devlink_params_register(prueth->devlink, + prueth_devlink_params, + ARRAY_SIZE(prueth_devlink_params)); + if (ret) { + dev_err(dev, "devlink params reg fail ret:%d\n", ret); + goto dl_unreg; + } + } + + for (i = PRUETH_MAC0; i < PRUETH_NUM_MACS; i++) { + emac = prueth->emac[i]; + if (!emac) + continue; + + dl_port = &emac->devlink_port; + + if (emac->ndev) + attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; + else + attrs.flavour = DEVLINK_PORT_FLAVOUR_UNUSED; + attrs.phys.port_number = emac->port_id; + attrs.switch_id.id_len = sizeof(resource_size_t); + memcpy(attrs.switch_id.id, prueth->switch_id, attrs.switch_id.id_len); + devlink_port_attrs_set(dl_port, &attrs); + + ret = devlink_port_register(prueth->devlink, dl_port, emac->port_id); + if (ret) { + dev_err(dev, "devlink_port reg fail for port %d, ret:%d\n", + emac->port_id, ret); + goto dl_port_unreg; + } + } + + devlink_register(prueth->devlink); + return ret; + +dl_port_unreg: + prueth_unregister_devlink_ports(prueth); +dl_unreg: + devlink_free(prueth->devlink); + + return ret; +} + +static void prueth_unregister_devlink(struct prueth *prueth) +{ + devlink_unregister(prueth->devlink); + + if (prueth->is_switchmode_supported) { + devlink_params_unregister(prueth->devlink, prueth_devlink_params, + ARRAY_SIZE(prueth_devlink_params)); + } + + prueth_unregister_devlink_ports(prueth); + devlink_unregister(prueth->devlink); + devlink_free(prueth->devlink); +} static int prueth_probe(struct platform_device *pdev) { @@ -1940,7 +1589,6 @@ struct genpool_data_align gp_data = { .align = SZ_64K, }; - const struct of_device_id *match; struct device *dev = &pdev->dev; struct device_node *np; struct prueth *prueth; @@ -1950,9 +1598,11 @@ np = dev->of_node; - match = of_match_device(prueth_dt_match, dev); - if (!match) - return -ENODEV; + if (sizeof(struct prueth_swdata) > PRUETH_NAV_SW_DATA_SIZE) { + dev_err(dev, "insufficient SW_DATA size: %d vs %ld\n", + PRUETH_NAV_SW_DATA_SIZE, sizeof(struct prueth_swdata)); + return -ENOMEM; + } prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL); if (!prueth) @@ -1960,7 +1610,7 @@ dev_set_drvdata(dev, prueth); prueth->pdev = pdev; - prueth->pdata = *(const struct prueth_pdata *)match->data; + prueth->pdata = *(const struct prueth_pdata *)device_get_match_data(dev); prueth->dev = dev; eth_ports_node = of_get_child_by_name(np, "ethernet-ports"); @@ -2026,14 +1676,20 @@ return -ENODEV; } + prueth->pa_stats = syscon_regmap_lookup_by_phandle(np, "ti,pa-stats"); + if (IS_ERR(prueth->pa_stats)) { + dev_err(dev, "couldn't get ti,pa-stats syscon regmap\n"); + return -ENODEV; + } + if (eth0_node) { - ret = prueth_get_cores(prueth, ICSS_SLICE0); + ret = prueth_get_cores(prueth, ICSS_SLICE0, false); if (ret) goto put_cores; } if (eth1_node) { - ret = prueth_get_cores(prueth, ICSS_SLICE1); + ret = prueth_get_cores(prueth, ICSS_SLICE1, false); if (ret) goto put_cores; } @@ -2064,6 +1720,9 @@ } msmc_ram_size = MSMC_RAM_SIZE; + prueth->is_switchmode_supported = prueth->pdata.switch_mode; + if (prueth->is_switchmode_supported) + msmc_ram_size = MSMC_RAM_SIZE_SWITCH_MODE; /* NOTE: FW bug needs buffer base to be 64KB aligned */ prueth->msmcram.va = @@ -2112,6 +1771,10 @@ eth0_node->name); goto exit_iep; } + + if (of_find_property(eth0_node, "ti,half-duplex-capable", NULL)) + prueth->emac[PRUETH_MAC0]->half_duplex = 1; + prueth->emac[PRUETH_MAC0]->iep = prueth->iep0; } @@ -2123,11 +1786,20 @@ goto netdev_exit; } + if (of_find_property(eth1_node, "ti,half-duplex-capable", NULL)) + prueth->emac[PRUETH_MAC1]->half_duplex = 1; + prueth->emac[PRUETH_MAC1]->iep = prueth->iep0; } + ret = prueth_register_devlink(prueth); + if (ret) + goto netdev_exit; + /* register the network devices */ if (eth0_node) { + SET_NETDEV_DEVLINK_PORT(prueth->emac[PRUETH_MAC0]->ndev, + &prueth->emac[PRUETH_MAC0]->devlink_port); ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev); if (ret) { dev_err(dev, "can't register netdev for port MII0"); @@ -2141,6 +1813,8 @@ } if (eth1_node) { + SET_NETDEV_DEVLINK_PORT(prueth->emac[PRUETH_MAC1]->ndev, + &prueth->emac[PRUETH_MAC1]->devlink_port); ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev); if (ret) { dev_err(dev, "can't register netdev for port MII1"); @@ -2152,6 +1826,14 @@ phy_attached_info(prueth->emac[PRUETH_MAC1]->ndev->phydev); } + if (prueth->is_switchmode_supported) { + ret = prueth_register_notifiers(prueth); + if (ret) + goto netdev_unregister; + + sprintf(prueth->switch_id, "%s", dev_name(dev)); + } + dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n", (!eth0_node || !eth1_node) ? "single" : "dual"); @@ -2221,6 +1903,8 @@ struct device_node *eth_node; int i; + prueth_unregister_notifiers(prueth); + for (i = 0; i < PRUETH_NUM_MACS; i++) { if (!prueth->registered_netdevs[i]) continue; @@ -2229,6 +1913,7 @@ prueth->emac[i]->ndev->phydev = NULL; unregister_netdev(prueth->registered_netdevs[i]); } + prueth_unregister_devlink(prueth); for (i = 0; i < PRUETH_NUM_MACS; i++) { eth_node = prueth->eth_node[i]; @@ -2259,69 +1944,20 @@ prueth_put_cores(prueth, ICSS_SLICE0); } -#ifdef CONFIG_PM_SLEEP -static int prueth_suspend(struct device *dev) -{ - struct prueth *prueth = dev_get_drvdata(dev); - struct net_device *ndev; - int i, ret; - - for (i = 0; i < PRUETH_NUM_MACS; i++) { - ndev = prueth->registered_netdevs[i]; - - if (!ndev) - continue; - - if (netif_running(ndev)) { - netif_device_detach(ndev); - ret = emac_ndo_stop(ndev); - if (ret < 0) { - netdev_err(ndev, "failed to stop: %d", ret); - return ret; - } - } - } - - return 0; -} - -static int prueth_resume(struct device *dev) -{ - struct prueth *prueth = dev_get_drvdata(dev); - struct net_device *ndev; - int i, ret; - - for (i = 0; i < PRUETH_NUM_MACS; i++) { - ndev = prueth->registered_netdevs[i]; - - if (!ndev) - continue; - - if (netif_running(ndev)) { - ret = emac_ndo_open(ndev); - if (ret < 0) { - netdev_err(ndev, "failed to start: %d", ret); - return ret; - } - netif_device_attach(ndev); - } - } - - return 0; -} -#endif /* CONFIG_PM_SLEEP */ - -static const struct dev_pm_ops prueth_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(prueth_suspend, prueth_resume) -}; - static const struct prueth_pdata am654_icssg_pdata = { .fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE, .quirk_10m_link_issue = 1, + .switch_mode = 1, +}; + +static const struct prueth_pdata am64x_icssg_pdata = { + .fdqring_mode = K3_RINGACC_RING_MODE_RING, + .switch_mode = 1, }; static const struct of_device_id prueth_dt_match[] = { { .compatible = "ti,am654-icssg-prueth", .data = &am654_icssg_pdata }, + { .compatible = "ti,am642-icssg-prueth", .data = &am64x_icssg_pdata }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, prueth_dt_match); diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h 2024-07-07 20:37:34.668306669 -0400 @@ -8,6 +8,8 @@ #ifndef __NET_TI_ICSSG_PRUETH_H #define __NET_TI_ICSSG_PRUETH_H +#include +#include #include #include #include @@ -33,10 +35,13 @@ #include #include +#include +#include #include "icssg_config.h" #include "icss_iep.h" #include "icssg_switch_map.h" +#include "icssg_qos.h" #define PRUETH_MAX_MTU (2000 - ETH_HLEN - ETH_FCS_LEN) #define PRUETH_MIN_PKT_SIZE (VLAN_ETH_ZLEN) @@ -50,10 +55,14 @@ #define ICSSG_MAX_RFLOWS 8 /* per slice */ +#define ICSSG_NUM_PA_STATS 5 +#define ICSSG_NUM_MII_G_RT_STATS 60 /* Number of ICSSG related stats */ -#define ICSSG_NUM_STATS 60 +#define ICSSG_NUM_STATS (ICSSG_NUM_MII_G_RT_STATS + ICSSG_NUM_PA_STATS) #define ICSSG_NUM_STANDARD_STATS 31 -#define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS) +#define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_MII_G_RT_STATS - ICSSG_NUM_STANDARD_STATS) + +#define IEP_DEFAULT_CYCLE_TIME_NS 1000000 /* 1 ms */ /* Firmware status codes */ #define ICSS_HS_FW_READY 0x55555555 @@ -96,6 +105,17 @@ PRUETH_MAC_INVALID, }; +enum prueth_devlink_param_id { + PRUETH_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, + PRUETH_DL_PARAM_SWITCH_MODE, + PRUETH_DL_PARAM_HSR_OFFLOAD_MODE, + PRUETH_DL_PARAM_CUT_THRU_EN, +}; + +struct prueth_devlink { + struct prueth *prueth; +}; + struct prueth_tx_chn { struct device *dma_dev; struct napi_struct napi_tx; @@ -106,6 +126,8 @@ u32 descs_num; unsigned int irq; char name[32]; + struct hrtimer tx_hrtimer; + unsigned long tx_pace_timeout_ns; }; struct prueth_rx_chn { @@ -116,6 +138,29 @@ u32 descs_num; unsigned int irq[ICSSG_MAX_RFLOWS]; /* separate irq per flow */ char name[32]; + struct page_pool *pg_pool; + struct xdp_rxq_info xdp_rxq; +}; + +enum prueth_swdata_type { + PRUETH_SWDATA_INVALID = 0, + PRUETH_SWDATA_SKB, + PRUETH_SWDATA_PAGE, + PRUETH_SWDATA_CMD, + PRUETH_SWDATA_XDPF, +}; + +union prueth_data { + struct sk_buff *skb; + struct page *page; + u32 cmd; + struct xdp_frame *xdpf; +}; + +struct prueth_swdata { + union prueth_data data; + struct prueth_rx_chn *rx_chn; + enum prueth_swdata_type type; }; /* There are 4 Tx DMA channels, but the highest priority is CH3 (thread 3) @@ -125,8 +170,18 @@ #define PRUETH_MAX_TX_TS_REQUESTS 50 /* Max simultaneous TX_TS requests */ +/* XDP BPF state */ +#define ICSSG_XDP_PASS 0 +#define ICSSG_XDP_CONSUMED BIT(0) +#define ICSSG_XDP_TX BIT(1) +#define ICSSG_XDP_REDIR BIT(2) + +/* Minimum coalesce time in usecs for both Tx and Rx */ +#define ICSSG_MIN_COALESCE_USECS 20 + /* data for each emac port */ struct prueth_emac { + bool is_sr1; bool fw_running; struct prueth *prueth; struct net_device *ndev; @@ -145,6 +200,7 @@ struct icss_iep *iep; unsigned int rx_ts_enabled : 1; unsigned int tx_ts_enabled : 1; + unsigned int half_duplex : 1; /* DMA related */ struct prueth_tx_chn tx_chns[PRUETH_MAX_TX_QUEUES]; @@ -154,6 +210,10 @@ int rx_flow_id_base; int tx_ch_num; + /* SR1.0 Management channel */ + struct prueth_rx_chn rx_mgm_chn; + int rx_mgm_flow_id_base; + spinlock_t lock; /* serialize access */ /* TX HW Timestamping */ @@ -164,7 +224,7 @@ u8 cmd_seq; /* shutdown related */ - u32 cmd_data[4]; + __le32 cmd_data[4]; struct completion cmd_complete; /* Mutex to serialize access to firmware command interface */ struct mutex cmd_lock; @@ -173,18 +233,44 @@ struct pruss_mem_region dram; + struct devlink_port devlink_port; + u8 cut_thru_queue_map; + bool offload_fwd_mark; + int port_vlan; + + struct prueth_qos qos; + struct delayed_work stats_work; u64 stats[ICSSG_NUM_STATS]; + + /* RX IRQ Coalescing Related */ + struct hrtimer rx_hrtimer; + unsigned long rx_pace_timeout_ns; + + struct bpf_prog *xdp_prog; + struct xdp_attachment_info xdpi; }; +/* The buf includes headroom compatible with both skb and xdpf */ +#define PRUETH_HEADROOM_NA (max(XDP_PACKET_HEADROOM, NET_SKB_PAD) + NET_IP_ALIGN) +#define PRUETH_HEADROOM ALIGN(PRUETH_HEADROOM_NA, sizeof(long)) + /** * struct prueth_pdata - PRUeth platform data * @fdqring_mode: Free desc queue mode * @quirk_10m_link_issue: 10M link detect errata + * @switch_mode: switch firmware support */ struct prueth_pdata { enum k3_ring_mode fdqring_mode; u32 quirk_10m_link_issue:1; + u32 switch_mode:1; +}; + +struct icssg_firmwares { + char *pru; + char *rtu; + char *txpru; }; /** @@ -209,6 +295,17 @@ * @emacs_initialized: num of EMACs/ext ports that are up/running * @iep0: pointer to IEP0 device * @iep1: pointer to IEP1 device + * @vlan_tbl: VLAN-FID table pointer + * @hw_bridge_dev: pointer to HW bridge net device + * @br_members: bitmask of bridge member ports + * @prueth_netdevice_nb: netdevice notifier block + * @prueth_switchdev_nb: switchdev notifier block + * @prueth_switchdev_bl_nb: switchdev blocking notifier block + * @is_switch_mode: flag to indicate if device is in Switch mode + * @is_switchmode_supported: indicates platform support for switch mode + * @switch_id: ID for mapping switch ports to bridge + * @default_vlan: Default VLAN for host + * @devlink: pointer to devlink */ struct prueth { struct device *dev; @@ -225,6 +322,7 @@ struct net_device *registered_netdevs[PRUETH_NUM_MACS]; struct regmap *miig_rt; struct regmap *mii_rt; + struct regmap *pa_stats; enum pruss_pru_id pru_id[PRUSS_NUM_PRUS]; struct platform_device *pdev; @@ -233,6 +331,18 @@ int emacs_initialized; struct icss_iep *iep0; struct icss_iep *iep1; + struct prueth_vlan_tbl *vlan_tbl; + + struct net_device *hw_bridge_dev; + u8 br_members; + struct notifier_block prueth_netdevice_nb; + struct notifier_block prueth_switchdev_nb; + struct notifier_block prueth_switchdev_bl_nb; + bool is_switch_mode; + bool is_switchmode_supported; + unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN]; + int default_vlan; + struct devlink *devlink; }; struct emac_tx_ts_response { @@ -242,6 +352,13 @@ u32 hi_ts; }; +struct emac_tx_ts_response_sr1 { + __le32 lo_ts; + __le32 hi_ts; + __le32 reserved; + __le32 cookie; +}; + /* get PRUSS SLICE number from prueth_emac */ static inline int prueth_emac_slice(struct prueth_emac *emac) { @@ -256,12 +373,17 @@ } extern const struct ethtool_ops icssg_ethtool_ops; +extern const struct dev_pm_ops prueth_dev_pm_ops; /* Classifier helpers */ void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac); void icssg_class_set_host_mac_addr(struct regmap *miig_rt, const u8 *mac); void icssg_class_disable(struct regmap *miig_rt, int slice); -void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti); +void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti, + bool is_sr1); +void icssg_class_promiscuous_sr1(struct regmap *miig_rt, int slice); +void icssg_class_add_mcast_sr1(struct regmap *miig_rt, int slice, + struct net_device *ndev); void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr); /* config helpers */ @@ -271,16 +393,84 @@ int emac_set_port_state(struct prueth_emac *emac, enum icssg_port_state_cmd state); void icssg_config_set_speed(struct prueth_emac *emac); +void icssg_config_half_duplex(struct prueth_emac *emac); /* Buffer queue helpers */ int icssg_queue_pop(struct prueth *prueth, u8 queue); void icssg_queue_push(struct prueth *prueth, int queue, u16 addr); u32 icssg_queue_level(struct prueth *prueth, int queue); +int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd, + struct mgmt_cmd_rsp *rsp); +int icssg_fdb_add_del(struct prueth_emac *emac, const unsigned char *addr, + u8 vid, u8 fid_c2, bool add); +int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr, + u8 vid); +void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask, + u8 untag_mask, bool add); +u16 icssg_get_pvid(struct prueth_emac *emac); +void icssg_set_pvid(struct prueth *prueth, u8 vid, u8 port); +int emac_fdb_flow_id_updated(struct prueth_emac *emac); #define prueth_napi_to_tx_chn(pnapi) \ container_of(pnapi, struct prueth_tx_chn, napi_tx) void emac_stats_work_handler(struct work_struct *work); void emac_update_hardware_stats(struct prueth_emac *emac); int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name); + +u64 prueth_iep_gettime(void *clockops_data, struct ptp_system_timestamp *sts); + +/* Common functions */ +void prueth_cleanup_rx_chns(struct prueth_emac *emac, + struct prueth_rx_chn *rx_chn, + int max_rflows); +void prueth_cleanup_tx_chns(struct prueth_emac *emac); +void prueth_ndev_del_tx_napi(struct prueth_emac *emac, int num); +void prueth_xmit_free(struct prueth_tx_chn *tx_chn, + struct cppi5_host_desc_t *desc); +int emac_tx_complete_packets(struct prueth_emac *emac, int chn, + int budget, bool *tdown); +int prueth_ndev_add_tx_napi(struct prueth_emac *emac); +int prueth_init_tx_chns(struct prueth_emac *emac); +int prueth_init_rx_chns(struct prueth_emac *emac, + struct prueth_rx_chn *rx_chn, + char *name, u32 max_rflows, + u32 max_desc_num); +int prueth_dma_rx_push(struct prueth_emac *emac, + struct sk_buff *skb, + struct prueth_rx_chn *rx_chn); +void emac_rx_timestamp(struct prueth_emac *emac, + struct sk_buff *skb, u32 *psdata); +enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev); +irqreturn_t prueth_rx_irq(int irq, void *dev_id); +void prueth_emac_stop(struct prueth_emac *emac); +void prueth_cleanup_tx_ts(struct prueth_emac *emac); +int emac_napi_rx_poll(struct napi_struct *napi_rx, int budget); +int prueth_prepare_rx_chan(struct prueth_emac *emac, + struct prueth_rx_chn *chn, + int buf_size); +void prueth_reset_tx_chan(struct prueth_emac *emac, int ch_num, + bool free_skb); +void prueth_reset_rx_chan(struct prueth_rx_chn *chn, + int num_flows, bool disable); +void emac_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue); +int emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd); +void emac_ndo_get_stats64(struct net_device *ndev, + struct rtnl_link_stats64 *stats); +int emac_ndo_get_phys_port_name(struct net_device *ndev, char *name, + size_t len); +int prueth_node_port(struct device_node *eth_node); +int prueth_node_mac(struct device_node *eth_node); +void prueth_netdev_exit(struct prueth *prueth, + struct device_node *eth_node); +int prueth_get_cores(struct prueth *prueth, int slice, bool is_sr1); +void prueth_put_cores(struct prueth *prueth, int slice); + +/* Revision specific helper */ +u64 icssg_ts_to_ns(u32 hi_sw, u32 hi, u32 lo, u32 cycle_time_ns); + +/* XDP Related helpers */ +int emac_run_xdp(struct prueth_emac *emac, struct xdp_buff *xdp, + struct page *page); + #endif /* __NET_TI_ICSSG_PRUETH_H */ diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c b/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c --- a/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,1181 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* Texas Instruments ICSSG SR1.0 Ethernet Driver + * + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (c) Siemens AG, 2024 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "icssg_prueth.h" +#include "icssg_mii_rt.h" +#include "../k3-cppi-desc-pool.h" + +#define PRUETH_MODULE_DESCRIPTION "PRUSS ICSSG SR1.0 Ethernet driver" + +/* SR1: Set buffer sizes for the pools. There are 8 internal queues + * implemented in firmware, but only 4 tx channels/threads in the Egress + * direction to firmware. Need a high priority queue for management + * messages since they shouldn't be blocked even during high traffic + * situation. So use Q0-Q2 as data queues and Q3 as management queue + * in the max case. However for ease of configuration, use the max + * data queue + 1 for management message if we are not using max + * case. + * + * Allocate 4 MTU buffers per data queue. Firmware requires + * pool sizes to be set for internal queues. Set the upper 5 queue + * pool size to min size of 128 bytes since there are only 3 tx + * data channels and management queue requires only minimum buffer. + * i.e lower queues are used by driver and highest priority queue + * from that is used for management message. + */ + +static int emac_egress_buf_pool_size[] = { + PRUETH_EMAC_BUF_POOL_SIZE_SR1, PRUETH_EMAC_BUF_POOL_SIZE_SR1, + PRUETH_EMAC_BUF_POOL_SIZE_SR1, PRUETH_EMAC_BUF_POOL_MIN_SIZE_SR1, + PRUETH_EMAC_BUF_POOL_MIN_SIZE_SR1, PRUETH_EMAC_BUF_POOL_MIN_SIZE_SR1, + PRUETH_EMAC_BUF_POOL_MIN_SIZE_SR1, PRUETH_EMAC_BUF_POOL_MIN_SIZE_SR1 +}; + +static void icssg_config_sr1(struct prueth *prueth, struct prueth_emac *emac, + int slice) +{ + struct icssg_sr1_config config; + void __iomem *va; + int i, index; + + memset(&config, 0, sizeof(config)); + config.addr_lo = cpu_to_le32(lower_32_bits(prueth->msmcram.pa)); + config.addr_hi = cpu_to_le32(upper_32_bits(prueth->msmcram.pa)); + config.rx_flow_id = cpu_to_le32(emac->rx_flow_id_base); /* flow id for host port */ + config.rx_mgr_flow_id = cpu_to_le32(emac->rx_mgm_flow_id_base); /* for mgm ch */ + config.rand_seed = cpu_to_le32(get_random_u32()); + + for (i = PRUETH_EMAC_BUF_POOL_START_SR1; i < PRUETH_NUM_BUF_POOLS_SR1; i++) { + index = i - PRUETH_EMAC_BUF_POOL_START_SR1; + config.tx_buf_sz[i] = cpu_to_le32(emac_egress_buf_pool_size[index]); + } + + va = prueth->shram.va + slice * ICSSG_CONFIG_OFFSET_SLICE1; + memcpy_toio(va, &config, sizeof(config)); + + emac->speed = SPEED_1000; + emac->duplex = DUPLEX_FULL; +} + +static int emac_send_command_sr1(struct prueth_emac *emac, u32 cmd) +{ + struct cppi5_host_desc_t *first_desc; + u32 pkt_len = sizeof(emac->cmd_data); + __le32 *data = emac->cmd_data; + dma_addr_t desc_dma, buf_dma; + struct prueth_tx_chn *tx_chn; + void **swdata; + int ret = 0; + u32 *epib; + + netdev_dbg(emac->ndev, "Sending cmd %x\n", cmd); + + /* only one command at a time allowed to firmware */ + mutex_lock(&emac->cmd_lock); + data[0] = cpu_to_le32(cmd); + + /* highest priority channel for management messages */ + tx_chn = &emac->tx_chns[emac->tx_ch_num - 1]; + + /* Map the linear buffer */ + buf_dma = dma_map_single(tx_chn->dma_dev, data, pkt_len, DMA_TO_DEVICE); + if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) { + netdev_err(emac->ndev, "cmd %x: failed to map cmd buffer\n", cmd); + ret = -EINVAL; + goto err_unlock; + } + + first_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool); + if (!first_desc) { + netdev_err(emac->ndev, "cmd %x: failed to allocate descriptor\n", cmd); + dma_unmap_single(tx_chn->dma_dev, buf_dma, pkt_len, DMA_TO_DEVICE); + ret = -ENOMEM; + goto err_unlock; + } + + cppi5_hdesc_init(first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT, + PRUETH_NAV_PS_DATA_SIZE); + cppi5_hdesc_set_pkttype(first_desc, PRUETH_PKT_TYPE_CMD); + epib = first_desc->epib; + epib[0] = 0; + epib[1] = 0; + + cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len); + swdata = cppi5_hdesc_get_swdata(first_desc); + *swdata = data; + + cppi5_hdesc_set_pktlen(first_desc, pkt_len); + desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, first_desc); + + /* send command */ + reinit_completion(&emac->cmd_complete); + ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma); + if (ret) { + netdev_err(emac->ndev, "cmd %x: push failed: %d\n", cmd, ret); + goto free_desc; + } + ret = wait_for_completion_timeout(&emac->cmd_complete, msecs_to_jiffies(100)); + if (!ret) + netdev_err(emac->ndev, "cmd %x: completion timeout\n", cmd); + + mutex_unlock(&emac->cmd_lock); + + return ret; +free_desc: + prueth_xmit_free(tx_chn, first_desc); +err_unlock: + mutex_unlock(&emac->cmd_lock); + + return ret; +} + +static void icssg_config_set_speed_sr1(struct prueth_emac *emac) +{ + u32 cmd = ICSSG_PSTATE_SPEED_DUPLEX_CMD_SR1, val; + struct prueth *prueth = emac->prueth; + int slice = prueth_emac_slice(emac); + + val = icssg_rgmii_get_speed(prueth->miig_rt, slice); + /* firmware expects speed settings in bit 2-1 */ + val <<= 1; + cmd |= val; + + val = icssg_rgmii_get_fullduplex(prueth->miig_rt, slice); + /* firmware expects full duplex settings in bit 3 */ + val <<= 3; + cmd |= val; + + emac_send_command_sr1(emac, cmd); +} + +/* called back by PHY layer if there is change in link state of hw port*/ +static void emac_adjust_link_sr1(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct phy_device *phydev = ndev->phydev; + struct prueth *prueth = emac->prueth; + bool new_state = false; + unsigned long flags; + + if (phydev->link) { + /* check the mode of operation - full/half duplex */ + if (phydev->duplex != emac->duplex) { + new_state = true; + emac->duplex = phydev->duplex; + } + if (phydev->speed != emac->speed) { + new_state = true; + emac->speed = phydev->speed; + } + if (!emac->link) { + new_state = true; + emac->link = 1; + } + } else if (emac->link) { + new_state = true; + emac->link = 0; + + /* f/w should support 100 & 1000 */ + emac->speed = SPEED_1000; + + /* half duplex may not be supported by f/w */ + emac->duplex = DUPLEX_FULL; + } + + if (new_state) { + phy_print_status(phydev); + + /* update RGMII and MII configuration based on PHY negotiated + * values + */ + if (emac->link) { + /* Set the RGMII cfg for gig en and full duplex */ + icssg_update_rgmii_cfg(prueth->miig_rt, emac); + + /* update the Tx IPG based on 100M/1G speed */ + spin_lock_irqsave(&emac->lock, flags); + icssg_config_ipg(emac); + spin_unlock_irqrestore(&emac->lock, flags); + icssg_config_set_speed_sr1(emac); + } + } + + if (emac->link) { + /* reactivate the transmit queue */ + netif_tx_wake_all_queues(ndev); + } else { + netif_tx_stop_all_queues(ndev); + prueth_cleanup_tx_ts(emac); + } +} + +static int emac_phy_connect(struct prueth_emac *emac) +{ + struct prueth *prueth = emac->prueth; + struct net_device *ndev = emac->ndev; + /* connect PHY */ + ndev->phydev = of_phy_connect(emac->ndev, emac->phy_node, + &emac_adjust_link_sr1, 0, + emac->phy_if); + if (!ndev->phydev) { + dev_err(prueth->dev, "couldn't connect to phy %s\n", + emac->phy_node->full_name); + return -ENODEV; + } + + if (!emac->half_duplex) { + dev_dbg(prueth->dev, "half duplex mode is not supported\n"); + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); + } + + /* Remove 100Mbits half-duplex due to RGMII misreporting connection + * as full duplex */ + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); + + /* remove unsupported modes */ + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Pause_BIT); + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT); + + if (emac->phy_if == PHY_INTERFACE_MODE_MII) + phy_set_max_speed(ndev->phydev, SPEED_100); + + return 0; +} + +/* get one packet from requested flow_id + * + * Returns skb pointer if packet found else NULL + * Caller must free the returned skb. + */ +static struct sk_buff *prueth_process_rx_mgm(struct prueth_emac *emac, + u32 flow_id) +{ + struct prueth_rx_chn *rx_chn = &emac->rx_mgm_chn; + struct net_device *ndev = emac->ndev; + struct cppi5_host_desc_t *desc_rx; + struct sk_buff *skb, *new_skb; + dma_addr_t desc_dma, buf_dma; + u32 buf_dma_len, pkt_len; + void **swdata; + int ret; + + ret = k3_udma_glue_pop_rx_chn(rx_chn->rx_chn, flow_id, &desc_dma); + if (ret) { + if (ret != -ENODATA) + netdev_err(ndev, "rx mgm pop: failed: %d\n", ret); + return NULL; + } + + if (cppi5_desc_is_tdcm(desc_dma)) /* Teardown */ + return NULL; + + desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); + + /* Fix FW bug about incorrect PSDATA size */ + if (cppi5_hdesc_get_psdata_size(desc_rx) != PRUETH_NAV_PS_DATA_SIZE) { + cppi5_hdesc_update_psdata_size(desc_rx, + PRUETH_NAV_PS_DATA_SIZE); + } + + swdata = cppi5_hdesc_get_swdata(desc_rx); + skb = *swdata; + cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); + pkt_len = cppi5_hdesc_get_pktlen(desc_rx); + + dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE); + k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); + + new_skb = netdev_alloc_skb_ip_align(ndev, PRUETH_MAX_PKT_SIZE); + /* if allocation fails we drop the packet but push the + * descriptor back to the ring with old skb to prevent a stall + */ + if (!new_skb) { + netdev_err(ndev, + "skb alloc failed, dropped mgm pkt from flow %d\n", + flow_id); + new_skb = skb; + skb = NULL; /* return NULL */ + } else { + /* return the filled skb */ + skb_put(skb, pkt_len); + } + + /* queue another DMA */ + ret = prueth_dma_rx_push(emac, new_skb, &emac->rx_mgm_chn); + if (WARN_ON(ret < 0)) + dev_kfree_skb_any(new_skb); + + return skb; +} + +static void prueth_tx_ts_sr1(struct prueth_emac *emac, + struct emac_tx_ts_response_sr1 *tsr) +{ + struct skb_shared_hwtstamps ssh; + u32 hi_ts, lo_ts, cookie; + struct sk_buff *skb; + u64 ns; + + hi_ts = le32_to_cpu(tsr->hi_ts); + lo_ts = le32_to_cpu(tsr->lo_ts); + + ns = (u64)hi_ts << 32 | lo_ts; + + cookie = le32_to_cpu(tsr->cookie); + if (cookie >= PRUETH_MAX_TX_TS_REQUESTS) { + netdev_dbg(emac->ndev, "Invalid TX TS cookie 0x%x\n", + cookie); + return; + } + + skb = emac->tx_ts_skb[cookie]; + emac->tx_ts_skb[cookie] = NULL; /* free slot */ + + memset(&ssh, 0, sizeof(ssh)); + ssh.hwtstamp = ns_to_ktime(ns); + + skb_tstamp_tx(skb, &ssh); + dev_consume_skb_any(skb); +} + +static irqreturn_t prueth_rx_mgm_ts_thread_sr1(int irq, void *dev_id) +{ + struct prueth_emac *emac = dev_id; + struct sk_buff *skb; + + skb = prueth_process_rx_mgm(emac, PRUETH_RX_MGM_FLOW_TIMESTAMP_SR1); + if (!skb) + return IRQ_NONE; + + prueth_tx_ts_sr1(emac, (void *)skb->data); + dev_kfree_skb_any(skb); + + return IRQ_HANDLED; +} + +static irqreturn_t prueth_rx_mgm_rsp_thread(int irq, void *dev_id) +{ + struct prueth_emac *emac = dev_id; + struct sk_buff *skb; + u32 rsp; + + skb = prueth_process_rx_mgm(emac, PRUETH_RX_MGM_FLOW_RESPONSE_SR1); + if (!skb) + return IRQ_NONE; + + /* Process command response */ + rsp = le32_to_cpu(*(__le32 *)skb->data) & 0xffff0000; + if (rsp == ICSSG_SHUTDOWN_CMD_SR1) { + netdev_dbg(emac->ndev, "f/w Shutdown cmd resp %x\n", rsp); + complete(&emac->cmd_complete); + } else if (rsp == ICSSG_PSTATE_SPEED_DUPLEX_CMD_SR1) { + netdev_dbg(emac->ndev, "f/w Speed/Duplex cmd rsp %x\n", rsp); + complete(&emac->cmd_complete); + } + + dev_kfree_skb_any(skb); + + return IRQ_HANDLED; +} + +static struct icssg_firmwares icssg_sr1_emac_firmwares[] = { + { + .pru = "ti-pruss/am65x-pru0-prueth-fw.elf", + .rtu = "ti-pruss/am65x-rtu0-prueth-fw.elf", + }, + { + .pru = "ti-pruss/am65x-pru1-prueth-fw.elf", + .rtu = "ti-pruss/am65x-rtu1-prueth-fw.elf", + } +}; + +static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac) +{ + struct icssg_firmwares *firmwares; + struct device *dev = prueth->dev; + int slice, ret; + + firmwares = icssg_sr1_emac_firmwares; + + slice = prueth_emac_slice(emac); + if (slice < 0) { + netdev_err(emac->ndev, "invalid port\n"); + return -EINVAL; + } + + icssg_config_sr1(prueth, emac, slice); + + ret = rproc_set_firmware(prueth->pru[slice], firmwares[slice].pru); + ret = rproc_boot(prueth->pru[slice]); + if (ret) { + dev_err(dev, "failed to boot PRU%d: %d\n", slice, ret); + return -EINVAL; + } + + ret = rproc_set_firmware(prueth->rtu[slice], firmwares[slice].rtu); + ret = rproc_boot(prueth->rtu[slice]); + if (ret) { + dev_err(dev, "failed to boot RTU%d: %d\n", slice, ret); + goto halt_pru; + } + + emac->fw_running = 1; + return 0; + +halt_pru: + rproc_shutdown(prueth->pru[slice]); + + return ret; +} + +/** + * emac_ndo_open - EMAC device open + * @ndev: network adapter device + * + * Called when system wants to start the interface. + * + * Return: 0 for a successful open, or appropriate error code + */ +static int emac_ndo_open(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + int num_data_chn = emac->tx_ch_num - 1; + struct prueth *prueth = emac->prueth; + int slice = prueth_emac_slice(emac); + struct device *dev = prueth->dev; + int max_rx_flows, rx_flow; + int ret, i; + + /* clear SMEM and MSMC settings for all slices */ + if (!prueth->emacs_initialized) { + memset_io(prueth->msmcram.va, 0, prueth->msmcram.size); + memset_io(prueth->shram.va, 0, ICSSG_CONFIG_OFFSET_SLICE1 * PRUETH_NUM_MACS); + } + + /* set h/w MAC as user might have re-configured */ + ether_addr_copy(emac->mac_addr, ndev->dev_addr); + + icssg_class_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr); + + icssg_class_default(prueth->miig_rt, slice, 0, true); + + /* Notify the stack of the actual queue counts. */ + ret = netif_set_real_num_tx_queues(ndev, num_data_chn); + if (ret) { + dev_err(dev, "cannot set real number of tx queues\n"); + return ret; + } + + init_completion(&emac->cmd_complete); + ret = prueth_init_tx_chns(emac); + if (ret) { + dev_err(dev, "failed to init tx channel: %d\n", ret); + return ret; + } + + max_rx_flows = PRUETH_MAX_RX_FLOWS_SR1; + ret = prueth_init_rx_chns(emac, &emac->rx_chns, "rx", + max_rx_flows, PRUETH_MAX_RX_DESC); + if (ret) { + dev_err(dev, "failed to init rx channel: %d\n", ret); + goto cleanup_tx; + } + + ret = prueth_init_rx_chns(emac, &emac->rx_mgm_chn, "rxmgm", + PRUETH_MAX_RX_MGM_FLOWS_SR1, + PRUETH_MAX_RX_MGM_DESC_SR1); + if (ret) { + dev_err(dev, "failed to init rx mgmt channel: %d\n", + ret); + goto cleanup_rx; + } + + ret = prueth_ndev_add_tx_napi(emac); + if (ret) + goto cleanup_rx_mgm; + + /* we use only the highest priority flow for now i.e. @irq[3] */ + rx_flow = PRUETH_RX_FLOW_DATA_SR1; + ret = request_irq(emac->rx_chns.irq[rx_flow], prueth_rx_irq, + IRQF_TRIGGER_HIGH, dev_name(dev), emac); + if (ret) { + dev_err(dev, "unable to request RX IRQ\n"); + goto cleanup_napi; + } + + ret = request_threaded_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_RESPONSE_SR1], + NULL, prueth_rx_mgm_rsp_thread, + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + dev_name(dev), emac); + if (ret) { + dev_err(dev, "unable to request RX Management RSP IRQ\n"); + goto free_rx_irq; + } + + ret = request_threaded_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_TIMESTAMP_SR1], + NULL, prueth_rx_mgm_ts_thread_sr1, + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + dev_name(dev), emac); + if (ret) { + dev_err(dev, "unable to request RX Management TS IRQ\n"); + goto free_rx_mgm_rsp_irq; + } + + /* reset and start PRU firmware */ + ret = prueth_emac_start(prueth, emac); + if (ret) + goto free_rx_mgmt_ts_irq; + + icssg_mii_update_mtu(prueth->mii_rt, slice, ndev->max_mtu); + + /* Prepare RX */ + ret = prueth_prepare_rx_chan(emac, &emac->rx_chns, PRUETH_MAX_PKT_SIZE); + if (ret) + goto stop; + + ret = prueth_prepare_rx_chan(emac, &emac->rx_mgm_chn, 64); + if (ret) + goto reset_rx_chn; + + ret = k3_udma_glue_enable_rx_chn(emac->rx_mgm_chn.rx_chn); + if (ret) + goto reset_rx_chn; + + ret = k3_udma_glue_enable_rx_chn(emac->rx_chns.rx_chn); + if (ret) + goto reset_rx_mgm_chn; + + for (i = 0; i < emac->tx_ch_num; i++) { + ret = k3_udma_glue_enable_tx_chn(emac->tx_chns[i].tx_chn); + if (ret) + goto reset_tx_chan; + } + + /* Enable NAPI in Tx and Rx direction */ + for (i = 0; i < emac->tx_ch_num; i++) + napi_enable(&emac->tx_chns[i].napi_tx); + napi_enable(&emac->napi_rx); + + /* start PHY */ + phy_start(ndev->phydev); + + prueth->emacs_initialized++; + + queue_work(system_long_wq, &emac->stats_work.work); + + return 0; + +reset_tx_chan: + /* Since interface is not yet up, there is wouldn't be + * any SKB for completion. So set false to free_skb + */ + prueth_reset_tx_chan(emac, i, false); +reset_rx_mgm_chn: + prueth_reset_rx_chan(&emac->rx_mgm_chn, + PRUETH_MAX_RX_MGM_FLOWS_SR1, true); +reset_rx_chn: + prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, false); +stop: + prueth_emac_stop(emac); +free_rx_mgmt_ts_irq: + free_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_TIMESTAMP_SR1], + emac); +free_rx_mgm_rsp_irq: + free_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_RESPONSE_SR1], + emac); +free_rx_irq: + free_irq(emac->rx_chns.irq[rx_flow], emac); +cleanup_napi: + prueth_ndev_del_tx_napi(emac, emac->tx_ch_num); +cleanup_rx_mgm: + prueth_cleanup_rx_chns(emac, &emac->rx_mgm_chn, + PRUETH_MAX_RX_MGM_FLOWS_SR1); +cleanup_rx: + prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows); +cleanup_tx: + prueth_cleanup_tx_chns(emac); + + return ret; +} + +/** + * emac_ndo_stop - EMAC device stop + * @ndev: network adapter device + * + * Called when system wants to stop or down the interface. + * + * Return: Always 0 (Success) + */ +static int emac_ndo_stop(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + int rx_flow = PRUETH_RX_FLOW_DATA_SR1; + struct prueth *prueth = emac->prueth; + int max_rx_flows; + int ret, i; + + /* inform the upper layers. */ + netif_tx_stop_all_queues(ndev); + + /* block packets from wire */ + if (ndev->phydev) + phy_stop(ndev->phydev); + + icssg_class_disable(prueth->miig_rt, prueth_emac_slice(emac)); + + emac_send_command_sr1(emac, ICSSG_SHUTDOWN_CMD_SR1); + + atomic_set(&emac->tdown_cnt, emac->tx_ch_num); + /* ensure new tdown_cnt value is visible */ + smp_mb__after_atomic(); + /* tear down and disable UDMA channels */ + reinit_completion(&emac->tdown_complete); + for (i = 0; i < emac->tx_ch_num; i++) + k3_udma_glue_tdown_tx_chn(emac->tx_chns[i].tx_chn, false); + + ret = wait_for_completion_timeout(&emac->tdown_complete, + msecs_to_jiffies(1000)); + if (!ret) + netdev_err(ndev, "tx teardown timeout\n"); + + prueth_reset_tx_chan(emac, emac->tx_ch_num, true); + for (i = 0; i < emac->tx_ch_num; i++) + napi_disable(&emac->tx_chns[i].napi_tx); + + max_rx_flows = PRUETH_MAX_RX_FLOWS_SR1; + k3_udma_glue_tdown_rx_chn(emac->rx_chns.rx_chn, true); + + prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, true); + /* Teardown RX MGM channel */ + k3_udma_glue_tdown_rx_chn(emac->rx_mgm_chn.rx_chn, true); + prueth_reset_rx_chan(&emac->rx_mgm_chn, + PRUETH_MAX_RX_MGM_FLOWS_SR1, true); + + napi_disable(&emac->napi_rx); + + /* Destroying the queued work in ndo_stop() */ + cancel_delayed_work_sync(&emac->stats_work); + + /* stop PRUs */ + prueth_emac_stop(emac); + + free_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_TIMESTAMP_SR1], emac); + free_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_RESPONSE_SR1], emac); + free_irq(emac->rx_chns.irq[rx_flow], emac); + prueth_ndev_del_tx_napi(emac, emac->tx_ch_num); + prueth_cleanup_tx_chns(emac); + + prueth_cleanup_rx_chns(emac, &emac->rx_mgm_chn, PRUETH_MAX_RX_MGM_FLOWS_SR1); + prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows); + + prueth->emacs_initialized--; + + return 0; +} + +static void emac_ndo_set_rx_mode_sr1(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + bool allmulti = ndev->flags & IFF_ALLMULTI; + bool promisc = ndev->flags & IFF_PROMISC; + struct prueth *prueth = emac->prueth; + int slice = prueth_emac_slice(emac); + + if (promisc) { + icssg_class_promiscuous_sr1(prueth->miig_rt, slice); + return; + } + + if (allmulti) { + icssg_class_default(prueth->miig_rt, slice, 1, true); + return; + } + + icssg_class_default(prueth->miig_rt, slice, 0, true); + if (!netdev_mc_empty(ndev)) { + /* program multicast address list into Classifier */ + icssg_class_add_mcast_sr1(prueth->miig_rt, slice, ndev); + } +} + +static const struct net_device_ops emac_netdev_ops = { + .ndo_open = emac_ndo_open, + .ndo_stop = emac_ndo_stop, + .ndo_start_xmit = emac_ndo_start_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = emac_ndo_tx_timeout, + .ndo_set_rx_mode = emac_ndo_set_rx_mode_sr1, + .ndo_eth_ioctl = emac_ndo_ioctl, + .ndo_get_stats64 = emac_ndo_get_stats64, + .ndo_get_phys_port_name = emac_ndo_get_phys_port_name, +}; + +static int prueth_netdev_init(struct prueth *prueth, + struct device_node *eth_node) +{ + struct prueth_emac *emac; + struct net_device *ndev; + enum prueth_port port; + enum prueth_mac mac; + /* Only enable one TX channel due to timeouts when + * using multiple channels */ + int num_tx_chn = 1; + int ret; + + port = prueth_node_port(eth_node); + if (port == PRUETH_PORT_INVALID) + return -EINVAL; + + mac = prueth_node_mac(eth_node); + if (mac == PRUETH_MAC_INVALID) + return -EINVAL; + + ndev = alloc_etherdev_mq(sizeof(*emac), num_tx_chn); + if (!ndev) + return -ENOMEM; + + emac = netdev_priv(ndev); + emac->is_sr1 = 1; + emac->prueth = prueth; + emac->ndev = ndev; + emac->port_id = port; + emac->cmd_wq = create_singlethread_workqueue("icssg_cmd_wq"); + if (!emac->cmd_wq) { + ret = -ENOMEM; + goto free_ndev; + } + + INIT_DELAYED_WORK(&emac->stats_work, emac_stats_work_handler); + + ret = pruss_request_mem_region(prueth->pruss, + port == PRUETH_PORT_MII0 ? + PRUSS_MEM_DRAM0 : PRUSS_MEM_DRAM1, + &emac->dram); + if (ret) { + dev_err(prueth->dev, "unable to get DRAM: %d\n", ret); + ret = -ENOMEM; + goto free_wq; + } + + /* SR1.0 uses a dedicated high priority channel + * to send commands to the firmware + */ + emac->tx_ch_num = 2; + + SET_NETDEV_DEV(ndev, prueth->dev); + spin_lock_init(&emac->lock); + mutex_init(&emac->cmd_lock); + + emac->phy_node = of_parse_phandle(eth_node, "phy-handle", 0); + if (!emac->phy_node && !of_phy_is_fixed_link(eth_node)) { + dev_err(prueth->dev, "couldn't find phy-handle\n"); + ret = -ENODEV; + goto free; + } else if (of_phy_is_fixed_link(eth_node)) { + ret = of_phy_register_fixed_link(eth_node); + if (ret) { + ret = dev_err_probe(prueth->dev, ret, + "failed to register fixed-link phy\n"); + goto free; + } + + emac->phy_node = eth_node; + } + + ret = of_get_phy_mode(eth_node, &emac->phy_if); + if (ret) { + dev_err(prueth->dev, "could not get phy-mode property\n"); + goto free; + } + + if (emac->phy_if != PHY_INTERFACE_MODE_MII && + !phy_interface_mode_is_rgmii(emac->phy_if)) { + dev_err(prueth->dev, "PHY mode unsupported %s\n", phy_modes(emac->phy_if)); + ret = -EINVAL; + goto free; + } + + /* AM65 SR2.0 has TX Internal delay always enabled by hardware + * and it is not possible to disable TX Internal delay. The below + * switch case block describes how we handle different phy modes + * based on hardware restriction. + */ + switch (emac->phy_if) { + case PHY_INTERFACE_MODE_RGMII_ID: + emac->phy_if = PHY_INTERFACE_MODE_RGMII_RXID; + break; + case PHY_INTERFACE_MODE_RGMII_TXID: + emac->phy_if = PHY_INTERFACE_MODE_RGMII; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_RXID: + dev_err(prueth->dev, "RGMII mode without TX delay is not supported"); + ret = -EINVAL; + goto free; + default: + break; + } + + /* get mac address from DT and set private and netdev addr */ + ret = of_get_ethdev_address(eth_node, ndev); + if (!is_valid_ether_addr(ndev->dev_addr)) { + eth_hw_addr_random(ndev); + dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n", + port, ndev->dev_addr); + } + ether_addr_copy(emac->mac_addr, ndev->dev_addr); + + ndev->min_mtu = PRUETH_MIN_PKT_SIZE; + ndev->max_mtu = PRUETH_MAX_MTU; + ndev->netdev_ops = &emac_netdev_ops; + ndev->ethtool_ops = &icssg_ethtool_ops; + ndev->hw_features = NETIF_F_SG; + ndev->features = ndev->hw_features; + + netif_napi_add(ndev, &emac->napi_rx, emac_napi_rx_poll); + prueth->emac[mac] = emac; + + return 0; + +free: + pruss_release_mem_region(prueth->pruss, &emac->dram); +free_wq: + destroy_workqueue(emac->cmd_wq); +free_ndev: + emac->ndev = NULL; + prueth->emac[mac] = NULL; + free_netdev(ndev); + + return ret; +} + +static int prueth_probe(struct platform_device *pdev) +{ + struct device_node *eth_node, *eth_ports_node; + struct device_node *eth0_node = NULL; + struct device_node *eth1_node = NULL; + struct device *dev = &pdev->dev; + struct device_node *np; + struct prueth *prueth; + struct pruss *pruss; + u32 msmc_ram_size; + int i, ret; + + np = dev->of_node; + + prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL); + if (!prueth) + return -ENOMEM; + + dev_set_drvdata(dev, prueth); + prueth->pdev = pdev; + prueth->pdata = *(const struct prueth_pdata *)device_get_match_data(dev); + + prueth->dev = dev; + eth_ports_node = of_get_child_by_name(np, "ethernet-ports"); + if (!eth_ports_node) + return -ENOENT; + + for_each_child_of_node(eth_ports_node, eth_node) { + u32 reg; + + if (strcmp(eth_node->name, "port")) + continue; + ret = of_property_read_u32(eth_node, "reg", ®); + if (ret < 0) { + dev_err(dev, "%pOF error reading port_id %d\n", + eth_node, ret); + } + + of_node_get(eth_node); + + if (reg == 0) { + eth0_node = eth_node; + if (!of_device_is_available(eth0_node)) { + of_node_put(eth0_node); + eth0_node = NULL; + } + } else if (reg == 1) { + eth1_node = eth_node; + if (!of_device_is_available(eth1_node)) { + of_node_put(eth1_node); + eth1_node = NULL; + } + } else { + dev_err(dev, "port reg should be 0 or 1\n"); + } + } + + of_node_put(eth_ports_node); + + /* At least one node must be present and available else we fail */ + if (!eth0_node && !eth1_node) { + dev_err(dev, "neither port0 nor port1 node available\n"); + return -ENODEV; + } + + if (eth0_node == eth1_node) { + dev_err(dev, "port0 and port1 can't have same reg\n"); + of_node_put(eth0_node); + return -ENODEV; + } + + prueth->eth_node[PRUETH_MAC0] = eth0_node; + prueth->eth_node[PRUETH_MAC1] = eth1_node; + + prueth->miig_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-g-rt"); + if (IS_ERR(prueth->miig_rt)) { + dev_err(dev, "couldn't get ti,mii-g-rt syscon regmap\n"); + return -ENODEV; + } + + prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-rt"); + if (IS_ERR(prueth->mii_rt)) { + dev_err(dev, "couldn't get ti,mii-rt syscon regmap\n"); + return -ENODEV; + } + + if (eth0_node) { + ret = prueth_get_cores(prueth, ICSS_SLICE0, true); + if (ret) + goto put_cores; + } + + if (eth1_node) { + ret = prueth_get_cores(prueth, ICSS_SLICE1, true); + if (ret) + goto put_cores; + } + + pruss = pruss_get(eth0_node ? + prueth->pru[ICSS_SLICE0] : prueth->pru[ICSS_SLICE1]); + if (IS_ERR(pruss)) { + ret = PTR_ERR(pruss); + dev_err(dev, "unable to get pruss handle\n"); + goto put_cores; + } + + prueth->pruss = pruss; + + ret = pruss_request_mem_region(pruss, PRUSS_MEM_SHRD_RAM2, + &prueth->shram); + if (ret) { + dev_err(dev, "unable to get PRUSS SHRD RAM2: %d\n", ret); + goto put_pruss; + } + + prueth->sram_pool = of_gen_pool_get(np, "sram", 0); + if (!prueth->sram_pool) { + dev_err(dev, "unable to get SRAM pool\n"); + ret = -ENODEV; + + goto put_mem; + } + + msmc_ram_size = MSMC_RAM_SIZE_SR1; + + prueth->msmcram.va = (void __iomem *)gen_pool_alloc(prueth->sram_pool, + msmc_ram_size); + + if (!prueth->msmcram.va) { + ret = -ENOMEM; + dev_err(dev, "unable to allocate MSMC resource\n"); + goto put_mem; + } + prueth->msmcram.pa = gen_pool_virt_to_phys(prueth->sram_pool, + (unsigned long)prueth->msmcram.va); + prueth->msmcram.size = msmc_ram_size; + memset_io(prueth->msmcram.va, 0, msmc_ram_size); + dev_dbg(dev, "sram: pa %llx va %p size %zx\n", prueth->msmcram.pa, + prueth->msmcram.va, prueth->msmcram.size); + + if (eth0_node) { + ret = prueth_netdev_init(prueth, eth0_node); + if (ret) { + dev_err_probe(dev, ret, "netdev init %s failed\n", + eth0_node->name); + goto free_pool; + } + + if (of_find_property(eth0_node, "ti,half-duplex-capable", NULL)) + prueth->emac[PRUETH_MAC0]->half_duplex = 1; + } + + if (eth1_node) { + ret = prueth_netdev_init(prueth, eth1_node); + if (ret) { + dev_err_probe(dev, ret, "netdev init %s failed\n", + eth1_node->name); + goto netdev_exit; + } + + if (of_find_property(eth1_node, "ti,half-duplex-capable", NULL)) + prueth->emac[PRUETH_MAC1]->half_duplex = 1; + } + + /* register the network devices */ + if (eth0_node) { + ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev); + if (ret) { + dev_err(dev, "can't register netdev for port MII0\n"); + goto netdev_exit; + } + + prueth->registered_netdevs[PRUETH_MAC0] = prueth->emac[PRUETH_MAC0]->ndev; + emac_phy_connect(prueth->emac[PRUETH_MAC0]); + phy_attached_info(prueth->emac[PRUETH_MAC0]->ndev->phydev); + } + + if (eth1_node) { + ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev); + if (ret) { + dev_err(dev, "can't register netdev for port MII1\n"); + goto netdev_unregister; + } + + prueth->registered_netdevs[PRUETH_MAC1] = prueth->emac[PRUETH_MAC1]->ndev; + emac_phy_connect(prueth->emac[PRUETH_MAC1]); + phy_attached_info(prueth->emac[PRUETH_MAC1]->ndev->phydev); + } + + dev_info(dev, "TI PRU SR1.0 ethernet driver initialized: %s EMAC mode\n", + (!eth0_node || !eth1_node) ? "single" : "dual"); + + if (eth1_node) + of_node_put(eth1_node); + if (eth0_node) + of_node_put(eth0_node); + + return 0; + +netdev_unregister: + for (i = 0; i < PRUETH_NUM_MACS; i++) { + if (!prueth->registered_netdevs[i]) + continue; + + if (prueth->emac[i]->ndev->phydev) { + phy_disconnect(prueth->emac[i]->ndev->phydev); + prueth->emac[i]->ndev->phydev = NULL; + } + unregister_netdev(prueth->registered_netdevs[i]); + } + +netdev_exit: + for (i = 0; i < PRUETH_NUM_MACS; i++) { + eth_node = prueth->eth_node[i]; + if (!eth_node) + continue; + + prueth_netdev_exit(prueth, eth_node); + } + +free_pool: + gen_pool_free(prueth->sram_pool, + (unsigned long)prueth->msmcram.va, msmc_ram_size); + +put_mem: + pruss_release_mem_region(prueth->pruss, &prueth->shram); + +put_pruss: + pruss_put(prueth->pruss); + +put_cores: + if (eth1_node) { + prueth_put_cores(prueth, ICSS_SLICE1); + of_node_put(eth1_node); + } + + if (eth0_node) { + prueth_put_cores(prueth, ICSS_SLICE0); + of_node_put(eth0_node); + } + + return ret; +} + +static void prueth_remove(struct platform_device *pdev) +{ + struct prueth *prueth = platform_get_drvdata(pdev); + struct device_node *eth_node; + int i; + + for (i = 0; i < PRUETH_NUM_MACS; i++) { + if (!prueth->registered_netdevs[i]) + continue; + phy_stop(prueth->emac[i]->ndev->phydev); + phy_disconnect(prueth->emac[i]->ndev->phydev); + prueth->emac[i]->ndev->phydev = NULL; + unregister_netdev(prueth->registered_netdevs[i]); + } + + for (i = 0; i < PRUETH_NUM_MACS; i++) { + eth_node = prueth->eth_node[i]; + if (!eth_node) + continue; + + prueth_netdev_exit(prueth, eth_node); + } + + gen_pool_free(prueth->sram_pool, + (unsigned long)prueth->msmcram.va, + MSMC_RAM_SIZE_SR1); + + pruss_release_mem_region(prueth->pruss, &prueth->shram); + + pruss_put(prueth->pruss); + + if (prueth->eth_node[PRUETH_MAC1]) + prueth_put_cores(prueth, ICSS_SLICE1); + + if (prueth->eth_node[PRUETH_MAC0]) + prueth_put_cores(prueth, ICSS_SLICE0); +} + +static const struct prueth_pdata am654_sr1_icssg_pdata = { + .fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE, +}; + +static const struct of_device_id prueth_dt_match[] = { + { .compatible = "ti,am654-sr1-icssg-prueth", .data = &am654_sr1_icssg_pdata }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, prueth_dt_match); + +static struct platform_driver prueth_driver = { + .probe = prueth_probe, + .remove_new = prueth_remove, + .driver = { + .name = "icssg-prueth-sr1", + .of_match_table = prueth_dt_match, + .pm = &prueth_dev_pm_ops, + }, +}; +module_platform_driver(prueth_driver); + +MODULE_AUTHOR("Roger Quadros "); +MODULE_AUTHOR("Md Danish Anwar "); +MODULE_AUTHOR("Diogo Ivo "); +MODULE_DESCRIPTION(PRUETH_MODULE_DESCRIPTION); +MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_qos.c b/drivers/net/ethernet/ti/icssg/icssg_qos.c --- a/drivers/net/ethernet/ti/icssg/icssg_qos.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/ethernet/ti/icssg/icssg_qos.c 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,475 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Texas Instruments ICSSG PRUETH QoS submodule + * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +#include +#include "icssg_prueth.h" +#include "icssg_switch_map.h" + +static void icssg_qos_tas_init(struct net_device *ndev); +static void icssg_prueth_iet_fpe_disable(struct prueth_qos_iet *iet); +static int icssg_prueth_iet_fpe_enable(struct prueth_emac *emac); +static void icssg_prueth_iet_fpe_disable(struct prueth_qos_iet *iet); +static void icssg_qos_enable_ietfpe(struct work_struct *work); + +void icssg_qos_init(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_qos_iet *iet = &emac->qos.iet; + + icssg_qos_tas_init(ndev); + + if (!iet->fpe_configured) + return; + + /* Init work queue for IET MAC verify process */ + iet->emac = emac; + INIT_WORK(&iet->fpe_config_task, icssg_qos_enable_ietfpe); + init_completion(&iet->fpe_config_compl); + + /* As worker may be sleeping, check this flag to abort + * as soon as it comes of out of sleep and cancel the + * fpe config task. + */ + atomic_set(&iet->cancel_fpe_config, 0); +} + +static void tas_update_fw_list_pointers(struct prueth_emac *emac) +{ + struct tas_config *tas = &emac->qos.tas.config; + + if ((readb(tas->active_list)) == TAS_LIST0) { + tas->fw_active_list = emac->dram.va + TAS_GATE_MASK_LIST0; + tas->fw_shadow_list = emac->dram.va + TAS_GATE_MASK_LIST1; + } else { + tas->fw_active_list = emac->dram.va + TAS_GATE_MASK_LIST1; + tas->fw_shadow_list = emac->dram.va + TAS_GATE_MASK_LIST0; + } +} + +void icssg_qos_link_up(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_qos_iet *iet = &emac->qos.iet; + + if (!iet->fpe_configured) + return; + + icssg_prueth_iet_fpe_enable(emac); +} + +void icssg_qos_link_down(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth_qos_iet *iet = &emac->qos.iet; + + if (iet->fpe_configured) + icssg_prueth_iet_fpe_disable(iet); +} + +static void tas_update_maxsdu_table(struct prueth_emac *emac) +{ + struct tas_config *tas = &emac->qos.tas.config; + u16 __iomem *max_sdu_tbl_ptr; + u8 gate_idx; + + /* update the maxsdu table */ + max_sdu_tbl_ptr = emac->dram.va + TAS_QUEUE_MAX_SDU_LIST; + + for (gate_idx = 0; gate_idx < TAS_MAX_NUM_QUEUES; gate_idx++) + writew(tas->max_sdu_table.max_sdu[gate_idx], &max_sdu_tbl_ptr[gate_idx]); +} + +static void tas_reset(struct prueth_emac *emac) +{ + struct tas_config *tas = &emac->qos.tas.config; + int i; + + for (i = 0; i < TAS_MAX_NUM_QUEUES; i++) + tas->max_sdu_table.max_sdu[i] = 2048; + + tas_update_maxsdu_table(emac); + + writeb(TAS_LIST0, tas->active_list); + + memset_io(tas->fw_active_list, 0, sizeof(*tas->fw_active_list)); + memset_io(tas->fw_shadow_list, 0, sizeof(*tas->fw_shadow_list)); +} + +static int tas_set_state(struct prueth_emac *emac, enum tas_state state) +{ + struct tas_config *tas = &emac->qos.tas.config; + int ret; + + if (tas->state == state) + return 0; + + switch (state) { + case TAS_STATE_RESET: + tas_reset(emac); + ret = emac_set_port_state(emac, ICSSG_EMAC_PORT_TAS_RESET); + tas->state = TAS_STATE_RESET; + break; + case TAS_STATE_ENABLE: + ret = emac_set_port_state(emac, ICSSG_EMAC_PORT_TAS_ENABLE); + tas->state = TAS_STATE_ENABLE; + break; + case TAS_STATE_DISABLE: + ret = emac_set_port_state(emac, ICSSG_EMAC_PORT_TAS_DISABLE); + tas->state = TAS_STATE_DISABLE; + break; + default: + netdev_err(emac->ndev, "%s: unsupported state\n", __func__); + ret = -EINVAL; + break; + } + + if (ret) + netdev_err(emac->ndev, "TAS set state failed %d\n", ret); + return ret; +} + +static int tas_set_trigger_list_change(struct prueth_emac *emac) +{ + struct tc_taprio_qopt_offload *admin_list = emac->qos.tas.taprio_admin; + struct tas_config *tas = &emac->qos.tas.config; + struct ptp_system_timestamp sts; + u32 change_cycle_count; + u32 cycle_time; + u64 base_time; + u64 cur_time; + + /* IEP clock has a hardware errata due to which it wraps around exactly + * once every taprio cycle. To compensate for that, adjust cycle time + * by the wrap around time which is stored in emac->iep->def_inc + */ + cycle_time = admin_list->cycle_time - emac->iep->def_inc; + base_time = admin_list->base_time; + cur_time = prueth_iep_gettime(emac, &sts); + + if (base_time > cur_time) + change_cycle_count = DIV_ROUND_UP_ULL(base_time - cur_time, cycle_time); + else + change_cycle_count = 1; + + writel(cycle_time, emac->dram.va + TAS_ADMIN_CYCLE_TIME); + writel(change_cycle_count, emac->dram.va + TAS_CONFIG_CHANGE_CYCLE_COUNT); + writeb(admin_list->num_entries, emac->dram.va + TAS_ADMIN_LIST_LENGTH); + + /* config_change cleared by f/w to ack reception of new shadow list */ + writeb(1, &tas->config_list->config_change); + /* config_pending cleared by f/w when new shadow list is copied to active list */ + writeb(1, &tas->config_list->config_pending); + + return emac_set_port_state(emac, ICSSG_EMAC_PORT_TAS_TRIGGER); +} + +static int tas_update_oper_list(struct prueth_emac *emac) +{ + struct tc_taprio_qopt_offload *admin_list = emac->qos.tas.taprio_admin; + struct tas_config *tas = &emac->qos.tas.config; + u32 tas_acc_gate_close_time = 0; + u8 idx, gate_idx, val; + int ret; + + if (admin_list->cycle_time > TAS_MAX_CYCLE_TIME) + return -EINVAL; + + tas_update_fw_list_pointers(emac); + + for (idx = 0; idx < admin_list->num_entries; idx++) { + writeb(admin_list->entries[idx].gate_mask, + &tas->fw_shadow_list->gate_mask_list[idx]); + tas_acc_gate_close_time += admin_list->entries[idx].interval; + + /* extend last entry till end of cycle time */ + if (idx == admin_list->num_entries - 1) + writel(admin_list->cycle_time, + &tas->fw_shadow_list->win_end_time_list[idx]); + else + writel(tas_acc_gate_close_time, + &tas->fw_shadow_list->win_end_time_list[idx]); + } + + /* clear remaining entries */ + for (idx = admin_list->num_entries; idx < TAS_MAX_CMD_LISTS; idx++) { + writeb(0, &tas->fw_shadow_list->gate_mask_list[idx]); + writel(0, &tas->fw_shadow_list->win_end_time_list[idx]); + } + + /* update the Array of gate close time for each queue in each window */ + for (idx = 0 ; idx < admin_list->num_entries; idx++) { + /* On Linux, only PRUETH_MAX_TX_QUEUES are supported per port */ + for (gate_idx = 0; gate_idx < PRUETH_MAX_TX_QUEUES; gate_idx++) { + u8 gate_mask_list_idx = readb(&tas->fw_shadow_list->gate_mask_list[idx]); + u32 gate_close_time = 0; + + if (gate_mask_list_idx & BIT(gate_idx)) + gate_close_time = readl(&tas->fw_shadow_list->win_end_time_list[idx]); + + writel(gate_close_time, + &tas->fw_shadow_list->gate_close_time_list[idx][gate_idx]); + } + } + + /* tell f/w to swap active & shadow list */ + ret = tas_set_trigger_list_change(emac); + if (ret) { + netdev_err(emac->ndev, "failed to swap f/w config list: %d\n", ret); + return ret; + } + + /* Wait for completion */ + ret = readb_poll_timeout(&tas->config_list->config_change, val, !val, + USEC_PER_MSEC, 10 * USEC_PER_MSEC); + if (ret) { + netdev_err(emac->ndev, "TAS list change completion time out\n"); + return ret; + } + + tas_update_fw_list_pointers(emac); + + return 0; +} + +static int emac_taprio_replace(struct net_device *ndev, + struct tc_taprio_qopt_offload *taprio) +{ + struct prueth_emac *emac = netdev_priv(ndev); + int ret; + + if (taprio->cycle_time_extension) { + NL_SET_ERR_MSG_MOD(taprio->extack, "Cycle time extension not supported"); + return -EOPNOTSUPP; + } + + if (taprio->cycle_time < TAS_MIN_CYCLE_TIME) { + NL_SET_ERR_MSG_FMT_MOD(taprio->extack, "cycle_time %llu is less than min supported cycle_time %d", + taprio->cycle_time, TAS_MIN_CYCLE_TIME); + return -EINVAL; + } + + if (taprio->num_entries > TAS_MAX_CMD_LISTS) { + NL_SET_ERR_MSG_FMT_MOD(taprio->extack, "num_entries %lu is more than max supported entries %d", + taprio->num_entries, TAS_MAX_CMD_LISTS); + return -EINVAL; + } + + if (emac->qos.tas.taprio_admin) + taprio_offload_free(emac->qos.tas.taprio_admin); + + emac->qos.tas.taprio_admin = taprio_offload_get(taprio); + ret = tas_update_oper_list(emac); + if (ret) + goto clear_taprio; + + ret = tas_set_state(emac, TAS_STATE_ENABLE); + if (ret) + goto clear_taprio; + +clear_taprio: + emac->qos.tas.taprio_admin = NULL; + taprio_offload_free(taprio); + + return ret; +} + +static int emac_taprio_destroy(struct net_device *ndev, + struct tc_taprio_qopt_offload *taprio) +{ + struct prueth_emac *emac = netdev_priv(ndev); + int ret; + + taprio_offload_free(taprio); + + ret = tas_set_state(emac, TAS_STATE_RESET); + if (ret) + return ret; + + return tas_set_state(emac, TAS_STATE_DISABLE); +} + +static int emac_setup_taprio(struct net_device *ndev, void *type_data) +{ + struct tc_taprio_qopt_offload *taprio = type_data; + int ret; + + switch (taprio->cmd) { + case TAPRIO_CMD_REPLACE: + ret = emac_taprio_replace(ndev, taprio); + break; + case TAPRIO_CMD_DESTROY: + ret = emac_taprio_destroy(ndev, taprio); + break; + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +int icssg_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, + void *type_data) +{ + switch (type) { + case TC_SETUP_QDISC_TAPRIO: + return emac_setup_taprio(ndev, type_data); + default: + return -EOPNOTSUPP; + } +} + +static void icssg_qos_tas_init(struct net_device *ndev) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct tas_config *tas; + + tas = &emac->qos.tas.config; + + tas->config_list = emac->dram.va + TAS_CONFIG_CHANGE_TIME; + tas->active_list = emac->dram.va + TAS_ACTIVE_LIST_INDEX; + + tas_update_fw_list_pointers(emac); + + tas_set_state(emac, TAS_STATE_RESET); +} + +static int icssg_config_ietfpe(struct prueth_qos_iet *iet, bool enable) +{ + void __iomem *config = iet->emac->dram.va + ICSSG_CONFIG_OFFSET; + int ret, i; + u8 val; + + /* If FPE is to be enabled, first configure MAC Verify state + * machine in firmware as firmware kicks the Verify process + * as soon as ICSSG_EMAC_PORT_PREMPT_TX_ENABLE command is + * received. + */ + if (enable && iet->mac_verify_configured) { + writeb(1, config + PRE_EMPTION_ENABLE_VERIFY); + writew(iet->tx_min_frag_size, config + PRE_EMPTION_ADD_FRAG_SIZE_LOCAL); + writel(iet->verify_time_ms, config + PRE_EMPTION_VERIFY_TIME); + } + + /* Send command to enable FPE Tx side. Rx is always enabled */ + ret = emac_set_port_state(iet->emac, + enable ? ICSSG_EMAC_PORT_PREMPT_TX_ENABLE : + ICSSG_EMAC_PORT_PREMPT_TX_DISABLE); + if (ret) { + netdev_err(iet->emac->ndev, "TX pre-empt %s command failed\n", + enable ? "enable" : "disable"); + writeb(0, config + PRE_EMPTION_ENABLE_VERIFY); + return ret; + } + + /* Update FPE Tx enable bit. Assume firmware use this bit + * and enable PRE_EMPTION_ACTIVE_TX if everything looks + * good at firmware + */ + writeb(enable ? 1 : 0, config + PRE_EMPTION_ENABLE_TX); + + if (enable && iet->mac_verify_configured) { + ret = readb_poll_timeout(config + PRE_EMPTION_VERIFY_STATUS, val, + (val == ICSSG_IETFPE_STATE_SUCCEEDED), + USEC_PER_MSEC, 5 * USEC_PER_SEC); + if (ret) { + netdev_err(iet->emac->ndev, + "timeout for MAC Verify: status %x\n", + val); + return ret; + } + } else { + /* Give f/w some time to update PRE_EMPTION_ACTIVE_TX state */ + usleep_range(100, 200); + } + + if (enable) { + val = readb(config + PRE_EMPTION_ACTIVE_TX); + if (val != 1) { + netdev_err(iet->emac->ndev, + "F/w fails to activate IET/FPE\n"); + writeb(0, config + PRE_EMPTION_ENABLE_TX); + return -ENODEV; + } + } else { + return 0; + } + + /* Configure highest queue as express. Set Bit 4 for FPE, + * Reset for express + */ + + /* first set all 8 queues as Pre-emptive */ + for (i = 0; i < PRUETH_MAX_TX_QUEUES * PRUETH_NUM_MACS; i++) + writeb(BIT(4), config + EXPRESS_PRE_EMPTIVE_Q_MAP + i); + + /* set highest priority channel queue as express */ + writeb(0, config + EXPRESS_PRE_EMPTIVE_Q_MAP + iet->emac->tx_ch_num - 1); + + /* set up queue mask for FPE. 1 means express */ + writeb(BIT(iet->emac->tx_ch_num - 1), config + EXPRESS_PRE_EMPTIVE_Q_MASK); + + iet->fpe_enabled = true; + + return ret; +} + +static void icssg_qos_enable_ietfpe(struct work_struct *work) +{ + struct prueth_qos_iet *iet = + container_of(work, struct prueth_qos_iet, fpe_config_task); + int ret; + + /* Set the required flag and send a command to ICSSG firmware to + * enable FPE and start MAC verify + */ + ret = icssg_config_ietfpe(iet, true); + + /* if verify configured, poll for the status and complete. + * Or just do completion + */ + if (!ret) + netdev_err(iet->emac->ndev, "IET FPE configured successfully\n"); + else + netdev_err(iet->emac->ndev, "IET FPE config error\n"); + complete(&iet->fpe_config_compl); +} + +static void icssg_prueth_iet_fpe_disable(struct prueth_qos_iet *iet) +{ + int ret; + + atomic_set(&iet->cancel_fpe_config, 1); + cancel_work_sync(&iet->fpe_config_task); + ret = icssg_config_ietfpe(iet, false); + if (!ret) + netdev_err(iet->emac->ndev, "IET FPE disabled successfully\n"); + else + netdev_err(iet->emac->ndev, "IET FPE disable failed\n"); +} + +static int icssg_prueth_iet_fpe_enable(struct prueth_emac *emac) +{ + struct prueth_qos_iet *iet = &emac->qos.iet; + int ret; + + /* Schedule MAC Verify and enable IET FPE if configured */ + atomic_set(&iet->cancel_fpe_config, 0); + reinit_completion(&iet->fpe_config_compl); + schedule_work(&iet->fpe_config_task); + /* By trial, found it takes about 1.5s. So + * wait for 10s + */ + ret = wait_for_completion_timeout(&iet->fpe_config_compl, + msecs_to_jiffies(10000)); + if (!ret) { + netdev_err(emac->ndev, + "IET verify completion timeout\n"); + /* cancel verify in progress */ + atomic_set(&iet->cancel_fpe_config, 1); + cancel_work_sync(&iet->fpe_config_task); + } + + return ret; +} diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_qos.h b/drivers/net/ethernet/ti/icssg/icssg_qos.h --- a/drivers/net/ethernet/ti/icssg/icssg_qos.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/ethernet/ti/icssg/icssg_qos.h 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +#ifndef __NET_TI_ICSSG_QOS_H +#define __NET_TI_ICSSG_QOS_H + +#include +#include +#include + +/* Maximum number of gate command entries in each list. */ +#define TAS_MAX_CMD_LISTS (16) + +/* Maximum number of transmit queues supported by implementation */ +#define TAS_MAX_NUM_QUEUES (8) + +/* Minimum cycle time supported by implementation (in ns) */ +#define TAS_MIN_CYCLE_TIME (1000000) + +/* Minimum cycle time supported by implementation (in ns) */ +#define TAS_MAX_CYCLE_TIME (4000000000) + +/* Minimum TAS window duration supported by implementation (in ns) */ +#define TAS_MIN_WINDOW_DURATION (10000) + +/** + * enum tas_list_num - TAS list number + * @TAS_LIST0: TAS list number is 0 + * @TAS_LIST1: TAS list number is 1 + */ +enum tas_list_num { + TAS_LIST0 = 0, + TAS_LIST1 = 1 +}; + +/** + * enum tas_state - State of TAS in firmware + * @TAS_STATE_DISABLE: TAS state machine is disabled. + * @TAS_STATE_ENABLE: TAS state machine is enabled. + * @TAS_STATE_RESET: TAS state machine is reset. + */ +enum tas_state { + TAS_STATE_DISABLE = 0, + TAS_STATE_ENABLE = 1, + TAS_STATE_RESET = 2, +}; + +/** + * struct tas_config_list - Config state machine variables + * @config_change_time: New list is copied at this time + * @config_change_error_counter: Incremented if admin->BaseTime < current time + * and TAS_enabled is true + * @config_pending: True if list update is pending + * @config_change: Set to true when application trigger updating of admin list + * to active list, cleared when configChangeTime is updated + */ +struct tas_config_list { + u64 config_change_time; + u32 config_change_error_counter; + u8 config_pending; + u8 config_change; +}; + +/* Max SDU table. See IEEE Std 802.1Q-2018 12.29.1.1 */ +struct tas_max_sdu_table { + u16 max_sdu[TAS_MAX_NUM_QUEUES]; +}; + +/** + * struct tas_firmware_list - TAS List Structure based on firmware memory map + * @gate_mask_list: Window gate mask list + * @win_end_time_list: Window end time list + * @gate_close_time_list: Array of gate close time for each queue in each window + */ +struct tas_firmware_list { + u8 gate_mask_list[TAS_MAX_CMD_LISTS]; + u32 win_end_time_list[TAS_MAX_CMD_LISTS]; + u32 gate_close_time_list[TAS_MAX_CMD_LISTS][TAS_MAX_NUM_QUEUES]; +}; + +/** + * struct tas_config - Main Time Aware Shaper Handle + * @state: TAS state + * @max_sdu_table: Max SDU table + * @config_list: Config change variables + * @active_list: Current operating list operating list + * @fw_active_list: Active List pointer, used by firmware + * @fw_shadow_list: Shadow List pointer, used by driver + */ +struct tas_config { + enum tas_state state; + struct tas_max_sdu_table max_sdu_table; + struct tas_config_list __iomem *config_list; + u8 __iomem *active_list; + struct tas_firmware_list __iomem *fw_active_list; + struct tas_firmware_list __iomem *fw_shadow_list; +}; + +struct prueth_qos_tas { + struct tc_taprio_qopt_offload *taprio_admin; + struct tc_taprio_qopt_offload *taprio_oper; + struct tas_config config; +}; + +struct prueth_qos_iet { + struct work_struct fpe_config_task; + struct completion fpe_config_compl; + struct prueth_emac *emac; + atomic_t cancel_fpe_config; + /* Set through priv flags to enable IET frame preemption */ + bool fpe_configured; + /* Set through priv flags to enable IET MAC Verify state machine + * in firmware + */ + bool mac_verify_configured; + /* Min TX fragment size, set via ethtool */ + u32 tx_min_frag_size; + /* wait time between verification attempts in ms (according to clause + * 30.14.1.6 aMACMergeVerifyTime), set via ethtool + */ + u32 verify_time_ms; + /* Set if IET FPE is active */ + bool fpe_enabled; +}; + +struct prueth_qos { + struct prueth_qos_iet iet; + struct prueth_qos_tas tas; +}; + +void icssg_qos_init(struct net_device *ndev); +int icssg_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, + void *type_data); +void icssg_qos_link_up(struct net_device *ndev); +void icssg_qos_link_down(struct net_device *ndev); +#endif /* __NET_TI_ICSSG_QOS_H */ diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_stats.c b/drivers/net/ethernet/ti/icssg/icssg_stats.c --- a/drivers/net/ethernet/ti/icssg/icssg_stats.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/icssg/icssg_stats.c 2024-07-07 20:37:34.668306669 -0400 @@ -11,6 +11,7 @@ #define ICSSG_TX_PACKET_OFFSET 0xA0 #define ICSSG_TX_BYTE_OFFSET 0xEC +#define ICSSG_IET_STATS_BASE 0x180 static u32 stats_base[] = { 0x54c, /* Slice 0 stats start */ 0xb18, /* Slice 1 stats start */ @@ -22,8 +23,8 @@ int slice = prueth_emac_slice(emac); u32 base = stats_base[slice]; u32 tx_pkt_cnt = 0; + int i, j; u32 val; - int i; for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) { regmap_read(prueth->miig_rt, @@ -40,6 +41,13 @@ if (icssg_all_stats[i].offset == ICSSG_TX_BYTE_OFFSET) emac->stats[i] -= tx_pkt_cnt * 8; } + + for (j = 0; j < ICSSG_NUM_PA_STATS; j++) { + regmap_read(prueth->pa_stats, ICSSG_IET_STATS_BASE + + ((j * PRUETH_NUM_MACS) + slice) * sizeof(u32), + &val); + emac->stats[i + j] += val; + } } void emac_stats_work_handler(struct work_struct *work) @@ -54,13 +62,18 @@ int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name) { - int i; + int i, j; for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) { if (!strcmp(icssg_all_stats[i].name, stat_name)) return emac->stats[icssg_all_stats[i].offset / sizeof(u32)]; } + for (j = 0; j < ICSSG_NUM_PA_STATS; j++) { + if (!strcmp(icssg_all_pa_stats[j].name, stat_name)) + return emac->stats[i + icssg_all_pa_stats[j].offset / sizeof(u32)]; + } + netdev_err(emac->ndev, "Invalid stats %s\n", stat_name); return -EINVAL; } diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h --- a/drivers/net/ethernet/ti/icssg/icssg_stats.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h 2024-07-07 20:37:34.668306669 -0400 @@ -77,6 +77,14 @@ u32 tx_bytes; }; +struct pa_stats_regs { + u32 iet_bad_frag; + u32 iet_asm_err; + u32 iet_tx_frag; + u32 iet_asm_ok; + u32 iet_rx_frag; +}; + #define ICSSG_STATS(field, stats_type) \ { \ #field, \ @@ -84,12 +92,23 @@ stats_type \ } +#define ICSSG_PA_STATS(field) \ +{ \ + #field, \ + offsetof(struct pa_stats_regs, field), \ +} + struct icssg_stats { char name[ETH_GSTRING_LEN]; u32 offset; bool standard_stats; }; +struct icssg_pa_stats { + char name[ETH_GSTRING_LEN]; + u32 offset; +}; + static const struct icssg_stats icssg_all_stats[] = { /* Rx */ ICSSG_STATS(rx_packets, true), @@ -155,4 +174,12 @@ ICSSG_STATS(tx_bytes, true), }; +static const struct icssg_pa_stats icssg_all_pa_stats[] = { + ICSSG_PA_STATS(iet_bad_frag), + ICSSG_PA_STATS(iet_asm_err), + ICSSG_PA_STATS(iet_tx_frag), + ICSSG_PA_STATS(iet_asm_ok), + ICSSG_PA_STATS(iet_rx_frag), +}; + #endif /* __NET_TI_ICSSG_STATS_H */ diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c --- a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,477 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* Texas Instruments K3 ICSSG Ethernet Switchdev Driver + * + * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +#include +#include +#include +#include +#include + +#include "icssg_prueth.h" +#include "icssg_switchdev.h" +#include "icssg_mii_rt.h" + +struct prueth_switchdev_event_work { + struct work_struct work; + struct switchdev_notifier_fdb_info fdb_info; + struct prueth_emac *emac; + unsigned long event; +}; + +static int prueth_switchdev_stp_state_set(struct prueth_emac *emac, + u8 state) +{ + enum icssg_port_state_cmd emac_state; + int ret = 0; + + switch (state) { + case BR_STATE_FORWARDING: + emac_state = ICSSG_EMAC_PORT_FORWARD; + break; + case BR_STATE_DISABLED: + emac_state = ICSSG_EMAC_PORT_DISABLE; + break; + case BR_STATE_LISTENING: + case BR_STATE_BLOCKING: + emac_state = ICSSG_EMAC_PORT_BLOCK; + break; + default: + return -EOPNOTSUPP; + } + + emac_set_port_state(emac, emac_state); + netdev_dbg(emac->ndev, "STP state: %u\n", emac_state); + + return ret; +} + +static int prueth_switchdev_attr_br_flags_set(struct prueth_emac *emac, + struct net_device *orig_dev, + struct switchdev_brport_flags brport_flags) +{ + enum icssg_port_state_cmd emac_state; + + if (brport_flags.mask & BR_MCAST_FLOOD) + emac_state = ICSSG_EMAC_PORT_MC_FLOODING_ENABLE; + else + emac_state = ICSSG_EMAC_PORT_MC_FLOODING_DISABLE; + + netdev_dbg(emac->ndev, "BR_MCAST_FLOOD: %d port %u\n", + emac_state, emac->port_id); + + emac_set_port_state(emac, emac_state); + + return 0; +} + +static int prueth_switchdev_attr_br_flags_pre_set(struct net_device *netdev, + struct switchdev_brport_flags brport_flags) +{ + if (brport_flags.mask & ~(BR_LEARNING | BR_MCAST_FLOOD)) + return -EINVAL; + + return 0; +} + +static int prueth_switchdev_attr_set(struct net_device *ndev, const void *ctx, + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack) +{ + struct prueth_emac *emac = netdev_priv(ndev); + int ret; + + netdev_dbg(ndev, "attr: id %u port: %u\n", attr->id, emac->port_id); + + switch (attr->id) { + case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: + ret = prueth_switchdev_attr_br_flags_pre_set(ndev, + attr->u.brport_flags); + break; + case SWITCHDEV_ATTR_ID_PORT_STP_STATE: + ret = prueth_switchdev_stp_state_set(emac, + attr->u.stp_state); + netdev_dbg(ndev, "stp state: %u\n", attr->u.stp_state); + break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: + ret = prueth_switchdev_attr_br_flags_set(emac, attr->orig_dev, + attr->u.brport_flags); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static void prueth_switchdev_fdb_offload_notify(struct net_device *ndev, + struct switchdev_notifier_fdb_info *rcv) +{ + struct switchdev_notifier_fdb_info info; + + memset(&info, 0, sizeof(info)); + info.addr = rcv->addr; + info.vid = rcv->vid; + info.offloaded = true; + call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, + ndev, &info.info, NULL); +} + +static void prueth_switchdev_event_work(struct work_struct *work) +{ + struct prueth_switchdev_event_work *switchdev_work = + container_of(work, struct prueth_switchdev_event_work, work); + struct prueth_emac *emac = switchdev_work->emac; + struct switchdev_notifier_fdb_info *fdb; + int port_id = emac->port_id; + int ret; + + rtnl_lock(); + switch (switchdev_work->event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + fdb = &switchdev_work->fdb_info; + + netdev_dbg(emac->ndev, "prueth_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n", + fdb->addr, fdb->vid, fdb->added_by_user, + fdb->offloaded, port_id); + + if (!fdb->added_by_user) + break; + if (!ether_addr_equal(emac->mac_addr, fdb->addr)) + break; + + ret = icssg_fdb_add_del(emac, fdb->addr, fdb->vid, + BIT(port_id), true); + if (!ret) + prueth_switchdev_fdb_offload_notify(emac->ndev, fdb); + break; + case SWITCHDEV_FDB_DEL_TO_DEVICE: + fdb = &switchdev_work->fdb_info; + + netdev_dbg(emac->ndev, "prueth_fdb_del: MACID = %pM vid = %u flags = %u %u -- port %d\n", + fdb->addr, fdb->vid, fdb->added_by_user, + fdb->offloaded, port_id); + + if (!fdb->added_by_user) + break; + if (!ether_addr_equal(emac->mac_addr, fdb->addr)) + break; + icssg_fdb_add_del(emac, fdb->addr, fdb->vid, + BIT(port_id), false); + break; + default: + break; + } + rtnl_unlock(); + + kfree(switchdev_work->fdb_info.addr); + kfree(switchdev_work); + dev_put(emac->ndev); +} + +static int prueth_switchdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *ndev = switchdev_notifier_info_to_dev(ptr); + struct prueth_switchdev_event_work *switchdev_work; + struct switchdev_notifier_fdb_info *fdb_info = ptr; + struct prueth_emac *emac = netdev_priv(ndev); + int err; + + if (!prueth_dev_check(ndev)) + return NOTIFY_DONE; + + if (event == SWITCHDEV_PORT_ATTR_SET) { + err = switchdev_handle_port_attr_set(ndev, ptr, + prueth_dev_check, + prueth_switchdev_attr_set); + return notifier_from_errno(err); + } + + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (WARN_ON(!switchdev_work)) + return NOTIFY_BAD; + + INIT_WORK(&switchdev_work->work, prueth_switchdev_event_work); + switchdev_work->emac = emac; + switchdev_work->event = event; + + switch (event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + case SWITCHDEV_FDB_DEL_TO_DEVICE: + memcpy(&switchdev_work->fdb_info, ptr, + sizeof(switchdev_work->fdb_info)); + switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); + if (!switchdev_work->fdb_info.addr) + goto err_addr_alloc; + ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, + fdb_info->addr); + dev_hold(ndev); + break; + default: + kfree(switchdev_work); + return NOTIFY_DONE; + } + + queue_work(system_long_wq, &switchdev_work->work); + + return NOTIFY_DONE; + +err_addr_alloc: + kfree(switchdev_work); + return NOTIFY_BAD; +} + +static int prueth_switchdev_vlan_add(struct prueth_emac *emac, bool untag, bool pvid, + u8 vid, struct net_device *orig_dev) +{ + bool cpu_port = netif_is_bridge_master(orig_dev); + int untag_mask = 0; + int port_mask; + int ret = 0; + + if (cpu_port) + port_mask = BIT(PRUETH_PORT_HOST); + else + port_mask = BIT(emac->port_id); + + if (untag) + untag_mask = port_mask; + + icssg_vtbl_modify(emac, vid, port_mask, untag_mask, true); + + netdev_dbg(emac->ndev, "VID add vid:%u port_mask:%X untag_mask %X PVID %d\n", + vid, port_mask, untag_mask, pvid); + + if (!pvid) + return ret; + + icssg_set_pvid(emac->prueth, vid, emac->port_id); + + return ret; +} + +static int prueth_switchdev_vlan_del(struct prueth_emac *emac, u16 vid, + struct net_device *orig_dev) +{ + bool cpu_port = netif_is_bridge_master(orig_dev); + int port_mask; + int ret = 0; + + if (cpu_port) + port_mask = BIT(PRUETH_PORT_HOST); + else + port_mask = BIT(emac->port_id); + + icssg_vtbl_modify(emac, vid, port_mask, 0, false); + + if (cpu_port) + icssg_fdb_add_del(emac, emac->mac_addr, vid, + BIT(PRUETH_PORT_HOST), false); + + if (vid == icssg_get_pvid(emac)) + icssg_set_pvid(emac->prueth, 0, emac->port_id); + + netdev_dbg(emac->ndev, "VID del vid:%u port_mask:%X\n", + vid, port_mask); + + return ret; +} + +static int prueth_switchdev_vlans_add(struct prueth_emac *emac, + const struct switchdev_obj_port_vlan *vlan) +{ + bool untag = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + struct net_device *orig_dev = vlan->obj.orig_dev; + bool cpu_port = netif_is_bridge_master(orig_dev); + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + + netdev_dbg(emac->ndev, "VID add vid:%u flags:%X\n", + vlan->vid, vlan->flags); + + if (cpu_port && !(vlan->flags & BRIDGE_VLAN_INFO_BRENTRY)) + return 0; + + if (vlan->vid > 0xff) + return 0; + + return prueth_switchdev_vlan_add(emac, untag, pvid, vlan->vid, + orig_dev); +} + +static int prueth_switchdev_vlans_del(struct prueth_emac *emac, + const struct switchdev_obj_port_vlan *vlan) +{ + if (vlan->vid > 0xff) + return 0; + + return prueth_switchdev_vlan_del(emac, vlan->vid, + vlan->obj.orig_dev); +} + +static int prueth_switchdev_mdb_add(struct prueth_emac *emac, + struct switchdev_obj_port_mdb *mdb) +{ + struct net_device *orig_dev = mdb->obj.orig_dev; + u8 port_mask, fid_c2; + bool cpu_port; + int err; + + cpu_port = netif_is_bridge_master(orig_dev); + + if (cpu_port) + port_mask = BIT(PRUETH_PORT_HOST); + else + port_mask = BIT(emac->port_id); + + fid_c2 = icssg_fdb_lookup(emac, mdb->addr, mdb->vid); + + err = icssg_fdb_add_del(emac, mdb->addr, mdb->vid, fid_c2 | port_mask, true); + netdev_dbg(emac->ndev, "MDB add vid %u:%pM ports: %X\n", + mdb->vid, mdb->addr, port_mask); + + return err; +} + +static int prueth_switchdev_mdb_del(struct prueth_emac *emac, + struct switchdev_obj_port_mdb *mdb) +{ + struct net_device *orig_dev = mdb->obj.orig_dev; + int del_mask, ret, fid_c2; + bool cpu_port; + + cpu_port = netif_is_bridge_master(orig_dev); + + if (cpu_port) + del_mask = BIT(PRUETH_PORT_HOST); + else + del_mask = BIT(emac->port_id); + + fid_c2 = icssg_fdb_lookup(emac, mdb->addr, mdb->vid); + + if (fid_c2 & ~del_mask) + ret = icssg_fdb_add_del(emac, mdb->addr, mdb->vid, fid_c2 & ~del_mask, true); + else + ret = icssg_fdb_add_del(emac, mdb->addr, mdb->vid, 0, false); + + netdev_dbg(emac->ndev, "MDB del vid %u:%pM ports: %X\n", + mdb->vid, mdb->addr, del_mask); + + return ret; +} + +static int prueth_switchdev_obj_add(struct net_device *ndev, const void *ctx, + const struct switchdev_obj *obj, + struct netlink_ext_ack *extack) +{ + struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); + struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj); + struct prueth_emac *emac = netdev_priv(ndev); + int err = 0; + + netdev_dbg(ndev, "obj_add: id %u port: %u\n", obj->id, emac->port_id); + + switch (obj->id) { + case SWITCHDEV_OBJ_ID_PORT_VLAN: + err = prueth_switchdev_vlans_add(emac, vlan); + break; + case SWITCHDEV_OBJ_ID_PORT_MDB: + case SWITCHDEV_OBJ_ID_HOST_MDB: + err = prueth_switchdev_mdb_add(emac, mdb); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static int prueth_switchdev_obj_del(struct net_device *ndev, const void *ctx, + const struct switchdev_obj *obj) +{ + struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); + struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj); + struct prueth_emac *emac = netdev_priv(ndev); + int err = 0; + + netdev_dbg(ndev, "obj_del: id %u port: %u\n", obj->id, emac->port_id); + + switch (obj->id) { + case SWITCHDEV_OBJ_ID_PORT_VLAN: + err = prueth_switchdev_vlans_del(emac, vlan); + break; + case SWITCHDEV_OBJ_ID_PORT_MDB: + case SWITCHDEV_OBJ_ID_HOST_MDB: + err = prueth_switchdev_mdb_del(emac, mdb); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static int prueth_switchdev_blocking_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); + int err; + + switch (event) { + case SWITCHDEV_PORT_OBJ_ADD: + err = switchdev_handle_port_obj_add(dev, ptr, + prueth_dev_check, + prueth_switchdev_obj_add); + return notifier_from_errno(err); + case SWITCHDEV_PORT_OBJ_DEL: + err = switchdev_handle_port_obj_del(dev, ptr, + prueth_dev_check, + prueth_switchdev_obj_del); + return notifier_from_errno(err); + case SWITCHDEV_PORT_ATTR_SET: + err = switchdev_handle_port_attr_set(dev, ptr, + prueth_dev_check, + prueth_switchdev_attr_set); + return notifier_from_errno(err); + default: + break; + } + + return NOTIFY_DONE; +} + +int prueth_switchdev_register_notifiers(struct prueth *prueth) +{ + int ret = 0; + + prueth->prueth_switchdev_nb.notifier_call = &prueth_switchdev_event; + ret = register_switchdev_notifier(&prueth->prueth_switchdev_nb); + if (ret) { + dev_err(prueth->dev, "register switchdev notifier fail ret:%d\n", + ret); + return ret; + } + + prueth->prueth_switchdev_bl_nb.notifier_call = &prueth_switchdev_blocking_event; + ret = register_switchdev_blocking_notifier(&prueth->prueth_switchdev_bl_nb); + if (ret) { + dev_err(prueth->dev, "register switchdev blocking notifier ret:%d\n", + ret); + unregister_switchdev_notifier(&prueth->prueth_switchdev_nb); + } + + return ret; +} + +void prueth_switchdev_unregister_notifiers(struct prueth *prueth) +{ + unregister_switchdev_blocking_notifier(&prueth->prueth_switchdev_bl_nb); + unregister_switchdev_notifier(&prueth->prueth_switchdev_nb); +} diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icssg_switchdev.h b/drivers/net/ethernet/ti/icssg/icssg_switchdev.h --- a/drivers/net/ethernet/ti/icssg/icssg_switchdev.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/ethernet/ti/icssg/icssg_switchdev.h 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/ + */ +#ifndef __NET_TI_ICSSG_SWITCHDEV_H +#define __NET_TI_ICSSG_SWITCHDEV_H + +#include "icssg_prueth.h" + +int prueth_switchdev_register_notifiers(struct prueth *prueth); +void prueth_switchdev_unregister_notifiers(struct prueth *prueth); +bool prueth_dev_check(const struct net_device *ndev); + +#endif /* __NET_TI_ICSSG_SWITCHDEV_H */ diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icss_iep.c b/drivers/net/ethernet/ti/icssg/icss_iep.c --- a/drivers/net/ethernet/ti/icssg/icss_iep.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/icssg/icss_iep.c 2024-07-07 20:37:34.668306669 -0400 @@ -52,78 +52,6 @@ #define IEP_CAP_CFG_CAPNR_1ST_EVENT_EN(n) BIT(LATCH_INDEX(n)) #define IEP_CAP_CFG_CAP_ASYNC_EN(n) BIT(LATCH_INDEX(n) + 10) -enum { - ICSS_IEP_GLOBAL_CFG_REG, - ICSS_IEP_GLOBAL_STATUS_REG, - ICSS_IEP_COMPEN_REG, - ICSS_IEP_SLOW_COMPEN_REG, - ICSS_IEP_COUNT_REG0, - ICSS_IEP_COUNT_REG1, - ICSS_IEP_CAPTURE_CFG_REG, - ICSS_IEP_CAPTURE_STAT_REG, - - ICSS_IEP_CAP6_RISE_REG0, - ICSS_IEP_CAP6_RISE_REG1, - - ICSS_IEP_CAP7_RISE_REG0, - ICSS_IEP_CAP7_RISE_REG1, - - ICSS_IEP_CMP_CFG_REG, - ICSS_IEP_CMP_STAT_REG, - ICSS_IEP_CMP0_REG0, - ICSS_IEP_CMP0_REG1, - ICSS_IEP_CMP1_REG0, - ICSS_IEP_CMP1_REG1, - - ICSS_IEP_CMP8_REG0, - ICSS_IEP_CMP8_REG1, - ICSS_IEP_SYNC_CTRL_REG, - ICSS_IEP_SYNC0_STAT_REG, - ICSS_IEP_SYNC1_STAT_REG, - ICSS_IEP_SYNC_PWIDTH_REG, - ICSS_IEP_SYNC0_PERIOD_REG, - ICSS_IEP_SYNC1_DELAY_REG, - ICSS_IEP_SYNC_START_REG, - ICSS_IEP_MAX_REGS, -}; - -/** - * struct icss_iep_plat_data - Plat data to handle SoC variants - * @config: Regmap configuration data - * @reg_offs: register offsets to capture offset differences across SoCs - * @flags: Flags to represent IEP properties - */ -struct icss_iep_plat_data { - struct regmap_config *config; - u32 reg_offs[ICSS_IEP_MAX_REGS]; - u32 flags; -}; - -struct icss_iep { - struct device *dev; - void __iomem *base; - const struct icss_iep_plat_data *plat_data; - struct regmap *map; - struct device_node *client_np; - unsigned long refclk_freq; - int clk_tick_time; /* one refclk tick time in ns */ - struct ptp_clock_info ptp_info; - struct ptp_clock *ptp_clock; - struct mutex ptp_clk_mutex; /* PHC access serializer */ - spinlock_t irq_lock; /* CMP IRQ vs icss_iep_ptp_enable access */ - u32 def_inc; - s16 slow_cmp_inc; - u32 slow_cmp_count; - const struct icss_iep_clockops *ops; - void *clockops_data; - u32 cycle_time_ns; - u32 perout_enabled; - bool pps_enabled; - int cap_cmp_irq; - u64 period; - u32 latch_enable; -}; - /** * icss_iep_get_count_hi() - Get the upper 32 bit IEP counter * @iep: Pointer to structure representing IEP. diff -Naur --no-dereference a/drivers/net/ethernet/ti/icssg/icss_iep.h b/drivers/net/ethernet/ti/icssg/icss_iep.h --- a/drivers/net/ethernet/ti/icssg/icss_iep.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/icssg/icss_iep.h 2024-07-07 20:37:34.668306669 -0400 @@ -12,7 +12,78 @@ #include #include -struct icss_iep; +enum { + ICSS_IEP_GLOBAL_CFG_REG, + ICSS_IEP_GLOBAL_STATUS_REG, + ICSS_IEP_COMPEN_REG, + ICSS_IEP_SLOW_COMPEN_REG, + ICSS_IEP_COUNT_REG0, + ICSS_IEP_COUNT_REG1, + ICSS_IEP_CAPTURE_CFG_REG, + ICSS_IEP_CAPTURE_STAT_REG, + + ICSS_IEP_CAP6_RISE_REG0, + ICSS_IEP_CAP6_RISE_REG1, + + ICSS_IEP_CAP7_RISE_REG0, + ICSS_IEP_CAP7_RISE_REG1, + + ICSS_IEP_CMP_CFG_REG, + ICSS_IEP_CMP_STAT_REG, + ICSS_IEP_CMP0_REG0, + ICSS_IEP_CMP0_REG1, + ICSS_IEP_CMP1_REG0, + ICSS_IEP_CMP1_REG1, + + ICSS_IEP_CMP8_REG0, + ICSS_IEP_CMP8_REG1, + ICSS_IEP_SYNC_CTRL_REG, + ICSS_IEP_SYNC0_STAT_REG, + ICSS_IEP_SYNC1_STAT_REG, + ICSS_IEP_SYNC_PWIDTH_REG, + ICSS_IEP_SYNC0_PERIOD_REG, + ICSS_IEP_SYNC1_DELAY_REG, + ICSS_IEP_SYNC_START_REG, + ICSS_IEP_MAX_REGS, +}; + +/** + * struct icss_iep_plat_data - Plat data to handle SoC variants + * @config: Regmap configuration data + * @reg_offs: register offsets to capture offset differences across SoCs + * @flags: Flags to represent IEP properties + */ +struct icss_iep_plat_data { + struct regmap_config *config; + u32 reg_offs[ICSS_IEP_MAX_REGS]; + u32 flags; +}; + +struct icss_iep { + struct device *dev; + void __iomem *base; + const struct icss_iep_plat_data *plat_data; + struct regmap *map; + struct device_node *client_np; + unsigned long refclk_freq; + int clk_tick_time; /* one refclk tick time in ns */ + struct ptp_clock_info ptp_info; + struct ptp_clock *ptp_clock; + struct mutex ptp_clk_mutex; /* PHC access serializer */ + spinlock_t irq_lock; /* CMP IRQ vs icss_iep_ptp_enable access */ + u32 def_inc; + s16 slow_cmp_inc; + u32 slow_cmp_count; + const struct icss_iep_clockops *ops; + void *clockops_data; + u32 cycle_time_ns; + u32 perout_enabled; + bool pps_enabled; + int cap_cmp_irq; + u64 period; + u32 latch_enable; +}; + extern const struct icss_iep_clockops prueth_iep_clockops; /* Firmware specific clock operations */ diff -Naur --no-dereference a/drivers/net/ethernet/ti/k3-cppi-desc-pool.c b/drivers/net/ethernet/ti/k3-cppi-desc-pool.c --- a/drivers/net/ethernet/ti/k3-cppi-desc-pool.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/k3-cppi-desc-pool.c 2024-07-07 20:37:34.668306669 -0400 @@ -22,6 +22,7 @@ size_t mem_size; size_t num_desc; struct gen_pool *gen_pool; + void **desc_infos; }; void k3_cppi_desc_pool_destroy(struct k3_cppi_desc_pool *pool) @@ -37,7 +38,11 @@ dma_free_coherent(pool->dev, pool->mem_size, pool->cpumem, pool->dma_addr); + kfree(pool->desc_infos); + gen_pool_destroy(pool->gen_pool); /* frees pool->name */ + + kfree(pool); } EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_destroy); @@ -50,7 +55,7 @@ const char *pool_name = NULL; int ret = -ENOMEM; - pool = devm_kzalloc(dev, sizeof(*pool), GFP_KERNEL); + pool = kzalloc(sizeof(*pool), GFP_KERNEL); if (!pool) return ERR_PTR(ret); @@ -62,18 +67,21 @@ pool_name = kstrdup_const(name ? name : dev_name(pool->dev), GFP_KERNEL); if (!pool_name) - return ERR_PTR(-ENOMEM); + goto gen_pool_create_fail; pool->gen_pool = gen_pool_create(ilog2(pool->desc_size), -1); if (!pool->gen_pool) { - ret = -ENOMEM; - dev_err(pool->dev, "pool create failed %d\n", ret); kfree_const(pool_name); goto gen_pool_create_fail; } pool->gen_pool->name = pool_name; + pool->desc_infos = kcalloc(pool->num_desc, + sizeof(*pool->desc_infos), GFP_KERNEL); + if (!pool->desc_infos) + goto gen_pool_desc_infos_alloc_fail; + pool->cpumem = dma_alloc_coherent(pool->dev, pool->mem_size, &pool->dma_addr, GFP_KERNEL); @@ -94,9 +102,11 @@ dma_free_coherent(pool->dev, pool->mem_size, pool->cpumem, pool->dma_addr); dma_alloc_fail: + kfree(pool->desc_infos); +gen_pool_desc_infos_alloc_fail: gen_pool_destroy(pool->gen_pool); /* frees pool->name */ gen_pool_create_fail: - devm_kfree(pool->dev, pool); + kfree(pool); return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_create_name); @@ -132,5 +142,31 @@ } EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_avail); +size_t k3_cppi_desc_pool_desc_size(const struct k3_cppi_desc_pool *pool) +{ + return pool->desc_size; +} +EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_desc_size); + +void *k3_cppi_desc_pool_cpuaddr(const struct k3_cppi_desc_pool *pool) +{ + return pool->cpumem; +} +EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_cpuaddr); + +void k3_cppi_desc_pool_desc_info_set(struct k3_cppi_desc_pool *pool, + int desc_idx, void *info) +{ + pool->desc_infos[desc_idx] = info; +} +EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_desc_info_set); + +void *k3_cppi_desc_pool_desc_info(const struct k3_cppi_desc_pool *pool, + int desc_idx) +{ + return pool->desc_infos[desc_idx]; +} +EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_desc_info); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("TI K3 CPPI5 descriptors pool API"); diff -Naur --no-dereference a/drivers/net/ethernet/ti/k3-cppi-desc-pool.h b/drivers/net/ethernet/ti/k3-cppi-desc-pool.h --- a/drivers/net/ethernet/ti/k3-cppi-desc-pool.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/k3-cppi-desc-pool.h 2024-07-07 20:37:34.668306669 -0400 @@ -26,5 +26,11 @@ void *k3_cppi_desc_pool_alloc(struct k3_cppi_desc_pool *pool); void k3_cppi_desc_pool_free(struct k3_cppi_desc_pool *pool, void *addr); size_t k3_cppi_desc_pool_avail(struct k3_cppi_desc_pool *pool); +size_t k3_cppi_desc_pool_desc_size(const struct k3_cppi_desc_pool *pool); +void *k3_cppi_desc_pool_cpuaddr(const struct k3_cppi_desc_pool *pool); +void k3_cppi_desc_pool_desc_info_set(struct k3_cppi_desc_pool *pool, + int desc_idx, void *info); +void *k3_cppi_desc_pool_desc_info(const struct k3_cppi_desc_pool *pool, + int desc_idx); #endif /* K3_CPPI_DESC_POOL_H_ */ diff -Naur --no-dereference a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig --- a/drivers/net/ethernet/ti/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/Kconfig 2024-07-07 20:37:34.668306669 -0400 @@ -79,6 +79,20 @@ To compile this driver as a module, choose M here: the module will be called cpsw_new. +config TI_CPSW_PROXY_CLIENT + tristate "TI CPSW Proxy Client" + depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER + help + This driver supports Ethernet functionality for CPSWnG + Ethernet Subsystem which is configured by Ethernet Switch + Firmware (EthFw). + + The Ethernet Switch Firmware acts as a proxy to the Linux + Client driver by performing all the necessary configuration + of the CPSW Peripheral while enabling network data transfer + to/from the Linux Client to CPSW over the allocated TX DMA + Channels and RX DMA Flows. + config TI_CPTS tristate "TI Common Platform Time Sync (CPTS) Support" depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST @@ -134,14 +148,16 @@ protocol, Ethernet Enhanced Scheduled Traffic Operations (CPTS_ESTFn) and PCIe Subsystem Precision Time Measurement (PTM). -config TI_AM65_CPSW_TAS - bool "Enable TAS offload in AM65 CPSW" +config TI_AM65_CPSW_QOS + bool "Enable QoS offload features in AM65 CPSW" depends on TI_K3_AM65_CPSW_NUSS && NET_SCH_TAPRIO && TI_K3_AM65_CPTS help - Say y here to support Time Aware Shaper(TAS) offload in AM65 CPSW. - AM65 CPSW hardware supports Enhanced Scheduled Traffic (EST) - defined in IEEE 802.1Q 2018. The EST scheduler runs on CPTS and the - TAS/EST schedule is updated in the Fetch RAM memory of the CPSW. + This option enables QoS offload features in AM65 CPSW like + Time Aware Shaper (TAS) / Enhanced Scheduled Traffic (EST), + MQPRIO qdisc offload and Frame-Preemption MAC Merge / Interspersing + Express Traffic (IET). + The EST scheduler runs on CPTS and the TAS/EST schedule is + updated in the Fetch RAM memory of the CPSW. config TI_KEYSTONE_NETCP tristate "TI Keystone NETCP Core Support" @@ -192,8 +208,11 @@ select PHYLIB select TI_ICSS_IEP select TI_K3_CPPI_DESC_POOL + select PAGE_POOL depends on PRU_REMOTEPROC depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER + depends on PTP_1588_CLOCK_OPTIONAL + depends on NET_SCH_TAPRIO help Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem. This subsystem is available starting with the AM65 platform. @@ -202,6 +221,22 @@ to support the Ethernet operation. Currently, it supports Ethernet with 1G and 100M link speed. +config TI_ICSSG_PRUETH_SR1 + tristate "TI Gigabit PRU SR1.0 Ethernet driver" + select PHYLIB + select TI_ICSS_IEP + select TI_K3_CPPI_DESC_POOL + depends on PRU_REMOTEPROC + depends on NET_SWITCHDEV + depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER + help + Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem. + This subsystem is available on the AM65 SR1.0 platform. + + This driver requires firmware binaries which will run on the PRUs + to support the Ethernet operation. Currently, it supports Ethernet + with 1G, 100M and 10M link speed. + config TI_ICSS_IEP tristate "TI PRU ICSS IEP driver" depends on PTP_1588_CLOCK_OPTIONAL diff -Naur --no-dereference a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile --- a/drivers/net/ethernet/ti/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ethernet/ti/Makefile 2024-07-07 20:37:34.668306669 -0400 @@ -7,6 +7,9 @@ obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o obj-$(CONFIG_TI_CPSW_SWITCHDEV) += cpsw-common.o +obj-$(CONFIG_TI_CPSW_PROXY_CLIENT) += ti-cpsw-proxy-client.o +ti-cpsw-proxy-client-y := cpsw-proxy-client.o + obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_CPMAC) += cpmac.o obj-$(CONFIG_TI_DAVINCI_EMAC) += ti_davinci_emac.o @@ -27,16 +30,28 @@ obj-$(CONFIG_TI_K3_CPPI_DESC_POOL) += k3-cppi-desc-pool.o obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o -ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o am65-cpsw-qos.o +ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o k3-cppi-desc-pool.o am65-debugfs.o +ti-am65-cpsw-nuss-$(CONFIG_TI_AM65_CPSW_QOS) += am65-cpsw-qos.o ti-am65-cpsw-nuss-$(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV) += am65-cpsw-switchdev.o obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o obj-$(CONFIG_TI_ICSSG_PRUETH) += icssg-prueth.o icssg-prueth-y := icssg/icssg_prueth.o \ + icssg/icssg_common.o \ icssg/icssg_classifier.o \ icssg/icssg_queues.o \ icssg/icssg_config.o \ icssg/icssg_mii_cfg.o \ icssg/icssg_stats.o \ - icssg/icssg_ethtool.o + icssg/icssg_ethtool.o \ + icssg/icssg_switchdev.o \ + icssg/icssg_qos.o +obj-$(CONFIG_TI_ICSSG_PRUETH_SR1) += icssg-prueth-sr1.o +icssg-prueth-sr1-y := icssg/icssg_prueth_sr1.o \ + icssg/icssg_common.o \ + icssg/icssg_classifier.o \ + icssg/icssg_config.o \ + icssg/icssg_mii_cfg.o \ + icssg/icssg_stats.o \ + icssg/icssg_ethtool.o obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o diff -Naur --no-dereference a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig --- a/drivers/net/ieee802154/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ieee802154/Kconfig 2024-07-07 20:37:34.668306669 -0400 @@ -66,6 +66,15 @@ This driver can also be built as a module. To do so say M here. The module will be called 'atusb'. +config IEEE802154_WPANUSB + tristate "WPANUSB driver" + depends on IEEE802154_DRIVERS && MAC802154 && USB + help + Adds support for WPANUSB 802.15.4 adapters. + + This driver should work with at least the following devices: + * BeagleBoard.org BeagleConnect Freedom + config IEEE802154_ADF7242 tristate "ADF7242 transceiver driver" depends on IEEE802154_DRIVERS && MAC802154 diff -Naur --no-dereference a/drivers/net/ieee802154/Makefile b/drivers/net/ieee802154/Makefile --- a/drivers/net/ieee802154/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/ieee802154/Makefile 2024-07-07 20:37:34.668306669 -0400 @@ -4,6 +4,7 @@ obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o +obj-$(CONFIG_IEEE802154_WPANUSB) += wpanusb.o obj-$(CONFIG_IEEE802154_ADF7242) += adf7242.o obj-$(CONFIG_IEEE802154_CA8210) += ca8210.o obj-$(CONFIG_IEEE802154_MCR20A) += mcr20a.o diff -Naur --no-dereference a/drivers/net/ieee802154/wpanusb.c b/drivers/net/ieee802154/wpanusb.c --- a/drivers/net/ieee802154/wpanusb.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/ieee802154/wpanusb.c 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,776 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the WPANUSB IEEE 802.15.4 dongle + * + * Copyright (C) 2018 Intel Corp. + * + * The driver implements SoftMAC 802.15.4 protocol based on atusb + * driver for ATUSB IEEE 802.15.4 dongle. + * + * Written by Andrei Emeltchenko + */ + +#include +#include +#include +#include + +#include +#include + +#define DEBUG +#include "wpanusb.h" + +#define WPANUSB_NUM_RX_URBS 4 /* allow for a bit of local latency */ +#define WPANUSB_ALLOC_DELAY_MS 100 /* delay after failed allocation */ + +#define VENDOR_OUT (USB_TYPE_VENDOR | USB_DIR_OUT) +#define VENDOR_IN (USB_TYPE_VENDOR | USB_DIR_IN) + +#define WPANUSB_VALID_CHANNELS (0x07FFFFFF) + +struct wpanusb { + struct ieee802154_hw *hw; + struct usb_device *udev; + int shutdown; /* non-zero if shutting down */ + + /* RX variables */ + struct delayed_work work; /* memory allocations */ + struct usb_anchor idle_urbs; /* URBs waiting to be submitted */ + struct usb_anchor rx_urbs; /* URBs waiting for reception */ + + /* TX variables */ + struct usb_ctrlrequest tx_dr; + struct urb *tx_urb; + struct sk_buff *tx_skb; + u8 tx_ack_seq; /* current TX ACK sequence number */ +}; + +/* ----- USB commands without data ----------------------------------------- */ + +static int wpanusb_control_send(struct wpanusb *wpanusb, unsigned int pipe, + u8 request, void *data, u16 size) +{ + struct usb_device *udev = wpanusb->udev; + + return usb_control_msg(udev, pipe, request, VENDOR_OUT, + 0, 0, data, size, 1000); +} + +static int wpanusb_control_recv(struct wpanusb *wpanusb, u8 request, void *data, u16 size) +{ + struct usb_device *udev = wpanusb->udev; + + usb_control_msg(udev, usb_sndctrlpipe(udev, 0), request, VENDOR_OUT, + 0, 0, data, size, 1000); + + return usb_control_msg(udev, usb_rcvbulkpipe(udev, 1), request, VENDOR_IN, + 0, 0, data, size, 1000); +} + +/* ----- skb allocation ---------------------------------------------------- */ + +#define MAX_PSDU 127 +#define MAX_RX_XFER (1 + MAX_PSDU + 2 + 1) /* PHR+PSDU+CRC+LQI */ + +#define SKB_WPANUSB(skb) (*(struct wpanusb **)(skb)->cb) + +static void wpanusb_bulk_complete(struct urb *urb); + +static int wpanusb_submit_rx_urb(struct wpanusb *wpanusb, struct urb *urb) +{ + struct usb_device *udev = wpanusb->udev; + struct sk_buff *skb = urb->context; + int ret; + + if (!skb) { + skb = alloc_skb(MAX_RX_XFER, GFP_KERNEL); + if (!skb) { + dev_warn_ratelimited(&udev->dev, + "can't allocate skb\n"); + return -ENOMEM; + } + skb_put(skb, MAX_RX_XFER); + SKB_WPANUSB(skb) = wpanusb; + } + + usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, 1), + skb->data, MAX_RX_XFER, wpanusb_bulk_complete, skb); + usb_anchor_urb(urb, &wpanusb->rx_urbs); + + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret) { + usb_unanchor_urb(urb); + kfree_skb(skb); + urb->context = NULL; + } + + return ret; +} + +static void wpanusb_work_urbs(struct work_struct *work) +{ + struct wpanusb *wpanusb = + container_of(to_delayed_work(work), struct wpanusb, work); + struct usb_device *udev = wpanusb->udev; + struct urb *urb; + int ret; + + if (wpanusb->shutdown) + return; + + do { + urb = usb_get_from_anchor(&wpanusb->idle_urbs); + if (!urb) + return; + + ret = wpanusb_submit_rx_urb(wpanusb, urb); + } while (!ret); + + usb_anchor_urb(urb, &wpanusb->idle_urbs); + dev_warn_ratelimited(&udev->dev, "can't allocate/submit URB (%d)\n", + ret); + schedule_delayed_work(&wpanusb->work, + msecs_to_jiffies(WPANUSB_ALLOC_DELAY_MS) + 1); +} + +/* ----- Asynchronous USB -------------------------------------------------- */ + +static void wpanusb_tx_done(struct wpanusb *wpanusb, uint8_t seq) +{ + struct usb_device *udev = wpanusb->udev; + u8 expect = wpanusb->tx_ack_seq; + + dev_dbg(&udev->dev, "seq 0x%02x expect 0x%02x\n", seq, expect); + + if (seq == expect) { + ieee802154_xmit_complete(wpanusb->hw, wpanusb->tx_skb, false); + } else { + dev_dbg(&udev->dev, "unknown ack %u\n", seq); + + ieee802154_xmit_hw_error(wpanusb->hw, wpanusb->tx_skb); + } +} + +static void wpanusb_process_urb(struct urb *urb) +{ + struct usb_device *udev = urb->dev; + struct sk_buff *skb = urb->context; + struct wpanusb *wpanusb = SKB_WPANUSB(skb); + u8 len, lqi; + + if (!urb->actual_length) { + dev_dbg(&udev->dev, "zero-sized URB ?\n"); + return; + } + + len = *skb->data; + + dev_dbg(&udev->dev, "urb %p urb len %u pkt len %u", urb, + urb->actual_length, len); + + /* Handle ACK */ + if (urb->actual_length == 1) { + wpanusb_tx_done(wpanusb, len); + return; + } + + if (len + 1 > urb->actual_length - 1) { + dev_dbg(&udev->dev, "frame len %d+1 > URB %u-1\n", + len, urb->actual_length); + return; + } + + if (!ieee802154_is_valid_psdu_len(len)) { + dev_dbg(&udev->dev, "frame corrupted\n"); + return; + } + + print_hex_dump_bytes("> ", DUMP_PREFIX_OFFSET, skb->data, + urb->actual_length); + + /* Get LQI at the end of the packet */ + lqi = skb->data[len + 1]; + dev_dbg(&udev->dev, "rx len %d lqi 0x%02x\n", len, lqi); + skb_pull(skb, 1); /* remove length */ + skb_trim(skb, len); /* remove LQI */ + ieee802154_rx_irqsafe(wpanusb->hw, skb, lqi); + urb->context = NULL; /* skb is gone */ +} + +static void wpanusb_bulk_complete(struct urb *urb) +{ + struct usb_device *udev = urb->dev; + struct sk_buff *skb = urb->context; + struct wpanusb *wpanusb = SKB_WPANUSB(skb); + + dev_dbg(&udev->dev, "status %d len %d\n", + urb->status, urb->actual_length); + + if (urb->status) { + if (urb->status == -ENOENT) { /* being killed */ + kfree_skb(skb); + urb->context = NULL; + return; + } + + dev_dbg(&udev->dev, "URB error %d\n", urb->status); + } else { + wpanusb_process_urb(urb); + } + + usb_anchor_urb(urb, &wpanusb->idle_urbs); + if (!wpanusb->shutdown) + schedule_delayed_work(&wpanusb->work, 0); +} + +/* ----- URB allocation/deallocation --------------------------------------- */ + +static void wpanusb_free_urbs(struct wpanusb *wpanusb) +{ + struct urb *urb; + + do { + urb = usb_get_from_anchor(&wpanusb->idle_urbs); + if (!urb) + break; + kfree_skb(urb->context); + usb_free_urb(urb); + } while (true); +} + +static int wpanusb_alloc_urbs(struct wpanusb *wpanusb, unsigned int n) +{ + struct urb *urb; + + while (n--) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + wpanusb_free_urbs(wpanusb); + return -ENOMEM; + } + usb_anchor_urb(urb, &wpanusb->idle_urbs); + } + + return 0; +} + +/* ----- IEEE 802.15.4 interface operations -------------------------------- */ + +static void wpanusb_xmit_complete(struct urb *urb) +{ + dev_dbg(&urb->dev->dev, "urb transmit completed"); +} + +static int wpanusb_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + int ret = 0; + + dev_dbg(&udev->dev, "len %u", skb->len); + + /* ack_seq range is 0x01 - 0xff */ + wpanusb->tx_ack_seq++; + if (!wpanusb->tx_ack_seq) + wpanusb->tx_ack_seq++; + + wpanusb->tx_skb = skb; + wpanusb->tx_dr.wIndex = cpu_to_le16(wpanusb->tx_ack_seq); + wpanusb->tx_dr.wLength = cpu_to_le16(skb->len); + + usb_fill_control_urb(wpanusb->tx_urb, udev, + usb_sndctrlpipe(udev, 0), + (unsigned char *)&wpanusb->tx_dr, skb->data, + skb->len, wpanusb_xmit_complete, NULL); + ret = usb_submit_urb(wpanusb->tx_urb, GFP_ATOMIC); + + dev_dbg(&udev->dev, "%s: ret %d len %u seq %u\n", __func__, ret, + skb->len, wpanusb->tx_ack_seq); + + return ret; +} + +static int wpanusb_channel(struct ieee802154_hw *hw, u8 page, u8 channel) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + struct set_channel *req; + int ret; + + req = kmalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->page = page; + req->channel = channel; + + ret = wpanusb_control_send(wpanusb, usb_sndctrlpipe(udev, 0), + SET_CHANNEL, req, sizeof(*req)); + kfree(req); + if (ret < 0) { + dev_err(&udev->dev, "Failed set channel, ret %d", ret); + return ret; + } + + dev_dbg(&udev->dev, "set page %u channel %u", page, channel); + + return 0; +} + +static int wpanusb_ed(struct ieee802154_hw *hw, u8 *level) +{ + WARN_ON(!level); + + *level = 0xbe; + + return 0; +} + +static int wpanusb_set_hw_addr_filt(struct ieee802154_hw *hw, + struct ieee802154_hw_addr_filt *filt, + unsigned long changed) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + int ret = 0; + + if (changed & IEEE802154_AFILT_SADDR_CHANGED) { + struct set_short_addr *req; + + req = kmalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->short_addr = filt->short_addr; + + ret = wpanusb_control_send(wpanusb, usb_sndctrlpipe(udev, 0), + SET_SHORT_ADDR, req, sizeof(*req)); + kfree(req); + if (ret < 0) { + dev_err(&udev->dev, "Failed to set short_addr, ret %d", + ret); + return ret; + } + + dev_dbg(&udev->dev, "short addr changed to 0x%04x", + le16_to_cpu(filt->short_addr)); + } + + if (changed & IEEE802154_AFILT_PANID_CHANGED) { + struct set_pan_id *req; + + req = kmalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->pan_id = filt->pan_id; + + ret = wpanusb_control_send(wpanusb, usb_sndctrlpipe(udev, 0), + SET_PAN_ID, req, sizeof(*req)); + kfree(req); + if (ret < 0) { + dev_err(&udev->dev, "Failed to set pan_id, ret %d", + ret); + return ret; + } + + dev_dbg(&udev->dev, "pan id changed to 0x%04x", + le16_to_cpu(filt->pan_id)); + } + + if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) { + struct set_ieee_addr *req; + + req = kmalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + memcpy(&req->ieee_addr, &filt->ieee_addr, + sizeof(req->ieee_addr)); + + ret = wpanusb_control_send(wpanusb, usb_sndctrlpipe(udev, 0), + SET_IEEE_ADDR, req, sizeof(*req)); + kfree(req); + if (ret < 0) { + dev_err(&udev->dev, "Failed to set ieee_addr, ret %d", + ret); + return ret; + } + + dev_dbg(&udev->dev, "IEEE addr changed"); + } + + if (changed & IEEE802154_AFILT_PANC_CHANGED) { + dev_dbg(&udev->dev, "panc changed"); + + dev_err(&udev->dev, "Not handled AFILT_PANC_CHANGED"); + } + + return ret; +} + +static int wpanusb_set_extended_addr(struct ieee802154_hw *hw) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + unsigned char *buffer; + __le64 extended_addr; + int ret = 0; + u64 addr; + + buffer = kmalloc(IEEE802154_EXTENDED_ADDR_LEN, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + ret = wpanusb_control_send(wpanusb, usb_sndctrlpipe(udev, 0), GET_EXTENDED_ADDR, buffer, + IEEE802154_EXTENDED_ADDR_LEN); + if (ret < 0) { + dev_err(&udev->dev, "failed to fetch extended address, random address set\n"); + ieee802154_random_extended_addr(&wpanusb->hw->phy->perm_extended_addr); + kfree(buffer); + return ret; + } + + memcpy(&extended_addr, buffer, IEEE802154_EXTENDED_ADDR_LEN); + /* Check if read address is not empty and the unicast bit is set correctly */ + if (!ieee802154_is_valid_extended_unicast_addr(extended_addr)) { + dev_info(&udev->dev, "no permanent extended address found, random address set\n"); + ieee802154_random_extended_addr(&wpanusb->hw->phy->perm_extended_addr); + } else { + wpanusb->hw->phy->perm_extended_addr = extended_addr; + addr = swab64((__force u64)wpanusb->hw->phy->perm_extended_addr); + dev_info(&udev->dev, "Read permanent extended address %8phC from device\n", &addr); + } + + kfree(buffer); + return ret; +} + +/* FIXME: these need to come as capabilities from the device */ +static const s32 wpanusb_powers[] = { + 300, 280, 230, 180, 130, 70, 0, -100, -200, -300, -400, -500, -700, + -900, -1200, -1700, +}; + +static int wpanusb_get_device_capabilities(struct ieee802154_hw *hw) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + unsigned char *buffer; + uint32_t valid_channels; + int ret = 0; + + buffer = kmalloc(IEEE802154_EXTENDED_ADDR_LEN, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + ret = wpanusb_control_send(wpanusb, usb_sndctrlpipe(udev, 0), GET_EXTENDED_ADDR, buffer, + IEEE802154_EXTENDED_ADDR_LEN); + if (ret < 0) { + dev_err(&udev->dev, "failed to fetch extended address, random address set\n"); + ieee802154_random_extended_addr(&wpanusb->hw->phy->perm_extended_addr); + kfree(buffer); + return ret; + } + + buffer = kmalloc(sizeof(valid_channels), GFP_NOIO); + if (!buffer) + return -ENOMEM; + ret = wpanusb_control_recv(wpanusb, GET_SUPPORTED_CHANNELS, buffer, sizeof(valid_channels)); + valid_channels = *(uint32_t *)buffer; + if (ret < 0 || !valid_channels) { + dev_err(&udev->dev, "failed to fetch valid channels, setting default valid channels\n"); + valid_channels = WPANUSB_VALID_CHANNELS; + } + + /* FIXME: these need to come from device capabilities */ + hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT; + + /* FIXME: these need to come from device capabilities */ + hw->phy->flags = WPAN_PHY_FLAG_TXPOWER; + + /* Set default and supported channels */ + hw->phy->current_page = 0; + hw->phy->current_channel = ffs(valid_channels) - 1; //set to lowest valid channel + hw->phy->supported.channels[0] = valid_channels; + + /* FIXME: these need to come from device capabilities */ + hw->phy->supported.tx_powers = wpanusb_powers; + hw->phy->supported.tx_powers_size = ARRAY_SIZE(wpanusb_powers); + hw->phy->transmit_power = hw->phy->supported.tx_powers[0]; + + kfree(buffer); + return ret; +} + +static int wpanusb_start(struct ieee802154_hw *hw) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + int ret; + + schedule_delayed_work(&wpanusb->work, 0); + + ret = wpanusb_control_send(wpanusb, usb_sndctrlpipe(udev, 0), + START, NULL, 0); + if (ret < 0) { + dev_err(&udev->dev, "Failed to start ieee802154"); + usb_kill_anchored_urbs(&wpanusb->idle_urbs); + } + + return ret; +} + +static void wpanusb_stop(struct ieee802154_hw *hw) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + int ret; + + dev_dbg(&udev->dev, "stop"); + + usb_kill_anchored_urbs(&wpanusb->idle_urbs); + + ret = wpanusb_control_send(wpanusb, usb_sndctrlpipe(udev, 0), + STOP, NULL, 0); + if (ret < 0) + dev_err(&udev->dev, "Failed to stop ieee802154"); +} + +static int wpanusb_set_txpower(struct ieee802154_hw *hw, s32 mbm) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + + dev_err(&udev->dev, "%s: Not handled, mbm %d", __func__, mbm); + + return -ENOTSUPP; +} + +static int wpanusb_set_cca_mode(struct ieee802154_hw *hw, + const struct wpan_phy_cca *cca) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + + dev_err(&udev->dev, "%s: Not handled, mode %u opt %u", + __func__, cca->mode, cca->opt); + + switch (cca->mode) { + case NL802154_CCA_ENERGY: + break; + case NL802154_CCA_CARRIER: + break; + case NL802154_CCA_ENERGY_CARRIER: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wpanusb_set_lbt(struct ieee802154_hw *hw, bool on) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + int ret = 0; + + if (on) + ret = wpanusb_control_send(wpanusb, usb_sndctrlpipe(udev, 0), + SET_LBT, NULL, 0); + + return ret; +} + +static int wpanusb_set_frame_retries(struct ieee802154_hw *hw, s8 retries) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + int ret; + + /* FIXME pass retries onwards to device */ + ret = wpanusb_control_send(wpanusb, usb_sndctrlpipe(udev, 0), + SET_FRAME_RETRIES, NULL, 0); + + return ret; +} + +static int wpanusb_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + + dev_err(&udev->dev, "%s: Not handled, mbm %d", __func__, mbm); + + return 0; +} + +static int wpanusb_set_csma_params(struct ieee802154_hw *hw, u8 min_be, + u8 max_be, u8 retries) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + + dev_err(&udev->dev, "%s: Not handled, min_be %u max_be %u retr %u", + __func__, min_be, max_be, retries); + + return 0; +} + +static int wpanusb_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on) +{ + struct wpanusb *wpanusb = hw->priv; + struct usb_device *udev = wpanusb->udev; + + dev_err(&udev->dev, "%s: Not handled, on %d", __func__, on); + + return 0; +} + +static const struct ieee802154_ops wpanusb_ops = { + .owner = THIS_MODULE, + .xmit_async = wpanusb_xmit, + .ed = wpanusb_ed, + .set_channel = wpanusb_channel, + .start = wpanusb_start, + .stop = wpanusb_stop, + .set_hw_addr_filt = wpanusb_set_hw_addr_filt, + .set_txpower = wpanusb_set_txpower, + .set_lbt = wpanusb_set_lbt, + .set_cca_mode = wpanusb_set_cca_mode, + .set_cca_ed_level = wpanusb_set_cca_ed_level, + .set_csma_params = wpanusb_set_csma_params, + .set_frame_retries = wpanusb_set_frame_retries, + .set_promiscuous_mode = wpanusb_set_promiscuous_mode, +}; + +/* ----- Setup ------------------------------------------------------------- */ + +static int wpanusb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct ieee802154_hw *hw; + struct wpanusb *wpanusb; + int ret; + + hw = ieee802154_alloc_hw(sizeof(struct wpanusb), &wpanusb_ops); + if (!hw) + return -ENOMEM; + + wpanusb = hw->priv; + wpanusb->hw = hw; + wpanusb->udev = usb_get_dev(udev); + usb_set_intfdata(interface, wpanusb); + + wpanusb->shutdown = 0; + INIT_DELAYED_WORK(&wpanusb->work, wpanusb_work_urbs); + init_usb_anchor(&wpanusb->idle_urbs); + init_usb_anchor(&wpanusb->rx_urbs); + + ret = wpanusb_alloc_urbs(wpanusb, WPANUSB_NUM_RX_URBS); + if (ret) + goto fail; + + wpanusb->tx_dr.bRequestType = VENDOR_OUT; + wpanusb->tx_dr.bRequest = TX; + wpanusb->tx_dr.wValue = cpu_to_le16(0); + + wpanusb->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!wpanusb->tx_urb) + goto fail; + + hw->parent = &udev->dev; + + ret = wpanusb_control_send(wpanusb, usb_sndctrlpipe(udev, 0), RESET, + NULL, 0); + if (ret < 0) { + dev_err(&udev->dev, "Failed to RESET ieee802154"); + goto fail; + } + + ret = wpanusb_get_device_capabilities(hw); + + if (ret < 0) { + dev_err(&udev->dev, "Failed to get device capabilities"); + goto fail; + } + + ret = wpanusb_set_extended_addr(hw); + + if (ret < 0) { + dev_err(&udev->dev, "Failed to set permanent address"); + goto fail; + } + + ret = ieee802154_register_hw(hw); + if (ret) { + dev_err(&udev->dev, "Failed to register ieee802154"); + goto fail; + } + + dev_dbg(&udev->dev, "ieee802154 ready to go"); + + return 0; + +fail: + dev_err(&udev->dev, "Failed ieee802154 probe"); + wpanusb_free_urbs(wpanusb); + usb_kill_urb(wpanusb->tx_urb); + usb_free_urb(wpanusb->tx_urb); + usb_put_dev(udev); + ieee802154_free_hw(hw); + + return ret; +} + +static void wpanusb_disconnect(struct usb_interface *interface) +{ + struct wpanusb *wpanusb = usb_get_intfdata(interface); + + wpanusb->shutdown = 1; + cancel_delayed_work_sync(&wpanusb->work); + + usb_kill_anchored_urbs(&wpanusb->rx_urbs); + wpanusb_free_urbs(wpanusb); + usb_kill_urb(wpanusb->tx_urb); + usb_free_urb(wpanusb->tx_urb); + + ieee802154_unregister_hw(wpanusb->hw); + + ieee802154_free_hw(wpanusb->hw); + + usb_set_intfdata(interface, NULL); + usb_put_dev(wpanusb->udev); +} + +/* The devices we work with */ +static const struct usb_device_id wpanusb_device_table[] = { + { + USB_DEVICE_AND_INTERFACE_INFO(WPANUSB_VENDOR_ID, + WPANUSB_PRODUCT_ID, + USB_CLASS_VENDOR_SPEC, + 0, 0), + USB_DEVICE_AND_INTERFACE_INFO(BEAGLECONNECT_VENDOR_ID, + BEAGLECONNECT_PRODUCT_ID, + USB_CLASS_VENDOR_SPEC, + 0, 0) + }, + /* end with null element */ + {} +}; +MODULE_DEVICE_TABLE(usb, wpanusb_device_table); + +static struct usb_driver wpanusb_driver = { + .name = "wpanusb", + .probe = wpanusb_probe, + .disconnect = wpanusb_disconnect, + .id_table = wpanusb_device_table, +}; +module_usb_driver(wpanusb_driver); + +MODULE_AUTHOR("Andrei Emeltchenko "); +MODULE_DESCRIPTION("WPANUSB IEEE 802.15.4 over USB Driver"); +MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/drivers/net/ieee802154/wpanusb.h b/drivers/net/ieee802154/wpanusb.h --- a/drivers/net/ieee802154/wpanusb.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/ieee802154/wpanusb.h 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Definitions shared between kernel and WPANUSB firmware + * + * Copyright (C) 2018 Intel Corp. + * + * Written by Andrei Emeltchenko + */ + +#define WPANUSB_VENDOR_ID 0x2fe3 +#define WPANUSB_PRODUCT_ID 0x0101 + +#define BEAGLECONNECT_VENDOR_ID 0x2047 +#define BEAGLECONNECT_PRODUCT_ID 0x0aa5 + +enum wpanusb_requests { + RESET, + TX, + XMIT_ASYNC, + ED, + SET_CHANNEL, + START, + STOP, + SET_SHORT_ADDR, + SET_PAN_ID, + SET_IEEE_ADDR, + SET_TXPOWER, + SET_CCA_MODE, + SET_CCA_ED_LEVEL, + SET_CSMA_PARAMS, + SET_LBT, + SET_FRAME_RETRIES, + SET_PROMISCUOUS_MODE, + GET_EXTENDED_ADDR, + GET_SUPPORTED_CHANNELS, +}; + +struct set_channel { + __u8 page; + __u8 channel; +} __packed; + +struct set_short_addr { + __le16 short_addr; +} __packed; + +struct set_pan_id { + __le16 pan_id; +} __packed; + +struct set_ieee_addr { + __le64 ieee_addr; +} __packed; diff -Naur --no-dereference a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h --- a/drivers/net/phy/mscc/mscc.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/phy/mscc/mscc.h 2024-07-07 20:37:34.668306669 -0400 @@ -196,6 +196,8 @@ #define MSCC_PHY_EXTENDED_INT_MS_EGR BIT(9) /* Extended Page 3 Registers */ +#define MSCC_PHY_SERDES_PCS_CTRL 16 +#define MSCC_PHY_SERDES_ANEG BIT(7) #define MSCC_PHY_SERDES_TX_VALID_CNT 21 #define MSCC_PHY_SERDES_TX_CRC_ERR_CNT 22 #define MSCC_PHY_SERDES_RX_VALID_CNT 28 diff -Naur --no-dereference a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c --- a/drivers/net/phy/mscc/mscc_main.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/phy/mscc/mscc_main.c 2024-07-07 20:37:34.668306669 -0400 @@ -1700,6 +1700,21 @@ PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_1000BASE_X); } +static int vsc85xx_config_inband_aneg(struct phy_device *phydev, bool enabled) +{ + u16 reg_val = 0; + int rc; + + if (enabled) + reg_val = MSCC_PHY_SERDES_ANEG; + + rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_3, + MSCC_PHY_SERDES_PCS_CTRL, MSCC_PHY_SERDES_ANEG, + reg_val); + + return rc; +} + static int vsc8584_config_init(struct phy_device *phydev) { struct vsc8531_private *vsc8531 = phydev->priv; @@ -2107,6 +2122,10 @@ return ret; ret = genphy_soft_reset(phydev); + if (ret) + return ret; + + ret = vsc85xx_config_inband_aneg(phydev, true); if (ret) return ret; diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/acx.c b/drivers/net/wireless/ti/cc33xx/acx.c --- a/drivers/net/wireless/ti/cc33xx/acx.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/acx.c 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,1008 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include "acx.h" + +int cc33xx_acx_clear_statistics(struct cc33xx *cc) +{ + struct acx_header *acx; + int ret = 0; + + cc33xx_debug(DEBUG_ACX, "acx clear statistics"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + ret = cc33xx_cmd_configure(cc, ACX_CLEAR_STATISTICS, acx, sizeof(*acx)); + if (ret < 0) { + cc33xx_warning("failed to clear firmware statistics: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int cc33xx_acx_wake_up_conditions(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 wake_up_event, u8 listen_interval) +{ + struct acx_wake_up_condition *wake_up; + int ret; + + cc33xx_debug(DEBUG_ACX, + "acx wake up conditions (wake_up_event %d listen_interval %d)", + wake_up_event, listen_interval); + + wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); + if (!wake_up) { + ret = -ENOMEM; + goto out; + } + + wake_up->wake_up_event = wake_up_event; + wake_up->listen_interval = listen_interval; + + ret = cc33xx_cmd_configure(cc, WAKE_UP_CONDITIONS_CFG, + wake_up, sizeof(*wake_up)); + if (ret < 0) { + cc33xx_warning("could not set wake up conditions: %d", ret); + goto out; + } + +out: + kfree(wake_up); + return ret; +} + +int cc33xx_acx_sleep_auth(struct cc33xx *cc, u8 sleep_auth) +{ + struct acx_sleep_auth *auth; + int ret; + + cc33xx_debug(DEBUG_ACX, "acx sleep auth %d", sleep_auth); + + auth = kzalloc(sizeof(*auth), GFP_KERNEL); + if (!auth) { + ret = -ENOMEM; + goto out; + } + + auth->sleep_auth = sleep_auth; + + ret = cc33xx_cmd_configure(cc, ACX_SLEEP_AUTH, auth, sizeof(*auth)); + if (ret < 0) { + cc33xx_error("could not configure sleep_auth to %d: %d", + sleep_auth, ret); + goto out; + } + + cc->sleep_auth = sleep_auth; +out: + kfree(auth); + return ret; +} + +int cc33xx_ble_enable(struct cc33xx *cc, u8 ble_enable) +{ + struct debug_header *buf; + int ret; + + cc33xx_debug(DEBUG_ACX, "ble enable"); + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto out; + } + + ret = cc33xx_cmd_debug(cc, BLE_ENABLE, buf, sizeof(*buf)); + if (ret < 0) { + cc33xx_error("could not enable ble"); + goto out; + } + + cc->ble_enable = 1; +out: + kfree(buf); + return ret; +} + +int cc33xx_acx_tx_power(struct cc33xx *cc, struct cc33xx_vif *wlvif, + int power) +{ + struct acx_tx_power_cfg *acx; + int ret; + + cc33xx_debug(DEBUG_ACX, "acx TX_POWER_CFG %d", power); + + if (power < CC33XX_MIN_TXPWR) { + cc33xx_warning("Configured Tx power %d dBm. Increasing to minimum %d dBm", + power, CC33XX_MIN_TXPWR); + power = CC33XX_MIN_TXPWR; + } else if (power > CC33XX_MAX_TXPWR) { + cc33xx_warning("Configured Tx power %d dBm is bigger than upper limit: %d dBm. Attenuating to max limit", + power, CC33XX_MAX_TXPWR); + power = CC33XX_MAX_TXPWR; + } + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->tx_power = power; + + ret = cc33xx_cmd_configure(cc, TX_POWER_CFG, acx, sizeof(*acx)); + if (ret < 0) { + cc33xx_warning("Configure of tx power failed: %d", ret); + goto out; + } + + wlvif->power_level = power; + +out: + kfree(acx); + return ret; +} + +static int cc33xx_acx_mem_map(struct cc33xx *cc, + struct acx_header *memeroy_map, size_t len) +{ + int ret; + + cc33xx_debug(DEBUG_ACX, "acx mem map"); + + ret = cc33xx_cmd_interrogate(cc, MEM_MAP_INTR, memeroy_map, + sizeof(struct acx_header), len); + if (ret < 0) + return ret; + + return 0; +} + +static int cc33xx_acx_get_fw_versions(struct cc33xx *cc, + struct cc33xx_acx_fw_versions *get_fw_versions, + size_t len) +{ + int ret; + + cc33xx_debug(DEBUG_ACX, "acx get FW versions"); + + ret = cc33xx_cmd_interrogate(cc, GET_FW_VERSIONS_INTR, get_fw_versions, + sizeof(struct cc33xx_acx_fw_versions), len); + if (ret < 0) + return ret; + return 0; +} + +int cc33xx_acx_slot(struct cc33xx *cc, struct cc33xx_vif *wlvif, + enum acx_slot_type slot_time) +{ + struct acx_slot *slot; + int ret; + + cc33xx_debug(DEBUG_ACX, "acx slot"); + + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) { + ret = -ENOMEM; + goto out; + } + + slot->role_id = wlvif->role_id; + slot->slot_time = slot_time; + ret = cc33xx_cmd_configure(cc, SLOT_CFG, slot, sizeof(*slot)); + + if (ret < 0) { + cc33xx_warning("failed to set slot time: %d", ret); + goto out; + } + +out: + kfree(slot); + return ret; +} + +int cc33xx_acx_group_address_tbl(struct cc33xx *cc, bool enable, void *mc_list, u32 mc_list_len) +{ + struct acx_dot11_grp_addr_tbl *acx; + int ret; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + cc33xx_debug(DEBUG_ACX, "acx group address tbl"); + + acx->enabled = enable; + acx->num_groups = mc_list_len; + memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); + + ret = cc33xx_cmd_configure(cc, DOT11_GROUP_ADDRESS_TBL, + acx, sizeof(*acx)); + if (ret < 0) { + cc33xx_warning("failed to set group addr table: %d", ret); + goto out; + } +out: + kfree(acx); + return ret; +} + +int cc33xx_acx_beacon_filter_opt(struct cc33xx *cc, struct cc33xx_vif *wlvif, + bool enable_filter) +{ + struct acx_beacon_filter_option *beacon_filter = NULL; + int ret = 0; + + cc33xx_debug(DEBUG_ACX, "acx beacon filter opt enable=%d", + enable_filter); + + if (enable_filter && + cc->conf.host_conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED) + goto out; + + beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); + if (!beacon_filter) { + ret = -ENOMEM; + goto out; + } + + beacon_filter->role_id = wlvif->role_id; + beacon_filter->enable = enable_filter; + + /* When set to zero, and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ + beacon_filter->max_num_beacons = 0; + + ret = cc33xx_cmd_configure(cc, BEACON_FILTER_OPT, + beacon_filter, sizeof(*beacon_filter)); + if (ret < 0) { + cc33xx_warning("failed to set beacon filter opt: %d", ret); + goto out; + } + +out: + kfree(beacon_filter); + return ret; +} + +int cc33xx_acx_beacon_filter_table(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + struct acx_beacon_filter_ie_table *ie_table; + struct conf_bcn_filt_rule bcn_filt_ie[32]; + struct conf_bcn_filt_rule *p_bcn_filt_ie; + int i, idx = 0; + int ret; + bool vendor_spec = false; + + cc33xx_debug(DEBUG_ACX, "acx beacon filter table"); + + ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); + if (!ie_table) { + ret = -ENOMEM; + goto out; + } + + /* configure default beacon pass-through rules */ + ie_table->role_id = wlvif->role_id; + ie_table->num_ie = 0; + p_bcn_filt_ie = &cc->conf.host_conf.conn.bcn_filt_ie0; + memcpy(bcn_filt_ie, p_bcn_filt_ie, 32 * sizeof(struct conf_bcn_filt_rule)); + for (i = 0; i < cc->conf.host_conf.conn.bcn_filt_ie_count; i++) { + struct conf_bcn_filt_rule *r = &bcn_filt_ie[i]; + + ie_table->table[idx++] = r->ie; + ie_table->table[idx++] = r->rule; + + if (r->ie == WLAN_EID_VENDOR_SPECIFIC) { + /* only one vendor specific ie allowed */ + if (vendor_spec) + continue; + + /* for vendor specific rules configure the + * additional fields + */ + memcpy(&ie_table->table[idx], r->oui, + CONF_BCN_IE_OUI_LEN); + idx += CONF_BCN_IE_OUI_LEN; + ie_table->table[idx++] = r->type; + memcpy(&ie_table->table[idx], r->version, + CONF_BCN_IE_VER_LEN); + idx += CONF_BCN_IE_VER_LEN; + vendor_spec = true; + } + + ie_table->num_ie++; + } + + ret = cc33xx_cmd_configure(cc, BEACON_FILTER_TABLE, + ie_table, sizeof(*ie_table)); + if (ret < 0) { + cc33xx_warning("failed to set beacon filter table: %d", ret); + goto out; + } + +out: + kfree(ie_table); + return ret; +} + +int cc33xx_assoc_info_cfg(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct ieee80211_sta *sta, u16 aid) +{ + struct assoc_info_cfg *cfg; + int ret; + + cc33xx_debug(DEBUG_ACX, "acx aid"); + + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) { + ret = -ENOMEM; + goto out; + } + + cfg->role_id = wlvif->role_id; + cfg->aid = cpu_to_le16(aid); + cfg->wmm_enabled = wlvif->wmm_enabled; + + cfg->nontransmitted = wlvif->nontransmitted; + cfg->bssid_index = wlvif->bssid_index; + cfg->bssid_indicator = wlvif->bssid_indicator; + cfg->ht_supported = sta->deflink.ht_cap.ht_supported; + cfg->vht_supported = sta->deflink.vht_cap.vht_supported; + cfg->has_he = sta->deflink.he_cap.has_he; + memcpy(cfg->transmitter_bssid, wlvif->transmitter_bssid, ETH_ALEN); + ret = cc33xx_cmd_configure(cc, ASSOC_INFO_CFG, cfg, sizeof(*cfg)); + if (ret < 0) { + cc33xx_warning("failed to set aid: %d", ret); + goto out; + } + +out: + kfree(cfg); + return ret; +} + +int cc33xx_acx_set_preamble(struct cc33xx *cc, struct cc33xx_vif *wlvif, + enum acx_preamble_type preamble) +{ + struct acx_preamble *acx; + int ret; + + cc33xx_debug(DEBUG_ACX, "acx_set_preamble"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->preamble = preamble; + + ret = cc33xx_cmd_configure(cc, PREAMBLE_TYPE_CFG, acx, sizeof(*acx)); + if (ret < 0) { + cc33xx_warning("Setting of preamble failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int cc33xx_acx_cts_protect(struct cc33xx *cc, struct cc33xx_vif *wlvif, + enum acx_ctsprotect_type ctsprotect) +{ + struct acx_ctsprotect *acx; + int ret; + + cc33xx_debug(DEBUG_ACX, "acx_set_ctsprotect"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->ctsprotect = ctsprotect; + + ret = cc33xx_cmd_configure(cc, CTS_PROTECTION_CFG, acx, sizeof(*acx)); + if (ret < 0) { + cc33xx_warning("Setting of ctsprotect failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int cc33xx_acx_statistics(struct cc33xx *cc, void *stats) +{ + int ret; + + cc33xx_debug(DEBUG_ACX, "acx statistics"); + + ret = cc33xx_cmd_interrogate(cc, ACX_STATISTICS, stats, + sizeof(struct acx_header), + sizeof(struct cc33xx_acx_statistics)); + if (ret < 0) { + cc33xx_warning("acx statistics failed: %d", ret); + return -ENOMEM; + } + + return 0; +} + +int cc33xx_update_ap_rates(struct cc33xx *cc, u8 role_id, + u32 basic_rates_set, u32 supported_rates) +{ + struct ap_rates_class_cfg *cfg; + int ret; + + cc33xx_debug(DEBUG_AP, "Attempting to Update Basic Rates and Supported Rates"); + + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + + if (!cfg) { + ret = -ENOMEM; + goto out; + } + + cfg->basic_rates_set = cpu_to_le32(basic_rates_set); + cfg->supported_rates = cpu_to_le32(supported_rates); + cfg->role_id = role_id; + ret = cc33xx_cmd_configure(cc, AP_RATES_CFG, cfg, sizeof(*cfg)); + if (ret < 0) { + cc33xx_warning("Updating AP Rates failed: %d", ret); + goto out; + } + +out: + kfree(cfg); + return ret; +} + +int cc33xx_tx_param_cfg(struct cc33xx *cc, struct cc33xx_vif *wlvif, u8 ac, + u8 cw_min, u16 cw_max, u8 aifsn, u16 txop, bool acm, + u8 ps_scheme, u8 is_mu_edca, u8 mu_edca_aifs, + u8 mu_edca_ecw_min_max, u8 mu_edca_timer) +{ + struct tx_param_cfg *cfg; + int ret = 0; + + cc33xx_debug(DEBUG_ACX, + "tx param cfg %d cw_ming %d cw_max %d aifs %d txop %d", + ac, cw_min, cw_max, aifsn, txop); + + cc33xx_debug(DEBUG_ACX, "tx param cfg ps_scheme %d is_mu_edca %d mu_edca_aifs %d mu_edca_ecw_min_max %d mu_edca_timer %d", + ps_scheme, is_mu_edca, mu_edca_aifs, mu_edca_ecw_min_max, + mu_edca_timer); + + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + + if (!cfg) { + ret = -ENOMEM; + goto out; + } + + cfg->role_id = wlvif->role_id; + cfg->ac = ac; + cfg->cw_min = cw_min; + cfg->cw_max = cpu_to_le16(cw_max); + cfg->aifsn = aifsn; + cfg->tx_op_limit = cpu_to_le16(txop); + cfg->acm = cpu_to_le16(acm); + cfg->ps_scheme = ps_scheme; + cfg->is_mu_edca = is_mu_edca; + cfg->mu_edca_aifs = mu_edca_aifs; + cfg->mu_edca_ecw_min_max = mu_edca_ecw_min_max; + cfg->mu_edca_timer = mu_edca_timer; + + ret = cc33xx_cmd_configure(cc, TX_PARAMS_CFG, cfg, sizeof(*cfg)); + if (ret < 0) { + cc33xx_warning("tx param cfg failed: %d", ret); + goto out; + } + +out: + kfree(cfg); + return ret; +} + +int cc33xx_acx_init_mem_config(struct cc33xx *cc) +{ + int ret; + + cc->target_mem_map = kzalloc(sizeof(*cc->target_mem_map), + GFP_KERNEL); + if (!cc->target_mem_map) { + cc33xx_error("couldn't allocate target memory map"); + return -ENOMEM; + } + + /* we now ask for the firmware built memory map */ + ret = cc33xx_acx_mem_map(cc, (void *)cc->target_mem_map, + sizeof(struct cc33xx_acx_mem_map)); + if (ret < 0) { + cc33xx_error("couldn't retrieve firmware memory map"); + kfree(cc->target_mem_map); + cc->target_mem_map = NULL; + return ret; + } + + /* initialize TX block book keeping */ + cc->tx_blocks_available = + le32_to_cpu(cc->target_mem_map->num_tx_mem_blocks); + cc33xx_debug(DEBUG_TX, "available tx blocks: %d", + cc->tx_blocks_available); + + cc33xx_debug(DEBUG_TX, + "available tx descriptor: %d available rx blocks %d", + cc->target_mem_map->num_tx_descriptor, + cc->target_mem_map->num_rx_mem_blocks); + + return 0; +} + +int cc33xx_acx_init_get_fw_versions(struct cc33xx *cc) +{ + int ret; + + cc->fw_ver = kzalloc(sizeof(*cc->fw_ver), + GFP_KERNEL); + if (!cc->fw_ver) { + cc33xx_error("couldn't allocate cc33xx_acx_fw_versions"); + return -ENOMEM; + } + + ret = cc33xx_acx_get_fw_versions(cc, (void *)cc->fw_ver, + sizeof(struct cc33xx_acx_fw_versions)); + if (ret < 0) { + cc33xx_error("couldn't retrieve firmware versions"); + kfree(cc->fw_ver); + cc->fw_ver = NULL; + return ret; + } + + return 0; +} + +int cc33xx_acx_set_ht_information(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u16 ht_operation_mode, u32 he_oper_params, + u16 he_oper_nss_set) +{ + struct cc33xx_acx_ht_information *acx; + int ret = 0; + + cc33xx_debug(DEBUG_ACX, "acx ht information setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->ht_protection = + (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); + acx->rifs_mode = 0; + acx->gf_protection = + !!(ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + + acx->dual_cts_protection = 0; + + cc33xx_debug(DEBUG_ACX, "HE operation: 0x%xm mcs: 0x%x", + he_oper_params, he_oper_nss_set); + + acx->he_operation = cpu_to_le32(he_oper_params); + acx->bss_basic_mcs_set = cpu_to_le16(he_oper_nss_set); + acx->qos_info_more_data_ack_bit = 0; + ret = cc33xx_cmd_configure(cc, BSS_OPERATION_CFG, acx, sizeof(*acx)); + + if (ret < 0) { + cc33xx_warning("acx ht information setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +/* setup BA session receiver setting in the FW. */ +int cc33xx_acx_set_ba_receiver_session(struct cc33xx *cc, u8 tid_index, u16 ssn, + bool enable, u8 peer_hlid, u8 win_size) +{ + struct cc33xx_acx_ba_receiver_setup *acx; + int ret; + + cc33xx_debug(DEBUG_ACX, "acx ba receiver session setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->hlid = peer_hlid; + acx->tid = tid_index; + acx->enable = enable; + acx->win_size = win_size; + acx->ssn = cpu_to_le16(ssn); + + ret = cc33xx_cmd_configure_failsafe(cc, BA_SESSION_RX_SETUP_CFG, + acx, sizeof(*acx), + BIT(CMD_STATUS_NO_RX_BA_SESSION)); + if (ret < 0) { + cc33xx_warning("acx ba receiver session failed: %d", ret); + goto out; + } + + /* sometimes we can't start the session */ + if (ret == CMD_STATUS_NO_RX_BA_SESSION) { + cc33xx_warning("no fw rx ba on tid %d", tid_index); + ret = -EBUSY; + goto out; + } + + ret = 0; +out: + kfree(acx); + return ret; +} + +int cc33xx_acx_tsf_info(struct cc33xx *cc, + struct cc33xx_vif *wlvif, u64 *mactime) +{ + struct cc33xx_acx_fw_tsf_information *tsf_info; + int ret = 0; + + tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); + if (!tsf_info) { + ret = -ENOMEM; + goto out; + } + + tsf_info->role_id = wlvif->role_id; + + *mactime = le32_to_cpu(tsf_info->current_tsf_low) | + ((u64)le32_to_cpu(tsf_info->current_tsf_high) << 32); + +out: + kfree(tsf_info); + return ret; +} + +int cc33xx_acx_config_ps(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + struct cc33xx_acx_config_ps *config_ps; + int ret; + + cc33xx_debug(DEBUG_ACX, "acx config ps"); + + config_ps = kzalloc(sizeof(*config_ps), GFP_KERNEL); + if (!config_ps) { + ret = -ENOMEM; + goto out; + } + + config_ps->exit_retries = cc->conf.host_conf.conn.psm_exit_retries; + config_ps->enter_retries = cc->conf.host_conf.conn.psm_entry_retries; + config_ps->null_data_rate = cpu_to_le32(wlvif->basic_rate); + + ret = cc33xx_cmd_configure(cc, ACX_CONFIG_PS, config_ps, + sizeof(*config_ps)); + + if (ret < 0) { + cc33xx_warning("acx config ps failed: %d", ret); + goto out; + } + +out: + kfree(config_ps); + return ret; +} + +int cc33xx_acx_average_rssi(struct cc33xx *cc, + struct cc33xx_vif *wlvif, s8 *avg_rssi) +{ + struct acx_roaming_stats *acx; + int ret = 0; + + cc33xx_debug(DEBUG_ACX, "acx roaming statistics"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + + ret = cc33xx_cmd_interrogate(cc, RSSI_INTR, + acx, sizeof(*acx), sizeof(*acx)); + if (ret < 0) { + cc33xx_warning("acx roaming statistics failed: %d", ret); + ret = -ENOMEM; + goto out; + } + + *avg_rssi = acx->rssi_beacon; + +out: + kfree(acx); + return ret; +} + +static const u16 cc33xx_idx_to_rate_100kbps[] = { + 10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540 +}; + +int cc33xx_acx_get_tx_rate(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct station_info *sinfo) +{ + struct acx_preamble_and_tx_rate *acx; + int ret; + + cc33xx_debug(DEBUG_ACX, "acx set tx rate"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + + ret = cc33xx_cmd_interrogate(cc, GET_PREAMBLE_AND_TX_RATE_INTR, + acx, sizeof(*acx), sizeof(*acx)); + if (ret < 0) { + cc33xx_warning("acx get preamble and tx rate failed: %d", ret); + ret = -ENOMEM; + goto out; + } + + sinfo->txrate.flags = 0; + if (acx->preamble == CONF_PREAMBLE_TYPE_AC_VHT) + sinfo->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; + else if ((acx->preamble >= CONF_PREAMBLE_TYPE_AX_SU) && + (acx->preamble <= CONF_PREAMBLE_TYPE_AX_TB_NDP_FB)) + sinfo->txrate.flags = RATE_INFO_FLAGS_HE_MCS; + else if ((acx->preamble == CONF_PREAMBLE_TYPE_N_MIXED_MODE) || + (acx->preamble == CONF_PREAMBLE_TYPE_GREENFIELD)) + sinfo->txrate.flags = RATE_INFO_FLAGS_MCS; + + if (acx->tx_rate >= CONF_HW_RATE_INDEX_MCS0) + sinfo->txrate.mcs = acx->tx_rate - CONF_HW_RATE_INDEX_MCS0; + else + sinfo->txrate.legacy = cc33xx_idx_to_rate_100kbps[acx->tx_rate - 1]; + + sinfo->txrate.nss = 1; + sinfo->txrate.bw = RATE_INFO_BW_20; + sinfo->txrate.he_gi = NL80211_RATE_INFO_HE_GI_3_2; + sinfo->txrate.he_dcm = 0; + sinfo->txrate.he_ru_alloc = 0; + sinfo->txrate.n_bonded_ch = 0; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); + +out: + kfree(acx); + return ret; +} + +#ifdef CONFIG_PM +/* Set the global behaviour of RX filters - On/Off + default action */ +int cc33xx_acx_default_rx_filter_enable(struct cc33xx *cc, bool enable, + enum rx_filter_action action) +{ + struct acx_default_rx_filter *acx; + int ret; + + cc33xx_debug(DEBUG_ACX, "acx default rx filter en: %d act: %d", + enable, action); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + acx->enable = enable; + acx->default_action = action; + acx->special_packet_bitmask = 0; + + ret = cc33xx_cmd_configure(cc, ACX_ENABLE_RX_DATA_FILTER, acx, + sizeof(*acx)); + if (ret < 0) { + cc33xx_warning("acx default rx filter enable failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +static int cc33xx_rx_filter_get_fields_size(struct cc33xx_rx_filter *filter) +{ + int i, fields_size = 0; + + for (i = 0; i < filter->num_fields; i++) { + fields_size += filter->fields[i].len - sizeof(u8 *) + + sizeof(struct cc33xx_rx_filter_field); + } + + return fields_size; +} + +static void cc33xx_rx_filter_flatten_fields(struct cc33xx_rx_filter *filter, + u8 *buf) +{ + int i; + struct cc33xx_rx_filter_field *field; + + for (i = 0; i < filter->num_fields; i++) { + field = (struct cc33xx_rx_filter_field *)buf; + + field->offset = filter->fields[i].offset; + field->flags = filter->fields[i].flags; + field->len = filter->fields[i].len; + + memcpy(&field->pattern, filter->fields[i].pattern, field->len); + buf += sizeof(struct cc33xx_rx_filter_field) - sizeof(u8 *); + buf += field->len; + } +} + +/* Configure or disable a specific RX filter pattern */ +int cc33xx_acx_set_rx_filter(struct cc33xx *cc, u8 index, bool enable, + struct cc33xx_rx_filter *filter) +{ + struct acx_rx_filter_cfg *acx; + int fields_size = 0; + int acx_size; + int ret; + + WARN_ON(enable && !filter); + WARN_ON(index >= CC33XX_MAX_RX_FILTERS); + + cc33xx_debug(DEBUG_ACX, + "acx set rx filter idx: %d enable: %d filter: %p", + index, enable, filter); + + if (enable) { + fields_size = cc33xx_rx_filter_get_fields_size(filter); + + cc33xx_debug(DEBUG_ACX, "act: %d num_fields: %d field_size: %d", + filter->action, filter->num_fields, fields_size); + } + + acx_size = ALIGN(sizeof(*acx) + fields_size, 4); + acx = kzalloc(acx_size, GFP_KERNEL); + + if (!acx) + return -ENOMEM; + + acx->enable = enable; + acx->index = index; + + if (enable) { + acx->num_fields = filter->num_fields; + acx->action = filter->action; + cc33xx_rx_filter_flatten_fields(filter, acx->fields); + } + + cc33xx_dump(DEBUG_ACX, "RX_FILTER: ", acx, acx_size); + + ret = cc33xx_cmd_configure(cc, ACX_SET_RX_DATA_FILTER, acx, acx_size); + if (ret < 0) { + cc33xx_warning("setting rx filter failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} +#endif /* CONFIG_PM */ + +/* this command is basically the same as cc33xx_acx_ht_capabilities, + * with the addition of supported rates. they should be unified in + * the next fw api change + */ +int cc33xx_acx_set_peer_cap(struct cc33xx *cc, + struct ieee80211_sta_ht_cap *ht_cap, + struct ieee80211_sta_he_cap *he_cap, + struct cc33xx_vif *wlvif, bool allow_ht_operation, + u32 rate_set, u8 hlid) +{ + struct cc33xx_acx_peer_cap *acx; + int ret = 0; + u32 ht_capabilites = 0; + u8 *cap_info = NULL; + u8 dcm_max_const_rx_mask = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK; + u8 partial_bw_ext_range = IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE; + + cc33xx_debug(DEBUG_ACX, + "acx set cap ht_supp: %d ht_cap: %d rates: 0x%x", + ht_cap->ht_supported, ht_cap->cap, rate_set); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + if (allow_ht_operation && ht_cap->ht_supported) { + /* no need to translate capabilities - use the spec values */ + ht_capabilites = ht_cap->cap; + + /* this bit is not employed by the spec but only by FW to + * indicate peer HT support + */ + ht_capabilites |= CC33XX_HT_CAP_HT_OPERATION; + + /* get data from A-MPDU parameters field */ + acx->ampdu_max_length = ht_cap->ampdu_factor; + acx->ampdu_min_spacing = ht_cap->ampdu_density; + } + + acx->ht_capabilites = cpu_to_le32(ht_capabilites); + acx->supported_rates = cpu_to_le32(rate_set); + + acx->role_id = wlvif->role_id; + acx->has_he = he_cap->has_he; + memcpy(acx->mac_cap_info, he_cap->he_cap_elem.mac_cap_info, 6); + cap_info = he_cap->he_cap_elem.phy_cap_info; + acx->nominal_packet_padding = (cap_info[8] & NOMINAL_PACKET_PADDING); + /* Max DCM constelation for RX - bits [4:3] in PHY capabilities byte 3 */ + acx->dcm_max_constelation = (cap_info[3] & dcm_max_const_rx_mask) >> 3; + acx->er_upper_supported = ((cap_info[6] & partial_bw_ext_range) != 0); + ret = cc33xx_cmd_configure(cc, PEER_CAP_CFG, acx, sizeof(*acx)); + + if (ret < 0) { + cc33xx_warning("acx ht capabilities setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int cc33xx_acx_trigger_fw_assert(struct cc33xx *cc) +{ + struct debug_header *buf; + int ret; + + cc33xx_debug(DEBUG_ACX, "acx trigger firmware assert"); + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto out; + } + + ret = cc33xx_cmd_debug(cc, TRIGGER_FW_ASSERT, buf, sizeof(*buf)); + if (ret < 0) { + cc33xx_error("failed to trigger firmware assert"); + goto out; + } + +out: + kfree(buf); + return ret; +} diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/acx.h b/drivers/net/wireless/ti/cc33xx/acx.h --- a/drivers/net/wireless/ti/cc33xx/acx.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/acx.h 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,835 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __ACX_H__ +#define __ACX_H__ + +#include "cmd.h" +#include "debug.h" + +enum { + /* Regular PS: simple sending of packets */ + PS_SCHEME_LEGACY = 0, + /* UPSD: sending a packet triggers a UPSD downstream*/ + PS_SCHEME_UPSD_TRIGGER = 1, + /* Mixed mode is partially supported: we are not going to sleep, and + * triggers (on APSD AC's) are not sent when service period ends with + * more_data = 1. + */ + PS_SCHEME_MIXED_MODE = 2, + /* Legacy PSPOLL: a PSPOLL packet will be sent before every data packet + * transmission in this queue. + */ + PS_SCHEME_LEGACY_PSPOLL = 3, + /* Scheduled APSD mode. */ + PS_SCHEME_SAPSD = 4, + /* No PSPOLL: move to active after first packet. no need to sent pspoll */ + PS_SCHEME_NOPSPOLL = 5, + + MAX_PS_SCHEME = PS_SCHEME_NOPSPOLL +}; + +/* Target's information element */ +struct acx_header { + struct cc33xx_cmd_header cmd; + + /* acx (or information element) header */ + __le16 id; + + /* payload length (not including headers */ + __le16 len; +} __packed; + +struct debug_header { + struct cc33xx_cmd_header cmd; + + /* debug (or information element) header */ + __le16 id; + + /* payload length (not including headers */ + __le16 len; +} __packed; + +enum cc33xx_role { + CC33XX_ROLE_STA = 0, + CC33XX_ROLE_IBSS, + CC33XX_ROLE_AP, + CC33XX_ROLE_DEVICE, + CC33XX_ROLE_P2P_CL, + CC33XX_ROLE_P2P_GO, + CC33XX_ROLE_MESH_POINT, + + ROLE_TRANSCEIVER = 16, + + CC33XX_INVALID_ROLE_TYPE = 0xff +}; + +enum cc33xx_psm_mode { + /* Active mode */ + CC33XX_PSM_CAM = 0, + + /* Power save mode */ + CC33XX_PSM_PS = 1, + + /* Extreme low power */ + CC33XX_PSM_ELP = 2, + + CC33XX_PSM_MAX = CC33XX_PSM_ELP, + + /* illegal out of band value of PSM mode */ + CC33XX_PSM_ILLEGAL = 0xff +}; + +struct acx_sleep_auth { + struct acx_header header; + + /* The sleep level authorization of the device. */ + /* 0 - Always active*/ + /* 1 - Power down mode: light / fast sleep*/ + /* 2 - ELP mode: Deep / Max sleep*/ + u8 sleep_auth; + u8 padding[3]; +} __packed; + +enum acx_slot_type { + SLOT_TIME_LONG = 0, + SLOT_TIME_SHORT = 1, + DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, + MAX_SLOT_TIMES = 0xFF +}; + +struct acx_slot { + struct acx_header header; + + u8 role_id; + u8 slot_time; + u8 reserved[2]; +} __packed; + +#define ACX_MC_ADDRESS_GROUP_MAX (20) +#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX) + +struct acx_dot11_grp_addr_tbl { + struct acx_header header; + + u8 enabled; + u8 num_groups; + u8 pad[2]; + u8 mac_table[ADDRESS_GROUP_MAX_LEN]; +} __packed; + +struct acx_beacon_filter_option { + struct acx_header header; + + u8 role_id; + u8 enable; + /* The number of beacons without the unicast TIM + * bit set that the firmware buffers before + * signaling the host about ready frames. + * When set to 0 and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ + u8 max_num_beacons; + u8 pad; +} __packed; + +/* ACXBeaconFilterEntry (not 221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * + * ACXBeaconFilterEntry (221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * 2 3 OUI + * 5 1 Type + * 6 2 Version + * + * + * Treatment bit mask - The information element handling: + * bit 0 - The information element is compared and transferred + * in case of change. + * bit 1 - The information element is transferred to the host + * with each appearance or disappearance. + * Note that both bits can be set at the same time. + */ + +enum { + BEACON_FILTER_TABLE_MAX_IE_NUM = 32, + BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM = 6, + BEACON_FILTER_TABLE_IE_ENTRY_SIZE = 2, + BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE = 6 +}; + +#define BEACON_FILTER_TABLE_MAX_SIZE \ + ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ + BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ + (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ + BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) + +struct acx_beacon_filter_ie_table { + struct acx_header header; + + u8 role_id; + u8 num_ie; + u8 pad[2]; + u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; +} __packed; + +struct acx_energy_detection { + struct acx_header header; + + /* The RX Clear Channel Assessment threshold in the PHY */ + __le16 rx_cca_threshold; + u8 tx_energy_detection; + u8 pad; +} __packed; + +struct acx_event_mask { + struct acx_header header; + + __le32 event_mask; + __le32 high_event_mask; /* Unused */ +} __packed; + +struct acx_tx_power_cfg { + struct acx_header header; + + u8 role_id; + s8 tx_power; + u8 padding[2]; +} __packed; + +struct acx_wake_up_condition { + struct acx_header header; + + u8 wake_up_event; + u8 listen_interval; + u8 padding[2]; +} __packed; + +struct assoc_info_cfg { + struct acx_header header; + + u8 role_id; + __le16 aid; + u8 wmm_enabled; + u8 nontransmitted; + u8 bssid_index; + u8 bssid_indicator; + u8 transmitter_bssid[ETH_ALEN]; + u8 ht_supported; + u8 vht_supported; + u8 has_he; +} __packed; + +enum acx_preamble_type { + ACX_PREAMBLE_LONG = 0, + ACX_PREAMBLE_SHORT = 1 +}; + +struct acx_preamble { + struct acx_header header; + + /* When set, the WiLink transmits the frames with a short preamble and + * when cleared, the WiLink transmits the frames with a long preamble. + */ + u8 role_id; + u8 preamble; + u8 padding[2]; +} __packed; + +enum acx_ctsprotect_type { + CTSPROTECT_DISABLE = 0, + CTSPROTECT_ENABLE = 1 +}; + +struct acx_ctsprotect { + struct acx_header header; + u8 role_id; + u8 ctsprotect; + u8 padding[2]; +} __packed; + +struct ap_rates_class_cfg { + struct acx_header header; + u8 role_id; + __le32 basic_rates_set; + __le32 supported_rates; + u8 padding[3]; +} __packed; + +struct tx_param_cfg { + struct acx_header header; + + u8 role_id; + u8 ac; + u8 aifsn; + u8 cw_min; + + __le16 cw_max; + __le16 tx_op_limit; + + __le16 acm; + + u8 ps_scheme; + + u8 is_mu_edca; + u8 mu_edca_aifs; + u8 mu_edca_ecw_min_max; + u8 mu_edca_timer; + + u8 reserved; +} __packed; + +struct cc33xx_acx_config_memory { + struct acx_header header; + + u8 rx_mem_block_num; + u8 tx_min_mem_block_num; + u8 num_stations; + u8 num_ssid_profiles; + __le32 total_tx_descriptors; + u8 dyn_mem_enable; + u8 tx_free_req; + u8 rx_free_req; + u8 tx_min; + u8 fwlog_blocks; + u8 padding[3]; +} __packed; + +struct cc33xx_acx_mem_map { + struct acx_header header; + + /* Number of blocks FW allocated for TX packets */ + __le32 num_tx_mem_blocks; + + /* Number of blocks FW allocated for RX packets */ + __le32 num_rx_mem_blocks; + + /* Number of TX descriptor that allocated. */ + __le32 num_tx_descriptor; + + __le32 tx_result; + +} __packed; + +struct cc33xx_acx_fw_versions { + struct acx_header header; + + __le16 major_version; + __le16 minor_version; + __le16 api_version; + __le16 build_version; + + u8 phy_version[6]; + u8 padding[2]; +} __packed; + +/* special capability bit (not employed by the 802.11n spec) */ +#define CC33XX_HT_CAP_HT_OPERATION BIT(16) + +/* ACX_HT_BSS_OPERATION + * Configure HT capabilities - AP rules for behavior in the BSS. + */ +struct cc33xx_acx_ht_information { + struct acx_header header; + + u8 role_id; + + /* Values: 0 - RIFS not allowed, 1 - RIFS allowed */ + u8 rifs_mode; + + /* Values: 0 - 3 like in spec */ + u8 ht_protection; + + /* Values: 0 - GF protection not required, 1 - GF protection required */ + u8 gf_protection; + + /* Values: 0 - Dual CTS protection not required, + * 1 - Dual CTS Protection required + * Note: When this value is set to 1 FW will protect all TXOP with RTS + * frame and will not use CTS-to-self regardless of the value of the + * ACX_CTS_PROTECTION information element + */ + u8 dual_cts_protection; + + __le32 he_operation; + + __le16 bss_basic_mcs_set; + u8 qos_info_more_data_ack_bit; + +} __packed; + +struct cc33xx_acx_ba_receiver_setup { + struct acx_header header; + + /* Specifies link id, range 0-31 */ + u8 hlid; + + u8 tid; + + u8 enable; + + /* Windows size in number of packets */ + u8 win_size; + + /* BA session starting sequence number. RANGE 0-FFF */ + __le16 ssn; + + u8 padding[2]; +} __packed; + +struct cc33xx_acx_fw_tsf_information { + struct acx_header header; + + u8 role_id; + u8 padding1[3]; + __le32 current_tsf_high; + __le32 current_tsf_low; + __le32 last_bttt_high; + __le32 last_tbtt_low; + u8 last_dtim_count; + u8 padding2[3]; +} __packed; + +struct cc33xx_acx_config_ps { + struct acx_header header; + + u8 exit_retries; + u8 enter_retries; + u8 padding[2]; + __le32 null_data_rate; +} __packed; + +#define ACX_RATE_MGMT_ALL_PARAMS 0xff + +struct acx_default_rx_filter { + struct acx_header header; + u8 enable; + + /* action of type FILTER_XXX */ + u8 default_action; + + /* special packet bitmask - packet that use for trigger the host */ + u8 special_packet_bitmask; + + u8 padding; +} __packed; + +struct acx_rx_filter_cfg { + struct acx_header header; + + u8 enable; + + /* 0 - WL1271_MAX_RX_FILTERS-1 */ + u8 index; + + u8 action; + + u8 num_fields; + u8 fields[]; +} __packed; + +struct acx_roaming_stats { + struct acx_header header; + + u8 role_id; + u8 pad[3]; + __le32 missed_beacons; + u8 snr_data; + u8 snr_bacon; + s8 rssi_data; + s8 rssi_beacon; +} __packed; + +enum cfg { + CTS_PROTECTION_CFG = 0, + TX_PARAMS_CFG = 1, + ASSOC_INFO_CFG = 2, + PEER_CAP_CFG = 3, + BSS_OPERATION_CFG = 4, + SLOT_CFG = 5, + PREAMBLE_TYPE_CFG = 6, + DOT11_GROUP_ADDRESS_TBL = 7, + BA_SESSION_RX_SETUP_CFG = 8, + ACX_SLEEP_AUTH = 9, + STATIC_CALIBRATION_CFG = 10, + AP_RATES_CFG = 11, + WAKE_UP_CONDITIONS_CFG = 12, + SET_ANTENNA_SELECT_CFG = 13, + TX_POWER_CFG = 14, + VENDOR_IE_CFG = 15, + START_COEX_STATISTICS_CFG = 16, + BEACON_FILTER_OPT = 17, + BEACON_FILTER_TABLE = 18, + ACX_ENABLE_RX_DATA_FILTER = 19, + ACX_SET_RX_DATA_FILTER = 20, + ACX_GET_DATA_FILTER_STATISTICS = 21, + TWT_SETUP = 22, + TWT_TERMINATE = 23, + TWT_SUSPEND = 24, + TWT_RESUME = 25, + ANT_DIV_ENABLE = 26, + ANT_DIV_SET_RSSI_THRESHOLD = 27, + ANT_DIV_SELECT_DEFAULT_ANTENNA = 28, + + LAST_CFG_VALUE, + MAX_DOT11_CFG = LAST_CFG_VALUE, + + MAX_CFG = 0xFFFF /*force enumeration to 16bits*/ +}; + +enum cmd_debug { + UPLINK_MULTI_USER_CFG, + UPLINK_MULTI_USER_DATA_CFG, + OPERATION_MODE_CTRL_CFG, + UPLINK_POWER_HEADER_CFG, + MCS_FIXED_RATE_CFG, + GI_LTF_CFG, + TRANSMIT_OMI_CFG, + TB_ONLY_CFG, + BA_SESSION_CFG, + FORCE_PS_CFG, + RATE_OVERRRIDE_CFG, + BLS_CFG, + BLE_ENABLE, + SET_TSF, + RTS_TH_CFG, + LINK_ADAPT_CFG, + CALIB_BITMAP_CFG, + PWR_PARTIAL_MODES_CFG, + TRIGGER_FW_ASSERT, + BURST_MODE_CFG, + + LAST_DEBUG_VALUE, + + MAX_DEBUG = 0xFFFF /*force enumeration to 16bits*/ + +}; + +enum interrogate_opt { + MEM_MAP_INTR = 0, + GET_FW_VERSIONS_INTR = 1, + RSSI_INTR = 2, + GET_ANTENNA_SELECT_INTR = 3, + GET_PREAMBLE_AND_TX_RATE_INTR = 4, + GET_MAC_ADDRESS = 5, + READ_COEX_STATISTICS = 6, + LAST_IE_VALUE, + MAX_DOT11_IE = LAST_IE_VALUE, + + MAX_IE = 0xFFFF /*force enumeration to 16bits*/ +}; + +enum { + ACX_STATISTICS = LAST_CFG_VALUE, + ACX_CONFIG_PS, + ACX_CLEAR_STATISTICS = 0x0054, +}; + +struct cc33xx_acx_error_stats { + __le32 error_frame_non_ctrl; + __le32 error_frame_ctrl; + __le32 error_frame_during_protection; + __le32 null_frame_tx_start; + __le32 null_frame_cts_start; + __le32 bar_retry; + __le32 num_frame_cts_nul_flid; + __le32 tx_abort_failure; + __le32 tx_resume_failure; + __le32 rx_cmplt_db_overflow_cnt; + __le32 elp_while_rx_exch; + __le32 elp_while_tx_exch; + __le32 elp_while_tx; + __le32 elp_while_nvic_pending; + __le32 rx_excessive_frame_len; + __le32 burst_mismatch; + __le32 tbc_exch_mismatch; +} __packed; + +#define NUM_OF_RATES_INDEXES 30 +struct cc33xx_acx_tx_stats { + __le32 tx_prepared_descs; + __le32 tx_cmplt; + __le32 tx_template_prepared; + __le32 tx_data_prepared; + __le32 tx_template_programmed; + __le32 tx_data_programmed; + __le32 tx_burst_programmed; + __le32 tx_starts; + __le32 tx_stop; + __le32 tx_start_templates; + __le32 tx_start_int_templates; + __le32 tx_start_fw_gen; + __le32 tx_start_data; + __le32 tx_start_null_frame; + __le32 tx_exch; + __le32 tx_retry_template; + __le32 tx_retry_data; + __le32 tx_retry_per_rate[NUM_OF_RATES_INDEXES]; + __le32 tx_exch_pending; + __le32 tx_exch_expiry; + __le32 tx_done_template; + __le32 tx_done_data; + __le32 tx_done_int_template; + __le32 tx_cfe1; + __le32 tx_cfe2; + __le32 frag_called; + __le32 frag_mpdu_alloc_failed; + __le32 frag_init_called; + __le32 frag_in_process_called; + __le32 frag_tkip_called; + __le32 frag_key_not_found; + __le32 frag_need_fragmentation; + __le32 frag_bad_mblk_num; + __le32 frag_failed; + __le32 frag_cache_hit; + __le32 frag_cache_miss; +} __packed; + +struct cc33xx_acx_rx_stats { + __le32 rx_beacon_early_term; + __le32 rx_out_of_mpdu_nodes; + __le32 rx_hdr_overflow; + __le32 rx_dropped_frame; + __le32 rx_done_stage; + __le32 rx_done; + __le32 rx_defrag; + __le32 rx_defrag_end; + __le32 rx_cmplt; + __le32 rx_pre_complt; + __le32 rx_cmplt_task; + __le32 rx_phy_hdr; + __le32 rx_timeout; + __le32 rx_rts_timeout; + __le32 rx_timeout_wa; + __le32 defrag_called; + __le32 defrag_init_called; + __le32 defrag_in_process_called; + __le32 defrag_tkip_called; + __le32 defrag_need_defrag; + __le32 defrag_decrypt_failed; + __le32 decrypt_key_not_found; + __le32 defrag_need_decrypt; + __le32 rx_tkip_replays; + __le32 rx_xfr; +} __packed; + +struct cc33xx_acx_isr_stats { + __le32 irqs; +} __packed; + +#define PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD 10 + +struct cc33xx_acx_pwr_stats { + __le32 missing_bcns_cnt; + __le32 rcvd_bcns_cnt; + __le32 connection_out_of_sync; + __le32 cont_miss_bcns_spread[PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD]; + __le32 rcvd_awake_bcns_cnt; + __le32 sleep_time_count; + __le32 sleep_time_avg; + __le32 sleep_cycle_avg; + __le32 sleep_percent; + __le32 ap_sleep_active_conf; + __le32 ap_sleep_user_conf; + __le32 ap_sleep_counter; +} __packed; + +struct cc33xx_acx_rx_filter_stats { + __le32 beacon_filter; + __le32 arp_filter; + __le32 mc_filter; + __le32 dup_filter; + __le32 data_filter; + __le32 ibss_filter; + __le32 protection_filter; + __le32 accum_arp_pend_requests; + __le32 max_arp_queue_dep; +} __packed; + +struct cc33xx_acx_rx_rate_stats { + __le32 rx_frames_per_rates[50]; +} __packed; + +#define AGGR_STATS_TX_AGG 16 +#define AGGR_STATS_RX_SIZE_LEN 16 + +struct cc33xx_acx_aggr_stats { + __le32 tx_agg_rate[AGGR_STATS_TX_AGG]; + __le32 tx_agg_len[AGGR_STATS_TX_AGG]; + __le32 rx_size[AGGR_STATS_RX_SIZE_LEN]; +} __packed; + +#define PIPE_STATS_HW_FIFO 11 + +struct cc33xx_acx_pipeline_stats { + __le32 hs_tx_stat_fifo_int; + __le32 hs_rx_stat_fifo_int; + __le32 enc_tx_stat_fifo_int; + __le32 enc_rx_stat_fifo_int; + __le32 rx_complete_stat_fifo_int; + __le32 pre_proc_swi; + __le32 post_proc_swi; + __le32 sec_frag_swi; + __le32 pre_to_defrag_swi; + __le32 defrag_to_rx_xfer_swi; + __le32 dec_packet_in; + __le32 dec_packet_in_fifo_full; + __le32 dec_packet_out; + __le16 pipeline_fifo_full[PIPE_STATS_HW_FIFO]; + __le16 padding; +} __packed; + +#define DIVERSITY_STATS_NUM_OF_ANT 2 + +struct cc33xx_acx_diversity_stats { + __le32 num_of_packets_per_ant[DIVERSITY_STATS_NUM_OF_ANT]; + __le32 total_num_of_toggles; +} __packed; + +struct cc33xx_acx_thermal_stats { + __le16 irq_thr_low; + __le16 irq_thr_high; + __le16 tx_stop; + __le16 tx_resume; + __le16 false_irq; + __le16 adc_source_unexpected; +} __packed; + +#define CC33XX_NUM_OF_CALIBRATIONS_ERRORS 18 +struct cc33xx_acx_calib_failure_stats { + __le16 fail_count[CC33XX_NUM_OF_CALIBRATIONS_ERRORS]; + __le32 calib_count; +} __packed; + +struct cc33xx_roaming_stats { + s32 rssi_level; +} __packed; + +struct cc33xx_dfs_stats { + __le32 num_of_radar_detections; +} __packed; + +struct cc33xx_acx_statistics { + struct acx_header header; + + struct cc33xx_acx_error_stats error; + struct cc33xx_acx_tx_stats tx; + struct cc33xx_acx_rx_stats rx; + struct cc33xx_acx_isr_stats isr; + struct cc33xx_acx_pwr_stats pwr; + struct cc33xx_acx_rx_filter_stats rx_filter; + struct cc33xx_acx_rx_rate_stats rx_rate; + struct cc33xx_acx_aggr_stats aggr_size; + struct cc33xx_acx_pipeline_stats pipeline; + struct cc33xx_acx_diversity_stats diversity; + struct cc33xx_acx_thermal_stats thermal; + struct cc33xx_acx_calib_failure_stats calib; + struct cc33xx_roaming_stats roaming; + struct cc33xx_dfs_stats dfs; +} __packed; + +/* ACX_PEER_CAP + * this struct is very similar to cc33xx_acx_ht_capabilities, with the + * addition of supported rates + */ +#define NOMINAL_PACKET_PADDING (0xC0) +struct cc33xx_acx_peer_cap { + struct acx_header header; + + u8 role_id; + + /* rates supported by the remote peer */ + __le32 supported_rates; + + /* bitmask of capability bits supported by the peer */ + __le32 ht_capabilites; + /* This the maximum A-MPDU length supported by the AP. The FW may not + * exceed this length when sending A-MPDUs + */ + u8 ampdu_max_length; + + /* This is the minimal spacing required when sending A-MPDUs to the AP*/ + u8 ampdu_min_spacing; + + /* HE capabilities */ + u8 mac_cap_info[8]; + + /* Nominal packet padding value, used for determining the packet extension duration */ + u8 nominal_packet_padding; + + /* HE peer support */ + bool has_he; + + u8 dcm_max_constelation; + + u8 er_upper_supported; + + u8 padding; +} __packed; + +struct acx_preamble_and_tx_rate { + struct acx_header header; + u16 tx_rate; + u8 preamble; + u8 role_id; +} __packed; + +int cc33xx_acx_wake_up_conditions(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 wake_up_event, u8 listen_interval); +int cc33xx_acx_sleep_auth(struct cc33xx *cc, u8 sleep_auth); +int cc33xx_ble_enable(struct cc33xx *cc, u8 ble_enable); +int cc33xx_acx_tx_power(struct cc33xx *cc, struct cc33xx_vif *wlvif, int power); +int cc33xx_acx_slot(struct cc33xx *cc, struct cc33xx_vif *wlvif, + enum acx_slot_type slot_time); +int cc33xx_acx_group_address_tbl(struct cc33xx *cc, bool enable, void *mc_list, u32 mc_list_len); +int cc33xx_acx_beacon_filter_opt(struct cc33xx *cc, struct cc33xx_vif *wlvif, + bool enable_filter); +int cc33xx_acx_beacon_filter_table(struct cc33xx *cc, struct cc33xx_vif *wlvif); +int cc33xx_assoc_info_cfg(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct ieee80211_sta *sta, u16 aid); +int cc33xx_acx_set_preamble(struct cc33xx *cc, struct cc33xx_vif *wlvif, + enum acx_preamble_type preamble); +int cc33xx_acx_cts_protect(struct cc33xx *cc, struct cc33xx_vif *wlvif, + enum acx_ctsprotect_type ctsprotect); +int cc33xx_acx_statistics(struct cc33xx *cc, void *stats); +int cc33xx_tx_param_cfg(struct cc33xx *cc, struct cc33xx_vif *wlvif, u8 ac, + u8 cw_min, u16 cw_max, u8 aifsn, u16 txop, bool acm, + u8 ps_scheme, u8 is_mu_edca, u8 mu_edca_aifs, + u8 mu_edca_ecw_min_max, u8 mu_edca_timer); +int cc33xx_update_ap_rates(struct cc33xx *cc, u8 role_id, + u32 basic_rates_set, u32 supported_rates); +int cc33xx_acx_init_mem_config(struct cc33xx *cc); +int cc33xx_acx_init_get_fw_versions(struct cc33xx *cc); +int cc33xx_acx_set_ht_information(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u16 ht_operation_mode, u32 he_oper_params, + u16 he_oper_nss_set); +int cc33xx_acx_set_ba_receiver_session(struct cc33xx *cc, u8 tid_index, u16 ssn, + bool enable, u8 peer_hlid, u8 win_size); +int cc33xx_acx_tsf_info(struct cc33xx *cc, + struct cc33xx_vif *wlvif, u64 *mactime); +int cc33xx_acx_config_ps(struct cc33xx *cc, struct cc33xx_vif *wlvif); +int cc33xx_acx_get_tx_rate(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct station_info *sinfo); +int cc33xx_acx_average_rssi(struct cc33xx *cc, + struct cc33xx_vif *wlvif, s8 *avg_rssi); +int cc33xx_acx_default_rx_filter_enable(struct cc33xx *cc, bool enable, + enum rx_filter_action action); +int cc33xx_acx_set_rx_filter(struct cc33xx *cc, u8 index, bool enable, + struct cc33xx_rx_filter *filter); +int cc33xx_acx_clear_statistics(struct cc33xx *cc); +int cc33xx_acx_set_peer_cap(struct cc33xx *cc, + struct ieee80211_sta_ht_cap *ht_cap, + struct ieee80211_sta_he_cap *he_cap, + struct cc33xx_vif *wlvif, bool allow_ht_operation, + u32 rate_set, u8 hlid); +int cc33xx_acx_trigger_fw_assert(struct cc33xx *cc); + +#endif /* __CC33XX_ACX_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/boot.c b/drivers/net/wireless/ti/cc33xx/boot.c --- a/drivers/net/wireless/ti/cc33xx/boot.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/boot.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include +#include + +#include "boot.h" +#include "cmd.h" +#include "debug.h" +#include "init.h" +#include "io.h" + +#define CC33XX_BOOT_TIMEOUT 2000 + +struct hwinfo_bitmap { + u32 disable_5g : 1u; + u32 disable_6g : 1u; + u32 disable_ble : 1u; + u32 disable_ble_m0plus : 1u; + u32 disable_m33 : 1u; + u64 udi : 64u; + u32 pg_version : 4u; + u32 metal_version : 4u; + u32 boot_rom_version : 4u; + u32 m3_rom_version : 4u; + u32 fuse_rom_structure_version : 4u; + u64 mac_address : 48u; + u32 device_part_number : 6u; + u32 package_type : 4u; + u32 fw_rollback_protection_1 : 32u; + u32 fw_rollback_protection_2 : 32u; + u32 fw_rollback_protection_3 : 32u; + u32 reserved : 13u; +} /* Aligned with boot code, must not be __packed */; + +union hw_info { + struct hwinfo_bitmap bitmap; + u8 bytes[sizeof(struct hwinfo_bitmap)]; +}; + +/* Called from threaded irq context */ +void cc33xx_handle_boot_irqs(struct cc33xx *cc, u32 pending_interrupts) +{ + if (WARN_ON(!cc->fw_download)) + return; + + cc33xx_debug(DEBUG_BOOT, "BOOT IRQs: 0x%x", pending_interrupts); + + atomic_or(pending_interrupts, &cc->fw_download->pending_irqs); + complete(&cc->fw_download->wait_on_irq); +} + +static u8 *fetch_container(struct cc33xx *cc, const char *container_name, + size_t *container_len) +{ + u8 *container_data = NULL; + const struct firmware *container; + int ret; + + ret = request_firmware(&container, container_name, cc->dev); + + if (ret < 0) { + cc33xx_error("could not get container %s: (%d)", + container_name, ret); + return NULL; + } + + if (container->size % 4) { + cc33xx_error("container size is not word-aligned: %zu", + container->size); + goto out; + } + + *container_len = container->size; + container_data = vmalloc(container->size); + + if (!container_data) { + cc33xx_error("could not allocate memory for the container"); + goto out; + } + + memcpy(container_data, container->data, container->size); + +out: + release_firmware(container); + return container_data; +} + +static int cc33xx_set_power_on(struct cc33xx *cc) +{ + int ret; + + msleep(CC33XX_PRE_POWER_ON_SLEEP); + ret = cc33xx_power_on(cc); + if (ret < 0) + goto out; + msleep(CC33XX_POWER_ON_SLEEP); + cc33xx_io_reset(cc); + cc33xx_io_init(cc); + +out: + return ret; +} + +static int cc33xx_chip_wakeup(struct cc33xx *cc) +{ + int ret = 0; + + cc33xx_debug(DEBUG_BOOT, "Chip wakeup"); + + ret = cc33xx_set_power_on(cc); + if (ret < 0) + goto out; + + if (!cc33xx_set_block_size(cc)) + cc->quirks &= ~CC33XX_QUIRK_TX_BLOCKSIZE_ALIGN; + +out: + return ret; +} + +static int wait_for_boot_irq(struct cc33xx *cc, u32 boot_irq_mask, + unsigned long timeout) +{ + int ret; + u32 pending_irqs; + struct cc33xx_fw_download *fw_download; + + fw_download = cc->fw_download; + + ret = wait_for_completion_interruptible_timeout(&fw_download->wait_on_irq, + msecs_to_jiffies(timeout)); + + /* Fetch pending IRQs while clearing them in fw_download */ + pending_irqs = atomic_fetch_and(0, &fw_download->pending_irqs); + pending_irqs &= ~HINT_COMMAND_COMPLETE; + + reinit_completion(&fw_download->wait_on_irq); + + if (ret == 0) { + cc33xx_error("boot IRQ timeout"); + return -1; + } else if (ret < 0) { + cc33xx_error("boot IRQ completion error %d", ret); + return -2; + } + + if (boot_irq_mask != pending_irqs) { + cc33xx_error("Unexpected IRQ received @ boot: 0x%x", + pending_irqs); + return -3; + } + + return 0; +} + +static int download_container(struct cc33xx *cc, u8 *container, size_t len) +{ + int ret = 0; + u8 *current_transfer; + size_t current_transfer_size; + u8 *const container_end = container + len; + size_t max_transfer_size = cc->fw_download->max_transfer_size; + bool is_last_transfer; + + current_transfer = container; + + while (current_transfer < container_end) { + current_transfer_size = container_end - current_transfer; + current_transfer_size = + min(current_transfer_size, max_transfer_size); + + is_last_transfer = (current_transfer + current_transfer_size >= container_end); + + ret = cmd_download_container_chunk(cc, + current_transfer, + current_transfer_size, + is_last_transfer); + + current_transfer += current_transfer_size; + + if (ret < 0) { + cc33xx_error("Chunk transfer failed"); + goto out; + } + } + +out: + return ret; +} + +static int container_download_and_wait(struct cc33xx *cc, + const char *container_name, + const u32 irq_wait_mask) +{ + int ret = -1; + u8 *container_data; + size_t container_len; + + cc33xx_debug(DEBUG_BOOT, "Downloading %s to device", container_name); + + container_data = fetch_container(cc, container_name, &container_len); + if (!container_data) + return ret; + + ret = download_container(cc, container_data, container_len); + if (ret < 0) { + cc33xx_error("Transfer error while downloading %s", + container_name); + goto out; + } + + ret = wait_for_boot_irq(cc, irq_wait_mask, CC33XX_BOOT_TIMEOUT); + + if (ret < 0) { + cc33xx_error("%s boot signal timeout", container_name); + goto out; + } + + cc33xx_debug(DEBUG_BOOT, "%s loaded successfully", container_name); + ret = 0; + +out: + vfree(container_data); + return ret; +} + +static int fw_download_alloc(struct cc33xx *cc) +{ + if (WARN_ON(cc->fw_download)) + return -EFAULT; + + cc->fw_download = kzalloc(sizeof(*cc->fw_download), GFP_KERNEL); + if (!cc->fw_download) + return -ENOMEM; + + init_completion(&cc->fw_download->wait_on_irq); + + return 0; +} + +static void fw_download_free(struct cc33xx *cc) +{ + if (WARN_ON(!cc->fw_download)) + return; + + kfree(cc->fw_download); + cc->fw_download = NULL; +} + +static int get_device_info(struct cc33xx *cc) +{ + int ret; + union hw_info hw_info; + u64 mac_address; + + ret = cmd_get_device_info(cc, hw_info.bytes, sizeof(hw_info.bytes)); + if (ret < 0) + return ret; + + cc33xx_debug(DEBUG_BOOT, + "CC33XX device info: PG version: %d, Metal version: %d, Boot ROM version: %d, M3 ROM version: %d, MAC address: 0x%llx, Device part number: %d", + hw_info.bitmap.pg_version, hw_info.bitmap.metal_version, + hw_info.bitmap.boot_rom_version, + hw_info.bitmap.m3_rom_version, + (u64)hw_info.bitmap.mac_address, + hw_info.bitmap.device_part_number); + + cc->fw_download->max_transfer_size = 640; + + mac_address = hw_info.bitmap.mac_address; + + cc->fuse_rom_structure_version = hw_info.bitmap.fuse_rom_structure_version; + cc->pg_version = hw_info.bitmap.pg_version; + cc->device_part_number = hw_info.bitmap.device_part_number; + cc->disable_5g = hw_info.bitmap.disable_5g; + cc->disable_6g = hw_info.bitmap.disable_6g; + + cc->efuse_mac_address[5] = (u8)(mac_address); + cc->efuse_mac_address[4] = (u8)(mac_address >> 8); + cc->efuse_mac_address[3] = (u8)(mac_address >> 16); + cc->efuse_mac_address[2] = (u8)(mac_address >> 24); + cc->efuse_mac_address[1] = (u8)(mac_address >> 32); + cc->efuse_mac_address[0] = (u8)(mac_address >> 40); + + return 0; +} + +int cc33xx_init_fw(struct cc33xx *cc) +{ + int ret; + + cc->max_cmd_size = CC33XX_CMD_MAX_SIZE; + + ret = fw_download_alloc(cc); + if (ret < 0) + return ret; + + reinit_completion(&cc->fw_download->wait_on_irq); + + ret = cc33xx_chip_wakeup(cc); + if (ret < 0) + goto power_off; + + cc33xx_enable_interrupts(cc); + + ret = wait_for_boot_irq(cc, HINT_ROM_LOADER_INIT_COMPLETE, + CC33XX_BOOT_TIMEOUT); + if (ret < 0) + goto disable_irq; + + ret = get_device_info(cc); + if (ret < 0) + goto disable_irq; + + ret = container_download_and_wait(cc, SECOND_LOADER_NAME, + HINT_SECOND_LOADER_INIT_COMPLETE); + if (ret < 0) + goto disable_irq; + + ret = container_download_and_wait(cc, FW_NAME, + HINT_FW_WAKEUP_COMPLETE); + if (ret < 0) + goto disable_irq; + + ret = cc33xx_download_ini_params_and_wait(cc); + + if (ret < 0) + goto disable_irq; + + ret = wait_for_boot_irq(cc, HINT_FW_INIT_COMPLETE, CC33XX_BOOT_TIMEOUT); + + if (ret < 0) + goto disable_irq; + + ret = cc33xx_hw_init(cc); + if (ret < 0) + goto disable_irq; + + /* Now we know if 11a is supported (info from the INI File), so disable + * 11a channels if not supported + */ + cc->enable_11a = cc->conf.core.enable_5ghz; + + cc33xx_debug(DEBUG_MAC80211, "11a is %ssupported", + cc->enable_11a ? "" : "not "); + + cc->state = CC33XX_STATE_ON; + ret = 0; + goto out; + +disable_irq: + cc33xx_disable_interrupts_nosync(cc); + +power_off: + cc33xx_power_off(cc); + +out: + fw_download_free(cc); + return ret; +} diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/boot.h b/drivers/net/wireless/ti/cc33xx/boot.h --- a/drivers/net/wireless/ti/cc33xx/boot.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/boot.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __BOOT_H__ +#define __BOOT_H__ + +#include "cc33xx.h" + +int cc33xx_init_fw(struct cc33xx *cc); + +void cc33xx_handle_boot_irqs(struct cc33xx *cc, u32 pending_interrupts); + +#define SECOND_LOADER_NAME "ti-connectivity/cc33xx_2nd_loader.bin" +#define FW_NAME "ti-connectivity/cc33xx_fw.bin" + +struct cc33xx_fw_download { + atomic_t pending_irqs; + struct completion wait_on_irq; + size_t max_transfer_size; +}; + +#endif /* __BOOT_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/cc33xx.h b/drivers/net/wireless/ti/cc33xx/cc33xx.h --- a/drivers/net/wireless/ti/cc33xx/cc33xx.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/cc33xx.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,483 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __CC33XX_H__ +#define __CC33XX_H__ + +#include "cc33xx_i.h" +#include "rx.h" + +/* The maximum number of Tx descriptors in all chip families */ +#define CC33XX_MAX_TX_DESCRIPTORS 32 + +#define CC33XX_CMD_MAX_SIZE (896) +#define CC33XX_INI_PARAM_COMMAND_SIZE (16UL) +#define CC33XX_INI_CMD_MAX_SIZE (CC33X_CONF_SIZE + CC33XX_INI_PARAM_COMMAND_SIZE + sizeof(int)) + +#define CC33XX_CMD_BUFFER_SIZE ((CC33XX_INI_CMD_MAX_SIZE > CC33XX_CMD_MAX_SIZE)\ + ? CC33XX_INI_CMD_MAX_SIZE : CC33XX_CMD_MAX_SIZE) + +#define CC33XX_NUM_MAC_ADDRESSES 3 + +#define CC33XX_AGGR_BUFFER_SIZE (8 * PAGE_SIZE) + +#define CC33XX_NUM_TX_DESCRIPTORS 32 +#define CC33XX_NUM_RX_DESCRIPTORS 32 + +#define CC33XX_RX_BA_MAX_SESSIONS 13 + +#define CC33XX_MAX_AP_STATIONS 16 + +struct cc33xx_tx_hw_descr; +struct cc33xx_rx_descriptor; +struct partial_rx_frame; +struct core_fw_status; +struct core_status; + +enum wl_rx_buf_align; + +struct cc33xx_stats { + void *fw_stats; + unsigned long fw_stats_update; + unsigned int retry_count; + unsigned int excessive_retries; +}; + +struct cc33xx_ant_diversity { + u8 diversity_enable; + s8 rssi_threshold; + u8 default_antenna; + u8 padding; +}; + +struct cc33xx { + bool initialized; + struct ieee80211_hw *hw; + bool mac80211_registered; + + struct device *dev; + struct platform_device *pdev; + + struct cc33xx_if_operations *if_ops; + + int wakeirq; + + /* Protects all mac80211 operations and parts of Rx, Tx and IRQ handling. + * All functions postfixed with "_locked" (i.e, cc33xx_irq_locked) + * assume this lock is held by caller. + */ + struct mutex mutex; + + /* Used independently from above mutex to protect short critical sections. + * Though many of these sections may theoretically execute in parallel, a + * single lock will be used for simplicity. + */ + spinlock_t cc_lock; + + enum cc33xx_state state; + bool plt; + enum plt_mode plt_mode; + u8 plt_role_id; + u8 fem_manuf; + u8 last_vif_count; + + struct core_status *core_status; + u8 last_fw_rls_idx; + u8 command_result[CC33XX_CMD_MAX_SIZE]; + u16 result_length; + struct partial_rx_frame partial_rx; + + unsigned long flags; + + void *nvs_mac_addr; + size_t nvs_mac_addr_len; + struct cc33xx_fw_download *fw_download; + + struct mac_address addresses[CC33XX_NUM_MAC_ADDRESSES]; + + unsigned long links_map[BITS_TO_LONGS(CC33XX_MAX_LINKS)]; + unsigned long roles_map[BITS_TO_LONGS(CC33XX_MAX_ROLES)]; + unsigned long roc_map[BITS_TO_LONGS(CC33XX_MAX_ROLES)]; + unsigned long rate_policies_map[BITS_TO_LONGS(CC33XX_MAX_RATE_POLICIES)]; + + u8 session_ids[CC33XX_MAX_LINKS]; + + struct list_head wlvif_list; + + u8 sta_count; + u8 ap_count; + + struct cc33xx_acx_mem_map *target_mem_map; + + /* Accounting for allocated / available TX blocks on HW */ + + u32 tx_blocks_available; + u32 tx_allocated_blocks; + + /* Accounting for allocated / available Tx packets in HW */ + + u32 tx_allocated_pkts[NUM_TX_QUEUES]; + + /* Time-offset between host and chipset clocks */ + + /* Frames scheduled for transmission, not handled yet */ + int tx_queue_count[NUM_TX_QUEUES]; + unsigned long queue_stop_reasons[NUM_TX_QUEUES * CC33XX_NUM_MAC_ADDRESSES]; + + /* Frames received, not handled yet by mac80211 */ + struct sk_buff_head deferred_rx_queue; + + /* Frames sent, not returned yet to mac80211 */ + struct sk_buff_head deferred_tx_queue; + + struct work_struct tx_work; + struct workqueue_struct *freezable_wq; + + /*freezable wq for netstack_work*/ + struct workqueue_struct *freezable_netstack_wq; + + /* Pending TX frames */ + unsigned long tx_frames_map[BITS_TO_LONGS(CC33XX_MAX_TX_DESCRIPTORS)]; + struct sk_buff *tx_frames[CC33XX_MAX_TX_DESCRIPTORS]; + int tx_frames_cnt; + + /* FW Rx counter */ + u32 rx_counter; + + /* Intermediate buffer, used for packet aggregation */ + u8 *aggr_buf; + u32 aggr_buf_size; + size_t max_transaction_len; + + /* Reusable dummy packet template */ + struct sk_buff *dummy_packet; + + /* Network stack work */ + struct work_struct netstack_work; + /* FW log buffer */ + u8 *fwlog; + + /* Number of valid bytes in the FW log buffer */ + ssize_t fwlog_size; + + /* Hardware recovery work */ + struct work_struct recovery_work; + + struct work_struct irq_deferred_work; + + /* Reg domain last configuration */ + DECLARE_BITMAP(reg_ch_conf_last, 64); + /* Reg domain pending configuration */ + DECLARE_BITMAP(reg_ch_conf_pending, 64); + + /* Lock-less list for deferred event handling */ + struct llist_head event_list; + /* The mbox event mask */ + u32 event_mask; + /* events to unmask only when ap interface is up */ + u32 ap_event_mask; + + /* Are we currently scanning */ + struct cc33xx_vif *scan_wlvif; + struct cc33xx_scan scan; + struct delayed_work scan_complete_work; + + struct ieee80211_vif *roc_vif; + struct delayed_work roc_complete_work; + + struct cc33xx_vif *sched_vif; + + u8 mac80211_scan_stopped; + + /* The current band */ + enum nl80211_band band; + + /* in dBm */ + int power_level; + + struct cc33xx_stats stats; + + __le32 *buffer_32; + + /* Current chipset configuration */ + struct cc33xx_conf_file conf; + + bool enable_11a; + + /* bands supported by this instance of cc33xx */ + struct ieee80211_supported_band bands[CC33XX_NUM_BANDS]; + + /* wowlan trigger was configured during suspend. + * (currently, only "ANY" and "PATTERN" trigger is supported) + */ + + bool keep_device_power; + + /* AP-mode - links indexed by HLID. The global and broadcast links + * are always active. + */ + struct cc33xx_link links[CC33XX_MAX_LINKS]; + + /* number of currently active links */ + int active_link_count; + + /* AP-mode - a bitmap of links currently in PS mode according to FW */ + unsigned long ap_fw_ps_map; + + /* AP-mode - a bitmap of links currently in PS mode in mac80211 */ + unsigned long ap_ps_map; + + /* Quirks of specific hardware revisions */ + unsigned int quirks; + + /* number of currently active RX BA sessions */ + int ba_rx_session_count; + + /* AP-mode - number of currently connected stations */ + int active_sta_count; + + /* last wlvif we transmitted from */ + struct cc33xx_vif *last_wlvif; + + /* work to fire when Tx is stuck */ + struct delayed_work tx_watchdog_work; + + /* HW HT (11n) capabilities */ + struct ieee80211_sta_ht_cap ht_cap[CC33XX_NUM_BANDS]; + + /* the current dfs region */ + enum nl80211_dfs_regions dfs_region; + bool radar_debug_mode; + + /* RX Data filter rule state - enabled/disabled */ + /* used in CONFIG PM AND W8 Code */ + unsigned long rx_filter_enabled[BITS_TO_LONGS(CC33XX_MAX_RX_FILTERS)]; + + /* mutex for protecting the tx_flush function */ + struct mutex flush_mutex; + + /* sleep auth value currently configured to FW */ + int sleep_auth; + + /*ble_enable value - 1=enabled, 0=disabled. */ + int ble_enable; + + /* parameters for joining a TWT agreement */ + int min_wake_duration_usec; + int min_wake_interval_mantissa; + int min_wake_interval_exponent; + int max_wake_interval_mantissa; + int max_wake_interval_exponent; + + /* the number of allocated MAC addresses in this chip */ + int num_mac_addr; + + /* sta role index - if 0 - wlan0 primary station interface, + * if 1 - wlan2 - secondary station interface + */ + u8 sta_role_idx; + + u16 max_cmd_size; + + struct completion nvs_loading_complete; + struct completion command_complete; + + /* dynamic fw traces */ + u32 dynamic_fw_traces; + + /* buffer for sending commands to FW */ + u8 cmd_buf[CC33XX_CMD_BUFFER_SIZE]; + + /* number of keys requiring extra spare mem-blocks */ + int extra_spare_key_count; + + u8 efuse_mac_address[ETH_ALEN]; + + u32 fuse_rom_structure_version; + u32 device_part_number; + u32 pg_version; + u8 disable_5g; + u8 disable_6g; + + struct cc33xx_acx_fw_versions *fw_ver; + + u8 antenna_selection; + + /* burst mode cfg */ + u8 burst_disable; + + struct cc33xx_ant_diversity diversity; +}; + +void cc33xx_update_inconn_sta(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct cc33xx_station *wl_sta, bool in_conn); + +void cc33xx_irq(void *cookie); + +/* Quirks */ + +/* the first start_role(sta) sometimes doesn't work on wl12xx */ +#define CC33XX_QUIRK_START_STA_FAILS BIT(1) + +/* wl127x and SPI don't support SDIO block size alignment */ +#define CC33XX_QUIRK_TX_BLOCKSIZE_ALIGN BIT(2) + +/* means aggregated Rx packets are aligned to a SDIO block */ +#define CC33XX_QUIRK_RX_BLOCKSIZE_ALIGN BIT(3) + +/* pad only the last frame in the aggregate buffer */ +#define CC33XX_QUIRK_TX_PAD_LAST_FRAME BIT(7) + +/* extra header space is required for TKIP */ +#define CC33XX_QUIRK_TKIP_HEADER_SPACE BIT(8) + +/* Some firmwares not support sched scans while connected */ +#define CC33XX_QUIRK_NO_SCHED_SCAN_WHILE_CONN BIT(9) + +/* separate probe response templates for one-shot and sched scans */ +#define CC33XX_QUIRK_DUAL_PROBE_TMPL BIT(10) + +/* Firmware requires reg domain configuration for active calibration */ +#define CC33XX_QUIRK_REGDOMAIN_CONF BIT(11) + +/* The FW only support a zero session id for AP */ +#define CC33XX_QUIRK_AP_ZERO_SESSION_ID BIT(12) + +/* TODO: move all these common registers and values elsewhere */ +#define HW_ACCESS_ELP_CTRL_REG 0x1FFFC + +enum CC33xx_FRAME_FORMAT { + CC33xx_B_SHORT = 0, + CC33xx_B_LONG, + CC33xx_LEGACY_OFDM, + CC33xx_HT_MF, + CC33xx_HT_GF, + CC33xx_HE_SU, + CC33xx_HE_MU, + CC33xx_HE_SU_ER, + CC33xx_HE_TB, + CC33xx_HE_TB_NDP_FB, + CC33xx_VHT +}; + +/* CC33xx HW Common Definitions */ + +#define HOST_SYNC_PATTERN 0x5C5C5C5C +#define DEVICE_SYNC_PATTERN 0xABCDDCBA +#define NAB_DATA_ADDR 0x0000BFF0 +#define NAB_CONTROL_ADDR 0x0000BFF8 +#define NAB_STATUS_ADDR 0x0000BFFC + +#define NAB_SEND_CMD 0x940d +#define NAB_SEND_FLAGS 0x08 +#define CC33xx_INTERNAL_DESC_SIZE 200 +#define NAB_EXTRA_BYTES 4 + +#define TX_RESULT_QUEUE_SIZE 108 + +struct control_info_descriptor { + __le16 type_and_length; +}; + +enum control_message_type { + CTRL_MSG_NONE = 0, + CTRL_MSG_EVENT = 1, + CTRL_MSG_COMMND_COMPLETE = 2 +}; + +struct core_fw_status { + u8 tx_result_queue_index; + u8 reserved1[3]; + u8 tx_result_queue[TX_RESULT_QUEUE_SIZE]; + + /* A bitmap (where each bit represents a single HLID) + * to indicate PS/Active mode of the link + */ + __le32 link_ps_bitmap; + + /* A bitmap (where each bit represents a single HLID) + * to indicate if the station is in Fast mode + */ + __le32 link_fast_bitmap; + + /* A bitmap (where each bit represents a single HLID) + * to indicate if a links is suspended/aboout to be suspended + */ + __le32 link_suspend_bitmap; + + /* Host TX Flow Control descriptor per AC threshold */ + u8 tx_flow_control_ac_threshold; + + /* Host TX Flow Control descriptor PS link threshold */ + u8 tx_ps_threshold; + + /* Host TX Flow Control descriptor Suspended link threshold */ + u8 tx_suspend_threshold; + + /* Host TX Flow Control descriptor Slow link threshold */ + u8 tx_slow_link_prio_threshold; + + /* Host TX Flow Control descriptor Fast link threshold */ + u8 tx_fast_link_prio_threshold; + + /* Host TX Flow Control descriptor Stop Slow link threshold */ + u8 tx_slow_stop_threshold; + + /* Host TX Flow Control descriptor Stop Fast link threshold */ + u8 tx_fast_stop_threshold; + + u8 reserved2; + /* Additional information can be added here */ +} __packed; + +struct core_status { + __le32 block_pad[28]; + __le32 host_interrupt_status; + __le32 rx_status; + struct core_fw_status fw_info; + __le32 tsf; +} __packed; + +struct NAB_header { + __le32 sync_pattern; + __le16 opcode; + __le16 len; +}; + +/* rx_status lower bytes hold the rx byte count */ +#define RX_BYTE_COUNT_MASK 0xFFFF + +#define HINT_NEW_TX_RESULT 0x1 +#define HINT_COMMAND_COMPLETE 0x2 +#define HINT_ROM_LOADER_INIT_COMPLETE 0x8 +#define HINT_SECOND_LOADER_INIT_COMPLETE 0x10 +#define HINT_FW_WAKEUP_COMPLETE 0x20 +#define HINT_FW_INIT_COMPLETE 0x40 +#define HINT_GENERAL_ERROR 0x80000000 + +#define BOOT_TIME_INTERRUPTS (\ + HINT_ROM_LOADER_INIT_COMPLETE | \ + HINT_SECOND_LOADER_INIT_COMPLETE | \ + HINT_FW_WAKEUP_COMPLETE | \ + HINT_FW_INIT_COMPLETE) + +struct NAB_tx_header { + __le32 sync; + __le16 opcode; + __le16 len; + __le16 desc_length; + u8 sd; + u8 flags; +} __packed; + +struct NAB_rx_header { + __le32 cnys; + __le16 opcode; + __le16 len; + __le32 rx_desc; + __le32 reserved; +} __packed; + +#endif /* __CC33XX_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/cc33xx_i.h b/drivers/net/wireless/ti/cc33xx/cc33xx_i.h --- a/drivers/net/wireless/ti/cc33xx/cc33xx_i.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/cc33xx_i.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,459 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __CC33XX_I_H__ +#define __CC33XX_I_H__ + +#include +#include + +#include "conf.h" + +struct cc33xx_family_data { + const char *name; + const char *nvs_name; /* nvs file */ + const char *cfg_name; /* cfg file */ +}; + +#define CC33XX_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) +#define CC33XX_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) +#define CC33XX_TX_SQN_POST_RECOVERY_PADDING 0xff +/* Use smaller padding for GEM, as some APs have issues when it's too big */ +#define CC33XX_TX_SQN_POST_RECOVERY_PADDING_GEM 0x20 + +#define CC33XX_CIPHER_SUITE_GEM 0x00147201 + +#define CC33XX_BUSY_WORD_LEN (sizeof(u32)) + +#define CC33XX_DEFAULT_BEACON_INT 100 + +#define CC33XX_MAX_ROLES 4 +#define CC33XX_INVALID_ROLE_ID 0xff +#define CC33XX_INVALID_LINK_ID 0xff + +#define CC33XX_MAX_LINKS 21 + +/* the driver supports the 2.4Ghz and 5Ghz bands */ +#define CC33XX_NUM_BANDS 2 + +#define CC33XX_MAX_RATE_POLICIES 16 + +/* Defined by FW as 0. Will not be freed or allocated. */ +#define CC33XX_SYSTEM_HLID 0 + +/* When in AP-mode, we allow (at least) this number of packets + * to be transmitted to FW for a STA in PS-mode. Only when packets are + * present in the FW buffers it will wake the sleeping STA. We want to put + * enough packets for the driver to transmit all of its buffered data before + * the STA goes to sleep again. But we don't want to take too much memory + * as it might hurt the throughput of active STAs. + */ +#define CC33XX_PS_STA_MAX_PACKETS 2 + +#define CC33XX_AP_BSS_INDEX 0 + +enum cc33xx_state { + CC33XX_STATE_OFF, + CC33XX_STATE_RESTARTING, + CC33XX_STATE_ON, +}; + +struct cc33xx; + +#define NUM_TX_QUEUES 4 + +#define CC33XX_MAX_CHANNELS 64 +struct cc33xx_scan { + struct cfg80211_scan_request *req; + unsigned long scanned_ch[BITS_TO_LONGS(CC33XX_MAX_CHANNELS)]; + bool failed; + u8 state; + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; + size_t ssid_len; +}; + +struct cc33xx_if_operations { + void (*interface_claim)(struct device *child); + void (*interface_release)(struct device *child); + int __must_check (*read)(struct device *child, int addr, void *buf, + size_t len, bool fixed); + int __must_check (*write)(struct device *child, int addr, void *buf, + size_t len, bool fixed); + void (*reset)(struct device *child); + void (*init)(struct device *child); + int (*power)(struct device *child, bool enable); + void (*set_block_size)(struct device *child, unsigned int blksz); + size_t (*get_max_transaction_len)(struct device *child); + void (*set_irq_handler)(struct device *child, void *irq_handler); + void (*enable_irq)(struct device *child); + void (*disable_irq)(struct device *child); +}; + +struct cc33xx_platdev_data { + struct cc33xx_if_operations *if_ops; + const struct cc33xx_family_data *family; + void (*irq_handler)(struct platform_device *pdev); + int gpio_irq_num; + + bool ref_clock_xtal; /* specify whether the clock is XTAL or not */ + bool pwr_in_suspend; +}; + +#define MAX_NUM_KEYS 14 +#define MAX_KEY_SIZE 32 + +struct cc33xx_ap_key { + u8 id; + u8 key_type; + u8 key_size; + u8 key[MAX_KEY_SIZE]; + u8 hlid; + u32 tx_seq_32; + u16 tx_seq_16; +}; + +enum cc33xx_flags { + CC33XX_FLAG_GPIO_POWER, + CC33XX_FLAG_TX_PENDING, + CC33XX_FLAG_IN_ELP, + CC33XX_FLAG_FW_TX_BUSY, + CC33XX_FLAG_DUMMY_PACKET_PENDING, + CC33XX_FLAG_SUSPENDED, + CC33XX_FLAG_PENDING_WORK, + CC33XX_FLAG_SOFT_GEMINI, + CC33XX_FLAG_DRIVER_REMOVED, + CC33XX_FLAG_RECOVERY_IN_PROGRESS, + CC33XX_FLAG_VIF_CHANGE_IN_PROGRESS, + CC33XX_FLAG_IO_FAILED, + CC33XX_FLAG_REINIT_TX_WDOG, +}; + +enum cc33xx_vif_flags { + WLVIF_FLAG_INITIALIZED, + WLVIF_FLAG_STA_ASSOCIATED, + WLVIF_FLAG_STA_AUTHORIZED, + WLVIF_FLAG_IBSS_JOINED, + WLVIF_FLAG_AP_STARTED, + WLVIF_FLAG_IN_PS, + WLVIF_FLAG_STA_STATE_SENT, + WLVIF_FLAG_PSPOLL_FAILURE, + WLVIF_FLAG_CS_PROGRESS, + WLVIF_FLAG_AP_PROBE_RESP_SET, + WLVIF_FLAG_IN_USE, + WLVIF_FLAG_ACTIVE, + WLVIF_FLAG_BEACON_DISABLED, +}; + +struct cc33xx_vif; + +struct cc33xx_link { + /* AP-mode - TX queue per AC in link */ + struct sk_buff_head tx_queue[NUM_TX_QUEUES]; + + /* accounting for allocated / freed packets in FW */ + u8 allocated_pkts; + u8 prev_freed_pkts; + + u8 addr[ETH_ALEN]; + + /* bitmap of TIDs where RX BA sessions are active for this link */ + u8 ba_bitmap; + + /* the last fw rate index we used for this link */ + u8 fw_rate_idx; + + /* the last fw rate [Mbps] we used for this link */ + u8 fw_rate_mbps; + + /* The wlvif this link belongs to. Might be null for global links */ + struct cc33xx_vif *wlvif; + + /* total freed FW packets on the link - used for tracking the + * AES/TKIP PN across recoveries. Re-initialized each time + * from the cc33xx_station structure. + */ + u64 total_freed_pkts; +}; + +#define CC33XX_MAX_RX_FILTERS 5 +#define CC33XX_RX_FILTER_MAX_FIELDS 8 + +#define CC33XX_RX_FILTER_ETH_HEADER_SIZE 14 +#define CC33XX_RX_FILTER_MAX_FIELDS_SIZE 95 +#define RX_FILTER_FIELD_OVERHEAD \ + (sizeof(struct cc33xx_rx_filter_field) - sizeof(u8 *)) +#define CC33XX_RX_FILTER_MAX_PATTERN_SIZE \ + (CC33XX_RX_FILTER_MAX_FIELDS_SIZE - RX_FILTER_FIELD_OVERHEAD) + +#define CC33XX_RX_FILTER_FLAG_IP_HEADER 0 +#define CC33XX_RX_FILTER_FLAG_ETHERNET_HEADER BIT(1) + +struct ieee80211_header { + __le16 frame_ctl; + __le16 duration_id; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[]; +} __packed; + +enum rx_filter_action { + FILTER_DROP = 0, + FILTER_SIGNAL = 1, + FILTER_FW_HANDLE = 2 +}; + +enum plt_mode { + PLT_OFF = 0, + PLT_ON = 1, + PLT_FEM_DETECT = 2, + PLT_CHIP_AWAKE = 3 +}; + +struct cc33xx_rx_filter_field { + __le16 offset; + u8 len; + u8 flags; + u8 *pattern; +} __packed; + +struct cc33xx_rx_filter { + u8 action; + int num_fields; + struct cc33xx_rx_filter_field fields[CC33XX_RX_FILTER_MAX_FIELDS]; +}; + +struct cc33xx_station { + u8 hlid; + bool in_connection; + + /* total freed FW packets on the link to the STA - used for tracking the + * AES/TKIP PN across recoveries. Re-initialized each time from the + * cc33xx_station structure. + * Used in both AP and STA mode. + */ + u64 total_freed_pkts; +}; + +struct cc33xx_vif { + struct cc33xx *cc; + struct list_head list; + unsigned long flags; + u8 bss_type; + u8 p2p; /* we are using p2p role */ + u8 role_id; + + /* sta/ibss specific */ + u8 dev_role_id; + u8 dev_hlid; + + union { + struct { + u8 hlid; + + u8 basic_rate_idx; + u8 ap_rate_idx; + u8 p2p_rate_idx; + + bool qos; + /* channel type we started the STA role with */ + enum nl80211_channel_type role_chan_type; + } sta; + struct { + u8 global_hlid; + u8 bcast_hlid; + + /* HLIDs bitmap of associated stations */ + unsigned long sta_hlid_map[BITS_TO_LONGS(CC33XX_MAX_LINKS)]; + + /* recoreded keys - set here before AP startup */ + struct cc33xx_ap_key *recorded_keys[MAX_NUM_KEYS]; + + u8 mgmt_rate_idx; + u8 bcast_rate_idx; + u8 ucast_rate_idx[CONF_TX_MAX_AC_COUNT]; + } ap; + }; + + /* the hlid of the last transmitted skb */ + int last_tx_hlid; + + /* counters of packets per AC, across all links in the vif */ + int tx_queue_count[NUM_TX_QUEUES]; + + unsigned long links_map[BITS_TO_LONGS(CC33XX_MAX_LINKS)]; + + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; + u8 ssid_len; + + /* The current band */ + enum nl80211_band band; + int channel; + enum nl80211_channel_type channel_type; + + u32 bitrate_masks[CC33XX_NUM_BANDS]; + u32 basic_rate_set; + + /* currently configured rate set: + * bits 0-15 - 802.11abg rates + * bits 16-23 - 802.11n MCS index mask + * support only 1 stream, thus only 8 bits for the MCS rates (0-7). + */ + u32 basic_rate; + u32 rate_set; + + /* probe-req template for the current AP */ + struct sk_buff *probereq; + + /* Beaconing interval (needed for ad-hoc) */ + u32 beacon_int; + + /* Default key (for WEP) */ + u32 default_key; + + /* Our association ID */ + u16 aid; + + /* retry counter for PSM entries */ + u8 psm_entry_retry; + + /* in dBm */ + int power_level; + + int rssi_thold; + int last_rssi_event; + + /* save the current encryption type for auto-arp config */ + u8 encryption_type; + __be32 ip_addr; + + /* RX BA constraint value */ + bool ba_support; + bool ba_allowed; + + bool wmm_enabled; + + bool radar_enabled; + + struct delayed_work channel_switch_work; + struct delayed_work connection_loss_work; + + /* number of in connection stations */ + int inconn_count; + + /* This vif's queues are mapped to mac80211 HW queues as: + * VO - hw_queue_base + * VI - hw_queue_base + 1 + * BE - hw_queue_base + 2 + * BK - hw_queue_base + 3 + */ + int hw_queue_base; + + /* do we have a pending auth reply? (and ROC) */ + bool ap_pending_auth_reply; + + /* time when we sent the pending auth reply */ + unsigned long pending_auth_reply_time; + + /* work for canceling ROC after pending auth reply */ + struct delayed_work pending_auth_complete_work; + + struct delayed_work roc_timeout_work; + + /* update rate conrol */ + enum ieee80211_sta_rx_bandwidth rc_update_bw; + struct ieee80211_sta_ht_cap rc_ht_cap; + struct work_struct rc_update_work; + + /* total freed FW packets on the link. + * For STA this holds the PN of the link to the AP. + * For AP this holds the PN of the broadcast link. + */ + u64 total_freed_pkts; + + /* for MBSSID: this BSS is a nontransmitted BSS profile + * Relevant for STA role + */ + bool nontransmitted; + + /* for MBSSID: update transmitter BSSID */ + u8 transmitter_bssid[ETH_ALEN]; + + /* for MBSSID: BSSID index */ + u8 bssid_index; + + /* for MBSSID: BSSID indicator */ + u8 bssid_indicator; + + /* for STA: if connection established and has HE support*/ + u8 sta_has_he; + + /* This struct must be last! + * data that has to be saved acrossed reconfigs (e.g. recovery) + * should be declared in this struct. + */ + u8 persistent[]; +}; + +static inline struct cc33xx_vif *cc33xx_vif_to_data(struct ieee80211_vif *vif) +{ + WARN_ON(!vif); + return (struct cc33xx_vif *)vif->drv_priv; +} + +static inline +struct ieee80211_vif *cc33xx_wlvif_to_vif(struct cc33xx_vif *wlvif) +{ + return container_of((void *)wlvif, struct ieee80211_vif, drv_priv); +} + +static inline bool cc33xx_is_p2p_mgmt(struct cc33xx_vif *wlvif) +{ + return cc33xx_wlvif_to_vif(wlvif)->type == NL80211_IFTYPE_P2P_DEVICE; +} + +#define cc33xx_for_each_wlvif(cc, wlvif) \ + list_for_each_entry(wlvif, &(cc)->wlvif_list, list) + +#define cc33xx_for_each_wlvif_continue(cc, wlvif) \ + list_for_each_entry_continue(wlvif, &(cc)->wlvif_list, list) + +#define cc33xx_for_each_wlvif_bss_type(cc, wlvif, _bss_type) \ + cc33xx_for_each_wlvif((cc), (wlvif)) \ + if ((wlvif)->bss_type == (_bss_type)) + +#define cc33xx_for_each_wlvif_sta(cc, wlvif) \ + cc33xx_for_each_wlvif_bss_type(cc, wlvif, BSS_TYPE_STA_BSS) + +#define cc33xx_for_each_wlvif_ap(cc, wlvif) \ + cc33xx_for_each_wlvif_bss_type(cc, wlvif, BSS_TYPE_AP_BSS) + +int cc33xx_plt_start(struct cc33xx *cc, const enum plt_mode plt_mode); +int cc33xx_plt_stop(struct cc33xx *cc); +void cc33xx_queue_recovery_work(struct cc33xx *cc); +void cc33xx_flush_deferred_work(struct cc33xx *cc); + +#define SESSION_COUNTER_INVALID 7 /* used with dummy_packet */ + +#define CC33XX_MAX_TXPWR 21 /* maximum power limit is 21dBm */ +#define CC33XX_MIN_TXPWR -10 /* minmum power limit is -10dBm */ + +#define CC33XX_TX_QUEUE_LOW_WATERMARK 32 +#define CC33XX_TX_QUEUE_HIGH_WATERMARK 256 + +#define CC33XX_RX_QUEUE_MAX_LEN 256 + +/* cc33xx needs a 200ms sleep after power on, and a 20ms sleep before power + * on in case is has been shut down shortly before + */ +#define CC33XX_PRE_POWER_ON_SLEEP 20 /* in milliseconds */ +#define CC33XX_POWER_ON_SLEEP 200 /* in milliseconds */ + +/* Macros to handle cc33xx.sta_rate_set */ +#define HW_HT_RATES_OFFSET 16 +#define HW_MIMO_RATES_OFFSET 24 + +#endif /* __CC33XX_I_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/cmd.c b/drivers/net/wireless/ti/cc33xx/cmd.c --- a/drivers/net/wireless/ti/cc33xx/cmd.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/cmd.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,2030 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include "acx.h" +#include "event.h" +#include "io.h" +#include "tx.h" + +#define CC33XX_REBOOT_TIMEOUT_MSEC 100 + +static void init_cmd_header(struct cc33xx_cmd_header *header, + size_t cmd_len, u16 id) +{ + header->NAB_header.len = cpu_to_le16(cmd_len); + WARN_ON(le16_to_cpu(header->NAB_header.len) != cmd_len); + + header->NAB_header.sync_pattern = cpu_to_le32(HOST_SYNC_PATTERN); + header->NAB_header.opcode = cpu_to_le16(id); +} + +int cc33xx_set_max_buffer_size(struct cc33xx *cc, enum buffer_size max_buffer_size) +{ + switch (max_buffer_size) { + case INI_MAX_BUFFER_SIZE: + /* INI FILE PAYLOAD SIZE + INI CMD PARAM + INT */ + cc->max_cmd_size = CC33XX_INI_CMD_MAX_SIZE; + cc->max_cmd_size += sizeof(struct cc33xx_cmd_ini_params_download); + cc->max_cmd_size += sizeof(u32); + break; + + case CMD_MAX_BUFFER_SIZE: + cc->max_cmd_size = CC33XX_CMD_MAX_SIZE; + break; + + default: + cc33xx_warning("max_buffer_size invalid, not changing buffer size"); + break; + } + + return 0; +} + +static int send_buffer(struct cc33xx *cc, int cmd_box_addr, + void *buf, size_t len) +{ + size_t max_cmd_size_align; + + memcpy(cc->cmd_buf, buf, len); + + memset(cc->cmd_buf + len, 0, (CC33XX_CMD_BUFFER_SIZE) - len); + + max_cmd_size_align = __ALIGN_MASK(cc->max_cmd_size, + CC33XX_BUS_BLOCK_SIZE * 2 - 1); + + return cc33xx_write(cc, cmd_box_addr, cc->cmd_buf, + max_cmd_size_align, true); +} + +/* send command to firmware + * + * @cc: cc struct + * @id: command id + * @buf: buffer containing the command, must work with dma + * @len: length of the buffer + * return the cmd status code on success. + */ +static int __cc33xx_cmd_send(struct cc33xx *cc, u16 id, void *buf, + size_t len, size_t res_len, bool sync) +{ + struct cc33xx_cmd_header *cmd; + unsigned long timeout; + int ret; + + if (id >= CMD_LAST_SUPPORTED_COMMAND) { + cc33xx_debug(DEBUG_CMD, "command ID: %d, blocked", id); + return CMD_STATUS_SUCCESS; + } + + if (WARN_ON(len < sizeof(*cmd)) || + WARN_ON(len > cc->max_cmd_size) || + WARN_ON(len % 4 != 0)) + return -EIO; + + cmd = buf; + cmd->id = cpu_to_le16(id); + cmd->status = 0; + + init_cmd_header(cmd, len, id); + init_completion(&cc->command_complete); + ret = send_buffer(cc, NAB_DATA_ADDR, buf, len); + + if (ret < 0) + return ret; + + if (unlikely(!sync)) + return CMD_STATUS_SUCCESS; + + timeout = msecs_to_jiffies(CC33XX_COMMAND_TIMEOUT); + ret = wait_for_completion_timeout(&cc->command_complete, timeout); + + if (ret < 1) { + cc33xx_debug(DEBUG_CMD, "Command T.O"); + return -EIO; + } + + switch (id) { + case CMD_INTERROGATE: + case CMD_DEBUG_READ: + case CMD_TEST_MODE: + case CMD_BM_READ_DEVICE_INFO: + cc33xx_debug(DEBUG_CMD, + "Response len %d, allocated buffer len %zu", + cc->result_length, res_len); + + if (!res_len) + break; /* Response should be discarded */ + + if (WARN_ON(cc->result_length > res_len)) { + cc33xx_error("Error, insufficient response buffer"); + break; + } + + memcpy(buf + sizeof(struct NAB_header), + cc->command_result, + cc->result_length); + + break; + + default: + break; + } + + return CMD_STATUS_SUCCESS; +} + +/* send command to fw and return cmd status on success + * valid_rets contains a bitmap of allowed error codes + */ +static int cc33xx_cmd_send_failsafe(struct cc33xx *cc, u16 id, void *buf, + size_t len, size_t res_len, + unsigned long valid_rets) +{ + int ret = __cc33xx_cmd_send(cc, id, buf, len, res_len, true); + + cc33xx_debug(DEBUG_TESTMODE, "CMD# %d, len=%zu", id, len); + + if (ret < 0) + goto fail; + + /* success is always a valid status */ + valid_rets |= BIT(CMD_STATUS_SUCCESS); + + if (ret >= MAX_COMMAND_STATUS || !test_bit(ret, &valid_rets)) { + cc33xx_error("command execute failure %d", ret); + ret = -EIO; + } + + return ret; +fail: + cc33xx_queue_recovery_work(cc); + return ret; +} + +/* wrapper for cc33xx_cmd_send that accept only CMD_STATUS_SUCCESS + * return 0 on success. + */ +int cc33xx_cmd_send(struct cc33xx *cc, u16 id, void *buf, + size_t len, size_t res_len) +{ + int ret; + /* Support id */ + switch ((enum cc33xx_cmd)id) { + case CMD_EMPTY: + case CMD_START_DHCP_MGMT_SEQ: + case CMD_STOP_DHCP_MGMT_SEQ: + case CMD_START_SECURITY_MGMT_SEQ: + case CMD_STOP_SECURITY_MGMT_SEQ: + case CMD_START_ARP_MGMT_SEQ: + case CMD_STOP_ARP_MGMT_SEQ: + case CMD_START_DNS_MGMT_SEQ: + case CMD_STOP_DNS_MGMT_SEQ: + case CMD_SEND_DEAUTH_DISASSOC: + case CMD_SCHED_STATE_EVENT: + { + return 0; + } break; + default: + { + if ((enum cc33xx_cmd)id >= CMD_LAST_SUPPORTED_COMMAND) + return 0; + goto send; + } + } +send: + ret = cc33xx_cmd_send_failsafe(cc, id, buf, len, res_len, 0); + if (ret < 0) + return ret; + return 0; +} + +static int cc33xx_count_role_set_bits(unsigned long role_map) +{ + int count = 0; + /* if device bit is set ( BIT_2 = ROLE_DEVICE) + * since role device is not counted + * remove it from map + */ + role_map &= ~BIT(2); + + while (role_map != 0) { + count += role_map & 1; + role_map >>= 1; + } + + return count; +} + +int cc33xx_cmd_role_enable(struct cc33xx *cc, u8 *addr, + u8 role_type, u8 *role_id) +{ + struct cc33xx_cmd_role_enable *cmd; + + int ret; + unsigned long role_count; + + struct cc33xx_cmd_complete_role_enable *command_complete = + (struct cc33xx_cmd_complete_role_enable *)&cc->command_result; + + role_count = *cc->roles_map; + ret = cc33xx_count_role_set_bits(role_count); + cc33xx_debug(DEBUG_CMD, "cmd roles enabled: bitmap before: %ld, ret=%d", + role_count, ret); + + /* do not enable more than 2 roles at once, exception is device role */ + if (ret >= 2 && role_type != CC33XX_ROLE_DEVICE) { + cc33xx_debug(DEBUG_CMD, + "cmd role enable: 2 roles already have beed allocated"); + cc33xx_error("failed to initiate cmd role enable"); + ret = -EBUSY; + goto out; + } + + cc33xx_debug(DEBUG_CMD, "cmd role enable, role type %d, addr = %pM", + role_type, addr); + + if (WARN_ON(*role_id != CC33XX_INVALID_ROLE_ID)) + return -EBUSY; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + memcpy(cmd->mac_address, addr, ETH_ALEN); + cmd->role_type = role_type; + + ret = cc33xx_cmd_send(cc, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to initiate cmd role enable"); + goto out_free; + } + cc33xx_debug(DEBUG_CMD, "complete role_id = %d", + command_complete->role_id); + __set_bit(command_complete->role_id, cc->roles_map); + *role_id = command_complete->role_id; + +out_free: + kfree(cmd); +out: + return ret; +} + +int cc33xx_cmd_role_disable(struct cc33xx *cc, u8 *role_id) +{ + struct cc33xx_cmd_role_disable *cmd; + int ret; + + cc33xx_debug(DEBUG_CMD, "cmd role disable"); + + if (WARN_ON(*role_id == CC33XX_INVALID_ROLE_ID)) + return -ENOENT; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + cmd->role_id = *role_id; + + ret = cc33xx_cmd_send(cc, CMD_ROLE_DISABLE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to initiate cmd role disable"); + goto out_free; + } + + __clear_bit(*role_id, cc->roles_map); + *role_id = CC33XX_INVALID_ROLE_ID; + +out_free: + kfree(cmd); + +out: + return ret; +} + +int cc33xx_set_link(struct cc33xx *cc, struct cc33xx_vif *wlvif, u8 link) +{ + unsigned long flags; + + /* these bits are used by op_tx */ + spin_lock_irqsave(&cc->cc_lock, flags); + __set_bit(link, cc->links_map); + __set_bit(link, wlvif->links_map); + spin_unlock_irqrestore(&cc->cc_lock, flags); + cc->links[link].wlvif = wlvif; + + /* Take saved value for total freed packets from wlvif, in case this is + * recovery/resume + */ + if (wlvif->bss_type != BSS_TYPE_AP_BSS) + cc->links[link].total_freed_pkts = wlvif->total_freed_pkts; + + cc->active_link_count++; + return 0; +} + +void cc33xx_clear_link(struct cc33xx *cc, struct cc33xx_vif *wlvif, u8 *hlid) +{ + unsigned long flags; + + if (*hlid == CC33XX_INVALID_LINK_ID) + return; + + /* these bits are used by op_tx */ + spin_lock_irqsave(&cc->cc_lock, flags); + __clear_bit(*hlid, cc->links_map); + __clear_bit(*hlid, wlvif->links_map); + spin_unlock_irqrestore(&cc->cc_lock, flags); + + cc->links[*hlid].prev_freed_pkts = 0; + cc->links[*hlid].ba_bitmap = 0; + eth_zero_addr(cc->links[*hlid].addr); + + /* At this point op_tx() will not add more packets to the queues. We + * can purge them. + */ + cc33xx_tx_reset_link_queues(cc, *hlid); + cc->links[*hlid].wlvif = NULL; + + if (wlvif->bss_type == BSS_TYPE_AP_BSS && + *hlid == wlvif->ap.bcast_hlid) { + u32 sqn_padding = CC33XX_TX_SQN_POST_RECOVERY_PADDING; + /* save the total freed packets in the wlvif, in case this is + * recovery or suspend + */ + wlvif->total_freed_pkts = cc->links[*hlid].total_freed_pkts; + + /* increment the initial seq number on recovery to account for + * transmitted packets that we haven't yet got in the FW status + */ + if (wlvif->encryption_type == KEY_GEM) + sqn_padding = CC33XX_TX_SQN_POST_RECOVERY_PADDING_GEM; + + if (test_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, &cc->flags)) + wlvif->total_freed_pkts += sqn_padding; + } + + cc->links[*hlid].total_freed_pkts = 0; + + *hlid = CC33XX_INVALID_LINK_ID; + cc->active_link_count--; + WARN_ON_ONCE(cc->active_link_count < 0); +} + +static u8 cc33xx_get_native_channel_type(u8 nl_channel_type) +{ + switch (nl_channel_type) { + case NL80211_CHAN_NO_HT: + return CC33XX_CHAN_NO_HT; + case NL80211_CHAN_HT20: + return CC33XX_CHAN_HT20; + case NL80211_CHAN_HT40MINUS: + return CC33XX_CHAN_HT40MINUS; + case NL80211_CHAN_HT40PLUS: + return CC33XX_CHAN_HT40PLUS; + default: + WARN_ON(1); + return CC33XX_CHAN_NO_HT; + } +} + +static int cc33xx_cmd_role_start_dev(struct cc33xx *cc, struct cc33xx_vif *wlvif, + enum nl80211_band band, int channel) +{ + struct cc33xx_cmd_role_start *cmd; + int ret; + + struct cc33xx_cmd_complete_role_start *command_complete = + (struct cc33xx_cmd_complete_role_start *)&cc->command_result; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cc33xx_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id); + + cmd->role_id = wlvif->dev_role_id; + cmd->role_type = CC33XX_ROLE_DEVICE; + if (band == NL80211_BAND_5GHZ) + cmd->band = CC33XX_BAND_5GHZ; + cmd->channel = channel; + cmd->channel_type = cc33xx_get_native_channel_type(wlvif->channel_type); + + ret = cc33xx_cmd_send(cc, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to initiate cmd role device start"); + goto err_hlid; + } + + wlvif->dev_hlid = command_complete->sta.hlid; + cc->links[wlvif->dev_hlid].allocated_pkts = 0; + cc->session_ids[wlvif->dev_hlid] = command_complete->sta.session; + cc33xx_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d ", + wlvif->dev_role_id, command_complete->sta.hlid, + command_complete->sta.session); + ret = cc33xx_set_link(cc, wlvif, wlvif->dev_hlid); + goto out_free; + +err_hlid: + /* clear links on error */ + cc33xx_clear_link(cc, wlvif, &wlvif->dev_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int cc33xx_cmd_role_stop_transceiver(struct cc33xx *cc) +{ + struct cc33xx_cmd_role_stop *cmd; + int ret; + + if (unlikely(cc->state != CC33XX_STATE_ON || !cc->plt)) { + ret = -EINVAL; + goto out; + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + cc33xx_debug(DEBUG_CMD, "cmd role stop transceiver"); + + cmd->role_id = cc->plt_role_id; + + ret = cc33xx_cmd_send(cc, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("transceiver - failed to initiate cmd role stop"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int cc33xx_cmd_plt_disable(struct cc33xx *cc) +{ + struct cc33xx_cmd_PLT_disable *cmd; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = cc33xx_cmd_send(cc, CMD_PLT_DISABLE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("transceiver: failed to disable Transceiver mode"); + goto out_free; + } else { + cc33xx_debug(DEBUG_CMD, "Succeed to disable Transceiver mode"); + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +static int cc333xx_cmd_role_stop_dev(struct cc33xx *cc, + struct cc33xx_vif *wlvif) +{ + struct cc33xx_cmd_role_stop *cmd; + int ret; + + if (WARN_ON(wlvif->dev_hlid == CC33XX_INVALID_LINK_ID)) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cc33xx_debug(DEBUG_CMD, "cmd role stop dev"); + + cmd->role_id = wlvif->dev_role_id; + + ret = cc33xx_cmd_send(cc, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to initiate cmd role stop"); + goto out_free; + } + + cc33xx_clear_link(cc, wlvif, &wlvif->dev_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int cc33xx_cmd_plt_enable(struct cc33xx *cc, u8 role_id) +{ + struct cc33xx_cmd_PLT_enable *cmd; + s32 ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = cc33xx_cmd_send(cc, CMD_PLT_ENABLE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("Failed to send CMD_PLT_ENABLE"); + goto out_free; + } + cc33xx_debug(DEBUG_CMD, "Success to send CMD_PLT_ENABLE"); + +out_free: + kfree(cmd); +out: + return ret; +} + +int cc33xx_cmd_role_start_transceiver(struct cc33xx *cc, u8 role_id) +{ + struct cc33xx_cmd_role_start *cmd; + s32 ret; + u8 role_type = ROLE_TRANSCEIVER; + + /* Default values */ + u8 band = NL80211_BAND_2GHZ; + u8 channel = 6; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->role_type = role_type; + cmd->role_id = role_id; + cmd->channel = channel; + cmd->band = band; + + ret = cc33xx_cmd_send(cc, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to initiate cmd role start PLT"); + goto out_free; + } + + cc33xx_debug(DEBUG_CMD, "cmd role start PLT. Role ID number: %u", role_id); + +out_free: + kfree(cmd); +out: + return ret; +} + +int cc33xx_cmd_role_start_sta(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + struct ieee80211_vif *vif = cc33xx_wlvif_to_vif(wlvif); + struct cc33xx_cmd_role_start *cmd; + + u32 supported_rates; + int ret; + + struct cc33xx_cmd_complete_role_start *command_complete = + (struct cc33xx_cmd_complete_role_start *)&cc->command_result; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cc33xx_debug(DEBUG_CMD, "cmd role start sta %d", wlvif->role_id); + + cmd->role_id = wlvif->role_id; + cmd->role_type = CC33XX_ROLE_STA; + cmd->channel = wlvif->channel; + if (wlvif->band == NL80211_BAND_5GHZ) { + cmd->band = CC33XX_BAND_5GHZ; + cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set + & ~CONF_TX_CCK_RATES); + } else { + cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); + } + cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int); + cmd->sta.ssid_type = CC33XX_SSID_TYPE_ANY; + cmd->sta.ssid_len = wlvif->ssid_len; + memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len); + memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN); + + supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | wlvif->rate_set; + if (wlvif->band == NL80211_BAND_5GHZ) + supported_rates &= ~CONF_TX_CCK_RATES; + + if (wlvif->p2p) + supported_rates &= ~CONF_TX_CCK_RATES; + + cmd->sta.local_rates = cpu_to_le32(supported_rates); + + cmd->channel_type = cc33xx_get_native_channel_type(wlvif->channel_type); + + /* We don't have the correct remote rates in this stage. The + * rates will be reconfigured later, after association, if the + * firmware supports ACX_PEER_CAP. Otherwise, there's nothing + * we can do, so use all supported_rates here. + */ + cmd->sta.remote_rates = cpu_to_le32(supported_rates); + + ret = cc33xx_cmd_send(cc, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to initiate cmd role start sta"); + goto err_hlid; + } + + wlvif->sta.role_chan_type = wlvif->channel_type; + + wlvif->sta.hlid = command_complete->sta.hlid; + cc->links[wlvif->sta.hlid].allocated_pkts = 0; + cc->session_ids[wlvif->sta.hlid] = command_complete->sta.session; + cc33xx_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d basic_rate_set: 0x%x, remote_rates: 0x%x", + wlvif->role_id, + command_complete->sta.hlid, command_complete->sta.session, + wlvif->basic_rate_set, wlvif->rate_set); + ret = cc33xx_set_link(cc, wlvif, wlvif->sta.hlid); + + goto out_free; + +err_hlid: + cc33xx_clear_link(cc, wlvif, &wlvif->sta.hlid); + +out_free: + kfree(cmd); +out: + return ret; +} + +/* use this function to stop ibss as well */ +int cc33xx_cmd_role_stop_sta(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + struct cc33xx_cmd_role_stop *cmd; + int ret; + + if (WARN_ON(wlvif->sta.hlid == CC33XX_INVALID_LINK_ID)) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cc33xx_debug(DEBUG_CMD, "cmd role stop sta %d", wlvif->role_id); + + cmd->role_id = wlvif->role_id; + + ret = cc33xx_cmd_send(cc, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to initiate cmd role stop sta"); + goto out_free; + } + + cc33xx_clear_link(cc, wlvif, &wlvif->sta.hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int cc33xx_cmd_role_start_ap(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + struct cc33xx_cmd_role_start *cmd; + struct ieee80211_vif *vif = cc33xx_wlvif_to_vif(wlvif); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + u32 supported_rates; + int ret; + + struct cc33xx_cmd_complete_role_start *command_complete = + (struct cc33xx_cmd_complete_role_start *)&cc->command_result; + + cc33xx_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id); + cc33xx_debug(DEBUG_CMD, "cmd role start ap basic rateset: 0x%x", + wlvif->basic_rate_set); + + /* If MESH --> ssid_len is always 0 */ + if (!ieee80211_vif_is_mesh(vif)) { + /* trying to use hidden SSID with an old hostapd version */ + if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) { + cc33xx_error("got a null SSID from beacon/bss"); + ret = -EINVAL; + goto out; + } + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->role_id = wlvif->role_id; + cmd->role_type = CC33XX_ROLE_AP; + cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); + cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); + cmd->ap.dtim_interval = bss_conf->dtim_period; + cmd->ap.wmm = wlvif->wmm_enabled; + cmd->channel = wlvif->channel; + cmd->channel_type = cc33xx_get_native_channel_type(wlvif->channel_type); + + supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES; + if (wlvif->p2p) + supported_rates &= ~CONF_TX_CCK_RATES; + + cc33xx_debug(DEBUG_CMD, "cmd role start ap with supported_rates 0x%08x", + supported_rates); + + cmd->ap.local_rates = cpu_to_le32(supported_rates); + + switch (wlvif->band) { + case NL80211_BAND_2GHZ: + cmd->band = CC33XX_BAND_2_4GHZ; + break; + case NL80211_BAND_5GHZ: + cmd->band = CC33XX_BAND_5GHZ; + break; + default: + cc33xx_warning("ap start - unknown band: %d", (int)wlvif->band); + cmd->band = CC33XX_BAND_2_4GHZ; + break; + } + + ret = cc33xx_cmd_send(cc, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to initiate cmd role start ap"); + goto out_free_bcast; + } + + wlvif->ap.global_hlid = command_complete->ap.global_hlid; + wlvif->ap.bcast_hlid = command_complete->ap.broadcast_hlid; + cc->session_ids[wlvif->ap.global_hlid] = command_complete->ap.global_session_id; + cc->session_ids[wlvif->ap.bcast_hlid] = command_complete->ap.bcast_session_id; + + cc33xx_debug(DEBUG_CMD, "role start: roleid=%d, global_hlid=%d, broadcast_hlid=%d, global_session_id=%d, bcast_session_id=%d, basic_rate_set: 0x%x, remote_rates: 0x%x", + wlvif->role_id, + command_complete->ap.global_hlid, + command_complete->ap.broadcast_hlid, + command_complete->ap.global_session_id, + command_complete->ap.bcast_session_id, + wlvif->basic_rate_set, wlvif->rate_set); + + ret = cc33xx_set_link(cc, wlvif, wlvif->ap.global_hlid); + ret = cc33xx_set_link(cc, wlvif, wlvif->ap.bcast_hlid); + + goto out_free; + +out_free_bcast: + cc33xx_clear_link(cc, wlvif, &wlvif->ap.bcast_hlid); + cc33xx_clear_link(cc, wlvif, &wlvif->ap.global_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int cc33xx_cmd_role_stop_ap(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + struct cc33xx_cmd_role_stop *cmd; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cc33xx_debug(DEBUG_CMD, "cmd role stop ap %d", wlvif->role_id); + + cmd->role_id = wlvif->role_id; + + ret = cc33xx_cmd_send(cc, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to initiate cmd role stop ap"); + goto out_free; + } + + cc33xx_clear_link(cc, wlvif, &wlvif->ap.bcast_hlid); + cc33xx_clear_link(cc, wlvif, &wlvif->ap.global_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int cc33xx_cmd_role_start_ibss(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + struct ieee80211_vif *vif = cc33xx_wlvif_to_vif(wlvif); + struct cc33xx_cmd_role_start *cmd; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cc33xx_debug(DEBUG_CMD, "cmd role start ibss %d", wlvif->role_id); + + cmd->role_id = wlvif->role_id; + cmd->role_type = CC33XX_ROLE_IBSS; + if (wlvif->band == NL80211_BAND_5GHZ) + cmd->band = CC33XX_BAND_5GHZ; + cmd->channel = wlvif->channel; + cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); + cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int); + cmd->ibss.dtim_interval = bss_conf->dtim_period; + cmd->ibss.ssid_type = CC33XX_SSID_TYPE_ANY; + cmd->ibss.ssid_len = wlvif->ssid_len; + memcpy(cmd->ibss.ssid, wlvif->ssid, wlvif->ssid_len); + memcpy(cmd->ibss.bssid, vif->bss_conf.bssid, ETH_ALEN); + cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); + + if (wlvif->sta.hlid == CC33XX_INVALID_LINK_ID) { + ret = cc33xx_set_link(cc, wlvif, wlvif->sta.hlid); + if (ret) + goto out_free; + } + cmd->ibss.hlid = wlvif->sta.hlid; + cmd->ibss.remote_rates = cpu_to_le32(wlvif->rate_set); + + ret = cc33xx_cmd_send(cc, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to initiate cmd role enable"); + goto err_hlid; + } + + goto out_free; + +err_hlid: + /* clear links on error. */ + cc33xx_clear_link(cc, wlvif, &wlvif->sta.hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +/* send test command to firmware + * + * @cc: cc struct + * @buf: buffer containing the command, with all headers, must work with dma + * @len: length of the buffer + * @answer: is answer needed + */ +int cc33xx_cmd_test(struct cc33xx *cc, void *buf, size_t buf_len, u8 answer) +{ + int ret; + size_t res_len = 0; + + cc33xx_debug(DEBUG_CMD, "cmd test"); + + if (answer) + res_len = buf_len; + + ret = cc33xx_cmd_send(cc, CMD_TEST_MODE, buf, buf_len, res_len); + + if (ret < 0) { + cc33xx_warning("TEST command failed"); + return ret; + } + + return ret; +} + +/* read acx from firmware + * + * @cc: cc struct + * @id: acx id + * @buf: buffer for the response, including all headers, must work with dma + * @len: length of buf + */ +int cc33xx_cmd_interrogate(struct cc33xx *cc, u16 id, void *buf, + size_t cmd_len, size_t res_len) +{ + struct acx_header *acx = buf; + int ret; + + cc33xx_debug(DEBUG_CMD, "cmd interrogate"); + + acx->id = cpu_to_le16(id); + + /* response payload length, does not include any headers */ + acx->len = cpu_to_le16(res_len - sizeof(*acx)); + + ret = cc33xx_cmd_send(cc, CMD_INTERROGATE, acx, cmd_len, res_len); + if (ret < 0) + cc33xx_error("INTERROGATE command failed"); + + return ret; +} + +/* read debug acx from firmware + * + * @cc: cc struct + * @id: acx id + * @buf: buffer for the response, including all headers, must work with dma + * @len: length of buf + */ +int cc33xx_cmd_debug_inter(struct cc33xx *cc, u16 id, void *buf, + size_t cmd_len, size_t res_len) +{ + struct acx_header *acx = buf; + int ret; + + cc33xx_debug(DEBUG_CMD, "cmd debug interrogate"); + + acx->id = cpu_to_le16(id); + + /* response payload length, does not include any headers */ + acx->len = cpu_to_le16(res_len - sizeof(*acx)); + + ret = cc33xx_cmd_send(cc, CMD_DEBUG_READ, acx, cmd_len, res_len); + if (ret < 0) + cc33xx_error("CMD_DEBUG_READ command failed"); + + return ret; +} + +/* write acx value to firmware + * + * @cc: cc struct + * @id: acx id + * @buf: buffer containing acx, including all headers, must work with dma + * @len: length of buf + * @valid_rets: bitmap of valid cmd status codes (i.e. return values). + * return the cmd status on success. + */ +int cc33xx_cmd_configure_failsafe(struct cc33xx *cc, u16 id, void *buf, + size_t len, unsigned long valid_rets) +{ + struct acx_header *acx = buf; + int ret; + + cc33xx_debug(DEBUG_CMD, "cmd configure (%d), TSFL %x", + id, cc->core_status->tsf); + + if (WARN_ON_ONCE(len < sizeof(*acx))) + return -EIO; + + acx->id = cpu_to_le16(id); + + /* payload length, does not include any headers */ + acx->len = cpu_to_le16(len - sizeof(*acx)); + + ret = cc33xx_cmd_send_failsafe(cc, CMD_CONFIGURE, acx, len, 0, + valid_rets); + if (ret < 0) { + cc33xx_warning("CONFIGURE command NOK"); + return ret; + } + + return ret; +} + +/* wrapper for cc33xx_cmd_configure that accepts only success status. + * return 0 on success + */ +int cc33xx_cmd_configure(struct cc33xx *cc, u16 id, void *buf, size_t len) +{ + int ret = cc33xx_cmd_configure_failsafe(cc, id, buf, len, 0); + + if (ret < 0) + return ret; + return 0; +} + +/* write acx value to firmware + * + * @cc: cc struct + * @id: acx id + * @buf: buffer containing debug, including all headers, must work with dma + * @len: length of buf + * @valid_rets: bitmap of valid cmd status codes (i.e. return values). + * return the cmd status on success. + */ +static int cc33xx_cmd_debug_failsafe(struct cc33xx *cc, u16 id, void *buf, + size_t len, unsigned long valid_rets) +{ + struct debug_header *acx = buf; + int ret; + + cc33xx_debug(DEBUG_CMD, "cmd debug (%d)", id); + + if (WARN_ON_ONCE(len < sizeof(*acx))) + return -EIO; + + acx->id = cpu_to_le16(id); + + /* payload length, does not include any headers */ + acx->len = cpu_to_le16(len - sizeof(*acx)); + + ret = cc33xx_cmd_send_failsafe(cc, CMD_DEBUG, acx, len, 0, + valid_rets); + if (ret < 0) { + cc33xx_warning("CONFIGURE command NOK"); + return ret; + } + + return ret; +} + +/* wrapper for cc33xx_cmd_debug that accepts only success status. + * return 0 on success + */ +int cc33xx_cmd_debug(struct cc33xx *cc, u16 id, void *buf, size_t len) +{ + int ret = cc33xx_cmd_debug_failsafe(cc, id, buf, len, 0); + + if (ret < 0) + return ret; + return 0; +} + +int cc33xx_cmd_ps_mode(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 ps_mode, u16 auto_ps_timeout) +{ + struct cc33xx_cmd_ps_params *ps_params = NULL; + int ret = 0; + + cc33xx_debug(DEBUG_CMD, "cmd set ps mode"); + + ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); + if (!ps_params) { + ret = -ENOMEM; + goto out; + } + + ps_params->role_id = wlvif->role_id; + ps_params->ps_mode = ps_mode; + ps_params->auto_ps_timeout = cpu_to_le16(auto_ps_timeout); + + ret = cc33xx_cmd_send(cc, CMD_SET_PS_MODE, ps_params, + sizeof(*ps_params), 0); + if (ret < 0) { + cc33xx_error("cmd set_ps_mode failed"); + goto out; + } + +out: + kfree(ps_params); + return ret; +} + +int cc33xx_cmd_set_default_wep_key(struct cc33xx *cc, u8 id, u8 hlid) +{ + struct cc33xx_cmd_set_keys *cmd; + int ret = 0; + + cc33xx_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->hlid = hlid; + cmd->key_id = id; + cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; + cmd->key_action = cpu_to_le16(KEY_SET_ID); + cmd->key_type = KEY_WEP; + + ret = cc33xx_cmd_send(cc, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_warning("cmd set_default_wep_key failed: %d", ret); + goto out; + } + +out: + kfree(cmd); + + return ret; +} + +int cc33xx_cmd_set_sta_key(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u16 action, u8 id, u8 key_type, u8 key_size, + const u8 *key, const u8 *addr, u32 tx_seq_32, + u16 tx_seq_16) +{ + struct cc33xx_cmd_set_keys *cmd; + int ret = 0; + + /* hlid might have already been deleted */ + if (wlvif->sta.hlid == CC33XX_INVALID_LINK_ID) + return 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->hlid = wlvif->sta.hlid; + + if (key_type == KEY_WEP) + cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; + else if (is_broadcast_ether_addr(addr)) + cmd->lid_key_type = BROADCAST_LID_TYPE; + else + cmd->lid_key_type = UNICAST_LID_TYPE; + + cmd->key_action = cpu_to_le16(action); + cmd->key_size = key_size; + cmd->key_type = key_type; + + cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); + cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); + + cmd->key_id = id; + + if (key_type == KEY_TKIP) { + /* We get the key in the following form: + * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) + * but the target is expecting: + * TKIP - RX MIC - TX MIC + */ + memcpy(cmd->key, key, 16); + memcpy(cmd->key + 16, key + 24, 8); + memcpy(cmd->key + 24, key + 16, 8); + + } else { + memcpy(cmd->key, key, key_size); + } + + cc33xx_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); + + ret = cc33xx_cmd_send(cc, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_warning("could not set keys"); + goto out; + } + +out: + kfree(cmd); + + return ret; +} + +int cc33xx_cmd_set_ap_key(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u16 action, u8 id, u8 key_type, u8 key_size, + const u8 *key, u8 hlid, u32 tx_seq_32, u16 tx_seq_16) +{ + struct cc33xx_cmd_set_keys *cmd; + int ret = 0; + u8 lid_type; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + if (hlid == wlvif->ap.bcast_hlid) { + if (key_type == KEY_WEP) + lid_type = WEP_DEFAULT_LID_TYPE; + else + lid_type = BROADCAST_LID_TYPE; + } else { + lid_type = UNICAST_LID_TYPE; + } + + cc33xx_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d hlid: %d", + (int)action, (int)id, (int)lid_type, + (int)key_type, (int)hlid); + + cmd->lid_key_type = lid_type; + cmd->hlid = hlid; + cmd->key_action = cpu_to_le16(action); + cmd->key_size = key_size; + cmd->key_type = key_type; + cmd->key_id = id; + cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); + cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); + + if (key_type == KEY_TKIP) { + /* We get the key in the following form: + * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) + * but the target is expecting: + * TKIP - RX MIC - TX MIC + */ + memcpy(cmd->key, key, 16); + memcpy(cmd->key + 16, key + 24, 8); + memcpy(cmd->key + 24, key + 16, 8); + } else { + memcpy(cmd->key, key, key_size); + } + + cc33xx_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd)); + + ret = cc33xx_cmd_send(cc, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_warning("could not set ap keys"); + goto out; + } + +out: + kfree(cmd); + return ret; +} + +int cc33xx_cmd_set_peer_state(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 hlid) +{ + struct cc33xx_cmd_set_peer_state *cmd; + int ret = 0; + + cc33xx_debug(DEBUG_CMD, "cmd set peer state (hlid=%d)", hlid); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->hlid = hlid; + cmd->state = CC33XX_CMD_STA_STATE_CONNECTED; + + ret = cc33xx_cmd_send(cc, CMD_SET_LINK_CONNECTION_STATE, + cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to send set peer state command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int cc33xx_cmd_add_peer(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct ieee80211_sta *sta, u8 *hlid, u8 is_connected) +{ + struct cc33xx_cmd_add_peer *cmd; + + struct cc33xx_cmd_complete_add_peer *command_complete = + (struct cc33xx_cmd_complete_add_peer *)&cc->command_result; + + int i, ret; + u32 sta_rates; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cc33xx_debug(DEBUG_CMD, "cmd add peer is ap %d", is_connected); + cmd->is_connected = is_connected; + cmd->role_id = wlvif->role_id; + cmd->role_type = CC33XX_ROLE_AP; + cmd->link_type = 1; + + memcpy(cmd->addr, sta->addr, ETH_ALEN); + cmd->bss_index = CC33XX_AP_BSS_INDEX; + cmd->aid = cpu_to_le16(sta->aid); + cmd->sp_len = sta->max_sp; + cmd->wmm = sta->wme ? 1 : 0; + + for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++) { + if (sta->wme && (sta->uapsd_queues & BIT(i))) { + cmd->psd_type[NUM_ACCESS_CATEGORIES_COPY - 1 - i] = + CC33XX_PSD_UPSD_TRIGGER; + } else { + cmd->psd_type[NUM_ACCESS_CATEGORIES_COPY - 1 - i] = + CC33XX_PSD_LEGACY; + } + } + + sta_rates = sta->deflink.supp_rates[wlvif->band]; + if (sta->deflink.ht_cap.ht_supported) { + sta_rates |= + (sta->deflink.ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) | + (sta->deflink.ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET); + } + + cmd->supported_rates = + cpu_to_le32(cc33xx_tx_enabled_rates_get(cc, sta_rates, + wlvif->band)); + + if (!cmd->supported_rates) { + cc33xx_debug(DEBUG_CMD, + "peer has no supported rates yet, configuring basic rates: 0x%x", + wlvif->basic_rate_set); + cmd->supported_rates = cpu_to_le32(wlvif->basic_rate_set); + } + + cc33xx_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x", + cmd->supported_rates, sta->uapsd_queues); + + if (sta->deflink.ht_cap.ht_supported) { + cmd->ht_capabilities = cpu_to_le32(sta->deflink.ht_cap.cap); + cmd->ht_capabilities |= cpu_to_le32(CC33XX_HT_CAP_HT_OPERATION); + cmd->ampdu_params = sta->deflink.ht_cap.ampdu_factor | + sta->deflink.ht_cap.ampdu_density; + } + + cmd->has_he = sta->deflink.he_cap.has_he; + cmd->mfp = sta->mfp; + ret = cc33xx_cmd_send(cc, CMD_ADD_PEER, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to initiate cmd add peer"); + goto out_free; + } + + if (hlid) { + if (le16_to_cpu(command_complete->header.status) == CMD_STATUS_SUCCESS) { + *hlid = command_complete->hlid; + cc->links[*hlid].allocated_pkts = 0; + cc->session_ids[*hlid] = command_complete->session_id; + cc33xx_debug(DEBUG_CMD, "new peer hlid=%d session_ids=%d", + command_complete->hlid, command_complete->session_id); + } else { + ret = -EMLINK; + } + } else { + cc33xx_debug(DEBUG_CMD, "update peer done !"); + } +out_free: + kfree(cmd); + +out: + return ret; +} + +int cc33xx_cmd_remove_peer(struct cc33xx *cc, + struct cc33xx_vif *wlvif, u8 hlid) +{ + struct cc33xx_cmd_remove_peer *cmd; + int ret; + bool timeout = false; + + cc33xx_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->hlid = hlid; + + cmd->role_id = wlvif->role_id; + + ret = cc33xx_cmd_send(cc, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to initiate cmd remove peer"); + goto out_free; + } + + ret = cc33xx_wait_for_event(cc, CC33XX_EVENT_PEER_REMOVE_COMPLETE, + &timeout); + + /* We are ok with a timeout here. The event is sometimes not sent + * due to a firmware bug. In case of another error (like SDIO timeout) + * queue a recovery. + */ + if (ret < 0) + cc33xx_queue_recovery_work(cc); + +out_free: + kfree(cmd); + +out: + return ret; +} + +static int cc33xx_get_reg_conf_ch_idx(enum nl80211_band band, u16 ch) +{ + /* map the given band/channel to the respective predefined + * bit expected by the fw + */ + switch (band) { + case NL80211_BAND_2GHZ: + /* channels 1..14 are mapped to 0..13 */ + if (ch >= 1 && ch <= 14) + return ch - 1; + break; + case NL80211_BAND_5GHZ: + switch (ch) { + case 8 ... 16: + /* channels 8,12,16 are mapped to 18,19,20 */ + return 18 + (ch - 8) / 4; + case 34 ... 48: + /* channels 34,36..48 are mapped to 21..28 */ + return 21 + (ch - 34) / 2; + case 52 ... 64: + /* channels 52,56..64 are mapped to 29..32 */ + return 29 + (ch - 52) / 4; + case 100 ... 140: + /* channels 100,104..140 are mapped to 33..43 */ + return 33 + (ch - 100) / 4; + case 149 ... 165: + /* channels 149,153..165 are mapped to 44..48 */ + return 44 + (ch - 149) / 4; + default: + break; + } + break; + default: + break; + } + + cc33xx_error("%s: unknown band/channel: %d/%d", __func__, band, ch); + return -1; +} + +void cc33xx_set_pending_regdomain_ch(struct cc33xx *cc, u16 channel, + enum nl80211_band band) +{ + int ch_bit_idx = 0; + + if (!(cc->quirks & CC33XX_QUIRK_REGDOMAIN_CONF)) + return; + + ch_bit_idx = cc33xx_get_reg_conf_ch_idx(band, channel); + + if (ch_bit_idx >= 0 && ch_bit_idx <= CC33XX_MAX_CHANNELS) + __set_bit_le(ch_bit_idx, (long *)cc->reg_ch_conf_pending); +} + +int cc33xx_cmd_regdomain_config_locked(struct cc33xx *cc) +{ + struct cc33xx_cmd_regdomain_dfs_config *cmd = NULL; + int ret = 0, i, b, ch_bit_idx; + __le32 tmp_ch_bitmap[2] __aligned(sizeof(unsigned long)); + struct wiphy *wiphy = cc->hw->wiphy; + struct ieee80211_supported_band *band; + bool timeout = false; + + if (!(cc->quirks & CC33XX_QUIRK_REGDOMAIN_CONF)) + return 0; + + cc33xx_debug(DEBUG_CMD, "cmd reg domain config"); + + memcpy(tmp_ch_bitmap, cc->reg_ch_conf_pending, sizeof(tmp_ch_bitmap)); + + for (b = NL80211_BAND_2GHZ; b <= NL80211_BAND_5GHZ; b++) { + band = wiphy->bands[b]; + for (i = 0; i < band->n_channels; i++) { + struct ieee80211_channel *channel = &band->channels[i]; + u16 ch = channel->hw_value; + u32 flags = channel->flags; + + if (flags & (IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_NO_IR)) + continue; + + if ((flags & IEEE80211_CHAN_RADAR) && + channel->dfs_state != NL80211_DFS_AVAILABLE) + continue; + + ch_bit_idx = cc33xx_get_reg_conf_ch_idx(b, ch); + if (ch_bit_idx < 0) + continue; + + __set_bit_le(ch_bit_idx, (long *)tmp_ch_bitmap); + } + } + + if (!memcmp(tmp_ch_bitmap, cc->reg_ch_conf_last, sizeof(tmp_ch_bitmap))) + goto out; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->ch_bit_map1 = tmp_ch_bitmap[0]; + cmd->ch_bit_map2 = tmp_ch_bitmap[1]; + cmd->dfs_region = cc->dfs_region; + + cc33xx_debug(DEBUG_CMD, + "cmd reg domain bitmap1: 0x%08x, bitmap2: 0x%08x", + cmd->ch_bit_map1, cmd->ch_bit_map2); + + ret = cc33xx_cmd_send(cc, CMD_DFS_CHANNEL_CONFIG, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to send reg domain dfs config"); + goto out; + } + + ret = cc33xx_wait_for_event(cc, CC33XX_EVENT_DFS_CONFIG_COMPLETE, + &timeout); + + if (ret < 0 || timeout) { + cc33xx_error("reg domain conf %serror", + timeout ? "completion " : ""); + ret = timeout ? -ETIMEDOUT : ret; + goto out; + } + + memcpy(cc->reg_ch_conf_last, tmp_ch_bitmap, sizeof(tmp_ch_bitmap)); + memset(cc->reg_ch_conf_pending, 0, sizeof(cc->reg_ch_conf_pending)); + +out: + kfree(cmd); + return ret; +} + +int cc33xx_cmd_config_fwlog(struct cc33xx *cc) +{ + struct cc33xx_cmd_config_fwlog *cmd; + int ret = 0; + + cc33xx_debug(DEBUG_CMD, "cmd config firmware logger"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->logger_mode = cc->conf.host_conf.fwlog.mode; + cmd->log_severity = cc->conf.host_conf.fwlog.severity; + cmd->timestamp = cc->conf.host_conf.fwlog.timestamp; + cmd->output = cc->conf.host_conf.fwlog.output; + cmd->threshold = cc->conf.host_conf.fwlog.threshold; + + ret = cc33xx_cmd_send(cc, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to send config firmware logger command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +static int cc33xx_cmd_roc(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 role_id, enum nl80211_band band, u8 channel) +{ + struct cc33xx_cmd_roc *cmd; + int ret = 0; + + cc33xx_debug(DEBUG_CMD, "cmd roc %d (%d)", channel, role_id); + + if (WARN_ON(role_id == CC33XX_INVALID_ROLE_ID)) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->role_id = role_id; + cmd->channel = channel; + switch (band) { + case NL80211_BAND_2GHZ: + cmd->band = CC33XX_BAND_2_4GHZ; + break; + case NL80211_BAND_5GHZ: + cmd->band = CC33XX_BAND_5GHZ; + break; + default: + cc33xx_error("roc - unknown band: %d", (int)wlvif->band); + ret = -EINVAL; + goto out_free; + } + + ret = cc33xx_cmd_send(cc, CMD_REMAIN_ON_CHANNEL, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to send ROC command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +static int cc33xx_cmd_croc(struct cc33xx *cc, u8 role_id) +{ + struct cc33xx_cmd_croc *cmd; + int ret = 0; + + cc33xx_debug(DEBUG_CMD, "cmd croc (%d)", role_id); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + cmd->role_id = role_id; + + ret = cc33xx_cmd_send(cc, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd, + sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to send ROC command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int cc33xx_roc(struct cc33xx *cc, struct cc33xx_vif *wlvif, u8 role_id, + enum nl80211_band band, u8 channel) +{ + int ret = 0; + + if (WARN_ON(test_bit(role_id, cc->roc_map))) + return 0; + + ret = cc33xx_cmd_roc(cc, wlvif, role_id, band, channel); + if (ret < 0) + goto out; + + __set_bit(role_id, cc->roc_map); +out: + return ret; +} + +int cc33xx_croc(struct cc33xx *cc, u8 role_id) +{ + int ret = 0; + + if (WARN_ON(!test_bit(role_id, cc->roc_map))) + return 0; + + ret = cc33xx_cmd_croc(cc, role_id); + if (ret < 0) + goto out; + + __clear_bit(role_id, cc->roc_map); + + /* Rearm the tx watchdog when removing the last ROC. This prevents + * recoveries due to just finished ROCs - when Tx hasn't yet had + * a chance to get out. + */ + if (find_first_bit(cc->roc_map, CC33XX_MAX_ROLES) >= CC33XX_MAX_ROLES) + cc33xx_rearm_tx_watchdog_locked(cc); +out: + return ret; +} + +int cc33xx_cmd_stop_channel_switch(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + struct cc33xx_cmd_stop_channel_switch *cmd; + int ret; + + cc33xx_debug(DEBUG_ACX, "cmd stop channel switch"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->role_id = wlvif->role_id; + + ret = cc33xx_cmd_send(cc, CMD_STOP_CHANNEL_SWITCH, + cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to stop channel switch command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +/* start dev role and roc on its channel */ +int cc33xx_start_dev(struct cc33xx *cc, struct cc33xx_vif *wlvif, + enum nl80211_band band, int channel) +{ + int ret; + + if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS))) + return -EINVAL; + + /* the dev role is already started for p2p mgmt interfaces */ + + if (!cc33xx_is_p2p_mgmt(wlvif)) { + ret = cc33xx_cmd_role_enable(cc, + cc33xx_wlvif_to_vif(wlvif)->addr, + CC33XX_ROLE_DEVICE, + &wlvif->dev_role_id); + if (ret < 0) + goto out; + } + + cc33xx_debug(DEBUG_CMD, "cmd role start dev"); + ret = cc33xx_cmd_role_start_dev(cc, wlvif, band, channel); + if (ret < 0) + goto out_disable; + + cc33xx_debug(DEBUG_CMD, "cmd roc"); + ret = cc33xx_roc(cc, wlvif, wlvif->dev_role_id, band, channel); + if (ret < 0) + goto out_stop; + + return 0; + +out_stop: + cc333xx_cmd_role_stop_dev(cc, wlvif); +out_disable: + if (!cc33xx_is_p2p_mgmt(wlvif)) + cc33xx_cmd_role_disable(cc, &wlvif->dev_role_id); +out: + return ret; +} + +/* croc dev hlid, and stop the role */ +int cc33xx_stop_dev(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + int ret; + + if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS))) + return -EINVAL; + + /* flush all pending packets */ + ret = cc33xx_tx_work_locked(cc); + if (ret < 0) + goto out; + + if (test_bit(wlvif->dev_role_id, cc->roc_map)) { + ret = cc33xx_croc(cc, wlvif->dev_role_id); + if (ret < 0) + goto out; + } + + ret = cc333xx_cmd_role_stop_dev(cc, wlvif); + if (ret < 0) + goto out; + + if (!cc33xx_is_p2p_mgmt(wlvif)) { + ret = cc33xx_cmd_role_disable(cc, &wlvif->dev_role_id); + if (ret < 0) + goto out; + } + +out: + return ret; +} + +int cc33xx_cmd_generic_cfg(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 feature, u8 enable, u8 value) +{ + struct cc33xx_cmd_generic_cfg *cmd; + int ret; + + cc33xx_debug(DEBUG_CMD, + "cmd generic cfg (role %d feature %d enable %d value %d)", + wlvif->role_id, feature, enable, value); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->role_id = wlvif->role_id; + cmd->feature = feature; + cmd->enable = enable; + cmd->value = value; + + ret = cc33xx_cmd_send(cc, CMD_GENERIC_CFG, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to send generic cfg command"); + goto out_free; + } +out_free: + kfree(cmd); + return ret; +} + +int cmd_channel_switch(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct ieee80211_channel_switch *ch_switch) +{ + struct cmd_channel_switch *cmd; + u32 supported_rates; + int ret; + + cc33xx_debug(DEBUG_ACX, "cmd channel switch (role_id=%d, new channel=%d, count=%d, block tx=%d", + wlvif->role_id, ch_switch->chandef.chan->hw_value, + ch_switch->count, ch_switch->block_tx); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->role_id = wlvif->role_id; + cmd->channel = ch_switch->chandef.chan->hw_value; + cmd->switch_time = ch_switch->count; + cmd->stop_tx = ch_switch->block_tx; + + switch (ch_switch->chandef.chan->band) { + case NL80211_BAND_2GHZ: + cmd->band = CC33XX_BAND_2_4GHZ; + break; + case NL80211_BAND_5GHZ: + cmd->band = CC33XX_BAND_5GHZ; + break; + default: + cc33xx_error("invalid channel switch band: %d", + ch_switch->chandef.chan->band); + ret = -EINVAL; + goto out_free; + } + + supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES; + supported_rates |= wlvif->rate_set; + if (wlvif->p2p) + supported_rates &= ~CONF_TX_CCK_RATES; + cmd->local_supported_rates = cpu_to_le32(supported_rates); + cmd->channel_type = wlvif->channel_type; + + ret = cc33xx_cmd_send(cc, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to send channel switch command"); + goto out_free; + } + +out_free: + kfree(cmd); +out: + return ret; +} + +int cmd_dfs_master_restart(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + struct cmd_dfs_master_restart *cmd; + int ret = 0; + + cc33xx_debug(DEBUG_CMD, "cmd dfs master restart (role %d)", + wlvif->role_id); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->role_id = wlvif->role_id; + + ret = cc33xx_cmd_send(cc, CMD_DFS_MASTER_RESTART, + cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to send dfs master restart command"); + goto out_free; + } +out_free: + kfree(cmd); + return ret; +} + +int cmd_set_cac(struct cc33xx *cc, struct cc33xx_vif *wlvif, bool start) +{ + struct cmd_cac_start *cmd; + int ret = 0; + + cc33xx_debug(DEBUG_CMD, "cmd cac (channel %d) %s", + wlvif->channel, start ? "start" : "stop"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->role_id = wlvif->role_id; + cmd->channel = wlvif->channel; + if (wlvif->band == NL80211_BAND_5GHZ) + cmd->band = CC33XX_BAND_5GHZ; + cmd->bandwidth = cc33xx_get_native_channel_type(wlvif->channel_type); + + ret = cc33xx_cmd_send(cc, start ? CMD_CAC_START : CMD_CAC_STOP, + cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to send cac command"); + goto out_free; + } + +out_free: + kfree(cmd); + return ret; +} + +int cmd_set_bd_addr(struct cc33xx *cc, u8 *bd_addr) +{ + struct cmd_set_bd_addr *cmd; + int ret = 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + memcpy(cmd->bd_addr, bd_addr, sizeof(cmd->bd_addr)); + + ret = cc33xx_cmd_send(cc, CMD_SET_BD_ADDR, cmd, sizeof(*cmd), 0); + if (ret < 0) { + cc33xx_error("failed to set BD address"); + goto out_free; + } + +out_free: + kfree(cmd); +out: + return ret; +} + +int cmd_get_device_info(struct cc33xx *cc, u8 *info_buffer, size_t buffer_len) +{ + struct cc33xx_cmd_get_device_info *cmd; + int ret = 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + ret = cc33xx_cmd_send(cc, CMD_BM_READ_DEVICE_INFO, cmd, + sizeof(*cmd), sizeof(*cmd)); + if (ret < 0) { + cc33xx_error("Device info command failure "); + } else { + WARN_ON(buffer_len > sizeof(cmd->device_info)); + memcpy(info_buffer, cmd->device_info, buffer_len); + } + + kfree(cmd); + + return ret; +} + +int cmd_download_container_chunk(struct cc33xx *cc, u8 *chunk, + size_t chunk_len, bool is_last_chunk) +{ + struct cc33xx_cmd_container_download *cmd; + const size_t command_size = sizeof(*cmd) + chunk_len; + int ret; + bool is_sync_transfer = !is_last_chunk; + + cmd = kzalloc(command_size, GFP_KERNEL); + + if (!cmd) { + cc33xx_error("Chunk buffer allocation failure"); + return -ENOMEM; + } + + memcpy(cmd->payload, chunk, chunk_len); + cmd->length = cpu_to_le32(chunk_len); + + if (is_last_chunk) { + cc33xx_debug(DEBUG_BOOT, "Suspending IRQ while device reboots"); + cc33xx_disable_interrupts_nosync(cc); + } + + ret = __cc33xx_cmd_send(cc, CMD_CONTAINER_DOWNLOAD, cmd, + command_size, sizeof(u32), is_sync_transfer); + + kfree(cmd); + + if (is_last_chunk) { + msleep(CC33XX_REBOOT_TIMEOUT_MSEC); + cc33xx_debug(DEBUG_BOOT, "Resuming IRQ"); + cc33xx_enable_interrupts(cc); + } + + return ret; +} diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/cmd.h b/drivers/net/wireless/ti/cc33xx/cmd.h --- a/drivers/net/wireless/ti/cc33xx/cmd.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/cmd.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,700 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __CMD_H__ +#define __CMD_H__ + +#include "cc33xx.h" + +struct acx_header; + +enum buffer_size { + INI_MAX_BUFFER_SIZE, + CMD_MAX_BUFFER_SIZE +}; + +int cc33xx_set_max_buffer_size(struct cc33xx *cc, enum buffer_size max_buffer_size); +int cc33xx_cmd_send(struct cc33xx *cc, u16 id, void *buf, + size_t len, size_t res_len); +int cc33xx_cmd_role_enable(struct cc33xx *cc, u8 *addr, + u8 role_type, u8 *role_id); +int cc33xx_cmd_role_disable(struct cc33xx *cc, u8 *role_id); +int cc33xx_cmd_role_start_sta(struct cc33xx *cc, struct cc33xx_vif *wlvif); +int cc33xx_cmd_role_stop_sta(struct cc33xx *cc, struct cc33xx_vif *wlvif); +int cc33xx_cmd_role_start_ap(struct cc33xx *cc, struct cc33xx_vif *wlvif); +int cc33xx_cmd_role_stop_ap(struct cc33xx *cc, struct cc33xx_vif *wlvif); +int cc33xx_cmd_role_start_ibss(struct cc33xx *cc, struct cc33xx_vif *wlvif); +int cc33xx_start_dev(struct cc33xx *cc, struct cc33xx_vif *wlvif, + enum nl80211_band band, int channel); +int cc33xx_stop_dev(struct cc33xx *cc, struct cc33xx_vif *wlvif); +int cc33xx_cmd_test(struct cc33xx *cc, void *buf, size_t buf_len, u8 answer); +int cc33xx_cmd_interrogate(struct cc33xx *cc, u16 id, void *buf, + size_t cmd_len, size_t res_len); +int cc33xx_cmd_debug_inter(struct cc33xx *cc, u16 id, void *buf, + size_t cmd_len, size_t res_len); +int cc33xx_cmd_configure(struct cc33xx *cc, u16 id, void *buf, size_t len); +int cc33xx_cmd_debug(struct cc33xx *cc, u16 id, void *buf, size_t len); +int cc33xx_cmd_configure_failsafe(struct cc33xx *cc, u16 id, void *buf, + size_t len, unsigned long valid_rets); +int cc33xx_cmd_ps_mode(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 ps_mode, u16 auto_ps_timeout); +int cc33xx_cmd_set_default_wep_key(struct cc33xx *cc, u8 id, u8 hlid); +int cc33xx_cmd_set_sta_key(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, const u8 *addr, + u32 tx_seq_32, u16 tx_seq_16); +int cc33xx_cmd_set_ap_key(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u16 action, u8 id, u8 key_type, u8 key_size, + const u8 *key, u8 hlid, u32 tx_seq_32, u16 tx_seq_16); +int cc33xx_cmd_set_peer_state(struct cc33xx *cc, + struct cc33xx_vif *wlvif, u8 hlid); +int cc33xx_roc(struct cc33xx *cc, struct cc33xx_vif *wlvif, u8 role_id, + enum nl80211_band band, u8 channel); +int cc33xx_croc(struct cc33xx *cc, u8 role_id); +int cc33xx_cmd_add_peer(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct ieee80211_sta *sta, u8 *hlid, u8 is_connected); +int cc33xx_cmd_remove_peer(struct cc33xx *cc, + struct cc33xx_vif *wlvif, u8 hlid); +void cc33xx_set_pending_regdomain_ch(struct cc33xx *cc, u16 channel, + enum nl80211_band band); +int cc33xx_cmd_regdomain_config_locked(struct cc33xx *cc); +int cc33xx_cmd_generic_cfg(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 feature, u8 enable, u8 value); +int cc33xx_cmd_config_fwlog(struct cc33xx *cc); +int cc33xx_cmd_stop_channel_switch(struct cc33xx *cc, struct cc33xx_vif *wlvif); +int cc33xx_set_link(struct cc33xx *cc, struct cc33xx_vif *wlvif, u8 link); +void cc33xx_clear_link(struct cc33xx *cc, struct cc33xx_vif *wlvif, u8 *hlid); +int cc33xx_cmd_role_start_transceiver(struct cc33xx *cc, u8 role_id); +int cc33xx_cmd_role_stop_transceiver(struct cc33xx *cc); +int cc33xx_cmd_plt_enable(struct cc33xx *cc, u8 role_id); +int cc33xx_cmd_plt_disable(struct cc33xx *cc); +int cmd_channel_switch(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct ieee80211_channel_switch *ch_switch); +int cmd_dfs_master_restart(struct cc33xx *cc, struct cc33xx_vif *wlvif); +int cmd_set_cac(struct cc33xx *cc, struct cc33xx_vif *wlvif, bool start); +int cmd_set_bd_addr(struct cc33xx *cc, u8 *bd_addr); +int cmd_get_device_info(struct cc33xx *cc, u8 *info_buffer, size_t buffer_len); +int cmd_download_container_chunk(struct cc33xx *cc, u8 *chunk, + size_t chunk_len, bool is_last_chunk); + +enum cc33xx_cmd { + CMD_EMPTY, + CMD_SET_KEYS = 1, + CMD_SET_LINK_CONNECTION_STATE = 2, + + CMD_CHANNEL_SWITCH = 3, + CMD_STOP_CHANNEL_SWITCH = 4, + + CMD_REMAIN_ON_CHANNEL = 5, + CMD_CANCEL_REMAIN_ON_CHANNEL = 6, + + CMD_START_DHCP_MGMT_SEQ = 7, + CMD_STOP_DHCP_MGMT_SEQ = 8, + + CMD_START_SECURITY_MGMT_SEQ = 9, + CMD_STOP_SECURITY_MGMT_SEQ = 10, + + CMD_START_ARP_MGMT_SEQ = 11, + CMD_STOP_ARP_MGMT_SEQ = 12, + + CMD_START_DNS_MGMT_SEQ = 13, + CMD_STOP_DNS_MGMT_SEQ = 14, + + /* Access point commands */ + CMD_ADD_PEER = 15, + CMD_REMOVE_PEER = 16, + + /* Role API */ + CMD_ROLE_ENABLE = 17, + CMD_ROLE_DISABLE = 18, + CMD_ROLE_START = 19, + CMD_ROLE_STOP = 20, + + CMD_AP_SET_BEACON_INFO = 21, /* Set AP beacon template */ + + /* Managed sequence of sending deauth / disassoc frame */ + CMD_SEND_DEAUTH_DISASSOC = 22, + + CMD_SCHED_STATE_EVENT = 23, + CMD_SCAN = 24, + CMD_STOP_SCAN = 25, + CMD_SET_PROBE_IE = 26, + + CMD_CONFIGURE = 27, + CMD_INTERROGATE = 28, + + CMD_DEBUG = 29, + CMD_DEBUG_READ = 30, + + CMD_TEST_MODE = 31, + CMD_PLT_ENABLE = 32, + CMD_PLT_DISABLE = 33, + CMD_CONNECTION_SCAN_SSID_CFG = 34, + CMD_BM_READ_DEVICE_INFO = 35, + CMD_CONTAINER_DOWNLOAD = 36, + CMD_DOWNLOAD_INI_PARAMS = 37, + CMD_SET_BD_ADDR = 38, + CMD_BLE_COMMANDS = 39, + + CMD_LAST_SUPPORTED_COMMAND, + + /* The following commands are legacy and are not yet supported */ + + CMD_SET_PS_MODE, + CMD_DFS_CHANNEL_CONFIG, + CMD_CONFIG_FWLOGGER, + CMD_START_FWLOGGER, + CMD_STOP_FWLOGGER, + CMD_GENERIC_CFG, + CMD_DFS_MASTER_RESTART, + CMD_CAC_START, + CMD_CAC_STOP, + CMD_DFS_RADAR_DETECTION_DEBUG, + + MAX_COMMAND_ID_CC33xx = 0x7FFF, +}; + +#define MAX_CMD_PARAMS 572 + +/* unit ms */ +#define CC33XX_COMMAND_TIMEOUT 2000 +#define CC33XX_CMD_TEMPL_MAX_SIZE 512 +#define CC33XX_EVENT_TIMEOUT 5000 + +struct cc33xx_cmd_header { + struct NAB_header NAB_header; + __le16 id; + __le16 status; + + /* payload */ + u8 data[]; +} __packed; + +#define CC33XX_CMD_MAX_PARAMS 572 + +struct cc33xx_command { + struct cc33xx_cmd_header header; + u8 parameters[CC33XX_CMD_MAX_PARAMS]; +} __packed; + +enum { + CMD_MAILBOX_IDLE = 0, + CMD_STATUS_SUCCESS = 1, + CMD_STATUS_UNKNOWN_CMD = 2, + CMD_STATUS_UNKNOWN_IE = 3, + CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, + CMD_STATUS_RX_BUSY = 13, + CMD_STATUS_INVALID_PARAM = 14, + CMD_STATUS_TEMPLATE_TOO_LARGE = 15, + CMD_STATUS_OUT_OF_MEMORY = 16, + CMD_STATUS_STA_TABLE_FULL = 17, + CMD_STATUS_RADIO_ERROR = 18, + CMD_STATUS_WRONG_NESTING = 19, + CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ + CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ + CMD_STATUS_TEMPLATE_OOM = 23, + CMD_STATUS_NO_RX_BA_SESSION = 24, + + MAX_COMMAND_STATUS +}; + +enum { + BSS_TYPE_IBSS = 0, + BSS_TYPE_STA_BSS = 2, + BSS_TYPE_AP_BSS = 3, + MAX_BSS_TYPE = 0xFF +}; + +struct cc33xx_cmd_role_enable { + struct cc33xx_cmd_header header; + + u8 role_type; + u8 mac_address[ETH_ALEN]; + u8 padding; +} __packed; + +struct command_complete_header { + __le16 id; + __le16 status; + + /* payload */ + u8 data[]; +} __packed; + +struct cc33xx_cmd_complete_role_enable { + struct command_complete_header header; + u8 role_id; + u8 padding[3]; +} __packed; + +struct cc33xx_cmd_role_disable { + struct cc33xx_cmd_header header; + + u8 role_id; + u8 padding[3]; +} __packed; + +enum cc33xx_band { + CC33XX_BAND_2_4GHZ = 0, + CC33XX_BAND_5GHZ = 1, + CC33XX_BAND_JAPAN_4_9_GHZ = 2, + CC33XX_BAND_DEFAULT = CC33XX_BAND_2_4GHZ, + CC33XX_BAND_INVALID = 0x7E, + CC33XX_BAND_MAX_RADIO = 0x7F, +}; + +enum cc33xx_channel_type { + CC33XX_CHAN_NO_HT, + CC33XX_CHAN_HT20, + CC33XX_CHAN_HT40MINUS, + CC33XX_CHAN_HT40PLUS +}; + +struct cc33xx_cmd_role_start { + struct cc33xx_cmd_header header; + u8 role_id; + u8 role_type; + u8 band; + u8 channel; + + u8 channel_type; + + union { + struct { + u8 padding_1[54]; + } __packed device; + /* sta & p2p_cli use the same struct */ + struct { + u8 bssid[ETH_ALEN]; + + __le32 remote_rates; /* remote supported rates */ + + /* The target uses this field to determine the rate at + * which to transmit control frame responses (such as + * ACK or CTS frames). + */ + __le32 basic_rate_set; + __le32 local_rates; /* local supported rates */ + + u8 ssid_type; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + __le16 beacon_interval; /* in TBTTs */ + } __packed sta; + struct { + u8 bssid[ETH_ALEN]; + u8 hlid; /* data hlid */ + u8 dtim_interval; + __le32 remote_rates; /* remote supported rates */ + + __le32 basic_rate_set; + __le32 local_rates; /* local supported rates */ + + u8 ssid_type; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + __le16 beacon_interval; /* in TBTTs */ + + u8 padding_1[2]; + } __packed ibss; + /* ap & p2p_go use the same struct */ + struct { + __le16 beacon_interval; /* in TBTTs */ + + __le32 basic_rate_set; + __le32 local_rates; /* local supported rates */ + + u8 dtim_interval; + /* ap supports wmm (note that there is additional + * per-sta wmm configuration) + */ + u8 wmm; + u8 padding_1[42]; + } __packed ap; + }; + u8 padding; +} __packed; + +struct cc33xx_cmd_complete_role_start { + struct command_complete_header header; + union { + struct { + u8 hlid; + u8 session; + u8 padding[2]; + } __packed sta; + struct { + /* The host link id for the AP's global queue */ + u8 global_hlid; + /* The host link id for the AP's broadcast queue */ + u8 broadcast_hlid; + u8 bcast_session_id; + u8 global_session_id; + } __packed ap; + }; +} __packed; + +struct cc33xx_cmd_role_stop { + struct cc33xx_cmd_header header; + + u8 role_id; + u8 padding[3]; +} __packed; + +struct cmd_enabledisable_path { + struct cc33xx_cmd_header header; + + u8 channel; + u8 padding[3]; +} __packed; + +enum cc33xx_cmd_ps_mode_e { + STATION_AUTO_PS_MODE, /* Dynamic Power Save */ + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE +}; + +struct cc33xx_cmd_ps_params { + struct cc33xx_cmd_header header; + + u8 role_id; + u8 ps_mode; /* STATION_* */ + __le16 auto_ps_timeout; +} __packed; + +/* HW encryption keys */ +#define NUM_ACCESS_CATEGORIES_COPY 4 + +enum cc33xx_cmd_key_action { + KEY_ADD_OR_REPLACE = 1, + KEY_REMOVE = 2, + KEY_SET_ID = 3, + MAX_KEY_ACTION = 0xffff, +}; + +enum cc33xx_cmd_lid_key_type { + UNICAST_LID_TYPE = 0, + BROADCAST_LID_TYPE = 1, + WEP_DEFAULT_LID_TYPE = 2 +}; + +enum cc33xx_cmd_key_type { + KEY_NONE = 0, + KEY_WEP = 1, + KEY_TKIP = 2, + KEY_AES = 3, /* aes_ccmp_128 */ + KEY_GEM = 4, + KEY_IGTK = 5, /* bip_cmac_128 */ + KEY_CMAC_256 = 6, + KEY_GMAC_128 = 7, + KEY_GMAC_256 = 8, + KEY_GCMP_256 = 9, + KEY_CCMP256 = 10, + KEY_GCMP128 = 11, +}; + +struct cc33xx_cmd_set_keys { + struct cc33xx_cmd_header header; + + /* Indicates whether the HLID is a unicast key set + * or broadcast key set. A special value 0xFF is + * used to indicate that the HLID is on WEP-default + * (multi-hlids). of type cc33xx_cmd_lid_key_type. + */ + u8 hlid; + + /* In WEP-default network (hlid == 0xFF) used to + * indicate which network STA/IBSS/AP role should be + * changed + */ + u8 lid_key_type; + + /* Key ID - For TKIP and AES key types, this field + * indicates the value that should be inserted into + * the KeyID field of frames transmitted using this + * key entry. For broadcast keys the index use as a + * marker for TX/RX key. + * For WEP default network (HLID=0xFF), this field + * indicates the ID of the key to add or remove. + */ + u8 key_id; + u8 reserved_1; + + /* key_action_e */ + __le16 key_action; + + /* key size in bytes */ + u8 key_size; + + /* key_type_e */ + u8 key_type; + + /* This field holds the security key data to add to the STA table */ + u8 key[MAX_KEY_SIZE]; + __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __packed; + +struct cc33xx_cmd_test_header { + u8 id; + u8 padding[3]; +} __packed; + +#define CC33XX_CMD_STA_STATE_CONNECTED 1 + +struct cc33xx_cmd_set_peer_state { + struct cc33xx_cmd_header header; + + u8 hlid; + u8 state; + u8 padding[2]; +} __packed; + +struct cc33xx_cmd_roc { + struct cc33xx_cmd_header header; + + u8 role_id; + u8 channel; + u8 band; + u8 padding; +}; + +struct cc33xx_cmd_croc { + struct cc33xx_cmd_header header; + + u8 role_id; + u8 padding[3]; +}; + +enum cc33xx_ssid_type { + CC33XX_SSID_TYPE_PUBLIC = 0, + CC33XX_SSID_TYPE_HIDDEN = 1, + CC33XX_SSID_TYPE_ANY = 2, +}; + +enum CC33XX_psd_type { + CC33XX_PSD_LEGACY = 0, + CC33XX_PSD_UPSD_TRIGGER = 1, + CC33XX_PSD_LEGACY_PSPOLL = 2, + CC33XX_PSD_SAPSD = 3 +}; + +#define MAX_SIZE_BEACON_TEMP (450) +struct cc33xx_cmd_set_beacon_info { + struct cc33xx_cmd_header header; + + u8 role_id; + __le16 beacon_len; + u8 beacon[MAX_SIZE_BEACON_TEMP]; + u8 padding[3]; +} __packed; + +struct cc33xx_cmd_add_peer { + struct cc33xx_cmd_header header; + + u8 is_connected; + u8 role_id; + u8 role_type; + u8 link_type; + u8 addr[ETH_ALEN]; + __le16 aid; + u8 psd_type[NUM_ACCESS_CATEGORIES_COPY]; + __le32 supported_rates; + u8 bss_index; + u8 sp_len; + u8 wmm; + __le32 ht_capabilities; + u8 ampdu_params; + + /* HE peer support */ + bool has_he; + bool mfp; + u8 padding[2]; +} __packed; + +struct cc33xx_cmd_complete_add_peer { + struct command_complete_header header; + u8 hlid; + u8 session_id; +} __packed; + +struct cc33xx_cmd_remove_peer { + struct cc33xx_cmd_header header; + u8 hlid; + u8 role_id; + u8 padding[2]; +} __packed; + +/* Continuous mode - packets are transferred to the host periodically + * via the data path. + * On demand - Log messages are stored in a cyclic buffer in the + * firmware, and only transferred to the host when explicitly requested + */ +enum cc33xx_fwlogger_log_mode { + CC33XX_FWLOG_CONTINUOUS, +}; + +/* Include/exclude timestamps from the log messages */ +enum cc33xx_fwlogger_timestamp { + CC33XX_FWLOG_TIMESTAMP_DISABLED, + CC33XX_FWLOG_TIMESTAMP_ENABLED +}; + +/* Logs can be routed to the debug pinouts (where available), to the host bus + * (SDIO/SPI), or dropped + */ +enum cc33xx_fwlogger_output { + CC33XX_FWLOG_OUTPUT_NONE, + CC33XX_FWLOG_OUTPUT_DBG_PINS, + CC33XX_FWLOG_OUTPUT_HOST, +}; + +struct cc33xx_cmd_regdomain_dfs_config { + struct cc33xx_cmd_header header; + + __le32 ch_bit_map1; + __le32 ch_bit_map2; + u8 dfs_region; + u8 padding[3]; +} __packed; + +enum cc33xx_generic_cfg_feature { + CC33XX_CFG_FEATURE_RADAR_DEBUG = 2, +}; + +struct cc33xx_cmd_generic_cfg { + struct cc33xx_cmd_header header; + + u8 role_id; + u8 feature; + u8 enable; + u8 value; +} __packed; + +struct cc33xx_cmd_config_fwlog { + struct cc33xx_cmd_header header; + + /* See enum cc33xx_fwlogger_log_mode */ + u8 logger_mode; + + /* Minimum log level threshold */ + u8 log_severity; + + /* Include/exclude timestamps from the log messages */ + u8 timestamp; + + /* See enum cc33xx_fwlogger_output */ + u8 output; + + /* Regulates the frequency of log messages */ + u8 threshold; + + u8 padding[3]; +} __packed; + +struct cc33xx_cmd_stop_channel_switch { + struct cc33xx_cmd_header header; + + u8 role_id; + u8 padding[3]; +} __packed; + +/* Used to check radio status after calibration */ +#define MAX_TLV_LENGTH 500 +#define TEST_CMD_P2G_CAL 2 /* TX BiP */ + +struct cc33xx_cmd_cal_p2g { + struct cc33xx_cmd_header header; + + struct cc33xx_cmd_test_header test; + + __le32 ver; + __le16 len; + u8 buf[MAX_TLV_LENGTH]; + u8 type; + u8 padding; + + __le16 radio_status; + + u8 sub_band_mask; + u8 padding2; +} __packed; + +struct cmd_channel_switch { + struct cc33xx_cmd_header header; + + u8 role_id; + + /* The new serving channel */ + u8 channel; + /* Relative time of the serving channel switch in TBTT units */ + u8 switch_time; + /* Stop the role TX, should expect it after radar detection */ + u8 stop_tx; + + __le32 local_supported_rates; + + u8 channel_type; + u8 band; + + u8 padding[2]; +} __packed; + +struct cmd_set_bd_addr { + struct cc33xx_cmd_header header; + + u8 bd_addr[ETH_ALEN]; + u8 padding[2]; +} __packed; + +struct cmd_dfs_master_restart { + struct cc33xx_cmd_header header; + + u8 role_id; + u8 padding[3]; +} __packed; + +/* cac_start and cac_stop share the same params */ +struct cmd_cac_start { + struct cc33xx_cmd_header header; + + u8 role_id; + u8 channel; + u8 band; + u8 bandwidth; +} __packed; + +/* PLT structs */ + +struct cc33xx_cmd_PLT_enable { + struct cc33xx_cmd_header header; + __le32 dummy; +}; + +struct cc33xx_cmd_PLT_disable { + struct cc33xx_cmd_header header; + __le32 dummy; +}; + +struct cc33xx_cmd_ini_params_download { + struct cc33xx_cmd_header header; + __le32 length; + u8 payload[]; +} __packed; + +struct cc33xx_cmd_container_download { + struct cc33xx_cmd_header header; + __le32 length; + u8 payload[]; +} __packed; + +struct cc33xx_cmd_get_device_info { + struct cc33xx_cmd_header header; + u8 device_info[700]; +} __packed; + +#endif /* __CC33XX_CMD_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/conf.h b/drivers/net/wireless/ti/cc33xx/conf.h --- a/drivers/net/wireless/ti/cc33xx/conf.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/conf.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,1246 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __CONF_H__ +#define __CONF_H__ + +struct cc33xx_conf_header { + __le32 magic; + __le32 version; + __le32 checksum; +} __packed; + +#define CC33XX_CONF_MAGIC 0x10e100ca +#define CC33XX_CONF_VERSION 0x01070069 +#define CC33XX_CONF_MASK 0x0000ffff +#define CC33X_CONF_SIZE (sizeof(struct cc33xx_conf_file)) + +enum { + CONF_HW_BIT_RATE_1MBPS = BIT(1), + CONF_HW_BIT_RATE_2MBPS = BIT(2), + CONF_HW_BIT_RATE_5_5MBPS = BIT(3), + CONF_HW_BIT_RATE_11MBPS = BIT(4), + CONF_HW_BIT_RATE_6MBPS = BIT(5), + CONF_HW_BIT_RATE_9MBPS = BIT(6), + CONF_HW_BIT_RATE_12MBPS = BIT(7), + CONF_HW_BIT_RATE_18MBPS = BIT(8), + CONF_HW_BIT_RATE_24MBPS = BIT(9), + CONF_HW_BIT_RATE_36MBPS = BIT(10), + CONF_HW_BIT_RATE_48MBPS = BIT(11), + CONF_HW_BIT_RATE_54MBPS = BIT(12), + CONF_HW_BIT_RATE_MCS_0 = BIT(13), + CONF_HW_BIT_RATE_MCS_1 = BIT(14), + CONF_HW_BIT_RATE_MCS_2 = BIT(15), + CONF_HW_BIT_RATE_MCS_3 = BIT(16), + CONF_HW_BIT_RATE_MCS_4 = BIT(17), + CONF_HW_BIT_RATE_MCS_5 = BIT(18), + CONF_HW_BIT_RATE_MCS_6 = BIT(19), + CONF_HW_BIT_RATE_MCS_7 = BIT(20) +}; + +enum { + CONF_HW_RATE_INDEX_1MBPS = 1, + CONF_HW_RATE_INDEX_2MBPS = 2, + CONF_HW_RATE_INDEX_5_5MBPS = 3, + CONF_HW_RATE_INDEX_11MBPS = 4, + CONF_HW_RATE_INDEX_6MBPS = 5, + CONF_HW_RATE_INDEX_9MBPS = 6, + CONF_HW_RATE_INDEX_12MBPS = 7, + CONF_HW_RATE_INDEX_18MBPS = 8, + CONF_HW_RATE_INDEX_24MBPS = 9, + CONF_HW_RATE_INDEX_36MBPS = 10, + CONF_HW_RATE_INDEX_48MBPS = 11, + CONF_HW_RATE_INDEX_54MBPS = 12, + CONF_HW_RATE_INDEX_MCS0 = 13, + CONF_HW_RATE_INDEX_MCS1 = 14, + CONF_HW_RATE_INDEX_MCS2 = 15, + CONF_HW_RATE_INDEX_MCS3 = 16, + CONF_HW_RATE_INDEX_MCS4 = 17, + CONF_HW_RATE_INDEX_MCS5 = 18, + CONF_HW_RATE_INDEX_MCS6 = 19, + CONF_HW_RATE_INDEX_MCS7 = 20, + + CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_MCS7, +}; + +enum { + CONF_PREAMBLE_TYPE_SHORT = 0, + CONF_PREAMBLE_TYPE_LONG = 1, + CONF_PREAMBLE_TYPE_OFDM = 2, + CONF_PREAMBLE_TYPE_N_MIXED_MODE = 3, + CONF_PREAMBLE_TYPE_GREENFIELD = 4, + CONF_PREAMBLE_TYPE_AX_SU = 5, + CONF_PREAMBLE_TYPE_AX_MU = 6, + CONF_PREAMBLE_TYPE_AX_SU_ER = 7, + CONF_PREAMBLE_TYPE_AX_TB = 8, + CONF_PREAMBLE_TYPE_AX_TB_NDP_FB = 9, + CONF_PREAMBLE_TYPE_AC_VHT = 10, + CONF_PREAMBLE_TYPE_BE_EHT_MU = 13, + CONF_PREAMBLE_TYPE_BE_EHT_TB = 14, + CONF_PREAMBLE_TYPE_INVALID = 0xFF +}; + +#define CONF_HW_RXTX_RATE_UNSUPPORTED 0xff + +enum conf_rx_queue_type { + CONF_RX_QUEUE_TYPE_LOW_PRIORITY, /* All except the high priority */ + CONF_RX_QUEUE_TYPE_HIGH_PRIORITY, /* Management and voice packets */ +}; + +struct cc33xx_clk_cfg { + u32 n; + u32 m; + u32 p; + u32 q; + u8 swallow; +}; + +struct conf_rx_settings { + /* The maximum amount of time, in TU, before the + * firmware discards the MSDU. + * + * Range: 0 - 0xFFFFFFFF + */ + u32 rx_msdu_life_time; + + /* Packet detection threshold in the PHY. + * + * FIXME: details unknown. + */ + u32 packet_detection_threshold; + + /* The longest time the STA will wait to receive traffic from the AP + * after a PS-poll has been transmitted. + * + * Range: 0 - 200000 + */ + u16 ps_poll_timeout; + /* The longest time the STA will wait to receive traffic from the AP + * after a frame has been sent from an UPSD enabled queue. + * + * Range: 0 - 200000 + */ + u16 upsd_timeout; + + /* The number of octets in an MPDU, below which an RTS/CTS + * handshake is not performed. + * + * Range: 0 - 4096 + */ + u16 rts_threshold; + + /* The RX Clear Channel Assessment threshold in the PHY + * (the energy threshold). + * + * Range: ENABLE_ENERGY_D == 0x140A + * DISABLE_ENERGY_D == 0xFFEF + */ + u16 rx_cca_threshold; + + /* Occupied Rx mem-blocks number which requires interrupting the host + * (0 = no buffering, 0xffff = disabled). + * + * Range: uint16_t + */ + u16 irq_blk_threshold; + + /* Rx packets number which requires interrupting the host + * (0 = no buffering). + * + * Range: uint16_t + */ + u16 irq_pkt_threshold; + + /* Max time in msec the FW may delay RX-Complete interrupt. + * + * Range: 1 - 100 + */ + u16 irq_timeout; + + /* The RX queue type. + * + * Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY, + */ + u8 queue_type; +} __packed; + +#define CONF_TX_MAX_RATE_CLASSES 10 + +#define CONF_TX_RATE_MASK_UNSPECIFIED 0 +#define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS) +#define CONF_TX_RATE_RETRY_LIMIT 10 + +/* basic rates for p2p operations (probe req/resp, etc.) */ +#define CONF_TX_RATE_MASK_BASIC_P2P CONF_HW_BIT_RATE_6MBPS + +/* Rates supported for data packets when operating as STA/AP. Note the absence + * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop + * one. The rate dropped is not mandatory under any operating mode. + */ +#define CONF_TX_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ + CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \ + CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \ + CONF_HW_BIT_RATE_18MBPS | CONF_HW_BIT_RATE_24MBPS | \ + CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ + CONF_HW_BIT_RATE_54MBPS) + +#define CONF_TX_CCK_RATES (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ + CONF_HW_BIT_RATE_11MBPS) + +#define CONF_TX_OFDM_RATES (CONF_HW_BIT_RATE_6MBPS | \ + CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \ + CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ + CONF_HW_BIT_RATE_54MBPS) + +#define CONF_TX_MCS_RATES (CONF_HW_BIT_RATE_MCS_0 | \ + CONF_HW_BIT_RATE_MCS_1 | CONF_HW_BIT_RATE_MCS_2 | \ + CONF_HW_BIT_RATE_MCS_3 | CONF_HW_BIT_RATE_MCS_4 | \ + CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 | \ + CONF_HW_BIT_RATE_MCS_7) + +/* Default rates for management traffic when operating in AP mode. This + * should be configured according to the basic rate set of the AP + */ +#define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS) + +/* default rates for working as IBSS (11b and OFDM) */ +#define CONF_TX_IBSS_DEFAULT_RATES (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ + CONF_HW_BIT_RATE_11MBPS | CONF_TX_OFDM_RATES) + +struct conf_tx_rate_class { + /* The rates enabled for this rate class. + * + * Range: CONF_HW_BIT_RATE_* bit mask + */ + u32 enabled_rates; + + /* The dot11 short retry limit used for TX retries. + * + * Range: uint8_t + */ + u8 short_retry_limit; + + /* The dot11 long retry limit used for TX retries. + * + * Range: uint8_t + */ + u8 long_retry_limit; + + /* Flags controlling the attributes of TX transmission. + * + * Range: bit 0: Truncate - when set, FW attempts to send a frame stop + * when the total valid per-rate attempts have + * been exhausted; otherwise transmissions + * will continue at the lowest available rate + * until the appropriate one of the + * short_retry_limit, long_retry_limit, + * dot11_max_transmit_msdu_life_time, or + * max_tx_life_time, is exhausted. + * 1: Preamble Override - indicates if the preamble type + * should be used in TX. + * 2: Preamble Type - the type of the preamble to be used by + * the policy (0 - long preamble, 1 - short preamble. + */ + u8 aflags; +} __packed; + +#define CONF_TX_MAX_AC_COUNT 4 + +/* Slot number setting to start transmission at PIFS interval */ +#define CONF_TX_AIFS_PIFS 1 +/* Slot number setting to start transmission at DIFS interval normal + * DCF access + */ +#define CONF_TX_AIFS_DIFS 2 + +enum conf_tx_ac { + CONF_TX_AC_BE = 0, /* best effort / legacy */ + CONF_TX_AC_BK = 1, /* background */ + CONF_TX_AC_VI = 2, /* video */ + CONF_TX_AC_VO = 3, /* voice */ + CONF_TX_AC_CTS2SELF = 4, /* fictitious AC, follows AC_VO */ + CONF_TX_AC_ANY_TID = 0xff +}; + +struct conf_sig_weights { + /* RSSI from beacons average weight. + * + * Range: uint8_t + */ + u8 rssi_bcn_avg_weight; + + /* RSSI from data average weight. + * + * Range: uint8_t + */ + u8 rssi_pkt_avg_weight; + + /* SNR from beacons average weight. + * + * Range: uint8_t + */ + u8 snr_bcn_avg_weight; + + /* SNR from data average weight. + * + * Range: uint8_t + */ + u8 snr_pkt_avg_weight; +} __packed; + +struct conf_tx_ac_category { + /* The AC class identifier. + * + * Range: enum conf_tx_ac + */ + u8 ac; + + /* The contention window minimum size (in slots) for the access + * class. + * + * Range: uint8_t + */ + u8 cw_min; + + /* The contention window maximum size (in slots) for the access + * class. + * + * Range: uint8_t + */ + u16 cw_max; + + /* The AIF value (in slots) for the access class. + * + * Range: uint8_t + */ + u8 aifsn; + + /* The TX Op Limit (in microseconds) for the access class. + * + * Range: uint16_t + */ + u16 tx_op_limit; + + /* Is the MU EDCA configured + * + * Range: uint8_t + */ + u8 is_mu_edca; + + /* The AIFSN value for the corresonding access class + * + * Range: uint8_t + */ + u8 mu_edca_aifs; + + /* The ECWmin and ECWmax value is indicating contention window maximum + * size (in slots) for the access + * + * Range: uint8_t + */ + u8 mu_edca_ecw_min_max; + + /* The MU EDCA timer (in microseconds) obtaining an EDCA TXOP + * for STA using MU EDCA parameters + * + * Range: uint8_t + */ + u8 mu_edca_timer; +} __packed; + +#define CONF_TX_MAX_TID_COUNT 8 + +/* Allow TX BA on all TIDs but 6,7. These are currently reserved in the FW */ +#define CONF_TX_BA_ENABLED_TID_BITMAP 0x3F + +enum { + CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ + CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/ + CONF_CHANNEL_TYPE_HCCA = 2, /* HCCA*/ +}; + +enum { + CONF_PS_SCHEME_LEGACY = 0, + CONF_PS_SCHEME_UPSD_TRIGGER = 1, + CONF_PS_SCHEME_LEGACY_PSPOLL = 2, + CONF_PS_SCHEME_SAPSD = 3, +}; + +enum { + CONF_ACK_POLICY_LEGACY = 0, + CONF_ACK_POLICY_NO_ACK = 1, + CONF_ACK_POLICY_BLOCK = 2, +}; + +struct conf_tx_tid { + u8 queue_id; + u8 channel_type; + u8 tsid; + u8 ps_scheme; + u8 ack_policy; + u32 apsd_conf[2]; +} __packed; + +struct conf_tx_settings { + /* The TX ED value for TELEC Enable/Disable. + * + * Range: 0, 1 + */ + u8 tx_energy_detection; + + /* Configuration for rate classes for TX (currently only one + * rate class supported). Used in non-AP mode. + */ + struct conf_tx_rate_class sta_rc_conf; + + /* Configuration for access categories for TX rate control. + */ + u8 ac_conf_count; + /*struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT];*/ + struct conf_tx_ac_category ac_conf0; + struct conf_tx_ac_category ac_conf1; + struct conf_tx_ac_category ac_conf2; + struct conf_tx_ac_category ac_conf3; + + /* AP-mode - allow this number of TX retries to a station before an + * event is triggered from FW. + * In AP-mode the hlids of unreachable stations are given in the + * "sta_tx_retry_exceeded" member in the event mailbox. + */ + u8 max_tx_retries; + + /* AP-mode - after this number of seconds a connected station is + * considered inactive. + */ + u16 ap_aging_period; + + /* Configuration for TID parameters. + */ + u8 tid_conf_count; + /* struct conf_tx_tid tid_conf[]; */ + struct conf_tx_tid tid_conf0; + struct conf_tx_tid tid_conf1; + struct conf_tx_tid tid_conf2; + struct conf_tx_tid tid_conf3; + struct conf_tx_tid tid_conf4; + struct conf_tx_tid tid_conf5; + struct conf_tx_tid tid_conf6; + struct conf_tx_tid tid_conf7; + + /* The TX fragmentation threshold. + * + * Range: uint16_t + */ + u16 frag_threshold; + + /* Max time in msec the FW may delay frame TX-Complete interrupt. + * + * Range: uint16_t + */ + u16 tx_compl_timeout; + + /* Completed TX packet count which requires to issue the TX-Complete + * interrupt. + * + * Range: uint16_t + */ + u16 tx_compl_threshold; + + /* The rate used for control messages and scanning on the 2.4GHz band + * + * Range: CONF_HW_BIT_RATE_* bit mask + */ + u32 basic_rate; + + /* The rate used for control messages and scanning on the 5GHz band + * + * Range: CONF_HW_BIT_RATE_* bit mask + */ + u32 basic_rate_5; + + /* TX retry limits for templates + */ + u8 tmpl_short_retry_limit; + u8 tmpl_long_retry_limit; + + /* Time in ms for Tx watchdog timer to expire */ + u32 tx_watchdog_timeout; + + /* when a slow link has this much packets pending, it becomes a low + * priority link, scheduling-wise + */ + u8 slow_link_thold; + + /* when a fast link has this much packets pending, it becomes a low + * priority link, scheduling-wise + */ + u8 fast_link_thold; +} __packed; + +enum { + CONF_WAKE_UP_EVENT_BEACON = 0x00, /* Wake on every Beacon */ + CONF_WAKE_UP_EVENT_DTIM = 0x01, /* Wake on every DTIM */ + CONF_WAKE_UP_EVENT_N_DTIM = 0x02, /* Wake every Nth DTIM */ + CONF_WAKE_UP_EVENT_LIMIT = CONF_WAKE_UP_EVENT_N_DTIM, + /* Not supported: */ + CONF_WAKE_UP_EVENT_N_BEACONS = 0x03, /* Wake every Nth beacon */ + CONF_WAKE_UP_EVENT_BITS_MASK = 0x0F +}; + +#define CONF_MAX_BCN_FILT_IE_COUNT 32 + +#define CONF_BCN_RULE_PASS_ON_CHANGE BIT(0) +#define CONF_BCN_RULE_PASS_ON_APPEARANCE BIT(1) + +#define CONF_BCN_IE_OUI_LEN 3 +#define CONF_BCN_IE_VER_LEN 2 + +struct conf_bcn_filt_rule { + /* IE number to which to associate a rule. + * + * Range: uint8_t + */ + u8 ie; + + /* Rule to associate with the specific ie. + * + * Range: CONF_BCN_RULE_PASS_ON_* + */ + u8 rule; + + /* OUI for the vendor specifie IE (221) + */ + u8 oui[3]; + + /* Type for the vendor specifie IE (221) + */ + u8 type; + + /* Version for the vendor specifie IE (221) + */ + u8 version[2]; +} __packed; + +enum conf_bcn_filt_mode { + CONF_BCN_FILT_MODE_DISABLED = 0, + CONF_BCN_FILT_MODE_ENABLED = 1 +}; + +enum conf_bet_mode { + CONF_BET_MODE_DISABLE = 0, + CONF_BET_MODE_ENABLE = 1, +}; + +struct conf_conn_settings { + /* Enable or disable the beacon filtering. + * + * Range: CONF_BCN_FILT_MODE_* + */ + u8 bcn_filt_mode; + + /* Configure Beacon filter pass-thru rules. + */ + u8 bcn_filt_ie_count; + /*struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT];*/ + /* struct conf_bcn_filt_rule bcn_filt_ie[32]; */ + struct conf_bcn_filt_rule bcn_filt_ie0; + struct conf_bcn_filt_rule bcn_filt_ie1; + struct conf_bcn_filt_rule bcn_filt_ie2; + struct conf_bcn_filt_rule bcn_filt_ie3; + struct conf_bcn_filt_rule bcn_filt_ie4; + struct conf_bcn_filt_rule bcn_filt_ie5; + struct conf_bcn_filt_rule bcn_filt_ie6; + struct conf_bcn_filt_rule bcn_filt_ie7; + struct conf_bcn_filt_rule bcn_filt_ie8; + struct conf_bcn_filt_rule bcn_filt_ie9; + struct conf_bcn_filt_rule bcn_filt_ie10; + struct conf_bcn_filt_rule bcn_filt_ie11; + struct conf_bcn_filt_rule bcn_filt_ie12; + struct conf_bcn_filt_rule bcn_filt_ie13; + struct conf_bcn_filt_rule bcn_filt_ie14; + struct conf_bcn_filt_rule bcn_filt_ie15; + struct conf_bcn_filt_rule bcn_filt_ie16; + struct conf_bcn_filt_rule bcn_filt_ie17; + struct conf_bcn_filt_rule bcn_filt_ie18; + struct conf_bcn_filt_rule bcn_filt_ie19; + struct conf_bcn_filt_rule bcn_filt_ie20; + struct conf_bcn_filt_rule bcn_filt_ie21; + struct conf_bcn_filt_rule bcn_filt_ie22; + struct conf_bcn_filt_rule bcn_filt_ie23; + struct conf_bcn_filt_rule bcn_filt_ie24; + struct conf_bcn_filt_rule bcn_filt_ie25; + struct conf_bcn_filt_rule bcn_filt_ie26; + struct conf_bcn_filt_rule bcn_filt_ie27; + struct conf_bcn_filt_rule bcn_filt_ie28; + struct conf_bcn_filt_rule bcn_filt_ie29; + struct conf_bcn_filt_rule bcn_filt_ie30; + struct conf_bcn_filt_rule bcn_filt_ie31; + + /* The number of consecutive beacons to lose, before the firmware + * becomes out of synch. + * + * Range: uint32_t + */ + u32 synch_fail_thold; + + /* After out-of-synch, the number of TU's to wait without a further + * received beacon (or probe response) before issuing the BSS_EVENT_LOSE + * event. + * + * Range: uint32_t + */ + u32 bss_lose_timeout; + + /* Beacon receive timeout. + * + * Range: uint32_t + */ + u32 beacon_rx_timeout; + + /* Broadcast receive timeout. + * + * Range: uint32_t + */ + u32 broadcast_timeout; + + /* Enable/disable reception of broadcast packets in power save mode + * + * Range: 1 - enable, 0 - disable + */ + u8 rx_broadcast_in_ps; + + /* Consecutive PS Poll failures before sending event to driver + * + * Range: uint8_t + */ + u8 ps_poll_threshold; + + /* Configuration of signal average weights. + */ + struct conf_sig_weights sig_weights; + + /* Specifies if beacon early termination procedure is enabled or + * disabled. + * + * Range: CONF_BET_MODE_* + */ + u8 bet_enable; + + /* Specifies the maximum number of consecutive beacons that may be + * early terminated. After this number is reached at least one full + * beacon must be correctly received in FW before beacon ET + * resumes. + * + * Range 0 - 255 + */ + u8 bet_max_consecutive; + + /* Specifies the maximum number of times to try PSM entry if it fails + * (if sending the appropriate null-func message fails.) + * + * Range 0 - 255 + */ + u8 psm_entry_retries; + + /* Specifies the maximum number of times to try PSM exit if it fails + * (if sending the appropriate null-func message fails.) + * + * Range 0 - 255 + */ + u8 psm_exit_retries; + + /* Specifies the maximum number of times to try transmit the PSM entry + * null-func frame for each PSM entry attempt + * + * Range 0 - 255 + */ + u8 psm_entry_nullfunc_retries; + + /* Specifies the dynamic PS timeout in ms that will be used + * by the FW when in AUTO_PS mode + */ + u16 dynamic_ps_timeout; + + /* Specifies whether dynamic PS should be disabled and PSM forced. + * This is required for certain WiFi certification tests. + */ + u8 forced_ps; + + /* Specifies the interval of the connection keep-alive null-func + * frame in ms. + * + * Range: 1000 - 3600000 + */ + u32 keep_alive_interval; + + /* Maximum listen interval supported by the driver in units of beacons. + * + * Range: uint16_t + */ + u8 max_listen_interval; + + /* Default sleep authorization for a new STA interface. This determines + * whether we can go to ELP. + */ + u8 sta_sleep_auth; + + /* Default RX BA Activity filter configuration + */ + u8 suspend_rx_ba_activity; +} __packed; + +struct conf_itrim_settings { + /* enable dco itrim */ + u8 enable; + + /* moderation timeout in microsecs from the last TX */ + u32 timeout; +} __packed; + +enum conf_fast_wakeup { + CONF_FAST_WAKEUP_ENABLE, + CONF_FAST_WAKEUP_DISABLE, +}; + +struct conf_pm_config_settings { + /* Host clock settling time + * + * Range: 0 - 30000 us + */ + u32 host_clk_settling_time; + + /* Host fast wakeup support + * + * Range: enum conf_fast_wakeup + */ + u8 host_fast_wakeup_support; +} __packed; + +struct conf_roam_trigger_settings { + /* The minimum interval between two trigger events. + * + * Range: 0 - 60000 ms + */ + u16 trigger_pacing; + + /* The weight for rssi/beacon average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_rssi_beacon; + + /* The weight for rssi/data frame average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_rssi_data; + + /* The weight for snr/beacon average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_snr_beacon; + + /* The weight for snr/data frame average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_snr_data; +} __packed; + +struct conf_scan_settings { + /* The minimum time to wait on each channel for active scans + * This value will be used whenever there's a connected interface. + * + * Range: uint32_t tu/1000 + */ + u32 min_dwell_time_active; + + /* The maximum time to wait on each channel for active scans + * This value will be currently used whenever there's a + * connected interface. It shouldn't exceed 30000 (~30ms) to avoid + * possible interference of voip traffic going on while scanning. + * + * Range: uint32_t tu/1000 + */ + u32 max_dwell_time_active; + + /* The minimum time to wait on each channel for active scans + * when it's possible to have longer scan dwell times. + * Currently this is used whenever we're idle on all interfaces. + * Longer dwell times improve detection of networks within a + * single scan. + * + * Range: uint32_t tu/1000 + */ + u32 min_dwell_time_active_long; + + /* The maximum time to wait on each channel for active scans + * when it's possible to have longer scan dwell times. + * See min_dwell_time_active_long + * + * Range: uint32_t tu/1000 + */ + u32 max_dwell_time_active_long; + + /* time to wait on the channel for passive scans (in TU/1000) */ + u32 dwell_time_passive; + + /* time to wait on the channel for DFS scans (in TU/1000) */ + u32 dwell_time_dfs; + + /* Number of probe requests to transmit on each active scan channel + * + * Range: uint8_t + */ + u16 num_probe_reqs; + + /* Scan trigger (split scan) timeout. The FW will split the scan + * operation into slices of the given time and allow the FW to schedule + * other tasks in between. + * + * Range: uint32_t Microsecs + */ + u32 split_scan_timeout; +} __packed; + +struct conf_sched_scan_settings { + /* The base time to wait on the channel for active scans (in TU/1000). + * The minimum dwell time is calculated according to this: + * min_dwell_time = base + num_of_probes_to_be_sent * delta_per_probe + * The maximum dwell time is calculated according to this: + * max_dwell_time = min_dwell_time + max_dwell_time_delta + */ + u32 base_dwell_time; + + /* The delta between the min dwell time and max dwell time for + * active scans (in TU/1000s). The max dwell time is used by the FW once + * traffic is detected on the channel. + */ + u32 max_dwell_time_delta; + + /* Delta added to min dwell time per each probe in 2.4 GHz (TU/1000) */ + u32 dwell_time_delta_per_probe; + + /* Delta added to min dwell time per each probe in 5 GHz (TU/1000) */ + u32 dwell_time_delta_per_probe_5; + + /* time to wait on the channel for passive scans (in TU/1000) */ + u32 dwell_time_passive; + + /* time to wait on the channel for DFS scans (in TU/1000) */ + u32 dwell_time_dfs; + + /* number of probe requests to send on each channel in active scans */ + u8 num_probe_reqs; + + /* RSSI threshold to be used for filtering */ + s8 rssi_threshold; + + /* SNR threshold to be used for filtering */ + s8 snr_threshold; + + /* number of short intervals scheduled scan cycles before + * switching to long intervals + */ + u8 num_short_intervals; + + /* interval between each long scheduled scan cycle (in ms) */ + u16 long_interval; +} __packed; + +struct conf_ht_setting { + u8 rx_ba_win_size; + u8 tx_ba_win_size; + u16 inactivity_timeout; + + /* bitmap of enabled TIDs for TX BA sessions */ + u8 tx_ba_tid_bitmap; + + /* DEFAULT / WIDE / SISO20 */ + u8 mode; +} __packed; + +struct conf_memory_settings { + /* Number of stations supported in IBSS mode */ + u8 num_stations; + + /* Number of ssid profiles used in IBSS mode */ + u8 ssid_profiles; + + /* Number of memory buffers allocated to rx pool */ + u8 rx_block_num; + + /* Minimum number of blocks allocated to tx pool */ + u8 tx_min_block_num; + + /* Disable/Enable dynamic memory */ + u8 dynamic_memory; + + /* Minimum required free tx memory blocks in order to assure optimum + * performance + * + * Range: 0-120 + */ + u8 min_req_tx_blocks; + + /* Minimum required free rx memory blocks in order to assure optimum + * performance + * + * Range: 0-120 + */ + u8 min_req_rx_blocks; + + /* Minimum number of mem blocks (free+used) guaranteed for TX + * + * Range: 0-120 + */ + u8 tx_min; +} __packed; + +struct conf_rx_streaming_settings { + /* RX Streaming duration (in msec) from last tx/rx + * + * Range: uint32_t + */ + u32 duration; + + /* Bitmap of tids to be polled during RX streaming. + * (Note: it doesn't look like it really matters) + * + * Range: 0x1-0xff + */ + u8 queues; + + /* RX Streaming interval. + * (Note:this value is also used as the rx streaming timeout) + * Range: 0 (disabled), 10 - 100 + */ + u8 interval; + + /* enable rx streaming also when there is no coex activity + */ + u8 always; +} __packed; + +struct conf_fwlog { + /* Continuous or on-demand */ + u8 mode; + + /* Number of memory blocks dedicated for the FW logger + * + * Range: 2-16, or 0 to disable the FW logger + */ + u8 mem_blocks; + + /* Minimum log level threshold */ + u8 severity; + + /* Include/exclude timestamps from the log messages */ + u8 timestamp; + + /* See enum cc33xx_fwlogger_output */ + u8 output; + + /* Regulates the frequency of log messages */ + u8 threshold; +} __packed; + +#define ACX_RATE_MGMT_NUM_OF_RATES 13 +struct conf_rate_policy_settings { + u16 rate_retry_score; + u16 per_add; + u16 per_th1; + u16 per_th2; + u16 max_per; + u8 inverse_curiosity_factor; + u8 tx_fail_low_th; + u8 tx_fail_high_th; + u8 per_alpha_shift; + u8 per_add_shift; + u8 per_beta1_shift; + u8 per_beta2_shift; + u8 rate_check_up; + u8 rate_check_down; + u8 rate_retry_policy[13]; +} __packed; + +struct conf_hangover_settings { + u32 recover_time; + u8 hangover_period; + u8 dynamic_mode; + u8 early_termination_mode; + u8 max_period; + u8 min_period; + u8 increase_delta; + u8 decrease_delta; + u8 quiet_time; + u8 increase_time; + u8 window_size; +} __packed; + +enum { + CLOCK_CONFIG_16_2_M = 1, + CLOCK_CONFIG_16_368_M, + CLOCK_CONFIG_16_8_M, + CLOCK_CONFIG_19_2_M, + CLOCK_CONFIG_26_M, + CLOCK_CONFIG_32_736_M, + CLOCK_CONFIG_33_6_M, + CLOCK_CONFIG_38_468_M, + CLOCK_CONFIG_52_M, + + NUM_CLOCK_CONFIGS, +}; + +enum cc33xx_ht_mode { + /* Default - use MIMO, fallback to SISO20 */ + HT_MODE_DEFAULT = 0, + + /* Wide - use SISO40 */ + HT_MODE_WIDE = 1, + + /* Use SISO20 */ + HT_MODE_SISO20 = 2, +}; + +struct conf_ap_sleep_settings { + /* Duty Cycle (20-80% of staying Awake) for IDLE AP + * (0: disable) + */ + u8 idle_duty_cycle; + /* Duty Cycle (20-80% of staying Awake) for Connected AP + * (0: disable) + */ + u8 connected_duty_cycle; + /* Maximum stations that are allowed to be connected to AP + * (255: no limit) + */ + u8 max_stations_thresh; + /* Timeout till enabling the Sleep Mechanism after data stops + * [unit: 100 msec] + */ + u8 idle_conn_thresh; +} __packed; + +#define CHANNELS_COUNT 39 /* 14 2.4GHz channels, 25 5GHz channels*/ +#define PER_CHANNEL_REG_RULE_BYTES 13 +#define REG_RULES_COUNT (CHANNELS_COUNT * PER_CHANNEL_REG_RULE_BYTES) /* 507 */ + +/* TX Power limitation for a channel, used for reg domain */ +struct conf_channel_power_limit { + u32 reg_lim_0; + u32 reg_lim_1; + u32 reg_lim_2; + u8 reg_lim_3; +} __packed; + +struct conf_coex_configuration { + /* Work without Coex HW + * + * Range: 1 - YES, 0 - NO + */ + u8 disable_coex; + /* Yes/No Choose if External SoC entity is connected + * + * Range: 1 - YES, 0 - NO + */ + u8 is_ext_soc_enable; + /* External SoC grant polarity + * + * 0 - Active Low + * + * 1 - Active High (Default) + */ + u8 ext_soc_grant_polarity; + /* External SoC priority polarity + * + * 0 - Active Low (Default) + * + * 1 - Active High + */ + u8 ext_soc_priority_polarity; + /* External SoC request polarity + * + * 0 - Active Low (Default) + * + * 1 - Active High + */ + u8 ext_soc_request_polarity; + u16 ext_soc_min_grant_time; + u16 ext_soc_max_grant_time; + /* Range: 0 - 20 us + */ + u8 ext_soc_t2_time; + + u8 ext_soc_to_wifi_grant_delay; + u8 ext_soc_to_ble_grant_delay; +} __packed; + +struct conf_iomux_configuration { + /* For any iomux pull value: + * 1: Pull up + * 2: Pull down + * 3: Pull disable + * ff: Default value set by HW + * ANY other value is invalid + */ + u8 slow_clock_in_pull_val; + u8 sdio_clk_pull_val; + u8 sdio_cmd_pull_val; + u8 sdio_d0_pull_val; + u8 sdio_d1_pull_val; + u8 sdio_d2_pull_val; + u8 sdio_d3_pull_val; + u8 host_irq_wl_pull_val; + u8 uart1_tx_pull_val; + u8 uart1_rx_pull_val; + u8 uart1_cts_pull_val; + u8 uart1_rts_pull_val; + u8 coex_priority_pull_val; + u8 coex_req_pull_val; + u8 coex_grant_pull_val; + u8 host_irq_ble_pull_val; + u8 fast_clk_req_pull_val; + u8 ant_sel_pull_val; +} __packed; + +struct conf_ant_diversity { + /* First beacons after antenna switch. + * In this window we asses our satisfaction from the new antenna. + */ + u8 fast_switching_window; + + /* Deltas above this threshold between the curiosity score and + * the average RSSI will lead to antenna switch. + */ + u8 rssi_delta_for_switching; + + /* Used in the first beacons after antenna switch: + * Deltas above this threshold between the average RSSI and + * the curiosity score will make us switch back the antennas. + */ + u8 rssi_delta_for_fast_switching; + + /* Curiosity punishment in beacon timeout after an antenna switch. + */ + u8 curiosity_punish; + + /* Curiosity raise in beacon timeout not after an antenna switch. + */ + u8 curiosity_raise; + + /* Used for the average RSSI punishment in beacon timeout + * not after antenna switch. + */ + u8 consecutive_missed_beacons_threshold; + + /* Used in the curiosity metric. + */ + u8 compensation_log; + + /* Used in the average RSSI metric. + */ + u8 log_alpha; + + /* Curiosity initialization score. + */ + s8 initial_curiosity; + + /* MR configuration: should the AP follow the STA antenna or use the default antenna. + */ + u8 ap_follows_sta; + + /* MR configuration: should the BLE follow the STA antenna or use the default antenna. + */ + u8 ble_follows_sta; + + /* The antenna to use when the diversity mechanism is not in charge. + */ + u8 default_antenna; +} __packed; + +struct cc33xx_core_conf { + u8 enable_5ghz; + u8 enable_ble; + u8 enable_at_test_debug; + u8 disable_beamforming_fftp; + u32 ble_uart_baudrate; + u8 enable_flow_ctrl; + u8 listen_interval; + u8 wake_up_event; + u8 suspend_listen_interval; + u8 suspend_wake_up_event; + u8 per_channel_power_limit[507]; + u32 internal_slowclk_wakeup_earlier; + u32 internal_slowclk_open_window_longer; + u32 external_slowclk_wakeup_earlier; + u32 external_slowclk_open_window_longer; + struct conf_coex_configuration coex_configuration; + /* Prevent HW recovery. FW will remain stuck. */ + u8 no_recovery; + u8 disable_logger; + u8 mixed_mode_support; + u8 sram_ldo_voltage_trimming; + u32 xtal_settling_time_usec; + struct conf_ant_diversity ant_diversity; + struct conf_iomux_configuration iomux_configuration; +} __packed; + +struct cc33xx_mac_conf { + u8 ps_scheme; + u8 he_enable; + u8 ap_max_num_stations; +} __packed; + +struct cc33xx_phy_conf { + u8 insertion_loss_2_4ghz[2]; + u8 insertion_loss_5ghz[2]; + u8 reserved_0[2]; + u8 ant_gain_2_4ghz[2]; + u8 ant_gain_5ghz[2]; + u8 reserved_1[2]; + u8 ble_ch_lim_1m[40]; + u8 ble_ch_lim_2m[40]; + u8 one_time_calibration_only; + u8 is_diplexer_present; + u8 num_of_antennas; + u8 reg_domain; + u16 calib_period; +} __packed; + +struct cc33xx_host_conf { + struct conf_rx_settings rx; + struct conf_tx_settings tx; + struct conf_conn_settings conn; + struct conf_itrim_settings itrim; + struct conf_pm_config_settings pm_config; + struct conf_roam_trigger_settings roam_trigger; + struct conf_scan_settings scan; + struct conf_sched_scan_settings sched_scan; + struct conf_ht_setting ht; + struct conf_memory_settings mem; + struct conf_rx_streaming_settings rx_streaming; + struct conf_fwlog fwlog; + struct conf_rate_policy_settings rate; + struct conf_hangover_settings hangover; + struct conf_ap_sleep_settings ap_sleep; + +} __packed; + +struct cc33xx_conf_file { + struct cc33xx_conf_header header; + struct cc33xx_phy_conf phy; + struct cc33xx_mac_conf mac; + struct cc33xx_core_conf core; + struct cc33xx_host_conf host_conf; +} __packed; + +#endif diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/debug.h b/drivers/net/wireless/ti/cc33xx/debug.h --- a/drivers/net/wireless/ti/cc33xx/debug.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/debug.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#define DRIVER_NAME "cc33xx" +#define DRIVER_PREFIX DRIVER_NAME ": " + +enum { + DEBUG_NONE = 0, + DEBUG_IRQ = BIT(0), + DEBUG_SPI = BIT(1), + DEBUG_BOOT = BIT(2), + DEBUG_CORE_STATUS = BIT(3), + DEBUG_TESTMODE = BIT(4), + DEBUG_EVENT = BIT(5), + DEBUG_TX = BIT(6), + DEBUG_RX = BIT(7), + DEBUG_SCAN = BIT(8), + DEBUG_CRYPT = BIT(9), + DEBUG_PSM = BIT(10), + DEBUG_MAC80211 = BIT(11), + DEBUG_CMD = BIT(12), + DEBUG_ACX = BIT(13), + DEBUG_SDIO = BIT(14), + DEBUG_FILTERS = BIT(15), + DEBUG_ADHOC = BIT(16), + DEBUG_AP = BIT(17), + DEBUG_PROBE = BIT(18), + DEBUG_IO = BIT(19), + DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP), + DEBUG_CC33xx = BIT(20), + DEBUG_ALL = GENMASK(31, 0), + DEBUG_NO_DATAPATH = (DEBUG_ALL & ~DEBUG_IRQ & ~DEBUG_TX & ~DEBUG_RX & ~DEBUG_CORE_STATUS), +}; + +extern u32 cc33xx_debug_level; + +#define DEBUG_DUMP_LIMIT 1024 + +#define cc33xx_error(fmt, arg...) \ + pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg) + +#define cc33xx_warning(fmt, arg...) \ + pr_warn(DRIVER_PREFIX "WARNING " fmt "\n", ##arg) + +#define cc33xx_notice(fmt, arg...) \ + pr_info(DRIVER_PREFIX fmt "\n", ##arg) + +#define cc33xx_info(fmt, arg...) \ + pr_info(DRIVER_PREFIX fmt "\n", ##arg) + +/* define the debug macro differently if dynamic debug is supported */ +#if defined(CONFIG_DYNAMIC_DEBUG) +#define cc33xx_debug(level, fmt, arg...) \ + do { \ + if (unlikely((level) & cc33xx_debug_level)) \ + dynamic_pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \ + } while (0) +#else +#define cc33xx_debug(level, fmt, arg...) \ + do { \ + if (unlikely((level) & cc33xx_debug_level)) \ + pr_debug(pr_fmt(DRIVER_PREFIX fmt "\n"), \ + ##arg); \ + } while (0) +#endif /* CONFIG_DYNAMIC_DEBUG */ + +#define cc33xx_dump(level, prefix, buf, len) \ + do { \ + if ((level) & cc33xx_debug_level) \ + print_hex_dump_debug(DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + 0); \ + } while (0) + +#define cc33xx_dump_ascii(level, prefix, buf, len) \ + do { \ + if ((level) & cc33xx_debug_level) \ + print_hex_dump_debug(DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + true); \ + } while (0) + +#endif /* __DEBUG_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/event.c b/drivers/net/wireless/ti/cc33xx/event.c --- a/drivers/net/wireless/ti/cc33xx/event.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/event.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,385 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include "acx.h" +#include "event.h" +#include "ps.h" +#include "io.h" +#include "scan.h" + +#define CC33XX_WAIT_EVENT_FAST_POLL_COUNT 20 + +struct cc33xx_event_mailbox { + __le32 events_vector; + + u8 number_of_scan_results; + u8 number_of_sched_scan_results; + + __le16 channel_switch_role_id_bitmap; + + s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; + + /* bitmap of removed links */ + __le32 hlid_removed_bitmap; + + /* rx ba constraint */ + __le16 rx_ba_role_id_bitmap; /* 0xfff means any role. */ + __le16 rx_ba_allowed_bitmap; + + /* bitmap of roc completed (by role id) */ + __le16 roc_completed_bitmap; + + /* bitmap of stations (by role id) with bss loss */ + __le16 bss_loss_bitmap; + + /* bitmap of stations (by HLID) which exceeded max tx retries */ + __le16 tx_retry_exceeded_bitmap; + + /* time sync high msb*/ + __le16 time_sync_tsf_high_msb; + + /* bitmap of inactive stations (by HLID) */ + __le16 inactive_sta_bitmap; + + /* time sync high lsb*/ + __le16 time_sync_tsf_high_lsb; + + /* rx BA win size indicated by RX_BA_WIN_SIZE_CHANGE_EVENT_ID */ + u8 rx_ba_role_id; + u8 rx_ba_link_id; + u8 rx_ba_win_size; + u8 padding; + + /* smart config */ + u8 sc_ssid_len; + u8 sc_pwd_len; + u8 sc_token_len; + u8 padding1; + u8 sc_ssid[32]; + u8 sc_pwd[64]; + u8 sc_token[32]; + + /* smart config sync channel */ + u8 sc_sync_channel; + u8 sc_sync_band; + + /* time sync low msb*/ + __le16 time_sync_tsf_low_msb; + + /* radar detect */ + u8 radar_channel; + u8 radar_type; + + /* time sync low lsb*/ + __le16 time_sync_tsf_low_lsb; + + u8 ble_event[260]; + +} __packed; + +struct event_node { + struct llist_node node; + struct cc33xx_event_mailbox event_data; +}; + +void deffer_event(struct cc33xx *cc, + const void *event_payload, size_t event_length) +{ + struct event_node *event_node; + bool ret; + + if (WARN_ON(event_length != sizeof(event_node->event_data))) + return; + + event_node = kzalloc(sizeof(*event_node), GFP_KERNEL); + if (WARN_ON(!event_node)) + return; + + memcpy(&event_node->event_data, + event_payload, sizeof(event_node->event_data)); + + llist_add(&event_node->node, &cc->event_list); + ret = queue_work(cc->freezable_wq, &cc->irq_deferred_work); + + cc33xx_debug(DEBUG_IRQ, "Queued deferred work (%d)", ret); +} + +static inline struct llist_node *get_event_list(struct cc33xx *cc) +{ + struct llist_node *node; + + node = llist_del_all(&cc->event_list); + if (!node) + return NULL; + + return llist_reverse_order(node); +} + +void flush_deferred_event_list(struct cc33xx *cc) +{ + struct event_node *event_node, *tmp; + struct llist_node *event_list; + + event_list = get_event_list(cc); + llist_for_each_entry_safe(event_node, tmp, event_list, node) { + kfree(event_node); + } +} + +static int wait_for_event_or_timeout(struct cc33xx *cc, u32 mask, bool *timeout) +{ + u32 event; + unsigned long timeout_time; + u16 poll_count = 0; + int ret = 0; + struct event_node *event_node, *tmp; + struct llist_node *event_list; + u32 vector; + + *timeout = false; + + timeout_time = jiffies + msecs_to_jiffies(CC33XX_EVENT_TIMEOUT); + + do { + if (time_after(jiffies, timeout_time)) { + cc33xx_debug(DEBUG_CMD, "timeout waiting for event %d", + (int)mask); + *timeout = true; + goto out; + } + + poll_count++; + if (poll_count < CC33XX_WAIT_EVENT_FAST_POLL_COUNT) + usleep_range(50, 51); + else + usleep_range(1000, 5000); + + vector = 0; + event_list = get_event_list(cc); + llist_for_each_entry_safe(event_node, tmp, event_list, node) { + vector |= le32_to_cpu(event_node->event_data.events_vector); + } + + event = vector & mask; + } while (!event); + +out: + + return ret; +} + +int cc33xx_wait_for_event(struct cc33xx *cc, enum cc33xx_wait_event event, + bool *timeout) +{ + u32 local_event; + + switch (event) { + case CC33XX_EVENT_PEER_REMOVE_COMPLETE: + local_event = PEER_REMOVE_COMPLETE_EVENT_ID; + break; + + case CC33XX_EVENT_DFS_CONFIG_COMPLETE: + local_event = DFS_CHANNELS_CONFIG_COMPLETE_EVENT; + break; + + default: + /* event not implemented */ + return 0; + } + return wait_for_event_or_timeout(cc, local_event, timeout); +} + +static void cc33xx_event_sched_scan_completed(struct cc33xx *cc, u8 status) +{ + cc33xx_debug(DEBUG_EVENT, + "PERIODIC_SCAN_COMPLETE_EVENT (status 0x%0x)", status); + + if (cc->mac80211_scan_stopped) { + cc->mac80211_scan_stopped = false; + } else { + if (cc->sched_vif) { + ieee80211_sched_scan_stopped(cc->hw); + cc->sched_vif = NULL; + } + } +} + +static void cc33xx_event_channel_switch(struct cc33xx *cc, + unsigned long roles_bitmap, + bool success) +{ + struct cc33xx_vif *wlvif; + struct ieee80211_vif *vif; + + cc33xx_debug(DEBUG_EVENT, "%s: roles=0x%lx success=%d", + __func__, roles_bitmap, success); + + cc33xx_for_each_wlvif(cc, wlvif) { + if (wlvif->role_id == CC33XX_INVALID_ROLE_ID || + !test_bit(wlvif->role_id, &roles_bitmap)) + continue; + + if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, + &wlvif->flags)) + continue; + + vif = cc33xx_wlvif_to_vif(wlvif); + + if (wlvif->bss_type == BSS_TYPE_STA_BSS) { + ieee80211_chswitch_done(vif, success); + cancel_delayed_work(&wlvif->channel_switch_work); + } else { + set_bit(WLVIF_FLAG_BEACON_DISABLED, &wlvif->flags); + ieee80211_csa_finish(vif); + } + } +} + +static void cc33xx_disconnect_sta(struct cc33xx *cc, unsigned long sta_bitmap) +{ + u32 num_packets = cc->conf.host_conf.tx.max_tx_retries; + struct cc33xx_vif *wlvif; + struct ieee80211_vif *vif; + struct ieee80211_sta *sta; + const u8 *addr; + int h; + + for_each_set_bit(h, &sta_bitmap, CC33XX_MAX_LINKS) { + bool found = false; + /* find the ap vif connected to this sta */ + cc33xx_for_each_wlvif_ap(cc, wlvif) { + if (!test_bit(h, wlvif->ap.sta_hlid_map)) + continue; + found = true; + break; + } + if (!found) + continue; + + vif = cc33xx_wlvif_to_vif(wlvif); + addr = cc->links[h].addr; + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, addr); + if (sta) { + cc33xx_debug(DEBUG_EVENT, "remove sta %d", h); + ieee80211_report_low_ack(sta, num_packets); + } + rcu_read_unlock(); + } +} + +static void cc33xx_event_max_tx_failure(struct cc33xx *cc, + unsigned long sta_bitmap) +{ + cc33xx_disconnect_sta(cc, sta_bitmap); +} + +static void cc33xx_event_roc_complete(struct cc33xx *cc) +{ + if (cc->roc_vif) + ieee80211_ready_on_channel(cc->hw); +} + +static void cc33xx_event_beacon_loss(struct cc33xx *cc, + unsigned long roles_bitmap) +{ + /* We are HW_MONITOR device. On beacon loss - queue + * connection loss work. Cancel it on REGAINED event. + */ + struct cc33xx_vif *wlvif; + struct ieee80211_vif *vif; + int delay = cc->conf.host_conf.conn.synch_fail_thold; + + delay *= cc->conf.host_conf.conn.bss_lose_timeout; + + cc33xx_info("Beacon loss detected. roles:0x%lx", roles_bitmap); + + cc33xx_for_each_wlvif_sta(cc, wlvif) { + if (wlvif->role_id == CC33XX_INVALID_ROLE_ID || + !test_bit(wlvif->role_id, &roles_bitmap)) + continue; + + vif = cc33xx_wlvif_to_vif(wlvif); + + /* don't attempt roaming in case of p2p */ + if (wlvif->p2p) { + ieee80211_connection_loss(vif); + continue; + } + + /* if the work is already queued, it should take place. + * We don't want to delay the connection loss + * indication any more. + */ + ieee80211_queue_delayed_work(cc->hw, + &wlvif->connection_loss_work, + msecs_to_jiffies(delay)); + + ieee80211_cqm_beacon_loss_notify(vif, GFP_KERNEL); + } +} + +void process_deferred_events(struct cc33xx *cc) +{ + struct event_node *event_node, *tmp; + struct llist_node *event_list; + u32 vector; + + event_list = get_event_list(cc); + + llist_for_each_entry_safe(event_node, tmp, event_list, node) { + struct cc33xx_event_mailbox *event_data; + + event_data = &event_node->event_data; + + vector = le32_to_cpu(event_node->event_data.events_vector); + cc33xx_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector); + + if (vector & SCAN_COMPLETE_EVENT_ID) { + cc33xx_debug(DEBUG_EVENT, "scan results: %d", + event_node->event_data.number_of_scan_results); + + if (cc->scan_wlvif) + cc33xx_scan_completed(cc, cc->scan_wlvif); + } + + if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) + cc33xx_event_sched_scan_completed(cc, 1); + + if (vector & BSS_LOSS_EVENT_ID) { + u16 bss_loss_bitmap = le16_to_cpu(event_data->bss_loss_bitmap); + + cc33xx_event_beacon_loss(cc, bss_loss_bitmap); + } + + if (vector & MAX_TX_FAILURE_EVENT_ID) { + u16 tx_retry_exceeded_bitmap = + le16_to_cpu(event_data->tx_retry_exceeded_bitmap); + + cc33xx_event_max_tx_failure(cc, tx_retry_exceeded_bitmap); + } + + if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { + cc33xx_debug(DEBUG_EVENT, + "PERIODIC_SCAN_REPORT (results %d)", + event_data->number_of_sched_scan_results); + + cc33xx_scan_sched_scan_results(cc); + } + + if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) { + u16 channel_switch_role_id_bitmap = + le16_to_cpu(event_data->channel_switch_role_id_bitmap); + + cc33xx_event_channel_switch(cc, channel_switch_role_id_bitmap, true); + } + + if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID) + cc33xx_event_roc_complete(cc); + + kfree(event_node); + } +} diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/event.h b/drivers/net/wireless/ti/cc33xx/event.h --- a/drivers/net/wireless/ti/cc33xx/event.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/event.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __EVENT_H__ +#define __EVENT_H__ + +/* Mbox events + * + * The event mechanism is based on a pair of event buffers (buffers A and + * B) at fixed locations in the target's memory. The host processes one + * buffer while the other buffer continues to collect events. If the host + * is not processing events, an interrupt is issued to signal that a buffer + * is ready. Once the host is done with processing events from one buffer, + * it signals the target (with an ACK interrupt) that the event buffer is + * free. + */ + +enum { + RSSI_SNR_TRIGGER_0_EVENT_ID = BIT(0), + RSSI_SNR_TRIGGER_1_EVENT_ID = BIT(1), + RSSI_SNR_TRIGGER_2_EVENT_ID = BIT(2), + RSSI_SNR_TRIGGER_3_EVENT_ID = BIT(3), + RSSI_SNR_TRIGGER_4_EVENT_ID = BIT(4), + RSSI_SNR_TRIGGER_5_EVENT_ID = BIT(5), + RSSI_SNR_TRIGGER_6_EVENT_ID = BIT(6), + RSSI_SNR_TRIGGER_7_EVENT_ID = BIT(7), + + EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, +}; + +enum { + SCAN_COMPLETE_EVENT_ID = BIT(8), + RADAR_DETECTED_EVENT_ID = BIT(9), + CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(10), + BSS_LOSS_EVENT_ID = BIT(11), + MAX_TX_FAILURE_EVENT_ID = BIT(12), + DUMMY_PACKET_EVENT_ID = BIT(13), + INACTIVE_STA_EVENT_ID = BIT(14), + PEER_REMOVE_COMPLETE_EVENT_ID = BIT(15), + PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(16), + BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(17), + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(18), + DFS_CHANNELS_CONFIG_COMPLETE_EVENT = BIT(19), + PERIODIC_SCAN_REPORT_EVENT_ID = BIT(20), + RX_BA_WIN_SIZE_CHANGE_EVENT_ID = BIT(21), + SMART_CONFIG_SYNC_EVENT_ID = BIT(22), + SMART_CONFIG_DECODE_EVENT_ID = BIT(23), + TIME_SYNC_EVENT_ID = BIT(24), + FW_LOGGER_INDICATION = BIT(25), +}; + +/* events the driver might want to wait for */ +enum cc33xx_wait_event { + CC33XX_EVENT_ROLE_STOP_COMPLETE, + CC33XX_EVENT_PEER_REMOVE_COMPLETE, + CC33XX_EVENT_DFS_CONFIG_COMPLETE +}; + +#define NUM_OF_RSSI_SNR_TRIGGERS 8 + +struct cc33xx; + +int cc33xx_wait_for_event(struct cc33xx *cc, enum cc33xx_wait_event event, + bool *timeout); +void deffer_event(struct cc33xx *cc, const void *event_payload, size_t event_length); +void process_deferred_events(struct cc33xx *cc); +void flush_deferred_event_list(struct cc33xx *cc); + +#endif /* __EVENT_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/init.c b/drivers/net/wireless/ti/cc33xx/init.c --- a/drivers/net/wireless/ti/cc33xx/init.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/init.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include +#include "acx.h" +#include "cmd.h" +#include "conf.h" +#include "event.h" +#include "tx.h" +#include "init.h" + +static int cc33xx_init_phy_vif_config(struct cc33xx *cc, + struct cc33xx_vif *wlvif) +{ + int ret; + + ret = cc33xx_acx_slot(cc, wlvif, DEFAULT_SLOT_TIME); + if (ret < 0) + return ret; + + return 0; +} + +static int cc33xx_init_sta_beacon_filter(struct cc33xx *cc, + struct cc33xx_vif *wlvif) +{ + int ret; + + ret = cc33xx_acx_beacon_filter_table(cc, wlvif); + if (ret < 0) + return ret; + + /* disable beacon filtering until we get the first beacon */ + ret = cc33xx_acx_beacon_filter_opt(cc, wlvif, false); + if (ret < 0) + return ret; + + return 0; +} + +static int cc33xx_ap_init_templates(struct cc33xx *cc, + struct ieee80211_vif *vif) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + int ret; + + /* when operating as AP we want to receive external beacons for + * configuring ERP protection. + */ + ret = cc33xx_acx_beacon_filter_opt(cc, wlvif, false); + if (ret < 0) + return ret; + + return 0; +} + +static void cc33xx_set_ba_policies(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + /* Reset the BA RX indicators */ + wlvif->ba_allowed = true; + cc->ba_rx_session_count = 0; + + /* BA is supported in STA/AP modes */ + wlvif->ba_support = (wlvif->bss_type != BSS_TYPE_AP_BSS && + wlvif->bss_type != BSS_TYPE_STA_BSS); +} + +/* vif-specifc initialization */ +static int cc33xx_init_sta_role(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + int ret = cc33xx_acx_group_address_tbl(cc, true, NULL, 0); + + if (ret < 0) + return ret; + + /* Beacon filtering */ + ret = cc33xx_init_sta_beacon_filter(cc, wlvif); + if (ret < 0) + return ret; + + return 0; +} + +/* vif-specific initialization */ +static int cc33xx_init_ap_role(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + int ret; + + /* initialize Tx power */ + ret = cc33xx_acx_tx_power(cc, wlvif, wlvif->power_level); + if (ret < 0) + return ret; + + if (cc->radar_debug_mode) + cc33xx_cmd_generic_cfg(cc, wlvif, + CC33XX_CFG_FEATURE_RADAR_DEBUG, + cc->radar_debug_mode, 0); + + return 0; +} + +int cc33xx_init_vif_specific(struct cc33xx *cc, struct ieee80211_vif *vif) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + struct conf_tx_ac_category *conf_ac; + struct conf_tx_ac_category ac_conf[4]; + struct conf_tx_tid tid_conf[8]; + struct conf_tx_settings *tx_settings = &cc->conf.host_conf.tx; + struct conf_tx_ac_category *p_wl_host_ac_conf = &tx_settings->ac_conf0; + struct conf_tx_tid *p_wl_host_tid_conf = &tx_settings->tid_conf0; + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + u8 ps_scheme = cc->conf.mac.ps_scheme; + int ret, i; + + /* consider all existing roles before configuring psm. */ + + if (cc->ap_count == 0 && is_ap) { /* first AP */ + ret = cc33xx_acx_sleep_auth(cc, CC33XX_PSM_ELP); + if (ret < 0) + return ret; + + /* unmask ap events */ + cc->event_mask |= cc->ap_event_mask; + + /* first STA, no APs */ + } else if (cc->sta_count == 0 && cc->ap_count == 0 && !is_ap) { + u8 sta_auth = cc->conf.host_conf.conn.sta_sleep_auth; + /* Configure for power according to debugfs */ + if (sta_auth != CC33XX_PSM_ILLEGAL) + ret = cc33xx_acx_sleep_auth(cc, sta_auth); + /* Configure for ELP power saving */ + else + ret = cc33xx_acx_sleep_auth(cc, CC33XX_PSM_ELP); + + if (ret < 0) + return ret; + } + + /* Mode specific init */ + if (is_ap) { + ret = cc33xx_init_ap_role(cc, wlvif); + if (ret < 0) + return ret; + } else { + ret = cc33xx_init_sta_role(cc, wlvif); + if (ret < 0) + return ret; + } + + cc33xx_init_phy_vif_config(cc, wlvif); + + /* Default TID/AC configuration */ + WARN_ON(tx_settings->tid_conf_count != tx_settings->ac_conf_count); + memcpy(ac_conf, p_wl_host_ac_conf, 4 * sizeof(struct conf_tx_ac_category)); + memcpy(tid_conf, p_wl_host_tid_conf, 8 * sizeof(struct conf_tx_tid)); + + for (i = 0; i < tx_settings->tid_conf_count; i++) { + conf_ac = &ac_conf[i]; + + /* If no ps poll is used, send legacy ps scheme in cmd */ + if (ps_scheme == PS_SCHEME_NOPSPOLL) + ps_scheme = PS_SCHEME_LEGACY; + + ret = cc33xx_tx_param_cfg(cc, wlvif, conf_ac->ac, + conf_ac->cw_min, conf_ac->cw_max, + conf_ac->aifsn, conf_ac->tx_op_limit, + false, ps_scheme, conf_ac->is_mu_edca, + conf_ac->mu_edca_aifs, + conf_ac->mu_edca_ecw_min_max, + conf_ac->mu_edca_timer); + + if (ret < 0) + return ret; + } + + /* Mode specific init - post mem init */ + if (is_ap) + ret = cc33xx_ap_init_templates(cc, vif); + + if (ret < 0) + return ret; + + /* Configure initiator BA sessions policies */ + cc33xx_set_ba_policies(cc, wlvif); + + return 0; +} + +int cc33xx_hw_init(struct cc33xx *cc) +{ + cc33xx_acx_init_mem_config(cc); + + cc33xx_debug(DEBUG_TX, "available tx blocks: %d", 16); + cc->last_fw_rls_idx = 0; + cc->partial_rx.status = CURR_RX_START; + return 0; +} + +int cc33xx_download_ini_params_and_wait(struct cc33xx *cc) +{ + struct cc33xx_cmd_ini_params_download *cmd; + size_t command_size = ALIGN((sizeof(*cmd) + sizeof(cc->conf)), 4); + int ret; + + cc33xx_set_max_buffer_size(cc, INI_MAX_BUFFER_SIZE); + + cc33xx_debug(DEBUG_ACX, + "Downloading INI configurations to FW, payload Length: %zu", + sizeof(cc->conf)); + + cmd = kzalloc(command_size, GFP_KERNEL); + if (!cmd) { + cc33xx_set_max_buffer_size(cc, CMD_MAX_BUFFER_SIZE); + return -ENOMEM; + } + + cmd->length = cpu_to_le32(sizeof(cc->conf)); + + /* copy INI file params payload */ + memcpy((cmd->payload), &cc->conf, sizeof(cc->conf)); + + ret = cc33xx_cmd_send(cc, CMD_DOWNLOAD_INI_PARAMS, + cmd, command_size, 0); + if (ret < 0) { + cc33xx_warning("download INI params to FW command sending failed: %d", + ret); + } else { + cc33xx_debug(DEBUG_BOOT, "INI Params downloaded successfully"); + } + + cc33xx_set_max_buffer_size(cc, CMD_MAX_BUFFER_SIZE); + kfree(cmd); + return ret; +} diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/init.h b/drivers/net/wireless/ti/cc33xx/init.h --- a/drivers/net/wireless/ti/cc33xx/init.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/init.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __INIT_H__ +#define __INIT_H__ + +#include "cc33xx.h" + +int cc33xx_hw_init(struct cc33xx *cc); +int cc33xx_download_ini_params_and_wait(struct cc33xx *cc); +int cc33xx_init_vif_specific(struct cc33xx *cc, struct ieee80211_vif *vif); + +#endif /* __INIT_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/io.c b/drivers/net/wireless/ti/cc33xx/io.c --- a/drivers/net/wireless/ti/cc33xx/io.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/io.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include "cc33xx.h" +#include "debug.h" +#include "io.h" +#include "tx.h" + +bool cc33xx_set_block_size(struct cc33xx *cc) +{ + if (cc->if_ops->set_block_size) { + cc->if_ops->set_block_size(cc->dev, CC33XX_BUS_BLOCK_SIZE); + cc33xx_debug(DEBUG_CC33xx, + "Set BLKsize to %d", CC33XX_BUS_BLOCK_SIZE); + return true; + } + + cc33xx_debug(DEBUG_CC33xx, "Could not set BLKsize"); + return false; +} + +void cc33xx_disable_interrupts_nosync(struct cc33xx *cc) +{ + cc->if_ops->disable_irq(cc->dev); +} + +void cc33xx_irq(void *cookie); +void cc33xx_enable_interrupts(struct cc33xx *cc) +{ + cc->if_ops->enable_irq(cc->dev); + + cc33xx_debug(DEBUG_CC33xx, "IBI_WA: Read core status"); + cc33xx_irq(cc); + cc33xx_debug(DEBUG_CC33xx, "IBI_WA: Core status processed"); +} + +void cc33xx_io_reset(struct cc33xx *cc) +{ + if (cc->if_ops->reset) + cc->if_ops->reset(cc->dev); +} + +void cc33xx_io_init(struct cc33xx *cc) +{ + if (cc->if_ops->init) + cc->if_ops->init(cc->dev); +} + +/* Raw target IO, address is not translated */ +static int __must_check cc33xx_raw_write(struct cc33xx *cc, int addr, + void *buf, size_t len, bool fixed) +{ + int ret; + + if (test_bit(CC33XX_FLAG_IO_FAILED, &cc->flags) || + WARN_ON((test_bit(CC33XX_FLAG_IN_ELP, &cc->flags) && + addr != HW_ACCESS_ELP_CTRL_REG))) + return -EIO; + + ret = cc->if_ops->write(cc->dev, addr, buf, len, fixed); + if (ret && cc->state != CC33XX_STATE_OFF) + set_bit(CC33XX_FLAG_IO_FAILED, &cc->flags); + + return ret; +} + +int __must_check cc33xx_raw_read(struct cc33xx *cc, int addr, + void *buf, size_t len, bool fixed) +{ + int ret; + + if (test_bit(CC33XX_FLAG_IO_FAILED, &cc->flags) || + WARN_ON((test_bit(CC33XX_FLAG_IN_ELP, &cc->flags) && + addr != HW_ACCESS_ELP_CTRL_REG))) + return -EIO; + + ret = cc->if_ops->read(cc->dev, addr, buf, len, fixed); + if (ret && cc->state != CC33XX_STATE_OFF) + set_bit(CC33XX_FLAG_IO_FAILED, &cc->flags); + + return ret; +} + +int __must_check cc33xx_write(struct cc33xx *cc, int addr, + void *buf, size_t len, bool fixed) +{ + return cc33xx_raw_write(cc, addr, buf, len, fixed); +} + +void claim_core_status_lock(struct cc33xx *cc) +{ + /* When accessing core-status data (read or write) the transport lock + * should be held. + */ + cc->if_ops->interface_claim(cc->dev); +} + +void release_core_status_lock(struct cc33xx *cc) +{ + /* After accessing core-status data (read or write) the transport lock + * should be released. + */ + cc->if_ops->interface_release(cc->dev); +} + +void cc33xx_power_off(struct cc33xx *cc) +{ + int ret = 0; + + if (!test_bit(CC33XX_FLAG_GPIO_POWER, &cc->flags)) + return; + + if (cc->if_ops->power) + ret = cc->if_ops->power(cc->dev, false); + if (!ret) + clear_bit(CC33XX_FLAG_GPIO_POWER, &cc->flags); +} + +int cc33xx_power_on(struct cc33xx *cc) +{ + int ret = 0; + + if (cc->if_ops->power) + ret = cc->if_ops->power(cc->dev, true); + if (ret == 0) + set_bit(CC33XX_FLAG_GPIO_POWER, &cc->flags); + + return ret; +} diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/io.h b/drivers/net/wireless/ti/cc33xx/io.h --- a/drivers/net/wireless/ti/cc33xx/io.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/io.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __IO_H__ +#define __IO_H__ + +struct cc33xx; + +void cc33xx_disable_interrupts_nosync(struct cc33xx *cc); +void cc33xx_enable_interrupts(struct cc33xx *cc); +void cc33xx_io_reset(struct cc33xx *cc); +void cc33xx_io_init(struct cc33xx *cc); +int __must_check cc33xx_raw_read(struct cc33xx *cc, int addr, + void *buf, size_t len, bool fixed); +int __must_check cc33xx_write(struct cc33xx *cc, int addr, + void *buf, size_t len, bool fixed); +void claim_core_status_lock(struct cc33xx *cc); +void release_core_status_lock(struct cc33xx *cc); +void cc33xx_power_off(struct cc33xx *cc); +int cc33xx_power_on(struct cc33xx *cc); +int cc33xx_translate_addr(struct cc33xx *cc, int addr); +bool cc33xx_set_block_size(struct cc33xx *cc); + +#endif /* __IO_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/Kconfig b/drivers/net/wireless/ti/cc33xx/Kconfig --- a/drivers/net/wireless/ti/cc33xx/Kconfig 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/Kconfig 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-only +config CC33XX + tristate "TI CC33XX support" + depends on MAC80211 + select FW_LOADER + help + This module contains the main code for TI CC33XX WLAN chips. It abstracts + hardware-specific differences among different chipset families. + Each chipset family needs to implement its own lower-level module + that will depend on this module for the common code. + + If you choose to build a module, it will be called cc33xx. Say N if + unsure. + +config CC33XX_SDIO + tristate "TI CC33XX SDIO support" + depends on CC33XX && MMC + help + This module adds support for the SDIO interface of adapters using + TI CC33XX WLAN chipsets. Select this if your platform is using + the SDIO bus. + + If you choose to build a module, it'll be called cc33xx_sdio. + Say N if unsure. diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/main.c b/drivers/net/wireless/ti/cc33xx/main.c --- a/drivers/net/wireless/ti/cc33xx/main.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/main.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,5854 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include +#include +#include +#include +#include + +#include "../net/mac80211/ieee80211_i.h" + +#include "acx.h" +#include "boot.h" +#include "io.h" +#include "tx.h" +#include "ps.h" +#include "init.h" +#include "testmode.h" +#include "scan.h" +#include "event.h" + +#define CC33XX_FW_RX_PACKET_RAM (9 * 1024) +static int no_recovery = -1; + +u32 cc33xx_debug_level = DEBUG_NO_DATAPATH; + +/* HT cap appropriate for wide channels in 2Ghz */ +static struct ieee80211_sta_ht_cap cc33xx_siso40_ht_cap_2ghz = { + .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40 | + IEEE80211_HT_CAP_GRN_FLD, + .ht_supported = true, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .mcs = { + .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + .rx_highest = cpu_to_le16(150), + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, + }, +}; + +/* HT cap appropriate for wide channels in 5Ghz */ +static struct ieee80211_sta_ht_cap cc33xx_siso40_ht_cap_5ghz = { + .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD, + .ht_supported = true, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .mcs = { + .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + .rx_highest = cpu_to_le16(150), + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, + }, +}; + +/* HT cap appropriate for SISO 20 */ +static struct ieee80211_sta_ht_cap cc33xx_siso20_ht_cap = { + .cap = IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_MAX_AMSDU, + .ht_supported = true, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .mcs = { + .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + .rx_highest = cpu_to_le16(72), + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, + }, +}; + +#ifdef CONFIG_MAC80211_MESH +static const struct ieee80211_iface_limit cc33xx_iface_limits[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_P2P_CLIENT), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_GO) + | BIT(NL80211_IFTYPE_MESH_POINT) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +}; + +static inline u16 cc33xx_wiphy_interface_modes(void) +{ + return BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_DEVICE); +} +#else +static const struct ieee80211_iface_limit cc33xx_iface_limits[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_P2P_CLIENT), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_GO) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +}; + +static inline u16 cc33xx_wiphy_interface_modes(void) +{ + return BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE); +} +#endif /* CONFIG_MAC80211_MESH */ + +static const struct ieee80211_iface_combination +cc33xx_iface_combinations[] = { + { + .max_interfaces = 3, + .limits = cc33xx_iface_limits, + .n_limits = ARRAY_SIZE(cc33xx_iface_limits), + .num_different_channels = 2, + } +}; + +static const u8 cc33xx_rate_to_idx_2ghz[] = { + CONF_HW_RXTX_RATE_UNSUPPORTED, + 0, /* RATE_INDEX_1MBPS */ + 1, /* RATE_INDEX_2MBPS */ + 2, /* RATE_INDEX_5_5MBPS */ + 3, /* RATE_INDEX_11MBPS */ + 4, /* RATE_INDEX_6MBPS */ + 5, /* RATE_INDEX_9MBPS */ + 6, /* RATE_INDEX_12MBPS */ + 7, /* RATE_INDEX_18MBPS */ + 8, /* RATE_INDEX_24MBPS */ + 9, /* RATE_INDEX_36MBPS */ + 10, /* RATE_INDEX_48MBPS */ + 11, /* RATE_INDEX_54MBPS */ + 0, /* RATE_INDEX_MCS0 */ + 1, /* RATE_INDEX_MCS1 */ + 2, /* RATE_INDEX_MCS2 */ + 3, /* RATE_INDEX_MCS3 */ + 4, /* RATE_INDEX_MCS4 */ + 5, /* RATE_INDEX_MCS5 */ + 6, /* RATE_INDEX_MCS6 */ + 7 /* RATE_INDEX_MCS7 */ +}; + +static const u8 cc33xx_rate_to_idx_5ghz[] = { + CONF_HW_RXTX_RATE_UNSUPPORTED, + CONF_HW_RXTX_RATE_UNSUPPORTED, /* RATE_INDEX_1MBPS */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* RATE_INDEX_2MBPS */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* RATE_INDEX_5_5MBPS */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* RATE_INDEX_11MBPS */ + 0, /* RATE_INDEX_6MBPS */ + 1, /* RATE_INDEX_9MBPS */ + 2, /* RATE_INDEX_12MBPS */ + 3, /* RATE_INDEX_18MBPS */ + 4, /* RATE_INDEX_24MBPS */ + 5, /* RATE_INDEX_36MBPS */ + 6, /* RATE_INDEX_48MBPS */ + 7, /* RATE_INDEX_54MBPS */ + 0, /* RATE_INDEX_MCS0 */ + 1, /* RATE_INDEX_MCS1 */ + 2, /* RATE_INDEX_MCS2 */ + 3, /* RATE_INDEX_MCS3 */ + 4, /* RATE_INDEX_MCS4 */ + 5, /* RATE_INDEX_MCS5 */ + 6, /* RATE_INDEX_MCS6 */ + 7 /* RATE_INDEX_MCS7 */ +}; + +static const u8 *cc33xx_band_rate_to_idx[] = { + [NL80211_BAND_2GHZ] = cc33xx_rate_to_idx_2ghz, + [NL80211_BAND_5GHZ] = cc33xx_rate_to_idx_5ghz +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_rate cc33xx_rates[] = { + { .bitrate = 10, + .hw_value = CONF_HW_BIT_RATE_1MBPS, + .hw_value_short = CONF_HW_BIT_RATE_1MBPS, }, + { .bitrate = 20, + .hw_value = CONF_HW_BIT_RATE_2MBPS, + .hw_value_short = CONF_HW_BIT_RATE_2MBPS, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = CONF_HW_BIT_RATE_5_5MBPS, + .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = CONF_HW_BIT_RATE_11MBPS, + .hw_value_short = CONF_HW_BIT_RATE_11MBPS, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = CONF_HW_BIT_RATE_6MBPS, + .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, + { .bitrate = 90, + .hw_value = CONF_HW_BIT_RATE_9MBPS, + .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, + { .bitrate = 120, + .hw_value = CONF_HW_BIT_RATE_12MBPS, + .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, + { .bitrate = 180, + .hw_value = CONF_HW_BIT_RATE_18MBPS, + .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, + { .bitrate = 240, + .hw_value = CONF_HW_BIT_RATE_24MBPS, + .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, + { .bitrate = 360, + .hw_value = CONF_HW_BIT_RATE_36MBPS, + .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, + { .bitrate = 480, + .hw_value = CONF_HW_BIT_RATE_48MBPS, + .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, + { .bitrate = 540, + .hw_value = CONF_HW_BIT_RATE_54MBPS, + .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_channel cc33xx_channels[] = { + { .hw_value = 1, .center_freq = 2412, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 2, .center_freq = 2417, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 3, .center_freq = 2422, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 4, .center_freq = 2427, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 5, .center_freq = 2432, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 6, .center_freq = 2437, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 7, .center_freq = 2442, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 8, .center_freq = 2447, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 9, .center_freq = 2452, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 10, .center_freq = 2457, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 11, .center_freq = 2462, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 12, .center_freq = 2467, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 13, .center_freq = 2472, .max_power = CC33XX_MAX_TXPWR }, +}; + +static struct ieee80211_sband_iftype_data iftype_data_2ghz[] = {{ + .types_mask = BIT(NL80211_IFTYPE_STATION), + .he_cap = { + .has_he = true, + .he_cap_elem = { + .mac_cap_info[0] = + IEEE80211_HE_MAC_CAP0_HTC_HE | + IEEE80211_HE_MAC_CAP0_TWT_REQ, + .mac_cap_info[1] = + IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | + IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, + .mac_cap_info[2] = + IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP | + IEEE80211_HE_MAC_CAP2_ALL_ACK | + IEEE80211_HE_MAC_CAP2_TRS | + IEEE80211_HE_MAC_CAP2_BSR | + IEEE80211_HE_MAC_CAP2_ACK_EN, + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS, + .mac_cap_info[4] = + IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU | + IEEE80211_HE_MAC_CAP4_NDP_FB_REP | + IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, + .mac_cap_info[5] = + IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX, + .phy_cap_info[0] = 0, + .phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | + IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US, + .phy_cap_info[2] = + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, + .phy_cap_info[3] = + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM | + IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM | + IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, + .phy_cap_info[4] = + IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4, + .phy_cap_info[5] = + IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | + IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK, + .phy_cap_info[6] = + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | + IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | + IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB | + IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE, + .phy_cap_info[7] = + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI, + .phy_cap_info[8] = + IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | + IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI, + .phy_cap_info[9] = + IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US, + }, + /* Set default Tx/Rx HE MCS NSS Support field. + * Indicate support for up to 2 spatial streams and all + * MCS, without any special cases + */ + .he_mcs_nss_supp = { + .rx_mcs_80 = cpu_to_le16(0xfffc), + .tx_mcs_80 = cpu_to_le16(0xfffc), + .rx_mcs_160 = cpu_to_le16(0xffff), + .tx_mcs_160 = cpu_to_le16(0xffff), + .rx_mcs_80p80 = cpu_to_le16(0xffff), + .tx_mcs_80p80 = cpu_to_le16(0xffff), + }, + /* Set default PPE thresholds, with PPET16 set to 0, + * PPET8 set to 7 + */ + .ppe_thres = {0xff, 0xff, 0xff, 0xff}, + }, +}}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_supported_band cc33xx_band_2ghz = { + .channels = cc33xx_channels, + .n_channels = ARRAY_SIZE(cc33xx_channels), + .bitrates = cc33xx_rates, + .n_bitrates = ARRAY_SIZE(cc33xx_rates), + .iftype_data = iftype_data_2ghz, + .n_iftype_data = ARRAY_SIZE(iftype_data_2ghz), +}; + +/* 5 GHz data rates for cc33xx */ +static struct ieee80211_rate cc33xx_rates_5ghz[] = { + { .bitrate = 60, + .hw_value = CONF_HW_BIT_RATE_6MBPS, + .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, + { .bitrate = 90, + .hw_value = CONF_HW_BIT_RATE_9MBPS, + .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, + { .bitrate = 120, + .hw_value = CONF_HW_BIT_RATE_12MBPS, + .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, + { .bitrate = 180, + .hw_value = CONF_HW_BIT_RATE_18MBPS, + .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, + { .bitrate = 240, + .hw_value = CONF_HW_BIT_RATE_24MBPS, + .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, + { .bitrate = 360, + .hw_value = CONF_HW_BIT_RATE_36MBPS, + .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, + { .bitrate = 480, + .hw_value = CONF_HW_BIT_RATE_48MBPS, + .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, + { .bitrate = 540, + .hw_value = CONF_HW_BIT_RATE_54MBPS, + .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, +}; + +/* 5 GHz band channels for cc33xx */ +static struct ieee80211_channel cc33xx_channels_5ghz[] = { + { .hw_value = 36, .center_freq = 5180, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 40, .center_freq = 5200, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 44, .center_freq = 5220, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 48, .center_freq = 5240, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 52, .center_freq = 5260, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 56, .center_freq = 5280, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 60, .center_freq = 5300, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 64, .center_freq = 5320, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 100, .center_freq = 5500, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 104, .center_freq = 5520, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 108, .center_freq = 5540, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 112, .center_freq = 5560, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 116, .center_freq = 5580, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 120, .center_freq = 5600, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 124, .center_freq = 5620, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 128, .center_freq = 5640, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 132, .center_freq = 5660, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 136, .center_freq = 5680, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 140, .center_freq = 5700, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 149, .center_freq = 5745, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 153, .center_freq = 5765, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 157, .center_freq = 5785, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 161, .center_freq = 5805, .max_power = CC33XX_MAX_TXPWR }, + { .hw_value = 165, .center_freq = 5825, .max_power = CC33XX_MAX_TXPWR }, +}; + +static struct ieee80211_sband_iftype_data iftype_data_5ghz[] = {{ + .types_mask = BIT(NL80211_IFTYPE_STATION), + .he_cap = { + .has_he = true, + .he_cap_elem = { + .mac_cap_info[0] = + IEEE80211_HE_MAC_CAP0_HTC_HE | + IEEE80211_HE_MAC_CAP0_TWT_REQ, + .mac_cap_info[1] = + IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | + IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, + .mac_cap_info[2] = + IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP | + IEEE80211_HE_MAC_CAP2_ALL_ACK | + IEEE80211_HE_MAC_CAP2_TRS | + IEEE80211_HE_MAC_CAP2_BSR | + IEEE80211_HE_MAC_CAP2_ACK_EN, + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS, + .mac_cap_info[4] = + IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU | + IEEE80211_HE_MAC_CAP4_NDP_FB_REP | + IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, + .mac_cap_info[5] = + IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX, + .phy_cap_info[0] = 0, + .phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | + IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US, + .phy_cap_info[2] = + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, + .phy_cap_info[3] = + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM | + IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM | + IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, + .phy_cap_info[4] = + IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4, + .phy_cap_info[5] = + IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | + IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK, + .phy_cap_info[6] = + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | + IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | + IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB | + IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE, + .phy_cap_info[7] = + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI, + .phy_cap_info[8] = + IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | + IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI, + .phy_cap_info[9] = + IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US, + }, + /* Set default Tx/Rx HE MCS NSS Support field. + * Indicate support for up to 2 spatial streams and all + * MCS, without any special cases + */ + .he_mcs_nss_supp = { + .rx_mcs_80 = cpu_to_le16(0xfffc), + .tx_mcs_80 = cpu_to_le16(0xfffc), + .rx_mcs_160 = cpu_to_le16(0xffff), + .tx_mcs_160 = cpu_to_le16(0xffff), + .rx_mcs_80p80 = cpu_to_le16(0xffff), + .tx_mcs_80p80 = cpu_to_le16(0xffff), + }, + /* Set default PPE thresholds, with PPET16 set to 0, + * PPET8 set to 7 + */ + .ppe_thres = {0xff, 0xff, 0xff, 0xff}, + }, +}}; + +static struct ieee80211_supported_band cc33xx_band_5ghz = { + .channels = cc33xx_channels_5ghz, + .n_channels = ARRAY_SIZE(cc33xx_channels_5ghz), + .bitrates = cc33xx_rates_5ghz, + .n_bitrates = ARRAY_SIZE(cc33xx_rates_5ghz), + .vht_cap = { + .vht_supported = true, + .cap = (IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | (1 << + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT)), + .vht_mcs = { + .rx_mcs_map = cpu_to_le16(0xfffc), + .rx_highest = cpu_to_le16(7), + .tx_mcs_map = cpu_to_le16(0xfffc), + .tx_highest = cpu_to_le16(7), + }, + }, + .iftype_data = iftype_data_5ghz, + .n_iftype_data = ARRAY_SIZE(iftype_data_5ghz), + +}; + +static void __cc33xx_op_remove_interface(struct cc33xx *cc, + struct ieee80211_vif *vif, + bool reset_tx_queues); +static void cc33xx_turn_off(struct cc33xx *cc); +static void cc33xx_free_ap_keys(struct cc33xx *cc, struct cc33xx_vif *wlvif); +static int process_core_status(struct cc33xx *cc, + struct core_status *core_status); +static int cc33xx_setup(struct cc33xx *cc); + +static int cc33xx_set_authorized(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + int ret; + + if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS)) + return -EINVAL; + + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + return 0; + + if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags)) + return 0; + + ret = cc33xx_cmd_set_peer_state(cc, wlvif, wlvif->sta.hlid); + if (ret < 0) + return ret; + + cc33xx_info("Association complete."); + return 0; +} + +/* cc->mutex must be taken */ +void cc33xx_rearm_tx_watchdog_locked(struct cc33xx *cc) +{ + /* if the watchdog is not armed, don't do anything */ + if (cc->tx_allocated_blocks == 0) + return; + + cancel_delayed_work(&cc->tx_watchdog_work); + ieee80211_queue_delayed_work(cc->hw, &cc->tx_watchdog_work, + msecs_to_jiffies(cc->conf.host_conf.tx.tx_watchdog_timeout)); +} + +static void cc33xx_sta_rc_update(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + bool wide = wlvif->rc_update_bw >= IEEE80211_STA_RX_BW_40; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide); + + /* sanity */ + if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS)) + return; + + /* ignore the change before association */ + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + return; + + /* If we started out as wide, we can change the operation mode. If we + * thought this was a 20mhz AP, we have to reconnect + */ + if (wlvif->sta.role_chan_type != NL80211_CHAN_HT40MINUS && + wlvif->sta.role_chan_type != NL80211_CHAN_HT40PLUS) + ieee80211_connection_loss(cc33xx_wlvif_to_vif(wlvif)); +} + +static void cc33xx_rc_update_work(struct work_struct *work) +{ + struct cc33xx_vif *wlvif = container_of(work, struct cc33xx_vif, + rc_update_work); + struct cc33xx *cc = wlvif->cc; + struct ieee80211_vif *vif = cc33xx_wlvif_to_vif(wlvif); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + if (!ieee80211_vif_is_mesh(vif)) + cc33xx_sta_rc_update(cc, wlvif); + +out: + mutex_unlock(&cc->mutex); +} + +static inline void cc33xx_tx_watchdog_work(struct work_struct *work) +{ + container_of(to_delayed_work(work), struct cc33xx, tx_watchdog_work); +} + +static void cc33xx_adjust_conf(struct cc33xx *cc) +{ + if (no_recovery != -1) + cc->conf.core.no_recovery = (u8)no_recovery; +} + +void cc33xx_flush_deferred_work(struct cc33xx *cc) +{ + struct sk_buff *skb; + + /* Pass all received frames to the network stack */ + while ((skb = skb_dequeue(&cc->deferred_rx_queue))) { + cc33xx_debug(DEBUG_RX, "%s: rx skb 0x%p", __func__, skb); + ieee80211_rx_ni(cc->hw, skb); + } + + /* Return sent skbs to the network stack */ + while ((skb = skb_dequeue(&cc->deferred_tx_queue))) + ieee80211_tx_status_ni(cc->hw, skb); +} + +static void cc33xx_netstack_work(struct work_struct *work) +{ + struct cc33xx *cc = container_of(work, struct cc33xx, netstack_work); + + do { + cc33xx_flush_deferred_work(cc); + } while (skb_queue_len(&cc->deferred_rx_queue)); +} + +static int cc33xx_irq_locked(struct cc33xx *cc) +{ + int ret = 0; + struct core_status *core_status_ptr; + u8 *rx_buf_ptr; + u16 rx_buf_len; + size_t read_data_len; + const size_t maximum_rx_packet_size = CC33XX_FW_RX_PACKET_RAM; + size_t rx_byte_count; + struct NAB_rx_header *NAB_rx_header; + + process_deferred_events(cc); + + claim_core_status_lock(cc); + + rx_byte_count = (le32_to_cpu(cc->core_status->rx_status) & RX_BYTE_COUNT_MASK); + if (rx_byte_count != 0) { + const int read_headers_len = sizeof(struct core_status) + + sizeof(struct NAB_rx_header); + + /* Read aggressively as more data might be coming in */ + rx_byte_count *= 2; + + read_data_len = rx_byte_count + read_headers_len; + + if (cc->max_transaction_len) { /* Used in SPI interface */ + const int spi_alignment = sizeof(u32) - 1; + + read_data_len = __ALIGN_MASK(read_data_len, + spi_alignment); + read_data_len = min(read_data_len, + cc->max_transaction_len); + } else { /* SDIO */ + const int sdio_alignment = CC33XX_BUS_BLOCK_SIZE - 1; + + read_data_len = __ALIGN_MASK(read_data_len, + sdio_alignment); + read_data_len = min(read_data_len, + maximum_rx_packet_size); + } + + ret = cc33xx_raw_read(cc, NAB_DATA_ADDR, cc->aggr_buf, + read_data_len, true); + if (ret < 0) { + cc33xx_debug(DEBUG_IRQ, + "rx read Error response 0x%x", ret); + release_core_status_lock(cc); + return ret; + } + + core_status_ptr = (struct core_status *)((u8 *)cc->aggr_buf + + read_data_len - sizeof(struct core_status)); + + memcpy(cc->core_status, + core_status_ptr, sizeof(struct core_status)); + + process_core_status(cc, cc->core_status); + + release_core_status_lock(cc); + + cc33xx_debug(DEBUG_IRQ, "read rx data 0x%x", ret); + NAB_rx_header = (struct NAB_rx_header *)cc->aggr_buf; + rx_buf_len = le16_to_cpu(NAB_rx_header->len) - 8; + if (rx_buf_len != 0) { + rx_buf_ptr = (u8 *)cc->aggr_buf + sizeof(struct NAB_rx_header); + cc33xx_rx(cc, rx_buf_ptr, rx_buf_len); + } else { + cc33xx_error("Rx buffer length is 0"); + cc33xx_queue_recovery_work(cc); + } + } else { + cc33xx_debug(DEBUG_IRQ, "IRQ locked work: No rx data, releasing core-status lock"); + release_core_status_lock(cc); + } + + cc33xx_tx_immediate_complete(cc); + + return ret; +} + +static int read_core_status(struct cc33xx *cc, struct core_status *core_status) +{ + cc33xx_debug(DEBUG_CORE_STATUS, "Reading core status"); + + return cc33xx_raw_read(cc, NAB_STATUS_ADDR, core_status, + sizeof(*core_status), false); +} + +#define CTRL_TYPE_BITS 4 +static int get_type(struct control_info_descriptor *control_info_descriptor) +{ + u16 type_mask = GENMASK(CTRL_TYPE_BITS - 1, 0); + + return le16_to_cpu(control_info_descriptor->type_and_length) & type_mask; +} + +static unsigned int get_length(struct control_info_descriptor *control_info_descriptor) +{ + return le16_to_cpu(control_info_descriptor->type_and_length) >> CTRL_TYPE_BITS; +} + +static int parse_control_message(struct cc33xx *cc, + const u8 *buffer, size_t buffer_length) +{ + u8 *const end_of_payload = (u8 *const)buffer + buffer_length; + u8 *const start_of_payload = (u8 *const)buffer; + struct control_info_descriptor *control_info_descriptor; + const u8 *event_data, *cmd_result_data; + unsigned int ctrl_info_type, ctrl_info_length; + + while (buffer < end_of_payload) { + control_info_descriptor = + (struct control_info_descriptor *)buffer; + + ctrl_info_type = get_type(control_info_descriptor); + ctrl_info_length = get_length(control_info_descriptor); + + cc33xx_debug(DEBUG_CMD, "Processing message type %d, len %d", + ctrl_info_type, ctrl_info_length); + + switch (ctrl_info_type) { + case CTRL_MSG_EVENT: + event_data = buffer + sizeof(*control_info_descriptor); + + deffer_event(cc, event_data, ctrl_info_length); + break; + + case CTRL_MSG_COMMND_COMPLETE: + cmd_result_data = buffer; + cmd_result_data += sizeof(*control_info_descriptor); + + if (ctrl_info_length > sizeof(cc->command_result)) { + print_hex_dump(KERN_DEBUG, "message dump:", + DUMP_PREFIX_OFFSET, 16, 1, + cmd_result_data, + ctrl_info_length, false); + + WARN(1, "Error device response exceeds result buffer size"); + + goto message_parse_error; + } + + memcpy(cc->command_result, + cmd_result_data, ctrl_info_length); + + cc->result_length = ctrl_info_length; + + complete(&cc->command_complete); + break; + + default: + print_hex_dump(KERN_DEBUG, "message dump:", + DUMP_PREFIX_OFFSET, 16, 1, + start_of_payload, buffer_length, false); + + WARN(1, "Error processing device message @ offset %zu", + (size_t)(buffer - start_of_payload)); + + goto message_parse_error; + } + + buffer += sizeof(*control_info_descriptor); + buffer += ctrl_info_length; + } + + return 0; + +message_parse_error: + return -EIO; +} + +static int read_control_message(struct cc33xx *cc, u8 *read_buffer, + size_t buffer_size) +{ + int ret; + size_t device_message_size; + struct NAB_header *nab_header; + + ret = cc33xx_raw_read(cc, NAB_CONTROL_ADDR, read_buffer, + buffer_size, false); + + if (ret < 0) { + cc33xx_debug(DEBUG_CMD, + "control read Error response 0x%x", ret); + return ret; + } + + nab_header = (struct NAB_header *)read_buffer; + + if (le32_to_cpu(nab_header->sync_pattern) != DEVICE_SYNC_PATTERN) { + cc33xx_error("Wrong device sync pattern: 0x%x", + nab_header->sync_pattern); + return -EIO; + } + + device_message_size = sizeof(*nab_header) + NAB_EXTRA_BYTES + + le16_to_cpu(nab_header->len); + + if (device_message_size > buffer_size) { + cc33xx_error("Invalid NAB length field: %x", nab_header->len); + return -EIO; + } + + return le16_to_cpu(nab_header->len); +} + +static int process_event_and_cmd_result(struct cc33xx *cc, + struct core_status *core_status) +{ + int ret; + u8 *read_buffer, *message; + const size_t buffer_size = CC33XX_CMD_MAX_SIZE; + size_t message_length; + struct core_status *new_core_status; + __le32 previous_hint; + + read_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!read_buffer) + return -ENOMEM; + + ret = read_control_message(cc, read_buffer, buffer_size); + if (ret < 0) + goto out; + + message_length = ret - NAB_EXTRA_BYTES; + message = read_buffer + sizeof(struct NAB_header) + NAB_EXTRA_BYTES; + ret = parse_control_message(cc, message, message_length); + if (ret < 0) + goto out; + + /* Each read transaction always carries an updated core status */ + previous_hint = core_status->host_interrupt_status; + new_core_status = (struct core_status *) + (read_buffer + buffer_size - sizeof(struct core_status)); + memcpy(core_status, new_core_status, sizeof(*core_status)); + /* Host interrupt filed is clear-on-read and we do not want + * to overrun previously unhandled bits. + */ + core_status->host_interrupt_status |= previous_hint; + +out: + kfree(read_buffer); + return ret; +} + +static int verify_padding(struct core_status *core_status) +{ + unsigned int i; + const u32 valid_padding = 0x55555555; + + for (i = 0; i < ARRAY_SIZE(core_status->block_pad); i++) { + if (le32_to_cpu(core_status->block_pad[i]) != valid_padding) { + cc33xx_error("Error in core status padding:"); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, + 1, core_status, sizeof(*core_status), + false); + return -1; + } + } + + return 0; +} + +static int process_core_status(struct cc33xx *cc, + struct core_status *core_status) +{ + bool core_status_idle; + u32 shadow_host_interrupt_status; + int ret; + + do { + core_status_idle = true; + + shadow_host_interrupt_status = + le32_to_cpu(core_status->host_interrupt_status); + + /* Interrupts are aggregated (ORed) in this filed with each + * read operation from the device. + */ + core_status->host_interrupt_status = 0; + + cc33xx_debug(DEBUG_IRQ, + "HINT_STATUS: 0x%x, TSF: 0x%x, rx status: 0x%x", + shadow_host_interrupt_status, core_status->tsf, + core_status->rx_status); + + if (shadow_host_interrupt_status & HINT_COMMAND_COMPLETE) { + ret = process_event_and_cmd_result(cc, core_status); + if (ret < 0) { + memset(core_status, 0, sizeof(*core_status)); + return ret; + } + core_status_idle = false; + } + + if ((le32_to_cpu(core_status->rx_status) & RX_BYTE_COUNT_MASK) != 0) { + cc33xx_debug(DEBUG_RX, "Rx data pending, triggering deferred work"); + queue_work(cc->freezable_wq, &cc->irq_deferred_work); + } + + if (core_status->fw_info.tx_result_queue_index + != cc->last_fw_rls_idx){ + cc33xx_debug(DEBUG_TX, "Tx new result, triggering deferred work"); + queue_work(cc->freezable_wq, &cc->irq_deferred_work); + } + + if (shadow_host_interrupt_status & HINT_NEW_TX_RESULT) { + cc33xx_debug(DEBUG_TX, "Tx complete, triggering deferred work"); + queue_work(cc->freezable_wq, &cc->irq_deferred_work); + } + + if (shadow_host_interrupt_status & BOOT_TIME_INTERRUPTS) { + cc33xx_handle_boot_irqs(cc, + shadow_host_interrupt_status); + } + + if (shadow_host_interrupt_status & HINT_GENERAL_ERROR) { + cc33xx_error("FW is stuck, triggering recovery"); + cc33xx_queue_recovery_work(cc); + } + } while (!core_status_idle); + + return 0; +} + +void cc33xx_irq(void *cookie) +{ + struct cc33xx *cc = cookie; + unsigned long flags; + int ret; + + claim_core_status_lock(cc); + + if (test_bit(CC33XX_FLAG_SUSPENDED, &cc->flags)) { + /* don't enqueue a work right now. mark it as pending */ + set_bit(CC33XX_FLAG_PENDING_WORK, &cc->flags); + spin_lock_irqsave(&cc->cc_lock, flags); + cc33xx_disable_interrupts_nosync(cc); + pm_wakeup_hard_event(cc->dev); + spin_unlock_irqrestore(&cc->cc_lock, flags); + goto out; + } + + ret = read_core_status(cc, cc->core_status); + if (unlikely(ret < 0)) { + cc33xx_error("IO error during core status read"); + cc33xx_queue_recovery_work(cc); + goto out; + } + + ret = verify_padding(cc->core_status); + if (unlikely(ret < 0)) { + cc33xx_queue_recovery_work(cc); + goto out; + } + + process_core_status(cc, cc->core_status); + +out: + release_core_status_lock(cc); +} + +struct vif_counter_data { + u8 counter; + + struct ieee80211_vif *cur_vif; + bool cur_vif_running; +}; + +static void cc33xx_vif_count_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct vif_counter_data *counter = data; + + counter->counter++; + if (counter->cur_vif == vif) + counter->cur_vif_running = true; +} + +/* caller must not hold cc->mutex, as it might deadlock */ +static void cc33xx_get_vif_count(struct ieee80211_hw *hw, + struct ieee80211_vif *cur_vif, + struct vif_counter_data *data) +{ + memset(data, 0, sizeof(*data)); + data->cur_vif = cur_vif; + + ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, + cc33xx_vif_count_iter, data); +} + +void cc33xx_queue_recovery_work(struct cc33xx *cc) +{ + /* Avoid a recursive recovery */ + if (cc->state == CC33XX_STATE_ON) { + cc->state = CC33XX_STATE_RESTARTING; + set_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, &cc->flags); + ieee80211_queue_work(cc->hw, &cc->recovery_work); + } +} + +static void cc33xx_save_freed_pkts(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 hlid, struct ieee80211_sta *sta) +{ + struct cc33xx_station *wl_sta; + u32 sqn_recovery_padding = CC33XX_TX_SQN_POST_RECOVERY_PADDING; + + wl_sta = (void *)sta->drv_priv; + wl_sta->total_freed_pkts = cc->links[hlid].total_freed_pkts; + + /* increment the initial seq number on recovery to account for + * transmitted packets that we haven't yet got in the FW status + */ + if (wlvif->encryption_type == KEY_GEM) + sqn_recovery_padding = CC33XX_TX_SQN_POST_RECOVERY_PADDING_GEM; + + if (test_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, &cc->flags)) + wl_sta->total_freed_pkts += sqn_recovery_padding; +} + +static void cc33xx_save_freed_pkts_addr(struct cc33xx *cc, + struct cc33xx_vif *wlvif, + u8 hlid, const u8 *addr) +{ + struct ieee80211_sta *sta; + struct ieee80211_vif *vif = cc33xx_wlvif_to_vif(wlvif); + + if (WARN_ON(hlid == CC33XX_INVALID_LINK_ID || + is_zero_ether_addr(addr))) + return; + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, addr); + + if (sta) + cc33xx_save_freed_pkts(cc, wlvif, hlid, sta); + + rcu_read_unlock(); +} + +static void cc33xx_recovery_work(struct work_struct *work) +{ + struct cc33xx *cc = container_of(work, struct cc33xx, recovery_work); + struct cc33xx_vif *wlvif; + struct ieee80211_vif *vif; + + cc33xx_notice("CC33xx driver attempting recovery"); + + if (cc->conf.core.no_recovery) { + cc33xx_info("Recovery disabled by configuration, driver will not restart."); + return; + } + + if (test_bit(CC33XX_FLAG_DRIVER_REMOVED, &cc->flags)) { + cc33xx_info("Driver being removed, recovery disabled"); + return; + } + + cc->state = CC33XX_STATE_RESTARTING; + set_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, &cc->flags); + + mutex_lock(&cc->mutex); + while (!list_empty(&cc->wlvif_list)) { + wlvif = list_first_entry(&cc->wlvif_list, + struct cc33xx_vif, list); + vif = cc33xx_wlvif_to_vif(wlvif); + + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + ieee80211_connection_loss(vif); + + __cc33xx_op_remove_interface(cc, vif, false); + } + mutex_unlock(&cc->mutex); + + cc33xx_turn_off(cc); + msleep(500); + + mutex_lock(&cc->mutex); + cc33xx_init_fw(cc); + mutex_unlock(&cc->mutex); + + ieee80211_restart_hw(cc->hw); + + mutex_lock(&cc->mutex); + clear_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, &cc->flags); + mutex_unlock(&cc->mutex); +} + +static void irq_deferred_work(struct work_struct *work) +{ + int ret; + unsigned long flags; + struct cc33xx *cc = + container_of(work, struct cc33xx, irq_deferred_work); + + mutex_lock(&cc->mutex); + + ret = cc33xx_irq_locked(cc); + if (ret) + cc33xx_queue_recovery_work(cc); + + spin_lock_irqsave(&cc->cc_lock, flags); + /* In case TX was not handled here, queue TX work */ + clear_bit(CC33XX_FLAG_TX_PENDING, &cc->flags); + if (!test_bit(CC33XX_FLAG_FW_TX_BUSY, &cc->flags) && + cc33xx_tx_total_queue_count(cc) > 0) + ieee80211_queue_work(cc->hw, &cc->tx_work); + spin_unlock_irqrestore(&cc->cc_lock, flags); + + mutex_unlock(&cc->mutex); +} + +static void irq_wrapper(struct platform_device *pdev) +{ + struct cc33xx *cc = platform_get_drvdata(pdev); + + cc33xx_irq(cc); +} + +static int cc33xx_plt_init(struct cc33xx *cc) +{ + /* PLT init: Role enable + Role start + plt Init */ + int ret = 0; + + /* Role enable */ + u8 returned_role_id = CC33XX_INVALID_ROLE_ID; + u8 bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + ret = cc33xx_cmd_role_enable(cc, bcast_addr, + ROLE_TRANSCEIVER, &returned_role_id); + if (ret < 0) { + cc33xx_info("PLT init Role Enable FAILED! , PLT roleID is: %u ", + returned_role_id); + goto out; + } + + ret = cc33xx_cmd_role_start_transceiver(cc, returned_role_id); + if (ret < 0) { + cc33xx_info("PLT init Role Start FAILED! , PLT roleID is: %u ", + returned_role_id); + cc33xx_cmd_role_disable(cc, &returned_role_id); + goto out; + } + + cc->plt_role_id = returned_role_id; + ret = cc33xx_cmd_plt_enable(cc, returned_role_id); + + if (ret >= 0) { + cc33xx_info("PLT init Role Start succeed!, PLT roleID is: %u ", + returned_role_id); + } else { + cc33xx_info("PLT init Role Start FAILED! , PLT roleID is: %u ", + returned_role_id); + } + +out: + return ret; +} + +int cc33xx_plt_start(struct cc33xx *cc, const enum plt_mode plt_mode) +{ + int ret = 0; + + mutex_lock(&cc->mutex); + + if (plt_mode == PLT_ON && cc->plt_mode == PLT_ON) { + cc33xx_error("PLT already on"); + ret = 0; + goto out; + } + + cc33xx_notice("PLT start"); + + if (plt_mode != PLT_CHIP_AWAKE) { + ret = cc33xx_plt_init(cc); + if (ret < 0) { + cc33xx_error("PLT start failed"); + goto out; + } + } + + /* Indicate to lower levels that we are now in PLT mode */ + cc->plt = true; + cc->plt_mode = plt_mode; + +out: + mutex_unlock(&cc->mutex); + + return ret; +} + +int cc33xx_plt_stop(struct cc33xx *cc) +{ + int ret = 0; + + cc33xx_notice("PLT stop"); + + ret = cc33xx_cmd_role_stop_transceiver(cc); + if (ret < 0) + goto out; + + ret = cc33xx_cmd_role_disable(cc, &cc->plt_role_id); + if (ret < 0) + goto out; + else + cc33xx_cmd_plt_disable(cc); + + cc33xx_flush_deferred_work(cc); + + flush_deferred_event_list(cc); + + mutex_lock(&cc->mutex); + cc->plt = false; + cc->plt_mode = PLT_OFF; + cc->rx_counter = 0; + mutex_unlock(&cc->mutex); + +out: + return ret; +} + +static void cc33xx_op_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct cc33xx *cc = hw->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct cc33xx_vif *wlvif = NULL; + enum cc33xx_queue_stop_reason stop_reason = CC33XX_QUEUE_STOP_REASON_WATERMARK; + unsigned long flags; + int q, mapping; + u8 hlid; + + if (!vif) { + cc33xx_debug(DEBUG_TX, "DROP skb with no vif"); + ieee80211_free_txskb(hw, skb); + return; + } + + wlvif = cc33xx_vif_to_data(vif); + mapping = skb_get_queue_mapping(skb); + q = cc33xx_tx_get_queue(mapping); + + hlid = cc33xx_tx_get_hlid(cc, wlvif, skb, control->sta); + + spin_lock_irqsave(&cc->cc_lock, flags); + + /* drop the packet if the link is invalid or the queue is stopped + * for any reason but watermark. Watermark is a "soft"-stop so we + * allow these packets through. + */ + + if (hlid == CC33XX_INVALID_LINK_ID || + (!test_bit(hlid, wlvif->links_map)) || + (cc33xx_is_queue_stopped_locked(cc, wlvif, q) && + !cc33xx_is_queue_stopped_by_reason_locked(cc, wlvif, q, + stop_reason))) { + cc33xx_debug(DEBUG_TX, "DROP skb hlid %d q %d ", hlid, q); + ieee80211_free_txskb(hw, skb); + goto out; + } + + cc33xx_debug(DEBUG_TX, "queue skb hlid %d q %d len %d %p", + hlid, q, skb->len, skb); + skb_queue_tail(&cc->links[hlid].tx_queue[q], skb); + + cc->tx_queue_count[q]++; + wlvif->tx_queue_count[q]++; + + /* The workqueue is slow to process the tx_queue and we need stop + * the queue here, otherwise the queue will get too long. + */ + if (wlvif->tx_queue_count[q] >= CC33XX_TX_QUEUE_HIGH_WATERMARK && + !cc33xx_is_queue_stopped_by_reason_locked(cc, wlvif, q, + stop_reason)) { + cc33xx_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); + cc33xx_stop_queue_locked(cc, wlvif, q, stop_reason); + } + + /* The chip specific setup must run before the first TX packet - + * before that, the tx_work will not be initialized! + */ + if (!test_bit(CC33XX_FLAG_FW_TX_BUSY, &cc->flags) && + !test_bit(CC33XX_FLAG_TX_PENDING, &cc->flags)) { + cc33xx_debug(DEBUG_TX, "Triggering tx thread"); + ieee80211_queue_work(cc->hw, &cc->tx_work); + } else { + cc33xx_debug(DEBUG_TX, "Not triggering tx thread cc->flags 0x%lx", + cc->flags); + } + +out: + spin_unlock_irqrestore(&cc->cc_lock, flags); +} + +/* The size of the dummy packet should be at least 1400 bytes. However, in + * order to minimize the number of bus transactions, aligning it to 512 bytes + * boundaries could be beneficial, performance wise + */ +#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512)) + +static struct sk_buff *cc33xx_alloc_dummy_packet(struct cc33xx *cc) +{ + struct sk_buff *skb; + struct ieee80211_hdr_3addr *hdr; + unsigned int dummy_packet_size; + + dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE - + sizeof(struct cc33xx_tx_hw_descr) - sizeof(*hdr); + + skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE); + if (!skb) + return NULL; + + skb_reserve(skb, sizeof(struct cc33xx_tx_hw_descr)); + + hdr = skb_put_zero(skb, sizeof(*hdr)); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); + + skb_put_zero(skb, dummy_packet_size); + + /* Dummy packets require the TID to be management */ + skb->priority = CC33XX_TID_MGMT; + + /* Initialize all fields that might be used */ + skb_set_queue_mapping(skb, 0); + memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info)); + + return skb; +} + +static int cc33xx_validate_wowlan_pattern(struct cfg80211_pkt_pattern *p) +{ + int num_fields = 0, in_field = 0, fields_size = 0; + int i, pattern_len = 0; + + if (!p->mask) { + cc33xx_warning("No mask in WoWLAN pattern"); + return -EINVAL; + } + + /* The pattern is broken up into segments of bytes at different offsets + * that need to be checked by the FW filter. Each segment is called + * a field in the FW API. We verify that the total number of fields + * required for this pattern won't exceed FW limits (8) + * as well as the total fields buffer won't exceed the FW limit. + * Note that if there's a pattern which crosses Ethernet/IP header + * boundary a new field is required. + */ + for (i = 0; i < p->pattern_len; i++) { + if (test_bit(i, (unsigned long *)p->mask)) { + if (!in_field) { + in_field = 1; + pattern_len = 1; + } else if (i == CC33XX_RX_FILTER_ETH_HEADER_SIZE) { + num_fields++; + fields_size += pattern_len + + RX_FILTER_FIELD_OVERHEAD; + pattern_len = 1; + } else { + pattern_len++; + } + } else if (in_field) { + in_field = 0; + fields_size += pattern_len + RX_FILTER_FIELD_OVERHEAD; + num_fields++; + } + } + + if (in_field) { + fields_size += pattern_len + RX_FILTER_FIELD_OVERHEAD; + num_fields++; + } + + if (num_fields > CC33XX_RX_FILTER_MAX_FIELDS) { + cc33xx_warning("RX Filter too complex. Too many segments"); + return -EINVAL; + } + + if (fields_size > CC33XX_RX_FILTER_MAX_FIELDS_SIZE) { + cc33xx_warning("RX filter pattern is too big"); + return -E2BIG; + } + + return 0; +} + +static void cc33xx_rx_filter_free(struct cc33xx_rx_filter *filter) +{ + int i; + + if (!filter) + return; + + for (i = 0; i < filter->num_fields; i++) + kfree(filter->fields[i].pattern); + + kfree(filter); +} + +static int cc33xx_rx_filter_alloc_field(struct cc33xx_rx_filter *filter, + u16 offset, u8 flags, + const u8 *pattern, u8 len) +{ + struct cc33xx_rx_filter_field *field; + + if (filter->num_fields == CC33XX_RX_FILTER_MAX_FIELDS) { + cc33xx_warning("Max fields per RX filter. can't alloc another"); + return -EINVAL; + } + + field = &filter->fields[filter->num_fields]; + + field->pattern = kzalloc(len, GFP_KERNEL); + if (!field->pattern) + return -ENOMEM; + + filter->num_fields++; + + field->offset = cpu_to_le16(offset); + field->flags = flags; + field->len = len; + memcpy(field->pattern, pattern, len); + + return 0; +} + +/* Allocates an RX filter returned through f + * which needs to be freed using rx_filter_free() + */ +static int +cc33xx_convert_wowlan_pattern_to_rx_filter(struct cfg80211_pkt_pattern *p, + struct cc33xx_rx_filter **f) +{ + int i, j, ret = 0; + struct cc33xx_rx_filter *filter; + u16 offset; + u8 flags, len; + + filter = kzalloc(sizeof(*filter), GFP_KERNEL); + if (!filter) { + ret = -ENOMEM; + goto err; + } + + i = 0; + while (i < p->pattern_len) { + if (!test_bit(i, (unsigned long *)p->mask)) { + i++; + continue; + } + + for (j = i; j < p->pattern_len; j++) { + if (!test_bit(j, (unsigned long *)p->mask)) + break; + + if (i < CC33XX_RX_FILTER_ETH_HEADER_SIZE && + j >= CC33XX_RX_FILTER_ETH_HEADER_SIZE) + break; + } + + if (i < CC33XX_RX_FILTER_ETH_HEADER_SIZE) { + offset = i; + flags = CC33XX_RX_FILTER_FLAG_ETHERNET_HEADER; + } else { + offset = i - CC33XX_RX_FILTER_ETH_HEADER_SIZE; + flags = CC33XX_RX_FILTER_FLAG_IP_HEADER; + } + + len = j - i; + + ret = cc33xx_rx_filter_alloc_field(filter, offset, flags, + &p->pattern[i], len); + if (ret) + goto err; + + i = j; + } + + filter->action = FILTER_SIGNAL; + + *f = filter; + ret = 0; + goto out; + +err: + cc33xx_rx_filter_free(filter); + *f = NULL; +out: + return ret; +} + +static int cc33xx_configure_wowlan(struct cc33xx *cc, + struct cfg80211_wowlan *wow) +{ + int i, ret; + + if (!wow || (!wow->any && !wow->n_patterns)) { + if (wow) + cc33xx_warning("invalid wow configuration - set to pattern trigger without setting pattern"); + + ret = cc33xx_acx_default_rx_filter_enable(cc, 0, + FILTER_SIGNAL); + if (ret) + goto out; + + ret = cc33xx_rx_filter_clear_all(cc); + if (ret) + goto out; + + return 0; + } + + if (wow->any) { + ret = cc33xx_acx_default_rx_filter_enable(cc, 1, + FILTER_SIGNAL); + if (ret) + goto out; + + ret = cc33xx_rx_filter_clear_all(cc); + if (ret) + goto out; + + return 0; + } + + if (WARN_ON(wow->n_patterns > CC33XX_MAX_RX_FILTERS)) + return -EINVAL; + + /* Validate all incoming patterns before clearing current FW state */ + for (i = 0; i < wow->n_patterns; i++) { + ret = cc33xx_validate_wowlan_pattern(&wow->patterns[i]); + if (ret) { + cc33xx_warning("Bad wowlan pattern %d", i); + return ret; + } + } + + ret = cc33xx_acx_default_rx_filter_enable(cc, 0, FILTER_SIGNAL); + if (ret) + goto out; + + ret = cc33xx_rx_filter_clear_all(cc); + if (ret) + goto out; + + /* Translate WoWLAN patterns into filters */ + for (i = 0; i < wow->n_patterns; i++) { + struct cfg80211_pkt_pattern *p; + struct cc33xx_rx_filter *filter = NULL; + + p = &wow->patterns[i]; + + ret = cc33xx_convert_wowlan_pattern_to_rx_filter(p, &filter); + if (ret) { + cc33xx_warning("Failed to create an RX filter from wowlan pattern %d", + i); + goto out; + } + + ret = cc33xx_rx_filter_enable(cc, i, 1, filter); + + cc33xx_rx_filter_free(filter); + if (ret) + goto out; + } + + ret = cc33xx_acx_default_rx_filter_enable(cc, 1, FILTER_DROP); + +out: + return ret; +} + +static int cc33xx_configure_suspend_sta(struct cc33xx *cc, + struct cc33xx_vif *wlvif, + struct cfg80211_wowlan *wow) +{ + struct cc33xx_core_conf *core_conf = &cc->conf.core; + int ret = 0; + + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + goto out; + + ret = cc33xx_configure_wowlan(cc, wow); + if (ret < 0) + goto out; + + if (core_conf->suspend_wake_up_event == core_conf->wake_up_event && + core_conf->suspend_listen_interval == core_conf->listen_interval) + goto out; + + ret = cc33xx_acx_wake_up_conditions(cc, wlvif, + core_conf->suspend_wake_up_event, + core_conf->suspend_listen_interval); + + if (ret < 0) + cc33xx_error("suspend: set wake up conditions failed: %d", ret); +out: + return ret; +} + +static int cc33xx_configure_suspend_ap(struct cc33xx *cc, + struct cc33xx_vif *wlvif, + struct cfg80211_wowlan *wow) +{ + int ret = 0; + + if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) + goto out; + + ret = cc33xx_acx_beacon_filter_opt(cc, wlvif, true); + if (ret < 0) + goto out; + + ret = cc33xx_configure_wowlan(cc, wow); + if (ret < 0) + goto out; + +out: + return ret; +} + +static int cc33xx_configure_suspend(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct cfg80211_wowlan *wow) +{ + if (wlvif->bss_type == BSS_TYPE_STA_BSS) + return cc33xx_configure_suspend_sta(cc, wlvif, wow); + + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + return cc33xx_configure_suspend_ap(cc, wlvif, wow); + + return 0; +} + +static void cc33xx_configure_resume(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + int ret = 0; + bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; + bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; + struct cc33xx_core_conf *core_conf = &cc->conf.core; + + if (!is_ap && !is_sta) + return; + + if ((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) || + (is_ap && !test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))) + return; + + cc33xx_configure_wowlan(cc, NULL); + + if (is_sta) { + if (core_conf->suspend_wake_up_event == core_conf->wake_up_event && + core_conf->suspend_listen_interval == core_conf->listen_interval) + return; + + ret = cc33xx_acx_wake_up_conditions(cc, wlvif, + core_conf->wake_up_event, + core_conf->listen_interval); + + if (ret < 0) + cc33xx_error("resume: wake up conditions failed: %d", + ret); + + } else if (is_ap) { + ret = cc33xx_acx_beacon_filter_opt(cc, wlvif, false); + } +} + +static int __maybe_unused cc33xx_op_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wow) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif; + unsigned long flags; + int ret = 0; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); + WARN_ON(!wow); + + /* we want to perform the recovery before suspending */ + if (test_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, &cc->flags)) { + cc33xx_warning("postponing suspend to perform recovery"); + return -EBUSY; + } + + cc33xx_tx_flush(cc); + + mutex_lock(&cc->mutex); + + cc->keep_device_power = true; + cc33xx_for_each_wlvif(cc, wlvif) { + if (cc33xx_is_p2p_mgmt(wlvif)) + continue; + + ret = cc33xx_configure_suspend(cc, wlvif, wow); + if (ret < 0) { + mutex_unlock(&cc->mutex); + cc33xx_warning("couldn't prepare device to suspend"); + return ret; + } + } + + mutex_unlock(&cc->mutex); + + if (ret < 0) { + cc33xx_warning("couldn't prepare device to suspend"); + return ret; + } + + /* flush any remaining work */ + cc33xx_debug(DEBUG_MAC80211, "flushing remaining works"); + + flush_work(&cc->tx_work); + + /* Cancel the watchdog even if above tx_flush failed. We will detect + * it on resume anyway. + */ + cancel_delayed_work(&cc->tx_watchdog_work); + + /* set suspended flag to avoid triggering a new threaded_irq + * work. + */ + spin_lock_irqsave(&cc->cc_lock, flags); + set_bit(CC33XX_FLAG_SUSPENDED, &cc->flags); + spin_unlock_irqrestore(&cc->cc_lock, flags); + + return 0; +} + +static int __maybe_unused cc33xx_op_resume(struct ieee80211_hw *hw) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif; + unsigned long flags; + bool run_irq_work = false, pending_recovery; + int ret = 0; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", + cc->keep_device_power); + WARN_ON(!cc->keep_device_power); + + /* re-enable irq_work enqueuing, and call irq_work directly if + * there is a pending work. + */ + spin_lock_irqsave(&cc->cc_lock, flags); + clear_bit(CC33XX_FLAG_SUSPENDED, &cc->flags); + run_irq_work = test_and_clear_bit(CC33XX_FLAG_PENDING_WORK, &cc->flags); + spin_unlock_irqrestore(&cc->cc_lock, flags); + + mutex_lock(&cc->mutex); + + /* test the recovery flag before calling any SDIO functions */ + pending_recovery = test_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, + &cc->flags); + + if (run_irq_work) { + cc33xx_debug(DEBUG_MAC80211, "Running postponed irq_work directly"); + + /* don't talk to the HW if recovery is pending */ + if (!pending_recovery) { + ret = cc33xx_irq_locked(cc); + if (ret) + cc33xx_queue_recovery_work(cc); + } + + cc33xx_enable_interrupts(cc); + } + + if (pending_recovery) { + cc33xx_warning("queuing forgotten recovery on resume"); + ieee80211_queue_work(cc->hw, &cc->recovery_work); + goto out; + } + + cc33xx_for_each_wlvif(cc, wlvif) { + if (cc33xx_is_p2p_mgmt(wlvif)) + continue; + + cc33xx_configure_resume(cc, wlvif); + } + +out: + cc->keep_device_power = false; + + /* Set a flag to re-init the watchdog on the first Tx after resume. + * That way we avoid possible conditions where Tx-complete interrupts + * fail to arrive and we perform a spurious recovery. + */ + set_bit(CC33XX_FLAG_REINIT_TX_WDOG, &cc->flags); + mutex_unlock(&cc->mutex); + + return ret; +} + +static int cc33xx_op_start(struct ieee80211_hw *hw) +{ + cc33xx_debug(DEBUG_MAC80211, "mac80211 start"); + + /* We have to delay the booting of the hardware because + * we need to know the local MAC address before downloading and + * initializing the firmware. The MAC address cannot be changed + * after boot, and without the proper MAC address, the firmware + * will not function properly. + * + * The MAC address is first known when the corresponding interface + * is added. That is where we will initialize the hardware. + */ + + return 0; +} + +static void cc33xx_turn_off(struct cc33xx *cc) +{ + int i; + + if (cc->state == CC33XX_STATE_OFF) { + if (test_and_clear_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, + &cc->flags)) + cc33xx_enable_interrupts(cc); + + return; + } + + cc33xx_debug(DEBUG_BOOT, "Turning off"); + + mutex_lock(&cc->mutex); + + /* this must be before the cancel_work calls below, so that the work + * functions don't perform further work. + */ + cc->state = CC33XX_STATE_OFF; + + /* Use the nosync variant to disable interrupts, so the mutex could be + * held while doing so without deadlocking. + */ + cc33xx_disable_interrupts_nosync(cc); + + mutex_unlock(&cc->mutex); + + if (!test_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, &cc->flags)) + cancel_work_sync(&cc->recovery_work); + cc33xx_flush_deferred_work(cc); + cancel_delayed_work_sync(&cc->scan_complete_work); + cancel_work_sync(&cc->netstack_work); + cancel_work_sync(&cc->tx_work); + cancel_work_sync(&cc->irq_deferred_work); + cancel_delayed_work_sync(&cc->tx_watchdog_work); + + /* let's notify MAC80211 about the remaining pending TX frames */ + mutex_lock(&cc->mutex); + cc33xx_tx_reset(cc); + + cc33xx_power_off(cc); + + cc->band = NL80211_BAND_2GHZ; + + cc->rx_counter = 0; + cc->power_level = CC33XX_MAX_TXPWR; + cc->tx_blocks_available = 0; + cc->tx_allocated_blocks = 0; + + cc->ap_fw_ps_map = 0; + cc->ap_ps_map = 0; + cc->sleep_auth = CC33XX_PSM_ILLEGAL; + memset(cc->roles_map, 0, sizeof(cc->roles_map)); + memset(cc->links_map, 0, sizeof(cc->links_map)); + memset(cc->roc_map, 0, sizeof(cc->roc_map)); + memset(cc->session_ids, 0, sizeof(cc->session_ids)); + memset(cc->rx_filter_enabled, 0, sizeof(cc->rx_filter_enabled)); + cc->active_sta_count = 0; + cc->active_link_count = 0; + cc->ble_enable = 0; + + /* The system link is always allocated */ + cc->links[CC33XX_SYSTEM_HLID].allocated_pkts = 0; + cc->links[CC33XX_SYSTEM_HLID].prev_freed_pkts = 0; + __set_bit(CC33XX_SYSTEM_HLID, cc->links_map); + + /* this is performed after the cancel_work calls and the associated + * mutex_lock, so that cc33xx_op_add_interface does not accidentally + * get executed before all these vars have been reset. + */ + cc->flags = 0; + + for (i = 0; i < NUM_TX_QUEUES; i++) + cc->tx_allocated_pkts[i] = 0; + + kfree(cc->target_mem_map); + cc->target_mem_map = NULL; + + /* FW channels must be re-calibrated after recovery, + * save current Reg-Domain channel configuration and clear it. + */ + memcpy(cc->reg_ch_conf_pending, cc->reg_ch_conf_last, + sizeof(cc->reg_ch_conf_pending)); + memset(cc->reg_ch_conf_last, 0, sizeof(cc->reg_ch_conf_last)); + + mutex_unlock(&cc->mutex); +} + +static inline void cc33xx_op_stop(struct ieee80211_hw *hw) +{ + cc33xx_debug(DEBUG_MAC80211, "mac80211 stop"); +} + +static void cc33xx_channel_switch_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct cc33xx *cc; + struct ieee80211_vif *vif; + struct cc33xx_vif *wlvif; + + dwork = to_delayed_work(work); + wlvif = container_of(dwork, struct cc33xx_vif, channel_switch_work); + cc = wlvif->cc; + + cc33xx_info("channel switch failed (role_id: %d).", wlvif->role_id); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + /* check the channel switch is still ongoing */ + if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) + goto out; + + vif = cc33xx_wlvif_to_vif(wlvif); + ieee80211_chswitch_done(vif, false); + + cc33xx_cmd_stop_channel_switch(cc, wlvif); + +out: + mutex_unlock(&cc->mutex); +} + +static void cc33xx_connection_loss_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct cc33xx *cc; + struct ieee80211_vif *vif; + struct cc33xx_vif *wlvif; + + dwork = to_delayed_work(work); + wlvif = container_of(dwork, struct cc33xx_vif, connection_loss_work); + cc = wlvif->cc; + + cc33xx_info("Connection loss work (role_id: %d).", wlvif->role_id); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + /* Call mac80211 connection loss */ + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + goto out; + + vif = cc33xx_wlvif_to_vif(wlvif); + ieee80211_connection_loss(vif); + +out: + mutex_unlock(&cc->mutex); +} + +static void cc33xx_pending_auth_complete_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct cc33xx *cc; + struct cc33xx_vif *wlvif; + unsigned long time_spare; + + dwork = to_delayed_work(work); + wlvif = container_of(dwork, struct cc33xx_vif, + pending_auth_complete_work); + cc = wlvif->cc; + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + /* Make sure a second really passed since the last auth reply. Maybe + * a second auth reply arrived while we were stuck on the mutex. + * Check for a little less than the timeout to protect from scheduler + * irregularities. + */ + time_spare = msecs_to_jiffies(CC33XX_PEND_AUTH_ROC_TIMEOUT - 50); + time_spare += jiffies; + if (!time_after(time_spare, wlvif->pending_auth_reply_time)) + goto out; + + /* cancel the ROC if active */ + cc33xx_debug(DEBUG_CMD, + "pending_auth t/o expired - cancel ROC if active"); + + cc33xx_update_inconn_sta(cc, wlvif, NULL, false); + +out: + mutex_unlock(&cc->mutex); +} + +static void cc33xx_roc_timeout_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct cc33xx *cc; + struct cc33xx_vif *wlvif; + unsigned long time_spare; + + dwork = to_delayed_work(work); + wlvif = container_of(dwork, struct cc33xx_vif, roc_timeout_work); + cc = wlvif->cc; + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + /* Make sure that requested timeout really passed. Maybe an association + * completed and croc arrived while we were stuck on the mutex. + * Check for a little less than the timeout to protect from scheduler + * irregularities. + */ + time_spare = msecs_to_jiffies(CC33xx_PEND_ROC_COMPLETE_TIMEOUT - 50); + time_spare += jiffies; + if (!time_after(time_spare, wlvif->pending_auth_reply_time)) + goto out; + + /* cancel the ROC if active */ + cc33xx_debug(DEBUG_CMD, "Waiting for CROC Timeout has expired -> cancel ROC if exist"); + + if (test_bit(wlvif->role_id, cc->roc_map)) + cc33xx_croc(cc, wlvif->role_id); + +out: + mutex_unlock(&cc->mutex); +} + +static int cc33xx_allocate_rate_policy(struct cc33xx *cc, u8 *idx) +{ + u8 policy = find_first_zero_bit(cc->rate_policies_map, + CC33XX_MAX_RATE_POLICIES); + if (policy >= CC33XX_MAX_RATE_POLICIES) + return -EBUSY; + + __set_bit(policy, cc->rate_policies_map); + *idx = policy; + return 0; +} + +static void cc33xx_free_rate_policy(struct cc33xx *cc, u8 *idx) +{ + if (WARN_ON(*idx >= CC33XX_MAX_RATE_POLICIES)) + return; + + __clear_bit(*idx, cc->rate_policies_map); + *idx = CC33XX_MAX_RATE_POLICIES; +} + +static u8 cc33xx_get_role_type(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + struct ieee80211_vif *vif = cc33xx_wlvif_to_vif(wlvif); + + switch (wlvif->bss_type) { + case BSS_TYPE_AP_BSS: + if (wlvif->p2p) + return CC33XX_ROLE_P2P_GO; + else if (ieee80211_vif_is_mesh(vif)) + return CC33XX_ROLE_MESH_POINT; + else + return CC33XX_ROLE_AP; + + case BSS_TYPE_STA_BSS: + if (wlvif->p2p) + return CC33XX_ROLE_P2P_CL; + else + return CC33XX_ROLE_STA; + + case BSS_TYPE_IBSS: + return CC33XX_ROLE_IBSS; + + default: + cc33xx_error("invalid bss_type: %d", wlvif->bss_type); + } + return CC33XX_INVALID_ROLE_TYPE; +} + +static int cc33xx_init_vif_data(struct cc33xx *cc, struct ieee80211_vif *vif) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + struct conf_tx_settings *tx_settings = &cc->conf.host_conf.tx; + int i; + + /* clear everything but the persistent data */ + memset(wlvif, 0, offsetof(struct cc33xx_vif, persistent)); + + switch (ieee80211_vif_type_p2p(vif)) { + case NL80211_IFTYPE_P2P_CLIENT: + wlvif->p2p = 1; + fallthrough; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_DEVICE: + wlvif->bss_type = BSS_TYPE_STA_BSS; + break; + case NL80211_IFTYPE_ADHOC: + wlvif->bss_type = BSS_TYPE_IBSS; + break; + case NL80211_IFTYPE_P2P_GO: + wlvif->p2p = 1; + fallthrough; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + wlvif->bss_type = BSS_TYPE_AP_BSS; + break; + default: + wlvif->bss_type = MAX_BSS_TYPE; + return -EOPNOTSUPP; + } + + wlvif->role_id = CC33XX_INVALID_ROLE_ID; + wlvif->dev_role_id = CC33XX_INVALID_ROLE_ID; + wlvif->dev_hlid = CC33XX_INVALID_LINK_ID; + + if (wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS) { + /* init sta/ibss data */ + wlvif->sta.hlid = CC33XX_INVALID_LINK_ID; + cc33xx_allocate_rate_policy(cc, &wlvif->sta.basic_rate_idx); + cc33xx_allocate_rate_policy(cc, &wlvif->sta.ap_rate_idx); + cc33xx_allocate_rate_policy(cc, &wlvif->sta.p2p_rate_idx); + wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC; + wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC; + wlvif->rate_set = CONF_TX_RATE_MASK_BASIC; + } else { + /* init ap data */ + wlvif->ap.bcast_hlid = CC33XX_INVALID_LINK_ID; + wlvif->ap.global_hlid = CC33XX_INVALID_LINK_ID; + cc33xx_allocate_rate_policy(cc, &wlvif->ap.mgmt_rate_idx); + cc33xx_allocate_rate_policy(cc, &wlvif->ap.bcast_rate_idx); + for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) + cc33xx_allocate_rate_policy(cc, + &wlvif->ap.ucast_rate_idx[i]); + wlvif->basic_rate_set = CONF_TX_ENABLED_RATES; + /* TODO: check if basic_rate shouldn't be + * cc33xx_tx_min_rate_get(cc, wlvif->basic_rate_set); + * instead (the same thing for STA above). + */ + wlvif->basic_rate = CONF_TX_ENABLED_RATES; + /* TODO: this seems to be used only for STA, check it */ + wlvif->rate_set = CONF_TX_ENABLED_RATES; + } + + wlvif->bitrate_masks[NL80211_BAND_2GHZ] = tx_settings->basic_rate; + wlvif->bitrate_masks[NL80211_BAND_5GHZ] = tx_settings->basic_rate_5; + wlvif->beacon_int = CC33XX_DEFAULT_BEACON_INT; + + /* mac80211 configures some values globally, while we treat them + * per-interface. thus, on init, we have to copy them from cc + */ + wlvif->band = cc->band; + wlvif->power_level = cc->power_level; + + INIT_WORK(&wlvif->rc_update_work, cc33xx_rc_update_work); + INIT_DELAYED_WORK(&wlvif->channel_switch_work, + cc33xx_channel_switch_work); + INIT_DELAYED_WORK(&wlvif->connection_loss_work, + cc33xx_connection_loss_work); + INIT_DELAYED_WORK(&wlvif->pending_auth_complete_work, + cc33xx_pending_auth_complete_work); + INIT_DELAYED_WORK(&wlvif->roc_timeout_work, + cc33xx_roc_timeout_work); + INIT_LIST_HEAD(&wlvif->list); + + return 0; +} + +struct cc33xx_hw_queue_iter_data { + unsigned long hw_queue_map[BITS_TO_LONGS(CC33XX_NUM_MAC_ADDRESSES)]; + + /* current vif */ + struct ieee80211_vif *vif; + + /* is the current vif among those iterated */ + bool cur_running; +}; + +static void cc33xx_hw_queue_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct cc33xx_hw_queue_iter_data *iter_data = data; + + if (vif->type == NL80211_IFTYPE_P2P_DEVICE || + WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE)) + return; + + if (iter_data->cur_running || vif == iter_data->vif) { + iter_data->cur_running = true; + return; + } + + __set_bit(vif->hw_queue[0] / NUM_TX_QUEUES, iter_data->hw_queue_map); +} + +static int cc33xx_allocate_hw_queue_base(struct cc33xx *cc, + struct cc33xx_vif *wlvif) +{ + struct ieee80211_vif *vif = cc33xx_wlvif_to_vif(wlvif); + struct cc33xx_hw_queue_iter_data iter_data = {}; + int i, q_base; + + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { + vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; + return 0; + } + + iter_data.vif = vif; + + /* mark all bits taken by active interfaces */ + ieee80211_iterate_active_interfaces_atomic(cc->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + cc33xx_hw_queue_iter, &iter_data); + + /* the current vif is already running in mac80211 (resume/recovery) */ + if (iter_data.cur_running) { + wlvif->hw_queue_base = vif->hw_queue[0]; + cc33xx_debug(DEBUG_MAC80211, + "using pre-allocated hw queue base %d", + wlvif->hw_queue_base); + + /* interface type might have changed type */ + goto adjust_cab_queue; + } + + q_base = find_first_zero_bit(iter_data.hw_queue_map, + CC33XX_NUM_MAC_ADDRESSES); + if (q_base >= CC33XX_NUM_MAC_ADDRESSES) + return -EBUSY; + + wlvif->hw_queue_base = q_base * NUM_TX_QUEUES; + cc33xx_debug(DEBUG_MAC80211, "allocating hw queue base: %d", + wlvif->hw_queue_base); + + for (i = 0; i < NUM_TX_QUEUES; i++) { + cc->queue_stop_reasons[wlvif->hw_queue_base + i] = 0; + /* register hw queues in mac80211 */ + vif->hw_queue[i] = wlvif->hw_queue_base + i; + } + +adjust_cab_queue: + /* the last places are reserved for cab queues per interface */ + if (wlvif->bss_type == BSS_TYPE_AP_BSS) { + vif->cab_queue = NUM_TX_QUEUES * CC33XX_NUM_MAC_ADDRESSES + + wlvif->hw_queue_base / NUM_TX_QUEUES; + } else { + vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; + } + + return 0; +} + +static int cc33xx_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + struct vif_counter_data vif_count; + int ret = 0; + u8 role_type; + + if (cc->plt) { + cc33xx_error("Adding Interface not allowed while in PLT mode"); + return -EBUSY; + } + + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_UAPSD | + IEEE80211_VIF_SUPPORTS_CQM_RSSI; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", + ieee80211_vif_type_p2p(vif), vif->addr); + + cc33xx_get_vif_count(hw, vif, &vif_count); + + mutex_lock(&cc->mutex); + + /* in some very corner case HW recovery scenarios its possible to + * get here before __cc33xx_op_remove_interface is complete, so + * opt out if that is the case. + */ + if (test_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, &cc->flags) || + test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) { + ret = -EBUSY; + goto out; + } + + ret = cc33xx_init_vif_data(cc, vif); + if (ret < 0) + goto out; + + wlvif->cc = cc; + role_type = cc33xx_get_role_type(cc, wlvif); + if (role_type == CC33XX_INVALID_ROLE_TYPE) { + ret = -EINVAL; + goto out; + } + + ret = cc33xx_allocate_hw_queue_base(cc, wlvif); + if (ret < 0) + goto out; + + if (!cc33xx_is_p2p_mgmt(wlvif)) { + ret = cc33xx_cmd_role_enable(cc, vif->addr, + role_type, &wlvif->role_id); + if (ret < 0) + goto out; + + ret = cc33xx_init_vif_specific(cc, vif); + if (ret < 0) + goto out; + } else { + ret = cc33xx_cmd_role_enable(cc, vif->addr, CC33XX_ROLE_DEVICE, + &wlvif->dev_role_id); + if (ret < 0) + goto out; + + /* needed mainly for configuring rate policies */ + ret = cc33xx_acx_config_ps(cc, wlvif); + if (ret < 0) + goto out; + } + + list_add(&wlvif->list, &cc->wlvif_list); + set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags); + + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + cc->ap_count++; + else + cc->sta_count++; + +out: + mutex_unlock(&cc->mutex); + + return ret; +} + +static void __cc33xx_op_remove_interface(struct cc33xx *cc, + struct ieee80211_vif *vif, + bool reset_tx_queues) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + int i, ret; + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + + cc33xx_debug(DEBUG_MAC80211, "mac80211 remove interface %d", vif->type); + cc33xx_debug(DEBUG_MAC80211, "mac80211 rm: name1=%s, name2=%s, name3=%s", + sdata->name, sdata->dev->name, sdata->wdev.netdev->name); + + if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) + return; + + /* because of hardware recovery, we may get here twice */ + if (cc->state == CC33XX_STATE_OFF) + return; + + if (cc->scan.state != CC33XX_SCAN_STATE_IDLE && + cc->scan_wlvif == wlvif) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + /* Rearm the tx watchdog just before idling scan. This + * prevents just-finished scans from triggering the watchdog + */ + cc33xx_rearm_tx_watchdog_locked(cc); + + cc->scan.state = CC33XX_SCAN_STATE_IDLE; + memset(cc->scan.scanned_ch, 0, sizeof(cc->scan.scanned_ch)); + cc->scan_wlvif = NULL; + cc->scan.req = NULL; + ieee80211_scan_completed(cc->hw, &info); + } + + if (cc->sched_vif == wlvif) + cc->sched_vif = NULL; + + if (cc->roc_vif == vif) { + cc->roc_vif = NULL; + ieee80211_remain_on_channel_expired(cc->hw); + } + + if (!test_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, &cc->flags)) { + /* disable active roles */ + + if (wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS) { + if (wlvif->dev_hlid != CC33XX_INVALID_LINK_ID) + cc33xx_stop_dev(cc, wlvif); + } + + if (!cc33xx_is_p2p_mgmt(wlvif)) { + ret = cc33xx_cmd_role_disable(cc, &wlvif->role_id); + if (ret < 0) + goto deinit; + } else { + ret = cc33xx_cmd_role_disable(cc, &wlvif->dev_role_id); + if (ret < 0) + goto deinit; + } + } +deinit: + cc33xx_tx_reset_wlvif(cc, wlvif); + + /* clear all hlids (except system_hlid) */ + wlvif->dev_hlid = CC33XX_INVALID_LINK_ID; + + if (wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS) { + wlvif->sta.hlid = CC33XX_INVALID_LINK_ID; + cc33xx_free_rate_policy(cc, &wlvif->sta.basic_rate_idx); + cc33xx_free_rate_policy(cc, &wlvif->sta.ap_rate_idx); + cc33xx_free_rate_policy(cc, &wlvif->sta.p2p_rate_idx); + } else { + wlvif->ap.bcast_hlid = CC33XX_INVALID_LINK_ID; + wlvif->ap.global_hlid = CC33XX_INVALID_LINK_ID; + cc33xx_free_rate_policy(cc, &wlvif->ap.mgmt_rate_idx); + cc33xx_free_rate_policy(cc, &wlvif->ap.bcast_rate_idx); + for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) + cc33xx_free_rate_policy(cc, + &wlvif->ap.ucast_rate_idx[i]); + cc33xx_free_ap_keys(cc, wlvif); + } + + dev_kfree_skb(wlvif->probereq); + wlvif->probereq = NULL; + if (cc->last_wlvif == wlvif) + cc->last_wlvif = NULL; + list_del(&wlvif->list); + memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map)); + wlvif->role_id = CC33XX_INVALID_ROLE_ID; + wlvif->dev_role_id = CC33XX_INVALID_ROLE_ID; + + if (is_ap) + cc->ap_count--; + else + cc->sta_count--; + + /* Last AP, have more stations. Configure sleep auth according to STA. + * Don't do thin on unintended recovery. + */ + if (test_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, &cc->flags)) + goto unlock; + + /* mask ap events */ + if (cc->ap_count == 0 && is_ap) + cc->event_mask &= ~cc->ap_event_mask; + + if (cc->ap_count == 0 && is_ap && cc->sta_count) { + u8 sta_auth = cc->conf.host_conf.conn.sta_sleep_auth; + /* Configure for power according to debugfs */ + if (sta_auth != CC33XX_PSM_ILLEGAL) + cc33xx_acx_sleep_auth(cc, sta_auth); + /* Configure for ELP power saving */ + else + cc33xx_acx_sleep_auth(cc, CC33XX_PSM_ELP); + } + +unlock: + mutex_unlock(&cc->mutex); + + cancel_work_sync(&wlvif->rc_update_work); + cancel_delayed_work_sync(&wlvif->connection_loss_work); + cancel_delayed_work_sync(&wlvif->channel_switch_work); + cancel_delayed_work_sync(&wlvif->pending_auth_complete_work); + cancel_delayed_work_sync(&wlvif->roc_timeout_work); + + mutex_lock(&cc->mutex); +} + +static void cc33xx_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + struct cc33xx_vif *iter; + struct vif_counter_data vif_count; + + cc33xx_get_vif_count(hw, vif, &vif_count); + mutex_lock(&cc->mutex); + + if (cc->state == CC33XX_STATE_OFF || + !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) + goto out; + + /* cc->vif can be null here if someone shuts down the interface + * just when hardware recovery has been started. + */ + cc33xx_for_each_wlvif(cc, iter) { + if (iter != wlvif) + continue; + + __cc33xx_op_remove_interface(cc, vif, true); + break; + } + WARN_ON(iter != wlvif); + +out: + mutex_unlock(&cc->mutex); +} + +static int cc33xx_op_change_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum nl80211_iftype new_type, bool p2p) +{ + struct cc33xx *cc = hw->priv; + int ret; + + set_bit(CC33XX_FLAG_VIF_CHANGE_IN_PROGRESS, &cc->flags); + cc33xx_op_remove_interface(hw, vif); + + vif->type = new_type; + vif->p2p = p2p; + ret = cc33xx_op_add_interface(hw, vif); + + clear_bit(CC33XX_FLAG_VIF_CHANGE_IN_PROGRESS, &cc->flags); + return ret; +} + +static int cc33xx_join(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + int ret; + bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); + + /* One of the side effects of the JOIN command is that is clears + * WPA/WPA2 keys from the chipset. Performing a JOIN while associated + * to a WPA/WPA2 access point will therefore kill the data-path. + * Currently the only valid scenario for JOIN during association + * is on roaming, in which case we will also be given new keys. + * Keep the below message for now, unless it starts bothering + * users who really like to roam a lot :) + */ + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + cc33xx_info("JOIN while associated."); + + /* clear encryption type */ + wlvif->encryption_type = KEY_NONE; + + if (is_ibss) { + ret = cc33xx_cmd_role_start_ibss(cc, wlvif); + } else { + if (cc->quirks & CC33XX_QUIRK_START_STA_FAILS) { + /* TODO: this is an ugly workaround for wl12xx fw + * bug - we are not able to tx/rx after the first + * start_sta, so make dummy start+stop calls, + * and then call start_sta again. + * this should be fixed in the fw. + */ + cc33xx_cmd_role_start_sta(cc, wlvif); + cc33xx_cmd_role_stop_sta(cc, wlvif); + } + + ret = cc33xx_cmd_role_start_sta(cc, wlvif); + } + + return ret; +} + +static int cc33xx_ssid_set(struct cc33xx_vif *wlvif, + struct sk_buff *skb, int offset) +{ + u8 ssid_len; + const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, + skb->len - offset); + + if (!ptr) { + cc33xx_error("No SSID in IEs!"); + return -ENOENT; + } + + ssid_len = ptr[1]; + if (ssid_len > IEEE80211_MAX_SSID_LEN) { + cc33xx_error("SSID is too long!"); + return -EINVAL; + } + + wlvif->ssid_len = ssid_len; + memcpy(wlvif->ssid, ptr + 2, ssid_len); + return 0; +} + +static int cc33xx_set_ssid(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + struct ieee80211_vif *vif = cc33xx_wlvif_to_vif(wlvif); + struct sk_buff *skb; + int ieoffset; + + /* we currently only support setting the ssid from the ap probe req */ + if (wlvif->bss_type != BSS_TYPE_STA_BSS) + return -EINVAL; + + skb = ieee80211_ap_probereq_get(cc->hw, vif); + if (!skb) + return -EINVAL; + + ieoffset = offsetof(struct ieee80211_mgmt, u.probe_req.variable); + cc33xx_ssid_set(wlvif, skb, ieoffset); + dev_kfree_skb(skb); + + return 0; +} + +static int cc33xx_set_assoc(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct ieee80211_bss_conf *bss_conf, + struct ieee80211_sta *sta, + struct ieee80211_vif *vif, u32 sta_rate_set) +{ + int ret; + + wlvif->aid = vif->cfg.aid; + wlvif->channel_type = cfg80211_get_chandef_type(&bss_conf->chandef); + wlvif->beacon_int = bss_conf->beacon_int; + wlvif->wmm_enabled = bss_conf->qos; + + wlvif->nontransmitted = bss_conf->nontransmitted; + cc33xx_debug(DEBUG_MAC80211, "set_assoc mbssid params: nonTxbssid: %d, idx: %d, max_ind: %d, trans_bssid: %pM, ema_ap: %d", + bss_conf->nontransmitted, bss_conf->bssid_index, + bss_conf->bssid_indicator, bss_conf->transmitter_bssid, + bss_conf->ema_ap); + wlvif->bssid_index = bss_conf->bssid_index; + wlvif->bssid_indicator = bss_conf->bssid_indicator; + memcpy(wlvif->transmitter_bssid, bss_conf->transmitter_bssid, ETH_ALEN); + + set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); + + ret = cc33xx_assoc_info_cfg(cc, wlvif, sta, wlvif->aid); + if (ret < 0) + return ret; + + if (sta_rate_set) { + wlvif->rate_set = cc33xx_tx_enabled_rates_get(cc, sta_rate_set, + wlvif->band); + } + + return ret; +} + +static int cc33xx_unset_assoc(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + int ret; + bool sta = wlvif->bss_type == BSS_TYPE_STA_BSS; + + /* make sure we are connected (sta) joined */ + if (sta && !test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, + &wlvif->flags)) + return false; + + /* make sure we are joined (ibss) */ + if (!sta && test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) + return false; + + if (sta) { + /* use defaults when not associated */ + wlvif->aid = 0; + + /* free probe-request template */ + dev_kfree_skb(wlvif->probereq); + wlvif->probereq = NULL; + + /* disable beacon filtering */ + ret = cc33xx_acx_beacon_filter_opt(cc, wlvif, false); + if (ret < 0) + return ret; + } + + if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) { + struct ieee80211_vif *vif = cc33xx_wlvif_to_vif(wlvif); + + cc33xx_cmd_stop_channel_switch(cc, wlvif); + ieee80211_chswitch_done(vif, false); + cancel_delayed_work(&wlvif->channel_switch_work); + } + + return 0; +} + +static void cc33xx_set_band_rate(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band]; + wlvif->rate_set = wlvif->basic_rate_set; +} + +static void cc33xx_sta_handle_idle(struct cc33xx *cc, + struct cc33xx_vif *wlvif, bool idle) +{ + bool cur_idle = !test_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags); + + if (idle == cur_idle) + return; + + if (idle) { + clear_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags); + } else { + /* The current firmware only supports sched_scan in idle */ + if (cc->sched_vif == wlvif) + cc33xx_scan_sched_scan_stop(cc, wlvif); + + set_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags); + } +} + +static int cc33xx_config_vif(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct ieee80211_conf *conf, u64 changed) +{ + int ret; + + if (cc33xx_is_p2p_mgmt(wlvif)) + return 0; + + if (conf->power_level != wlvif->power_level && + (changed & IEEE80211_CONF_CHANGE_POWER)) { + ret = cc33xx_acx_tx_power(cc, wlvif, conf->power_level); + if (ret < 0) + return ret; + } + + return 0; +} + +static int cc33xx_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif; + struct ieee80211_conf *conf = &hw->conf; + int ret = 0; + + cc33xx_debug(DEBUG_MAC80211, + "mac80211 config psm %s power %d %s changed 0x%x", + conf->flags & IEEE80211_CONF_PS ? "on" : "off", + conf->power_level, + conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use", + changed); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + /* configure each interface */ + cc33xx_for_each_wlvif(cc, wlvif) { + ret = cc33xx_config_vif(cc, wlvif, conf, changed); + if (ret < 0) + goto out; + } + +out: + mutex_unlock(&cc->mutex); + + return ret; +} + +struct cc33xx_filter_params { + bool enabled; + int mc_list_length; + u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; +}; + +static u64 cc33xx_op_prepare_multicast(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list) +{ + struct cc33xx_filter_params *fp; + struct netdev_hw_addr *ha; + + fp = kzalloc(sizeof(*fp), GFP_ATOMIC); + if (!fp) { + cc33xx_error("Out of memory setting filters."); + return 0; + } + + /* update multicast filtering parameters */ + fp->mc_list_length = 0; + if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) { + fp->enabled = false; + cc33xx_debug(DEBUG_MAC80211, "mac80211 prepare multicast: too many addresses received, disable multicast filtering"); + } else { + fp->enabled = true; + netdev_hw_addr_list_for_each(ha, mc_list) { + memcpy(fp->mc_list[fp->mc_list_length], + ha->addr, ETH_ALEN); + fp->mc_list_length++; + } + } + + return (u64)(unsigned long)fp; +} + +#define CC33XX_SUPPORTED_FILTERS (FIF_ALLMULTI) + +static void cc33xx_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *total, u64 multicast) +{ + struct cc33xx_filter_params *fp = (void *)(unsigned long)multicast; + struct cc33xx *cc = hw->priv; + + cc33xx_debug(DEBUG_MAC80211, + "mac80211 configure filter, FIF_ALLMULTI = %d", + *total & FIF_ALLMULTI); + + mutex_lock(&cc->mutex); + + *total &= CC33XX_SUPPORTED_FILTERS; + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + if (!fp) + cc33xx_acx_group_address_tbl(cc, false, NULL, 0); + else if (*total & FIF_ALLMULTI || !fp->enabled) + cc33xx_acx_group_address_tbl(cc, false, NULL, 0); + else + cc33xx_acx_group_address_tbl(cc, true, fp->mc_list, fp->mc_list_length); + +out: + mutex_unlock(&cc->mutex); + kfree(fp); +} + +static int cc33xx_record_ap_key(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 id, u8 key_type, u8 key_size, const u8 *key, + u8 hlid, u32 tx_seq_32, u16 tx_seq_16) +{ + struct cc33xx_ap_key *ap_key; + int i; + + cc33xx_debug(DEBUG_CRYPT, "record ap key id %d", (int)id); + + if (key_size > MAX_KEY_SIZE) + return -EINVAL; + + /* Find next free entry in ap_keys. Also check we are not replacing + * an existing key. + */ + for (i = 0; i < MAX_NUM_KEYS; i++) { + if (!wlvif->ap.recorded_keys[i]) + break; + + if (wlvif->ap.recorded_keys[i]->id == id) { + cc33xx_warning("trying to record key replacement"); + return -EINVAL; + } + } + + if (i == MAX_NUM_KEYS) + return -EBUSY; + + ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL); + if (!ap_key) + return -ENOMEM; + + ap_key->id = id; + ap_key->key_type = key_type; + ap_key->key_size = key_size; + memcpy(ap_key->key, key, key_size); + ap_key->hlid = hlid; + ap_key->tx_seq_32 = tx_seq_32; + ap_key->tx_seq_16 = tx_seq_16; + + wlvif->ap.recorded_keys[i] = ap_key; + return 0; +} + +static void cc33xx_free_ap_keys(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + int i; + + for (i = 0; i < MAX_NUM_KEYS; i++) { + kfree(wlvif->ap.recorded_keys[i]); + wlvif->ap.recorded_keys[i] = NULL; + } +} + +static int cc33xx_ap_init_hwenc(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + int i, ret = 0; + struct cc33xx_ap_key *key; + bool wep_key_added = false; + + for (i = 0; i < MAX_NUM_KEYS; i++) { + u8 hlid; + + if (!wlvif->ap.recorded_keys[i]) + break; + + key = wlvif->ap.recorded_keys[i]; + hlid = key->hlid; + if (hlid == CC33XX_INVALID_LINK_ID) + hlid = wlvif->ap.bcast_hlid; + + ret = cc33xx_cmd_set_ap_key(cc, wlvif, KEY_ADD_OR_REPLACE, + key->id, key->key_type, + key->key_size, key->key, hlid, + key->tx_seq_32, key->tx_seq_16); + if (ret < 0) + goto out; + + if (key->key_type == KEY_WEP) + wep_key_added = true; + } + + if (wep_key_added) { + ret = cc33xx_cmd_set_default_wep_key(cc, wlvif->default_key, + wlvif->ap.bcast_hlid); + if (ret < 0) + goto out; + } + +out: + cc33xx_free_ap_keys(cc, wlvif); + return ret; +} + +static int cc33xx_config_key(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u16 action, u8 id, u8 key_type, u8 key_size, + const u8 *key, u32 tx_seq_32, u16 tx_seq_16, + struct ieee80211_sta *sta) +{ + int ret; + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + + if (is_ap) { + struct cc33xx_station *wl_sta; + u8 hlid; + + if (sta) { + wl_sta = (struct cc33xx_station *)sta->drv_priv; + hlid = wl_sta->hlid; + } else { + hlid = wlvif->ap.bcast_hlid; + } + + if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { + /* We do not support removing keys after AP shutdown. + * Pretend we do to make mac80211 happy. + */ + if (action != KEY_ADD_OR_REPLACE) + return 0; + + ret = cc33xx_record_ap_key(cc, wlvif, id, key_type, + key_size, key, hlid, + tx_seq_32, tx_seq_16); + } else { + ret = cc33xx_cmd_set_ap_key(cc, wlvif, action, id, + key_type, key_size, key, + hlid, tx_seq_32, tx_seq_16); + } + + if (ret < 0) + return ret; + } else { + const u8 *addr; + static const u8 bcast_addr[ETH_ALEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + addr = sta ? sta->addr : bcast_addr; + + if (is_zero_ether_addr(addr)) { + /* We dont support TX only encryption */ + return -EOPNOTSUPP; + } + + /* The cc33xx does not allow to remove unicast keys - they + * will be cleared automatically on next CMD_JOIN. Ignore the + * request silently, as we dont want the mac80211 to emit + * an error message. + */ + if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr)) + return 0; + + /* don't remove key if hlid was already deleted */ + if (action == KEY_REMOVE && + wlvif->sta.hlid == CC33XX_INVALID_LINK_ID) + return 0; + + ret = cc33xx_cmd_set_sta_key(cc, wlvif, action, id, key_type, + key_size, key, addr, tx_seq_32, + tx_seq_16); + if (ret < 0) + return ret; + } + + return 0; +} + +static int cc33xx_set_key(struct cc33xx *cc, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key_conf) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + int ret; + u32 tx_seq_32 = 0; + u16 tx_seq_16 = 0; + u8 key_type; + u8 hlid; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 set key"); + + cc33xx_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta); + cc33xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", + key_conf->cipher, key_conf->keyidx, + key_conf->keylen, key_conf->flags); + cc33xx_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); + + if (wlvif->bss_type == BSS_TYPE_AP_BSS) { + if (sta) { + struct cc33xx_station *wl_sta = (void *)sta->drv_priv; + + hlid = wl_sta->hlid; + } else { + hlid = wlvif->ap.bcast_hlid; + } + } else { + hlid = wlvif->sta.hlid; + } + + if (hlid != CC33XX_INVALID_LINK_ID) { + u64 tx_seq = cc->links[hlid].total_freed_pkts; + + tx_seq_32 = CC33XX_TX_SECURITY_HI32(tx_seq); + tx_seq_16 = CC33XX_TX_SECURITY_LO16(tx_seq); + } + + switch (key_conf->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + key_type = KEY_WEP; + key_conf->hw_key_idx = key_conf->keyidx; + break; + case WLAN_CIPHER_SUITE_TKIP: + key_type = KEY_TKIP; + key_conf->hw_key_idx = key_conf->keyidx; + break; + case WLAN_CIPHER_SUITE_CCMP: + key_type = KEY_AES; + key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + break; + case WLAN_CIPHER_SUITE_GCMP: + key_type = KEY_GCMP128; + key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + break; + case WLAN_CIPHER_SUITE_CCMP_256: + key_type = KEY_CCMP256; + key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + break; + case WLAN_CIPHER_SUITE_GCMP_256: + key_type = KEY_GCMP_256; + key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + key_type = KEY_IGTK; + break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + key_type = KEY_CMAC_256; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + key_type = KEY_GMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + key_type = KEY_GMAC_256; + break; + case CC33XX_CIPHER_SUITE_GEM: + key_type = KEY_GEM; + break; + default: + cc33xx_error("Unknown key algo 0x%x", key_conf->cipher); + + return -EOPNOTSUPP; + } + + switch (cmd) { + case SET_KEY: + ret = cc33xx_config_key(cc, wlvif, KEY_ADD_OR_REPLACE, + key_conf->keyidx, key_type, key_conf->keylen, + key_conf->key, tx_seq_32, tx_seq_16, sta); + if (ret < 0) { + cc33xx_error("Could not add or replace key"); + return ret; + } + + /* reconfiguring arp response if the unicast (or common) + * encryption key type was changed + */ + if (wlvif->bss_type == BSS_TYPE_STA_BSS && + (sta || key_type == KEY_WEP) && + wlvif->encryption_type != key_type) { + wlvif->encryption_type = key_type; + if (ret < 0) { + cc33xx_warning("build arp rsp failed: %d", ret); + return ret; + } + } + break; + + case DISABLE_KEY: + ret = cc33xx_config_key(cc, wlvif, KEY_REMOVE, key_conf->keyidx, + key_type, key_conf->keylen, + key_conf->key, 0, 0, sta); + if (ret < 0) { + cc33xx_error("Could not remove key"); + return ret; + } + break; + + default: + cc33xx_error("Unsupported key cmd 0x%x", cmd); + return -EOPNOTSUPP; + } + + return ret; +} + +static int cc33xx_hw_set_key(struct cc33xx *cc, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key_conf) +{ + bool special_enc; + int ret; + + cc33xx_debug(DEBUG_CRYPT, "extra spare keys before: %d", + cc->extra_spare_key_count); + + special_enc = key_conf->cipher == CC33XX_CIPHER_SUITE_GEM || + key_conf->cipher == WLAN_CIPHER_SUITE_TKIP; + + ret = cc33xx_set_key(cc, cmd, vif, sta, key_conf); + if (ret < 0) + goto out; + + /* when adding the first or removing the last GEM/TKIP key, + * we have to adjust the number of spare blocks. + */ + if (special_enc) { + if (cmd == SET_KEY) { + /* first key */ + cc->extra_spare_key_count++; + } else if (cmd == DISABLE_KEY) { + /* last key */ + cc->extra_spare_key_count--; + } + } + + cc33xx_debug(DEBUG_CRYPT, "extra spare keys after: %d", + cc->extra_spare_key_count); + +out: + return ret; +} + +static int cc33xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key_conf) +{ + struct cc33xx *cc = hw->priv; + int ret; + bool might_change_spare = key_conf->cipher == CC33XX_CIPHER_SUITE_GEM || + key_conf->cipher == WLAN_CIPHER_SUITE_TKIP; + + if (might_change_spare) { + /* stop the queues and flush to ensure the next packets are + * in sync with FW spare block accounting + */ + cc33xx_stop_queues(cc, CC33XX_QUEUE_STOP_REASON_SPARE_BLK); + cc33xx_tx_flush(cc); + } + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) { + ret = -EAGAIN; + goto out_wake_queues; + } + + ret = cc33xx_hw_set_key(cc, cmd, vif, sta, key_conf); + +out_wake_queues: + if (might_change_spare) + cc33xx_wake_queues(cc, CC33XX_QUEUE_STOP_REASON_SPARE_BLK); + + mutex_unlock(&cc->mutex); + + return ret; +} + +static void cc33xx_op_set_default_key_idx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + int key_idx) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + + cc33xx_debug(DEBUG_MAC80211, + "mac80211 set default key idx %d", key_idx); + + /* we don't handle unsetting of default key */ + if (key_idx == -1) + return; + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out_unlock; + + wlvif->default_key = key_idx; + + /* the default WEP key needs to be configured at least once */ + if (wlvif->encryption_type == KEY_WEP) + cc33xx_cmd_set_default_wep_key(cc, key_idx, wlvif->sta.hlid); + +out_unlock: + mutex_unlock(&cc->mutex); +} + +static int cc33xx_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req) +{ + struct cfg80211_scan_request *req = &hw_req->req; + struct cc33xx *cc = hw->priv; + int ret; + u8 *ssid = NULL; + size_t len = 0; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 hw scan"); + + if (req->n_ssids) { + ssid = req->ssids[0].ssid; + len = req->ssids[0].ssid_len; + } + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) { + /* We cannot return -EBUSY here because cfg80211 will expect + * a call to ieee80211_scan_completed if we do - in this case + * there won't be any call. + */ + ret = -EAGAIN; + goto out; + } + + /* fail if there is any role in ROC */ + if (find_first_bit(cc->roc_map, CC33XX_MAX_ROLES) < CC33XX_MAX_ROLES) { + /* don't allow scanning right now */ + ret = -EBUSY; + goto out; + } + + ret = cc33xx_scan(hw->priv, vif, ssid, len, req); + +out: + mutex_unlock(&cc->mutex); + + return ret; +} + +static void cc33xx_op_cancel_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + struct cfg80211_scan_info info = { + .aborted = true, + }; + int ret; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 cancel hw scan"); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + if (cc->scan.state == CC33XX_SCAN_STATE_IDLE) + goto out; + + if (cc->scan.state != CC33XX_SCAN_STATE_DONE) { + ret = cc33xx_scan_stop(cc, wlvif); + if (ret < 0) + goto out; + } + + /* Rearm the tx watchdog just before idling scan. This + * prevents just-finished scans from triggering the watchdog + */ + cc33xx_rearm_tx_watchdog_locked(cc); + + cc->scan.state = CC33XX_SCAN_STATE_IDLE; + memset(cc->scan.scanned_ch, 0, sizeof(cc->scan.scanned_ch)); + cc->scan_wlvif = NULL; + cc->scan.req = NULL; + ieee80211_scan_completed(cc->hw, &info); + +out: + mutex_unlock(&cc->mutex); + + cancel_delayed_work_sync(&cc->scan_complete_work); +} + +static int cc33xx_op_sched_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_scan_ies *ies) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + int ret; + + cc33xx_debug(DEBUG_MAC80211, "cc33xx_op_sched_scan_start"); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) { + ret = -EAGAIN; + goto out; + } + + ret = cc33xx_sched_scan_start(cc, wlvif, req, ies); + if (ret < 0) + goto out; + + cc->sched_vif = wlvif; + +out: + mutex_unlock(&cc->mutex); + return ret; +} + +static int cc33xx_op_sched_scan_stop(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + + cc33xx_debug(DEBUG_MAC80211, "cc33xx_op_sched_scan_stop"); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + /* command to stop periodic scan was sent from mac80211 + * mark than stop command is from mac80211 and release sched_vif + */ + cc->mac80211_scan_stopped = true; + cc->sched_vif = NULL; + cc33xx_scan_sched_scan_stop(cc, wlvif); + +out: + mutex_unlock(&cc->mutex); + + return 0; +} + +static int cc33xx_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) +{ + return 0; +} + +static int cc33xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + return 0; +} + +static int cc33xx_bss_erp_info_changed(struct cc33xx *cc, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u64 changed) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + int ret = 0; + + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + ret = cc33xx_acx_slot(cc, wlvif, SLOT_TIME_SHORT); + else + ret = cc33xx_acx_slot(cc, wlvif, SLOT_TIME_LONG); + if (ret < 0) { + cc33xx_warning("Set slot time failed %d", ret); + goto out; + } + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + cc33xx_acx_set_preamble(cc, wlvif, ACX_PREAMBLE_SHORT); + else + cc33xx_acx_set_preamble(cc, wlvif, ACX_PREAMBLE_LONG); + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (bss_conf->use_cts_prot) { + ret = cc33xx_acx_cts_protect(cc, wlvif, + CTSPROTECT_ENABLE); + } else { + ret = cc33xx_acx_cts_protect(cc, wlvif, + CTSPROTECT_DISABLE); + } + + if (ret < 0) { + cc33xx_warning("Set ctsprotect failed %d", ret); + goto out; + } + } + +out: + return ret; +} + +static int cc33xx_set_beacon_template(struct cc33xx *cc, + struct ieee80211_vif *vif, bool is_ap) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + int ret; + int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); + struct sk_buff *beacon = ieee80211_beacon_get(cc->hw, vif, 0); + + struct cc33xx_cmd_set_beacon_info *cmd; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + if (!beacon) { + ret = -EINVAL; + goto end_bcn; + } + + cc33xx_debug(DEBUG_MASTER, "beacon updated"); + + ret = cc33xx_ssid_set(wlvif, beacon, ieoffset); + if (ret < 0) + goto end_bcn; + + cmd->role_id = wlvif->role_id; + cmd->beacon_len = cpu_to_le16(beacon->len); + + memcpy(cmd->beacon, beacon->data, beacon->len); + + ret = cc33xx_cmd_send(cc, CMD_AP_SET_BEACON_INFO, cmd, sizeof(*cmd), 0); + if (ret < 0) + goto end_bcn; + +end_bcn: + dev_kfree_skb(beacon); + kfree(cmd); +out: + return ret; +} + +static int cc33xx_bss_beacon_info_changed(struct cc33xx *cc, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + int ret = 0; + + if (changed & BSS_CHANGED_BEACON_INT) { + cc33xx_debug(DEBUG_MASTER, "beacon interval updated: %d", + bss_conf->beacon_int); + + wlvif->beacon_int = bss_conf->beacon_int; + } + + if (changed & BSS_CHANGED_BEACON) { + ret = cc33xx_set_beacon_template(cc, vif, is_ap); + if (ret < 0) + goto out; + + if (test_and_clear_bit(WLVIF_FLAG_BEACON_DISABLED, + &wlvif->flags)) { + ret = cmd_dfs_master_restart(cc, wlvif); + if (ret < 0) + goto out; + } + } +out: + if (ret != 0) + cc33xx_error("beacon info change failed: %d", ret); + + return ret; +} + +/* AP mode changes */ +static void cc33xx_bss_info_changed_ap(struct cc33xx *cc, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u64 changed) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + int ret = 0; + + if (changed & BSS_CHANGED_BASIC_RATES) { + u32 rates = bss_conf->basic_rates; + u32 supported_rates = 0; + + wlvif->basic_rate_set = cc33xx_tx_enabled_rates_get(cc, rates, + wlvif->band); + wlvif->basic_rate = cc33xx_tx_min_rate_get(cc, + wlvif->basic_rate_set); + + supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES; + ret = cc33xx_update_ap_rates(cc, wlvif->role_id, + wlvif->basic_rate_set, + supported_rates); + + ret = cc33xx_set_beacon_template(cc, vif, true); + if (ret < 0) + goto out; + } + + ret = cc33xx_bss_beacon_info_changed(cc, vif, bss_conf, changed); + if (ret < 0) + goto out; + + if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (bss_conf->enable_beacon) { + if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { + ret = cc33xx_cmd_role_start_ap(cc, wlvif); + if (ret < 0) + goto out; + + ret = cc33xx_ap_init_hwenc(cc, wlvif); + if (ret < 0) + goto out; + + set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags); + cc33xx_debug(DEBUG_AP, "started AP"); + } + } else { + if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { + /* AP might be in ROC in case we have just + * sent auth reply. handle it. + */ + if (test_bit(wlvif->role_id, cc->roc_map)) + cc33xx_croc(cc, wlvif->role_id); + + ret = cc33xx_cmd_role_stop_ap(cc, wlvif); + if (ret < 0) + goto out; + + clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags); + clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, + &wlvif->flags); + cc33xx_debug(DEBUG_AP, "stopped AP"); + } + } + } + + ret = cc33xx_bss_erp_info_changed(cc, vif, bss_conf, changed); + if (ret < 0) + goto out; + +out: + return; +} + +static int cc33xx_set_bssid(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct ieee80211_bss_conf *bss_conf, + struct ieee80211_vif *vif, + u32 sta_rate_set) +{ + u32 rates; + + cc33xx_debug(DEBUG_MAC80211, "changed_bssid: %pM, aid: %d, bcn_int: %d, brates: 0x%x sta_rate_set: 0x%x, nontx: %d", + bss_conf->bssid, vif->cfg.aid, bss_conf->beacon_int, + bss_conf->basic_rates, sta_rate_set, + bss_conf->nontransmitted); + + wlvif->beacon_int = bss_conf->beacon_int; + rates = bss_conf->basic_rates; + wlvif->basic_rate_set = cc33xx_tx_enabled_rates_get(cc, rates, + wlvif->band); + wlvif->basic_rate = cc33xx_tx_min_rate_get(cc, wlvif->basic_rate_set); + + if (sta_rate_set) { + wlvif->rate_set = cc33xx_tx_enabled_rates_get(cc, sta_rate_set, + wlvif->band); + } + + wlvif->nontransmitted = bss_conf->nontransmitted; + cc33xx_debug(DEBUG_MAC80211, "changed_mbssid: nonTxbssid: %d, idx: %d, max_ind: %d, trans_bssid: %pM, ema_ap: %d", + bss_conf->nontransmitted, bss_conf->bssid_index, + bss_conf->bssid_indicator, bss_conf->transmitter_bssid, + bss_conf->ema_ap); + + if (bss_conf->nontransmitted) { + wlvif->bssid_index = bss_conf->bssid_index; + wlvif->bssid_indicator = bss_conf->bssid_indicator; + memcpy(wlvif->transmitter_bssid, + bss_conf->transmitter_bssid, + ETH_ALEN); + } + + /* we only support sched_scan while not connected */ + if (cc->sched_vif == wlvif) + cc33xx_scan_sched_scan_stop(cc, wlvif); + + cc33xx_set_ssid(cc, wlvif); + + set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); + + return 0; +} + +static int cc33xx_clear_bssid(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + int ret; + + /* revert back to minimum rates for the current band */ + cc33xx_set_band_rate(cc, wlvif); + wlvif->basic_rate = cc33xx_tx_min_rate_get(cc, wlvif->basic_rate_set); + + if (wlvif->bss_type == BSS_TYPE_STA_BSS && + test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) { + ret = cc33xx_cmd_role_stop_sta(cc, wlvif); + if (ret < 0) + return ret; + } + + clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); + return 0; +} + +static void cc33xx_sta_set_he(struct cc33xx *cc, struct cc33xx_vif *wlvif, bool has_he) +{ + struct cc33xx_vif *wlvif_itr; + u8 he_count = 0; + + wlvif->sta_has_he = has_he; + + if (has_he) + cc33xx_info("HE Enabled"); + else + cc33xx_info("HE Disabled"); + + cc33xx_for_each_wlvif_sta(cc, wlvif_itr) { + /* check for all valid link id's */ + if (wlvif_itr->role_id != 0xFF && wlvif_itr->sta_has_he) + he_count++; + } + + /* There can't be two stations connected with HE supported links */ + if (he_count > 1) + cc33xx_error("Both station interfaces has HE enabled!"); +} + +/* STA/IBSS mode changes */ +static void cc33xx_bss_info_changed_sta(struct cc33xx *cc, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u64 changed) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + bool do_join = false; + bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); + bool ibss_joined = false; + u32 sta_rate_set = 0; + int ret; + struct ieee80211_sta *sta = NULL; + bool sta_exists = false; + struct ieee80211_sta_ht_cap sta_ht_cap; + struct ieee80211_sta_he_cap sta_he_cap; + + if (is_ibss) { + ret = cc33xx_bss_beacon_info_changed(cc, vif, + bss_conf, changed); + if (ret < 0) + goto out; + } + + if (changed & BSS_CHANGED_IBSS) { + if (vif->cfg.ibss_joined) { + set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags); + ibss_joined = true; + } else { + cc33xx_unset_assoc(cc, wlvif); + cc33xx_cmd_role_stop_sta(cc, wlvif); + } + } + + if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined) + do_join = true; + + /* Need to update the SSID (for filtering etc) */ + if ((changed & BSS_CHANGED_BEACON) && ibss_joined) + do_join = true; + + if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) { + cc33xx_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s", + bss_conf->enable_beacon ? "enabled" : "disabled"); + + do_join = true; + } + + if (changed & BSS_CHANGED_IDLE && !is_ibss) + cc33xx_sta_handle_idle(cc, wlvif, vif->cfg.idle); + + if (changed & BSS_CHANGED_CQM) + wlvif->rssi_thold = bss_conf->cqm_rssi_thold; + + if (changed & (BSS_CHANGED_BSSID | BSS_CHANGED_HT | BSS_CHANGED_ASSOC)) { + rcu_read_lock(); + sta = ieee80211_find_sta(vif, bss_conf->bssid); + if (sta) { + u8 *rx_mask = sta->deflink.ht_cap.mcs.rx_mask; + + /* save the supp_rates of the ap */ + sta_rate_set = sta->deflink.supp_rates[wlvif->band]; + if (sta->deflink.ht_cap.ht_supported) { + sta_rate_set |= + (rx_mask[0] << HW_HT_RATES_OFFSET) | + (rx_mask[1] << HW_MIMO_RATES_OFFSET); + } + sta_ht_cap = sta->deflink.ht_cap; + sta_he_cap = sta->deflink.he_cap; + sta_exists = true; + } + + rcu_read_unlock(); + } + + if (changed & BSS_CHANGED_BSSID) { + if (!is_zero_ether_addr(bss_conf->bssid)) { + ret = cc33xx_set_bssid(cc, wlvif, + bss_conf, vif, sta_rate_set); + if (ret < 0) + goto out; + + /* Need to update the BSSID (for filtering etc) */ + do_join = true; + } else { + ret = cc33xx_clear_bssid(cc, wlvif); + if (ret < 0) + goto out; + } + } + + if (changed & BSS_CHANGED_IBSS) { + cc33xx_debug(DEBUG_ADHOC, "ibss_joined: %d", + vif->cfg.ibss_joined); + + if (vif->cfg.ibss_joined) { + u32 rates = bss_conf->basic_rates; + + wlvif->basic_rate_set = + cc33xx_tx_enabled_rates_get(cc, rates, + wlvif->band); + wlvif->basic_rate = + cc33xx_tx_min_rate_get(cc, + wlvif->basic_rate_set); + + /* by default, use 11b + OFDM rates */ + wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES; + } + } + + if ((changed & BSS_CHANGED_BEACON_INFO) && bss_conf->dtim_period) { + /* enable beacon filtering */ + ret = cc33xx_acx_beacon_filter_opt(cc, wlvif, true); + if (ret < 0) + goto out; + } + + ret = cc33xx_bss_erp_info_changed(cc, vif, bss_conf, changed); + if (ret < 0) + goto out; + + if (do_join) { + ret = cc33xx_join(cc, wlvif); + if (ret < 0) { + cc33xx_warning("cmd join failed %d", ret); + goto out; + } + } + + if (changed & BSS_CHANGED_ASSOC) { + if (vif->cfg.assoc) { + ret = cc33xx_set_assoc(cc, wlvif, bss_conf, sta, vif, + sta_rate_set); + if (ret < 0) + goto out; + + if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags)) + cc33xx_set_authorized(cc, wlvif); + + if (sta) + cc33xx_sta_set_he(cc, wlvif, sta->deflink.he_cap.has_he); + + } else { + cc33xx_unset_assoc(cc, wlvif); + } + } + + if (changed & BSS_CHANGED_PS) { + if (vif->cfg.ps && + test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && + !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { + int ps_mode; + char *ps_mode_str; + + if (cc->conf.host_conf.conn.forced_ps) { + ps_mode = STATION_POWER_SAVE_MODE; + ps_mode_str = "forced"; + } else { + ps_mode = STATION_AUTO_PS_MODE; + ps_mode_str = "auto"; + } + + cc33xx_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str); + + ret = cc33xx_ps_set_mode(cc, wlvif, ps_mode); + if (ret < 0) + cc33xx_warning("enter %s ps failed %d", + ps_mode_str, ret); + } else if (!vif->cfg.ps && test_bit(WLVIF_FLAG_IN_PS, + &wlvif->flags)) { + cc33xx_debug(DEBUG_PSM, "auto ps disabled"); + + ret = cc33xx_ps_set_mode(cc, wlvif, + STATION_ACTIVE_MODE); + if (ret < 0) + cc33xx_warning("exit auto ps failed %d", ret); + } + } + + /* Handle new association with HT. Do this after join. */ + if (sta_exists) { + bool enabled = bss_conf->chandef.width != + NL80211_CHAN_WIDTH_20_NOHT; + cc33xx_debug(DEBUG_CMD, "cc33xx_hw_set_peer_cap %x", + wlvif->rate_set); + ret = cc33xx_acx_set_peer_cap(cc, &sta_ht_cap, &sta_he_cap, + wlvif, enabled, wlvif->rate_set, + wlvif->sta.hlid); + if (ret < 0) { + cc33xx_warning("Set ht cap failed %d", ret); + goto out; + } + + if (enabled) { + ret = cc33xx_acx_set_ht_information(cc, wlvif, + bss_conf->ht_operation_mode, + bss_conf->he_oper.params, + bss_conf->he_oper.nss_set); + if (ret < 0) { + cc33xx_warning("Set ht information failed %d", + ret); + goto out; + } + } + } + + /* Handle arp filtering. Done after join. */ + if ((changed & BSS_CHANGED_ARP_FILTER) || + (!is_ibss && (changed & BSS_CHANGED_QOS))) { + __be32 addr = vif->cfg.arp_addr_list[0]; + + wlvif->sta.qos = bss_conf->qos; + WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); + + if (vif->cfg.arp_addr_cnt == 1 && vif->cfg.assoc) { + wlvif->ip_addr = addr; + /* The template should have been configured only upon + * association. however, it seems that the correct ip + * isn't being set (when sending), so we have to + * reconfigure the template upon every ip change. + */ + if (ret < 0) { + cc33xx_warning("build arp rsp failed: %d", ret); + goto out; + } + + } else { + wlvif->ip_addr = 0; + } + + if (ret < 0) + goto out; + } + +out: + return; +} + +static void cc33xx_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u64 changed) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + int ret, set_power; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 bss info role %d changed 0x%x", + wlvif->role_id, (int)changed); + + /* make sure to cancel pending disconnections if our association + * state changed + */ + if (!is_ap && (changed & BSS_CHANGED_ASSOC)) + cancel_delayed_work_sync(&wlvif->connection_loss_work); + + if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) && + !bss_conf->enable_beacon) + cc33xx_tx_flush(cc); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) + goto out; + + if ((changed & BSS_CHANGED_TXPOWER) && bss_conf->txpower != wlvif->power_level) { + /* bss_conf->txpower is initialized with a default value, + * meaning the power has not been set and should be ignored, use + * max value instead + */ + set_power = (bss_conf->txpower == INT_MIN) ? + CC33XX_MAX_TXPWR : bss_conf->txpower; + ret = cc33xx_acx_tx_power(cc, wlvif, set_power); + + if (ret < 0) + goto out; + } + + if (is_ap) + cc33xx_bss_info_changed_ap(cc, vif, bss_conf, changed); + else + cc33xx_bss_info_changed_sta(cc, vif, bss_conf, changed); + +out: + mutex_unlock(&cc->mutex); +} + +static int cc33xx_op_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx) +{ + cc33xx_debug(DEBUG_MAC80211, "mac80211 add chanctx %d (type %d)", + ieee80211_frequency_to_channel(ctx->def.chan->center_freq), + cfg80211_get_chandef_type(&ctx->def)); + return 0; +} + +static void cc33xx_op_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx) +{ + cc33xx_debug(DEBUG_MAC80211, "mac80211 remove chanctx %d (type %d)", + ieee80211_frequency_to_channel(ctx->def.chan->center_freq), + cfg80211_get_chandef_type(&ctx->def)); +} + +static void cc33xx_op_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx, + u32 changed) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif; + int channel = ieee80211_frequency_to_channel(ctx->def.chan->center_freq); + + cc33xx_debug(DEBUG_MAC80211, + "mac80211 change chanctx %d (type %d) changed 0x%x", + channel, cfg80211_get_chandef_type(&ctx->def), changed); + + mutex_lock(&cc->mutex); + + cc33xx_for_each_wlvif(cc, wlvif) { + struct ieee80211_vif *vif = cc33xx_wlvif_to_vif(wlvif); + + rcu_read_lock(); + if (rcu_access_pointer(vif->bss_conf.chanctx_conf) != ctx) { + rcu_read_unlock(); + continue; + } + rcu_read_unlock(); + + /* start radar if needed */ + if (changed & IEEE80211_CHANCTX_CHANGE_RADAR && + wlvif->bss_type == BSS_TYPE_AP_BSS && + ctx->radar_enabled && !wlvif->radar_enabled && + ctx->def.chan->dfs_state == NL80211_DFS_USABLE) { + cc33xx_debug(DEBUG_MAC80211, "Start radar detection"); + cmd_set_cac(cc, wlvif, true); + wlvif->radar_enabled = true; + } + } + + mutex_unlock(&cc->mutex); +} + +static int cc33xx_op_assign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *ctx) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + int channel = ieee80211_frequency_to_channel(ctx->def.chan->center_freq); + + cc33xx_debug(DEBUG_MAC80211, "mac80211 assign chanctx (role %d) %d (type %d) (radar %d dfs_state %d)", + wlvif->role_id, + channel, cfg80211_get_chandef_type(&ctx->def), + ctx->radar_enabled, ctx->def.chan->dfs_state); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) + goto out; + + wlvif->band = ctx->def.chan->band; + wlvif->channel = channel; + wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def); + + /* update default rates according to the band */ + cc33xx_set_band_rate(cc, wlvif); + + if (ctx->radar_enabled && ctx->def.chan->dfs_state == NL80211_DFS_USABLE) { + cc33xx_debug(DEBUG_MAC80211, "Start radar detection"); + cmd_set_cac(cc, wlvif, true); + wlvif->radar_enabled = true; + } + +out: + mutex_unlock(&cc->mutex); + + return 0; +} + +static void cc33xx_op_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *ctx) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + + cc33xx_debug(DEBUG_MAC80211, + "mac80211 unassign chanctx (role %d) %d (type %d)", + wlvif->role_id, + ieee80211_frequency_to_channel(ctx->def.chan->center_freq), + cfg80211_get_chandef_type(&ctx->def)); + + cc33xx_tx_flush(cc); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) + goto out; + + if (wlvif->radar_enabled) { + cc33xx_debug(DEBUG_MAC80211, "Stop radar detection"); + cmd_set_cac(cc, wlvif, false); + wlvif->radar_enabled = false; + } + +out: + mutex_unlock(&cc->mutex); +} + +static int cc33xx_switch_vif_chan(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct ieee80211_chanctx_conf *new_ctx) +{ + int channel = ieee80211_frequency_to_channel(new_ctx->def.chan->center_freq); + + cc33xx_debug(DEBUG_MAC80211, + "switch vif (role %d) %d -> %d chan_type: %d", + wlvif->role_id, wlvif->channel, channel, + cfg80211_get_chandef_type(&new_ctx->def)); + + cc33xx_debug(DEBUG_MAC80211, "switch vif bss_type: %d", wlvif->bss_type); + + wlvif->band = new_ctx->def.chan->band; + wlvif->channel = channel; + wlvif->channel_type = cfg80211_get_chandef_type(&new_ctx->def); + + if (wlvif->bss_type != BSS_TYPE_AP_BSS) + return 0; + + WARN_ON(!test_bit(WLVIF_FLAG_BEACON_DISABLED, &wlvif->flags)); + + if (wlvif->radar_enabled) { + cc33xx_debug(DEBUG_MAC80211, "Stop radar detection"); + cmd_set_cac(cc, wlvif, false); + wlvif->radar_enabled = false; + } + + /* start radar if needed */ + if (new_ctx->radar_enabled) { + cc33xx_debug(DEBUG_MAC80211, "Start radar detection"); + cmd_set_cac(cc, wlvif, true); + wlvif->radar_enabled = true; + } + + return 0; +} + +static int cc33xx_op_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode) +{ + struct cc33xx *cc = hw->priv; + int i, ret; + + cc33xx_debug(DEBUG_MAC80211, + "mac80211 switch chanctx n_vifs %d mode %d", n_vifs, mode); + + mutex_lock(&cc->mutex); + + for (i = 0; i < n_vifs; i++) { + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vifs[i].vif); + + ret = cc33xx_switch_vif_chan(cc, wlvif, vifs[i].new_ctx); + if (ret) + goto out; + } + +out: + mutex_unlock(&cc->mutex); + + return 0; +} + +static int cc33xx_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + u8 ps_scheme; + int ret = 0; + + if (cc33xx_is_p2p_mgmt(wlvif)) + return 0; + + mutex_lock(&cc->mutex); + + cc33xx_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); + + if (params->uapsd) + ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER; + else + ps_scheme = CONF_PS_SCHEME_LEGACY; + + if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) + goto out; + + ret = cc33xx_tx_param_cfg(cc, wlvif, cc33xx_tx_get_queue(queue), + params->cw_min, params->cw_max, params->aifs, + params->txop << 5, params->acm, ps_scheme, + params->mu_edca, params->mu_edca_param_rec.aifsn, + params->mu_edca_param_rec.ecw_min_max, + params->mu_edca_param_rec.mu_edca_timer); + +out: + mutex_unlock(&cc->mutex); + + return ret; +} + +static u64 cc33xx_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + u64 mactime = ULLONG_MAX; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 get tsf"); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + cc33xx_acx_tsf_info(cc, wlvif, &mactime); + +out: + mutex_unlock(&cc->mutex); + + return mactime; +} + +static int cc33xx_op_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct ieee80211_conf *conf = &hw->conf; + + if (idx != 0) + return -ENOENT; + + survey->channel = conf->chandef.chan; + survey->filled = 0; + return 0; +} + +static int cc33xx_allocate_sta(struct cc33xx *cc, + struct cc33xx_vif *wlvif, + struct ieee80211_sta *sta) +{ + struct cc33xx_station *wl_sta; + int ret; + + if (cc->active_sta_count >= CC33XX_MAX_AP_STATIONS) { + cc33xx_warning("could not allocate HLID - too much stations"); + return -EBUSY; + } + + wl_sta = (struct cc33xx_station *)sta->drv_priv; + + ret = cc33xx_set_link(cc, wlvif, wl_sta->hlid); + + if (ret < 0) { + cc33xx_warning("could not allocate HLID - too many links"); + return -EBUSY; + } + + /* use the previous security seq, if this is a recovery/resume */ + cc->links[wl_sta->hlid].total_freed_pkts = wl_sta->total_freed_pkts; + + set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map); + memcpy(cc->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); + cc->active_sta_count++; + return 0; +} + +void cc33xx_free_sta(struct cc33xx *cc, struct cc33xx_vif *wlvif, u8 hlid) +{ + if (!test_bit(hlid, wlvif->ap.sta_hlid_map)) + return; + + clear_bit(hlid, wlvif->ap.sta_hlid_map); + __clear_bit(hlid, &cc->ap_ps_map); + __clear_bit(hlid, &cc->ap_fw_ps_map); + + /* save the last used PN in the private part of iee80211_sta, + * in case of recovery/suspend + */ + cc33xx_save_freed_pkts_addr(cc, wlvif, hlid, cc->links[hlid].addr); + + cc33xx_clear_link(cc, wlvif, &hlid); + cc->active_sta_count--; + + /* rearm the tx watchdog when the last STA is freed - give the FW a + * chance to return STA-buffered packets before complaining. + */ + if (cc->active_sta_count == 0) + cc33xx_rearm_tx_watchdog_locked(cc); +} + +static int cc33xx_sta_add(struct cc33xx *cc, + struct cc33xx_vif *wlvif, + struct ieee80211_sta *sta) +{ + struct cc33xx_station *wl_sta; + int ret = 0; + u8 hlid; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid); + + wl_sta = (struct cc33xx_station *)sta->drv_priv; + ret = cc33xx_cmd_add_peer(cc, wlvif, sta, &hlid, 0); + if (ret < 0) + return ret; + + wl_sta->hlid = hlid; + ret = cc33xx_allocate_sta(cc, wlvif, sta); + + return ret; +} + +static int cc33xx_sta_remove(struct cc33xx *cc, + struct cc33xx_vif *wlvif, + struct ieee80211_sta *sta) +{ + struct cc33xx_station *wl_sta; + int ret = 0, id; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid); + + wl_sta = (struct cc33xx_station *)sta->drv_priv; + id = wl_sta->hlid; + if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map))) + return -EINVAL; + + ret = cc33xx_cmd_remove_peer(cc, wlvif, wl_sta->hlid); + if (ret < 0) + return ret; + + cc33xx_free_sta(cc, wlvif, wl_sta->hlid); + return ret; +} + +static void cc33xx_roc_if_possible(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + if (find_first_bit(cc->roc_map, CC33XX_MAX_ROLES) < CC33XX_MAX_ROLES) + return; + + if (WARN_ON(wlvif->role_id == CC33XX_INVALID_ROLE_ID)) + return; + + cc33xx_roc(cc, wlvif, wlvif->role_id, wlvif->band, wlvif->channel); +} + +/* when wl_sta is NULL, we treat this call as if coming from a + * pending auth reply. + * cc->mutex must be taken and the FW must be awake when the call + * takes place. + */ +void cc33xx_update_inconn_sta(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct cc33xx_station *wl_sta, bool in_conn) +{ + cc33xx_debug(DEBUG_CMD, "update_inconn_sta: in_conn=%d count=%d, pending_auth=%d", + in_conn, + wlvif->inconn_count, wlvif->ap_pending_auth_reply); + + if (in_conn) { + if (WARN_ON(wl_sta && wl_sta->in_connection)) + return; + + if (!wlvif->ap_pending_auth_reply && !wlvif->inconn_count) { + cc33xx_roc_if_possible(cc, wlvif); + if (test_bit(wlvif->role_id, cc->roc_map)) { + unsigned long roc_cmplt_jiffies = + msecs_to_jiffies(CC33xx_PEND_ROC_COMPLETE_TIMEOUT); + + /* set timer on croc timeout */ + wlvif->pending_auth_reply_time = jiffies; + cancel_delayed_work(&wlvif->roc_timeout_work); + + cc33xx_debug(DEBUG_AP, "delay queue roc_timeout_work"); + + ieee80211_queue_delayed_work(cc->hw, + &wlvif->roc_timeout_work, + roc_cmplt_jiffies); + } + } + + if (wl_sta) { + wl_sta->in_connection = true; + wlvif->inconn_count++; + } else { + wlvif->ap_pending_auth_reply = true; + } + } else { + if (wl_sta && !wl_sta->in_connection) + return; + + if (WARN_ON(!wl_sta && !wlvif->ap_pending_auth_reply)) + return; + + if (WARN_ON(wl_sta && !wlvif->inconn_count)) + return; + + if (wl_sta) { + wl_sta->in_connection = false; + wlvif->inconn_count--; + } else { + wlvif->ap_pending_auth_reply = false; + } + + if (!wlvif->inconn_count && !wlvif->ap_pending_auth_reply && + test_bit(wlvif->role_id, cc->roc_map)) { + cc33xx_croc(cc, wlvif->role_id); + /* remove timer for croc t/o */ + cc33xx_debug(DEBUG_AP, "Cancel pending_roc timeout"); + cancel_delayed_work(&wlvif->roc_timeout_work); + } + } + cc33xx_debug(DEBUG_CMD, "update_inconn_sta done: in_conn=%d count=%d, pending_auth=%d", + in_conn, wlvif->inconn_count, + wlvif->ap_pending_auth_reply); +} + +static int cc33xx_update_sta_state(struct cc33xx *cc, + struct cc33xx_vif *wlvif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) +{ + struct cc33xx_station *wl_sta; + bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; + bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; + int ret; + + wl_sta = (struct cc33xx_station *)sta->drv_priv; + + /* Add station (AP mode) */ + if (is_ap && old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) { + ret = cc33xx_sta_add(cc, wlvif, sta); + if (ret) + return ret; + + cc33xx_update_inconn_sta(cc, wlvif, wl_sta, true); + } + + /* Remove station (AP mode) */ + if (is_ap && old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST) { + /* must not fail */ + cc33xx_sta_remove(cc, wlvif, sta); + + cc33xx_update_inconn_sta(cc, wlvif, wl_sta, false); + } + + /* Authorize station (AP mode) */ + if (is_ap && new_state == IEEE80211_STA_AUTHORIZED) { + /* reconfigure peer */ + ret = cc33xx_cmd_add_peer(cc, wlvif, sta, NULL, true); + if (ret < 0) + return ret; + + cc33xx_update_inconn_sta(cc, wlvif, wl_sta, false); + } + + /* Authorize station */ + if (is_sta && new_state == IEEE80211_STA_AUTHORIZED) { + set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); + ret = cc33xx_set_authorized(cc, wlvif); + if (ret) + return ret; + } + + if (is_sta && old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { + clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); + clear_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags); + } + + /* save seq number on disassoc (suspend) */ + if (is_sta && old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTH) { + cc33xx_save_freed_pkts(cc, wlvif, wlvif->sta.hlid, sta); + wlvif->total_freed_pkts = 0; + } + + /* restore seq number on assoc (resume) */ + if (is_sta && old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) + wlvif->total_freed_pkts = wl_sta->total_freed_pkts; + + /* clear ROCs on failure or authorization */ + if (is_sta && + (new_state == IEEE80211_STA_AUTHORIZED || + new_state == IEEE80211_STA_NOTEXIST)) { + if (test_bit(wlvif->role_id, cc->roc_map)) + cc33xx_croc(cc, wlvif->role_id); + } + + if (is_sta && (old_state == IEEE80211_STA_NOTEXIST && + new_state == IEEE80211_STA_NONE)) { + if (find_first_bit(cc->roc_map, + CC33XX_MAX_ROLES) >= CC33XX_MAX_ROLES) { + WARN_ON(wlvif->role_id == CC33XX_INVALID_ROLE_ID); + cc33xx_roc(cc, wlvif, wlvif->role_id, + wlvif->band, wlvif->channel); + } + } + + return 0; +} + +static int cc33xx_op_sta_state(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + int ret; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 sta %d state=%d->%d", + sta->aid, old_state, new_state); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) { + ret = -EBUSY; + goto out; + } + + ret = cc33xx_update_sta_state(cc, wlvif, sta, old_state, new_state); + +out: + mutex_unlock(&cc->mutex); + if (new_state < old_state) + return 0; + return ret; +} + +static int cc33xx_op_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + int ret; + u8 hlid, *ba_bitmap; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", + action, tid); + + /* sanity check - the fields in FW are only 8bits wide */ + if (WARN_ON(tid > 0xFF)) + return -EOPNOTSUPP; + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) { + ret = -EAGAIN; + goto out; + } + + if (wlvif->bss_type == BSS_TYPE_STA_BSS) { + hlid = wlvif->sta.hlid; + } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) { + struct cc33xx_station *wl_sta; + + wl_sta = (struct cc33xx_station *)sta->drv_priv; + hlid = wl_sta->hlid; + } else { + ret = -EINVAL; + goto out; + } + + if (hlid == CC33XX_INVALID_LINK_ID) { + ret = 0; + goto out; + } + + if (WARN_ON(hlid >= CC33XX_MAX_LINKS)) { + ret = -EINVAL; + goto out; + } + + ba_bitmap = &cc->links[hlid].ba_bitmap; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d", + tid, action); + + switch (action) { + case IEEE80211_AMPDU_RX_START: + if (!wlvif->ba_support || !wlvif->ba_allowed) { + ret = -EOPNOTSUPP; + break; + } + + if (cc->ba_rx_session_count >= CC33XX_RX_BA_MAX_SESSIONS) { + ret = -EBUSY; + cc33xx_error("exceeded max RX BA sessions"); + break; + } + + if (*ba_bitmap & BIT(tid)) { + ret = -EINVAL; + cc33xx_error("cannot enable RX BA session on active tid: %d", + tid); + break; + } + + ret = cc33xx_acx_set_ba_receiver_session(cc, tid, *ssn, + true, hlid, + params->buf_size); + + if (!ret) { + *ba_bitmap |= BIT(tid); + cc->ba_rx_session_count++; + } + break; + + case IEEE80211_AMPDU_RX_STOP: + if (!(*ba_bitmap & BIT(tid))) { + /* this happens on reconfig - so only output a debug + * message for now, and don't fail the function. + */ + cc33xx_debug(DEBUG_MAC80211, + "no active RX BA session on tid: %d", tid); + ret = 0; + break; + } + + ret = cc33xx_acx_set_ba_receiver_session(cc, tid, 0, + false, hlid, 0); + if (!ret) { + *ba_bitmap &= ~BIT(tid); + cc->ba_rx_session_count--; + } + break; + + /* The BA initiator session management in FW independently. + * Falling break here on purpose for all TX APDU commands. + */ + case IEEE80211_AMPDU_TX_START: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + case IEEE80211_AMPDU_TX_OPERATIONAL: + ret = -EINVAL; + break; + + default: + cc33xx_error("Incorrect ampdu action id=%x\n", action); + ret = -EINVAL; + } + +out: + mutex_unlock(&cc->mutex); + + return ret; +} + +static int cc33xx_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + struct cc33xx *cc = hw->priv; + int ret = 0; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x", + mask->control[NL80211_BAND_2GHZ].legacy, + mask->control[NL80211_BAND_5GHZ].legacy); + + mutex_lock(&cc->mutex); + + wlvif->bitrate_masks[0] = cc33xx_tx_enabled_rates_get(cc, + mask->control[0].legacy, 0); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + if (wlvif->bss_type == BSS_TYPE_STA_BSS && + !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { + cc33xx_set_band_rate(cc, wlvif); + wlvif->basic_rate = cc33xx_tx_min_rate_get(cc, + wlvif->basic_rate_set); + } +out: + mutex_unlock(&cc->mutex); + + return ret; +} + +static void cc33xx_op_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *ch_switch) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + int ret; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 channel switch"); + + cc33xx_tx_flush(cc); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state == CC33XX_STATE_OFF)) { + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + ieee80211_chswitch_done(vif, false); + goto out; + } else if (unlikely(cc->state != CC33XX_STATE_ON)) { + goto out; + } + + /* TODO: change mac80211 to pass vif as param */ + + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { + unsigned long delay_usec; + + ret = cmd_channel_switch(cc, wlvif, ch_switch); + if (ret) + goto out; + + set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); + + /* indicate failure 5 seconds after channel switch time */ + delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) * + ch_switch->count; + ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work, + usecs_to_jiffies(delay_usec) + + msecs_to_jiffies(5000)); + } + +out: + mutex_unlock(&cc->mutex); +} + +static inline void cc33xx_op_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + cc33xx_error("AP channel switch is not supported"); +} + +static inline void cc33xx_op_flush(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + cc33xx_tx_flush(hw->priv); +} + +static int cc33xx_op_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel *chan, + int duration, + enum ieee80211_roc_type type) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + struct cc33xx *cc = hw->priv; + int channel, active_roc, ret = 0; + + channel = ieee80211_frequency_to_channel(chan->center_freq); + + cc33xx_debug(DEBUG_MAC80211, + "mac80211 roc %d (role %d)", channel, wlvif->role_id); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + /* return EBUSY if we can't ROC right now */ + active_roc = find_first_bit(cc->roc_map, CC33XX_MAX_ROLES); + if (cc->roc_vif || active_roc < CC33XX_MAX_ROLES) { + cc33xx_warning("active roc on role %d", active_roc); + ret = -EBUSY; + goto out; + } + + cc33xx_debug(DEBUG_MAC80211, + "call cc33xx_start_dev, band = %d, channel = %d", + chan->band, channel); + ret = cc33xx_start_dev(cc, wlvif, chan->band, channel); + if (ret < 0) + goto out; + + cc->roc_vif = vif; + ieee80211_queue_delayed_work(hw, &cc->roc_complete_work, + msecs_to_jiffies(duration)); + +out: + mutex_unlock(&cc->mutex); + return ret; +} + +static int __cc33xx_roc_completed(struct cc33xx *cc) +{ + struct cc33xx_vif *wlvif; + int ret; + + /* already completed */ + if (unlikely(!cc->roc_vif)) + return 0; + + wlvif = cc33xx_vif_to_data(cc->roc_vif); + + if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) + return -EBUSY; + + ret = cc33xx_stop_dev(cc, wlvif); + if (ret < 0) + return ret; + + cc->roc_vif = NULL; + + return 0; +} + +static int cc33xx_roc_completed(struct cc33xx *cc) +{ + int ret; + + cc33xx_debug(DEBUG_MAC80211, "roc complete"); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) { + ret = -EBUSY; + goto out; + } + + ret = __cc33xx_roc_completed(cc); + +out: + mutex_unlock(&cc->mutex); + + return ret; +} + +static void cc33xx_roc_complete_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct cc33xx *cc; + int ret; + + dwork = to_delayed_work(work); + cc = container_of(dwork, struct cc33xx, roc_complete_work); + + ret = cc33xx_roc_completed(cc); + if (!ret) + ieee80211_remain_on_channel_expired(cc->hw); +} + +static int cc33xx_op_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct cc33xx *cc = hw->priv; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 croc"); + + cc33xx_tx_flush(cc); + + /* we can't just flush_work here, because it might deadlock + * (as we might get called from the same workqueue) + */ + cancel_delayed_work_sync(&cc->roc_complete_work); + cc33xx_roc_completed(cc); + + return 0; +} + +static void cc33xx_op_sta_rc_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + u32 changed) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + + cc33xx_debug(DEBUG_MAC80211, "mac80211 sta_rc_update"); + + if (!(changed & IEEE80211_RC_BW_CHANGED)) + return; + + /* this callback is atomic, so schedule a new work */ + wlvif->rc_update_bw = sta->deflink.bandwidth; + memcpy(&wlvif->rc_ht_cap, &sta->deflink.ht_cap, sizeof(sta->deflink.ht_cap)); + ieee80211_queue_work(hw, &wlvif->rc_update_work); +} + +static void cc33xx_op_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) +{ + struct cc33xx *cc = hw->priv; + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + s8 rssi_dbm; + int ret; + + cc33xx_debug(DEBUG_MAC80211, "mac80211 get_rssi"); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + ret = cc33xx_acx_average_rssi(cc, wlvif, &rssi_dbm); + if (ret < 0) + goto out; + + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); + sinfo->signal = rssi_dbm; + + ret = cc33xx_acx_get_tx_rate(cc, wlvif, sinfo); + if (ret < 0) + goto out; + +out: + mutex_unlock(&cc->mutex); +} + +static u32 cc33xx_op_get_expected_throughput(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct cc33xx_station *wl_sta = (struct cc33xx_station *)sta->drv_priv; + struct cc33xx *cc = hw->priv; + u8 hlid = wl_sta->hlid; + + /* return in units of Kbps */ + return (cc->links[hlid].fw_rate_mbps * 1000); +} + +static bool cc33xx_tx_frames_pending(struct ieee80211_hw *hw) +{ + struct cc33xx *cc = hw->priv; + bool ret = false; + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + /* packets are considered pending if in the TX queue or the FW */ + ret = (cc33xx_tx_total_queue_count(cc) > 0) || (cc->tx_frames_cnt > 0); +out: + mutex_unlock(&cc->mutex); + + return ret; +} + +#ifdef CONFIG_PM +static const struct ieee80211_ops cc33xx_ops = { + .start = cc33xx_op_start, + .stop = cc33xx_op_stop, + .add_interface = cc33xx_op_add_interface, + .remove_interface = cc33xx_op_remove_interface, + .change_interface = cc33xx_op_change_interface, + .suspend = cc33xx_op_suspend, + .resume = cc33xx_op_resume, + .config = cc33xx_op_config, + .prepare_multicast = cc33xx_op_prepare_multicast, + .configure_filter = cc33xx_op_configure_filter, + .tx = cc33xx_op_tx, + .wake_tx_queue = ieee80211_handle_wake_tx_queue, + .set_key = cc33xx_op_set_key, + .hw_scan = cc33xx_op_hw_scan, + .cancel_hw_scan = cc33xx_op_cancel_hw_scan, + .sched_scan_start = cc33xx_op_sched_scan_start, + .sched_scan_stop = cc33xx_op_sched_scan_stop, + .bss_info_changed = cc33xx_op_bss_info_changed, + .set_frag_threshold = cc33xx_op_set_frag_threshold, + .set_rts_threshold = cc33xx_op_set_rts_threshold, + .conf_tx = cc33xx_op_conf_tx, + .get_tsf = cc33xx_op_get_tsf, + .get_survey = cc33xx_op_get_survey, + .sta_state = cc33xx_op_sta_state, + .ampdu_action = cc33xx_op_ampdu_action, + .tx_frames_pending = cc33xx_tx_frames_pending, + .set_bitrate_mask = cc33xx_set_bitrate_mask, + .set_default_unicast_key = cc33xx_op_set_default_key_idx, + .channel_switch = cc33xx_op_channel_switch, + .channel_switch_beacon = cc33xx_op_channel_switch_beacon, + .flush = cc33xx_op_flush, + .remain_on_channel = cc33xx_op_remain_on_channel, + .cancel_remain_on_channel = cc33xx_op_cancel_remain_on_channel, + .add_chanctx = cc33xx_op_add_chanctx, + .remove_chanctx = cc33xx_op_remove_chanctx, + .change_chanctx = cc33xx_op_change_chanctx, + .assign_vif_chanctx = cc33xx_op_assign_vif_chanctx, + .unassign_vif_chanctx = cc33xx_op_unassign_vif_chanctx, + .switch_vif_chanctx = cc33xx_op_switch_vif_chanctx, + .sta_rc_update = cc33xx_op_sta_rc_update, + .sta_statistics = cc33xx_op_sta_statistics, + .get_expected_throughput = cc33xx_op_get_expected_throughput, + CFG80211_TESTMODE_CMD(cc33xx_tm_cmd) +}; + +static const struct wiphy_wowlan_support cc33xx_wowlan_support = { + .flags = WIPHY_WOWLAN_ANY, + .n_patterns = CC33XX_MAX_RX_FILTERS, + .pattern_min_len = 1, + .pattern_max_len = CC33XX_RX_FILTER_MAX_PATTERN_SIZE, +}; + +static void setup_wake_irq(struct cc33xx *cc) +{ + struct platform_device *pdev = cc->pdev; + struct cc33xx_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); + + struct resource *res; + int ret; + + device_init_wakeup(cc->dev, true); + + if (pdev_data->pwr_in_suspend) + cc->hw->wiphy->wowlan = &cc33xx_wowlan_support; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res) { + cc->wakeirq = res->start; + ret = dev_pm_set_dedicated_wake_irq(cc->dev, cc->wakeirq); + if (ret) + cc->wakeirq = -ENODEV; + } else { + cc->wakeirq = -ENODEV; + } + + cc->keep_device_power = true; +} +#else +static const struct ieee80211_ops cc33xx_ops = { + .start = cc33xx_op_start, + .stop = cc33xx_op_stop, + .add_interface = cc33xx_op_add_interface, + .remove_interface = cc33xx_op_remove_interface, + .change_interface = cc33xx_op_change_interface, + .config = cc33xx_op_config, + .prepare_multicast = cc33xx_op_prepare_multicast, + .configure_filter = cc33xx_op_configure_filter, + .tx = cc33xx_op_tx, + .wake_tx_queue = ieee80211_handle_wake_tx_queue, + .set_key = cc33xx_op_set_key, + .hw_scan = cc33xx_op_hw_scan, + .cancel_hw_scan = cc33xx_op_cancel_hw_scan, + .sched_scan_start = cc33xx_op_sched_scan_start, + .sched_scan_stop = cc33xx_op_sched_scan_stop, + .bss_info_changed = cc33xx_op_bss_info_changed, + .set_frag_threshold = cc33xx_op_set_frag_threshold, + .set_rts_threshold = cc33xx_op_set_rts_threshold, + .conf_tx = cc33xx_op_conf_tx, + .get_tsf = cc33xx_op_get_tsf, + .get_survey = cc33xx_op_get_survey, + .sta_state = cc33xx_op_sta_state, + .ampdu_action = cc33xx_op_ampdu_action, + .tx_frames_pending = cc33xx_tx_frames_pending, + .set_bitrate_mask = cc33xx_set_bitrate_mask, + .set_default_unicast_key = cc33xx_op_set_default_key_idx, + .channel_switch = cc33xx_op_channel_switch, + .channel_switch_beacon = cc33xx_op_channel_switch_beacon, + .flush = cc33xx_op_flush, + .remain_on_channel = cc33xx_op_remain_on_channel, + .cancel_remain_on_channel = cc33xx_op_cancel_remain_on_channel, + .add_chanctx = cc33xx_op_add_chanctx, + .remove_chanctx = cc33xx_op_remove_chanctx, + .change_chanctx = cc33xx_op_change_chanctx, + .assign_vif_chanctx = cc33xx_op_assign_vif_chanctx, + .unassign_vif_chanctx = cc33xx_op_unassign_vif_chanctx, + .switch_vif_chanctx = cc33xx_op_switch_vif_chanctx, + .sta_rc_update = cc33xx_op_sta_rc_update, + .sta_statistics = cc33xx_op_sta_statistics, + .get_expected_throughput = cc33xx_op_get_expected_throughput, + CFG80211_TESTMODE_CMD(cc33xx_tm_cmd) +}; + +static inline void setup_wake_irq(struct cc33xx *cc) +{ + cc->keep_device_power = true; +} +#endif /* CONFIG_PM */ + +u8 cc33xx_rate_to_idx(struct cc33xx *cc, u8 rate, enum nl80211_band band) +{ + u8 idx; + + if (WARN_ON(band >= 2)) + return 0; + + if (unlikely(rate > CONF_HW_RATE_INDEX_MAX)) { + cc33xx_error("Illegal RX rate from HW: %d", rate); + return 0; + } + + idx = cc33xx_band_rate_to_idx[band][rate]; + if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) { + cc33xx_error("Unsupported RX rate from HW: %d", rate); + return 0; + } + + return idx; +} + +static void cc33xx_derive_mac_addresses(struct cc33xx *cc) +{ + const u8 zero_mac[ETH_ALEN] = {0}; + u8 base_addr[ETH_ALEN]; + u8 bd_addr[ETH_ALEN]; + bool use_nvs = false; + bool use_efuse = false; + bool use_random = false; + + if (cc->nvs_mac_addr_len != ETH_ALEN) { + if (unlikely(cc->nvs_mac_addr_len > 0)) + cc33xx_warning("NVS MAC address present but has a wrong size, ignoring."); + + if (!ether_addr_equal(zero_mac, cc->efuse_mac_address)) { + use_efuse = true; + ether_addr_copy(base_addr, cc->efuse_mac_address); + cc33xx_debug(DEBUG_BOOT, + "MAC address derived from EFUSE"); + } else { + use_random = true; + eth_random_addr(base_addr); + cc33xx_warning("No EFUSE / NVS data, using random locally administered address."); + } + } else { + u8 *nvs_addr = cc->nvs_mac_addr; + const u8 efuse_magic_addr[ETH_ALEN] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + const u8 random_magic_addr[ETH_ALEN] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; + + /* In NVS, addresses 00-00-00-00-00-00 and 00-00-00-00-00-01 + * have special meaning: + */ + + if (ether_addr_equal(nvs_addr, efuse_magic_addr)) { + use_efuse = true; + ether_addr_copy(base_addr, cc->efuse_mac_address); + cc33xx_debug(DEBUG_BOOT, + "NVS file selects address from EFUSE"); + } else if (ether_addr_equal(nvs_addr, random_magic_addr)) { + use_random = true; + eth_random_addr(base_addr); + cc33xx_debug(DEBUG_BOOT, + "NVS file sets random MAC address"); + } else { + use_nvs = true; + ether_addr_copy(base_addr, nvs_addr); + cc33xx_debug(DEBUG_BOOT, + "NVS file sets explicit MAC address"); + } + } + + if (use_nvs || use_efuse) { + u8 oui_laa_bit = BIT(1); + u8 oui_multicast_bit = BIT(0); + + base_addr[0] &= ~oui_multicast_bit; + + ether_addr_copy(cc->addresses[0].addr, base_addr); + ether_addr_copy(cc->addresses[1].addr, base_addr); + ether_addr_copy(cc->addresses[2].addr, base_addr); + ether_addr_copy(bd_addr, base_addr); + + cc->addresses[1].addr[0] |= oui_laa_bit; + cc->addresses[2].addr[0] |= oui_laa_bit; + + eth_addr_inc(cc->addresses[2].addr); + eth_addr_inc(bd_addr); + } else if (use_random) { + ether_addr_copy(cc->addresses[0].addr, base_addr); + ether_addr_copy(cc->addresses[1].addr, base_addr); + ether_addr_copy(cc->addresses[2].addr, base_addr); + ether_addr_copy(bd_addr, base_addr); + + eth_addr_inc(bd_addr); + eth_addr_inc(cc->addresses[1].addr); + eth_addr_inc(cc->addresses[1].addr); + eth_addr_inc(cc->addresses[2].addr); + eth_addr_inc(cc->addresses[2].addr); + eth_addr_inc(cc->addresses[2].addr); + } else { + WARN_ON(1); + } + + cc33xx_debug(DEBUG_BOOT, "Base MAC address: %pM", + cc->addresses[0].addr); + + cc->hw->wiphy->n_addresses = CC33XX_NUM_MAC_ADDRESSES; + cc->hw->wiphy->addresses = cc->addresses; + + cmd_set_bd_addr(cc, bd_addr); +} + +static int cc33xx_register_hw(struct cc33xx *cc) +{ + int ret; + + if (cc->mac80211_registered) + return 0; + + cc33xx_derive_mac_addresses(cc); + + ret = ieee80211_register_hw(cc->hw); + if (ret < 0) { + cc33xx_error("unable to register mac80211 hw: %d", ret); + goto out; + } + + cc->mac80211_registered = true; + +out: + return ret; +} + +static void cc33xx_unregister_hw(struct cc33xx *cc) +{ + if (cc->plt) + cc33xx_plt_stop(cc); + + ieee80211_unregister_hw(cc->hw); + cc->mac80211_registered = false; +} + +static int cc33xx_init_ieee80211(struct cc33xx *cc) +{ + unsigned int i; + + if (cc->conf.core.mixed_mode_support) { + static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_AES_CMAC, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_GCMP, + WLAN_CIPHER_SUITE_GCMP_256, + WLAN_CIPHER_SUITE_BIP_GMAC_128, + WLAN_CIPHER_SUITE_BIP_GMAC_256, + }; + cc->hw->wiphy->cipher_suites = cipher_suites; + cc->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + + } else { + static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_AES_CMAC, + WLAN_CIPHER_SUITE_GCMP, + WLAN_CIPHER_SUITE_GCMP_256, + WLAN_CIPHER_SUITE_BIP_GMAC_128, + WLAN_CIPHER_SUITE_BIP_GMAC_256, + }; + cc->hw->wiphy->cipher_suites = cipher_suites; + cc->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + } + + /* The tx descriptor buffer */ + cc->hw->extra_tx_headroom = CC33XX_TX_EXTRA_HEADROOM; + + if (cc->quirks & CC33XX_QUIRK_TKIP_HEADER_SPACE) + cc->hw->extra_tx_headroom += CC33XX_EXTRA_SPACE_TKIP; + + /* unit us */ + /* FIXME: find a proper value */ + cc->hw->max_listen_interval = + cc->conf.host_conf.conn.max_listen_interval; + + ieee80211_hw_set(cc->hw, SUPPORT_FAST_XMIT); + ieee80211_hw_set(cc->hw, CHANCTX_STA_CSA); + ieee80211_hw_set(cc->hw, QUEUE_CONTROL); + ieee80211_hw_set(cc->hw, TX_AMPDU_SETUP_IN_HW); + ieee80211_hw_set(cc->hw, AMPDU_AGGREGATION); + ieee80211_hw_set(cc->hw, AP_LINK_PS); + ieee80211_hw_set(cc->hw, SPECTRUM_MGMT); + ieee80211_hw_set(cc->hw, REPORTS_TX_ACK_STATUS); + ieee80211_hw_set(cc->hw, CONNECTION_MONITOR); + ieee80211_hw_set(cc->hw, HAS_RATE_CONTROL); + ieee80211_hw_set(cc->hw, SUPPORTS_DYNAMIC_PS); + ieee80211_hw_set(cc->hw, SIGNAL_DBM); + ieee80211_hw_set(cc->hw, SUPPORTS_PS); + ieee80211_hw_set(cc->hw, SUPPORTS_TX_FRAG); + ieee80211_hw_set(cc->hw, SUPPORTS_MULTI_BSSID); + ieee80211_hw_set(cc->hw, SUPPORTS_AMSDU_IN_AMPDU); + + cc->hw->wiphy->interface_modes = cc33xx_wiphy_interface_modes(); + + cc->hw->wiphy->max_scan_ssids = 1; + cc->hw->wiphy->max_sched_scan_ssids = 16; + cc->hw->wiphy->max_match_sets = 16; + /* Maximum length of elements in scanning probe request templates + * should be the maximum length possible for a template, without + * the IEEE80211 header of the template + */ + cc->hw->wiphy->max_scan_ie_len = CC33XX_CMD_TEMPL_MAX_SIZE - + sizeof(struct ieee80211_header); + + cc->hw->wiphy->max_sched_scan_reqs = 1; + cc->hw->wiphy->max_sched_scan_ie_len = CC33XX_CMD_TEMPL_MAX_SIZE - + sizeof(struct ieee80211_header); + + cc->hw->wiphy->max_remain_on_channel_duration = 30000; + + cc->hw->wiphy->features |= NL80211_FEATURE_AP_SCAN; + + /* clear channel flags from the previous usage + * and restore max_power & max_antenna_gain values. + */ + for (i = 0; i < ARRAY_SIZE(cc33xx_channels); i++) { + cc33xx_band_2ghz.channels[i].flags = 0; + cc33xx_band_2ghz.channels[i].max_power = CC33XX_MAX_TXPWR; + cc33xx_band_2ghz.channels[i].max_antenna_gain = 0; + } + + for (i = 0; i < ARRAY_SIZE(cc33xx_channels_5ghz); i++) { + cc33xx_band_5ghz.channels[i].flags = 0; + cc33xx_band_5ghz.channels[i].max_power = CC33XX_MAX_TXPWR; + cc33xx_band_5ghz.channels[i].max_antenna_gain = 0; + } + + /* Enable/Disable He based on conf file params */ + if (!cc->conf.mac.he_enable) { + cc33xx_band_2ghz.iftype_data = NULL; + cc33xx_band_2ghz.n_iftype_data = 0; + + cc33xx_band_5ghz.iftype_data = NULL; + cc33xx_band_5ghz.n_iftype_data = 0; + } + + /* We keep local copies of the band structs because we need to + * modify them on a per-device basis. + */ + memcpy(&cc->bands[NL80211_BAND_2GHZ], &cc33xx_band_2ghz, + sizeof(cc33xx_band_2ghz)); + memcpy(&cc->bands[NL80211_BAND_2GHZ].ht_cap, + &cc->ht_cap[NL80211_BAND_2GHZ], + sizeof(*cc->ht_cap)); + + memcpy(&cc->bands[NL80211_BAND_5GHZ], &cc33xx_band_5ghz, + sizeof(cc33xx_band_5ghz)); + memcpy(&cc->bands[NL80211_BAND_5GHZ].ht_cap, + &cc->ht_cap[NL80211_BAND_5GHZ], + sizeof(*cc->ht_cap)); + + cc->hw->wiphy->bands[NL80211_BAND_2GHZ] = + &cc->bands[NL80211_BAND_2GHZ]; + + if (!cc->disable_5g && cc->conf.core.enable_5ghz) + cc->hw->wiphy->bands[NL80211_BAND_5GHZ] = + &cc->bands[NL80211_BAND_5GHZ]; + + /* allow 4 queues per mac address we support + + * 1 cab queue per mac + one global offchannel Tx queue + */ + cc->hw->queues = (NUM_TX_QUEUES + 1) * CC33XX_NUM_MAC_ADDRESSES + 1; + + /* the last queue is the offchannel queue */ + cc->hw->offchannel_tx_hw_queue = cc->hw->queues - 1; + cc->hw->max_rates = 1; + + /* allowed interface combinations */ + cc->hw->wiphy->iface_combinations = cc33xx_iface_combinations; + cc->hw->wiphy->n_iface_combinations = ARRAY_SIZE(cc33xx_iface_combinations); + + SET_IEEE80211_DEV(cc->hw, cc->dev); + + cc->hw->sta_data_size = sizeof(struct cc33xx_station); + cc->hw->vif_data_size = sizeof(struct cc33xx_vif); + + cc->hw->max_rx_aggregation_subframes = cc->conf.host_conf.ht.rx_ba_win_size; + + /* For all ps schemes don't use UAPSD, except for UAPSD scheme + * As these are the currently supportedd PS schemes, use the default + * legacy otherwise + */ + if (cc->conf.mac.ps_scheme == PS_SCHEME_UPSD_TRIGGER) { + cc->hw->uapsd_queues = IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK; + } else if ((cc->conf.mac.ps_scheme != PS_SCHEME_LEGACY) && + (cc->conf.mac.ps_scheme != PS_SCHEME_NOPSPOLL)) { + cc->hw->uapsd_queues = 0; + cc->conf.mac.ps_scheme = PS_SCHEME_LEGACY; + } else { + cc->hw->uapsd_queues = 0; + } + + return 0; +} + +#define create_high_prio_freezable_workqueue(name) \ + alloc_workqueue("%s", __WQ_LEGACY | WQ_FREEZABLE | WQ_UNBOUND | \ + WQ_MEM_RECLAIM | WQ_HIGHPRI, 1, (name)) + +static struct ieee80211_hw *cc33xx_alloc_hw(u32 aggr_buf_size) +{ + struct ieee80211_hw *hw; + struct cc33xx *cc; + int i, j; + unsigned int order; + + hw = ieee80211_alloc_hw(sizeof(*cc), &cc33xx_ops); + if (!hw) { + cc33xx_error("could not alloc ieee80211_hw"); + goto err_hw_alloc; + } + + cc = hw->priv; + memset(cc, 0, sizeof(*cc)); + + INIT_LIST_HEAD(&cc->wlvif_list); + + cc->hw = hw; + + /* cc->num_links is not configured yet, so just use CC33XX_MAX_LINKS. + * we don't allocate any additional resource here, so that's fine. + */ + for (i = 0; i < NUM_TX_QUEUES; i++) + for (j = 0; j < CC33XX_MAX_LINKS; j++) + skb_queue_head_init(&cc->links[j].tx_queue[i]); + + skb_queue_head_init(&cc->deferred_rx_queue); + skb_queue_head_init(&cc->deferred_tx_queue); + + init_llist_head(&cc->event_list); + + INIT_WORK(&cc->netstack_work, cc33xx_netstack_work); + INIT_WORK(&cc->tx_work, cc33xx_tx_work); + INIT_WORK(&cc->recovery_work, cc33xx_recovery_work); + INIT_WORK(&cc->irq_deferred_work, irq_deferred_work); + INIT_DELAYED_WORK(&cc->scan_complete_work, cc33xx_scan_complete_work); + INIT_DELAYED_WORK(&cc->roc_complete_work, cc33xx_roc_complete_work); + INIT_DELAYED_WORK(&cc->tx_watchdog_work, cc33xx_tx_watchdog_work); + + cc->freezable_netstack_wq = create_freezable_workqueue("cc33xx_netstack_wq"); + if (!cc->freezable_netstack_wq) + goto err_hw_alloc; + + cc->freezable_wq = create_high_prio_freezable_workqueue("cc33xx_wq"); + if (!cc->freezable_wq) + goto err_ns_wq; + + cc->rx_counter = 0; + cc->power_level = CC33XX_MAX_TXPWR; + cc->band = NL80211_BAND_2GHZ; + cc->flags = 0; + cc->sleep_auth = CC33XX_PSM_ILLEGAL; + + cc->ap_ps_map = 0; + cc->ap_fw_ps_map = 0; + cc->quirks = 0; + cc->active_sta_count = 0; + cc->active_link_count = 0; + cc->fwlog_size = 0; + + /* The system link is always allocated */ + __set_bit(CC33XX_SYSTEM_HLID, cc->links_map); + + memset(cc->tx_frames_map, 0, sizeof(cc->tx_frames_map)); + for (i = 0; i < CC33XX_NUM_TX_DESCRIPTORS; i++) + cc->tx_frames[i] = NULL; + + spin_lock_init(&cc->cc_lock); + + cc->state = CC33XX_STATE_OFF; + mutex_init(&cc->mutex); + mutex_init(&cc->flush_mutex); + init_completion(&cc->nvs_loading_complete); + + order = get_order(aggr_buf_size); + cc->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); + if (!cc->aggr_buf) + goto err_all_wq; + + cc->aggr_buf_size = aggr_buf_size; + + cc->dummy_packet = cc33xx_alloc_dummy_packet(cc); + if (!cc->dummy_packet) + goto err_aggr; + + /* Allocate one page for the FW log */ + cc->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL); + if (!cc->fwlog) + goto err_dummy_packet; + + cc->buffer_32 = kmalloc(sizeof(*cc->buffer_32), GFP_KERNEL); + if (!cc->buffer_32) + goto err_fwlog; + + cc->core_status = kzalloc(sizeof(*cc->core_status), GFP_KERNEL); + if (!cc->core_status) + goto err_buf32; + + return hw; + +err_buf32: + kfree(cc->buffer_32); + +err_fwlog: + free_page((unsigned long)cc->fwlog); + +err_dummy_packet: + dev_kfree_skb(cc->dummy_packet); + +err_aggr: + free_pages((unsigned long)cc->aggr_buf, order); + +err_all_wq: + destroy_workqueue(cc->freezable_wq); + +err_ns_wq: + destroy_workqueue(cc->freezable_netstack_wq); + +err_hw_alloc: + return NULL; +} + +static int cc33xx_free_hw(struct cc33xx *cc) +{ + /* Unblock any fwlog readers */ + mutex_lock(&cc->mutex); + cc->fwlog_size = -1; + mutex_unlock(&cc->mutex); + + kfree(cc->buffer_32); + kfree(cc->core_status); + free_page((unsigned long)cc->fwlog); + dev_kfree_skb(cc->dummy_packet); + free_pages((unsigned long)cc->aggr_buf, get_order(cc->aggr_buf_size)); + + kfree(cc->nvs_mac_addr); + cc->nvs_mac_addr = NULL; + + destroy_workqueue(cc->freezable_wq); + destroy_workqueue(cc->freezable_netstack_wq); + flush_deferred_event_list(cc); + + ieee80211_free_hw(cc->hw); + + return 0; +} + +static int cc33xx_identify_chip(struct cc33xx *cc) +{ + int ret = 0; + + cc->quirks |= CC33XX_QUIRK_RX_BLOCKSIZE_ALIGN | + CC33XX_QUIRK_TX_BLOCKSIZE_ALIGN | + CC33XX_QUIRK_NO_SCHED_SCAN_WHILE_CONN | + CC33XX_QUIRK_TX_PAD_LAST_FRAME | + CC33XX_QUIRK_DUAL_PROBE_TMPL; + + if (cc->if_ops->get_max_transaction_len) + cc->max_transaction_len = + cc->if_ops->get_max_transaction_len(cc->dev); + else + cc->max_transaction_len = 0; + + return ret; +} + +static int read_version_info(struct cc33xx *cc) +{ + int ret; + + ret = cc33xx_acx_init_get_fw_versions(cc); + if (ret < 0) { + cc33xx_error("Get FW version FAILED!"); + return ret; + } + + cc33xx_debug(DEBUG_BOOT, "Wireless firmware version %u.%u.%u.%u", + cc->fw_ver->major_version, + cc->fw_ver->minor_version, + cc->fw_ver->api_version, + cc->fw_ver->build_version); + + cc33xx_debug(DEBUG_BOOT, "Wireless PHY version %u.%u.%u.%u.%u.%u", + cc->fw_ver->phy_version[5], + cc->fw_ver->phy_version[4], + cc->fw_ver->phy_version[3], + cc->fw_ver->phy_version[2], + cc->fw_ver->phy_version[1], + cc->fw_ver->phy_version[0]); + + return 0; +} + +static void cc33xx_nvs_cb(const struct firmware *fw, void *context) +{ + struct cc33xx *cc = context; + struct platform_device *pdev = cc->pdev; + struct cc33xx_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); + + int ret; + + if (fw) { + cc->nvs_mac_addr = kmemdup(fw->data, fw->size, GFP_KERNEL); + if (!cc->nvs_mac_addr) { + cc33xx_error("Could not allocate nvs data"); + goto out; + } + cc->nvs_mac_addr_len = fw->size; + } else if (pdev_data->family->nvs_name) { + cc33xx_debug(DEBUG_BOOT, "Could not get nvs file %s", + pdev_data->family->nvs_name); + cc->nvs_mac_addr = NULL; + cc->nvs_mac_addr_len = 0; + } else { + cc->nvs_mac_addr = NULL; + cc->nvs_mac_addr_len = 0; + } + + ret = cc33xx_setup(cc); + if (ret < 0) + goto out_free_nvs; + + BUILD_BUG_ON(CC33XX_NUM_TX_DESCRIPTORS > CC33XX_MAX_TX_DESCRIPTORS); + + /* adjust some runtime configuration parameters */ + cc33xx_adjust_conf(cc); + + cc->if_ops = pdev_data->if_ops; + cc->if_ops->set_irq_handler(cc->dev, irq_wrapper); + + cc33xx_power_off(cc); + + setup_wake_irq(cc); + + ret = cc33xx_init_fw(cc); + if (ret < 0) { + cc33xx_error("FW download failed"); + cc33xx_power_off(cc); + goto out_irq; + } + + ret = cc33xx_identify_chip(cc); + if (ret < 0) + goto out_irq; + + ret = read_version_info(cc); + if (ret < 0) + goto out_irq; + + ret = cc33xx_init_ieee80211(cc); + if (ret) + goto out_irq; + + ret = cc33xx_register_hw(cc); + if (ret) + goto out_irq; + + cc->initialized = true; + goto out; + +out_irq: + if (cc->wakeirq >= 0) + dev_pm_clear_wake_irq(cc->dev); + device_init_wakeup(cc->dev, false); + +out_free_nvs: + kfree(cc->nvs_mac_addr); + +out: + release_firmware(fw); + complete_all(&cc->nvs_loading_complete); + cc33xx_debug(DEBUG_CC33xx, "%s complete", __func__); +} + +static int cc33xx_load_ini_bin_file(struct device *dev, + struct cc33xx_conf_file *conf, + const char *file) +{ + struct cc33xx_conf_file *conf_file; + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, file, dev); + if (ret < 0) { + cc33xx_error("could not get configuration binary %s: %d", + file, ret); + return ret; + } + + if (fw->size != CC33X_CONF_SIZE) { + cc33xx_error("%s configuration binary size is wrong, expected %zu got %zu", + file, CC33X_CONF_SIZE, + fw->size); + ret = -EINVAL; + goto out_release; + } + + conf_file = (struct cc33xx_conf_file *)fw->data; + + if (conf_file->header.magic != cpu_to_le32(CC33XX_CONF_MAGIC)) { + cc33xx_error("conf file magic number mismatch, expected 0x%0x got 0x%0x", + CC33XX_CONF_MAGIC, conf_file->header.magic); + ret = -EINVAL; + goto out_release; + } + + memcpy(conf, conf_file, sizeof(*conf)); + +out_release: + release_firmware(fw); + return ret; +} + +static int cc33xx_ini_bin_init(struct cc33xx *cc, struct device *dev) +{ + struct platform_device *pdev = cc->pdev; + struct cc33xx_platdev_data *pdata = dev_get_platdata(&pdev->dev); + + if (cc33xx_load_ini_bin_file(dev, &cc->conf, + pdata->family->cfg_name) < 0) + cc33xx_warning("falling back to default config"); + + return 0; +} + +static inline void cc33xx_set_ht_cap(struct cc33xx *cc, enum nl80211_band band, + struct ieee80211_sta_ht_cap *ht_cap) +{ + memcpy(&cc->ht_cap[band], ht_cap, sizeof(*ht_cap)); +} + +static int cc33xx_setup(struct cc33xx *cc) +{ + int ret; + + BUILD_BUG_ON(CC33XX_MAX_AP_STATIONS > CC33XX_MAX_LINKS); + + ret = cc33xx_ini_bin_init(cc, cc->dev); + if (ret < 0) + return ret; + + if (cc->conf.host_conf.ht.mode == HT_MODE_DEFAULT) { + cc33xx_set_ht_cap(cc, NL80211_BAND_2GHZ, + &cc33xx_siso40_ht_cap_2ghz); + + /* 5Ghz is always wide */ + cc33xx_set_ht_cap(cc, NL80211_BAND_5GHZ, + &cc33xx_siso40_ht_cap_5ghz); + } else if (cc->conf.host_conf.ht.mode == HT_MODE_WIDE) { + cc33xx_set_ht_cap(cc, NL80211_BAND_2GHZ, + &cc33xx_siso40_ht_cap_2ghz); + cc33xx_set_ht_cap(cc, NL80211_BAND_5GHZ, + &cc33xx_siso40_ht_cap_5ghz); + } else if (cc->conf.host_conf.ht.mode == HT_MODE_SISO20) { + cc33xx_set_ht_cap(cc, NL80211_BAND_2GHZ, &cc33xx_siso20_ht_cap); + cc33xx_set_ht_cap(cc, NL80211_BAND_5GHZ, &cc33xx_siso20_ht_cap); + } + + cc->event_mask = BSS_LOSS_EVENT_ID | SCAN_COMPLETE_EVENT_ID | + RADAR_DETECTED_EVENT_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | + PERIODIC_SCAN_COMPLETE_EVENT_ID | + PERIODIC_SCAN_REPORT_EVENT_ID | DUMMY_PACKET_EVENT_ID | + PEER_REMOVE_COMPLETE_EVENT_ID | + BA_SESSION_RX_CONSTRAINT_EVENT_ID | + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | + CHANNEL_SWITCH_COMPLETE_EVENT_ID | + DFS_CHANNELS_CONFIG_COMPLETE_EVENT | + SMART_CONFIG_SYNC_EVENT_ID | INACTIVE_STA_EVENT_ID | + SMART_CONFIG_DECODE_EVENT_ID | TIME_SYNC_EVENT_ID | + FW_LOGGER_INDICATION | RX_BA_WIN_SIZE_CHANGE_EVENT_ID; + + cc->ap_event_mask = MAX_TX_FAILURE_EVENT_ID; + + return 0; +} + +static int cc33xx_probe(struct platform_device *pdev) +{ + struct cc33xx *cc; + struct ieee80211_hw *hw; + struct cc33xx_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); + const char *nvs_name; + int ret; + + if (!pdev_data) { + cc33xx_error("can't access platform data"); + return -EINVAL; + } + + hw = cc33xx_alloc_hw(CC33XX_AGGR_BUFFER_SIZE); + if (!hw) { + ret = -ENOMEM; + goto out; + } + cc = hw->priv; + cc->dev = &pdev->dev; + cc->pdev = pdev; + platform_set_drvdata(pdev, cc); + + if (pdev_data->family && pdev_data->family->nvs_name) { + nvs_name = pdev_data->family->nvs_name; + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, + nvs_name, &pdev->dev, GFP_KERNEL, + cc, cc33xx_nvs_cb); + if (ret < 0) { + cc33xx_error("request_firmware_nowait failed for %s: %d", + nvs_name, ret); + complete_all(&cc->nvs_loading_complete); + } + } else { + cc33xx_nvs_cb(NULL, cc); + cc33xx_error("Invalid platform data entry"); + ret = -EINVAL; + } + +out: + return ret; +} + +static int cc33xx_remove(struct platform_device *pdev) +{ + struct cc33xx_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); + struct cc33xx *cc = platform_get_drvdata(pdev); + + set_bit(CC33XX_FLAG_DRIVER_REMOVED, &cc->flags); + + cc->dev->driver->pm = NULL; + + if (pdev_data->family && pdev_data->family->nvs_name) + wait_for_completion(&cc->nvs_loading_complete); + + if (!cc->initialized) + goto out; + + if (cc->wakeirq >= 0) { + dev_pm_clear_wake_irq(cc->dev); + cc->wakeirq = -ENODEV; + } + + device_init_wakeup(cc->dev, false); + cc33xx_unregister_hw(cc); + cc33xx_turn_off(cc); + +out: + cc33xx_free_hw(cc); + return 0; +} + +static const struct platform_device_id cc33xx_id_table[] = { + { "cc33xx", 0 }, + { } +}; +MODULE_DEVICE_TABLE(platform, cc33xx_id_table); + +static struct platform_driver cc33xx_driver = { + .probe = cc33xx_probe, + .remove = cc33xx_remove, + .id_table = cc33xx_id_table, + .driver = { + .name = "cc33xx_driver", + } +}; + +module_platform_driver(cc33xx_driver); + +module_param_named(debug_level, cc33xx_debug_level, uint, 0600); +MODULE_PARM_DESC(debug_level, "cc33xx debugging level"); + +module_param(no_recovery, int, 0600); +MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck."); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Texas Instruments CC33xx WLAN driver"); +MODULE_AUTHOR("Michael Nemanov "); +MODULE_AUTHOR("Sabeeh Khan "); + +MODULE_FIRMWARE(SECOND_LOADER_NAME); +MODULE_FIRMWARE(FW_NAME); diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/Makefile b/drivers/net/wireless/ti/cc33xx/Makefile --- a/drivers/net/wireless/ti/cc33xx/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/Makefile 2024-07-07 20:37:34.668306669 -0400 @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 + +cc33xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ + boot.o init.o scan.o + +cc33xx_sdio-objs = sdio.o + +cc33xx-$(CONFIG_NL80211_TESTMODE) += testmode.o +obj-$(CONFIG_CC33XX) += cc33xx.o +obj-$(CONFIG_CC33XX_SDIO) += cc33xx_sdio.o diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/ps.c b/drivers/net/wireless/ti/cc33xx/ps.c --- a/drivers/net/wireless/ti/cc33xx/ps.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/ps.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include "ps.h" +#include "tx.h" +#include "debug.h" + +int cc33xx_ps_set_mode(struct cc33xx *cc, struct cc33xx_vif *wlvif, + enum cc33xx_cmd_ps_mode_e mode) +{ + int ret; + u16 timeout = cc->conf.host_conf.conn.dynamic_ps_timeout; + + switch (mode) { + case STATION_AUTO_PS_MODE: + case STATION_POWER_SAVE_MODE: + cc33xx_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)", + mode, timeout); + + ret = cc33xx_cmd_ps_mode(cc, wlvif, mode, timeout); + if (ret < 0) + return ret; + + set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags); + break; + + case STATION_ACTIVE_MODE: + cc33xx_debug(DEBUG_PSM, "leaving psm"); + + ret = cc33xx_cmd_ps_mode(cc, wlvif, mode, 0); + if (ret < 0) + return ret; + + clear_bit(WLVIF_FLAG_IN_PS, &wlvif->flags); + break; + + default: + cc33xx_warning("trying to set ps to unsupported mode %d", mode); + ret = -EINVAL; + } + + return ret; +} + +static void cc33xx_ps_filter_frames(struct cc33xx *cc, u8 hlid) +{ + int i; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + unsigned long flags; + int filtered[NUM_TX_QUEUES]; + struct cc33xx_link *lnk = &cc->links[hlid]; + + /* filter all frames currently in the low level queues for this hlid */ + for (i = 0; i < NUM_TX_QUEUES; i++) { + filtered[i] = 0; + while ((skb = skb_dequeue(&lnk->tx_queue[i]))) { + filtered[i]++; + + if (WARN_ON(cc33xx_is_dummy_packet(cc, skb))) + continue; + + info = IEEE80211_SKB_CB(skb); + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + info->status.rates[0].idx = -1; + ieee80211_tx_status_ni(cc->hw, skb); + } + } + + spin_lock_irqsave(&cc->cc_lock, flags); + for (i = 0; i < NUM_TX_QUEUES; i++) { + cc->tx_queue_count[i] -= filtered[i]; + if (lnk->wlvif) + lnk->wlvif->tx_queue_count[i] -= filtered[i]; + } + + spin_unlock_irqrestore(&cc->cc_lock, flags); + cc33xx_handle_tx_low_watermark(cc); +} + +void cc33xx_ps_link_start(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 hlid, bool clean_queues) +{ + struct ieee80211_sta *sta; + struct ieee80211_vif *vif = cc33xx_wlvif_to_vif(wlvif); + + if (WARN_ON_ONCE(wlvif->bss_type != BSS_TYPE_AP_BSS)) + return; + + if (!test_bit(hlid, wlvif->ap.sta_hlid_map) || + test_bit(hlid, &cc->ap_ps_map)) + return; + + cc33xx_debug(DEBUG_PSM, + "start mac80211 PSM on hlid %d pkts %d clean_queues %d", + hlid, cc->links[hlid].allocated_pkts, clean_queues); + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, cc->links[hlid].addr); + if (!sta) { + cc33xx_error("could not find sta %pM for starting ps", + cc->links[hlid].addr); + rcu_read_unlock(); + return; + } + + ieee80211_sta_ps_transition_ni(sta, true); + rcu_read_unlock(); + + /* do we want to filter all frames from this link's queues? */ + if (clean_queues) + cc33xx_ps_filter_frames(cc, hlid); + + __set_bit(hlid, &cc->ap_ps_map); +} diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/ps.h b/drivers/net/wireless/ti/cc33xx/ps.h --- a/drivers/net/wireless/ti/cc33xx/ps.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/ps.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __PS_H__ +#define __PS_H__ + +#include "acx.h" + +int cc33xx_ps_set_mode(struct cc33xx *cc, struct cc33xx_vif *wlvif, + enum cc33xx_cmd_ps_mode_e mode); +void cc33xx_ps_link_start(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 hlid, bool clean_queues); + +#endif /* __PS_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/rx.c b/drivers/net/wireless/ti/cc33xx/rx.c --- a/drivers/net/wireless/ti/cc33xx/rx.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/rx.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include "acx.h" +#include "rx.h" +#include "tx.h" +#include "io.h" + +#define RSSI_LEVEL_BITMASK 0x7F +#define ANT_DIVERSITY_BITMASK BIT(7) +#define ANT_DIVERSITY_SHIFT 7 + +/* Construct the rx status structure for upper layers */ +static void cc33xx_rx_status(struct cc33xx *cc, + struct cc33xx_rx_descriptor *desc, + struct ieee80211_rx_status *status, + u8 beacon, u8 probe_rsp) +{ + memset(status, 0, sizeof(struct ieee80211_rx_status)); + + if ((desc->flags & CC33XX_RX_DESC_BAND_MASK) == CC33XX_RX_DESC_BAND_BG) + status->band = NL80211_BAND_2GHZ; + else if ((desc->flags & CC33XX_RX_DESC_BAND_MASK) == CC33XX_RX_DESC_BAND_J) + status->band = NL80211_BAND_2GHZ; + else if ((desc->flags & CC33XX_RX_DESC_BAND_MASK) == CC33XX_RX_DESC_BAND_A) + status->band = NL80211_BAND_5GHZ; + else + status->band = NL80211_BAND_5GHZ; /* todo -Should be 6GHZ when added */ + + status->rate_idx = cc33xx_rate_to_idx(cc, desc->rate, status->band); + + if (desc->frame_format == CC33xx_VHT) + status->encoding = RX_ENC_VHT; + else if ((desc->frame_format == CC33xx_HT_MF) || + (desc->frame_format == CC33xx_HT_GF)) + status->encoding = RX_ENC_HT; + else if ((desc->frame_format == CC33xx_B_SHORT) || + (desc->frame_format == CC33xx_B_LONG) || + (desc->frame_format == CC33xx_LEGACY_OFDM)) + status->encoding = RX_ENC_LEGACY; + else + status->encoding = RX_ENC_HE; + + /* Read the signal level and antenna diversity indication. + * The msb in the signal level is always set as it is a + * negative number. + * The antenna indication is the msb of the rssi. + */ + status->signal = ((desc->rssi & RSSI_LEVEL_BITMASK) | BIT(7)); + status->antenna = ((desc->rssi & ANT_DIVERSITY_BITMASK) >> ANT_DIVERSITY_SHIFT); + status->freq = ieee80211_channel_to_frequency(desc->channel, + status->band); + + if (desc->flags & CC33XX_RX_DESC_ENCRYPT_MASK) { + u8 desc_err_code = desc->status & CC33XX_RX_DESC_STATUS_MASK; + + /* Frame is sent to driver with the IV (for PN replay check) + * but without the MIC + */ + status->flag |= RX_FLAG_MMIC_STRIPPED | + RX_FLAG_DECRYPTED | RX_FLAG_MIC_STRIPPED; + + if (unlikely(desc_err_code & CC33XX_RX_DESC_MIC_FAIL)) { + status->flag |= RX_FLAG_MMIC_ERROR; + cc33xx_warning("Michael MIC error. Desc: 0x%x", + desc_err_code); + } + } + + if (beacon || probe_rsp) + status->boottime_ns = ktime_get_boottime_ns(); + + if (beacon) + cc33xx_set_pending_regdomain_ch(cc, (u16)desc->channel, + status->band); + status->nss = 1; +} + +/* Copy part\ all of the descriptor. Allocate skb, or drop corrupted packet + */ +static int cc33xx_rx_get_packet_descriptor(struct cc33xx *cc, u8 *raw_buffer_ptr, + u16 *raw_buffer_len) +{ + u16 missing_desc_bytes; + u16 available_desc_bytes; + u16 pkt_data_len; + struct sk_buff *skb; + u16 prev_buffer_len = *raw_buffer_len; + + missing_desc_bytes = sizeof(struct cc33xx_rx_descriptor); + missing_desc_bytes -= cc->partial_rx.handled_bytes; + available_desc_bytes = min(*raw_buffer_len, missing_desc_bytes); + memcpy(((u8 *)(&cc->partial_rx.desc)) + cc->partial_rx.handled_bytes, + raw_buffer_ptr, available_desc_bytes); + + /* If descriptor was not completed */ + if (available_desc_bytes != missing_desc_bytes) { + cc->partial_rx.handled_bytes += *raw_buffer_len; + cc->partial_rx.status = CURR_RX_DESC; + *raw_buffer_len = 0; + goto out; + } else { + cc->partial_rx.handled_bytes += available_desc_bytes; + *raw_buffer_len -= available_desc_bytes; + } + + /* Descriptor was fully copied */ + pkt_data_len = cc->partial_rx.original_bytes; + pkt_data_len -= sizeof(struct cc33xx_rx_descriptor); + + if (unlikely(cc->partial_rx.desc.status & CC33XX_RX_DESC_DECRYPT_FAIL)) { + cc33xx_warning("corrupted packet in RX: status: 0x%x len: %d", + cc->partial_rx.desc.status & CC33XX_RX_DESC_STATUS_MASK, + pkt_data_len); + + /* If frame can be fully dropped */ + if (pkt_data_len <= *raw_buffer_len) { + *raw_buffer_len -= pkt_data_len; + cc->partial_rx.status = CURR_RX_START; + } else { + cc->partial_rx.handled_bytes += *raw_buffer_len; + cc->partial_rx.status = CURR_RX_DROP; + *raw_buffer_len = 0; + } + goto out; + } + + skb = __dev_alloc_skb(pkt_data_len, GFP_KERNEL); + if (!skb) { + cc33xx_error("Couldn't allocate RX frame"); + /* If frame can be fully dropped */ + if (pkt_data_len <= *raw_buffer_len) { + *raw_buffer_len -= pkt_data_len; + cc->partial_rx.status = CURR_RX_START; + } else { + /* Dropped partial frame */ + cc->partial_rx.handled_bytes += *raw_buffer_len; + cc->partial_rx.status = CURR_RX_DROP; + *raw_buffer_len = 0; + } + goto out; + } + + cc->partial_rx.skb = skb; + cc->partial_rx.status = CURR_RX_DATA; + +out: + /* Function return the amount of consumed bytes */ + return (prev_buffer_len - *raw_buffer_len); +} + +/* Copy part or all of the packet's data. push skb to queue if possible */ +static int cc33xx_rx_get_packet_data(struct cc33xx *cc, u8 *raw_buffer_ptr, + u16 *raw_buffer_len) +{ + u16 missing_data_bytes; + u16 available_data_bytes; + u32 defer_count; + enum cc33xx_rx_buf_align rx_align; + u16 extra_bytes; + struct ieee80211_hdr *hdr; + u8 beacon = 0; + u8 is_probe_resp = 0; + u16 seq_num; + u16 prev_buffer_len = *raw_buffer_len; + + missing_data_bytes = cc->partial_rx.original_bytes; + missing_data_bytes -= cc->partial_rx.handled_bytes; + available_data_bytes = min(missing_data_bytes, *raw_buffer_len); + + cc33xx_debug(DEBUG_RX, "current rx data: original bytes: %d, handled bytes %d, desc pad len %d, missing_data_bytes %d", + cc->partial_rx.original_bytes, + cc->partial_rx.handled_bytes, + cc->partial_rx.desc.pad_len, missing_data_bytes); + + skb_put_data(cc->partial_rx.skb, raw_buffer_ptr, available_data_bytes); + + /* Check if we didn't manage to copy the entire packet - got out, + * continue next time + */ + if (available_data_bytes != missing_data_bytes) { + cc->partial_rx.handled_bytes += *raw_buffer_len; + cc->partial_rx.status = CURR_RX_DATA; + *raw_buffer_len = 0; + goto out; + } else { + *raw_buffer_len -= available_data_bytes; + } + + /* Data fully copied */ + + rx_align = cc->partial_rx.desc.header_alignment; + if (rx_align == CC33XX_RX_BUF_PADDED) + skb_pull(cc->partial_rx.skb, RX_BUF_ALIGN); + + extra_bytes = cc->partial_rx.desc.pad_len; + if (extra_bytes != 0) + skb_trim(cc->partial_rx.skb, + cc->partial_rx.skb->len - extra_bytes); + + hdr = (struct ieee80211_hdr *)cc->partial_rx.skb->data; + + if (ieee80211_is_beacon(hdr->frame_control)) + beacon = 1; + if (ieee80211_is_probe_resp(hdr->frame_control)) + is_probe_resp = 1; + + cc33xx_rx_status(cc, &cc->partial_rx.desc, + IEEE80211_SKB_RXCB(cc->partial_rx.skb), + beacon, is_probe_resp); + + seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + cc33xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d link id %d", + cc->partial_rx.skb, + cc->partial_rx.skb->len - cc->partial_rx.desc.pad_len, + beacon ? "beacon" : "", seq_num, cc->partial_rx.desc.hlid); + + cc33xx_debug(DEBUG_RX, "rx frame. frame type 0x%x, frame length 0x%x, frame address 0x%lx", + hdr->frame_control, cc->partial_rx.skb->len, + (unsigned long)cc->partial_rx.skb->data); + + /* Adding frame to queue */ + skb_queue_tail(&cc->deferred_rx_queue, cc->partial_rx.skb); + cc->rx_counter++; + cc->partial_rx.status = CURR_RX_START; + + /* Make sure the deferred queues don't get too long */ + defer_count = skb_queue_len(&cc->deferred_tx_queue); + defer_count += skb_queue_len(&cc->deferred_rx_queue); + if (defer_count >= CC33XX_RX_QUEUE_MAX_LEN) + cc33xx_flush_deferred_work(cc); + else + queue_work(cc->freezable_netstack_wq, &cc->netstack_work); + +out: + return (prev_buffer_len - *raw_buffer_len); +} + +static int cc33xx_rx_drop_packet_data(struct cc33xx *cc, u8 *raw_buffer_ptr, + u16 *raw_buffer_len) +{ + u16 prev_buffer_len = *raw_buffer_len; + + /* Can we drop the entire frame ? */ + if (*raw_buffer_len >= + (cc->partial_rx.original_bytes - cc->partial_rx.handled_bytes)) { + *raw_buffer_len -= cc->partial_rx.original_bytes - + cc->partial_rx.handled_bytes; + cc->partial_rx.handled_bytes = 0; + cc->partial_rx.status = CURR_RX_START; + } else { + cc->partial_rx.handled_bytes += *raw_buffer_len; + *raw_buffer_len = 0; + } + + return (prev_buffer_len - *raw_buffer_len); +} + +/* Handle single packet from the RX buffer. We don't have to be aligned to + * packet boundary (buffer may start \ end in the middle of packet) + */ +static void cc33xx_rx_handle_packet(struct cc33xx *cc, u8 *raw_buffer_ptr, + u16 *raw_buffer_len) +{ + struct cc33xx_rx_descriptor *desc; + u16 consumed_bytes; + + if (cc->partial_rx.status == CURR_RX_START) { + WARN_ON(*raw_buffer_len < 2); + desc = (struct cc33xx_rx_descriptor *)raw_buffer_ptr; + cc->partial_rx.original_bytes = le16_to_cpu(desc->length); + cc->partial_rx.handled_bytes = 0; + cc->partial_rx.status = CURR_RX_DESC; + + cc33xx_debug(DEBUG_RX, "rx frame. desc length 0x%x, alignment 0x%x, padding 0x%x", + desc->length, desc->header_alignment, desc->pad_len); + } + + /* start \ continue copy descriptor */ + if (cc->partial_rx.status == CURR_RX_DESC) { + consumed_bytes = cc33xx_rx_get_packet_descriptor(cc, + raw_buffer_ptr, + raw_buffer_len); + raw_buffer_ptr += consumed_bytes; + } + + /* Check if we are in the middle of dropped packet */ + if (unlikely(cc->partial_rx.status == CURR_RX_DROP)) { + consumed_bytes = cc33xx_rx_drop_packet_data(cc, raw_buffer_ptr, + raw_buffer_len); + raw_buffer_ptr += consumed_bytes; + } + + /* start \ continue copy descriptor */ + if (cc->partial_rx.status == CURR_RX_DATA) { + consumed_bytes = cc33xx_rx_get_packet_data(cc, raw_buffer_ptr, + raw_buffer_len); + raw_buffer_ptr += consumed_bytes; + } +} + +/* It is assumed that SDIO buffer was read prior to this function (data buffer + * is read along with the status). The RX function gets pointer to the RX data + * and its length. This buffer may contain unknown number of packets, separated + * by hif descriptor and 0-3 bytes padding if required. + * The last packet may be truncated in the middle, and should be saved for next + * iteration. + */ +int cc33xx_rx(struct cc33xx *cc, u8 *rx_buf_ptr, u16 rx_buf_len) +{ + u16 local_rx_buffer_len = rx_buf_len; + u16 pkt_offset = 0; + u16 consumed_bytes; + u16 prev_rx_buf_len; + + /* Split data into separate packets */ + while (local_rx_buffer_len > 0) { + cc33xx_debug(DEBUG_RX, "start loop. buffer length %d", + local_rx_buffer_len); + + /* the handle data call can only fail in memory-outage + * conditions, in that case the received frame will just + * be dropped. + */ + prev_rx_buf_len = local_rx_buffer_len; + cc33xx_rx_handle_packet(cc, rx_buf_ptr + pkt_offset, + &local_rx_buffer_len); + consumed_bytes = prev_rx_buf_len - local_rx_buffer_len; + + pkt_offset += consumed_bytes; + + cc33xx_debug(DEBUG_RX, "end rx loop. buffer length %d, packet counter %d, current packet status %d", + local_rx_buffer_len, cc->rx_counter, + cc->partial_rx.status); + } + + return 0; +} + +#ifdef CONFIG_PM +int cc33xx_rx_filter_enable(struct cc33xx *cc, int index, bool enable, + struct cc33xx_rx_filter *filter) +{ + int ret; + + if (!!test_bit(index, cc->rx_filter_enabled) == enable) { + cc33xx_warning("Request to enable an already enabled rx filter %d", + index); + return 0; + } + + ret = cc33xx_acx_set_rx_filter(cc, index, enable, filter); + + if (ret) { + cc33xx_error("Failed to %s rx data filter %d (err=%d)", + enable ? "enable" : "disable", index, ret); + return ret; + } + + if (enable) + __set_bit(index, cc->rx_filter_enabled); + else + __clear_bit(index, cc->rx_filter_enabled); + + return 0; +} + +int cc33xx_rx_filter_clear_all(struct cc33xx *cc) +{ + int i, ret = 0; + + for (i = 0; i < CC33XX_MAX_RX_FILTERS; i++) { + if (!test_bit(i, cc->rx_filter_enabled)) + continue; + ret = cc33xx_rx_filter_enable(cc, i, 0, NULL); + if (ret) + goto out; + } + +out: + return ret; +} +#else +int cc33xx_rx_filter_enable(struct cc33xx *cc, int index, bool enable, + struct cc33xx_rx_filter *filter) +{ + return 0; +} + +int cc33xx_rx_filter_clear_all(struct cc33xx *cc) { return 0; } +#endif /* CONFIG_PM */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/rx.h b/drivers/net/wireless/ti/cc33xx/rx.h --- a/drivers/net/wireless/ti/cc33xx/rx.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/rx.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __RX_H__ +#define __RX_H__ + +/* RX Descriptor flags: + * + * Bits 0-1 - band + * Bit 2 - STBC + * Bit 3 - A-MPDU + * Bit 4 - HT + * Bits 5-7 - encryption + */ +#define CC33XX_RX_DESC_BAND_MASK 0x03 +#define CC33XX_RX_DESC_ENCRYPT_MASK 0xE0 + +#define CC33XX_RX_DESC_BAND_BG 0x00 +#define CC33XX_RX_DESC_BAND_J 0x01 +#define CC33XX_RX_DESC_BAND_A 0x02 + +/* RX Descriptor status + * + * Bits 0-2 - error code + * Bits 3-5 - process_id tag (AP mode FW) + * Bits 6-7 - reserved + */ +enum { + CC33XX_RX_DESC_SUCCESS = 0x00, + CC33XX_RX_DESC_DECRYPT_FAIL = 0x01, + CC33XX_RX_DESC_MIC_FAIL = 0x02, + CC33XX_RX_DESC_STATUS_MASK = 0x07 +}; + +/* Account for the padding inserted by the FW in case of RX_ALIGNMENT + * or for fixing alignment in case the packet wasn't aligned. + */ +#define RX_BUF_ALIGN 2 + +/* Describes the alignment state of a Rx buffer */ +enum cc33xx_rx_buf_align { + CC33XX_RX_BUF_ALIGNED, + CC33XX_RX_BUF_UNALIGNED, + CC33XX_RX_BUF_PADDED, +}; + +enum cc33xx_rx_curr_status { + CURR_RX_START, + CURR_RX_DROP, + CURR_RX_DESC, + CURR_RX_DATA +}; + +struct cc33xx_rx_descriptor { + __le16 length; + u8 header_alignment; + u8 status; + __le32 timestamp; + + u8 flags; + u8 rate; + u8 channel; + s8 rssi; + u8 snr; + + u8 hlid; + u8 pad_len; + u8 frame_format; +} __packed; + +struct partial_rx_frame { + struct sk_buff *skb; + struct cc33xx_rx_descriptor desc; + u16 handled_bytes; + u16 original_bytes; /* including descriptor */ + enum cc33xx_rx_curr_status status; +}; + +int cc33xx_rx(struct cc33xx *cc, u8 *rx_buf_ptr, u16 rx_buf_len); +int cc33xx_rx_filter_enable(struct cc33xx *cc, int index, bool enable, + struct cc33xx_rx_filter *filter); +int cc33xx_rx_filter_clear_all(struct cc33xx *cc); + +#endif /* __RX_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/scan.c b/drivers/net/wireless/ti/cc33xx/scan.c --- a/drivers/net/wireless/ti/cc33xx/scan.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/scan.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,754 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include "cc33xx.h" +#include "debug.h" +#include "cmd.h" +#include "scan.h" +#include "tx.h" +#include "conf.h" + +static void cc33xx_adjust_channels(struct scan_param *scan_param, + struct cc33xx_scan_channels *cmd_channels, + enum scan_request_type scan_type) +{ + struct conn_scan_ch_info *ch_info_list; + struct conn_scan_dwell_info *dwell_info; + struct conn_scan_ch_params *channel; + struct conn_scan_ch_params *ch_params_list; + + u8 *passive; + u8 *dfs; + u8 *active; + int i, j; + u8 band; + + if (scan_type == SCAN_REQUEST_CONNECT_PERIODIC_SCAN) { + ch_info_list = scan_param->u.periodic.channel_list; + dwell_info = scan_param->u.periodic.dwell_info; + active = (u8 *)&scan_param->u.periodic.active; + passive = (u8 *)&scan_param->u.periodic.passive; + dfs = (u8 *)&scan_param->u.periodic.dfs; + } else { + ch_info_list = scan_param->u.one_shot.channel_list; + dwell_info = scan_param->u.one_shot.dwell_info; + active = (u8 *)&scan_param->u.one_shot.active; + passive = (u8 *)&scan_param->u.one_shot.passive; + dfs = (u8 *)&scan_param->u.one_shot.dfs; + } + + memcpy(passive, cmd_channels->passive, sizeof(cmd_channels->passive)); + memcpy(active, cmd_channels->active, sizeof(cmd_channels->active)); + *dfs = cmd_channels->dfs; + + ch_params_list = cmd_channels->channels_2; + for (i = 0; i < MAX_CHANNELS_2GHZ; ++i) { + ch_info_list[i].channel = ch_params_list[i].channel; + ch_info_list[i].flags = ch_params_list[i].flags; + ch_info_list[i].tx_power_att = ch_params_list[i].tx_power_att; + } + + channel = &ch_params_list[0]; + band = NL80211_BAND_2GHZ; + dwell_info[band].min_duration = channel->min_duration; + dwell_info[band].max_duration = channel->max_duration; + dwell_info[band].passive_duration = channel->passive_duration; + + ch_params_list = cmd_channels->channels_5; + for (j = 0; j < MAX_CHANNELS_5GHZ; ++i, ++j) { + ch_info_list[i].channel = ch_params_list[j].channel; + ch_info_list[i].flags = ch_params_list[j].flags; + ch_info_list[i].tx_power_att = ch_params_list[j].tx_power_att; + } + + channel = &ch_params_list[0]; + band = NL80211_BAND_5GHZ; + dwell_info[band].min_duration = channel->min_duration; + dwell_info[band].max_duration = channel->max_duration; + dwell_info[band].passive_duration = channel->passive_duration; +} + +static int cc33xx_cmd_build_probe_req(struct cc33xx *cc, + struct cc33xx_vif *wlvif, u8 role_id, + u8 scan_type, const u8 *ssid, + size_t ssid_len, const u8 *ie0, + size_t ie0_len, const u8 *ie1, + size_t ie1_len, bool sched_scan) +{ + struct ieee80211_vif *vif = cc33xx_wlvif_to_vif(wlvif); + struct sk_buff *skb = NULL; + struct cc33xx_cmd_set_ies *cmd; + int ret; + + cc33xx_debug(DEBUG_SCAN, "build probe request scan_type %d", scan_type); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + skb = ieee80211_probereq_get(cc->hw, vif->addr, ssid, + ssid_len, ie0_len + ie1_len); + if (!skb) { + ret = -ENOMEM; + goto out_free; + } + + if (ie0_len) + skb_put_data(skb, ie0, ie0_len); + + if (ie1_len) + skb_put_data(skb, ie1, ie1_len); + + cmd->scan_type = scan_type; + cmd->role_id = role_id; + + cmd->len = cpu_to_le16(skb->len - sizeof(struct ieee80211_hdr_3addr)); + + if (skb->data) { + memcpy(cmd->data, + skb->data + sizeof(struct ieee80211_hdr_3addr), le16_to_cpu(cmd->len)); + } + + usleep_range(10000, 11000); + ret = cc33xx_cmd_send(cc, CMD_SET_PROBE_IE, cmd, sizeof(*cmd), 0); + + if (ret < 0) { + cc33xx_warning("cmd set_template failed: %d", ret); + goto out_free; + } + +out_free: + dev_kfree_skb(skb); + kfree(cmd); +out: + return ret; +} + +static void cc33xx_started_vifs_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + bool active = false; + int *count = (int *)data; + + /* count active interfaces according to interface type. + * checking only bss_conf.idle is bad for some cases, e.g. + * we don't want to count sta in p2p_find as active interface. + */ + switch (wlvif->bss_type) { + case BSS_TYPE_STA_BSS: + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + active = true; + break; + + case BSS_TYPE_AP_BSS: + if (wlvif->cc->active_sta_count > 0) + active = true; + break; + + default: + break; + } + + if (active) + (*count)++; +} + +static int cc33xx_count_started_vifs(struct cc33xx *cc) +{ + int count = 0; + + ieee80211_iterate_active_interfaces_atomic(cc->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + cc33xx_started_vifs_iter, + &count); + return count; +} + +static int cc33xx_scan_get_channels(struct cc33xx *cc, + struct ieee80211_channel *req_channels[], + u32 n_channels, u32 n_ssids, + struct conn_scan_ch_params *channels, + u32 band, bool radar, bool passive, + unsigned int start, unsigned int max_channels, + u8 *n_pactive_ch, int scan_type) +{ + unsigned int i, j; + u32 flags; + bool force_passive = !n_ssids; + u32 min_dwell_time_active, max_dwell_time_active; + u32 dwell_time_passive, dwell_time_dfs; + struct conn_scan_ch_params *ch; + struct ieee80211_channel *req_ch; + + /* configure dwell times according to scan type */ + if (scan_type == SCAN_TYPE_SEARCH) { + struct conf_scan_settings *c = &cc->conf.host_conf.scan; + bool active_vif_exists = !!cc33xx_count_started_vifs(cc); + + min_dwell_time_active = active_vif_exists ? + c->min_dwell_time_active : + c->min_dwell_time_active_long; + max_dwell_time_active = active_vif_exists ? + c->max_dwell_time_active : + c->max_dwell_time_active_long; + dwell_time_passive = c->dwell_time_passive; + dwell_time_dfs = c->dwell_time_dfs; + } else { + struct conf_sched_scan_settings *c = + &cc->conf.host_conf.sched_scan; + u32 delta_per_probe; + + delta_per_probe = (band == NL80211_BAND_5GHZ) ? + c->dwell_time_delta_per_probe_5 : + c->dwell_time_delta_per_probe; + + min_dwell_time_active = c->base_dwell_time + + n_ssids * c->num_probe_reqs * delta_per_probe; + + max_dwell_time_active = min_dwell_time_active; + max_dwell_time_active += c->max_dwell_time_delta; + dwell_time_passive = c->dwell_time_passive; + dwell_time_dfs = c->dwell_time_dfs; + } + + min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000); + max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000); + dwell_time_passive = DIV_ROUND_UP(dwell_time_passive, 1000); + dwell_time_dfs = DIV_ROUND_UP(dwell_time_dfs, 1000); + + for (i = 0, j = start; i < n_channels && j < max_channels; i++) { + flags = req_channels[i]->flags; + ch = &channels[j]; + req_ch = req_channels[i]; + + if (force_passive) + flags |= IEEE80211_CHAN_NO_IR; + + if (req_ch->band == band && !(flags & IEEE80211_CHAN_DISABLED) && + (!!(flags & IEEE80211_CHAN_RADAR) == radar) && + /* if radar is set, we ignore the passive flag */ + (radar || !!(flags & IEEE80211_CHAN_NO_IR) == passive)) { + if (flags & IEEE80211_CHAN_RADAR) { + ch->flags |= SCAN_CHANNEL_FLAGS_DFS; + + ch->passive_duration = + cpu_to_le16(dwell_time_dfs); + } else { + ch->passive_duration = + cpu_to_le16(dwell_time_passive); + } + + ch->min_duration = cpu_to_le16(min_dwell_time_active); + ch->max_duration = cpu_to_le16(max_dwell_time_active); + + ch->tx_power_att = req_ch->max_power; + ch->channel = req_ch->hw_value; + + if (n_pactive_ch && band == NL80211_BAND_2GHZ && + ch->channel >= 12 && ch->channel <= 14 && + (flags & IEEE80211_CHAN_NO_IR) && !force_passive) { + /* pactive channels treated as DFS */ + ch->flags = SCAN_CHANNEL_FLAGS_DFS; + + /* n_pactive_ch is counted down from the end of + * the passive channel list + */ + (*n_pactive_ch)++; + cc33xx_debug(DEBUG_SCAN, "n_pactive_ch = %d", + *n_pactive_ch); + } + + cc33xx_debug(DEBUG_SCAN, "freq %d, ch. %d, flags 0x%x, power %d, min/max_dwell %d/%d%s%s", + req_ch->center_freq, req_ch->hw_value, + req_ch->flags, req_ch->max_power, + min_dwell_time_active, + max_dwell_time_active, + flags & IEEE80211_CHAN_RADAR ? ", DFS" : "", + flags & IEEE80211_CHAN_NO_IR ? ", NO-IR" : ""); + j++; + } + } + + return j - start; +} + +static bool cc33xx_set_scan_chan_params(struct cc33xx *cc, + struct cc33xx_scan_channels *cfg, + struct ieee80211_channel *channels[], + u32 n_channels, u32 n_ssids, + int scan_type) +{ + u8 n_pactive_ch = 0; + + cfg->passive[0] = cc33xx_scan_get_channels(cc, channels, n_channels, + n_ssids, cfg->channels_2, + NL80211_BAND_2GHZ, false, + true, 0, MAX_CHANNELS_2GHZ, + &n_pactive_ch, scan_type); + + cfg->active[0] = cc33xx_scan_get_channels(cc, channels, n_channels, + n_ssids, cfg->channels_2, + NL80211_BAND_2GHZ, false, + false, cfg->passive[0], + MAX_CHANNELS_2GHZ, + &n_pactive_ch, scan_type); + + cfg->passive[1] = cc33xx_scan_get_channels(cc, channels, n_channels, + n_ssids, cfg->channels_5, + NL80211_BAND_5GHZ, false, + true, 0, MAX_CHANNELS_5GHZ, + &n_pactive_ch, scan_type); + + cfg->dfs = cc33xx_scan_get_channels(cc, channels, n_channels, n_ssids, + cfg->channels_5, NL80211_BAND_5GHZ, + true, true, cfg->passive[1], + MAX_CHANNELS_5GHZ, &n_pactive_ch, + scan_type); + + cfg->active[1] = cc33xx_scan_get_channels(cc, channels, n_channels, + n_ssids, cfg->channels_5, + NL80211_BAND_5GHZ, false, + false, + cfg->passive[1] + cfg->dfs, + MAX_CHANNELS_5GHZ, + &n_pactive_ch, scan_type); + + /* 802.11j channels are not supported yet */ + cfg->passive[2] = 0; + cfg->active[2] = 0; + + cfg->passive_active = n_pactive_ch; + + cc33xx_debug(DEBUG_SCAN, "2.4GHz: active %d passive %d", + cfg->active[0], cfg->passive[0]); + cc33xx_debug(DEBUG_SCAN, "5GHz: active %d passive %d", + cfg->active[1], cfg->passive[1]); + cc33xx_debug(DEBUG_SCAN, "DFS: %d", cfg->dfs); + + return cfg->passive[0] || cfg->active[0] || cfg->passive[1] || + cfg->active[1] || cfg->dfs || cfg->passive[2] || cfg->active[2]; +} + +static int cc33xx_scan_send(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct cfg80211_scan_request *req) +{ + struct cc33xx_cmd_scan_params *cmd; + struct cc33xx_scan_channels *cmd_channels = NULL; + struct cc33xx_ssid *cmd_ssid; + u16 alloc_size; + int ret; + int i; + + alloc_size = sizeof(*cmd) + (sizeof(struct cc33xx_ssid) * req->n_ssids); + cmd = kzalloc(alloc_size, GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + /* scan on the dev role if the regular one is not started */ + if (cc33xx_is_p2p_mgmt(wlvif)) + cmd->role_id = wlvif->dev_role_id; + else + cmd->role_id = wlvif->role_id; + + if (WARN_ON(cmd->role_id == CC33XX_INVALID_ROLE_ID)) { + ret = -EINVAL; + goto out; + } + + cmd->scan_type = SCAN_REQUEST_ONE_SHOT; + cmd->rssi_threshold = -127; + cmd->snr_threshold = 0; + + for (i = 0; i < ETH_ALEN; i++) + cmd->bssid[i] = req->bssid[i]; + cmd->ssid_from_list = 0; + cmd->filter = 0; + WARN_ON(req->n_ssids > 1); + + /* configure channels */ + cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL); + if (!cmd_channels) { + ret = -ENOMEM; + goto out; + } + + cc33xx_set_scan_chan_params(cc, cmd_channels, req->channels, + req->n_channels, req->n_ssids, + SCAN_TYPE_SEARCH); + + cc33xx_adjust_channels(&cmd->params, cmd_channels, cmd->scan_type); + if (req->n_ssids > 0) { + cmd->ssid_from_list = 1; + cmd->num_of_ssids = req->n_ssids; + cmd_ssid = (struct cc33xx_ssid *)((u8 *)cmd + sizeof(*cmd)); + + cmd_ssid->len = req->ssids[0].ssid_len; + memcpy(cmd_ssid->ssid, req->ssids[0].ssid, cmd_ssid->len); + cmd_ssid->type = (req->ssids[0].ssid_len) ? + SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC; + } + + ret = cc33xx_cmd_build_probe_req(cc, wlvif, cmd->role_id, cmd->scan_type, + req->ssids ? req->ssids[0].ssid : NULL, + req->ssids ? req->ssids[0].ssid_len : 0, + req->ie, req->ie_len, NULL, 0, false); + if (ret < 0) { + cc33xx_error("PROBE request template failed"); + goto out; + } + + cc33xx_dump(DEBUG_SCAN, "SCAN: ", cmd, alloc_size); + + ret = cc33xx_cmd_send(cc, CMD_SCAN, cmd, alloc_size, 0); + if (ret < 0) { + cc33xx_error("SCAN failed"); + goto out; + } + +out: + kfree(cmd_channels); + kfree(cmd); + return ret; +} + +static int cc33xx_scan_sched_scan_ssid_list(struct cc33xx *cc, + struct cc33xx_vif *wlvif, + struct cfg80211_sched_scan_request *req, + struct cc33xx_cmd_ssid_list *cmd) +{ + struct cfg80211_match_set *sets = req->match_sets; + struct cfg80211_ssid *ssids = req->ssids; + int ret = 0, i, j, n_match_ssids = 0; + + cc33xx_debug((DEBUG_CMD | DEBUG_SCAN), "cmd sched scan ssid list"); + /* count the match sets that contain SSIDs */ + for (i = 0; i < req->n_match_sets; i++) { + if (sets[i].ssid.ssid_len > 0) + n_match_ssids++; + } + + /* No filter, no ssids or only bcast ssid */ + if (!n_match_ssids && (!req->n_ssids || + (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) + goto out; + + cmd->role_id = wlvif->role_id; + if (!n_match_ssids) { + /* No filter, with ssids */ + + for (i = 0; i < req->n_ssids; i++) { + cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ? + SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC; + cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len; + memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid, + ssids[i].ssid_len); + cmd->n_ssids++; + } + } else { + /* Add all SSIDs from the filters */ + for (i = 0; i < req->n_match_sets; i++) { + /* ignore sets without SSIDs */ + if (!sets[i].ssid.ssid_len) + continue; + + cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; + cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len; + memcpy(cmd->ssids[cmd->n_ssids].ssid, + sets[i].ssid.ssid, sets[i].ssid.ssid_len); + cmd->n_ssids++; + } + if (req->n_ssids > 1 || (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) { + /* Mark all the SSIDs passed in the SSID list as HIDDEN, + * so they're used in probe requests. + */ + for (i = 0; i < req->n_ssids; i++) { + if (!req->ssids[i].ssid_len) + continue; + + for (j = 0; j < cmd->n_ssids; j++) { + if (req->ssids[i].ssid_len == cmd->ssids[j].len && + !memcmp(req->ssids[i].ssid, + cmd->ssids[j].ssid, + req->ssids[i].ssid_len)) { + cmd->ssids[j].type = + SCAN_SSID_TYPE_HIDDEN; + break; + } + } + /* Fail if SSID isn't present in the filters */ + if (j == cmd->n_ssids) { + ret = -EINVAL; + goto out; + } + } + } + } + + cc33xx_debug(DEBUG_CMD, "cmd sched scan with ssid list %d", + cmd->n_ssids); + return cmd->n_ssids; +out: + if (ret < 0) + return ret; + + return 0; +} + +int cc33xx_sched_scan_start(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_scan_ies *ies) +{ + struct cc33xx_cmd_scan_params *cmd; + struct cc33xx_cmd_ssid_list *ssid_list; + struct cc33xx_scan_channels *cmd_channels = NULL; + struct conf_sched_scan_settings *c = &cc->conf.host_conf.sched_scan; + int ret; + int n_ssids = 0; + int alloc_size = sizeof(*cmd); + + cc33xx_debug(DEBUG_CMD, "cmd sched_scan scan config"); + + ssid_list = kzalloc(sizeof(*ssid_list), GFP_KERNEL); + if (!ssid_list) { + ret = -ENOMEM; + goto out_ssid_free; + } + + n_ssids = cc33xx_scan_sched_scan_ssid_list(cc, wlvif, req, ssid_list); + if (n_ssids < 0) + return n_ssids; + + cc33xx_debug(DEBUG_CMD, "ssid list num of ssids %d", ssid_list->n_ssids); + + if (n_ssids <= 5) { + alloc_size += (n_ssids * sizeof(struct cc33xx_ssid)); + } else { /* n_ssids > 5 */ + ssid_list->scan_type = SCAN_REQUEST_CONNECT_PERIODIC_SCAN; + ret = cc33xx_cmd_send(cc, CMD_CONNECTION_SCAN_SSID_CFG, + ssid_list, sizeof(*ssid_list), 0); + if (ret < 0) { + cc33xx_error("cmd sched scan ssid list failed"); + goto out_ssid_free; + } + } + + cmd = kzalloc(alloc_size, GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out_free; + } + + cmd->role_id = wlvif->role_id; + + if (WARN_ON(cmd->role_id == CC33XX_INVALID_ROLE_ID)) { + ret = -EINVAL; + goto out_free; + } + + cmd->scan_type = SCAN_REQUEST_CONNECT_PERIODIC_SCAN; + cmd->rssi_threshold = c->rssi_threshold; + cmd->snr_threshold = c->snr_threshold; + + cmd->filter = 1; + cmd->num_of_ssids = n_ssids; + + cc33xx_debug(DEBUG_CMD, "ssid list num of n_ssids %d", n_ssids); + if (n_ssids > 0 && n_ssids <= 5) { + cmd->ssid_from_list = 1; + memcpy((u8 *)cmd + sizeof(*cmd), ssid_list->ssids, + n_ssids * sizeof(struct cc33xx_ssid)); + } + + cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL); + if (!cmd_channels) { + ret = -ENOMEM; + goto out_free; + } + + /* configure channels */ + cc33xx_set_scan_chan_params(cc, cmd_channels, req->channels, + req->n_channels, req->n_ssids, + SCAN_TYPE_PERIODIC); + cc33xx_adjust_channels(&cmd->params, cmd_channels, cmd->scan_type); + + memcpy(cmd->params.u.periodic.sched_scan_plans, req->scan_plans, + sizeof(struct sched_scan_plan_cmd) * req->n_scan_plans); + + cmd->params.u.periodic.sched_scan_plans_num = req->n_scan_plans; + + cc33xx_debug(DEBUG_SCAN, + "interval[0]: %d, iterations[0]: %d, num_plans: %d", + cmd->params.u.periodic.sched_scan_plans[0].interval, + cmd->params.u.periodic.sched_scan_plans[0].iterations, + cmd->params.u.periodic.sched_scan_plans_num); + + ret = cc33xx_cmd_build_probe_req(cc, wlvif, cmd->role_id, cmd->scan_type, + req->ssids ? req->ssids[0].ssid : NULL, + req->ssids ? req->ssids[0].ssid_len : 0, + ies->ies[NL80211_BAND_2GHZ], + ies->len[NL80211_BAND_2GHZ], + ies->common_ies, + ies->common_ie_len, true); + + if (ret < 0) { + cc33xx_error("PROBE request template failed"); + goto out_free; + } + + cc33xx_dump(DEBUG_SCAN, "SCAN: ", cmd, alloc_size); + + ret = cc33xx_cmd_send(cc, CMD_SCAN, cmd, alloc_size, 0); + if (ret < 0) { + cc33xx_error("SCAN failed"); + goto out_free; + } + +out_free: + kfree(cmd_channels); + kfree(cmd); + +out_ssid_free: + kfree(ssid_list); + + return ret; +} + +static int __cc33xx_scan_stop(struct cc33xx *cc, + struct cc33xx_vif *wlvif, u8 scan_type) +{ + struct cc33xx_cmd_scan_stop *stop; + int ret; + + cc33xx_debug(DEBUG_CMD, "cmd periodic scan stop"); + + stop = kzalloc(sizeof(*stop), GFP_KERNEL); + if (!stop) + return -ENOMEM; + + stop->role_id = wlvif->role_id; + stop->scan_type = scan_type; + + ret = cc33xx_cmd_send(cc, CMD_STOP_SCAN, stop, sizeof(*stop), 0); + if (ret < 0) { + cc33xx_error("failed to send sched scan stop command"); + goto out_free; + } + +out_free: + kfree(stop); + return ret; +} + +void cc33xx_scan_sched_scan_stop(struct cc33xx *cc, + struct cc33xx_vif *wlvif) +{ + __cc33xx_scan_stop(cc, wlvif, SCAN_REQUEST_CONNECT_PERIODIC_SCAN); +} + +static int cc33xx_scan_start(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct cfg80211_scan_request *req) +{ + return cc33xx_scan_send(cc, wlvif, req); +} + +int cc33xx_scan_stop(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + return __cc33xx_scan_stop(cc, wlvif, SCAN_REQUEST_ONE_SHOT); +} + +void cc33xx_scan_complete_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct cc33xx *cc; + struct cfg80211_scan_info info = { + .aborted = false, + }; + + dwork = to_delayed_work(work); + cc = container_of(dwork, struct cc33xx, scan_complete_work); + + cc33xx_debug(DEBUG_SCAN, "Scanning complete"); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) + goto out; + + if (cc->scan.state == CC33XX_SCAN_STATE_IDLE) + goto out; + + /* Rearm the tx watchdog just before idling scan. This + * prevents just-finished scans from triggering the watchdog + */ + cc33xx_rearm_tx_watchdog_locked(cc); + + cc->scan.state = CC33XX_SCAN_STATE_IDLE; + memset(cc->scan.scanned_ch, 0, sizeof(cc->scan.scanned_ch)); + cc->scan.req = NULL; + cc->scan_wlvif = NULL; + + if (cc->scan.failed) { + cc33xx_info("Scan completed due to error."); + cc33xx_queue_recovery_work(cc); + } + + cc33xx_cmd_regdomain_config_locked(cc); + + ieee80211_scan_completed(cc->hw, &info); + +out: + mutex_unlock(&cc->mutex); +} + +int cc33xx_scan(struct cc33xx *cc, struct ieee80211_vif *vif, const u8 *ssid, + size_t ssid_len, struct cfg80211_scan_request *req) +{ + struct cc33xx_vif *wlvif = cc33xx_vif_to_data(vif); + + if (cc->scan.state != CC33XX_SCAN_STATE_IDLE) + return -EBUSY; + + cc->scan.state = CC33XX_SCAN_STATE_2GHZ_ACTIVE; + + if (ssid_len && ssid) { + cc->scan.ssid_len = ssid_len; + memcpy(cc->scan.ssid, ssid, ssid_len); + } else { + cc->scan.ssid_len = 0; + } + + cc->scan_wlvif = wlvif; + cc->scan.req = req; + memset(cc->scan.scanned_ch, 0, sizeof(cc->scan.scanned_ch)); + + /* we assume failure so that timeout scenarios are handled correctly */ + cc->scan.failed = true; + ieee80211_queue_delayed_work(cc->hw, &cc->scan_complete_work, + msecs_to_jiffies(CC33XX_SCAN_TIMEOUT)); + + cc33xx_scan_start(cc, wlvif, req); + + return 0; +} + +inline void cc33xx_scan_sched_scan_results(struct cc33xx *cc) +{ + cc33xx_debug(DEBUG_SCAN, "got periodic scan results"); + + ieee80211_sched_scan_results(cc->hw); +} + +void cc33xx_scan_completed(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + cc->scan.failed = false; + cancel_delayed_work(&cc->scan_complete_work); + ieee80211_queue_delayed_work(cc->hw, &cc->scan_complete_work, + msecs_to_jiffies(0)); +} diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/scan.h b/drivers/net/wireless/ti/cc33xx/scan.h --- a/drivers/net/wireless/ti/cc33xx/scan.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/scan.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,364 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __SCAN_H__ +#define __SCAN_H__ + +#include "cc33xx.h" + +#define CC33XX_SCAN_TIMEOUT 30000 /* msec */ + +enum { + CC33XX_SCAN_STATE_IDLE, + CC33XX_SCAN_STATE_2GHZ_ACTIVE, + CC33XX_SCAN_STATE_2GHZ_PASSIVE, + CC33XX_SCAN_STATE_5GHZ_ACTIVE, + CC33XX_SCAN_STATE_5GHZ_PASSIVE, + CC33XX_SCAN_STATE_DONE +}; + +struct conn_scan_ch_params { + __le16 min_duration; + __le16 max_duration; + __le16 passive_duration; + + u8 channel; + u8 tx_power_att; + + /* bit 0: DFS channel; bit 1: DFS enabled */ + u8 flags; + + u8 padding[3]; +} __packed; + +enum { + SCAN_SSID_TYPE_PUBLIC = 0, + SCAN_SSID_TYPE_HIDDEN = 1, +}; + +#define MAX_CHANNELS_2GHZ 14 +#define MAX_CHANNELS_4GHZ 4 +#define MAX_CHANNELS_5GHZ 32 + +#define SCAN_MAX_CYCLE_INTERVALS 16 +#define SCAN_MAX_BANDS 3 +#define SCHED_SCAN_MAX_SSIDS 16 + +/****************************************************************************** + * ** *** *** ** * + * ** *** SCAN API *** ** * + * ** *** *** ** * + ******************************************************************************/ + +#define CONN_SCAN_MAX_BAND (2) +#define CONN_SCAN_MAX_CHANNELS_ALL_BANDS (46) +#define SCAN_MAX_SCHED_SCAN_PLANS (12) + +enum scan_request_type { + SCAN_REQUEST_NONE, + SCAN_REQUEST_CONNECT_PERIODIC_SCAN, + SCAN_REQUEST_ONE_SHOT, + SCAN_REQUEST_SURVEY_SCAN, + SCAN_NUM_OF_REQUEST_TYPE +}; + +/****************************************************************************** + * ID: CMD_SCAN + * Desc: This command will start scan process depending scan request + * type + * Return: CMD_COMPLETE + *****************************************************************************/ +/* struct cc33xx_ssid - SSIDs connection scan description + * + * @type: SSID type - SCAN_SSID_TYPE_HIDDEN/SCAN_SSID_TYPE_PUBLIC + * + * @len: Length of the ssid + * + * @ssid: SSID + */ +struct cc33xx_ssid { + u8 type; + u8 len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 padding[2]; +} __packed; + +/** + * struct cc33xx_cmd_ssid_list - scan SSID list description + * + * @role_id: roleID + * + * @num_of_ssids: Number of SSID in the list. MAX 16 entries + * + * @ssid_list: SSIDs to scan for (active scan only) + */ +struct cc33xx_cmd_ssid_list { + struct cc33xx_cmd_header header; + + u8 role_id; + u8 scan_type; + u8 n_ssids; + struct cc33xx_ssid ssids[SCHED_SCAN_MAX_SSIDS]; + u8 padding; +} __packed; + +/** + * struct conn_scan_dwell_info - Channels duration info per band + * + * @min_duration: Min duration (in ms) + * + * @max_duration: Max duration (in ms) + * + * @passive_duration: Duration to use for passive scans (in ms) + */ +struct conn_scan_dwell_info { + __le16 min_duration; + __le16 max_duration; + __le16 passive_duration; +} __packed; + +/** + * struct conn_scan_ch_info - Channels info + * + * @channel: channel number (channel_e) + * + * @tx_power_att: TX power level in dbm + * + * @flags: 0 - DFS channel, 1 - DFS enabled (to be included in active scan) + */ +struct conn_scan_ch_info { + u8 channel; + u8 tx_power_att; + u8 flags; +} __packed; + +/** + * struct scan_one_shot_info - ONE_SHOT scan param + * + * @passive: Number of passive scan channels in bands BG,A + * + * @active: Number of active scan channels in bands BG,A + * + * @dfs: Number of DFS channels in A band + * + * @channel_list: Channel list info + * BG band channels are set from place 0 and forward. + * A band channels are from CONN_SCAN_MAX_CHANNELS_BG and forward. + * 6Ghz band channels are from CONN_SCAN_MAX_CHANNELS_A_BG and forward. + + * @dwell_info: Scan duration time info per band + * + * @reserved: + * + */ +struct scan_one_shot_info { + u8 passive[CONN_SCAN_MAX_BAND]; + u8 active[CONN_SCAN_MAX_BAND]; + u8 dfs; + + struct conn_scan_ch_info channel_list[CONN_SCAN_MAX_CHANNELS_ALL_BANDS]; + struct conn_scan_dwell_info dwell_info[CONN_SCAN_MAX_BAND]; + u8 reserved; +}; + +/** + * sched_scan_plans - Scan plans for scheduled scan + * + * Each scan plan consists of the number of iterations to scan and the + * interval between scans. When a scan plan finishes (i.e., it was run + * for the specified number of iterations), the next scan plan is + * executed. The scan plans are executed in the order they appear in + * the array (lower index first). The last scan plan will run infinitely + * (until requested to stop), thus must not specify the number of + * iterations. All other scan plans must specify the number of + * iterations. + */ +struct sched_scan_plan_cmd { + u32 interval; /* In seconds */ + u32 iterations; /* Zero to run infinitely */ +}; + +/* struct periodicScanParams_t - Periodic scan param + * + * @sched_scan_plans: Scan plans for a scheduled scan (defined in supplicant's driver.h) + * interval and iterations + * + * @sched_scan_plans_num:Number of scan plans in sched_scan_plans array + * + * @passive: Number of passive scan channels in bands BG,A + * + * @active: Number of active scan channels in bands BG,A + * + * @dfs: number of DFS channels in A band + * + * @channel_list: Channel list info. + * BG band channels are set from place 0 and forward. + * A band channels are set from CONN_SCAN_MAX_CHANNELS_BG and forward. + * 6Ghz band are set from CONN_SCAN_MAX_CHANNELS_A_BG and forward. + * + * @dwell_info: Scan duration time info per band + * + */ +struct scan_periodic_info { + struct sched_scan_plan_cmd sched_scan_plans[SCAN_MAX_SCHED_SCAN_PLANS]; + u16 sched_scan_plans_num; + + u8 passive[CONN_SCAN_MAX_BAND]; + u8 active[CONN_SCAN_MAX_BAND]; + u8 dfs; + + struct conn_scan_ch_info channel_list[CONN_SCAN_MAX_CHANNELS_ALL_BANDS]; + struct conn_scan_dwell_info dwell_info[CONN_SCAN_MAX_BAND]; +} __packed; + +/** + * struct scan_param - union for ONE_SHOT/PERIODIC scan param + * + * @one_shot: ONE_SHOT scan param + * + * @periodic: Periodic scan param + */ +struct scan_param { + union { + struct scan_one_shot_info one_shot; + struct scan_periodic_info periodic; + } u; +} __packed; + +/** + * struct cc33xx_cmd_scan_params - scan configured param + * + * @scan_type: ONE_SHOT/PERIODIC scan + * + * @role_id: role ID + * + * @params: Scan parameter for ONE_SHOT/PERIODIC Scan + * + * @rssi_threshold: RSSI threshold for basic filter + * + * @snr_threshold: SNR threshold for basic filter + * + * @bssid: BSSID to scan for + * + * @ssid_from_list: 0 - if there are more than 5 SSIDs entries + * (list was sent SSID CONFIGURE COMMAND), + * 1 - 5 or less SSIDs entries, the list is at the end of the scan command + * + * @filter: 0 - not using filter and all the beacons/probe response frame + * forward to upper mac, 1 - using filter + * + * @num_of_ssids: Number of SSIDs + */ +struct cc33xx_cmd_scan_params { + struct cc33xx_cmd_header header; + u8 scan_type; + u8 role_id; + + struct scan_param params; + s8 rssi_threshold; /* for filtering (in dBm) */ + s8 snr_threshold; /* for filtering (in dB) */ + + u8 bssid[ETH_ALEN]; + u8 padding[2]; + + u8 ssid_from_list; /* use ssid from configured ssid list */ + u8 filter; /* forward only results with matching ssids */ + + u8 num_of_ssids; +} __packed; + +/****************************************************************************** + * ID: CMD_SET_PROBE_IE + * Desc: This command will set the Info elements data for + * probe request + * Return: CMD_COMPLETE + *******************************************************************************/ +#define MAX_EXTRA_IES_LEN 512 +/** + * struct cc33xx_cmd_set_ies - Probe request info elements + * + * @scan_type: ONE_SHOT/PERIODIC scan + * + * @role_id: roleID + * + * @data: info element buffer + * + * @len: info element length + */ +struct cc33xx_cmd_set_ies { + struct cc33xx_cmd_header header; + u8 scan_type; + u8 role_id; + __le16 len; + u8 data[MAX_EXTRA_IES_LEN]; +} __packed; + +/****************************************************************************** + * ID: CMD_STOP_SCAN + * Desc: This command will stop scan process depending scan request + * type, and if early termination is on + * Return: CMD_COMPLETE + ******************************************************************************/ +/** + * struct cc33xx_cmd_scan_stop - scan stop param + * + * @scan_type: Scan request type + * + * @role_id: role ID + * + * @is_ET: TRUE - Early termination is on, FALSE - no ET + */ +struct cc33xx_cmd_scan_stop { + struct cc33xx_cmd_header header; + + u8 scan_type; + u8 role_id; + u8 is_ET; + u8 padding; +} __packed; + +int cc33xx_scan_stop(struct cc33xx *cc, struct cc33xx_vif *wlvif); +void cc33xx_scan_completed(struct cc33xx *cc, struct cc33xx_vif *wlvif); +int cc33xx_sched_scan_start(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_scan_ies *ies); +void cc33xx_scan_sched_scan_stop(struct cc33xx *cc, struct cc33xx_vif *wlvif); + +int cc33xx_scan(struct cc33xx *cc, struct ieee80211_vif *vif, + const u8 *ssid, size_t ssid_len, + struct cfg80211_scan_request *req); +void cc33xx_scan_complete_work(struct work_struct *work); +void cc33xx_scan_sched_scan_results(struct cc33xx *cc); + +enum { + SCAN_SSID_FILTER_ANY = 0, + SCAN_SSID_FILTER_SPECIFIC = 1, + SCAN_SSID_FILTER_LIST = 2, + SCAN_SSID_FILTER_DISABLED = 3 +}; + +#define SCAN_CHANNEL_FLAGS_DFS BIT(0) /* channel is passive until an + * activity is detected on it + */ +#define SCAN_CHANNEL_FLAGS_DFS_ENABLED BIT(1) + +struct cc33xx_scan_channels { + u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */ + u8 active[SCAN_MAX_BANDS]; /* number of active scan channels */ + u8 dfs; /* number of dfs channels in 5ghz */ + u8 passive_active; /* number of passive before active channels 2.4ghz */ + + struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; + struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ]; + struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; +}; + +enum { + SCAN_TYPE_SEARCH = 0, + SCAN_TYPE_PERIODIC = 1, + SCAN_TYPE_TRACKING = 2, +}; + +#endif /* __CC33XX_SCAN_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/sdio.c b/drivers/net/wireless/ti/cc33xx/sdio.c --- a/drivers/net/wireless/ti/cc33xx/sdio.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/sdio.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,584 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include +#include +#include +#include +#include + +#include "cc33xx.h" +#include "io.h" + +#ifndef SDIO_VENDOR_ID_TI +#define SDIO_VENDOR_ID_TI 0x0097 +#endif + +#define SDIO_DEVICE_ID_CC33XX_NO_EFUSE 0x4076 +#define SDIO_DEVICE_ID_TI_CC33XX 0x4077 + +static bool dump; + +struct cc33xx_sdio_glue { + struct device *dev; + struct platform_device *core; +}; + +static const struct sdio_device_id cc33xx_devices[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_CC33XX) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_CC33XX_NO_EFUSE) }, + {} +}; +MODULE_DEVICE_TABLE(sdio, cc33xx_devices); + +static void cc33xx_sdio_claim(struct device *child) +{ + struct cc33xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct sdio_func *func = dev_to_sdio_func(glue->dev); + + sdio_claim_host(func); +} + +static void cc33xx_sdio_release(struct device *child) +{ + struct cc33xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct sdio_func *func = dev_to_sdio_func(glue->dev); + + sdio_release_host(func); +} + +static void cc33xx_sdio_set_block_size(struct device *child, + unsigned int blksz) +{ + struct cc33xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct sdio_func *func = dev_to_sdio_func(glue->dev); + + sdio_claim_host(func); + sdio_set_block_size(func, blksz); + sdio_release_host(func); +} + +static int __must_check cc33xx_sdio_raw_read(struct device *child, int addr, + void *buf, size_t len, bool fixed) +{ + int ret; + struct cc33xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct sdio_func *func = dev_to_sdio_func(glue->dev); + + sdio_claim_host(func); + + if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) { + ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); + dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n", + addr, ((u8 *)buf)[0]); + } else { + if (fixed) + ret = sdio_readsb(func, buf, addr, len); + else + ret = sdio_memcpy_fromio(func, buf, addr, len); + + dev_dbg(child->parent, "sdio read 53 addr 0x%x, %zu bytes\n", + addr, len); + } + + sdio_release_host(func); + + if (WARN_ON(ret)) + dev_err(child->parent, "sdio read failed (%d)\n", ret); + + if (unlikely(dump)) { + dev_dbg(glue->dev, "cc33xx_sdio: READ from 0x%04x\n", addr); + print_hex_dump(KERN_DEBUG, "cc33xx_sdio: READ ", + DUMP_PREFIX_OFFSET, 16, 1, buf, len, false); + } + + return ret; +} + +static int __must_check cc33xx_sdio_raw_write(struct device *child, int addr, + void *buf, size_t len, bool fixed) +{ + int ret; + struct cc33xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct sdio_func *func = dev_to_sdio_func(glue->dev); + + sdio_claim_host(func); + + if (unlikely(dump)) { + dev_dbg(child->parent, "cc33xx_sdio: WRITE to 0x%04x length 0x%zx (first 64 Bytes):\n", + addr, len); + print_hex_dump(KERN_DEBUG, "cc33xx_sdio: WRITE ", + DUMP_PREFIX_OFFSET, 16, 1, buf, + min(len, (size_t)64), false); + } + + if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) { + sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); + dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n", + addr, ((u8 *)buf)[0]); + } else { + dev_dbg(child->parent, "sdio write 53 addr 0x%x, %zu bytes\n", + addr, len); + + if (fixed) + ret = sdio_writesb(func, addr, buf, len); + else + ret = sdio_memcpy_toio(func, addr, buf, len); + } + + sdio_release_host(func); + + if (WARN_ON(ret)) + dev_err(child->parent, "sdio write failed (%d)\n", ret); + + return ret; +} + +static int cc33xx_sdio_power_on(struct cc33xx_sdio_glue *glue) +{ + int ret; + struct sdio_func *func = dev_to_sdio_func(glue->dev); + struct mmc_card *card = func->card; + + ret = pm_runtime_get_sync(&card->dev); + if (ret < 0) { + pm_runtime_put_noidle(&card->dev); + dev_err(glue->dev, "%s: failed to get_sync(%d)\n", + __func__, ret); + + return ret; + } + + sdio_claim_host(func); + sdio_enable_func(func); + sdio_release_host(func); + + return 0; +} + +static int cc33xx_sdio_power_off(struct cc33xx_sdio_glue *glue) +{ + struct sdio_func *func = dev_to_sdio_func(glue->dev); + struct mmc_card *card = func->card; + + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + + /* Let runtime PM know the card is powered off */ + pm_runtime_put(&card->dev); + return 0; +} + +static int cc33xx_sdio_set_power(struct device *child, bool enable) +{ + struct cc33xx_sdio_glue *glue = dev_get_drvdata(child->parent); + + if (enable) + return cc33xx_sdio_power_on(glue); + else + return cc33xx_sdio_power_off(glue); +} + +/** + * inband_irq_handler - Called from the MMC subsystem when the + * function's IRQ is signaled. + * @func: an SDIO function of the card + * + * Note that the host is already claimed when handler is invoked. + */ +static void inband_irq_handler(struct sdio_func *func) +{ + struct cc33xx_sdio_glue *glue = sdio_get_drvdata(func); + struct platform_device *pdev = glue->core; + struct cc33xx_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); + + dev_dbg(glue->dev, "Inband SDIO IRQ"); + + if (WARN_ON(!pdev_data->irq_handler)) + return; + + pdev_data->irq_handler(pdev); +} + +static void cc33xx_enable_async_interrupt(struct sdio_func *func) +{ + u8 reg_val; + const int CCCR_REG_16_ADDR = 0x16; + const int ENABLE_ASYNC_IRQ_BIT = BIT(1); + + reg_val = sdio_f0_readb(func, CCCR_REG_16_ADDR, NULL); + reg_val |= ENABLE_ASYNC_IRQ_BIT; + sdio_f0_writeb(func, reg_val, CCCR_REG_16_ADDR, NULL); +} + +static void cc33xx_sdio_enable_irq(struct device *child) +{ + struct cc33xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct sdio_func *func = dev_to_sdio_func(glue->dev); + + sdio_claim_host(func); + cc33xx_enable_async_interrupt(func); + sdio_claim_irq(func, inband_irq_handler); + sdio_release_host(func); +} + +static void cc33xx_sdio_disable_irq(struct device *child) +{ + struct cc33xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct sdio_func *func = dev_to_sdio_func(glue->dev); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_release_host(func); +} + +static void cc33xx_enable_line_irq(struct device *child) +{ + struct cc33xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct platform_device *pdev = glue->core; + struct cc33xx_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); + + enable_irq(pdev_data->gpio_irq_num); +} + +static void cc33xx_disable_line_irq(struct device *child) +{ + struct cc33xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct platform_device *pdev = glue->core; + struct cc33xx_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); + + disable_irq_nosync(pdev_data->gpio_irq_num); +} + +static void cc33xx_set_irq_handler(struct device *child, void *handler) +{ + struct cc33xx_sdio_glue *glue = dev_get_drvdata(child->parent); + struct platform_device *pdev = glue->core; + struct cc33xx_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); + + pdev_data->irq_handler = handler; +} + +static struct cc33xx_if_operations sdio_ops_gpio_irq = { + .interface_claim = cc33xx_sdio_claim, + .interface_release = cc33xx_sdio_release, + .read = cc33xx_sdio_raw_read, + .write = cc33xx_sdio_raw_write, + .power = cc33xx_sdio_set_power, + .set_block_size = cc33xx_sdio_set_block_size, + .set_irq_handler = cc33xx_set_irq_handler, + .disable_irq = cc33xx_disable_line_irq, + .enable_irq = cc33xx_enable_line_irq, +}; + +static struct cc33xx_if_operations sdio_ops_inband_irq = { + .interface_claim = cc33xx_sdio_claim, + .interface_release = cc33xx_sdio_release, + .read = cc33xx_sdio_raw_read, + .write = cc33xx_sdio_raw_write, + .power = cc33xx_sdio_set_power, + .set_block_size = cc33xx_sdio_set_block_size, + .set_irq_handler = cc33xx_set_irq_handler, + .disable_irq = cc33xx_sdio_disable_irq, + .enable_irq = cc33xx_sdio_enable_irq, +}; + +#ifdef CONFIG_OF +static const struct cc33xx_family_data cc33xx_data = { + .name = "cc33xx", + .cfg_name = "ti-connectivity/cc33xx-conf.bin", + .nvs_name = "ti-connectivity/cc33xx-nvs.bin", +}; + +static const struct of_device_id cc33xx_sdio_of_match_table[] = { + { .compatible = "ti,cc3300", .data = &cc33xx_data }, + { .compatible = "ti,cc3301", .data = &cc33xx_data }, + { .compatible = "ti,cc3350", .data = &cc33xx_data }, + { .compatible = "ti,cc3351", .data = &cc33xx_data }, + { } +}; + +static int cc33xx_probe_of(struct device *dev, int *irq, int *wakeirq, + struct cc33xx_platdev_data *pdev_data) +{ + struct device_node *np = dev->of_node; + const struct of_device_id *of_id; + + of_id = of_match_node(cc33xx_sdio_of_match_table, np); + if (!of_id) + return -ENODEV; + + pdev_data->family = of_id->data; + + *irq = irq_of_parse_and_map(np, 0); + + *wakeirq = irq_of_parse_and_map(np, 1); + + return 0; +} +#else +static int cc33xx_probe_of(struct device *dev, int *irq, int *wakeirq, + struct cc33xx_platdev_data *pdev_data) +{ + return -ENODATA; +} +#endif /* CONFIG_OF */ + +static irqreturn_t gpio_irq_hard_handler(int irq, void *cookie) +{ + return IRQ_WAKE_THREAD; +} + +static irqreturn_t gpio_irq_thread_handler(int irq, void *cookie) +{ + struct sdio_func *func = cookie; + struct cc33xx_sdio_glue *glue = sdio_get_drvdata(func); + struct platform_device *pdev = glue->core; + struct cc33xx_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); + + if (WARN_ON(!pdev_data->irq_handler)) + return IRQ_HANDLED; + + pdev_data->irq_handler(pdev); + + return IRQ_HANDLED; +} + +static int sdio_cc33xx_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct cc33xx_platdev_data *pdev_data; + struct cc33xx_sdio_glue *glue; + struct resource res[1]; + mmc_pm_flag_t mmcflags; + int ret = -ENOMEM; + int gpio_irq, wakeirq, irq_flags; + const char *chip_family; + + /* We are only able to handle the wlan function */ + if (func->num != 0x02) + return -ENODEV; + + pdev_data = devm_kzalloc(&func->dev, sizeof(*pdev_data), GFP_KERNEL); + if (!pdev_data) + return -ENOMEM; + + glue = devm_kzalloc(&func->dev, sizeof(*glue), GFP_KERNEL); + if (!glue) + return -ENOMEM; + + glue->dev = &func->dev; + + /* Grab access to FN0 for ELP reg. */ + func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + + /* Use block mode for transferring over one block size of data */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + + ret = cc33xx_probe_of(&func->dev, &gpio_irq, &wakeirq, pdev_data); + if (ret) + goto out; + + /* if sdio can keep power while host is suspended, enable wow */ + mmcflags = sdio_get_host_pm_caps(func); + dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); + + sdio_set_drvdata(func, glue); + + /* Tell PM core that we don't need the card to be powered now */ + pm_runtime_put_noidle(&func->dev); + + chip_family = "cc33xx"; + + glue->core = platform_device_alloc(chip_family, PLATFORM_DEVID_AUTO); + if (!glue->core) { + dev_err(glue->dev, "can't allocate platform_device"); + ret = -ENOMEM; + goto out; + } + + glue->core->dev.parent = &func->dev; + + if (gpio_irq) { + dev_info(glue->dev, "Using GPIO as IRQ\n"); + + irq_flags = irqd_get_trigger_type(irq_get_irq_data(gpio_irq)); + + irq_set_status_flags(gpio_irq, IRQ_NOAUTOEN); + + if (irq_flags & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) + irq_flags |= IRQF_ONESHOT; + + ret = request_threaded_irq(gpio_irq, gpio_irq_hard_handler, + gpio_irq_thread_handler, + irq_flags, glue->core->name, func); + if (ret) { + dev_err(glue->dev, "can't register GPIO IRQ handler\n"); + goto out_dev_put; + } + + pdev_data->gpio_irq_num = gpio_irq; + + if ((mmcflags & MMC_PM_KEEP_POWER) && + (enable_irq_wake(gpio_irq) == 0)) + pdev_data->pwr_in_suspend = true; + + pdev_data->if_ops = &sdio_ops_gpio_irq; + } else { + dev_info(glue->dev, "Using SDIO in-band IRQ\n"); + + pdev_data->if_ops = &sdio_ops_inband_irq; + } + + if (wakeirq > 0) { + res[0].start = wakeirq; + res[0].flags = IORESOURCE_IRQ | + irqd_get_trigger_type(irq_get_irq_data(wakeirq)); + res[0].name = "wakeirq"; + + ret = platform_device_add_resources(glue->core, res, 1); + if (ret) { + dev_err(glue->dev, "can't add resources\n"); + goto out_dev_put; + } + } + + ret = platform_device_add_data(glue->core, pdev_data, + sizeof(*pdev_data)); + if (ret) { + dev_err(glue->dev, "can't add platform data\n"); + goto out_dev_put; + } + + ret = platform_device_add(glue->core); + if (ret) { + dev_err(glue->dev, "can't add platform device\n"); + goto out_dev_put; + } + return 0; + +out_dev_put: + platform_device_put(glue->core); + + if (pdev_data->gpio_irq_num) + free_irq(pdev_data->gpio_irq_num, func); + +out: + return ret; +} + +static void sdio_cc33xx_remove(struct sdio_func *func) +{ + struct cc33xx_sdio_glue *glue = sdio_get_drvdata(func); + struct platform_device *pdev = glue->core; + struct cc33xx_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); + + /* Undo decrement done above in sdio_cc33xx_probe */ + pm_runtime_get_noresume(&func->dev); + + platform_device_unregister(glue->core); + + if (pdev_data->gpio_irq_num) { + free_irq(pdev_data->gpio_irq_num, func); + if (pdev_data->pwr_in_suspend) + disable_irq_wake(pdev_data->gpio_irq_num); + } else { + sdio_claim_host(func); + sdio_release_irq(func); + sdio_release_host(func); + } +} + +#ifdef CONFIG_PM +static int cc33xx_suspend(struct device *dev) +{ + /* Tell MMC/SDIO core it's OK to power down the card + * (if it isn't already), but not to remove it completely + */ + struct sdio_func *func = dev_to_sdio_func(dev); + struct cc33xx_sdio_glue *glue = sdio_get_drvdata(func); + struct cc33xx *cc = platform_get_drvdata(glue->core); + mmc_pm_flag_t sdio_flags; + int ret = 0; + + if (!cc) { + dev_err(dev, "no wilink module was probed\n"); + goto out; + } + + dev_dbg(dev, "cc33xx suspend. keep_device_power: %d\n", + cc->keep_device_power); + + if (cc->keep_device_power) { + sdio_flags = sdio_get_host_pm_caps(func); + + if (!(sdio_flags & MMC_PM_KEEP_POWER)) { + dev_err(dev, "can't keep power while host is suspended\n"); + ret = -EINVAL; + goto out; + } + + /* keep power while host suspended */ + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (ret) { + dev_err(dev, "error while trying to keep power\n"); + goto out; + } + } +out: + return ret; +} + +static int cc33xx_resume(struct device *dev) +{ + dev_dbg(dev, "cc33xx resume\n"); + + return 0; +} + +static const struct dev_pm_ops cc33xx_sdio_pm_ops = { + .suspend = cc33xx_suspend, + .resume = cc33xx_resume, +}; + +static struct sdio_driver cc33xx_sdio_driver = { + .name = "cc33xx_sdio", + .id_table = cc33xx_devices, + .probe = sdio_cc33xx_probe, + .remove = sdio_cc33xx_remove, + .drv = { + .pm = &cc33xx_sdio_pm_ops, + }, +}; +#else +static struct sdio_driver cc33xx_sdio_driver = { + .name = "cc33xx_sdio", + .id_table = cc33xx_devices, + .probe = sdio_cc33xx_probe, + .remove = sdio_cc33xx_remove, +}; +#endif /* CONFIG_PM */ + +static int __init sdio_cc33xx_init(void) +{ + return sdio_register_driver(&cc33xx_sdio_driver); +} + +static void __exit sdio_cc33xx_exit(void) +{ + sdio_unregister_driver(&cc33xx_sdio_driver); +} + +module_init(sdio_cc33xx_init); +module_exit(sdio_cc33xx_exit); + +module_param(dump, bool, 0600); +MODULE_PARM_DESC(dump, "Enable sdio read/write dumps."); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SDIO transport for Texas Instruments CC33xx WLAN driver"); +MODULE_AUTHOR("Michael Nemanov "); +MODULE_AUTHOR("Sabeeh Khan "); diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/testmode.c b/drivers/net/wireless/ti/cc33xx/testmode.c --- a/drivers/net/wireless/ti/cc33xx/testmode.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/testmode.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include + +#include "cc33xx.h" +#include "acx.h" +#include "io.h" +#include "testmode.h" + +#define CC33XX_TM_MAX_DATA_LENGTH 1024 + +enum cc33xx_tm_commands { + CC33XX_TM_CMD_UNSPEC, + CC33XX_TM_CMD_TEST, + CC33XX_TM_CMD_INTERROGATE, + CC33XX_TM_CMD_CONFIGURE, + CC33XX_TM_CMD_NVS_PUSH, /* Not in use. Keep to not break ABI */ + CC33XX_TM_CMD_SET_PLT_MODE, + CC33XX_TM_CMD_RECOVER, /* Not in use. Keep to not break ABI */ + CC33XX_TM_CMD_GET_MAC, + + __CC33XX_TM_CMD_AFTER_LAST +}; + +enum cc33xx_tm_attrs { + CC33XX_TM_ATTR_UNSPEC, + CC33XX_TM_ATTR_CMD_ID, + CC33XX_TM_ATTR_ANSWER, + CC33XX_TM_ATTR_DATA, + CC33XX_TM_ATTR_IE_ID, + CC33XX_TM_ATTR_PLT_MODE, + + __CC33XX_TM_ATTR_AFTER_LAST +}; + +#define CC33XX_TM_ATTR_MAX (__CC33XX_TM_ATTR_AFTER_LAST - 1) + +static struct nla_policy cc33xx_tm_policy[CC33XX_TM_ATTR_MAX + 1] = { + [CC33XX_TM_ATTR_CMD_ID] = { .type = NLA_U32 }, + [CC33XX_TM_ATTR_ANSWER] = { .type = NLA_U8 }, + [CC33XX_TM_ATTR_DATA] = { .type = NLA_BINARY, + .len = CC33XX_TM_MAX_DATA_LENGTH }, + [CC33XX_TM_ATTR_IE_ID] = { .type = NLA_U32 }, + [CC33XX_TM_ATTR_PLT_MODE] = { .type = NLA_U32 }, +}; + +static int cc33xx_tm_cmd_test(struct cc33xx *cc, struct nlattr *tb[]) +{ + int ret, len; + u16 buf_len; + struct sk_buff *skb; + void *buf; + u8 answer = 0; + + cc33xx_debug(DEBUG_TESTMODE, "testmode cmd test"); + + if (!tb[CC33XX_TM_ATTR_DATA]) + return -EINVAL; + + buf = nla_data(tb[CC33XX_TM_ATTR_DATA]); + buf_len = nla_len(tb[CC33XX_TM_ATTR_DATA]); + + if (tb[CC33XX_TM_ATTR_ANSWER]) + answer = nla_get_u8(tb[CC33XX_TM_ATTR_ANSWER]); + + if (buf_len > sizeof(struct cc33xx_command)) + return -EMSGSIZE; + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) { + ret = -EINVAL; + goto out; + } + + ret = cc33xx_cmd_test(cc, buf, buf_len, answer); + if (ret < 0) { + cc33xx_warning("testmode cmd test failed: %d", ret); + goto out; + } + + if (answer) { + /* If we got bip calibration answer print radio status */ + struct cc33xx_cmd_cal_p2g *params = + (struct cc33xx_cmd_cal_p2g *)buf; + s16 radio_status = (s16)le16_to_cpu(params->radio_status); + + if (params->test.id == TEST_CMD_P2G_CAL && radio_status < 0) + cc33xx_warning("testmode cmd: radio status=%d", + radio_status); + else + cc33xx_info("testmode cmd: radio status=%d", + radio_status); + + len = nla_total_size(buf_len); + skb = cfg80211_testmode_alloc_reply_skb(cc->hw->wiphy, len); + if (!skb) { + ret = -ENOMEM; + goto out; + } + + if (nla_put(skb, CC33XX_TM_ATTR_DATA, buf_len, buf)) { + kfree_skb(skb); + ret = -EMSGSIZE; + goto out; + } + + ret = cfg80211_testmode_reply(skb); + } + +out: + mutex_unlock(&cc->mutex); + + return ret; +} + +static int cc33xx_tm_cmd_interrogate(struct cc33xx *cc, struct nlattr *tb[]) +{ + int ret; + struct cc33xx_command *cmd; + struct sk_buff *skb; + u8 ie_id; + + cc33xx_debug(DEBUG_TESTMODE, "testmode cmd interrogate"); + + if (!tb[CC33XX_TM_ATTR_IE_ID]) + return -EINVAL; + + ie_id = nla_get_u8(tb[CC33XX_TM_ATTR_IE_ID]); + + cc33xx_debug(DEBUG_TESTMODE, "testmode cmd interrogate id %d", ie_id); + + mutex_lock(&cc->mutex); + + if (unlikely(cc->state != CC33XX_STATE_ON)) { + ret = -EINVAL; + goto out; + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = cc33xx_cmd_debug_inter(cc, ie_id, cmd, + sizeof(struct acx_header), sizeof(*cmd)); + if (ret < 0) { + cc33xx_warning("testmode cmd interrogate failed: %d", ret); + goto out_free; + } + + skb = cfg80211_testmode_alloc_reply_skb(cc->hw->wiphy, sizeof(*cmd)); + if (!skb) { + ret = -ENOMEM; + goto out_free; + } + + if (nla_put(skb, CC33XX_TM_ATTR_DATA, sizeof(*cmd), cmd)) { + kfree_skb(skb); + ret = -EMSGSIZE; + goto out_free; + } + + ret = cfg80211_testmode_reply(skb); + if (ret < 0) + goto out_free; + +out_free: + kfree(cmd); + +out: + mutex_unlock(&cc->mutex); + + return ret; +} + +static int cc33xx_tm_cmd_configure(struct cc33xx *cc, struct nlattr *tb[]) +{ + int ret; + u16 buf_len; + void *buf; + u8 ie_id; + + cc33xx_debug(DEBUG_TESTMODE, "testmode cmd configure"); + + if (!tb[CC33XX_TM_ATTR_DATA]) + return -EINVAL; + if (!tb[CC33XX_TM_ATTR_IE_ID]) + return -EINVAL; + + ie_id = nla_get_u8(tb[CC33XX_TM_ATTR_IE_ID]); + buf = nla_data(tb[CC33XX_TM_ATTR_DATA]); + buf_len = nla_len(tb[CC33XX_TM_ATTR_DATA]); + + if (buf_len > sizeof(struct cc33xx_command)) + return -EMSGSIZE; + + mutex_lock(&cc->mutex); + ret = cc33xx_cmd_debug(cc, ie_id, buf, buf_len); + mutex_unlock(&cc->mutex); + + if (ret < 0) { + cc33xx_warning("testmode cmd configure failed: %d", ret); + return ret; + } + + return 0; +} + +static int cc33xx_tm_detect_fem(struct cc33xx *cc, struct nlattr *tb[]) +{ + /* return FEM type */ + int ret, len; + struct sk_buff *skb; + + ret = cc33xx_plt_start(cc, PLT_FEM_DETECT); + if (ret < 0) + goto out; + + mutex_lock(&cc->mutex); + + len = nla_total_size(sizeof(cc->fem_manuf)); + skb = cfg80211_testmode_alloc_reply_skb(cc->hw->wiphy, len); + if (!skb) { + ret = -ENOMEM; + goto out_mutex; + } + + if (nla_put(skb, CC33XX_TM_ATTR_DATA, sizeof(cc->fem_manuf), + &cc->fem_manuf)) { + kfree_skb(skb); + ret = -EMSGSIZE; + goto out_mutex; + } + + ret = cfg80211_testmode_reply(skb); + +out_mutex: + mutex_unlock(&cc->mutex); + + /* We always stop plt after DETECT mode */ + cc33xx_plt_stop(cc); +out: + return ret; +} + +static int cc33xx_tm_cmd_set_plt_mode(struct cc33xx *cc, struct nlattr *tb[]) +{ + u32 val; + int ret; + + cc33xx_debug(DEBUG_TESTMODE, "testmode cmd set plt mode"); + + if (!tb[CC33XX_TM_ATTR_PLT_MODE]) + return -EINVAL; + + val = nla_get_u32(tb[CC33XX_TM_ATTR_PLT_MODE]); + + switch (val) { + case PLT_OFF: + ret = cc33xx_plt_stop(cc); + break; + case PLT_ON: + case PLT_CHIP_AWAKE: + ret = cc33xx_plt_start(cc, val); + break; + case PLT_FEM_DETECT: + ret = cc33xx_tm_detect_fem(cc, tb); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int cc33xx_tm_cmd_get_mac(struct cc33xx *cc, struct nlattr *tb[]) +{ + struct sk_buff *skb; + u8 zero_mac[ETH_ALEN] = {0}; + int ret = 0; + + mutex_lock(&cc->mutex); + + if (!cc->plt) { + ret = -EINVAL; + goto out; + } + + if (memcmp(zero_mac, cc->efuse_mac_address, ETH_ALEN) == 0) { + ret = -EOPNOTSUPP; + goto out; + } + + skb = cfg80211_testmode_alloc_reply_skb(cc->hw->wiphy, ETH_ALEN); + if (!skb) { + ret = -ENOMEM; + goto out; + } + + if (nla_put(skb, CC33XX_TM_ATTR_DATA, + ETH_ALEN, cc->efuse_mac_address)) { + kfree_skb(skb); + ret = -EMSGSIZE; + goto out; + } + + ret = cfg80211_testmode_reply(skb); + if (ret < 0) + goto out; + +out: + mutex_unlock(&cc->mutex); + return ret; +} + +int cc33xx_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len) +{ + struct cc33xx *cc = hw->priv; + struct nlattr *tb[CC33XX_TM_ATTR_MAX + 1]; + u32 nla_cmd; + int err; + + err = nla_parse_deprecated(tb, CC33XX_TM_ATTR_MAX, data, len, + cc33xx_tm_policy, NULL); + if (err) + return err; + + if (!tb[CC33XX_TM_ATTR_CMD_ID]) + return -EINVAL; + + nla_cmd = nla_get_u32(tb[CC33XX_TM_ATTR_CMD_ID]); + + /* Only SET_PLT_MODE is allowed in case of mode PLT_CHIP_AWAKE */ + if (cc->plt_mode == PLT_CHIP_AWAKE && + nla_cmd != CC33XX_TM_CMD_SET_PLT_MODE) + return -EOPNOTSUPP; + + switch (nla_cmd) { + case CC33XX_TM_CMD_TEST: + return cc33xx_tm_cmd_test(cc, tb); + case CC33XX_TM_CMD_INTERROGATE: + return cc33xx_tm_cmd_interrogate(cc, tb); + case CC33XX_TM_CMD_CONFIGURE: + return cc33xx_tm_cmd_configure(cc, tb); + case CC33XX_TM_CMD_SET_PLT_MODE: + return cc33xx_tm_cmd_set_plt_mode(cc, tb); + case CC33XX_TM_CMD_GET_MAC: + return cc33xx_tm_cmd_get_mac(cc, tb); + default: + return -EOPNOTSUPP; + } +} diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/testmode.h b/drivers/net/wireless/ti/cc33xx/testmode.h --- a/drivers/net/wireless/ti/cc33xx/testmode.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/testmode.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __TESTMODE_H__ +#define __TESTMODE_H__ + +int cc33xx_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len); + +#endif /* __TESTMODE_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/tx.c b/drivers/net/wireless/ti/cc33xx/tx.c --- a/drivers/net/wireless/ti/cc33xx/tx.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/tx.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,1411 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include "acx.h" +#include "debug.h" +#include "io.h" +#include "ps.h" +#include "tx.h" +#include "cc33xx.h" + +static int cc33xx_set_default_wep_key(struct cc33xx *cc, + struct cc33xx_vif *wlvif, u8 id) +{ + int ret; + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + + if (is_ap) + ret = cc33xx_cmd_set_default_wep_key(cc, id, + wlvif->ap.bcast_hlid); + else + ret = cc33xx_cmd_set_default_wep_key(cc, id, wlvif->sta.hlid); + + if (ret < 0) + return ret; + + cc33xx_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id); + return 0; +} + +static int cc33xx_alloc_tx_id(struct cc33xx *cc, struct sk_buff *skb) +{ + int id; + + id = find_first_zero_bit(cc->tx_frames_map, CC33XX_NUM_TX_DESCRIPTORS); + if (id >= CC33XX_NUM_TX_DESCRIPTORS) + return -EBUSY; + + __set_bit(id, cc->tx_frames_map); + cc->tx_frames[id] = skb; + cc->tx_frames_cnt++; + cc33xx_debug(DEBUG_TX, "alloc desc ID. id - %d, frames count %d", + id, cc->tx_frames_cnt); + return id; +} + +void cc33xx_free_tx_id(struct cc33xx *cc, int id) +{ + if (__test_and_clear_bit(id, cc->tx_frames_map)) { + if (unlikely(cc->tx_frames_cnt == CC33XX_NUM_TX_DESCRIPTORS)) + clear_bit(CC33XX_FLAG_FW_TX_BUSY, &cc->flags); + + cc->tx_frames[id] = NULL; + cc->tx_frames_cnt--; + } + cc33xx_debug(DEBUG_TX, "free desc ID. id - %d, frames count %d", + id, cc->tx_frames_cnt); +} +EXPORT_SYMBOL(cc33xx_free_tx_id); + +static void cc33xx_tx_ap_update_inconnection_sta(struct cc33xx *cc, + struct cc33xx_vif *wlvif, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)(skb->data + + sizeof(struct cc33xx_tx_hw_descr)); + if (!ieee80211_is_auth(hdr->frame_control)) + return; + + /* ROC for 1 second on the AP channel for completing the connection. + * Note the ROC will be continued by the update_sta_state callbacks + * once the station reaches the associated state. + */ + cc33xx_update_inconn_sta(cc, wlvif, NULL, true); + wlvif->pending_auth_reply_time = jiffies; + cancel_delayed_work(&wlvif->pending_auth_complete_work); + ieee80211_queue_delayed_work(cc->hw, + &wlvif->pending_auth_complete_work, + msecs_to_jiffies(CC33XX_PEND_AUTH_ROC_TIMEOUT)); +} + +static void cc33xx_tx_regulate_link(struct cc33xx *cc, + struct cc33xx_vif *wlvif, + u8 hlid) +{ + bool fw_ps; + u8 tx_pkts; + + if (WARN_ON(!test_bit(hlid, wlvif->links_map))) + return; + + fw_ps = test_bit(hlid, &cc->ap_fw_ps_map); + tx_pkts = cc->links[hlid].allocated_pkts; + + /* if in FW PS and there is enough data in FW we can put the link + * into high-level PS and clean out its TX queues. + * Make an exception if this is the only connected link. In this + * case FW-memory congestion is less of a problem. + * Note that a single connected STA means 2*ap_count + 1 active links, + * since we must account for the global and broadcast AP links + * for each AP. The "fw_ps" check assures us the other link is a STA + * connected to the AP. Otherwise the FW would not set the PSM bit. + */ + if (cc->active_link_count > (cc->ap_count * 2 + 1) && fw_ps && + tx_pkts >= CC33XX_PS_STA_MAX_PACKETS) + cc33xx_ps_link_start(cc, wlvif, hlid, true); +} + +inline bool cc33xx_is_dummy_packet(struct cc33xx *cc, struct sk_buff *skb) +{ + return cc->dummy_packet == skb; +} +EXPORT_SYMBOL(cc33xx_is_dummy_packet); + +static u8 cc33xx_tx_get_hlid_ap(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct sk_buff *skb, struct ieee80211_sta *sta) +{ + struct ieee80211_hdr *hdr; + + if (sta) { + struct cc33xx_station *wl_sta; + + wl_sta = (struct cc33xx_station *)sta->drv_priv; + return wl_sta->hlid; + } + + if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) + return CC33XX_SYSTEM_HLID; + + hdr = (struct ieee80211_hdr *)skb->data; + if (is_multicast_ether_addr(ieee80211_get_DA(hdr))) + return wlvif->ap.bcast_hlid; + else + return wlvif->ap.global_hlid; +} + +u8 cc33xx_tx_get_hlid(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct sk_buff *skb, struct ieee80211_sta *sta) +{ + struct ieee80211_tx_info *control; + + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + return cc33xx_tx_get_hlid_ap(cc, wlvif, skb, sta); + + control = IEEE80211_SKB_CB(skb); + if (control->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { + cc33xx_debug(DEBUG_TX, "tx offchannel"); + return wlvif->dev_hlid; + } + + return wlvif->sta.hlid; +} + +unsigned int cc33xx_calc_packet_alignment(struct cc33xx *cc, + unsigned int packet_length) +{ + if ((cc->quirks & CC33XX_QUIRK_TX_PAD_LAST_FRAME) || + !(cc->quirks & CC33XX_QUIRK_TX_BLOCKSIZE_ALIGN)) + return ALIGN(packet_length, CC33XX_TX_ALIGN_TO); + else + return ALIGN(packet_length, CC33XX_BUS_BLOCK_SIZE); +} +EXPORT_SYMBOL(cc33xx_calc_packet_alignment); + +static u32 cc33xx_calc_tx_blocks(struct cc33xx *cc, u32 len, u32 spare_blks) +{ + u32 blk_size = CC33XX_TX_HW_BLOCK_SIZE; + /* In CC33xx the packet will be stored along with its internal descriptor. + * the descriptor is not part of the host transaction, but should be + * considered as part of the allocate memory blocks in the device + */ + len = len + CC33xx_INTERNAL_DESC_SIZE; + return (len + blk_size - 1) / blk_size + spare_blks; +} + +static inline void cc33xx_set_tx_desc_blocks(struct cc33xx *cc, + struct cc33xx_tx_hw_descr *desc, + u32 blks, u32 spare_blks) +{ + desc->cc33xx_mem.total_mem_blocks = blks; +} + +static void cc33xx_set_tx_desc_data_len(struct cc33xx *cc, + struct cc33xx_tx_hw_descr *desc, + struct sk_buff *skb) +{ + desc->length = cpu_to_le16(skb->len); + + /* if only the last frame is to be padded, we unset this bit on Tx */ + if (cc->quirks & CC33XX_QUIRK_TX_PAD_LAST_FRAME) + desc->cc33xx_mem.ctrl = CC33XX_TX_CTRL_NOT_PADDED; + else + desc->cc33xx_mem.ctrl = 0; + + cc33xx_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d len: %d life: %d mem: %d", + desc->hlid, le16_to_cpu(desc->length), + le16_to_cpu(desc->life_time), + desc->cc33xx_mem.total_mem_blocks); +} + +static int cc33xx_get_spare_blocks(struct cc33xx *cc, bool is_gem) +{ + /* If we have keys requiring extra spare, indulge them */ + if (cc->extra_spare_key_count) + return CC33XX_TX_HW_EXTRA_BLOCK_SPARE; + + return CC33XX_TX_HW_BLOCK_SPARE; +} + +int cc33xx_tx_get_queue(int queue) +{ + switch (queue) { + case 0: + return CONF_TX_AC_VO; + case 1: + return CONF_TX_AC_VI; + case 2: + return CONF_TX_AC_BE; + case 3: + return CONF_TX_AC_BK; + default: + return CONF_TX_AC_BE; + } +} + +static int cc33xx_tx_allocate(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct sk_buff *skb, u32 extra, u32 buf_offset, + u8 hlid, bool is_gem, + struct NAB_tx_header *nab_cmd) +{ + struct cc33xx_tx_hw_descr *desc; + u32 total_blocks; + int id, ret = -EBUSY, ac; + u32 spare_blocks; + u32 total_skb_len = skb->len + extra; + /* Add NAB command required for CC33xx architecture */ + u32 total_len = sizeof(struct NAB_tx_header); + + total_skb_len += sizeof(struct cc33xx_tx_hw_descr); + total_len += total_skb_len; + + cc33xx_debug(DEBUG_TX, "cc->tx_blocks_available %d", + cc->tx_blocks_available); + + if (buf_offset + total_len > cc->aggr_buf_size) + return -EAGAIN; + + spare_blocks = cc33xx_get_spare_blocks(cc, is_gem); + + /* allocate free identifier for the packet */ + id = cc33xx_alloc_tx_id(cc, skb); + if (id < 0) + return id; + + /* memblocks should not include nab descriptor */ + total_blocks = cc33xx_calc_tx_blocks(cc, total_skb_len, spare_blocks); + cc33xx_debug(DEBUG_TX, "total blocks %d", total_blocks); + + if (total_blocks <= cc->tx_blocks_available) { + /** + * In CC33XX the packet starts with NAB command, + * only then the descriptor. + */ + nab_cmd->sync = cpu_to_le32(HOST_SYNC_PATTERN); + nab_cmd->opcode = cpu_to_le16(NAB_SEND_CMD); + + /** + * length should include the following 4 bytes + * of the NAB command. + */ + nab_cmd->len = cpu_to_le16(total_len - + sizeof(struct NAB_header)); + nab_cmd->desc_length = cpu_to_le16(total_len - + sizeof(struct NAB_tx_header)); + nab_cmd->sd = 0; + nab_cmd->flags = NAB_SEND_FLAGS; + + desc = skb_push(skb, total_skb_len - skb->len); + + cc33xx_set_tx_desc_blocks(cc, desc, total_blocks, spare_blocks); + + desc->id = id; + + cc33xx_debug(DEBUG_TX, + "tx allocate id %u skb 0x%p tx_memblocks %d", + id, skb, desc->cc33xx_mem.total_mem_blocks); + + cc->tx_blocks_available -= total_blocks; + cc->tx_allocated_blocks += total_blocks; + + /* If the FW was empty before, arm the Tx watchdog. Also do + * this on the first Tx after resume, as we always cancel the + * watchdog on suspend. + */ + if (cc->tx_allocated_blocks == total_blocks || + test_and_clear_bit(CC33XX_FLAG_REINIT_TX_WDOG, &cc->flags)) + cc33xx_rearm_tx_watchdog_locked(cc); + + ac = cc33xx_tx_get_queue(skb_get_queue_mapping(skb)); + desc->ac = ac; + cc->tx_allocated_pkts[ac]++; + + if (test_bit(hlid, cc->links_map)) + cc->links[hlid].allocated_pkts++; + + ret = 0; + + cc33xx_debug(DEBUG_TX, + "tx_allocate: size: %d, blocks: %d, id: %d", + total_len, total_blocks, id); + } else { + cc33xx_free_tx_id(cc, id); + } + + return ret; +} + +static void cc33xx_tx_fill_hdr(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct sk_buff *skb, u32 extra, + struct ieee80211_tx_info *control, u8 hlid) +{ + struct cc33xx_tx_hw_descr *desc; + int ac, rate_idx; + u16 tx_attr = 0; + __le16 frame_control; + struct ieee80211_hdr *hdr; + u8 *frame_start; + bool is_dummy; + + desc = (struct cc33xx_tx_hw_descr *)skb->data; + + frame_start = (u8 *)(desc + 1); + hdr = (struct ieee80211_hdr *)(frame_start + extra); + frame_control = hdr->frame_control; + + /* relocate space for security header */ + if (extra) { + int hdrlen = ieee80211_hdrlen(frame_control); + + memmove(frame_start, hdr, hdrlen); + skb_set_network_header(skb, skb_network_offset(skb) + extra); + } + + is_dummy = cc33xx_is_dummy_packet(cc, skb); + if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS) + desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); + else + desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); + + /* queue */ + ac = cc33xx_tx_get_queue(skb_get_queue_mapping(skb)); + desc->tid = skb->priority; + + if (is_dummy) { + /* FW expects the dummy packet to have an invalid session id - + * any session id that is different than the one set in the join + */ + tx_attr = (SESSION_COUNTER_INVALID << + TX_HW_ATTR_OFST_SESSION_COUNTER) & + TX_HW_ATTR_SESSION_COUNTER; + + tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; + } else if (wlvif) { + u8 session_id = cc->session_ids[hlid]; + + if (cc->quirks & CC33XX_QUIRK_AP_ZERO_SESSION_ID && + wlvif->bss_type == BSS_TYPE_AP_BSS) + session_id = 0; + + /* configure the tx attributes */ + tx_attr = session_id << TX_HW_ATTR_OFST_SESSION_COUNTER; + } + + desc->hlid = hlid; + if (is_dummy || !wlvif) { + rate_idx = 0; + } else if (wlvif->bss_type != BSS_TYPE_AP_BSS) { + /* if the packets are data packets + * send them with AP rate policies (EAPOLs are an exception), + * otherwise use default basic rates + */ + if (skb->protocol == cpu_to_be16(ETH_P_PAE)) + rate_idx = wlvif->sta.basic_rate_idx; + else if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE) + rate_idx = wlvif->sta.p2p_rate_idx; + else if (ieee80211_is_data(frame_control)) + rate_idx = wlvif->sta.ap_rate_idx; + else + rate_idx = wlvif->sta.basic_rate_idx; + } else { + if (hlid == wlvif->ap.global_hlid) + rate_idx = wlvif->ap.mgmt_rate_idx; + else if (hlid == wlvif->ap.bcast_hlid || + skb->protocol == cpu_to_be16(ETH_P_PAE) || + !ieee80211_is_data(frame_control)) + /* send non-data, bcast and EAPOLs using the + * min basic rate + */ + rate_idx = wlvif->ap.bcast_rate_idx; + else + rate_idx = wlvif->ap.ucast_rate_idx[ac]; + } + + tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; + + /* for WEP shared auth - no fw encryption is needed */ + if (ieee80211_is_auth(frame_control) && + ieee80211_has_protected(frame_control)) + tx_attr |= TX_HW_ATTR_HOST_ENCRYPT; + + /* send EAPOL frames as voice */ + if (control->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) + tx_attr |= TX_HW_ATTR_EAPOL_FRAME; + + desc->tx_attr = cpu_to_le16(tx_attr); + + cc33xx_set_tx_desc_data_len(cc, desc, skb); +} + +/* caller must hold cc->mutex */ +static int cc33xx_prepare_tx_frame(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct sk_buff *skb, u32 buf_offset, u8 hlid) +{ + struct ieee80211_tx_info *info; + u32 extra = 0; + int ret = 0; + u32 total_len; + bool is_dummy; + bool is_gem = false; + struct NAB_tx_header nab_cmd; + + if (!skb) { + cc33xx_error("discarding null skb"); + return -EINVAL; + } + + if (hlid == CC33XX_INVALID_LINK_ID) { + cc33xx_error("invalid hlid. dropping skb 0x%p", skb); + return -EINVAL; + } + + info = IEEE80211_SKB_CB(skb); + + is_dummy = cc33xx_is_dummy_packet(cc, skb); + + if ((cc->quirks & CC33XX_QUIRK_TKIP_HEADER_SPACE) && + info->control.hw_key && + info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) + extra = CC33XX_EXTRA_SPACE_TKIP; + + if (info->control.hw_key) { + bool is_wep; + u8 idx = info->control.hw_key->hw_key_idx; + u32 cipher = info->control.hw_key->cipher; + + is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || + (cipher == WLAN_CIPHER_SUITE_WEP104); + + if (WARN_ON(is_wep && wlvif && wlvif->default_key != idx)) { + ret = cc33xx_set_default_wep_key(cc, wlvif, idx); + if (ret < 0) + return ret; + wlvif->default_key = idx; + } + + is_gem = (cipher == CC33XX_CIPHER_SUITE_GEM); + } + + /* Add 4 bytes gap, may be filled later on by the PMAC. */ + extra += IEEE80211_HT_CTL_LEN; + ret = cc33xx_tx_allocate(cc, wlvif, skb, extra, buf_offset, hlid, + is_gem, &nab_cmd); + cc33xx_debug(DEBUG_TX, "cc33xx_tx_allocate %d", ret); + + if (ret < 0) + return ret; + + cc33xx_tx_fill_hdr(cc, wlvif, skb, extra, info, hlid); + + if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) { + cc33xx_tx_ap_update_inconnection_sta(cc, wlvif, skb); + cc33xx_tx_regulate_link(cc, wlvif, hlid); + } + + /* The length of each packet is stored in terms of + * words. Thus, we must pad the skb data to make sure its + * length is aligned. The number of padding bytes is computed + * and set in cc33xx_tx_fill_hdr. + * In special cases, we want to align to a specific block size + * (eg. for wl128x with SDIO we align to 256). + */ + total_len = cc33xx_calc_packet_alignment(cc, skb->len); + + memcpy(cc->aggr_buf + buf_offset, + &nab_cmd, sizeof(struct NAB_tx_header)); + memcpy(cc->aggr_buf + buf_offset + sizeof(struct NAB_tx_header), + skb->data, skb->len); + memset(cc->aggr_buf + buf_offset + sizeof(struct NAB_tx_header) + + skb->len, 0, total_len - skb->len); + + /* Revert side effects in the dummy packet skb, so it can be reused */ + if (is_dummy) + skb_pull(skb, sizeof(struct cc33xx_tx_hw_descr)); + + return (total_len + sizeof(struct NAB_tx_header)); +} + +u32 cc33xx_tx_enabled_rates_get(struct cc33xx *cc, u32 rate_set, + enum nl80211_band rate_band) +{ + struct ieee80211_supported_band *band; + u32 enabled_rates = 0; + int bit; + + band = cc->hw->wiphy->bands[rate_band]; + for (bit = 0; bit < band->n_bitrates; bit++) { + if (rate_set & 0x1) + enabled_rates |= band->bitrates[bit].hw_value; + rate_set >>= 1; + } + + /* MCS rates indication are on bits 16 - 31 */ + rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; + + for (bit = 0; bit < 16; bit++) { + if (rate_set & 0x1) + enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); + rate_set >>= 1; + } + + return enabled_rates; +} + +static inline int cc33xx_tx_get_mac80211_queue(struct cc33xx_vif *wlvif, + int queue) +{ + int mac_queue = wlvif->hw_queue_base; + + switch (queue) { + case CONF_TX_AC_VO: + return mac_queue + 0; + case CONF_TX_AC_VI: + return mac_queue + 1; + case CONF_TX_AC_BE: + return mac_queue + 2; + case CONF_TX_AC_BK: + return mac_queue + 3; + default: + return mac_queue + 2; + } +} + +static void cc33xx_wake_queue(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 queue, enum cc33xx_queue_stop_reason reason) +{ + unsigned long flags; + int hwq = cc33xx_tx_get_mac80211_queue(wlvif, queue); + + spin_lock_irqsave(&cc->cc_lock, flags); + + /* queue should not be clear for this reason */ + WARN_ON_ONCE(!test_and_clear_bit(reason, &cc->queue_stop_reasons[hwq])); + + if (cc->queue_stop_reasons[hwq]) + goto out; + + ieee80211_wake_queue(cc->hw, hwq); + +out: + spin_unlock_irqrestore(&cc->cc_lock, flags); +} + +void cc33xx_handle_tx_low_watermark(struct cc33xx *cc) +{ + int i; + struct cc33xx_vif *wlvif; + + cc33xx_for_each_wlvif(cc, wlvif) { + for (i = 0; i < NUM_TX_QUEUES; i++) { + if (cc33xx_is_queue_stopped_by_reason(cc, wlvif, i, + CC33XX_QUEUE_STOP_REASON_WATERMARK) && + wlvif->tx_queue_count[i] <= + CC33XX_TX_QUEUE_LOW_WATERMARK) + /* firmware buffer has space, restart queues */ + cc33xx_wake_queue(cc, wlvif, i, + CC33XX_QUEUE_STOP_REASON_WATERMARK); + } + } +} + +static int cc33xx_select_ac(struct cc33xx *cc) +{ + int i, q = -1, ac; + u32 min_pkts = 0xffffffff; + + /* Find a non-empty ac where: + * 1. There are packets to transmit + * 2. The FW has the least allocated blocks + * + * We prioritize the ACs according to VO>VI>BE>BK + */ + for (i = 0; i < NUM_TX_QUEUES; i++) { + ac = cc33xx_tx_get_queue(i); + if (cc->tx_queue_count[ac] && + cc->tx_allocated_pkts[ac] < min_pkts) { + q = ac; + min_pkts = cc->tx_allocated_pkts[q]; + } + } + + return q; +} + +static struct sk_buff *cc33xx_lnk_dequeue(struct cc33xx *cc, + struct cc33xx_link *lnk, u8 q) +{ + struct sk_buff *skb; + unsigned long flags; + + skb = skb_dequeue(&lnk->tx_queue[q]); + if (skb) { + spin_lock_irqsave(&cc->cc_lock, flags); + WARN_ON_ONCE(cc->tx_queue_count[q] <= 0); + cc->tx_queue_count[q]--; + if (lnk->wlvif) { + WARN_ON_ONCE(lnk->wlvif->tx_queue_count[q] <= 0); + lnk->wlvif->tx_queue_count[q]--; + } + spin_unlock_irqrestore(&cc->cc_lock, flags); + } + + return skb; +} + +static bool cc33xx_lnk_high_prio(struct cc33xx *cc, u8 hlid, + struct cc33xx_link *lnk) +{ + u8 thold; + struct core_fw_status *core_fw_status = &cc->core_status->fw_info; + unsigned long suspend_bitmap, fast_bitmap, ps_bitmap; + + suspend_bitmap = le32_to_cpu(core_fw_status->link_suspend_bitmap); + fast_bitmap = le32_to_cpu(core_fw_status->link_fast_bitmap); + ps_bitmap = le32_to_cpu(core_fw_status->link_ps_bitmap); + + /* suspended links are never high priority */ + if (test_bit(hlid, &suspend_bitmap)) + return false; + + /* the priority thresholds are taken from FW */ + if (test_bit(hlid, &fast_bitmap) && !test_bit(hlid, &ps_bitmap)) + thold = core_fw_status->tx_fast_link_prio_threshold; + else + thold = core_fw_status->tx_slow_link_prio_threshold; + + return lnk->allocated_pkts < thold; +} + +static bool cc33xx_lnk_low_prio(struct cc33xx *cc, u8 hlid, + struct cc33xx_link *lnk) +{ + u8 thold; + struct core_fw_status *core_fw_status = &cc->core_status->fw_info; + unsigned long suspend_bitmap, fast_bitmap, ps_bitmap; + + suspend_bitmap = le32_to_cpu(core_fw_status->link_suspend_bitmap); + fast_bitmap = le32_to_cpu(core_fw_status->link_fast_bitmap); + ps_bitmap = le32_to_cpu(core_fw_status->link_ps_bitmap); + + if (test_bit(hlid, &suspend_bitmap)) + thold = core_fw_status->tx_suspend_threshold; + else if (test_bit(hlid, &fast_bitmap) && !test_bit(hlid, &ps_bitmap)) + thold = core_fw_status->tx_fast_stop_threshold; + else + thold = core_fw_status->tx_slow_stop_threshold; + + return lnk->allocated_pkts < thold; +} + +static struct sk_buff *cc33xx_lnk_dequeue_high_prio(struct cc33xx *cc, + u8 hlid, u8 ac, + u8 *low_prio_hlid) +{ + struct cc33xx_link *lnk = &cc->links[hlid]; + + if (!cc33xx_lnk_high_prio(cc, hlid, lnk)) { + if (*low_prio_hlid == CC33XX_INVALID_LINK_ID && + !skb_queue_empty(&lnk->tx_queue[ac]) && + cc33xx_lnk_low_prio(cc, hlid, lnk)) + /* we found the first non-empty low priority queue */ + *low_prio_hlid = hlid; + + return NULL; + } + + return cc33xx_lnk_dequeue(cc, lnk, ac); +} + +static struct sk_buff *cc33xx_vif_dequeue_high_prio(struct cc33xx *cc, + struct cc33xx_vif *wlvif, + u8 ac, u8 *hlid, + u8 *low_prio_hlid) +{ + struct sk_buff *skb = NULL; + int i, h, start_hlid; + + /* start from the link after the last one */ + start_hlid = (wlvif->last_tx_hlid + 1) % CC33XX_MAX_LINKS; + + /* dequeue according to AC, round robin on each link */ + for (i = 0; i < CC33XX_MAX_LINKS; i++) { + h = (start_hlid + i) % CC33XX_MAX_LINKS; + + /* only consider connected stations */ + if (!test_bit(h, wlvif->links_map)) + continue; + + skb = cc33xx_lnk_dequeue_high_prio(cc, h, ac, low_prio_hlid); + if (!skb) + continue; + + wlvif->last_tx_hlid = h; + break; + } + + if (!skb) + wlvif->last_tx_hlid = 0; + + *hlid = wlvif->last_tx_hlid; + return skb; +} + +static struct sk_buff *cc33xx_skb_dequeue(struct cc33xx *cc, u8 *hlid) +{ + unsigned long flags; + struct cc33xx_vif *wlvif = cc->last_wlvif; + struct sk_buff *skb = NULL; + int ac; + u8 low_prio_hlid = CC33XX_INVALID_LINK_ID; + + ac = cc33xx_select_ac(cc); + if (ac < 0) + goto out; + + /* continue from last wlvif (round robin) */ + if (wlvif) { + cc33xx_for_each_wlvif_continue(cc, wlvif) { + if (!wlvif->tx_queue_count[ac]) + continue; + + skb = cc33xx_vif_dequeue_high_prio(cc, wlvif, ac, hlid, + &low_prio_hlid); + if (!skb) + continue; + + cc->last_wlvif = wlvif; + break; + } + } + + /* dequeue from the system HLID before the restarting wlvif list */ + if (!skb) { + skb = cc33xx_lnk_dequeue_high_prio(cc, CC33XX_SYSTEM_HLID, + ac, &low_prio_hlid); + if (skb) { + *hlid = CC33XX_SYSTEM_HLID; + cc->last_wlvif = NULL; + } + } + + /* Do a new pass over the wlvif list. But no need to continue + * after last_wlvif. The previous pass should have found it. + */ + if (!skb) { + cc33xx_for_each_wlvif(cc, wlvif) { + if (!wlvif->tx_queue_count[ac]) + goto next; + + skb = cc33xx_vif_dequeue_high_prio(cc, wlvif, ac, hlid, + &low_prio_hlid); + if (skb) { + cc->last_wlvif = wlvif; + break; + } + +next: + if (wlvif == cc->last_wlvif) + break; + } + } + + /* no high priority skbs found - but maybe a low priority one? */ + if (!skb && low_prio_hlid != CC33XX_INVALID_LINK_ID) { + struct cc33xx_link *lnk = &cc->links[low_prio_hlid]; + + skb = cc33xx_lnk_dequeue(cc, lnk, ac); + + WARN_ON(!skb); /* we checked this before */ + *hlid = low_prio_hlid; + + /* ensure proper round robin in the vif/link levels */ + cc->last_wlvif = lnk->wlvif; + if (lnk->wlvif) + lnk->wlvif->last_tx_hlid = low_prio_hlid; + } + +out: + if (!skb && + test_and_clear_bit(CC33XX_FLAG_DUMMY_PACKET_PENDING, &cc->flags)) { + int q; + + skb = cc->dummy_packet; + *hlid = CC33XX_SYSTEM_HLID; + q = cc33xx_tx_get_queue(skb_get_queue_mapping(skb)); + spin_lock_irqsave(&cc->cc_lock, flags); + WARN_ON_ONCE(cc->tx_queue_count[q] <= 0); + cc->tx_queue_count[q]--; + spin_unlock_irqrestore(&cc->cc_lock, flags); + } + + return skb; +} + +static void cc33xx_skb_queue_head(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct sk_buff *skb, u8 hlid) +{ + unsigned long flags; + int q = cc33xx_tx_get_queue(skb_get_queue_mapping(skb)); + + if (cc33xx_is_dummy_packet(cc, skb)) { + set_bit(CC33XX_FLAG_DUMMY_PACKET_PENDING, &cc->flags); + } else { + skb_queue_head(&cc->links[hlid].tx_queue[q], skb); + + /* make sure we dequeue the same packet next time */ + wlvif->last_tx_hlid = (hlid + CC33XX_MAX_LINKS - 1) % + CC33XX_MAX_LINKS; + } + + spin_lock_irqsave(&cc->cc_lock, flags); + cc->tx_queue_count[q]++; + if (wlvif) + wlvif->tx_queue_count[q]++; + spin_unlock_irqrestore(&cc->cc_lock, flags); +} + +static inline bool cc33xx_tx_is_data_present(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + + return ieee80211_is_data_present(hdr->frame_control); +} + +/* Returns failure values only in case of failed bus ops within this function. + * cc33xx_prepare_tx_frame retvals won't be returned in order to avoid + * triggering recovery by higher layers when not necessary. + * In case a FW command fails within cc33xx_prepare_tx_frame fails a recovery + * will be queued in cc33xx_cmd_send. -EAGAIN/-EBUSY from prepare_tx_frame + * can occur and are legitimate so don't propagate. -EINVAL will emit a WARNING + * within prepare_tx_frame code but there's nothing we should do about those + * as well. + */ +int cc33xx_tx_work_locked(struct cc33xx *cc) +{ + struct cc33xx_vif *wlvif; + struct sk_buff *skb; + struct cc33xx_tx_hw_descr *desc; + u32 buf_offset = 0, last_len = 0; + u32 transfer_len = 0; + u32 padding_size = 0; + bool sent_packets = false; + unsigned long active_hlids[BITS_TO_LONGS(CC33XX_MAX_LINKS)] = {0}; + int ret = 0; + int bus_ret = 0; + u8 hlid; + + memset(cc->aggr_buf, 0, 0x300); + if (unlikely(cc->state != CC33XX_STATE_ON)) + return 0; + + while ((skb = cc33xx_skb_dequeue(cc, &hlid))) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + bool has_data = false; + + cc33xx_debug(DEBUG_TX, "skb dequeue skb: 0x%p data %#lx head %#lx tail %#lx end %#lx", + skb, + (unsigned long)skb->data, (unsigned long)skb->head, + (unsigned long)skb->tail, (unsigned long)skb->end); + wlvif = NULL; + if (!cc33xx_is_dummy_packet(cc, skb)) + wlvif = cc33xx_vif_to_data(info->control.vif); + else + hlid = CC33XX_SYSTEM_HLID; + + has_data = wlvif && cc33xx_tx_is_data_present(skb); + ret = cc33xx_prepare_tx_frame(cc, wlvif, skb, buf_offset, + hlid); + + if (ret == -EAGAIN) { + /* Aggregation buffer is full. + * Flush buffer and try again. + */ + cc33xx_skb_queue_head(cc, wlvif, skb, hlid); + + transfer_len = __ALIGN_MASK(buf_offset, + CC33XX_BUS_BLOCK_SIZE * 2 - 1); + + padding_size = transfer_len - buf_offset; + memset(cc->aggr_buf + buf_offset, 0x33, padding_size); + + cc33xx_debug(DEBUG_TX, "sdio transaction length: %d ", + transfer_len); + + bus_ret = cc33xx_write(cc, NAB_DATA_ADDR, cc->aggr_buf, + transfer_len, true); + if (bus_ret < 0) + goto out; + + sent_packets = true; + buf_offset = 0; + continue; + } else if (ret == -EBUSY) { + /* Firmware buffer is full. + * Queue back last skb, and stop aggregating. + */ + cc33xx_skb_queue_head(cc, wlvif, skb, hlid); + /* No work left, avoid scheduling redundant tx work */ + set_bit(CC33XX_FLAG_FW_TX_BUSY, &cc->flags); + goto out_ack; + } else if (ret < 0) { + if (cc33xx_is_dummy_packet(cc, skb)) + /* fw still expects dummy packet, + * so re-enqueue it + */ + cc33xx_skb_queue_head(cc, wlvif, skb, hlid); + else + ieee80211_free_txskb(cc->hw, skb); + goto out_ack; + } + + last_len = ret; + buf_offset += last_len; + + if (has_data) { + desc = (struct cc33xx_tx_hw_descr *)skb->data; + __set_bit(desc->hlid, active_hlids); + } + } + +out_ack: + if (buf_offset) { + transfer_len = __ALIGN_MASK(buf_offset, + CC33XX_BUS_BLOCK_SIZE * 2 - 1); + + padding_size = transfer_len - buf_offset; + memset(cc->aggr_buf + buf_offset, 0x33, padding_size); + + cc33xx_debug(DEBUG_TX, "sdio transaction (926) length: %d ", + transfer_len); + + bus_ret = cc33xx_write(cc, NAB_DATA_ADDR, cc->aggr_buf, + transfer_len, true); + if (bus_ret < 0) + goto out; + + sent_packets = true; + } + + if (sent_packets) + cc33xx_handle_tx_low_watermark(cc); + +out: + return bus_ret; +} + +void cc33xx_tx_work(struct work_struct *work) +{ + struct cc33xx *cc = container_of(work, struct cc33xx, tx_work); + int ret; + + mutex_lock(&cc->mutex); + + ret = cc33xx_tx_work_locked(cc); + if (ret < 0) { + cc33xx_queue_recovery_work(cc); + goto out; + } + +out: + mutex_unlock(&cc->mutex); +} + +void cc33xx_tx_reset_link_queues(struct cc33xx *cc, u8 hlid) +{ + struct sk_buff *skb; + int i; + unsigned long flags; + struct ieee80211_tx_info *info; + int total[NUM_TX_QUEUES]; + struct cc33xx_link *lnk = &cc->links[hlid]; + + for (i = 0; i < NUM_TX_QUEUES; i++) { + total[i] = 0; + while ((skb = skb_dequeue(&lnk->tx_queue[i]))) { + cc33xx_debug(DEBUG_TX, "link freeing skb 0x%p", skb); + + if (!cc33xx_is_dummy_packet(cc, skb)) { + info = IEEE80211_SKB_CB(skb); + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; + ieee80211_tx_status_ni(cc->hw, skb); + } + + total[i]++; + } + } + + spin_lock_irqsave(&cc->cc_lock, flags); + for (i = 0; i < NUM_TX_QUEUES; i++) { + cc->tx_queue_count[i] -= total[i]; + if (lnk->wlvif) + lnk->wlvif->tx_queue_count[i] -= total[i]; + } + spin_unlock_irqrestore(&cc->cc_lock, flags); + + cc33xx_handle_tx_low_watermark(cc); +} + +/* caller must hold cc->mutex and TX must be stopped */ +void cc33xx_tx_reset_wlvif(struct cc33xx *cc, struct cc33xx_vif *wlvif) +{ + int i; + + /* TX failure */ + for_each_set_bit(i, wlvif->links_map, CC33XX_MAX_LINKS) { + if (wlvif->bss_type == BSS_TYPE_AP_BSS && + i != wlvif->ap.bcast_hlid && + i != wlvif->ap.global_hlid) { + /* this calls cc33xx_clear_link */ + cc33xx_free_sta(cc, wlvif, i); + } else { + u8 hlid = i; + + cc33xx_clear_link(cc, wlvif, &hlid); + } + } + + wlvif->last_tx_hlid = 0; + + for (i = 0; i < NUM_TX_QUEUES; i++) + wlvif->tx_queue_count[i] = 0; +} + +int cc33xx_tx_total_queue_count(struct cc33xx *cc) +{ + int i, count = 0; + + for (i = 0; i < NUM_TX_QUEUES; i++) + count += cc->tx_queue_count[i]; + + return count; +} + +/* caller must hold cc->mutex and TX must be stopped */ +void cc33xx_tx_reset(struct cc33xx *cc) +{ + int i; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + + /* only reset the queues if something bad happened */ + if (cc33xx_tx_total_queue_count(cc) != 0) { + for (i = 0; i < CC33XX_MAX_LINKS; i++) + cc33xx_tx_reset_link_queues(cc, i); + + for (i = 0; i < NUM_TX_QUEUES; i++) + cc->tx_queue_count[i] = 0; + } + + /* Make sure the driver is at a consistent state, in case this + * function is called from a context other than interface removal. + * This call will always wake the TX queues. + */ + cc33xx_handle_tx_low_watermark(cc); + + for (i = 0; i < CC33XX_NUM_TX_DESCRIPTORS; i++) { + if (!cc->tx_frames[i]) + continue; + + skb = cc->tx_frames[i]; + cc33xx_free_tx_id(cc, i); + cc33xx_debug(DEBUG_TX, "freeing skb 0x%p", skb); + + if (!cc33xx_is_dummy_packet(cc, skb)) { + /* Remove private headers before passing the skb to + * mac80211 + */ + info = IEEE80211_SKB_CB(skb); + skb_pull(skb, sizeof(struct cc33xx_tx_hw_descr)); + if ((cc->quirks & CC33XX_QUIRK_TKIP_HEADER_SPACE) && + info->control.hw_key && + info->control.hw_key->cipher == + WLAN_CIPHER_SUITE_TKIP) { + int hdrlen = ieee80211_get_hdrlen_from_skb(skb); + + memmove(skb->data + CC33XX_EXTRA_SPACE_TKIP, + skb->data, hdrlen); + skb_pull(skb, CC33XX_EXTRA_SPACE_TKIP); + } + + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; + + ieee80211_tx_status_ni(cc->hw, skb); + } + } +} + +#define CC33XX_TX_FLUSH_TIMEOUT 500000 + +/* caller must *NOT* hold cc->mutex */ +void cc33xx_tx_flush(struct cc33xx *cc) +{ + unsigned long timeout, start_time; + int i; + + start_time = jiffies; + timeout = start_time + usecs_to_jiffies(CC33XX_TX_FLUSH_TIMEOUT); + + /* only one flush should be in progress, for consistent queue state */ + mutex_lock(&cc->flush_mutex); + + mutex_lock(&cc->mutex); + if (cc->tx_frames_cnt == 0 && cc33xx_tx_total_queue_count(cc) == 0) { + mutex_unlock(&cc->mutex); + goto out; + } + + cc33xx_stop_queues(cc, CC33XX_QUEUE_STOP_REASON_FLUSH); + + while (!time_after(jiffies, timeout)) { + cc33xx_debug(DEBUG_MAC80211, "flushing tx buffer: %d %d", + cc->tx_frames_cnt, + cc33xx_tx_total_queue_count(cc)); + + /* force Tx and give the driver some time to flush data */ + mutex_unlock(&cc->mutex); + if (cc33xx_tx_total_queue_count(cc)) + cc33xx_tx_work(&cc->tx_work); + msleep(20); + mutex_lock(&cc->mutex); + + if (cc->tx_frames_cnt == 0 && cc33xx_tx_total_queue_count(cc) == 0) { + cc33xx_debug(DEBUG_MAC80211, "tx flush took %d ms", + jiffies_to_msecs(jiffies - start_time)); + goto out_wake; + } + } + + cc33xx_warning("Unable to flush all TX buffers, timed out (timeout %d ms", + CC33XX_TX_FLUSH_TIMEOUT / 1000); + + /* forcibly flush all Tx buffers on our queues */ + for (i = 0; i < CC33XX_MAX_LINKS; i++) + cc33xx_tx_reset_link_queues(cc, i); + +out_wake: + cc33xx_wake_queues(cc, CC33XX_QUEUE_STOP_REASON_FLUSH); + mutex_unlock(&cc->mutex); +out: + mutex_unlock(&cc->flush_mutex); +} + +u32 cc33xx_tx_min_rate_get(struct cc33xx *cc, u32 rate_set) +{ + if (WARN_ON(!rate_set)) + return 0; + + return BIT(__ffs(rate_set)); +} + +void cc33xx_stop_queue_locked(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 queue, enum cc33xx_queue_stop_reason reason) +{ + int hwq = cc33xx_tx_get_mac80211_queue(wlvif, queue); + bool stopped = !!cc->queue_stop_reasons[hwq]; + + /* queue should not be stopped for this reason */ + WARN_ON_ONCE(test_and_set_bit(reason, &cc->queue_stop_reasons[hwq])); + + if (stopped) + return; + + ieee80211_stop_queue(cc->hw, hwq); +} + +void cc33xx_stop_queues(struct cc33xx *cc, + enum cc33xx_queue_stop_reason reason) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&cc->cc_lock, flags); + + /* mark all possible queues as stopped */ + for (i = 0; i < CC33XX_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++) { + WARN_ON_ONCE(test_and_set_bit(reason, + &cc->queue_stop_reasons[i])); + } + + /* use the global version to make sure all vifs in mac80211 we don't + * know are stopped. + */ + ieee80211_stop_queues(cc->hw); + + spin_unlock_irqrestore(&cc->cc_lock, flags); +} + +void cc33xx_wake_queues(struct cc33xx *cc, + enum cc33xx_queue_stop_reason reason) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&cc->cc_lock, flags); + + /* mark all possible queues as awake */ + for (i = 0; i < CC33XX_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++) { + WARN_ON_ONCE(!test_and_clear_bit(reason, + &cc->queue_stop_reasons[i])); + } + + /* use the global version to make sure all vifs in mac80211 we don't + * know are woken up. + */ + ieee80211_wake_queues(cc->hw); + + spin_unlock_irqrestore(&cc->cc_lock, flags); +} + +bool cc33xx_is_queue_stopped_by_reason(struct cc33xx *cc, + struct cc33xx_vif *wlvif, u8 queue, + enum cc33xx_queue_stop_reason reason) +{ + unsigned long flags; + bool stopped; + + spin_lock_irqsave(&cc->cc_lock, flags); + stopped = cc33xx_is_queue_stopped_by_reason_locked(cc, wlvif, queue, + reason); + spin_unlock_irqrestore(&cc->cc_lock, flags); + + return stopped; +} + +bool cc33xx_is_queue_stopped_by_reason_locked(struct cc33xx *cc, + struct cc33xx_vif *wlvif, u8 queue, + enum cc33xx_queue_stop_reason reason) +{ + int hwq = cc33xx_tx_get_mac80211_queue(wlvif, queue); + + assert_spin_locked(&cc->cc_lock); + return test_bit(reason, &cc->queue_stop_reasons[hwq]); +} + +bool cc33xx_is_queue_stopped_locked(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 queue) +{ + int hwq = cc33xx_tx_get_mac80211_queue(wlvif, queue); + + assert_spin_locked(&cc->cc_lock); + return !!cc->queue_stop_reasons[hwq]; +} + +static void cc33xx_tx_complete_packet(struct cc33xx *cc, u8 tx_stat_byte, + struct core_fw_status *core_fw_status) +{ + struct ieee80211_tx_info *info; + struct sk_buff *skb; + int id = tx_stat_byte & CC33XX_TX_STATUS_DESC_ID_MASK; + bool tx_success; + struct cc33xx_tx_hw_descr *tx_desc; + u16 desc_session_idx; + + /* check for id legality */ + if (unlikely(id >= CC33XX_NUM_TX_DESCRIPTORS || + !cc->tx_frames[id])) { + cc33xx_warning("illegal id in tx completion: %d", id); + + print_hex_dump(KERN_DEBUG, "fw_info local:", + DUMP_PREFIX_OFFSET, 16, 4, (u8 *)(core_fw_status), + sizeof(struct core_fw_status), false); + + cc33xx_queue_recovery_work(cc); + return; + } + + /* a zero bit indicates Tx success */ + tx_success = !(tx_stat_byte & BIT(CC33XX_TX_STATUS_STAT_BIT_IDX)); + + skb = cc->tx_frames[id]; + info = IEEE80211_SKB_CB(skb); + tx_desc = (struct cc33xx_tx_hw_descr *)skb->data; + + if (cc33xx_is_dummy_packet(cc, skb)) { + cc33xx_free_tx_id(cc, id); + return; + } + + /* update the TX status info */ + if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = 1; /* no data about retries */ + info->status.ack_signal = -1; + + if (!tx_success) + cc->stats.retry_count++; + + /* remove private header from packet */ + skb_pull(skb, sizeof(struct cc33xx_tx_hw_descr)); + + /* remove TKIP header space if present */ + if ((cc->quirks & CC33XX_QUIRK_TKIP_HEADER_SPACE) && + info->control.hw_key && + info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { + int hdrlen = ieee80211_get_hdrlen_from_skb(skb); + + memmove(skb->data + CC33XX_EXTRA_SPACE_TKIP, skb->data, hdrlen); + skb_pull(skb, CC33XX_EXTRA_SPACE_TKIP); + } + + cc33xx_debug(DEBUG_TX, + "tx status id %u skb 0x%p success %d, tx_memblocks %d", + id, skb, tx_success, tx_desc->cc33xx_mem.total_mem_blocks); + + /** + * in order to update the memory management + * we should have total_blocks, ac, and hlid + */ + cc->tx_blocks_available += tx_desc->cc33xx_mem.total_mem_blocks; + cc->tx_allocated_blocks -= tx_desc->cc33xx_mem.total_mem_blocks; + /* per queue */ + + /* prevent wrap-around in freed-packets counter */ + cc->tx_allocated_pkts[tx_desc->ac]--; + + /* per link */ + desc_session_idx = (le16_to_cpu(tx_desc->tx_attr) & TX_HW_ATTR_SESSION_COUNTER) >> + TX_HW_ATTR_OFST_SESSION_COUNTER; + + if (cc->session_ids[tx_desc->hlid] == desc_session_idx) + cc->links[tx_desc->hlid].allocated_pkts--; + + cc33xx_free_tx_id(cc, id); + + /* new mem blocks are available now */ + clear_bit(CC33XX_FLAG_FW_TX_BUSY, &cc->flags); + + /* return the packet to the stack */ + skb_queue_tail(&cc->deferred_tx_queue, skb); + queue_work(cc->freezable_wq, &cc->netstack_work); +} + +void cc33xx_tx_immediate_complete(struct cc33xx *cc) +{ + u8 tx_result_queue_index; + struct core_fw_status core_fw_status; + u8 i; + + claim_core_status_lock(cc); + memcpy(&core_fw_status, &cc->core_status->fw_info, + sizeof(struct core_fw_status)); + + tx_result_queue_index = cc->core_status->fw_info.tx_result_queue_index; + /* Lock guarantees we shadow tx_result_queue_index NOT during + * an active transaction. Subsequent references to fw_info can be done + * without locking as long we do not pass this index. + */ + release_core_status_lock(cc); + + cc33xx_debug(DEBUG_TX, "last released desc = %d, current idx = %d", + cc->last_fw_rls_idx, tx_result_queue_index); + + /* nothing to do here */ + if (cc->last_fw_rls_idx == tx_result_queue_index) + return; + + /* freed Tx descriptors */ + + if (tx_result_queue_index >= TX_RESULT_QUEUE_SIZE) { + cc33xx_error("invalid desc release index %d", + tx_result_queue_index); + WARN_ON(1); + return; + } + + cc33xx_debug(DEBUG_TX, "TX result queue! priv last fw idx %d, current resut index %d ", + cc->last_fw_rls_idx, tx_result_queue_index); + + for (i = cc->last_fw_rls_idx; i != tx_result_queue_index; + i = (i + 1) % TX_RESULT_QUEUE_SIZE) { + cc33xx_tx_complete_packet(cc, core_fw_status.tx_result_queue[i], + &core_fw_status); + } + + cc->last_fw_rls_idx = tx_result_queue_index; +} diff -Naur --no-dereference a/drivers/net/wireless/ti/cc33xx/tx.h b/drivers/net/wireless/ti/cc33xx/tx.h --- a/drivers/net/wireless/ti/cc33xx/tx.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/net/wireless/ti/cc33xx/tx.h 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#ifndef __TX_H__ +#define __TX_H__ + +#define CC33XX_TX_HW_BLOCK_SPARE 1 +/* for special cases - namely, TKIP and GEM */ +#define CC33XX_TX_HW_EXTRA_BLOCK_SPARE 2 +#define CC33XX_TX_HW_BLOCK_SIZE 256 + +#define CC33XX_TX_STATUS_DESC_ID_MASK 0x7F +#define CC33XX_TX_STATUS_STAT_BIT_IDX 7 + +/* Indicates this TX HW frame is not padded to SDIO block size */ +#define CC33XX_TX_CTRL_NOT_PADDED BIT(7) + +#define TX_HW_MGMT_PKT_LIFETIME_TU 2000 +#define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000 + +#define TX_HW_ATTR_SESSION_COUNTER (BIT(2) | BIT(3) | BIT(4)) +#define TX_HW_ATTR_TX_DUMMY_REQ BIT(13) +#define TX_HW_ATTR_HOST_ENCRYPT BIT(14) +#define TX_HW_ATTR_EAPOL_FRAME BIT(15) + +#define TX_HW_ATTR_OFST_SESSION_COUNTER 2 +#define TX_HW_ATTR_OFST_RATE_POLICY 5 + +#define CC33XX_TX_ALIGN_TO 4 +#define CC33XX_EXTRA_SPACE_TKIP 4 +#define CC33XX_EXTRA_SPACE_AES 8 +#define CC33XX_EXTRA_SPACE_MAX 8 + +#define CC33XX_TX_EXTRA_HEADROOM \ + (sizeof(struct cc33xx_tx_hw_descr) + IEEE80211_HT_CTL_LEN) + +/* Used for management frames and dummy packets */ +#define CC33XX_TID_MGMT 7 + +/* stop a ROC for pending authentication reply after this time (ms) */ +#define CC33XX_PEND_AUTH_ROC_TIMEOUT 1000 +#define CC33xx_PEND_ROC_COMPLETE_TIMEOUT 2000 + +struct cc33xx_tx_mem { + /* Total number of memory blocks allocated by the host for + * this packet. + */ + u8 total_mem_blocks; + + /* control bits + */ + u8 ctrl; +} __packed; + +/* On cc33xx based devices, when TX packets are aggregated, each packet + * size must be aligned to the SDIO block size. The maximum block size + * is bounded by the type of the padded bytes field that is sent to the + * FW. The HW maximum block size is 256 bytes. We use 128 to utilize the + * SDIO built-in busy signal when the FIFO is full. + */ +#define CC33XX_BUS_BLOCK_SIZE 128 + +struct cc33xx_tx_hw_descr { + /* Length of packet in words, including descriptor+header+data */ + __le16 length; + + struct cc33xx_tx_mem cc33xx_mem; + + /* Packet identifier used also in the Tx-Result. */ + u8 id; + /* The packet TID value (as User-Priority) */ + u8 tid; + /* host link ID (HLID) */ + u8 hlid; + u8 ac; + /* Max delay in TUs until transmission. The last device time the + * packet can be transmitted is: start_time + (1024 * life_time) + */ + __le16 life_time; + /* Bitwise fields - see TX_ATTR... definitions above. */ + __le16 tx_attr; +} __packed; + +struct cc33xx_tx_hw_res_descr { + /* Packet Identifier - same value used in the Tx descriptor.*/ + u8 id; + /* The status of the transmission, indicating success or one of + * several possible reasons for failure. + */ + u8 status; + /* Total air access duration including all retrys and overheads.*/ + __le16 medium_usage; + /* The time passed from host xfer to Tx-complete.*/ + __le32 fw_handling_time; + /* Total media delay + * (from 1st EDCA AIFS counter until TX Complete). + */ + __le32 medium_delay; + /* LS-byte of last TKIP seq-num (saved per AC for recovery). */ + u8 tx_security_sequence_number_lsb; + /* Retry count - number of transmissions without successful ACK.*/ + u8 ack_failures; + /* The rate that succeeded getting ACK + * (Valid only if status=SUCCESS). + */ + u8 rate_class_index; + /* for 4-byte alignment. */ + u8 spare; +} __packed; + +enum cc33xx_queue_stop_reason { + CC33XX_QUEUE_STOP_REASON_WATERMARK, + CC33XX_QUEUE_STOP_REASON_FW_RESTART, + CC33XX_QUEUE_STOP_REASON_FLUSH, + CC33XX_QUEUE_STOP_REASON_SPARE_BLK, /* 18xx specific */ +}; + +int cc33xx_tx_get_queue(int queue); +int cc33xx_tx_total_queue_count(struct cc33xx *cc); +void cc33xx_tx_immediate_complete(struct cc33xx *cc); +void cc33xx_tx_work(struct work_struct *work); +int cc33xx_tx_work_locked(struct cc33xx *cc); +void cc33xx_tx_reset_wlvif(struct cc33xx *cc, struct cc33xx_vif *wlvif); +void cc33xx_tx_reset(struct cc33xx *cc); +void cc33xx_tx_flush(struct cc33xx *cc); +u8 cc33xx_rate_to_idx(struct cc33xx *cc, u8 rate, enum nl80211_band band); +u32 cc33xx_tx_enabled_rates_get(struct cc33xx *cc, u32 rate_set, + enum nl80211_band rate_band); +u32 cc33xx_tx_min_rate_get(struct cc33xx *cc, u32 rate_set); +u8 cc33xx_tx_get_hlid(struct cc33xx *cc, struct cc33xx_vif *wlvif, + struct sk_buff *skb, struct ieee80211_sta *sta); +void cc33xx_tx_reset_link_queues(struct cc33xx *cc, u8 hlid); +void cc33xx_handle_tx_low_watermark(struct cc33xx *cc); +bool cc33xx_is_dummy_packet(struct cc33xx *cc, struct sk_buff *skb); +unsigned int cc33xx_calc_packet_alignment(struct cc33xx *cc, + unsigned int packet_length); +void cc33xx_free_tx_id(struct cc33xx *cc, int id); +void cc33xx_stop_queue_locked(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 queue, enum cc33xx_queue_stop_reason reason); +void cc33xx_stop_queues(struct cc33xx *cc, + enum cc33xx_queue_stop_reason reason); +void cc33xx_wake_queues(struct cc33xx *cc, + enum cc33xx_queue_stop_reason reason); +bool cc33xx_is_queue_stopped_by_reason(struct cc33xx *cc, + struct cc33xx_vif *wlvif, u8 queue, + enum cc33xx_queue_stop_reason reason); +bool cc33xx_is_queue_stopped_by_reason_locked(struct cc33xx *cc, + struct cc33xx_vif *wlvif, + u8 queue, + enum cc33xx_queue_stop_reason reason); +bool cc33xx_is_queue_stopped_locked(struct cc33xx *cc, struct cc33xx_vif *wlvif, + u8 queue); + +/* from main.c */ +void cc33xx_free_sta(struct cc33xx *cc, struct cc33xx_vif *wlvif, u8 hlid); +void cc33xx_rearm_tx_watchdog_locked(struct cc33xx *cc); + +#endif /* __TX_H__ */ diff -Naur --no-dereference a/drivers/net/wireless/ti/Kconfig b/drivers/net/wireless/ti/Kconfig --- a/drivers/net/wireless/ti/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/wireless/ti/Kconfig 2024-07-07 20:37:34.668306669 -0400 @@ -14,6 +14,7 @@ source "drivers/net/wireless/ti/wl1251/Kconfig" source "drivers/net/wireless/ti/wl12xx/Kconfig" source "drivers/net/wireless/ti/wl18xx/Kconfig" +source "drivers/net/wireless/ti/cc33xx/Kconfig" # keep last for automatic dependencies source "drivers/net/wireless/ti/wlcore/Kconfig" diff -Naur --no-dereference a/drivers/net/wireless/ti/Makefile b/drivers/net/wireless/ti/Makefile --- a/drivers/net/wireless/ti/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/net/wireless/ti/Makefile 2024-07-07 20:37:34.668306669 -0400 @@ -3,3 +3,4 @@ obj-$(CONFIG_WL12XX) += wl12xx/ obj-$(CONFIG_WL1251) += wl1251/ obj-$(CONFIG_WL18XX) += wl18xx/ +obj-$(CONFIG_CC33XX) += cc33xx/ \ No newline at end of file diff -Naur --no-dereference a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h --- a/drivers/pci/controller/cadence/pcie-cadence.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/pci/controller/cadence/pcie-cadence.h 2024-07-07 20:37:34.672306689 -0400 @@ -515,10 +515,22 @@ } #ifdef CONFIG_PCIE_CADENCE_HOST +int cdns_pcie_host_link_setup(struct cdns_pcie_rc *rc); +int cdns_pcie_host_init(struct cdns_pcie_rc *rc); int cdns_pcie_host_setup(struct cdns_pcie_rc *rc); void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn, int where); #else +static inline int cdns_pcie_host_link_setup(struct cdns_pcie_rc *rc) +{ + return 0; +} + +static inline int cdns_pcie_host_init(struct cdns_pcie_rc *rc) +{ + return 0; +} + static inline int cdns_pcie_host_setup(struct cdns_pcie_rc *rc) { return 0; diff -Naur --no-dereference a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c --- a/drivers/pci/controller/cadence/pcie-cadence-host.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/pci/controller/cadence/pcie-cadence-host.c 2024-07-07 20:37:34.672306689 -0400 @@ -485,8 +485,7 @@ return cdns_pcie_host_map_dma_ranges(rc); } -static int cdns_pcie_host_init(struct device *dev, - struct cdns_pcie_rc *rc) +int cdns_pcie_host_init(struct cdns_pcie_rc *rc) { int err; @@ -497,6 +496,30 @@ return cdns_pcie_host_init_address_translation(rc); } +int cdns_pcie_host_link_setup(struct cdns_pcie_rc *rc) +{ + struct cdns_pcie *pcie = &rc->pcie; + struct device *dev = rc->pcie.dev; + int ret; + + if (rc->quirk_detect_quiet_flag) + cdns_pcie_detect_quiet_min_delay_set(&rc->pcie); + + cdns_pcie_host_enable_ptm_response(pcie); + + ret = cdns_pcie_start_link(pcie); + if (ret) { + dev_err(dev, "Failed to start link\n"); + return ret; + } + + ret = cdns_pcie_host_start_link(rc); + if (ret) + dev_dbg(dev, "PCIe link never came up\n"); + + return 0; +} + int cdns_pcie_host_setup(struct cdns_pcie_rc *rc) { struct device *dev = rc->pcie.dev; @@ -533,25 +556,14 @@ return PTR_ERR(rc->cfg_base); rc->cfg_res = res; - if (rc->quirk_detect_quiet_flag) - cdns_pcie_detect_quiet_min_delay_set(&rc->pcie); - - cdns_pcie_host_enable_ptm_response(pcie); - - ret = cdns_pcie_start_link(pcie); - if (ret) { - dev_err(dev, "Failed to start link\n"); - return ret; - } - - ret = cdns_pcie_host_start_link(rc); + ret = cdns_pcie_host_link_setup(rc); if (ret) - dev_dbg(dev, "PCIe link never came up\n"); + return ret; for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) rc->avail_ib_bar[bar] = true; - ret = cdns_pcie_host_init(dev, rc); + ret = cdns_pcie_host_init(rc); if (ret) return ret; diff -Naur --no-dereference a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c --- a/drivers/pci/controller/cadence/pci-j721e.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/pci/controller/cadence/pci-j721e.c 2024-07-07 20:37:34.672306689 -0400 @@ -7,6 +7,8 @@ */ #include +#include +#include #include #include #include @@ -22,6 +24,8 @@ #include "../../pci.h" #include "pcie-cadence.h" +#define cdns_pcie_to_rc(p) container_of(p, struct cdns_pcie_rc, pcie) + #define ENABLE_REG_SYS_2 0x108 #define STATUS_REG_SYS_2 0x508 #define STATUS_CLR_REG_SYS_2 0x708 @@ -42,18 +46,18 @@ }; #define J721E_MODE_RC BIT(7) -#define LANE_COUNT_MASK BIT(8) #define LANE_COUNT(n) ((n) << 8) +#define ACSPCIE_PAD_ENABLE_MASK GENMASK(1, 0) #define GENERATION_SEL_MASK GENMASK(1, 0) -#define MAX_LANES 2 - struct j721e_pcie { struct cdns_pcie *cdns_pcie; struct clk *refclk; u32 mode; u32 num_lanes; + u32 max_lanes; + struct gpio_desc *reset_gpio; void __iomem *user_cfg_base; void __iomem *intd_cfg_base; u32 linkdown_irq_regfield; @@ -71,6 +75,7 @@ unsigned int quirk_disable_flr:1; u32 linkdown_irq_regfield; unsigned int byte_access_allowed:1; + unsigned int max_lanes; }; static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset) @@ -206,17 +211,45 @@ { struct device *dev = pcie->cdns_pcie->dev; u32 lanes = pcie->num_lanes; + u32 mask = BIT(8); u32 val = 0; int ret; + if (pcie->max_lanes == 4) + mask = GENMASK(9, 8); + val = LANE_COUNT(lanes - 1); - ret = regmap_update_bits(syscon, offset, LANE_COUNT_MASK, val); + ret = regmap_update_bits(syscon, offset, mask, val); if (ret) dev_err(dev, "failed to set link count\n"); return ret; } +static int j721e_acspcie_pad_enable(struct j721e_pcie *pcie, struct regmap *syscon) +{ + struct device *dev = pcie->cdns_pcie->dev; + struct device_node *node = dev->of_node; + u32 mask = ACSPCIE_PAD_ENABLE_MASK; + struct of_phandle_args args; + u32 val; + int ret; + + ret = of_parse_phandle_with_fixed_args(node, "ti,syscon-acspcie-proxy-ctrl", + 1, 0, &args); + if (!ret) { + /* PAD Enable Bits have to be cleared to in order to enable output */ + val = ~(args.args[0]); + ret = regmap_update_bits(syscon, 0, mask, val); + if (ret) + dev_err(dev, "Enabling ACSPCIE PAD output failed: %d\n", ret); + } else { + dev_err(dev, "ti,syscon-acspcie-proxy-ctrl has invalid parameters\n"); + } + + return ret; +} + static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie) { struct device *dev = pcie->cdns_pcie->dev; @@ -256,6 +289,14 @@ return ret; } + /* Enable ACSPCIe PAD IO Buffers if the optional property exists */ + syscon = syscon_regmap_lookup_by_phandle_optional(node, "ti,syscon-acspcie-proxy-ctrl"); + if (syscon) { + ret = j721e_acspcie_pad_enable(pcie, syscon); + if (ret) + return ret; + } + return 0; } @@ -290,11 +331,13 @@ .quirk_retrain_flag = true, .byte_access_allowed = false, .linkdown_irq_regfield = LINK_DOWN, + .max_lanes = 2, }; static const struct j721e_pcie_data j721e_pcie_ep_data = { .mode = PCI_MODE_EP, .linkdown_irq_regfield = LINK_DOWN, + .max_lanes = 2, }; static const struct j721e_pcie_data j7200_pcie_rc_data = { @@ -302,23 +345,48 @@ .quirk_detect_quiet_flag = true, .linkdown_irq_regfield = J7200_LINK_DOWN, .byte_access_allowed = true, + .max_lanes = 2, }; static const struct j721e_pcie_data j7200_pcie_ep_data = { .mode = PCI_MODE_EP, .quirk_detect_quiet_flag = true, .quirk_disable_flr = true, + .max_lanes = 2, }; static const struct j721e_pcie_data am64_pcie_rc_data = { .mode = PCI_MODE_RC, .linkdown_irq_regfield = J7200_LINK_DOWN, .byte_access_allowed = true, + .max_lanes = 1, }; static const struct j721e_pcie_data am64_pcie_ep_data = { .mode = PCI_MODE_EP, .linkdown_irq_regfield = J7200_LINK_DOWN, + .max_lanes = 1, +}; + +static const struct j721e_pcie_data j784s4_pcie_rc_data = { + .mode = PCI_MODE_RC, + .quirk_retrain_flag = true, + .byte_access_allowed = false, + .linkdown_irq_regfield = LINK_DOWN, + .max_lanes = 4, +}; + +static const struct j721e_pcie_data j784s4_pcie_ep_data = { + .mode = PCI_MODE_EP, + .linkdown_irq_regfield = LINK_DOWN, + .max_lanes = 4, +}; + +static const struct j721e_pcie_data j722s_pcie_rc_data = { + .mode = PCI_MODE_RC, + .linkdown_irq_regfield = J7200_LINK_DOWN, + .byte_access_allowed = true, + .max_lanes = 1, }; static const struct of_device_id of_j721e_pcie_match[] = { @@ -346,6 +414,18 @@ .compatible = "ti,am64-pcie-ep", .data = &am64_pcie_ep_data, }, + { + .compatible = "ti,j784s4-pcie-host", + .data = &j784s4_pcie_rc_data, + }, + { + .compatible = "ti,j784s4-pcie-ep", + .data = &j784s4_pcie_ep_data, + }, + { + .compatible = "ti,j722s-pcie-host", + .data = &j722s_pcie_rc_data, + }, {}, }; @@ -432,9 +512,13 @@ pcie->user_cfg_base = base; ret = of_property_read_u32(node, "num-lanes", &num_lanes); - if (ret || num_lanes > MAX_LANES) + if (ret || num_lanes > data->max_lanes) { + dev_warn(dev, "num-lanes property not provided or invalid, setting num-lanes to 1\n"); num_lanes = 1; + } + pcie->num_lanes = num_lanes; + pcie->max_lanes = data->max_lanes; if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48))) return -EINVAL; @@ -447,20 +531,20 @@ pm_runtime_enable(dev); ret = pm_runtime_get_sync(dev); if (ret < 0) { - dev_err(dev, "pm_runtime_get_sync failed\n"); + dev_err_probe(dev, ret, "pm_runtime_get_sync failed\n"); goto err_get_sync; } ret = j721e_pcie_ctrl_init(pcie); if (ret < 0) { - dev_err(dev, "pm_runtime_get_sync failed\n"); + dev_err_probe(dev, ret, "pm_runtime_get_sync failed\n"); goto err_get_sync; } ret = devm_request_irq(dev, irq, j721e_pcie_link_irq_handler, 0, "j721e-pcie-link-down-irq", pcie); if (ret < 0) { - dev_err(dev, "failed to request link state IRQ %d\n", irq); + dev_err_probe(dev, ret, "failed to request link state IRQ %d\n", irq); goto err_get_sync; } @@ -470,42 +554,40 @@ case PCI_MODE_RC: gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(gpiod)) { - ret = PTR_ERR(gpiod); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get reset GPIO\n"); + ret = dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get reset GPIO\n"); goto err_get_sync; } + pcie->reset_gpio = gpiod; ret = cdns_pcie_init_phy(dev, cdns_pcie); if (ret) { - dev_err(dev, "Failed to init phy\n"); + dev_err_probe(dev, ret, "Failed to init phy\n"); goto err_get_sync; } clk = devm_clk_get_optional(dev, "pcie_refclk"); if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - dev_err(dev, "failed to get pcie_refclk\n"); + ret = dev_err_probe(dev, PTR_ERR(clk), "failed to get pcie_refclk\n"); goto err_pcie_setup; } ret = clk_prepare_enable(clk); if (ret) { - dev_err(dev, "failed to enable pcie_refclk\n"); + dev_err_probe(dev, ret, "failed to enable pcie_refclk\n"); goto err_pcie_setup; } pcie->refclk = clk; /* - * "Power Sequencing and Reset Signal Timings" table in - * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 3.0 - * indicates PERST# should be deasserted after minimum of 100us - * once REFCLK is stable. The REFCLK to the connector in RC - * mode is selected while enabling the PHY. So deassert PERST# - * after 100 us. + * "Power Sequencing and Reset Signal Timings" table (section + * 2.9.2) in PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, + * REV. 5.1 indicates PERST# should be deasserted after minimum + * of 100us once REFCLK is stable (symbol T_PERST-CLK). + * The REFCLK to the connector in RC mode is selected while + * enabling the PHY. So deassert PERST# after 100 us. */ if (gpiod) { - usleep_range(100, 200); + fsleep(PCIE_T_PERST_CLK_US); gpiod_set_value_cansleep(gpiod, 1); } @@ -519,7 +601,7 @@ case PCI_MODE_EP: ret = cdns_pcie_init_phy(dev, cdns_pcie); if (ret) { - dev_err(dev, "Failed to init phy\n"); + dev_err_probe(dev, ret, "Failed to init phy\n"); goto err_get_sync; } @@ -554,6 +636,87 @@ pm_runtime_disable(dev); } +static int j721e_pcie_suspend_noirq(struct device *dev) +{ + struct j721e_pcie *pcie = dev_get_drvdata(dev); + + if (pcie->mode == PCI_MODE_RC) { + gpiod_set_value_cansleep(pcie->reset_gpio, 0); + clk_disable_unprepare(pcie->refclk); + } + + cdns_pcie_disable_phy(pcie->cdns_pcie); + + return 0; +} + +static int j721e_pcie_resume_noirq(struct device *dev) +{ + struct j721e_pcie *pcie = dev_get_drvdata(dev); + struct cdns_pcie *cdns_pcie = pcie->cdns_pcie; + int ret; + + ret = j721e_pcie_ctrl_init(pcie); + if (ret < 0) + return ret; + + j721e_pcie_config_link_irq(pcie); + + /* + * This is not called explicitly in the probe, it is called by + * cdns_pcie_init_phy(). + */ + ret = cdns_pcie_enable_phy(pcie->cdns_pcie); + if (ret < 0) + return ret; + + if (pcie->mode == PCI_MODE_RC) { + struct cdns_pcie_rc *rc = cdns_pcie_to_rc(cdns_pcie); + + ret = clk_prepare_enable(pcie->refclk); + if (ret < 0) + return ret; + + /* + * "Power Sequencing and Reset Signal Timings" table (section + * 2.9.2) in PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, + * REV. 5.1 indicates PERST# should be deasserted after minimum + * of 100us once REFCLK is stable (symbol T_PERST-CLK). + * The REFCLK to the connector in RC mode is selected while + * enabling the PHY. So deassert PERST# after 100 us. + */ + if (pcie->reset_gpio) { + fsleep(PCIE_T_PERST_CLK_US); + gpiod_set_value_cansleep(pcie->reset_gpio, 1); + } + + ret = cdns_pcie_host_link_setup(rc); + if (ret < 0) { + clk_disable_unprepare(pcie->refclk); + return ret; + } + + /* + * Reset internal status of BARs to force reinitialization in + * cdns_pcie_host_init(). + */ + for (enum cdns_pcie_rp_bar bar = RP_BAR0; bar <= RP_NO_BAR; bar++) + rc->avail_ib_bar[bar] = true; + + ret = cdns_pcie_host_init(rc); + if (ret) { + clk_disable_unprepare(pcie->refclk); + return ret; + } + } + + return 0; +} + +static DEFINE_NOIRQ_DEV_PM_OPS(j721e_pcie_pm_ops, + j721e_pcie_suspend_noirq, + j721e_pcie_resume_noirq); + static struct platform_driver j721e_pcie_driver = { .probe = j721e_pcie_probe, .remove_new = j721e_pcie_remove, @@ -561,6 +724,7 @@ .name = "j721e-pcie", .of_match_table = of_j721e_pcie_match, .suppress_bind_attrs = true, + .pm = pm_sleep_ptr(&j721e_pcie_pm_ops), }, }; builtin_platform_driver(j721e_pcie_driver); diff -Naur --no-dereference a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c --- a/drivers/pci/controller/dwc/pci-keystone.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/pci/controller/dwc/pci-keystone.c 2024-07-07 20:37:34.672306689 -0400 @@ -34,6 +34,11 @@ #define PCIE_DEVICEID_SHIFT 16 /* Application registers */ +#define PID 0x000 +#define RTL GENMASK(15, 11) +#define RTL_SHIFT 11 +#define AM6_PCI_PG1_RTL_VER 0x15 + #define CMD_STATUS 0x004 #define LTSSM_EN_VAL BIT(0) #define OB_XLAT_EN_VAL BIT(1) @@ -104,6 +109,8 @@ #define to_keystone_pcie(x) dev_get_drvdata((x)->dev) +#define PCI_DEVICE_ID_TI_AM654X 0xb00c + struct ks_pcie_of_data { enum dw_pcie_device_mode mode; const struct dw_pcie_host_ops *host_ops; @@ -246,8 +253,68 @@ .irq_unmask = ks_pcie_msi_unmask, }; +/** + * ks_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask registers + * @ks_pcie: A pointer to the keystone_pcie structure which holds the KeyStone + * PCIe host controller driver information. + * + * Since modification of dbi_cs2 involves different clock domain, read the + * status back to ensure the transition is complete. + */ +static void ks_pcie_set_dbi_mode(struct keystone_pcie *ks_pcie) +{ + u32 val; + + val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); + val |= DBI_CS2; + ks_pcie_app_writel(ks_pcie, CMD_STATUS, val); + + do { + val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); + } while (!(val & DBI_CS2)); +} + +/** + * ks_pcie_clear_dbi_mode() - Disable DBI mode + * @ks_pcie: A pointer to the keystone_pcie structure which holds the KeyStone + * PCIe host controller driver information. + * + * Since modification of dbi_cs2 involves different clock domain, read the + * status back to ensure the transition is complete. + */ +static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) +{ + u32 val; + + val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); + val &= ~DBI_CS2; + ks_pcie_app_writel(ks_pcie, CMD_STATUS, val); + + do { + val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); + } while (val & DBI_CS2); +} + static int ks_pcie_msi_host_init(struct dw_pcie_rp *pp) { + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + + /* Configure and set up BAR0 */ + ks_pcie_set_dbi_mode(ks_pcie); + + /* Enable BAR0 */ + dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 1); + dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, SZ_4K - 1); + + ks_pcie_clear_dbi_mode(ks_pcie); + + /* + * For BAR0, just setting bus address for inbound writes (MSI) should + * be sufficient. Use physical address to avoid any conflicts. + */ + dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, ks_pcie->app.start); + pp->msi_irq_chip = &ks_pcie_msi_irq_chip; return dw_pcie_allocate_domains(pp); } @@ -342,48 +409,6 @@ .xlate = irq_domain_xlate_onetwocell, }; -/** - * ks_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask registers - * @ks_pcie: A pointer to the keystone_pcie structure which holds the KeyStone - * PCIe host controller driver information. - * - * Since modification of dbi_cs2 involves different clock domain, read the - * status back to ensure the transition is complete. - */ -static void ks_pcie_set_dbi_mode(struct keystone_pcie *ks_pcie) -{ - u32 val; - - val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); - val |= DBI_CS2; - ks_pcie_app_writel(ks_pcie, CMD_STATUS, val); - - do { - val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); - } while (!(val & DBI_CS2)); -} - -/** - * ks_pcie_clear_dbi_mode() - Disable DBI mode - * @ks_pcie: A pointer to the keystone_pcie structure which holds the KeyStone - * PCIe host controller driver information. - * - * Since modification of dbi_cs2 involves different clock domain, read the - * status back to ensure the transition is complete. - */ -static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) -{ - u32 val; - - val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); - val &= ~DBI_CS2; - ks_pcie_app_writel(ks_pcie, CMD_STATUS, val); - - do { - val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); - } while (val & DBI_CS2); -} - static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) { u32 val; @@ -432,6 +457,17 @@ struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); u32 reg; + /* + * Checking whether the link is up here is a last line of defense + * against platforms that forward errors on the system bus as + * SError upon PCI configuration transactions issued when the link + * is down. This check is racy by definition and does not stop + * the system from triggering an SError if the link goes down + * after this check is performed. + */ + if (!dw_pcie_link_up(pci)) + return NULL; + reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) | CFG_FUNC(PCI_FUNC(devfn)); if (!pci_is_root_bus(bus->parent)) @@ -447,44 +483,10 @@ .write = pci_generic_config_write, }; -/** - * ks_pcie_v3_65_add_bus() - keystone add_bus post initialization - * @bus: A pointer to the PCI bus structure. - * - * This sets BAR0 to enable inbound access for MSI_IRQ register - */ -static int ks_pcie_v3_65_add_bus(struct pci_bus *bus) -{ - struct dw_pcie_rp *pp = bus->sysdata; - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - - if (!pci_is_root_bus(bus)) - return 0; - - /* Configure and set up BAR0 */ - ks_pcie_set_dbi_mode(ks_pcie); - - /* Enable BAR0 */ - dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 1); - dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, SZ_4K - 1); - - ks_pcie_clear_dbi_mode(ks_pcie); - - /* - * For BAR0, just setting bus address for inbound writes (MSI) should - * be sufficient. Use physical address to avoid any conflicts. - */ - dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, ks_pcie->app.start); - - return 0; -} - static struct pci_ops ks_pcie_ops = { .map_bus = dw_pcie_own_conf_map_bus, .read = pci_generic_config_read, .write = pci_generic_config_write, - .add_bus = ks_pcie_v3_65_add_bus, }; /** @@ -527,7 +529,11 @@ static void ks_pcie_quirk(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; + struct keystone_pcie *ks_pcie; + struct device *bridge_dev; struct pci_dev *bridge; + u32 val; + static const struct pci_device_id rc_pci_devids[] = { { PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2HK), .class = PCI_CLASS_BRIDGE_PCI_NORMAL, .class_mask = ~0, }, @@ -539,6 +545,11 @@ .class = PCI_CLASS_BRIDGE_PCI_NORMAL, .class_mask = ~0, }, { 0, }, }; + static const struct pci_device_id am6_pci_devids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654X), + .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, + { 0, }, + }; if (pci_is_root_bus(bus)) bridge = dev; @@ -564,6 +575,32 @@ pcie_set_readrq(dev, 256); } } + + /* + * Memory transactions fail with PCI controller in AM654 PG1.0 + * when MRRS is set to more than 128 Bytes. Force the MRRS to + * 128 Bytes in all downstream devices. + */ + if (pci_match_id(am6_pci_devids, bridge)) { + bridge_dev = pci_get_host_bridge_device(dev); + if (!bridge_dev && !bridge_dev->parent) + return; + + ks_pcie = dev_get_drvdata(bridge_dev->parent); + if (!ks_pcie) + return; + + val = ks_pcie_app_readl(ks_pcie, PID); + val &= RTL; + val >>= RTL_SHIFT; + if (val != AM6_PCI_PG1_RTL_VER) + return; + + if (pcie_get_readrq(dev) > 128) { + dev_info(&dev->dev, "limiting MRRS to 128\n"); + pcie_set_readrq(dev, 128); + } + } } DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, ks_pcie_quirk); @@ -1068,6 +1105,7 @@ static const struct ks_pcie_of_data ks_pcie_rc_of_data = { .host_ops = &ks_pcie_host_ops, + .mode = DW_PCIE_RC_TYPE, .version = DW_PCIE_VER_365A, }; diff -Naur --no-dereference a/drivers/pci/pci.h b/drivers/pci/pci.h --- a/drivers/pci/pci.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/pci/pci.h 2024-07-07 20:37:34.672306689 -0400 @@ -13,6 +13,9 @@ #define PCIE_LINK_RETRAIN_TIMEOUT_MS 1000 +/* REFCLK stable before PERST# inactive from PCIe card Electromechanical Spec */ +#define PCIE_T_PERST_CLK_US 100 + /* * PCIe r6.0, sec 5.3.3.2.1 * Recommends 1ms to 10ms timeout to check L2 ready. diff -Naur --no-dereference a/drivers/phy/cadence/cdns-dphy-rx.c b/drivers/phy/cadence/cdns-dphy-rx.c --- a/drivers/phy/cadence/cdns-dphy-rx.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/phy/cadence/cdns-dphy-rx.c 2024-07-07 20:37:34.672306689 -0400 @@ -12,6 +12,7 @@ #include #include #include +#include #include #define DPHY_PMA_CMN(reg) (reg) @@ -265,6 +266,12 @@ return PTR_ERR(provider); } + /* + * PHY framework handles calls to pm_runtime_(get|put) when + * phy_power_(on|off) hooks are called + */ + devm_pm_runtime_enable(dev); + return 0; } diff -Naur --no-dereference a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c --- a/drivers/phy/cadence/phy-cadence-torrent.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/phy/cadence/phy-cadence-torrent.c 2024-07-07 20:37:34.672306689 -0400 @@ -90,6 +90,7 @@ #define CMN_BGCAL_INIT_TMR 0x0064U #define CMN_BGCAL_ITER_TMR 0x0065U #define CMN_IBCAL_INIT_TMR 0x0074U +#define RX_CDRLF_CNFG2 0x0081U #define CMN_PLL0_VCOCAL_TCTRL 0x0082U #define CMN_PLL0_VCOCAL_INIT_TMR 0x0084U #define CMN_PLL0_VCOCAL_ITER_TMR 0x0085U @@ -204,6 +205,8 @@ #define RX_REE_GCSM1_EQENM_PH2 0x010AU #define RX_REE_GCSM2_CTRL 0x0110U #define RX_REE_PERGCSM_CTRL 0x0118U +#define RX_REE_PEAK_UTHR 0x0142U +#define RX_REE_PEAK_LTHR 0x0143U #define RX_REE_ATTEN_THR 0x0149U #define RX_REE_TAP1_CLIP 0x0171U #define RX_REE_TAP2TON_CLIP 0x0172U @@ -212,6 +215,7 @@ #define RX_DIAG_DFE_CTRL 0x01E0U #define RX_DIAG_DFE_AMP_TUNE_2 0x01E2U #define RX_DIAG_DFE_AMP_TUNE_3 0x01E3U +#define RX_DIAG_REE_DAC_CTRL 0x01E4U #define RX_DIAG_NQST_CTRL 0x01E5U #define RX_DIAG_SIGDET_TUNE 0x01E8U #define RX_DIAG_PI_RATE 0x01F4U @@ -295,6 +299,7 @@ TYPE_QSGMII, TYPE_USB, TYPE_USXGMII, + TYPE_PCIE_ML, }; enum cdns_torrent_ref_clk { @@ -355,9 +360,12 @@ struct reset_control *apb_rst; struct device *dev; struct clk *clk; + struct clk *clk1; enum cdns_torrent_ref_clk ref_clk_rate; + enum cdns_torrent_ref_clk ref_clk1_rate; struct cdns_torrent_inst phys[MAX_NUM_LANES]; int nsubnodes; + int already_configured; const struct cdns_torrent_data *init_data; struct regmap *regmap_common_cdb; struct regmap *regmap_phy_pcs_common_cdb; @@ -689,6 +697,7 @@ case TYPE_DP: return "DisplayPort"; case TYPE_PCIE: + case TYPE_PCIE_ML: return "PCIe"; case TYPE_SGMII: return "SGMII"; @@ -1592,6 +1601,9 @@ struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); int ret; + if (cdns_phy->already_configured) + return 0; + ret = cdns_torrent_dp_verify_config(inst, &opts->dp); if (ret) { dev_err(&phy->dev, "invalid params for phy configure\n"); @@ -1627,6 +1639,12 @@ u32 read_val; int ret; + if (cdns_phy->already_configured) { + /* Give 5ms to 10ms delay for the PIPE clock to be stable */ + usleep_range(5000, 10000); + return 0; + } + if (cdns_phy->nsubnodes == 1) { /* Take the PHY lane group out of reset */ reset_control_deassert(inst->lnk_rst); @@ -2305,6 +2323,9 @@ u32 num_regs; int i, j; + if (cdns_phy->already_configured) + return 0; + if (cdns_phy->nsubnodes > 1) { if (phy_type == TYPE_DP) return cdns_torrent_dp_multilink_init(cdns_phy, inst, phy); @@ -2442,53 +2463,55 @@ .owner = THIS_MODULE, }; -static int cdns_torrent_noop_phy_on(struct phy *phy) -{ - /* Give 5ms to 10ms delay for the PIPE clock to be stable */ - usleep_range(5000, 10000); - - return 0; -} - -static const struct phy_ops noop_ops = { - .power_on = cdns_torrent_noop_phy_on, - .owner = THIS_MODULE, -}; - static int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) { const struct cdns_torrent_data *init_data = cdns_phy->init_data; struct cdns_torrent_vals *cmn_vals, *tx_ln_vals, *rx_ln_vals; + enum cdns_torrent_ref_clk ref_clk1 = cdns_phy->ref_clk1_rate; enum cdns_torrent_ref_clk ref_clk = cdns_phy->ref_clk_rate; struct cdns_torrent_vals *link_cmn_vals, *xcvr_diag_vals; enum cdns_torrent_phy_type phy_t1, phy_t2; + struct cdns_torrent_vals *phy_pma_cmn_vals; struct cdns_torrent_vals *pcs_cmn_vals; int i, j, node, mlane, num_lanes, ret; + u32 num_links = cdns_phy->nsubnodes; struct cdns_reg_pairs *reg_pairs; enum cdns_torrent_ssc_mode ssc; + u32 num_regs, pcie_links = 0; struct regmap *regmap; - u32 num_regs; - - /* Maximum 2 links (subnodes) are supported */ - if (cdns_phy->nsubnodes != 2) - return -EINVAL; - phy_t1 = cdns_phy->phys[0].phy_type; - phy_t2 = cdns_phy->phys[1].phy_type; + if (num_links == 2) { + phy_t1 = cdns_phy->phys[0].phy_type; + phy_t2 = cdns_phy->phys[1].phy_type; + } else { + phy_t1 = TYPE_PCIE_ML; + phy_t2 = TYPE_NONE; + for (node = 0; node < num_links; node++) { + if (cdns_phy->phys[node].phy_type == TYPE_PCIE) { + pcie_links++; + continue; + } + phy_t2 = cdns_phy->phys[node].phy_type; + } + if (pcie_links <= 1 || phy_t2 != TYPE_USB) + return -EINVAL; + } /** * First configure the PHY for first link with phy_t1. Get the array * values as [phy_t1][phy_t2][ssc]. */ - for (node = 0; node < cdns_phy->nsubnodes; node++) { - if (node == 1) { + for (node = 0; node < num_links; node++) { + if ((num_links == 2 && node == 1) || + (num_links > 2 && node == pcie_links)) { /** * If first link with phy_t1 is configured, then * configure the PHY for second link with phy_t2. * Get the array values as [phy_t2][phy_t1][ssc]. */ swap(phy_t1, phy_t2); + swap(ref_clk, ref_clk1); } mlane = cdns_phy->phys[node].mlane; @@ -2552,9 +2575,22 @@ reg_pairs[i].val); } + /* PHY PMA common registers configurations */ + phy_pma_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->phy_pma_cmn_vals_tbl, + CLK_ANY, CLK_ANY, + phy_t1, phy_t2, ANY_SSC); + if (phy_pma_cmn_vals) { + reg_pairs = phy_pma_cmn_vals->reg_pairs; + num_regs = phy_pma_cmn_vals->num_regs; + regmap = cdns_phy->regmap_phy_pma_common_cdb; + for (i = 0; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); + } + /* PMA common registers configurations */ cmn_vals = cdns_torrent_get_tbl_vals(&init_data->cmn_vals_tbl, - ref_clk, ref_clk, + ref_clk, ref_clk1, phy_t1, phy_t2, ssc); if (cmn_vals) { reg_pairs = cmn_vals->reg_pairs; @@ -2567,7 +2603,7 @@ /* PMA TX lane registers configurations */ tx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->tx_ln_vals_tbl, - ref_clk, ref_clk, + ref_clk, ref_clk1, phy_t1, phy_t2, ssc); if (tx_ln_vals) { reg_pairs = tx_ln_vals->reg_pairs; @@ -2582,7 +2618,7 @@ /* PMA RX lane registers configurations */ rx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->rx_ln_vals_tbl, - ref_clk, ref_clk, + ref_clk, ref_clk1, phy_t1, phy_t2, ssc); if (rx_ln_vals) { reg_pairs = rx_ln_vals->reg_pairs; @@ -2660,7 +2696,7 @@ return 0; } -static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy) +static int cdns_torrent_of_get_reset(struct cdns_torrent_phy *cdns_phy) { struct device *dev = cdns_phy->dev; @@ -2681,29 +2717,40 @@ return 0; } +static int cdns_torrent_of_get_clk(struct cdns_torrent_phy *cdns_phy) +{ + /* refclk: Input reference clock for PLL0 */ + cdns_phy->clk = devm_clk_get(cdns_phy->dev, "refclk"); + if (IS_ERR(cdns_phy->clk)) + return dev_err_probe(cdns_phy->dev, PTR_ERR(cdns_phy->clk), + "phy ref clock not found\n"); + + /* refclk1: Input reference clock for PLL1 */ + cdns_phy->clk1 = devm_clk_get_optional(cdns_phy->dev, "pll1_refclk"); + if (IS_ERR(cdns_phy->clk1)) + return dev_err_probe(cdns_phy->dev, PTR_ERR(cdns_phy->clk1), + "phy PLL1 ref clock not found\n"); + + return 0; +} + static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy) { - struct device *dev = cdns_phy->dev; + unsigned long ref_clk1_rate; unsigned long ref_clk_rate; int ret; - cdns_phy->clk = devm_clk_get(dev, "refclk"); - if (IS_ERR(cdns_phy->clk)) { - dev_err(dev, "phy ref clock not found\n"); - return PTR_ERR(cdns_phy->clk); - } - ret = clk_prepare_enable(cdns_phy->clk); if (ret) { - dev_err(cdns_phy->dev, "Failed to prepare ref clock\n"); + dev_err(cdns_phy->dev, "Failed to prepare ref clock: %d\n", ret); return ret; } ref_clk_rate = clk_get_rate(cdns_phy->clk); if (!ref_clk_rate) { dev_err(cdns_phy->dev, "Failed to get ref clock rate\n"); - clk_disable_unprepare(cdns_phy->clk); - return -EINVAL; + ret = -EINVAL; + goto disable_clk; } switch (ref_clk_rate) { @@ -2720,12 +2767,54 @@ cdns_phy->ref_clk_rate = CLK_156_25_MHZ; break; default: - dev_err(cdns_phy->dev, "Invalid Ref Clock Rate\n"); - clk_disable_unprepare(cdns_phy->clk); - return -EINVAL; + dev_err(cdns_phy->dev, "Invalid ref clock rate\n"); + ret = -EINVAL; + goto disable_clk; + } + + if (cdns_phy->clk1) { + ret = clk_prepare_enable(cdns_phy->clk1); + if (ret) { + dev_err(cdns_phy->dev, "Failed to prepare PLL1 ref clock: %d\n", ret); + goto disable_clk; + } + + ref_clk1_rate = clk_get_rate(cdns_phy->clk1); + if (!ref_clk1_rate) { + dev_err(cdns_phy->dev, "Failed to get PLL1 ref clock rate\n"); + ret = -EINVAL; + goto disable_clk1; + } + + switch (ref_clk1_rate) { + case REF_CLK_19_2MHZ: + cdns_phy->ref_clk1_rate = CLK_19_2_MHZ; + break; + case REF_CLK_25MHZ: + cdns_phy->ref_clk1_rate = CLK_25_MHZ; + break; + case REF_CLK_100MHZ: + cdns_phy->ref_clk1_rate = CLK_100_MHZ; + break; + case REF_CLK_156_25MHZ: + cdns_phy->ref_clk1_rate = CLK_156_25_MHZ; + break; + default: + dev_err(cdns_phy->dev, "Invalid PLL1 ref clock rate\n"); + ret = -EINVAL; + goto disable_clk1; + } + } else { + cdns_phy->ref_clk1_rate = cdns_phy->ref_clk_rate; } return 0; + +disable_clk1: + clk_disable_unprepare(cdns_phy->clk1); +disable_clk: + clk_disable_unprepare(cdns_phy->clk); + return ret; } static int cdns_torrent_phy_probe(struct platform_device *pdev) @@ -2737,7 +2826,6 @@ struct device_node *child; int ret, subnodes, node = 0, i; u32 total_num_lanes = 0; - int already_configured; u8 init_dp_regmap = 0; u32 phy_type; @@ -2776,13 +2864,17 @@ if (ret) return ret; - regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &already_configured); + ret = cdns_torrent_of_get_reset(cdns_phy); + if (ret) + goto clk_cleanup; - if (!already_configured) { - ret = cdns_torrent_reset(cdns_phy); - if (ret) - goto clk_cleanup; + ret = cdns_torrent_of_get_clk(cdns_phy); + if (ret) + goto clk_cleanup; + + regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &cdns_phy->already_configured); + if (!cdns_phy->already_configured) { ret = cdns_torrent_clk(cdns_phy); if (ret) goto clk_cleanup; @@ -2862,10 +2954,7 @@ of_property_read_u32(child, "cdns,ssc-mode", &cdns_phy->phys[node].ssc_mode); - if (!already_configured) - gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops); - else - gphy = devm_phy_create(dev, child, &noop_ops); + gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops); if (IS_ERR(gphy)) { ret = PTR_ERR(gphy); goto put_child; @@ -2942,13 +3031,13 @@ } cdns_phy->nsubnodes = node; - if (total_num_lanes > MAX_NUM_LANES) { + if (total_num_lanes > MAX_NUM_LANES || cdns_phy->nsubnodes > MAX_NUM_LANES) { dev_err(dev, "Invalid lane configuration\n"); ret = -EINVAL; goto put_lnk_rst; } - if (cdns_phy->nsubnodes > 1 && !already_configured) { + if (cdns_phy->nsubnodes > 1 && !cdns_phy->already_configured) { ret = cdns_torrent_phy_configure_multilink(cdns_phy); if (ret) goto put_lnk_rst; @@ -2961,15 +3050,14 @@ } if (cdns_phy->nsubnodes > 1) - dev_dbg(dev, "Multi-link: %s (%d lanes) & %s (%d lanes)", - cdns_torrent_get_phy_type(cdns_phy->phys[0].phy_type), - cdns_phy->phys[0].num_lanes, - cdns_torrent_get_phy_type(cdns_phy->phys[1].phy_type), - cdns_phy->phys[1].num_lanes); + dev_dbg(dev, "Multi-link configuration:\n"); else - dev_dbg(dev, "Single link: %s (%d lanes)", - cdns_torrent_get_phy_type(cdns_phy->phys[0].phy_type), - cdns_phy->phys[0].num_lanes); + dev_dbg(dev, "Single-link configuration:\n"); + + for (i = 0; i < cdns_phy->nsubnodes; i++) + dev_dbg(dev, "%s (%d lanes)", + cdns_torrent_get_phy_type(cdns_phy->phys[i].phy_type), + cdns_phy->phys[i].num_lanes); return 0; @@ -2980,6 +3068,7 @@ reset_control_put(cdns_phy->phys[i].lnk_rst); of_node_put(child); reset_control_assert(cdns_phy->apb_rst); + clk_disable_unprepare(cdns_phy->clk1); clk_disable_unprepare(cdns_phy->clk); clk_cleanup: cdns_torrent_clk_cleanup(cdns_phy); @@ -2998,10 +3087,213 @@ reset_control_put(cdns_phy->phys[i].lnk_rst); } + clk_disable_unprepare(cdns_phy->clk1); clk_disable_unprepare(cdns_phy->clk); cdns_torrent_clk_cleanup(cdns_phy); } +static int cdns_torrent_phy_suspend_noirq(struct device *dev) +{ + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(dev); + int i; + + reset_control_assert(cdns_phy->phy_rst); + reset_control_assert(cdns_phy->apb_rst); + for (i = 0; i < cdns_phy->nsubnodes; i++) + reset_control_assert(cdns_phy->phys[i].lnk_rst); + + if (cdns_phy->already_configured) + cdns_phy->already_configured = 0; + else { + clk_disable_unprepare(cdns_phy->clk1); + clk_disable_unprepare(cdns_phy->clk); + } + + return 0; +} + +static int cdns_torrent_phy_resume_noirq(struct device *dev) +{ + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(dev); + int node = cdns_phy->nsubnodes; + int ret, i; + + ret = cdns_torrent_clk(cdns_phy); + if (ret) + return ret; + + /* Enable APB */ + reset_control_deassert(cdns_phy->apb_rst); + + if (cdns_phy->nsubnodes > 1) { + ret = cdns_torrent_phy_configure_multilink(cdns_phy); + if (ret) + goto put_lnk_rst; + } + + return 0; + +put_lnk_rst: + for (i = 0; i < node; i++) + reset_control_assert(cdns_phy->phys[i].lnk_rst); + reset_control_assert(cdns_phy->apb_rst); + + clk_disable_unprepare(cdns_phy->clk1); + clk_disable_unprepare(cdns_phy->clk); + + return ret; +} + +static DEFINE_NOIRQ_DEV_PM_OPS(cdns_torrent_phy_pm_ops, + cdns_torrent_phy_suspend_noirq, + cdns_torrent_phy_resume_noirq); + +/* Multilink PCIe and USB Same SSC link configuration */ +static struct cdns_reg_pairs ml_pcie_usb_link_cmn_regs[] = { + {0x0002, PHY_PLL_CFG}, + {0x8600, CMN_PDIAG_PLL0_CLK_SEL_M0} +}; + +static struct cdns_reg_pairs ml_pcie_usb_xcvr_diag_ln_regs[] = { + {0x0100, XCVR_DIAG_HSCLK_SEL}, + {0x0013, XCVR_DIAG_HSCLK_DIV}, + {0x0812, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_reg_pairs usb_ml_pcie_xcvr_diag_ln_regs[] = { + {0x0041, XCVR_DIAG_PLLDRC_CTRL}, +}; + +static struct cdns_torrent_vals ml_pcie_usb_link_cmn_vals = { + .reg_pairs = ml_pcie_usb_link_cmn_regs, + .num_regs = ARRAY_SIZE(ml_pcie_usb_link_cmn_regs), +}; + +static struct cdns_torrent_vals ml_pcie_usb_xcvr_diag_ln_vals = { + .reg_pairs = ml_pcie_usb_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(ml_pcie_usb_xcvr_diag_ln_regs), +}; + +static struct cdns_torrent_vals usb_ml_pcie_xcvr_diag_ln_vals = { + .reg_pairs = usb_ml_pcie_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(usb_ml_pcie_xcvr_diag_ln_regs), +}; + +/* Multi link PCIe configuration */ +static struct cdns_reg_pairs ml_pcie_link_cmn_regs[] = { + {0x0002, PHY_PLL_CFG}, + {0x0601, CMN_PDIAG_PLL0_CLK_SEL_M0} +}; + +static struct cdns_reg_pairs ml_pcie_xcvr_diag_ln_regs[] = { + {0x0100, XCVR_DIAG_HSCLK_SEL}, + {0x0001, XCVR_DIAG_HSCLK_DIV}, + {0x0812, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_torrent_vals ml_pcie_link_cmn_vals = { + .reg_pairs = ml_pcie_link_cmn_regs, + .num_regs = ARRAY_SIZE(ml_pcie_link_cmn_regs), +}; + +static struct cdns_torrent_vals ml_pcie_xcvr_diag_ln_vals = { + .reg_pairs = ml_pcie_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(ml_pcie_xcvr_diag_ln_regs), +}; + +/* Multi link PCIe, 100 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs ml_pcie_100_no_ssc_cmn_regs[] = { + {0x0003, CMN_PLL0_VCOCAL_TCTRL}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL} +}; + +static struct cdns_reg_pairs ml_pcie_100_no_ssc_rx_ln_regs[] = { + {0x0019, RX_REE_TAP1_CLIP}, + {0x0019, RX_REE_TAP2TON_CLIP}, + {0x0008, RX_REE_PEAK_UTHR}, + {0x018E, RX_CDRLF_CNFG}, + {0x2E33, RX_CDRLF_CNFG2}, + {0x0001, RX_DIAG_ACYA}, + {0x0C21, RX_DIAG_DFE_AMP_TUNE_2}, + {0x0002, RX_DIAG_DFE_AMP_TUNE_3}, + {0x0005, RX_DIAG_REE_DAC_CTRL} +}; + +static struct cdns_torrent_vals ml_pcie_100_no_ssc_cmn_vals = { + .reg_pairs = ml_pcie_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(ml_pcie_100_no_ssc_cmn_regs), +}; + +static struct cdns_torrent_vals ml_pcie_100_no_ssc_rx_ln_vals = { + .reg_pairs = ml_pcie_100_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(ml_pcie_100_no_ssc_rx_ln_regs), +}; + +/* Multi link PCIe, 100 MHz Ref clk, internal SSC */ +static struct cdns_reg_pairs ml_pcie_100_int_ssc_cmn_regs[] = { + {0x0004, CMN_PLL0_DSM_DIAG_M0}, + {0x0004, CMN_PLL1_DSM_DIAG_M0}, + {0x0509, CMN_PDIAG_PLL0_CP_PADJ_M0}, + {0x0509, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x0F00, CMN_PDIAG_PLL0_CP_IADJ_M0}, + {0x0F00, CMN_PDIAG_PLL1_CP_IADJ_M0}, + {0x0F08, CMN_PDIAG_PLL0_FILT_PADJ_M0}, + {0x0F08, CMN_PDIAG_PLL1_FILT_PADJ_M0}, + {0x0064, CMN_PLL0_INTDIV_M0}, + {0x0050, CMN_PLL1_INTDIV_M0}, + {0x0002, CMN_PLL0_FRACDIVH_M0}, + {0x0002, CMN_PLL1_FRACDIVH_M0}, + {0x0044, CMN_PLL0_HIGH_THR_M0}, + {0x0036, CMN_PLL1_HIGH_THR_M0}, + {0x0002, CMN_PDIAG_PLL0_CTRL_M0}, + {0x0002, CMN_PDIAG_PLL1_CTRL_M0}, + {0x0001, CMN_PLL0_SS_CTRL1_M0}, + {0x0001, CMN_PLL1_SS_CTRL1_M0}, + {0x011B, CMN_PLL0_SS_CTRL2_M0}, + {0x011B, CMN_PLL1_SS_CTRL2_M0}, + {0x006E, CMN_PLL0_SS_CTRL3_M0}, + {0x0058, CMN_PLL1_SS_CTRL3_M0}, + {0x000E, CMN_PLL0_SS_CTRL4_M0}, + {0x0012, CMN_PLL1_SS_CTRL4_M0}, + {0x0C5E, CMN_PLL0_VCOCAL_REFTIM_START}, + {0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START}, + {0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START}, + {0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START}, + {0x0003, CMN_PLL0_VCOCAL_TCTRL}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL}, + {0x00C7, CMN_PLL0_LOCK_REFCNT_START}, + {0x00C7, CMN_PLL1_LOCK_REFCNT_START}, + {0x00C7, CMN_PLL0_LOCK_PLLCNT_START}, + {0x00C7, CMN_PLL1_LOCK_PLLCNT_START}, + {0x0005, CMN_PLL0_LOCK_PLLCNT_THR}, + {0x0005, CMN_PLL1_LOCK_PLLCNT_THR} +}; + +static struct cdns_torrent_vals ml_pcie_100_int_ssc_cmn_vals = { + .reg_pairs = ml_pcie_100_int_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(ml_pcie_100_int_ssc_cmn_regs), +}; + +/* SGMII and QSGMII link configuration */ +static struct cdns_reg_pairs sgmii_qsgmii_link_cmn_regs[] = { + {0x0002, PHY_PLL_CFG} +}; + +static struct cdns_reg_pairs sgmii_qsgmii_xcvr_diag_ln_regs[] = { + {0x0003, XCVR_DIAG_HSCLK_DIV}, + {0x0113, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_torrent_vals sgmii_qsgmii_link_cmn_vals = { + .reg_pairs = sgmii_qsgmii_link_cmn_regs, + .num_regs = ARRAY_SIZE(sgmii_qsgmii_link_cmn_regs), +}; + +static struct cdns_torrent_vals sgmii_qsgmii_xcvr_diag_ln_vals = { + .reg_pairs = sgmii_qsgmii_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(sgmii_qsgmii_xcvr_diag_ln_regs), +}; + /* USB and DP link configuration */ static struct cdns_reg_pairs usb_dp_link_cmn_regs[] = { {0x0002, PHY_PLL_CFG}, @@ -3034,6 +3326,216 @@ .num_regs = ARRAY_SIZE(dp_usb_xcvr_diag_ln_regs), }; +/* USXGMII and SGMII/QSGMII link configuration */ +static struct cdns_reg_pairs usxgmii_sgmii_link_cmn_regs[] = { + {0x0002, PHY_PLL_CFG}, + {0x0400, CMN_PDIAG_PLL0_CLK_SEL_M0}, + {0x0601, CMN_PDIAG_PLL1_CLK_SEL_M0} +}; + +static struct cdns_reg_pairs usxgmii_sgmii_xcvr_diag_ln_regs[] = { + {0x0000, XCVR_DIAG_HSCLK_SEL}, + {0x0001, XCVR_DIAG_HSCLK_DIV}, + {0x0001, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_reg_pairs sgmii_usxgmii_xcvr_diag_ln_regs[] = { + {0x0111, XCVR_DIAG_HSCLK_SEL}, + {0x0103, XCVR_DIAG_HSCLK_DIV}, + {0x0A9B, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_torrent_vals usxgmii_sgmii_link_cmn_vals = { + .reg_pairs = usxgmii_sgmii_link_cmn_regs, + .num_regs = ARRAY_SIZE(usxgmii_sgmii_link_cmn_regs), +}; + +static struct cdns_torrent_vals usxgmii_sgmii_xcvr_diag_ln_vals = { + .reg_pairs = usxgmii_sgmii_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(usxgmii_sgmii_xcvr_diag_ln_regs), +}; + +static struct cdns_torrent_vals sgmii_usxgmii_xcvr_diag_ln_vals = { + .reg_pairs = sgmii_usxgmii_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(sgmii_usxgmii_xcvr_diag_ln_regs), +}; + +/* Multilink USXGMII, using PLL0, 156.25 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs ml_usxgmii_pll0_156_25_no_ssc_cmn_regs[] = { + {0x0014, CMN_PLL0_DSM_FBH_OVRD_M0}, + {0x0005, CMN_PLL0_DSM_FBL_OVRD_M0}, + {0x061B, CMN_PLL0_VCOCAL_INIT_TMR}, + {0x0019, CMN_PLL0_VCOCAL_ITER_TMR}, + {0x1354, CMN_PLL0_VCOCAL_REFTIM_START}, + {0x1354, CMN_PLL0_VCOCAL_PLLCNT_START}, + {0x0003, CMN_PLL0_VCOCAL_TCTRL}, + {0x0138, CMN_PLL0_LOCK_REFCNT_START}, + {0x0138, CMN_PLL0_LOCK_PLLCNT_START} +}; + +static struct cdns_torrent_vals ml_usxgmii_pll0_156_25_no_ssc_cmn_vals = { + .reg_pairs = ml_usxgmii_pll0_156_25_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(ml_usxgmii_pll0_156_25_no_ssc_cmn_regs), +}; + +/* Multilink SGMII/QSGMII, using PLL1, 100 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs ml_sgmii_pll1_100_no_ssc_cmn_regs[] = { + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + +static struct cdns_torrent_vals ml_sgmii_pll1_100_no_ssc_cmn_vals = { + .reg_pairs = ml_sgmii_pll1_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(ml_sgmii_pll1_100_no_ssc_cmn_regs), +}; + +/* TI J7200, Multilink USXGMII, using PLL0, 156.25 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_regs[] = { + {0x0014, CMN_SSM_BIAS_TMR}, + {0x0028, CMN_PLLSM0_PLLPRE_TMR}, + {0x00A4, CMN_PLLSM0_PLLLOCK_TMR}, + {0x0062, CMN_BGCAL_INIT_TMR}, + {0x0062, CMN_BGCAL_ITER_TMR}, + {0x0014, CMN_IBCAL_INIT_TMR}, + {0x0018, CMN_TXPUCAL_INIT_TMR}, + {0x0005, CMN_TXPUCAL_ITER_TMR}, + {0x0018, CMN_TXPDCAL_INIT_TMR}, + {0x0005, CMN_TXPDCAL_ITER_TMR}, + {0x024A, CMN_RXCAL_INIT_TMR}, + {0x0005, CMN_RXCAL_ITER_TMR}, + {0x000B, CMN_SD_CAL_REFTIM_START}, + {0x0132, CMN_SD_CAL_PLLCNT_START}, + {0x0014, CMN_PLL0_DSM_FBH_OVRD_M0}, + {0x0005, CMN_PLL0_DSM_FBL_OVRD_M0}, + {0x061B, CMN_PLL0_VCOCAL_INIT_TMR}, + {0x0019, CMN_PLL0_VCOCAL_ITER_TMR}, + {0x1354, CMN_PLL0_VCOCAL_REFTIM_START}, + {0x1354, CMN_PLL0_VCOCAL_PLLCNT_START}, + {0x0003, CMN_PLL0_VCOCAL_TCTRL}, + {0x0138, CMN_PLL0_LOCK_REFCNT_START}, + {0x0138, CMN_PLL0_LOCK_PLLCNT_START} +}; + +static struct cdns_torrent_vals j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_vals = { + .reg_pairs = j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_regs), +}; + +/* TI J7200, Multilink SGMII/QSGMII, using PLL1, 100 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs j7200_ml_sgmii_pll1_100_no_ssc_cmn_regs[] = { + {0x0028, CMN_PLLSM1_PLLPRE_TMR}, + {0x00A4, CMN_PLLSM1_PLLLOCK_TMR}, + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + +static struct cdns_torrent_vals j7200_ml_sgmii_pll1_100_no_ssc_cmn_vals = { + .reg_pairs = j7200_ml_sgmii_pll1_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(j7200_ml_sgmii_pll1_100_no_ssc_cmn_regs), +}; + +/* PCIe and USXGMII link configuration */ +static struct cdns_reg_pairs pcie_usxgmii_link_cmn_regs[] = { + {0x0003, PHY_PLL_CFG}, + {0x0601, CMN_PDIAG_PLL0_CLK_SEL_M0}, + {0x0400, CMN_PDIAG_PLL0_CLK_SEL_M1}, + {0x0400, CMN_PDIAG_PLL1_CLK_SEL_M0} +}; + +static struct cdns_reg_pairs pcie_usxgmii_xcvr_diag_ln_regs[] = { + {0x0000, XCVR_DIAG_HSCLK_SEL}, + {0x0001, XCVR_DIAG_HSCLK_DIV}, + {0x0012, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_reg_pairs usxgmii_pcie_xcvr_diag_ln_regs[] = { + {0x0011, XCVR_DIAG_HSCLK_SEL}, + {0x0001, XCVR_DIAG_HSCLK_DIV}, + {0x0089, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_torrent_vals pcie_usxgmii_link_cmn_vals = { + .reg_pairs = pcie_usxgmii_link_cmn_regs, + .num_regs = ARRAY_SIZE(pcie_usxgmii_link_cmn_regs), +}; + +static struct cdns_torrent_vals pcie_usxgmii_xcvr_diag_ln_vals = { + .reg_pairs = pcie_usxgmii_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(pcie_usxgmii_xcvr_diag_ln_regs), +}; + +static struct cdns_torrent_vals usxgmii_pcie_xcvr_diag_ln_vals = { + .reg_pairs = usxgmii_pcie_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(usxgmii_pcie_xcvr_diag_ln_regs), +}; + +/* + * Multilink USXGMII, using PLL1, 156.25 MHz Ref clk, no SSC + */ +static struct cdns_reg_pairs ml_usxgmii_pll1_156_25_no_ssc_cmn_regs[] = { + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x0014, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x0005, CMN_PLL1_DSM_FBL_OVRD_M0}, + {0x061B, CMN_PLL1_VCOCAL_INIT_TMR}, + {0x0019, CMN_PLL1_VCOCAL_ITER_TMR}, + {0x1354, CMN_PLL1_VCOCAL_REFTIM_START}, + {0x1354, CMN_PLL1_VCOCAL_PLLCNT_START}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL}, + {0x0138, CMN_PLL1_LOCK_REFCNT_START}, + {0x0138, CMN_PLL1_LOCK_PLLCNT_START}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + +static struct cdns_reg_pairs ml_usxgmii_156_25_no_ssc_tx_ln_regs[] = { + {0x00F3, TX_PSC_A0}, + {0x04A2, TX_PSC_A2}, + {0x04A2, TX_PSC_A3 }, + {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x0000, XCVR_DIAG_PSC_OVRD} +}; + +static struct cdns_reg_pairs ml_usxgmii_156_25_no_ssc_rx_ln_regs[] = { + {0x091D, RX_PSC_A0}, + {0x0900, RX_PSC_A2}, + {0x0100, RX_PSC_A3}, + {0x0030, RX_REE_SMGM_CTRL1}, + {0x03C7, RX_REE_GCSM1_EQENM_PH1}, + {0x01C7, RX_REE_GCSM1_EQENM_PH2}, + {0x0000, RX_DIAG_DFE_CTRL}, + {0x0019, RX_REE_TAP1_CLIP}, + {0x0019, RX_REE_TAP2TON_CLIP}, + {0x00B9, RX_DIAG_NQST_CTRL}, + {0x0C21, RX_DIAG_DFE_AMP_TUNE_2}, + {0x0002, RX_DIAG_DFE_AMP_TUNE_3}, + {0x0033, RX_DIAG_PI_RATE}, + {0x0001, RX_DIAG_ACYA}, + {0x018C, RX_CDRLF_CNFG} +}; + +static struct cdns_torrent_vals ml_usxgmii_pll1_156_25_no_ssc_cmn_vals = { + .reg_pairs = ml_usxgmii_pll1_156_25_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(ml_usxgmii_pll1_156_25_no_ssc_cmn_regs), +}; + +static struct cdns_torrent_vals ml_usxgmii_156_25_no_ssc_tx_ln_vals = { + .reg_pairs = ml_usxgmii_156_25_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(ml_usxgmii_156_25_no_ssc_tx_ln_regs), +}; + +static struct cdns_torrent_vals ml_usxgmii_156_25_no_ssc_rx_ln_vals = { + .reg_pairs = ml_usxgmii_156_25_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(ml_usxgmii_156_25_no_ssc_rx_ln_regs), +}; + /* TI USXGMII configuration: Enable cmn_refclk_rcv_out_en */ static struct cdns_reg_pairs ti_usxgmii_phy_pma_cmn_regs[] = { {0x0040, PHY_PMA_CMN_CTRL1}, @@ -3627,6 +4129,8 @@ {0x0C02, RX_REE_ATTEN_THR}, {0x0330, RX_REE_SMGM_CTRL1}, {0x0300, RX_REE_SMGM_CTRL2}, + {0x0000, RX_REE_PEAK_UTHR}, + {0x01F5, RX_REE_PEAK_LTHR}, {0x0019, RX_REE_TAP1_CLIP}, {0x0019, RX_REE_TAP2TON_CLIP}, {0x1004, RX_DIAG_SIGDET_TUNE}, @@ -3761,7 +4265,8 @@ {0x04A2, TX_PSC_A2}, {0x04A2, TX_PSC_A3}, {0x0000, TX_TXCC_CPOST_MULT_00}, - {0x00B3, DRV_DIAG_TX_DRV} + {0x00B3, DRV_DIAG_TX_DRV}, + {0x0002, XCVR_DIAG_PSC_OVRD} }; static struct cdns_reg_pairs ti_sgmii_100_no_ssc_tx_ln_regs[] = { @@ -3770,7 +4275,8 @@ {0x04A2, TX_PSC_A3}, {0x0000, TX_TXCC_CPOST_MULT_00}, {0x00B3, DRV_DIAG_TX_DRV}, - {0x4000, XCVR_DIAG_RXCLK_CTRL}, + {0x0002, XCVR_DIAG_PSC_OVRD}, + {0x4000, XCVR_DIAG_RXCLK_CTRL} }; static struct cdns_reg_pairs sgmii_100_no_ssc_rx_ln_regs[] = { @@ -3811,6 +4317,50 @@ .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_rx_ln_regs), }; +/* TI J7200, multilink SGMII */ +static struct cdns_reg_pairs j7200_sgmii_100_no_ssc_tx_ln_regs[] = { + {0x07A2, TX_RCVDET_ST_TMR}, + {0x00F3, TX_PSC_A0}, + {0x04A2, TX_PSC_A2}, + {0x04A2, TX_PSC_A3 }, + {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x00B3, DRV_DIAG_TX_DRV}, + {0x0002, XCVR_DIAG_PSC_OVRD}, + {0x4000, XCVR_DIAG_RXCLK_CTRL} +}; + +static struct cdns_torrent_vals j7200_sgmii_100_no_ssc_tx_ln_vals = { + .reg_pairs = j7200_sgmii_100_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(j7200_sgmii_100_no_ssc_tx_ln_regs), +}; + +static struct cdns_reg_pairs j7200_sgmii_100_no_ssc_rx_ln_regs[] = { + {0x0014, RX_SDCAL0_INIT_TMR}, + {0x0062, RX_SDCAL0_ITER_TMR}, + {0x0014, RX_SDCAL1_INIT_TMR}, + {0x0062, RX_SDCAL1_ITER_TMR}, + {0x091D, RX_PSC_A0}, + {0x0900, RX_PSC_A2}, + {0x0100, RX_PSC_A3}, + {0x03C7, RX_REE_GCSM1_EQENM_PH1}, + {0x01C7, RX_REE_GCSM1_EQENM_PH2}, + {0x0000, RX_DIAG_DFE_CTRL}, + {0x0019, RX_REE_TAP1_CLIP}, + {0x0019, RX_REE_TAP2TON_CLIP}, + {0x0098, RX_DIAG_NQST_CTRL}, + {0x0C01, RX_DIAG_DFE_AMP_TUNE_2}, + {0x0000, RX_DIAG_DFE_AMP_TUNE_3}, + {0x0000, RX_DIAG_PI_CAP}, + {0x0010, RX_DIAG_PI_RATE}, + {0x0001, RX_DIAG_ACYA}, + {0x018C, RX_CDRLF_CNFG} +}; + +static struct cdns_torrent_vals j7200_sgmii_100_no_ssc_rx_ln_vals = { + .reg_pairs = j7200_sgmii_100_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(j7200_sgmii_100_no_ssc_rx_ln_regs), +}; + /* SGMII 100 MHz Ref clk, internal SSC */ static struct cdns_reg_pairs sgmii_100_int_ssc_cmn_regs[] = { {0x0004, CMN_PLL0_DSM_DIAG_M0}, @@ -3893,7 +4443,8 @@ {0x04A2, TX_PSC_A3}, {0x0000, TX_TXCC_CPOST_MULT_00}, {0x0011, TX_TXCC_MGNFS_MULT_100}, - {0x0003, DRV_DIAG_TX_DRV} + {0x0003, DRV_DIAG_TX_DRV}, + {0x0002, XCVR_DIAG_PSC_OVRD} }; static struct cdns_reg_pairs ti_qsgmii_100_no_ssc_tx_ln_regs[] = { @@ -3903,7 +4454,8 @@ {0x0000, TX_TXCC_CPOST_MULT_00}, {0x0011, TX_TXCC_MGNFS_MULT_100}, {0x0003, DRV_DIAG_TX_DRV}, - {0x4000, XCVR_DIAG_RXCLK_CTRL}, + {0x0002, XCVR_DIAG_PSC_OVRD}, + {0x4000, XCVR_DIAG_RXCLK_CTRL} }; static struct cdns_reg_pairs qsgmii_100_no_ssc_rx_ln_regs[] = { @@ -3944,6 +4496,51 @@ .num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_rx_ln_regs), }; +/* TI J7200, multilink QSGMII */ +static struct cdns_reg_pairs j7200_qsgmii_100_no_ssc_tx_ln_regs[] = { + {0x07A2, TX_RCVDET_ST_TMR}, + {0x00F3, TX_PSC_A0}, + {0x04A2, TX_PSC_A2}, + {0x04A2, TX_PSC_A3 }, + {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x0011, TX_TXCC_MGNFS_MULT_100}, + {0x0003, DRV_DIAG_TX_DRV}, + {0x0002, XCVR_DIAG_PSC_OVRD}, + {0x4000, XCVR_DIAG_RXCLK_CTRL} +}; + +static struct cdns_torrent_vals j7200_qsgmii_100_no_ssc_tx_ln_vals = { + .reg_pairs = j7200_qsgmii_100_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(j7200_qsgmii_100_no_ssc_tx_ln_regs), +}; + +static struct cdns_reg_pairs j7200_qsgmii_100_no_ssc_rx_ln_regs[] = { + {0x0014, RX_SDCAL0_INIT_TMR}, + {0x0062, RX_SDCAL0_ITER_TMR}, + {0x0014, RX_SDCAL1_INIT_TMR}, + {0x0062, RX_SDCAL1_ITER_TMR}, + {0x091D, RX_PSC_A0}, + {0x0900, RX_PSC_A2}, + {0x0100, RX_PSC_A3}, + {0x03C7, RX_REE_GCSM1_EQENM_PH1}, + {0x01C7, RX_REE_GCSM1_EQENM_PH2}, + {0x0000, RX_DIAG_DFE_CTRL}, + {0x0019, RX_REE_TAP1_CLIP}, + {0x0019, RX_REE_TAP2TON_CLIP}, + {0x0098, RX_DIAG_NQST_CTRL}, + {0x0C01, RX_DIAG_DFE_AMP_TUNE_2}, + {0x0000, RX_DIAG_DFE_AMP_TUNE_3}, + {0x0000, RX_DIAG_PI_CAP}, + {0x0010, RX_DIAG_PI_RATE}, + {0x0001, RX_DIAG_ACYA}, + {0x018C, RX_CDRLF_CNFG} +}; + +static struct cdns_torrent_vals j7200_qsgmii_100_no_ssc_rx_ln_vals = { + .reg_pairs = j7200_qsgmii_100_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(j7200_qsgmii_100_no_ssc_rx_ln_regs), +}; + /* QSGMII 100 MHz Ref clk, internal SSC */ static struct cdns_reg_pairs qsgmii_100_int_ssc_cmn_regs[] = { {0x0004, CMN_PLL0_DSM_DIAG_M0}, @@ -4023,7 +4620,7 @@ .num_regs = ARRAY_SIZE(sl_sgmii_xcvr_diag_ln_regs), }; -/* Multi link PCIe, 100 MHz Ref clk, internal SSC */ +/* For PCIe (with some other protocol), 100 MHz Ref clk, internal SSC */ static struct cdns_reg_pairs pcie_100_int_ssc_cmn_regs[] = { {0x0004, CMN_PLL0_DSM_DIAG_M0}, {0x0004, CMN_PLL0_DSM_DIAG_M1}, @@ -4162,26 +4759,38 @@ {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_USB), &usb_dp_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_NONE), NULL}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_PCIE), &ml_pcie_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_SGMII), &pcie_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_QSGMII), &pcie_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USB), &pcie_usb_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_DP), &pcie_dp_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USXGMII), &pcie_usxgmii_link_cmn_vals}, + + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE_ML, TYPE_USB), &ml_pcie_usb_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_NONE), &sl_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_PCIE), &pcie_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_QSGMII), &sgmii_qsgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USB), &usb_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USXGMII), &usxgmii_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_NONE), &sl_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_PCIE), &pcie_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_SGMII), &sgmii_qsgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USB), &usb_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USXGMII), &usxgmii_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_NONE), &sl_usb_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_PCIE), &pcie_usb_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_PCIE_ML), &ml_pcie_usb_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_SGMII), &usb_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_QSGMII), &usb_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_DP), &usb_dp_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_NONE), &sl_usxgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &pcie_usxgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &usxgmii_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &usxgmii_sgmii_link_cmn_vals}, }; static struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = { @@ -4190,31 +4799,44 @@ {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_USB), &dp_usb_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_NONE), NULL}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_PCIE), &ml_pcie_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_SGMII), &pcie_sgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_QSGMII), &pcie_sgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USB), &pcie_usb_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_DP), &pcie_dp_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USXGMII), &pcie_usxgmii_xcvr_diag_ln_vals}, + + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE_ML, TYPE_USB), &ml_pcie_usb_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_NONE), &sl_sgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_PCIE), &sgmii_pcie_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_QSGMII), &sgmii_qsgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USB), &sgmii_usb_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USXGMII), &sgmii_usxgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_NONE), &sl_sgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_PCIE), &sgmii_pcie_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_SGMII), &sgmii_qsgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USB), &sgmii_usb_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USXGMII), &sgmii_usxgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_NONE), &sl_usb_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_PCIE), &usb_pcie_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_PCIE_ML), &usb_ml_pcie_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_SGMII), &usb_sgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_QSGMII), &usb_sgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_DP), &usb_dp_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_NONE), &sl_usxgmii_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &usxgmii_pcie_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &usxgmii_sgmii_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &usxgmii_sgmii_xcvr_diag_ln_vals}, }; static struct cdns_torrent_vals_entry pcs_cmn_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_NONE), &usb_phy_pcs_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_PCIE), &usb_phy_pcs_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_PCIE_ML), &usb_phy_pcs_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_SGMII), &usb_phy_pcs_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_QSGMII), &usb_phy_pcs_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_DP), &usb_phy_pcs_cmn_vals}, @@ -4232,6 +4854,10 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), NULL}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), &sl_pcie_100_int_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, NO_SSC), &ml_pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, EXTERNAL_SSC), &ml_pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, INTERNAL_SSC), &ml_pcie_100_int_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), &pcie_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), &pcie_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), &pcie_100_int_ssc_cmn_vals}, @@ -4246,12 +4872,18 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), &ml_pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), &ml_pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), &ml_pcie_100_int_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &sl_sgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &sgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_int_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sl_sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, @@ -4262,6 +4894,8 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_int_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &sl_qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, @@ -4274,6 +4908,10 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_int_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, NO_SSC), &usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, EXTERNAL_SSC), &usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, INTERNAL_SSC), &usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &sl_usb_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &sl_usb_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &sl_usb_100_int_ssc_cmn_vals}, @@ -4285,6 +4923,17 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &sl_usxgmii_156_25_no_ssc_cmn_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &ml_sgmii_pll1_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &ml_sgmii_pll1_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_pll1_156_25_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &ml_usxgmii_pll0_156_25_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &ml_usxgmii_pll0_156_25_no_ssc_cmn_vals}, }; static struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = { @@ -4299,6 +4948,10 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), NULL}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, INTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), NULL}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), NULL}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), NULL}, @@ -4313,12 +4966,18 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals}, @@ -4329,6 +4988,8 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, @@ -4341,6 +5002,10 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, @@ -4352,6 +5017,17 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, }; static struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = { @@ -4366,6 +5042,10 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, NO_SSC), &ml_pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, EXTERNAL_SSC), &ml_pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, INTERNAL_SSC), &ml_pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, @@ -4380,12 +5060,18 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), &ml_pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), &ml_pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), &ml_pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, @@ -4396,6 +5082,8 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, @@ -4408,6 +5096,10 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, @@ -4419,6 +5111,17 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, }; static const struct cdns_torrent_data cdns_map_torrent = { @@ -4452,6 +5155,9 @@ static struct cdns_torrent_vals_entry j721e_phy_pma_cmn_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_NONE), &ti_usxgmii_phy_pma_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &ti_usxgmii_phy_pma_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &ti_usxgmii_phy_pma_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &ti_usxgmii_phy_pma_cmn_vals}, }; static struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = { @@ -4466,6 +5172,10 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), NULL}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, INTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), NULL}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), NULL}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), NULL}, @@ -4480,12 +5190,18 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, @@ -4496,6 +5212,8 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, @@ -4508,6 +5226,10 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, @@ -4519,6 +5241,17 @@ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, }; static const struct cdns_torrent_data ti_j721e_map_torrent = { @@ -4554,6 +5287,322 @@ }, }; +/* TI J7200 (Torrent SD0805) */ +static struct cdns_torrent_vals_entry ti_j7200_cmn_vals_entries[] = { + {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_PCIE, NO_SSC), &dp_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_USB, NO_SSC), &sl_dp_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), &sl_pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, NO_SSC), &ml_pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, EXTERNAL_SSC), &ml_pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, INTERNAL_SSC), &ml_pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), &pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, NO_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, EXTERNAL_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, INTERNAL_SSC), &pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, NO_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, EXTERNAL_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, INTERNAL_SSC), &pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), &ml_pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), &ml_pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), &ml_pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &sl_sgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sl_sgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_NONE, NO_SSC), &sl_qsgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, NO_SSC), &qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &sl_qsgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, NO_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, EXTERNAL_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, INTERNAL_SSC), &sl_usb_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, NO_SSC), &usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, NO_SSC), &usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, EXTERNAL_SSC), &usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, INTERNAL_SSC), &usb_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &sl_usb_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, NO_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, EXTERNAL_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, INTERNAL_SSC), &sl_usb_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &sl_usxgmii_156_25_no_ssc_cmn_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &j7200_ml_sgmii_pll1_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &j7200_ml_sgmii_pll1_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_pll1_156_25_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_vals}, +}; + +static struct cdns_torrent_vals_entry ti_j7200_tx_ln_vals_entries[] = { + {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_PCIE, NO_SSC), &dp_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_USB, NO_SSC), &dp_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_NONE, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &j7200_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &j7200_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, +}; + +static struct cdns_torrent_vals_entry ti_j7200_rx_ln_vals_entries[] = { + {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_PCIE, NO_SSC), &dp_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_USB, NO_SSC), &dp_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_PCIE, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_NONE, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE_ML, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &j7200_sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &j7200_qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals}, +}; + +static const struct cdns_torrent_data ti_j7200_map_torrent = { + .block_offset_shift = 0x0, + .reg_offset_shift = 0x1, + .link_cmn_vals_tbl = { + .entries = link_cmn_vals_entries, + .num_entries = ARRAY_SIZE(link_cmn_vals_entries), + }, + .xcvr_diag_vals_tbl = { + .entries = xcvr_diag_vals_entries, + .num_entries = ARRAY_SIZE(xcvr_diag_vals_entries), + }, + .pcs_cmn_vals_tbl = { + .entries = pcs_cmn_vals_entries, + .num_entries = ARRAY_SIZE(pcs_cmn_vals_entries), + }, + .phy_pma_cmn_vals_tbl = { + .entries = j721e_phy_pma_cmn_vals_entries, + .num_entries = ARRAY_SIZE(j721e_phy_pma_cmn_vals_entries), + }, + .cmn_vals_tbl = { + .entries = ti_j7200_cmn_vals_entries, + .num_entries = ARRAY_SIZE(ti_j7200_cmn_vals_entries), + }, + .tx_ln_vals_tbl = { + .entries = ti_j7200_tx_ln_vals_entries, + .num_entries = ARRAY_SIZE(ti_j7200_tx_ln_vals_entries), + }, + .rx_ln_vals_tbl = { + .entries = ti_j7200_rx_ln_vals_entries, + .num_entries = ARRAY_SIZE(ti_j7200_rx_ln_vals_entries), + }, +}; + static const struct of_device_id cdns_torrent_phy_of_match[] = { { .compatible = "cdns,torrent-phy", @@ -4563,6 +5612,10 @@ .compatible = "ti,j721e-serdes-10g", .data = &ti_j721e_map_torrent, }, + { + .compatible = "ti,j7200-serdes-10g", + .data = &ti_j7200_map_torrent, + }, {} }; MODULE_DEVICE_TABLE(of, cdns_torrent_phy_of_match); @@ -4573,6 +5626,7 @@ .driver = { .name = "cdns-torrent-phy", .of_match_table = cdns_torrent_phy_of_match, + .pm = pm_sleep_ptr(&cdns_torrent_phy_pm_ops), } }; module_platform_driver(cdns_torrent_phy_driver); diff -Naur --no-dereference a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c --- a/drivers/phy/ti/phy-gmii-sel.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/phy/ti/phy-gmii-sel.c 2024-07-07 20:37:34.672306689 -0400 @@ -248,7 +248,7 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j784s4 = { .use_of_data = true, .regfields = phy_gmii_sel_fields_am654, - .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | + .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII) | BIT(PHY_INTERFACE_MODE_USXGMII), .num_ports = 8, .num_qsgmii_main_ports = 2, @@ -494,11 +494,35 @@ return 0; } +static int phy_gmii_sel_resume_noirq(struct device *dev) +{ + struct phy_gmii_sel_priv *priv = dev_get_drvdata(dev); + struct phy_gmii_sel_phy_priv *if_phys = priv->if_phys; + int ret, i; + + for (i = 0; i < priv->num_ports; i++) { + if (if_phys[i].phy_if_mode) { + ret = phy_gmii_sel_mode(if_phys[i].if_phy, + PHY_MODE_ETHERNET, if_phys[i].phy_if_mode); + if (ret) { + dev_err(dev, "port%u: restore mode fail %d\n", + if_phys[i].if_phy->id, ret); + return ret; + } + } + } + + return 0; +} + +static DEFINE_NOIRQ_DEV_PM_OPS(phy_gmii_sel_pm_ops, NULL, phy_gmii_sel_resume_noirq); + static struct platform_driver phy_gmii_sel_driver = { .probe = phy_gmii_sel_probe, .driver = { .name = "phy-gmii-sel", .of_match_table = phy_gmii_sel_id_table, + .pm = pm_sleep_ptr(&phy_gmii_sel_pm_ops), }, }; module_platform_driver(phy_gmii_sel_driver); diff -Naur --no-dereference a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c --- a/drivers/phy/ti/phy-j721e-wiz.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/phy/ti/phy-j721e-wiz.c 2024-07-07 20:37:34.672306689 -0400 @@ -1076,27 +1076,12 @@ return ret; } -static int wiz_clock_init(struct wiz *wiz, struct device_node *node) +static void wiz_clock_init(struct wiz *wiz) { - const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; - struct device *dev = wiz->dev; - struct device_node *clk_node; - const char *node_name; unsigned long rate; - struct clk *clk; - int ret; - int i; - clk = devm_clk_get(dev, "core_ref_clk"); - if (IS_ERR(clk)) { - dev_err(dev, "core_ref_clk clock not found\n"); - ret = PTR_ERR(clk); - return ret; - } - wiz->input_clks[WIZ_CORE_REFCLK] = clk; - - rate = clk_get_rate(clk); - if (rate >= 100000000) + rate = clk_get_rate(wiz->input_clks[WIZ_CORE_REFCLK]); + if (rate >= REF_CLK_100MHZ) regmap_field_write(wiz->pma_cmn_refclk_int_mode, 0x1); else regmap_field_write(wiz->pma_cmn_refclk_int_mode, 0x3); @@ -1120,35 +1105,55 @@ break; } - if (wiz->data->pma_cmn_refclk1_int_mode) { - clk = devm_clk_get(dev, "core_ref1_clk"); - if (IS_ERR(clk)) { - dev_err(dev, "core_ref1_clk clock not found\n"); - ret = PTR_ERR(clk); - return ret; - } - wiz->input_clks[WIZ_CORE_REFCLK1] = clk; - - rate = clk_get_rate(clk); - if (rate >= 100000000) + if (wiz->input_clks[WIZ_CORE_REFCLK1]) { + rate = clk_get_rate(wiz->input_clks[WIZ_CORE_REFCLK1]); + if (rate >= REF_CLK_100MHZ) regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x1); else regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x3); } - clk = devm_clk_get(dev, "ext_ref_clk"); - if (IS_ERR(clk)) { - dev_err(dev, "ext_ref_clk clock not found\n"); - ret = PTR_ERR(clk); - return ret; - } - wiz->input_clks[WIZ_EXT_REFCLK] = clk; - - rate = clk_get_rate(clk); - if (rate >= 100000000) + rate = clk_get_rate(wiz->input_clks[WIZ_EXT_REFCLK]); + if (rate >= REF_CLK_100MHZ) regmap_field_write(wiz->pma_cmn_refclk_mode, 0x0); else regmap_field_write(wiz->pma_cmn_refclk_mode, 0x2); +} + +static int wiz_clock_probe(struct wiz *wiz, struct device_node *node) +{ + const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; + struct device *dev = wiz->dev; + struct device_node *clk_node; + const char *node_name; + struct clk *clk; + int ret; + int i; + + clk = devm_clk_get(dev, "core_ref_clk"); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "core_ref_clk clock not found\n"); + + wiz->input_clks[WIZ_CORE_REFCLK] = clk; + + if (wiz->data->pma_cmn_refclk1_int_mode) { + clk = devm_clk_get(dev, "core_ref1_clk"); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "core_ref1_clk clock not found\n"); + + wiz->input_clks[WIZ_CORE_REFCLK1] = clk; + } + + clk = devm_clk_get(dev, "ext_ref_clk"); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "ext_ref_clk clock not found\n"); + + wiz->input_clks[WIZ_EXT_REFCLK] = clk; + + wiz_clock_init(wiz); switch (wiz->type) { case AM64_WIZ_10G: @@ -1157,8 +1162,9 @@ case J721S2_WIZ_10G: ret = wiz_clock_register(wiz); if (ret) - dev_err(dev, "Failed to register wiz clocks\n"); - return ret; + return dev_err_probe(dev, ret, "Failed to register wiz clocks\n"); + + return 0; default: break; } @@ -1167,16 +1173,15 @@ node_name = clk_mux_sel[i].node_name; clk_node = of_get_child_by_name(node, node_name); if (!clk_node) { - dev_err(dev, "Unable to get %s node\n", node_name); - ret = -EINVAL; + ret = dev_err_probe(dev, -EINVAL, "Unable to get %s node\n", node_name); goto err; } ret = wiz_mux_of_clk_register(wiz, clk_node, wiz->mux_sel_field[i], clk_mux_sel[i].table); if (ret) { - dev_err(dev, "Failed to register %s clock\n", - node_name); + dev_err_probe(dev, ret, "Failed to register %s clock\n", + node_name); of_node_put(clk_node); goto err; } @@ -1188,16 +1193,15 @@ node_name = clk_div_sel[i].node_name; clk_node = of_get_child_by_name(node, node_name); if (!clk_node) { - dev_err(dev, "Unable to get %s node\n", node_name); - ret = -EINVAL; + ret = dev_err_probe(dev, -EINVAL, "Unable to get %s node\n", node_name); goto err; } ret = wiz_div_clk_register(wiz, clk_node, wiz->div_sel_field[i], clk_div_sel[i].table); if (ret) { - dev_err(dev, "Failed to register %s clock\n", - node_name); + dev_err_probe(dev, ret, "Failed to register %s clock\n", + node_name); of_node_put(clk_node); goto err; } @@ -1240,6 +1244,7 @@ case J721E_WIZ_10G: case J7200_WIZ_10G: case J721S2_WIZ_10G: + case J784S4_WIZ_10G: if (wiz->lane_phy_type[lane] == PHY_TYPE_SGMII) return regmap_field_write(wiz->p0_fullrt_div[lane], 0x2); break; @@ -1592,7 +1597,7 @@ goto err_get_sync; } - ret = wiz_clock_init(wiz, node); + ret = wiz_clock_probe(wiz, node); if (ret < 0) { dev_warn(dev, "Failed to initialize clocks\n"); goto err_get_sync; @@ -1654,12 +1659,41 @@ pm_runtime_disable(dev); } +static int wiz_resume_noirq(struct device *dev) +{ + struct device_node *node = dev->of_node; + struct wiz *wiz = dev_get_drvdata(dev); + int ret; + + /* Enable supplemental Control override if available */ + if (wiz->sup_legacy_clk_override) + regmap_field_write(wiz->sup_legacy_clk_override, 1); + + wiz_clock_init(wiz); + + ret = wiz_init(wiz); + if (ret) { + dev_err(dev, "WIZ initialization failed\n"); + goto err_wiz_init; + } + + return 0; + +err_wiz_init: + wiz_clock_cleanup(wiz, node); + + return ret; +} + +static DEFINE_NOIRQ_DEV_PM_OPS(wiz_pm_ops, NULL, wiz_resume_noirq); + static struct platform_driver wiz_driver = { .probe = wiz_probe, .remove_new = wiz_remove, .driver = { .name = "wiz", .of_match_table = wiz_id_table, + .pm = pm_sleep_ptr(&wiz_pm_ops), }, }; module_platform_driver(wiz_driver); diff -Naur --no-dereference a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig --- a/drivers/pinctrl/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/pinctrl/Kconfig 2024-07-07 20:37:34.672306689 -0400 @@ -469,6 +469,22 @@ depends on OF && ARC_PLAT_TB10X select GPIOLIB +config PINCTRL_TPS6594 + tristate "Pinctrl and GPIO driver for TI TPS6594 PMIC" + depends on OF && MFD_TPS6594 + default MFD_TPS6594 + select PINMUX + select GPIOLIB + select REGMAP + select GPIO_REGMAP + select GENERIC_PINCONF + help + Say Y to select the pinmuxing and GPIOs driver for the TPS6594 + PMICs chip family. + + This driver can also be built as a module + called tps6594-pinctrl. + config PINCTRL_ZYNQ bool "Pinctrl driver for Xilinx Zynq" depends on ARCH_ZYNQ diff -Naur --no-dereference a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile --- a/drivers/pinctrl/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/pinctrl/Makefile 2024-07-07 20:37:34.672306689 -0400 @@ -48,6 +48,7 @@ obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o +obj-$(CONFIG_PINCTRL_TPS6594) += pinctrl-tps6594.o obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o diff -Naur --no-dereference a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c --- a/drivers/pinctrl/pinctrl-single.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/pinctrl/pinctrl-single.c 2024-07-07 20:37:34.672306689 -0400 @@ -1625,7 +1625,6 @@ return 0; } -#ifdef CONFIG_PM static int pcs_save_context(struct pcs_device *pcs) { int i, mux_bytes; @@ -1690,14 +1689,9 @@ } } -static int pinctrl_single_suspend(struct platform_device *pdev, - pm_message_t state) +static int pinctrl_single_suspend_noirq(struct device *dev) { - struct pcs_device *pcs; - - pcs = platform_get_drvdata(pdev); - if (!pcs) - return -EINVAL; + struct pcs_device *pcs = dev_get_drvdata(dev); if (pcs->flags & PCS_CONTEXT_LOSS_OFF) { int ret; @@ -1710,20 +1704,19 @@ return pinctrl_force_sleep(pcs->pctl); } -static int pinctrl_single_resume(struct platform_device *pdev) +static int pinctrl_single_resume_noirq(struct device *dev) { - struct pcs_device *pcs; - - pcs = platform_get_drvdata(pdev); - if (!pcs) - return -EINVAL; + struct pcs_device *pcs = dev_get_drvdata(dev); if (pcs->flags & PCS_CONTEXT_LOSS_OFF) pcs_restore_context(pcs); return pinctrl_force_default(pcs->pctl); } -#endif + +static DEFINE_NOIRQ_DEV_PM_OPS(pinctrl_single_pm_ops, + pinctrl_single_suspend_noirq, + pinctrl_single_resume_noirq); /** * pcs_quirk_missing_pinctrl_cells - handle legacy binding @@ -1960,6 +1953,10 @@ .irq_status_mask = (1 << 30), /* WKUP_EVT */ }; +static const struct pcs_soc_data pinctrl_single_j7200 = { + .flags = PCS_CONTEXT_LOSS_OFF, +}; + static const struct pcs_soc_data pinctrl_single = { }; @@ -1974,6 +1971,7 @@ { .compatible = "ti,omap3-padconf", .data = &pinctrl_single_omap_wkup }, { .compatible = "ti,omap4-padconf", .data = &pinctrl_single_omap_wkup }, { .compatible = "ti,omap5-padconf", .data = &pinctrl_single_omap_wkup }, + { .compatible = "ti,j7200-padconf", .data = &pinctrl_single_j7200 }, { .compatible = "pinctrl-single", .data = &pinctrl_single }, { .compatible = "pinconf-single", .data = &pinconf_single }, { }, @@ -1986,11 +1984,8 @@ .driver = { .name = DRIVER_NAME, .of_match_table = pcs_of_match, + .pm = pm_sleep_ptr(&pinctrl_single_pm_ops), }, -#ifdef CONFIG_PM - .suspend = pinctrl_single_suspend, - .resume = pinctrl_single_resume, -#endif }; module_platform_driver(pcs_driver); diff -Naur --no-dereference a/drivers/pinctrl/pinctrl-tps6594.c b/drivers/pinctrl/pinctrl-tps6594.c --- a/drivers/pinctrl/pinctrl-tps6594.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/pinctrl/pinctrl-tps6594.c 2024-07-07 20:37:34.672306689 -0400 @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Pinmux and GPIO driver for tps6594 PMIC + * + * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/ + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define TPS6594_PINCTRL_PINS_NB 11 + +#define TPS6594_PINCTRL_GPIO_FUNCTION 0 +#define TPS6594_PINCTRL_SCL_I2C2_CS_SPI_FUNCTION 1 +#define TPS6594_PINCTRL_TRIG_WDOG_FUNCTION 1 +#define TPS6594_PINCTRL_CLK32KOUT_FUNCTION 1 +#define TPS6594_PINCTRL_SCLK_SPMI_FUNCTION 1 +#define TPS6594_PINCTRL_SDATA_SPMI_FUNCTION 1 +#define TPS6594_PINCTRL_NERR_MCU_FUNCTION 1 +#define TPS6594_PINCTRL_PDOG_FUNCTION 1 +#define TPS6594_PINCTRL_SYNCCLKIN_FUNCTION 1 +#define TPS6594_PINCTRL_NRSTOUT_SOC_FUNCTION 2 +#define TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION 2 +#define TPS6594_PINCTRL_SDA_I2C2_SDO_SPI_FUNCTION 2 +#define TPS6594_PINCTRL_NERR_SOC_FUNCTION 2 +#define TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION 3 +#define TPS6594_PINCTRL_NSLEEP1_FUNCTION 4 +#define TPS6594_PINCTRL_NSLEEP2_FUNCTION 5 +#define TPS6594_PINCTRL_WKUP1_FUNCTION 6 +#define TPS6594_PINCTRL_WKUP2_FUNCTION 7 + +/* Special muxval for recalcitrant pins */ +#define TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION_GPIO8 2 +#define TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION_GPIO8 3 +#define TPS6594_PINCTRL_CLK32KOUT_FUNCTION_GPIO9 3 + +#define TPS6594_OFFSET_GPIO_SEL 5 + +#define FUNCTION(fname, v) \ +{ \ + .pinfunction = PINCTRL_PINFUNCTION(#fname, \ + tps6594_##fname##_func_group_names, \ + ARRAY_SIZE(tps6594_##fname##_func_group_names)),\ + .muxval = v, \ +} + +static const struct pinctrl_pin_desc tps6594_pins[TPS6594_PINCTRL_PINS_NB] = { + PINCTRL_PIN(0, "GPIO0"), PINCTRL_PIN(1, "GPIO1"), + PINCTRL_PIN(2, "GPIO2"), PINCTRL_PIN(3, "GPIO3"), + PINCTRL_PIN(4, "GPIO4"), PINCTRL_PIN(5, "GPIO5"), + PINCTRL_PIN(6, "GPIO6"), PINCTRL_PIN(7, "GPIO7"), + PINCTRL_PIN(8, "GPIO8"), PINCTRL_PIN(9, "GPIO9"), + PINCTRL_PIN(10, "GPIO10"), +}; + +static const char *const tps6594_gpio_func_group_names[] = { + "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", + "GPIO6", "GPIO7", "GPIO8", "GPIO9", "GPIO10", +}; + +static const char *const tps6594_nsleep1_func_group_names[] = { + "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", + "GPIO6", "GPIO7", "GPIO8", "GPIO9", "GPIO10", +}; + +static const char *const tps6594_nsleep2_func_group_names[] = { + "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", + "GPIO6", "GPIO7", "GPIO8", "GPIO9", "GPIO10", +}; + +static const char *const tps6594_wkup1_func_group_names[] = { + "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", + "GPIO6", "GPIO7", "GPIO8", "GPIO9", "GPIO10", +}; + +static const char *const tps6594_wkup2_func_group_names[] = { + "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", + "GPIO6", "GPIO7", "GPIO8", "GPIO9", "GPIO10", +}; + +static const char *const tps6594_scl_i2c2_cs_spi_func_group_names[] = { + "GPIO0", + "GPIO1", +}; + +static const char *const tps6594_nrstout_soc_func_group_names[] = { + "GPIO0", + "GPIO10", +}; + +static const char *const tps6594_trig_wdog_func_group_names[] = { + "GPIO1", + "GPIO10", +}; + +static const char *const tps6594_sda_i2c2_sdo_spi_func_group_names[] = { + "GPIO1", +}; + +static const char *const tps6594_clk32kout_func_group_names[] = { + "GPIO2", + "GPIO3", + "GPIO7", +}; + +static const char *const tps6594_nerr_soc_func_group_names[] = { + "GPIO2", +}; + +static const char *const tps6594_sclk_spmi_func_group_names[] = { + "GPIO4", +}; + +static const char *const tps6594_sdata_spmi_func_group_names[] = { + "GPIO5", +}; + +static const char *const tps6594_nerr_mcu_func_group_names[] = { + "GPIO6", +}; + +static const char *const tps6594_syncclkout_func_group_names[] = { + "GPIO7", + "GPIO9", +}; + +static const char *const tps6594_disable_wdog_func_group_names[] = { + "GPIO7", + "GPIO8", +}; + +static const char *const tps6594_pdog_func_group_names[] = { + "GPIO8", +}; + +static const char *const tps6594_syncclkin_func_group_names[] = { + "GPIO9", +}; + +struct tps6594_pinctrl_function { + struct pinfunction pinfunction; + u8 muxval; +}; + +static const struct tps6594_pinctrl_function pinctrl_functions[] = { + FUNCTION(gpio, TPS6594_PINCTRL_GPIO_FUNCTION), + FUNCTION(nsleep1, TPS6594_PINCTRL_NSLEEP1_FUNCTION), + FUNCTION(nsleep2, TPS6594_PINCTRL_NSLEEP2_FUNCTION), + FUNCTION(wkup1, TPS6594_PINCTRL_WKUP1_FUNCTION), + FUNCTION(wkup2, TPS6594_PINCTRL_WKUP2_FUNCTION), + FUNCTION(scl_i2c2_cs_spi, TPS6594_PINCTRL_SCL_I2C2_CS_SPI_FUNCTION), + FUNCTION(nrstout_soc, TPS6594_PINCTRL_NRSTOUT_SOC_FUNCTION), + FUNCTION(trig_wdog, TPS6594_PINCTRL_TRIG_WDOG_FUNCTION), + FUNCTION(sda_i2c2_sdo_spi, TPS6594_PINCTRL_SDA_I2C2_SDO_SPI_FUNCTION), + FUNCTION(clk32kout, TPS6594_PINCTRL_CLK32KOUT_FUNCTION), + FUNCTION(nerr_soc, TPS6594_PINCTRL_NERR_SOC_FUNCTION), + FUNCTION(sclk_spmi, TPS6594_PINCTRL_SCLK_SPMI_FUNCTION), + FUNCTION(sdata_spmi, TPS6594_PINCTRL_SDATA_SPMI_FUNCTION), + FUNCTION(nerr_mcu, TPS6594_PINCTRL_NERR_MCU_FUNCTION), + FUNCTION(syncclkout, TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION), + FUNCTION(disable_wdog, TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION), + FUNCTION(pdog, TPS6594_PINCTRL_PDOG_FUNCTION), + FUNCTION(syncclkin, TPS6594_PINCTRL_SYNCCLKIN_FUNCTION), +}; + +struct tps6594_pinctrl { + struct tps6594 *tps; + struct gpio_regmap *gpio_regmap; + struct pinctrl_dev *pctl_dev; + const struct tps6594_pinctrl_function *funcs; + const struct pinctrl_pin_desc *pins; +}; + +static int tps6594_gpio_regmap_xlate(struct gpio_regmap *gpio, + unsigned int base, unsigned int offset, + unsigned int *reg, unsigned int *mask) +{ + unsigned int line = offset % 8; + unsigned int stride = offset / 8; + + switch (base) { + case TPS6594_REG_GPIOX_CONF(0): + *reg = TPS6594_REG_GPIOX_CONF(offset); + *mask = TPS6594_BIT_GPIO_DIR; + return 0; + case TPS6594_REG_GPIO_IN_1: + case TPS6594_REG_GPIO_OUT_1: + *reg = base + stride; + *mask = BIT(line); + return 0; + default: + return -EINVAL; + } +} + +static int tps6594_pmx_func_cnt(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(pinctrl_functions); +} + +static const char *tps6594_pmx_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + + return pinctrl->funcs[selector].pinfunction.name; +} + +static int tps6594_pmx_func_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char *const **groups, + unsigned int *num_groups) +{ + struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pinctrl->funcs[selector].pinfunction.groups; + *num_groups = pinctrl->funcs[selector].pinfunction.ngroups; + + return 0; +} + +static int tps6594_pmx_set(struct tps6594_pinctrl *pinctrl, unsigned int pin, + u8 muxval) +{ + u8 mux_sel_val = muxval << TPS6594_OFFSET_GPIO_SEL; + + return regmap_update_bits(pinctrl->tps->regmap, + TPS6594_REG_GPIOX_CONF(pin), + TPS6594_MASK_GPIO_SEL, mux_sel_val); +} + +static int tps6594_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, unsigned int group) +{ + struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + u8 muxval = pinctrl->funcs[function].muxval; + + /* Some pins don't have the same muxval for the same function... */ + if (group == 8) { + if (muxval == TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION) + muxval = TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION_GPIO8; + else if (muxval == TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION) + muxval = TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION_GPIO8; + } else if (group == 9) { + if (muxval == TPS6594_PINCTRL_CLK32KOUT_FUNCTION) + muxval = TPS6594_PINCTRL_CLK32KOUT_FUNCTION_GPIO9; + } + + return tps6594_pmx_set(pinctrl, group, muxval); +} + +static int tps6594_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset, bool input) +{ + struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + u8 muxval = pinctrl->funcs[TPS6594_PINCTRL_GPIO_FUNCTION].muxval; + + return tps6594_pmx_set(pinctrl, offset, muxval); +} + +static const struct pinmux_ops tps6594_pmx_ops = { + .get_functions_count = tps6594_pmx_func_cnt, + .get_function_name = tps6594_pmx_func_name, + .get_function_groups = tps6594_pmx_func_groups, + .set_mux = tps6594_pmx_set_mux, + .gpio_set_direction = tps6594_pmx_gpio_set_direction, + .strict = true, +}; + +static int tps6594_groups_cnt(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(tps6594_pins); +} + +static int tps6594_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, const unsigned int **pins, + unsigned int *num_pins) +{ + struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = &pinctrl->pins[selector].number; + *num_pins = 1; + + return 0; +} + +static const char *tps6594_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + + return pinctrl->pins[selector].name; +} + +static const struct pinctrl_ops tps6594_pctrl_ops = { + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinconf_generic_dt_free_map, + .get_groups_count = tps6594_groups_cnt, + .get_group_name = tps6594_group_name, + .get_group_pins = tps6594_group_pins, +}; + +static int tps6594_pinctrl_probe(struct platform_device *pdev) +{ + struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct tps6594_pinctrl *pinctrl; + struct pinctrl_desc *pctrl_desc; + struct gpio_regmap_config config = {}; + + pctrl_desc = devm_kzalloc(dev, sizeof(*pctrl_desc), GFP_KERNEL); + if (!pctrl_desc) + return -ENOMEM; + pctrl_desc->name = dev_name(dev); + pctrl_desc->owner = THIS_MODULE; + pctrl_desc->pins = tps6594_pins; + pctrl_desc->npins = ARRAY_SIZE(tps6594_pins); + pctrl_desc->pctlops = &tps6594_pctrl_ops; + pctrl_desc->pmxops = &tps6594_pmx_ops; + + pinctrl = devm_kzalloc(dev, sizeof(*pinctrl), GFP_KERNEL); + if (!pinctrl) + return -ENOMEM; + pinctrl->tps = dev_get_drvdata(dev->parent); + pinctrl->funcs = pinctrl_functions; + pinctrl->pins = tps6594_pins; + pinctrl->pctl_dev = devm_pinctrl_register(dev, pctrl_desc, pinctrl); + if (IS_ERR(pinctrl->pctl_dev)) + return dev_err_probe(dev, PTR_ERR(pinctrl->pctl_dev), + "Couldn't register pinctrl driver\n"); + + config.parent = tps->dev; + config.regmap = tps->regmap; + config.ngpio = TPS6594_PINCTRL_PINS_NB; + config.ngpio_per_reg = 8; + config.reg_dat_base = TPS6594_REG_GPIO_IN_1; + config.reg_set_base = TPS6594_REG_GPIO_OUT_1; + config.reg_dir_out_base = TPS6594_REG_GPIOX_CONF(0); + config.reg_mask_xlate = tps6594_gpio_regmap_xlate; + + pinctrl->gpio_regmap = devm_gpio_regmap_register(dev, &config); + if (IS_ERR(pinctrl->gpio_regmap)) + return dev_err_probe(dev, PTR_ERR(pinctrl->gpio_regmap), + "Couldn't register gpio_regmap driver\n"); + + return 0; +} + +static const struct platform_device_id tps6594_pinctrl_id_table[] = { + { "tps6594-pinctrl", }, + {} +}; +MODULE_DEVICE_TABLE(platform, tps6594_pinctrl_id_table); + +static struct platform_driver tps6594_pinctrl_driver = { + .probe = tps6594_pinctrl_probe, + .driver = { + .name = "tps6594-pinctrl", + }, + .id_table = tps6594_pinctrl_id_table, +}; +module_platform_driver(tps6594_pinctrl_driver); + +MODULE_AUTHOR("Esteban Blanc "); +MODULE_DESCRIPTION("TPS6594 pinctrl and GPIO driver"); +MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c --- a/drivers/power/supply/bq27xxx_battery.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/power/supply/bq27xxx_battery.c 2024-07-07 20:37:34.676306709 -0400 @@ -1595,17 +1595,24 @@ * Return the Design Capacity in µAh * Or < 0 if something fails. */ -static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di) +static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di, + union power_supply_propval *val) { int dcap; + /* We only have to read charge design full once */ + if (di->charge_design_full > 0) { + val->intval = di->charge_design_full; + return 0; + } + if (di->opts & BQ27XXX_O_ZERO) dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, true); else dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false); if (dcap < 0) { - dev_dbg(di->dev, "error reading initial last measured discharge\n"); + dev_dbg(di->dev, "error reading design capacity\n"); return dcap; } @@ -1614,7 +1621,12 @@ else dcap *= 1000; - return dcap; + /* Save for later reads */ + di->charge_design_full = dcap; + + val->intval = dcap; + + return 0; } /* @@ -1865,10 +1877,6 @@ */ if (!(di->opts & BQ27XXX_O_ZERO)) bq27xxx_battery_current_and_status(di, NULL, &status, &cache); - - /* We only have to read charge design full once */ - if (di->charge_design_full <= 0) - di->charge_design_full = bq27xxx_battery_read_dcap(di); } if ((di->cache.capacity != cache.capacity) || @@ -2062,7 +2070,7 @@ ret = bq27xxx_simple_value(di->cache.charge_full, val); break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: - ret = bq27xxx_simple_value(di->charge_design_full, val); + ret = bq27xxx_battery_read_dcap(di, val); break; /* * TODO: Implement these to make registers set from @@ -2101,6 +2109,13 @@ mod_delayed_work(system_wq, &di->work, HZ / 2); } +static void bq27xxx_battery_mutex_destroy(void *data) +{ + struct mutex *lock = data; + + mutex_destroy(lock); +} + int bq27xxx_battery_setup(struct bq27xxx_device_info *di) { struct power_supply_desc *psy_desc; @@ -2108,9 +2123,14 @@ .of_node = di->dev->of_node, .drv_data = di, }; + int ret; INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll); mutex_init(&di->lock); + ret = devm_add_action_or_reset(di->dev, bq27xxx_battery_mutex_destroy, + &di->lock); + if (ret) + return ret; di->regs = bq27xxx_chip_data[di->chip].regs; di->unseal_key = bq27xxx_chip_data[di->chip].unseal_key; @@ -2128,7 +2148,7 @@ psy_desc->get_property = bq27xxx_battery_get_property; psy_desc->external_power_changed = bq27xxx_external_power_changed; - di->bat = power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg); + di->bat = devm_power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg); if (IS_ERR(di->bat)) return dev_err_probe(di->dev, PTR_ERR(di->bat), "failed to register battery\n"); @@ -2156,9 +2176,6 @@ mutex_unlock(&di->lock); cancel_delayed_work_sync(&di->work); - - power_supply_unregister(di->bat); - mutex_destroy(&di->lock); } EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown); diff -Naur --no-dereference a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c --- a/drivers/power/supply/bq27xxx_battery_i2c.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/power/supply/bq27xxx_battery_i2c.c 2024-07-07 20:37:34.676306709 -0400 @@ -13,8 +13,7 @@ #include -static DEFINE_IDR(battery_id); -static DEFINE_MUTEX(battery_mutex); +static DEFINE_IDA(battery_id); static irqreturn_t bq27xxx_battery_irq_handler_thread(int irq, void *data) { @@ -136,30 +135,39 @@ return 0; } +static void bq27xxx_battery_i2c_devm_ida_free(void *data) +{ + int num = (long)data; + + ida_free(&battery_id, num); +} + static int bq27xxx_battery_i2c_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); struct bq27xxx_device_info *di; int ret; char *name; - int num; + long num; /* Get new ID for the new battery device */ - mutex_lock(&battery_mutex); - num = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL); - mutex_unlock(&battery_mutex); + num = ida_alloc(&battery_id, GFP_KERNEL); if (num < 0) return num; + ret = devm_add_action_or_reset(&client->dev, + bq27xxx_battery_i2c_devm_ida_free, + (void *)num); + if (ret) + return ret; - name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%d", id->name, num); + name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%ld", id->name, num); if (!name) - goto err_mem; + return -ENOMEM; di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL); if (!di) - goto err_mem; + return -ENOMEM; - di->id = num; di->dev = &client->dev; di->chip = id->driver_data; di->name = name; @@ -171,7 +179,7 @@ ret = bq27xxx_battery_setup(di); if (ret) - goto err_failed; + return ret; /* Schedule a polling after about 1 min */ schedule_delayed_work(&di->work, 60 * HZ); @@ -188,21 +196,11 @@ "Unable to register IRQ %d error %d\n", client->irq, ret); bq27xxx_battery_teardown(di); - goto err_failed; + return ret; } } return 0; - -err_mem: - ret = -ENOMEM; - -err_failed: - mutex_lock(&battery_mutex); - idr_remove(&battery_id, num); - mutex_unlock(&battery_mutex); - - return ret; } static void bq27xxx_battery_i2c_remove(struct i2c_client *client) @@ -213,10 +211,6 @@ free_irq(client->irq, di); bq27xxx_battery_teardown(di); - - mutex_lock(&battery_mutex); - idr_remove(&battery_id, di->id); - mutex_unlock(&battery_mutex); } static const struct i2c_device_id bq27xxx_i2c_id_table[] = { diff -Naur --no-dereference a/drivers/regulator/tps6594-regulator.c b/drivers/regulator/tps6594-regulator.c --- a/drivers/regulator/tps6594-regulator.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/regulator/tps6594-regulator.c 2024-07-07 20:37:34.676306709 -0400 @@ -287,30 +287,30 @@ static const struct regulator_desc multi_regs[] = { TPS6594_REGULATOR("BUCK12", "buck12", TPS6594_BUCK_1, REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_VOUT_1(1), + TPS6594_REG_BUCKX_VOUT_1(0), TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_CTRL(1), + TPS6594_REG_BUCKX_CTRL(0), TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges, 4, 4000, 0, NULL, 0, 0), TPS6594_REGULATOR("BUCK34", "buck34", TPS6594_BUCK_3, REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_VOUT_1(3), + TPS6594_REG_BUCKX_VOUT_1(2), TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_CTRL(3), + TPS6594_REG_BUCKX_CTRL(2), TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges, 4, 0, 0, NULL, 0, 0), TPS6594_REGULATOR("BUCK123", "buck123", TPS6594_BUCK_1, REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_VOUT_1(1), + TPS6594_REG_BUCKX_VOUT_1(0), TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_CTRL(1), + TPS6594_REG_BUCKX_CTRL(0), TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges, 4, 4000, 0, NULL, 0, 0), TPS6594_REGULATOR("BUCK1234", "buck1234", TPS6594_BUCK_1, REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_VOUT_1(1), + TPS6594_REG_BUCKX_VOUT_1(0), TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_CTRL(1), + TPS6594_REG_BUCKX_CTRL(0), TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges, 4, 4000, 0, NULL, 0, 0), }; diff -Naur --no-dereference a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig --- a/drivers/remoteproc/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/remoteproc/Kconfig 2024-07-07 20:37:34.676306709 -0400 @@ -8,6 +8,7 @@ select FW_LOADER select VIRTIO select WANT_DEV_COREDUMP + select DMA_SHARED_BUFFER help Support for remote processors (such as DSP coprocessors). These are mainly used on embedded systems. @@ -339,6 +340,19 @@ It's safe to say N here if you're not interested in utilizing the DSP slave processors. +config TI_K3_M4_REMOTEPROC + tristate "TI K3 M4 remoteproc support" + depends on ARCH_K3 || COMPILE_TEST + select MAILBOX + select OMAP2PLUS_MBOX + help + Say m here to support TI's M4 remote processor subsystems + on various TI K3 family of SoCs through the remote processor + framework. + + It's safe to say N here if you're not interested in utilizing + a remote processor. + config TI_K3_R5_REMOTEPROC tristate "TI K3 R5 remoteproc support" depends on ARCH_K3 diff -Naur --no-dereference a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile --- a/drivers/remoteproc/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/remoteproc/Makefile 2024-07-07 20:37:34.676306709 -0400 @@ -37,5 +37,6 @@ obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o obj-$(CONFIG_TI_K3_DSP_REMOTEPROC) += ti_k3_dsp_remoteproc.o +obj-$(CONFIG_TI_K3_M4_REMOTEPROC) += ti_k3_m4_remoteproc.o obj-$(CONFIG_TI_K3_R5_REMOTEPROC) += ti_k3_r5_remoteproc.o obj-$(CONFIG_XLNX_R5_REMOTEPROC) += xlnx_r5_remoteproc.o diff -Naur --no-dereference a/drivers/remoteproc/remoteproc_cdev.c b/drivers/remoteproc/remoteproc_cdev.c --- a/drivers/remoteproc/remoteproc_cdev.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/remoteproc/remoteproc_cdev.c 2024-07-07 20:37:34.676306709 -0400 @@ -18,9 +18,23 @@ #define NUM_RPROC_DEVICES 64 static dev_t rproc_major; +struct rproc_cdev { + struct rproc *rproc; + bool cdev_put_on_release; + /* Protects the attachments lists */ + struct mutex mutex; + struct list_head attachments; +}; + +struct rproc_cdev_attach { + struct dma_buf *dmabuf; + struct list_head node; +}; + static ssize_t rproc_cdev_write(struct file *filp, const char __user *buf, size_t len, loff_t *pos) { - struct rproc *rproc = container_of(filp->f_inode->i_cdev, struct rproc, cdev); + struct rproc_cdev *rproc_cdev = filp->private_data; + struct rproc *rproc = rproc_cdev->rproc; int ret = 0; char cmd[10]; @@ -47,7 +61,8 @@ static long rproc_device_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { - struct rproc *rproc = container_of(filp->f_inode->i_cdev, struct rproc, cdev); + struct rproc_cdev *rproc_cdev = filp->private_data; + struct rproc *rproc = rproc_cdev->rproc; void __user *argp = (void __user *)arg; s32 param; @@ -56,14 +71,57 @@ if (copy_from_user(¶m, argp, sizeof(s32))) return -EFAULT; - rproc->cdev_put_on_release = !!param; + rproc_cdev->cdev_put_on_release = !!param; break; case RPROC_GET_SHUTDOWN_ON_RELEASE: - param = (s32)rproc->cdev_put_on_release; + param = (s32)rproc_cdev->cdev_put_on_release; if (copy_to_user(argp, ¶m, sizeof(s32))) return -EFAULT; break; + case RPROC_IOC_DMA_BUF_ATTACH: + { + struct rproc_dma_buf_attach_data data; + struct rproc_cdev_attach *attach; + struct dma_buf *dmabuf; + dma_addr_t da; + int ret; + + if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(ioctl))) + return -EFAULT; + + dmabuf = dma_buf_get(data.fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + ret = rproc_attach_dmabuf(rproc, dmabuf); + if (ret) { + dma_buf_put(dmabuf); + return ret; + } + + ret = rproc_dmabuf_get_da(rproc, dmabuf, &da); + if (ret) { + rproc_detach_dmabuf(rproc, dmabuf); + dma_buf_put(dmabuf); + return ret; + } + data.da = da; + + /* Save for later removal */ + attach = kzalloc(sizeof(*attach), GFP_KERNEL); + if (!attach) { + rproc_detach_dmabuf(rproc, dmabuf); + dma_buf_put(dmabuf); + return -ENOMEM; + } + attach->dmabuf = dmabuf; + list_add_tail(&attach->node, &rproc_cdev->attachments); + + if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(ioctl))) + return -EFAULT; + } + break; default: dev_err(&rproc->dev, "Unsupported ioctl\n"); return -EINVAL; @@ -72,18 +130,46 @@ return 0; } -static int rproc_cdev_release(struct inode *inode, struct file *filp) +static int rproc_cdev_open(struct inode *inode, struct file *file) { struct rproc *rproc = container_of(inode->i_cdev, struct rproc, cdev); + struct rproc_cdev *rproc_cdev; + + rproc_cdev = kzalloc(sizeof(*rproc_cdev), GFP_KERNEL); + if (!rproc_cdev) + return -ENOMEM; + + rproc_cdev->rproc = rproc; + mutex_init(&rproc_cdev->mutex); + INIT_LIST_HEAD(&rproc_cdev->attachments); + + file->private_data = rproc_cdev; + + return 0; +} + +static int rproc_cdev_release(struct inode *inode, struct file *filp) +{ + struct rproc_cdev *rproc_cdev = filp->private_data; + struct rproc *rproc = rproc_cdev->rproc; int ret = 0; - if (!rproc->cdev_put_on_release) - return 0; + if (rproc_cdev->cdev_put_on_release) { + if (rproc->state == RPROC_RUNNING) + rproc_shutdown(rproc); + else if (rproc->state == RPROC_ATTACHED) + ret = rproc_detach(rproc); + } - if (rproc->state == RPROC_RUNNING) - rproc_shutdown(rproc); - else if (rproc->state == RPROC_ATTACHED) - ret = rproc_detach(rproc); + /* Release all buffers attached with this file */ + struct rproc_cdev_attach *attach, *atmp; + list_for_each_entry_safe(attach, atmp, &rproc_cdev->attachments, node) { + rproc_detach_dmabuf(rproc, attach->dmabuf); + dma_buf_put(attach->dmabuf); + kfree(attach); + } + mutex_destroy(&rproc_cdev->mutex); + kfree(rproc_cdev); return ret; } @@ -92,6 +178,7 @@ .write = rproc_cdev_write, .unlocked_ioctl = rproc_device_ioctl, .compat_ioctl = compat_ptr_ioctl, + .open = rproc_cdev_open, .release = rproc_cdev_release, }; diff -Naur --no-dereference a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c --- a/drivers/remoteproc/remoteproc_core.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/remoteproc/remoteproc_core.c 2024-07-07 20:37:34.676306709 -0400 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -894,6 +895,125 @@ } EXPORT_SYMBOL(rproc_add_carveout); +static struct rproc_dmabuf_entry *rproc_find_entry_for_dmabuf(struct rproc *rproc, + struct dma_buf *dmabuf) +{ + struct rproc_dmabuf_entry *dmabuf_entry; + + list_for_each_entry(dmabuf_entry, &rproc->dmabufs, node) { + if (dmabuf_entry->dmabuf == dmabuf) + return dmabuf_entry; + } + + return NULL; +} + +/* TODO: Should we map here? */ +int rproc_dmabuf_get_da(struct rproc *rproc, struct dma_buf *dmabuf, dma_addr_t *dma) +{ + struct rproc_dmabuf_entry *dmabuf_entry; + + dmabuf_entry = rproc_find_entry_for_dmabuf(rproc, dmabuf); + if (!dmabuf_entry) + return -EINVAL; + + /* TODO: Should this be ->da? */ + *dma = dmabuf_entry->dma; + + return 0; +} + +/** + * rproc_attach_dmabuf() - attach a DMA-BUF to rproc device + * @rproc: rproc handle + * @dmabuf: dmabuf entry to register + * + * This function attaches and maps specified DMUBUF to this rproc. + */ +int rproc_attach_dmabuf(struct rproc *rproc, struct dma_buf *dmabuf) +{ + struct rproc_dmabuf_entry *dmabuf_entry; + struct device *dev = &rproc->dev; + struct dma_buf_attachment *attachment; + struct sg_table *sgt; + int ret; + + /* Check if already in list */ + dmabuf_entry = rproc_find_entry_for_dmabuf(rproc, dmabuf); + if (dmabuf_entry) { + dmabuf_entry->refcount++; + return 0; + } + + attachment = dma_buf_attach(dmabuf, dev); + if (IS_ERR(attachment)) { + ret = PTR_ERR(attachment); + goto out; + } + + /* TODO: Move mapping to get_da()? */ + sgt = dma_buf_map_attachment(attachment, DMA_BIDIRECTIONAL); + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + goto fail_detach; + } + + /* FIXME: Only physically contiguous buffers currently supported */ + if (sgt->orig_nents != 1) { + dev_err(dev, "DMA-BUF not contiguous\n"); + ret = -EINVAL; + goto fail_unmap; + } + + dmabuf_entry = kzalloc(sizeof(*dmabuf_entry), GFP_KERNEL); + dmabuf_entry->len = sg_dma_len(sgt->sgl); + dmabuf_entry->dma = sg_dma_address(sgt->sgl); + /* TODO: Check this */ +// rproc_pa_to_da(rproc, dmabuf_entry->dma, &dmabuf_entry->da); + dmabuf_entry->dmabuf = dmabuf; + dmabuf_entry->attachment = attachment; + dmabuf_entry->sgt = sgt; + dmabuf_entry->refcount = 1; + + list_add_tail(&dmabuf_entry->node, &rproc->dmabufs); + + return 0; + +fail_unmap: + dma_buf_unmap_attachment(attachment, sgt, DMA_BIDIRECTIONAL); +fail_detach: + dma_buf_detach(dmabuf, attachment); +out: + return ret; +} +EXPORT_SYMBOL(rproc_attach_dmabuf); + +static void rproc_release_dmabuf(struct rproc *rproc, struct rproc_dmabuf_entry *dmabuf_entry) +{ + if (dmabuf_entry->attachment && dmabuf_entry->sgt) + dma_buf_unmap_attachment(dmabuf_entry->attachment, dmabuf_entry->sgt, DMA_BIDIRECTIONAL); + if (dmabuf_entry->dmabuf && dmabuf_entry->attachment) + dma_buf_detach(dmabuf_entry->dmabuf, dmabuf_entry->attachment); + list_del(&dmabuf_entry->node); + kfree(dmabuf_entry); +} + +int rproc_detach_dmabuf(struct rproc *rproc, struct dma_buf *dmabuf) +{ + struct rproc_dmabuf_entry *dmabuf_entry; + + dmabuf_entry = rproc_find_entry_for_dmabuf(rproc, dmabuf); + if (!dmabuf_entry) + return -EINVAL; + + dmabuf_entry->refcount--; + if (dmabuf_entry->refcount < 1) + rproc_release_dmabuf(rproc, dmabuf_entry); + + return 0; +} +EXPORT_SYMBOL(rproc_detach_dmabuf); + /** * rproc_mem_entry_init() - allocate and initialize rproc_mem_entry struct * @dev: pointer on device struct @@ -1220,6 +1340,7 @@ void rproc_resource_cleanup(struct rproc *rproc) { struct rproc_mem_entry *entry, *tmp; + struct rproc_dmabuf_entry *dmabuf, *dtmp; struct rproc_debug_trace *trace, *ttmp; struct rproc_vdev *rvdev, *rvtmp; struct device *dev = &rproc->dev; @@ -1255,6 +1376,10 @@ kfree(entry); } + /* clean up dmabufs */ + list_for_each_entry_safe(dmabuf, dtmp, &rproc->dmabufs, node) + rproc_release_dmabuf(rproc, dmabuf); + /* clean up remote vdev entries */ list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node) platform_device_unregister(rvdev->pdev); @@ -2465,6 +2590,18 @@ rproc->dev.driver_data = rproc; idr_init(&rproc->notifyids); + /* Make device dma capable by inheriting from parent's capabilities */ + set_dma_ops(&rproc->dev, get_dma_ops(rproc->dev.parent)); + if (dma_coerce_mask_and_coherent(&rproc->dev, dma_get_mask(rproc->dev.parent))) + dev_warn(&rproc->dev, "Failed to set DMA mask. Trying to continue...\n"); + rproc->dev.dma_parms = &rproc->dma_parms; + /* + * We could use dma_get_max_seg_size(rproc->dev.parent) here but the + * parent is not usually setup correctly either, use full 32bit mask + * for now. + */ + dma_set_max_seg_size(&rproc->dev, DMA_BIT_MASK(32)); + rproc->name = kstrdup_const(name, GFP_KERNEL); if (!rproc->name) goto put_device; @@ -2489,6 +2626,7 @@ mutex_init(&rproc->lock); INIT_LIST_HEAD(&rproc->carveouts); + INIT_LIST_HEAD(&rproc->dmabufs); INIT_LIST_HEAD(&rproc->mappings); INIT_LIST_HEAD(&rproc->traces); INIT_LIST_HEAD(&rproc->rvdevs); diff -Naur --no-dereference a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h --- a/drivers/remoteproc/remoteproc_internal.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/remoteproc/remoteproc_internal.h 2024-07-07 20:37:34.676306709 -0400 @@ -39,6 +39,26 @@ struct fw_rsc_vdev *rsc; }; +/** + * struct rproc_dmabuf_entry - dmabuf entry descriptor + * @va: virtual address + * @dma: dma address + * @len: length, in bytes + * @da: device address + * + * @node: list node + */ +struct rproc_dmabuf_entry { + size_t len; + dma_addr_t dma; + u32 da; + struct dma_buf *dmabuf; + struct dma_buf_attachment *attachment; + struct sg_table *sgt; + size_t refcount; + struct list_head node; +}; + static inline bool rproc_has_feature(struct rproc *rproc, unsigned int feature) { return test_bit(feature, rproc->features); diff -Naur --no-dereference a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c --- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c 2024-07-07 20:37:34.676306709 -0400 @@ -158,8 +158,8 @@ /* send the index of the triggered virtqueue in the mailbox payload */ ret = mbox_send_message(kproc->mbox, (void *)msg); if (ret < 0) - dev_err(dev, "failed to send mailbox message, status = %d\n", - ret); + dev_err(dev, "failed to send mailbox message (%pe)\n", + ERR_PTR(ret)); } /* Put the DSP processor into reset */ @@ -170,7 +170,7 @@ ret = reset_control_assert(kproc->reset); if (ret) { - dev_err(dev, "local-reset assert failed, ret = %d\n", ret); + dev_err(dev, "local-reset assert failed (%pe)\n", ERR_PTR(ret)); return ret; } @@ -180,7 +180,7 @@ ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, kproc->ti_sci_id); if (ret) { - dev_err(dev, "module-reset assert failed, ret = %d\n", ret); + dev_err(dev, "module-reset assert failed (%pe)\n", ERR_PTR(ret)); if (reset_control_deassert(kproc->reset)) dev_warn(dev, "local-reset deassert back failed\n"); } @@ -200,14 +200,14 @@ ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, kproc->ti_sci_id); if (ret) { - dev_err(dev, "module-reset deassert failed, ret = %d\n", ret); + dev_err(dev, "module-reset deassert failed (%pe)\n", ERR_PTR(ret)); return ret; } lreset: ret = reset_control_deassert(kproc->reset); if (ret) { - dev_err(dev, "local-reset deassert failed, ret = %d\n", ret); + dev_err(dev, "local-reset deassert failed, (%pe)\n", ERR_PTR(ret)); if (kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, kproc->ti_sci_id)) dev_warn(dev, "module-reset assert back failed\n"); @@ -246,7 +246,7 @@ */ ret = mbox_send_message(kproc->mbox, (void *)RP_MBOX_ECHO_REQUEST); if (ret < 0) { - dev_err(dev, "mbox_send_message failed: %d\n", ret); + dev_err(dev, "mbox_send_message failed (%pe)\n", ERR_PTR(ret)); mbox_free_channel(kproc->mbox); return ret; } @@ -272,8 +272,8 @@ ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, kproc->ti_sci_id); if (ret) - dev_err(dev, "module-reset deassert failed, cannot enable internal RAM loading, ret = %d\n", - ret); + dev_err(dev, "module-reset deassert failed, cannot enable internal RAM loading (%pe)\n", + ERR_PTR(ret)); return ret; } @@ -296,7 +296,7 @@ ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, kproc->ti_sci_id); if (ret) - dev_err(dev, "module-reset assert failed, ret = %d\n", ret); + dev_err(dev, "module-reset assert failed (%pe)\n", ERR_PTR(ret)); return ret; } @@ -550,6 +550,13 @@ return 0; } +static void k3_dsp_mem_release(void *data) +{ + struct device *dev = data; + + of_reserved_mem_device_release(dev); +} + static int k3_dsp_reserved_mem_init(struct k3_dsp_rproc *kproc) { struct device *dev = kproc->dev; @@ -561,9 +568,9 @@ num_rmems = of_property_count_elems_of_size(np, "memory-region", sizeof(phandle)); - if (num_rmems <= 0) { - dev_err(dev, "device does not reserved memory regions, ret = %d\n", - num_rmems); + if (num_rmems < 0) { + dev_err(dev, "device does not reserved memory regions (%pe)\n", + ERR_PTR(num_rmems)); return -EINVAL; } if (num_rmems < 2) { @@ -575,31 +582,29 @@ /* use reserved memory region 0 for vring DMA allocations */ ret = of_reserved_mem_device_init_by_idx(dev, np, 0); if (ret) { - dev_err(dev, "device cannot initialize DMA pool, ret = %d\n", - ret); + dev_err(dev, "device cannot initialize DMA pool (%pe)\n", + ERR_PTR(ret)); return ret; } + ret = devm_add_action_or_reset(dev, k3_dsp_mem_release, dev); + if (ret) + return ret; num_rmems--; - kproc->rmem = kcalloc(num_rmems, sizeof(*kproc->rmem), GFP_KERNEL); - if (!kproc->rmem) { - ret = -ENOMEM; - goto release_rmem; - } + kproc->rmem = devm_kcalloc(dev, num_rmems, sizeof(*kproc->rmem), GFP_KERNEL); + if (!kproc->rmem) + return -ENOMEM; /* use remaining reserved memory regions for static carveouts */ for (i = 0; i < num_rmems; i++) { rmem_np = of_parse_phandle(np, "memory-region", i + 1); - if (!rmem_np) { - ret = -EINVAL; - goto unmap_rmem; - } + if (!rmem_np) + return -EINVAL; rmem = of_reserved_mem_lookup(rmem_np); if (!rmem) { of_node_put(rmem_np); - ret = -EINVAL; - goto unmap_rmem; + return -EINVAL; } of_node_put(rmem_np); @@ -607,12 +612,11 @@ /* 64-bit address regions currently not supported */ kproc->rmem[i].dev_addr = (u32)rmem->base; kproc->rmem[i].size = rmem->size; - kproc->rmem[i].cpu_addr = ioremap_wc(rmem->base, rmem->size); + kproc->rmem[i].cpu_addr = devm_ioremap_wc(dev, rmem->base, rmem->size); if (!kproc->rmem[i].cpu_addr) { dev_err(dev, "failed to map reserved memory#%d at %pa of size %pa\n", i + 1, &rmem->base, &rmem->size); - ret = -ENOMEM; - goto unmap_rmem; + return -ENOMEM; } dev_dbg(dev, "reserved memory%d: bus addr %pa size 0x%zx va %pK da 0x%x\n", @@ -623,25 +627,13 @@ kproc->num_rmems = num_rmems; return 0; - -unmap_rmem: - for (i--; i >= 0; i--) - iounmap(kproc->rmem[i].cpu_addr); - kfree(kproc->rmem); -release_rmem: - of_reserved_mem_device_release(kproc->dev); - return ret; } -static void k3_dsp_reserved_mem_exit(struct k3_dsp_rproc *kproc) +static void k3_dsp_release_tsp(void *data) { - int i; + struct ti_sci_proc *tsp = data; - for (i = 0; i < kproc->num_rmems; i++) - iounmap(kproc->rmem[i].cpu_addr); - kfree(kproc->rmem); - - of_reserved_mem_device_release(kproc->dev); + ti_sci_proc_release(tsp); } static @@ -657,7 +649,7 @@ if (ret < 0) return ERR_PTR(ret); - tsp = kzalloc(sizeof(*tsp), GFP_KERNEL); + tsp = devm_kzalloc(dev, sizeof(*tsp), GFP_KERNEL); if (!tsp) return ERR_PTR(-ENOMEM); @@ -680,21 +672,17 @@ const char *fw_name; bool p_state = false; int ret = 0; - int ret1; data = of_device_get_match_data(dev); if (!data) return -ENODEV; ret = rproc_of_parse_firmware(dev, 0, &fw_name); - if (ret) { - dev_err(dev, "failed to parse firmware-name property, ret = %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to parse firmware-name property\n"); - rproc = rproc_alloc(dev, dev_name(dev), &k3_dsp_rproc_ops, fw_name, - sizeof(*kproc)); + rproc = devm_rproc_alloc(dev, dev_name(dev), &k3_dsp_rproc_ops, + fw_name, sizeof(*kproc)); if (!rproc) return -ENOMEM; @@ -709,61 +697,46 @@ kproc->dev = dev; kproc->data = data; - kproc->ti_sci = ti_sci_get_by_phandle(np, "ti,sci"); - if (IS_ERR(kproc->ti_sci)) { - ret = PTR_ERR(kproc->ti_sci); - if (ret != -EPROBE_DEFER) { - dev_err(dev, "failed to get ti-sci handle, ret = %d\n", - ret); - } - kproc->ti_sci = NULL; - goto free_rproc; - } + kproc->ti_sci = devm_ti_sci_get_by_phandle(dev, "ti,sci"); + if (IS_ERR(kproc->ti_sci)) + return dev_err_probe(dev, PTR_ERR(kproc->ti_sci), + "failed to get ti-sci handle\n"); ret = of_property_read_u32(np, "ti,sci-dev-id", &kproc->ti_sci_id); - if (ret) { - dev_err(dev, "missing 'ti,sci-dev-id' property\n"); - goto put_sci; - } + if (ret) + return dev_err_probe(dev, ret, "missing 'ti,sci-dev-id' property\n"); kproc->reset = devm_reset_control_get_exclusive(dev, NULL); - if (IS_ERR(kproc->reset)) { - ret = PTR_ERR(kproc->reset); - dev_err(dev, "failed to get reset, status = %d\n", ret); - goto put_sci; - } + if (IS_ERR(kproc->reset)) + return dev_err_probe(dev, PTR_ERR(kproc->reset), + "failed to get reset\n"); kproc->tsp = k3_dsp_rproc_of_get_tsp(dev, kproc->ti_sci); - if (IS_ERR(kproc->tsp)) { - dev_err(dev, "failed to construct ti-sci proc control, ret = %d\n", - ret); - ret = PTR_ERR(kproc->tsp); - goto put_sci; - } + if (IS_ERR(kproc->tsp)) + return dev_err_probe(dev, PTR_ERR(kproc->tsp), + "failed to construct ti-sci proc control\n"); ret = ti_sci_proc_request(kproc->tsp); if (ret < 0) { - dev_err(dev, "ti_sci_proc_request failed, ret = %d\n", ret); - goto free_tsp; + dev_err_probe(dev, ret, "ti_sci_proc_request failed\n"); + return ret; } + ret = devm_add_action_or_reset(dev, k3_dsp_release_tsp, kproc->tsp); + if (ret) + return ret; ret = k3_dsp_rproc_of_get_memories(pdev, kproc); if (ret) - goto release_tsp; + return ret; ret = k3_dsp_reserved_mem_init(kproc); - if (ret) { - dev_err(dev, "reserved memory init failed, ret = %d\n", ret); - goto release_tsp; - } + if (ret) + return dev_err_probe(dev, ret, "reserved memory init failed\n"); ret = kproc->ti_sci->ops.dev_ops.is_on(kproc->ti_sci, kproc->ti_sci_id, NULL, &p_state); - if (ret) { - dev_err(dev, "failed to get initial state, mode cannot be determined, ret = %d\n", - ret); - goto release_mem; - } + if (ret) + return dev_err_probe(dev, ret, "failed to get initial state, mode cannot be determined\n"); /* configure J721E devices for either remoteproc or IPC-only mode */ if (p_state) { @@ -787,9 +760,7 @@ if (data->uses_lreset) { ret = reset_control_status(kproc->reset); if (ret < 0) { - dev_err(dev, "failed to get reset status, status = %d\n", - ret); - goto release_mem; + return dev_err_probe(dev, ret, "failed to get reset status\n"); } else if (ret == 0) { dev_warn(dev, "local reset is deasserted for device\n"); k3_dsp_rproc_reset(kproc); @@ -797,35 +768,16 @@ } } - ret = rproc_add(rproc); - if (ret) { - dev_err(dev, "failed to add register device with remoteproc core, status = %d\n", - ret); - goto release_mem; - } + ret = devm_rproc_add(dev, rproc); + if (ret) + return dev_err_probe(dev, ret, "failed to add register device with remoteproc core\n"); platform_set_drvdata(pdev, kproc); return 0; - -release_mem: - k3_dsp_reserved_mem_exit(kproc); -release_tsp: - ret1 = ti_sci_proc_release(kproc->tsp); - if (ret1) - dev_err(dev, "failed to release proc, ret = %d\n", ret1); -free_tsp: - kfree(kproc->tsp); -put_sci: - ret1 = ti_sci_put_handle(kproc->ti_sci); - if (ret1) - dev_err(dev, "failed to put ti_sci handle, ret = %d\n", ret1); -free_rproc: - rproc_free(rproc); - return ret; } -static int k3_dsp_rproc_remove(struct platform_device *pdev) +static void k3_dsp_rproc_remove(struct platform_device *pdev) { struct k3_dsp_rproc *kproc = platform_get_drvdata(pdev); struct rproc *rproc = kproc->rproc; @@ -834,28 +786,9 @@ if (rproc->state == RPROC_ATTACHED) { ret = rproc_detach(rproc); - if (ret) { - dev_err(dev, "failed to detach proc, ret = %d\n", ret); - return ret; - } + if (ret) + dev_err(dev, "failed to detach proc (%pe)\n", ERR_PTR(ret)); } - - rproc_del(kproc->rproc); - - ret = ti_sci_proc_release(kproc->tsp); - if (ret) - dev_err(dev, "failed to release proc, ret = %d\n", ret); - - kfree(kproc->tsp); - - ret = ti_sci_put_handle(kproc->ti_sci); - if (ret) - dev_err(dev, "failed to put ti_sci handle, ret = %d\n", ret); - - k3_dsp_reserved_mem_exit(kproc); - rproc_free(kproc->rproc); - - return 0; } static const struct k3_dsp_mem_data c66_mems[] = { @@ -906,7 +839,7 @@ static struct platform_driver k3_dsp_rproc_driver = { .probe = k3_dsp_rproc_probe, - .remove = k3_dsp_rproc_remove, + .remove_new = k3_dsp_rproc_remove, .driver = { .name = "k3-dsp-rproc", .of_match_table = k3_dsp_of_match, diff -Naur --no-dereference a/drivers/remoteproc/ti_k3_m4_remoteproc.c b/drivers/remoteproc/ti_k3_m4_remoteproc.c --- a/drivers/remoteproc/ti_k3_m4_remoteproc.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/remoteproc/ti_k3_m4_remoteproc.c 2024-07-07 20:37:34.676306709 -0400 @@ -0,0 +1,785 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * TI K3 Cortex-M4 Remote Processor(s) driver + * + * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/ + * Hari Nagalla + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "omap_remoteproc.h" +#include "remoteproc_internal.h" +#include "ti_sci_proc.h" + +/** + * struct k3_m4_rproc_mem - internal memory structure + * @cpu_addr: MPU virtual address of the memory region + * @bus_addr: Bus address used to access the memory region + * @dev_addr: Device address of the memory region from remote processor view + * @size: Size of the memory region + */ +struct k3_m4_rproc_mem { + void __iomem *cpu_addr; + phys_addr_t bus_addr; + u32 dev_addr; + size_t size; +}; + +/** + * struct k3_m4_rproc_mem_data - memory definitions for a remote processor + * @name: name for this memory entry + * @dev_addr: device address for the memory entry + */ +struct k3_m4_rproc_mem_data { + const char *name; + const u32 dev_addr; +}; + +/** + * struct k3_m4_rproc_dev_data - device data structure for a remote processor + * @mems: pointer to memory definitions for a remote processor + * @num_mems: number of memory regions in @mems + * @uses_lreset: flag to denote the need for local reset management + */ +struct k3_m4_rproc_dev_data { + const struct k3_m4_rproc_mem_data *mems; + u32 num_mems; + bool uses_lreset; +}; + +/** + * struct k3_m4_rproc - k3 remote processor driver structure + * @dev: cached device pointer + * @rproc: remoteproc device handle + * @mem: internal memory regions data + * @num_mems: number of internal memory regions + * @rmem: reserved memory regions data + * @num_rmems: number of reserved memory regions + * @reset: reset control handle + * @data: pointer to device data + * @tsp: TI-SCI processor control handle + * @ti_sci: TI-SCI handle + * @ti_sci_id: TI-SCI device identifier + * @mbox: mailbox channel handle + * @client: mailbox client to request the mailbox channel + */ +struct k3_m4_rproc { + struct device *dev; + struct rproc *rproc; + struct k3_m4_rproc_mem *mem; + int num_mems; + struct k3_m4_rproc_mem *rmem; + int num_rmems; + struct reset_control *reset; + const struct k3_m4_rproc_dev_data *data; + struct ti_sci_proc *tsp; + const struct ti_sci_handle *ti_sci; + u32 ti_sci_id; + struct mbox_chan *mbox; + struct mbox_client client; +}; + +/** + * k3_m4_rproc_mbox_callback() - inbound mailbox message handler + * @client: mailbox client pointer used for requesting the mailbox channel + * @data: mailbox payload + * + * This handler is invoked by the K3 mailbox driver whenever a mailbox + * message is received. Usually, the mailbox payload simply contains + * the index of the virtqueue that is kicked by the remote processor, + * and we let remoteproc core handle it. + * + * In addition to virtqueue indices, we also have some out-of-band values + * that indicate different events. Those values are deliberately very + * large so they don't coincide with virtqueue indices. + */ +static void k3_m4_rproc_mbox_callback(struct mbox_client *client, void *data) +{ + struct k3_m4_rproc *kproc = container_of(client, struct k3_m4_rproc, + client); + struct device *dev = kproc->rproc->dev.parent; + const char *name = kproc->rproc->name; + u32 msg = (u32)(uintptr_t)(data); + + dev_dbg(dev, "mbox msg: 0x%x\n", msg); + + switch (msg) { + case RP_MBOX_CRASH: + /* + * remoteproc detected an exception, but error recovery is not + * supported. So, just log this for now + */ + dev_err(dev, "K3 rproc %s crashed\n", name); + break; + case RP_MBOX_ECHO_REPLY: + dev_info(dev, "received echo reply from %s\n", name); + break; + default: + /* silently handle all other valid messages */ + if (msg >= RP_MBOX_READY && msg < RP_MBOX_END_MSG) + return; + if (msg > kproc->rproc->max_notifyid) { + dev_dbg(dev, "dropping unknown message 0x%x", msg); + return; + } + /* msg contains the index of the triggered vring */ + if (rproc_vq_interrupt(kproc->rproc, msg) == IRQ_NONE) + dev_dbg(dev, "no message was found in vqid %d\n", msg); + } +} + +/* + * Kick the remote processor to notify about pending unprocessed messages. + * The vqid usage is not used and is inconsequential, as the kick is performed + * through a simulated GPIO (a bit in an IPC interrupt-triggering register), + * the remote processor is expected to process both its Tx and Rx virtqueues. + */ +static void k3_m4_rproc_kick(struct rproc *rproc, int vqid) +{ + struct k3_m4_rproc *kproc = rproc->priv; + struct device *dev = rproc->dev.parent; + u32 msg = (u32)vqid; + int ret; + + /* send the index of the triggered virtqueue in the mailbox payload */ + ret = mbox_send_message(kproc->mbox, (void *)(uintptr_t)msg); + if (ret < 0) + dev_err(dev, "failed to send mailbox message, status = %d\n", + ret); +} + +/* Put the remote processor into reset */ +static int k3_m4_rproc_reset(struct k3_m4_rproc *kproc) +{ + struct device *dev = kproc->dev; + int ret; + + ret = reset_control_assert(kproc->reset); + if (ret) { + dev_err(dev, "local-reset assert failed, ret = %d\n", ret); + return ret; + } + + if (kproc->data->uses_lreset) + return ret; + + ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, + kproc->ti_sci_id); + if (ret) { + dev_err(dev, "module-reset assert failed, ret = %d\n", ret); + if (reset_control_deassert(kproc->reset)) + dev_warn(dev, "local-reset deassert back failed\n"); + } + + return ret; +} + +/* Release the remote processor from reset */ +static int k3_m4_rproc_release(struct k3_m4_rproc *kproc) +{ + struct device *dev = kproc->dev; + int ret; + + if (kproc->data->uses_lreset) + goto lreset; + + ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, + kproc->ti_sci_id); + if (ret) { + dev_err(dev, "module-reset deassert failed, ret = %d\n", ret); + return ret; + } + +lreset: + ret = reset_control_deassert(kproc->reset); + if (ret) { + dev_err(dev, "local-reset deassert failed, ret = %d\n", ret); + if (kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, + kproc->ti_sci_id)) + dev_warn(dev, "module-reset assert back failed\n"); + } + + return ret; +} + +static int k3_m4_rproc_request_mbox(struct rproc *rproc) +{ + struct k3_m4_rproc *kproc = rproc->priv; + struct mbox_client *client = &kproc->client; + struct device *dev = kproc->dev; + int ret; + + client->dev = dev; + client->tx_done = NULL; + client->rx_callback = k3_m4_rproc_mbox_callback; + client->tx_block = false; + client->knows_txdone = false; + + kproc->mbox = mbox_request_channel(client, 0); + if (IS_ERR(kproc->mbox)) { + ret = -EBUSY; + dev_err(dev, "mbox_request_channel failed: %ld\n", + PTR_ERR(kproc->mbox)); + return ret; + } + + /* + * Ping the remote processor, this is only for sanity-sake for now; + * there is no functional effect whatsoever. + * + * Note that the reply will _not_ arrive immediately: this message + * will wait in the mailbox fifo until the remote processor is booted. + */ + ret = mbox_send_message(kproc->mbox, (void *)RP_MBOX_ECHO_REQUEST); + if (ret < 0) { + dev_err(dev, "mbox_send_message failed: %d\n", ret); + mbox_free_channel(kproc->mbox); + return ret; + } + + return 0; +} + +/* + * The M4 cores have a local reset that affects only the CPU, and a + * generic module reset that powers on the device and allows the internal + * memories to be accessed while the local reset is asserted. This function is + * used to release the global reset on remote cores to allow loading into the + * internal RAMs. The .prepare() ops is invoked by remoteproc core before any + * firmware loading, and is followed by the .start() ops after loading to + * actually let the remote cores to run. This callback is invoked only in + * remoteproc mode. + */ +static int k3_m4_rproc_prepare(struct rproc *rproc) +{ + struct k3_m4_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + int ret; + + ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, + kproc->ti_sci_id); + if (ret) + dev_err(dev, "module-reset deassert failed, cannot enable internal RAM loading, ret = %d\n", + ret); + + return ret; +} + +/* + * This function implements the .unprepare() ops and performs the complimentary + * operations to that of the .prepare() ops. The function is used to assert the + * global reset on applicable cores. This completes the second portion of + * powering down the remote core. The cores themselves are only halted in the + * .stop() callback through the local reset, and the .unprepare() ops is invoked + * by the remoteproc core after the remoteproc is stopped to balance the global + * reset. This callback is invoked only in remoteproc mode. + */ +static int k3_m4_rproc_unprepare(struct rproc *rproc) +{ + struct k3_m4_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + int ret; + + ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, + kproc->ti_sci_id); + if (ret) + dev_err(dev, "module-reset assert failed, ret = %d\n", ret); + + return ret; +} + +/* + * This function implements the .get_loaded_rsc_table() callback and is used + * to provide the resource table for a booted remote processor in IPC-only + * mode. The remote processor firmwares follow a design-by-contract approach + * and are expected to have the resource table at the base of the DDR region + * reserved for firmware usage. This provides flexibility for the remote + * processor to be booted by different bootloaders that may or may not have the + * ability to publish the resource table address and size through a DT + * property. + */ +static struct resource_table *k3_m4_get_loaded_rsc_table(struct rproc *rproc, + size_t *rsc_table_sz) +{ + struct k3_m4_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + + if (!kproc->rmem[0].cpu_addr) { + dev_err(dev, "memory-region #1 does not exist, loaded rsc table can't be found"); + return ERR_PTR(-ENOMEM); + } + + /* + * NOTE: The resource table size is currently hard-coded to a maximum + * of 256 bytes. The most common resource table usage for K3 firmwares + * is to only have the vdev resource entry and an optional trace entry. + * The exact size could be computed based on resource table address, but + * the hard-coded value suffices to support the IPC-only mode. + */ + *rsc_table_sz = 256; + return (__force struct resource_table *)kproc->rmem[0].cpu_addr; +} + +/* + * Custom function to translate a remote processor device address (internal + * RAMs only) to a kernel virtual address. The remote processors can access + * their RAMs at either an internal address visible only from a remote + * processor, or at the SoC-level bus address. Both these addresses need to be + * looked through for translation. The translated addresses can be used either + * by the remoteproc core for loading (when using kernel remoteproc loader), or + * by any rpmsg bus drivers. + */ +static void *k3_m4_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) +{ + struct k3_m4_rproc *kproc = rproc->priv; + void __iomem *va = NULL; + phys_addr_t bus_addr; + u32 dev_addr, offset; + size_t size; + int i; + + if (len == 0) + return NULL; + + for (i = 0; i < kproc->num_mems; i++) { + bus_addr = kproc->mem[i].bus_addr; + dev_addr = kproc->mem[i].dev_addr; + size = kproc->mem[i].size; + + /* handle M4-view addresses */ + if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { + offset = da - dev_addr; + va = kproc->mem[i].cpu_addr + offset; + return (__force void *)va; + } + + /* handle SoC-view addresses */ + if (da >= bus_addr && ((da + len) <= (bus_addr + size))) { + offset = da - bus_addr; + va = kproc->mem[i].cpu_addr + offset; + return (__force void *)va; + } + } + + /* handle static DDR reserved memory regions */ + for (i = 0; i < kproc->num_rmems; i++) { + dev_addr = kproc->rmem[i].dev_addr; + size = kproc->rmem[i].size; + + if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { + offset = da - dev_addr; + va = kproc->rmem[i].cpu_addr + offset; + return (__force void *)va; + } + } + + return NULL; +} + +static int k3_m4_rproc_of_get_memories(struct platform_device *pdev, + struct k3_m4_rproc *kproc) +{ + const struct k3_m4_rproc_dev_data *data = kproc->data; + struct device *dev = &pdev->dev; + struct resource *res; + int num_mems = 0; + int i; + + num_mems = kproc->data->num_mems; + kproc->mem = devm_kcalloc(kproc->dev, num_mems, + sizeof(*kproc->mem), GFP_KERNEL); + if (!kproc->mem) + return -ENOMEM; + + for (i = 0; i < num_mems; i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + data->mems[i].name); + if (!res) { + dev_err(dev, "found no memory resource for %s\n", + data->mems[i].name); + return -EINVAL; + } + if (!devm_request_mem_region(dev, res->start, + resource_size(res), + dev_name(dev))) { + dev_err(dev, "could not request %s region for resource\n", + data->mems[i].name); + return -EBUSY; + } + + kproc->mem[i].cpu_addr = devm_ioremap_wc(dev, res->start, + resource_size(res)); + if (!kproc->mem[i].cpu_addr) { + dev_err(dev, "failed to map %s memory\n", + data->mems[i].name); + return -ENOMEM; + } + kproc->mem[i].bus_addr = res->start; + kproc->mem[i].dev_addr = data->mems[i].dev_addr; + kproc->mem[i].size = resource_size(res); + + dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %pK da 0x%x\n", + data->mems[i].name, &kproc->mem[i].bus_addr, + kproc->mem[i].size, kproc->mem[i].cpu_addr, + kproc->mem[i].dev_addr); + } + kproc->num_mems = num_mems; + + return 0; +} + +static void k3_m4_rproc_dev_mem_release(void *data) +{ + struct device *dev = data; + + of_reserved_mem_device_release(dev); +} + +static int k3_m4_reserved_mem_init(struct k3_m4_rproc *kproc) +{ + struct device *dev = kproc->dev; + struct device_node *np = dev->of_node; + struct device_node *rmem_np; + struct reserved_mem *rmem; + int num_rmems; + int ret, i; + + num_rmems = of_property_count_elems_of_size(np, "memory-region", + sizeof(phandle)); + if (num_rmems < 0) { + dev_err(dev, "device does not reserved memory regions (%pe)\n", + ERR_PTR(num_rmems)); + return -EINVAL; + } + if (num_rmems < 2) { + dev_err(dev, "device needs at least two memory regions to be defined, num = %d\n", + num_rmems); + return -EINVAL; + } + + /* use reserved memory region 0 for vring DMA allocations */ + ret = of_reserved_mem_device_init_by_idx(dev, np, 0); + if (ret) { + dev_err(dev, "device cannot initialize DMA pool (%pe)\n", + ERR_PTR(ret)); + return ret; + } + ret = devm_add_action_or_reset(dev, k3_m4_rproc_dev_mem_release, dev); + if (ret) + return ret; + + num_rmems--; + kproc->rmem = devm_kcalloc(dev, num_rmems, sizeof(*kproc->rmem), GFP_KERNEL); + if (!kproc->rmem) + return -ENOMEM; + + /* use remaining reserved memory regions for static carveouts */ + for (i = 0; i < num_rmems; i++) { + rmem_np = of_parse_phandle(np, "memory-region", i + 1); + if (!rmem_np) + return -EINVAL; + + rmem = of_reserved_mem_lookup(rmem_np); + if (!rmem) { + of_node_put(rmem_np); + return -EINVAL; + } + of_node_put(rmem_np); + + kproc->rmem[i].bus_addr = rmem->base; + /* 64-bit address regions currently not supported */ + kproc->rmem[i].dev_addr = (u32)rmem->base; + kproc->rmem[i].size = rmem->size; + kproc->rmem[i].cpu_addr = devm_ioremap_wc(dev, rmem->base, rmem->size); + if (!kproc->rmem[i].cpu_addr) { + dev_err(dev, "failed to map reserved memory#%d at %pa of size %pa\n", + i + 1, &rmem->base, &rmem->size); + return -ENOMEM; + } + + dev_dbg(dev, "reserved memory%d: bus addr %pa size 0x%zx va %pK da 0x%x\n", + i + 1, &kproc->rmem[i].bus_addr, + kproc->rmem[i].size, kproc->rmem[i].cpu_addr, + kproc->rmem[i].dev_addr); + } + kproc->num_rmems = num_rmems; + + return 0; +} + +static struct ti_sci_proc *k3_m4_rproc_of_get_tsp(struct device *dev, + const struct ti_sci_handle *sci) +{ + struct ti_sci_proc *tsp; + u32 temp[2]; + int ret; + + ret = of_property_read_u32_array(dev->of_node, "ti,sci-proc-ids", + temp, 2); + if (ret < 0) + return ERR_PTR(ret); + + tsp = devm_kzalloc(dev, sizeof(*tsp), GFP_KERNEL); + if (!tsp) + return ERR_PTR(-ENOMEM); + + tsp->dev = dev; + tsp->sci = sci; + tsp->ops = &sci->ops.proc_ops; + tsp->proc_id = temp[0]; + tsp->host_id = temp[1]; + + return tsp; +} + +static void k3_m4_release_tsp(void *data) +{ + struct ti_sci_proc *tsp = data; + + ti_sci_proc_release(tsp); +} + +/* + * Power up the M4F remote processor. + * + * This function will be invoked only after the firmware for this rproc + * was loaded, parsed successfully, and all of its resource requirements + * were met. This callback is invoked only in remoteproc mode. + */ +static int k3_m4_rproc_start(struct rproc *rproc) +{ + struct k3_m4_rproc *kproc = rproc->priv; + int ret; + + ret = k3_m4_rproc_request_mbox(rproc); + if (ret) + return ret; + + ret = k3_m4_rproc_release(kproc); + if (ret) + goto put_mbox; + + return 0; + +put_mbox: + mbox_free_channel(kproc->mbox); + return ret; +} + +/* + * Stop the M4 remote processor. + * + * This function puts the M4 processor into reset, and finishes processing + * of any pending messages. This callback is invoked only in remoteproc mode. + */ +static int k3_m4_rproc_stop(struct rproc *rproc) +{ + struct k3_m4_rproc *kproc = rproc->priv; + + mbox_free_channel(kproc->mbox); + + k3_m4_rproc_reset(kproc); + + return 0; +} + +/* + * Attach to a running M4 remote processor (IPC-only mode) + * + * This rproc attach callback only needs to request the mailbox, the remote + * processor is already booted, so there is no need to issue any TI-SCI + * commands to boot the M4 core. This callback is used only in IPC-only mode. + */ +static int k3_m4_rproc_attach(struct rproc *rproc) +{ + struct k3_m4_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + int ret; + + ret = k3_m4_rproc_request_mbox(rproc); + if (ret) + return ret; + + dev_info(dev, "M4 initialized in IPC-only mode\n"); + return 0; +} + +/* + * Detach from a running M4 remote processor (IPC-only mode) + * + * This rproc detach callback performs the opposite operation to attach callback + * and only needs to release the mailbox, the M4 core is not stopped and will + * be left to continue to run its booted firmware. This callback is invoked only in + * IPC-only mode. + */ +static int k3_m4_rproc_detach(struct rproc *rproc) +{ + struct k3_m4_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + + mbox_free_channel(kproc->mbox); + dev_info(dev, "M4 deinitialized in IPC-only mode\n"); + return 0; +} + +static const struct rproc_ops k3_m4_rproc_ops = { + .start = k3_m4_rproc_start, + .stop = k3_m4_rproc_stop, + .attach = k3_m4_rproc_attach, + .detach = k3_m4_rproc_detach, + .kick = k3_m4_rproc_kick, + .da_to_va = k3_m4_rproc_da_to_va, + .get_loaded_rsc_table = k3_m4_get_loaded_rsc_table, +}; + +static int k3_m4_rproc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const struct k3_m4_rproc_dev_data *data; + struct k3_m4_rproc *kproc; + struct rproc *rproc; + const char *fw_name; + bool r_state = false; + bool p_state = false; + int ret = 0; + + data = device_get_match_data(dev); + if (!data) + return -ENODEV; + + ret = rproc_of_parse_firmware(dev, 0, &fw_name); + if (ret) + return dev_err_probe(dev, ret, "failed to parse firmware-name property\n"); + + rproc = devm_rproc_alloc(dev, dev_name(dev), &k3_m4_rproc_ops, fw_name, + sizeof(*kproc)); + if (!rproc) + return -ENOMEM; + + rproc->has_iommu = false; + rproc->recovery_disabled = true; + if (data->uses_lreset) { + rproc->ops->prepare = k3_m4_rproc_prepare; + rproc->ops->unprepare = k3_m4_rproc_unprepare; + } + kproc = rproc->priv; + kproc->rproc = rproc; + kproc->dev = dev; + kproc->data = data; + + kproc->ti_sci = devm_ti_sci_get_by_phandle(dev, "ti,sci"); + if (IS_ERR(kproc->ti_sci)) + return dev_err_probe(dev, PTR_ERR(kproc->ti_sci), + "failed to get ti-sci handle\n"); + + ret = of_property_read_u32(np, "ti,sci-dev-id", &kproc->ti_sci_id); + if (ret) + return dev_err_probe(dev, ret, "missing 'ti,sci-dev-id' property\n"); + + kproc->reset = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(kproc->reset)) + return dev_err_probe(dev, PTR_ERR(kproc->reset), "failed to get reset\n"); + + kproc->tsp = k3_m4_rproc_of_get_tsp(dev, kproc->ti_sci); + if (IS_ERR(kproc->tsp)) + return dev_err_probe(dev, PTR_ERR(kproc->tsp), + "failed to construct ti-sci proc control\n"); + + ret = ti_sci_proc_request(kproc->tsp); + if (ret < 0) + return dev_err_probe(dev, ret, "ti_sci_proc_request failed\n"); + ret = devm_add_action_or_reset(dev, k3_m4_release_tsp, kproc->tsp); + if (ret) + return ret; + + ret = k3_m4_rproc_of_get_memories(pdev, kproc); + if (ret) + return ret; + + ret = k3_m4_reserved_mem_init(kproc); + if (ret) + return dev_err_probe(dev, ret, "reserved memory init failed\n"); + + ret = kproc->ti_sci->ops.dev_ops.is_on(kproc->ti_sci, kproc->ti_sci_id, + &r_state, &p_state); + if (ret) + return dev_err_probe(dev, ret, + "failed to get initial state, mode cannot be determined\n"); + + /* configure devices for either remoteproc or IPC-only mode */ + if (p_state) { + dev_info(dev, "configured M4 for IPC-only mode\n"); + rproc->state = RPROC_DETACHED; + /* override rproc ops with only required IPC-only mode ops */ + rproc->ops->prepare = NULL; + rproc->ops->unprepare = NULL; + rproc->ops->start = NULL; + rproc->ops->stop = NULL; + rproc->ops->attach = k3_m4_rproc_attach; + rproc->ops->detach = k3_m4_rproc_detach; + rproc->ops->get_loaded_rsc_table = k3_m4_get_loaded_rsc_table; + } else { + dev_info(dev, "configured M4 for remoteproc mode\n"); + /* + * ensure the M4 local reset is asserted to ensure the core + * doesn't execute bogus code in .prepare() when the module + * reset is released. + */ + if (data->uses_lreset) { + ret = reset_control_status(kproc->reset); + if (ret < 0) { + return dev_err_probe(dev, ret, "failed to get reset status\n"); + } else if (ret == 0) { + dev_warn(dev, "local reset is deasserted for device\n"); + k3_m4_rproc_reset(kproc); + } + } + } + + ret = devm_rproc_add(dev, rproc); + if (ret) + return dev_err_probe(dev, ret, + "failed to add register device with remoteproc core\n"); + + return 0; +} + +static const struct k3_m4_rproc_mem_data am64_m4_mems[] = { + { .name = "iram", .dev_addr = 0x0 }, + { .name = "dram", .dev_addr = 0x30000 }, +}; + +static const struct k3_m4_rproc_dev_data am64_m4_data = { + .mems = am64_m4_mems, + .num_mems = ARRAY_SIZE(am64_m4_mems), + .uses_lreset = true, +}; + +static const struct of_device_id k3_m4_of_match[] = { + { .compatible = "ti,am64-m4fss", .data = &am64_m4_data, }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, k3_m4_of_match); + +static struct platform_driver k3_m4_rproc_driver = { + .probe = k3_m4_rproc_probe, + .driver = { + .name = "k3-m4-rproc", + .of_match_table = k3_m4_of_match, + }, +}; +module_platform_driver(k3_m4_rproc_driver); + +MODULE_AUTHOR("Hari Nagalla "); +MODULE_DESCRIPTION("TI K3 M4 Remoteproc driver"); +MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c 2024-07-07 20:37:34.676306709 -0400 @@ -103,12 +103,14 @@ * @dev: cached device pointer * @mode: Mode to configure the Cluster - Split or LockStep * @cores: list of R5 cores within the cluster + * @core_transition: wait queue to sync core state changes * @soc_data: SoC-specific feature data for a R5FSS */ struct k3_r5_cluster { struct device *dev; enum cluster_mode mode; struct list_head cores; + wait_queue_head_t core_transition; const struct k3_r5_soc_data *soc_data; }; @@ -128,6 +130,7 @@ * @atcm_enable: flag to control ATCM enablement * @btcm_enable: flag to control BTCM enablement * @loczrama: flag to dictate which TCM is at device address 0x0 + * @released_from_reset: flag to signal when core is out of reset */ struct k3_r5_core { struct list_head elem; @@ -144,6 +147,7 @@ u32 atcm_enable; u32 btcm_enable; u32 loczrama; + bool released_from_reset; }; /** @@ -460,6 +464,8 @@ ret); return ret; } + core->released_from_reset = true; + wake_up_interruptible(&cluster->core_transition); /* * Newer IP revisions like on J7200 SoCs support h/w auto-initialization @@ -542,7 +548,7 @@ struct k3_r5_rproc *kproc = rproc->priv; struct k3_r5_cluster *cluster = kproc->cluster; struct device *dev = kproc->dev; - struct k3_r5_core *core; + struct k3_r5_core *core0, *core; u32 boot_addr; int ret; @@ -568,6 +574,16 @@ goto unroll_core_run; } } else { + /* do not allow core 1 to start before core 0 */ + core0 = list_first_entry(&cluster->cores, struct k3_r5_core, + elem); + if (core != core0 && core0->rproc->state == RPROC_OFFLINE) { + dev_err(dev, "%s: can not start core 1 before core 0\n", + __func__); + ret = -EPERM; + goto put_mbox; + } + ret = k3_r5_core_run(core); if (ret) goto put_mbox; @@ -613,7 +629,8 @@ { struct k3_r5_rproc *kproc = rproc->priv; struct k3_r5_cluster *cluster = kproc->cluster; - struct k3_r5_core *core = kproc->core; + struct device *dev = kproc->dev; + struct k3_r5_core *core1, *core = kproc->core; int ret; /* halt all applicable cores */ @@ -626,6 +643,16 @@ } } } else { + /* do not allow core 0 to stop before core 1 */ + core1 = list_last_entry(&cluster->cores, struct k3_r5_core, + elem); + if (core != core1 && core1->rproc->state != RPROC_OFFLINE) { + dev_err(dev, "%s: can not stop core 0 before core 1\n", + __func__); + ret = -EPERM; + goto out; + } + ret = k3_r5_core_halt(core); if (ret) goto out; @@ -1140,6 +1167,12 @@ return ret; } + /* + * Skip the waiting mechanism for sequential power-on of cores if the + * core has already been booted by another entity. + */ + core->released_from_reset = c_state; + ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl, &stat); if (ret < 0) { @@ -1280,6 +1313,26 @@ cluster->mode == CLUSTER_MODE_SINGLECPU || cluster->mode == CLUSTER_MODE_SINGLECORE) break; + + /* + * R5 cores require to be powered on sequentially, core0 + * should be in higher power state than core1 in a cluster + * So, wait for current core to power up before proceeding + * to next core and put timeout of 2sec for each core. + * + * This waiting mechanism is necessary because + * rproc_auto_boot_callback() for core1 can be called before + * core0 due to thread execution order. + */ + ret = wait_event_interruptible_timeout(cluster->core_transition, + core->released_from_reset, + msecs_to_jiffies(2000)); + if (ret <= 0) { + dev_err(dev, + "Timed out waiting for %s core to power up!\n", + rproc->name); + return ret; + } } return 0; @@ -1709,6 +1762,7 @@ cluster->dev = dev; cluster->soc_data = data; INIT_LIST_HEAD(&cluster->cores); + init_waitqueue_head(&cluster->core_transition); ret = of_property_read_u32(np, "ti,cluster-mode", &cluster->mode); if (ret < 0 && ret != -EINVAL) { diff -Naur --no-dereference a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c --- a/drivers/rpmsg/rpmsg_char.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/rpmsg/rpmsg_char.c 2024-07-07 20:37:34.676306709 -0400 @@ -170,6 +170,9 @@ ept->flow_cb = rpmsg_ept_flow_cb; eptdev->ept = ept; + if (eptdev->chinfo.src == RPMSG_ADDR_ANY) + eptdev->chinfo.src = ept->addr; + filp->private_data = eptdev; mutex_unlock(&eptdev->ept_lock); @@ -522,6 +525,7 @@ static struct rpmsg_device_id rpmsg_chrdev_id_table[] = { { .name = "rpmsg-raw" }, + { .name = "rpmsg_chrdev" }, { }, }; diff -Naur --no-dereference a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig --- a/drivers/rtc/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/rtc/Kconfig 2024-07-07 20:37:34.676306709 -0400 @@ -578,6 +578,18 @@ along with alarm. This driver supports the RTC driver for the TPS6586X RTC module. +config RTC_DRV_TPS6594 + tristate "TI TPS6594 RTC driver" + depends on MFD_TPS6594 + default MFD_TPS6594 + help + TI Power Management IC TPS6594 supports RTC functionality + along with alarm. This driver supports the RTC driver for + the TPS6594 RTC module. + + This driver can also be built as a module. If so, the module + will be called rtc-tps6594. + config RTC_DRV_TPS65910 tristate "TI TPS65910 RTC driver" depends on MFD_TPS65910 diff -Naur --no-dereference a/drivers/rtc/Makefile b/drivers/rtc/Makefile --- a/drivers/rtc/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/rtc/Makefile 2024-07-07 20:37:34.676306709 -0400 @@ -175,6 +175,7 @@ obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o +obj-$(CONFIG_RTC_DRV_TPS6594) += rtc-tps6594.o obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o diff -Naur --no-dereference a/drivers/rtc/rtc-tps6594.c b/drivers/rtc/rtc-tps6594.c --- a/drivers/rtc/rtc-tps6594.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/rtc/rtc-tps6594.c 2024-07-07 20:37:34.676306709 -0400 @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RTC driver for tps6594 PMIC + * + * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// Total number of RTC registers needed to set time +#define NUM_TIME_REGS (TPS6594_REG_RTC_WEEKS - TPS6594_REG_RTC_SECONDS + 1) + +// Total number of RTC alarm registers +#define NUM_TIME_ALARM_REGS (NUM_TIME_REGS - 1) + +/* + * Min and max values supported by 'offset' interface (swapped sign). + * After conversion, the values do not exceed the range [-32767, 33767] + * which COMP_REG must conform to. + */ +#define MIN_OFFSET (-277774) +#define MAX_OFFSET (277774) + +// Number of ticks per hour +#define TICKS_PER_HOUR (32768 * 3600) + +// Multiplier for ppb conversions +#define PPB_MULT NANO + +static int tps6594_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct tps6594 *tps = dev_get_drvdata(dev->parent); + u8 val; + + val = enabled ? TPS6594_BIT_IT_ALARM : 0; + + return regmap_update_bits(tps->regmap, TPS6594_REG_RTC_INTERRUPTS, + TPS6594_BIT_IT_ALARM, val); +} + +/* Pulse GET_TIME field of RTC_CTRL_1 to store a timestamp in shadow registers. */ +static int tps6594_rtc_shadow_timestamp(struct device *dev, struct tps6594 *tps) +{ + int ret; + + /* + * Set GET_TIME to 0. Next time we set GET_TIME to 1 we will be sure to store + * an up-to-date timestamp. + */ + ret = regmap_clear_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1, + TPS6594_BIT_GET_TIME); + if (ret < 0) + return ret; + + /* + * Copy content of RTC registers to shadow registers or latches to read + * a coherent timestamp. + */ + return regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1, + TPS6594_BIT_GET_TIME); +} + +static int tps6594_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + unsigned char rtc_data[NUM_TIME_REGS]; + struct tps6594 *tps = dev_get_drvdata(dev->parent); + int ret; + + // Check if RTC is running. + ret = regmap_test_bits(tps->regmap, TPS6594_REG_RTC_STATUS, + TPS6594_BIT_RUN); + if (ret < 0) + return ret; + if (ret == 0) + return -EINVAL; + + ret = tps6594_rtc_shadow_timestamp(dev, tps); + if (ret < 0) + return ret; + + // Read shadowed RTC registers. + ret = regmap_bulk_read(tps->regmap, TPS6594_REG_RTC_SECONDS, rtc_data, + NUM_TIME_REGS); + if (ret < 0) + return ret; + + tm->tm_sec = bcd2bin(rtc_data[0]); + tm->tm_min = bcd2bin(rtc_data[1]); + tm->tm_hour = bcd2bin(rtc_data[2]); + tm->tm_mday = bcd2bin(rtc_data[3]); + tm->tm_mon = bcd2bin(rtc_data[4]) - 1; + tm->tm_year = bcd2bin(rtc_data[5]) + 100; + tm->tm_wday = bcd2bin(rtc_data[6]); + + return 0; +} + +static int tps6594_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned char rtc_data[NUM_TIME_REGS]; + struct tps6594 *tps = dev_get_drvdata(dev->parent); + int ret; + + rtc_data[0] = bin2bcd(tm->tm_sec); + rtc_data[1] = bin2bcd(tm->tm_min); + rtc_data[2] = bin2bcd(tm->tm_hour); + rtc_data[3] = bin2bcd(tm->tm_mday); + rtc_data[4] = bin2bcd(tm->tm_mon + 1); + rtc_data[5] = bin2bcd(tm->tm_year - 100); + rtc_data[6] = bin2bcd(tm->tm_wday); + + // Stop RTC while updating the RTC time registers. + ret = regmap_clear_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1, + TPS6594_BIT_STOP_RTC); + if (ret < 0) + return ret; + + // Update all the time registers in one shot. + ret = regmap_bulk_write(tps->regmap, TPS6594_REG_RTC_SECONDS, rtc_data, + NUM_TIME_REGS); + if (ret < 0) + return ret; + + // Start back RTC. + return regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1, + TPS6594_BIT_STOP_RTC); +} + +static int tps6594_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + unsigned char alarm_data[NUM_TIME_ALARM_REGS]; + u32 int_val; + struct tps6594 *tps = dev_get_drvdata(dev->parent); + int ret; + + ret = regmap_bulk_read(tps->regmap, TPS6594_REG_ALARM_SECONDS, + alarm_data, NUM_TIME_ALARM_REGS); + if (ret < 0) + return ret; + + alm->time.tm_sec = bcd2bin(alarm_data[0]); + alm->time.tm_min = bcd2bin(alarm_data[1]); + alm->time.tm_hour = bcd2bin(alarm_data[2]); + alm->time.tm_mday = bcd2bin(alarm_data[3]); + alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1; + alm->time.tm_year = bcd2bin(alarm_data[5]) + 100; + + ret = regmap_read(tps->regmap, TPS6594_REG_RTC_INTERRUPTS, &int_val); + if (ret < 0) + return ret; + + alm->enabled = int_val & TPS6594_BIT_IT_ALARM; + + return 0; +} + +static int tps6594_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + unsigned char alarm_data[NUM_TIME_ALARM_REGS]; + struct tps6594 *tps = dev_get_drvdata(dev->parent); + int ret; + + // Disable alarm irq before changing the alarm timestamp. + ret = tps6594_rtc_alarm_irq_enable(dev, 0); + if (ret) + return ret; + + alarm_data[0] = bin2bcd(alm->time.tm_sec); + alarm_data[1] = bin2bcd(alm->time.tm_min); + alarm_data[2] = bin2bcd(alm->time.tm_hour); + alarm_data[3] = bin2bcd(alm->time.tm_mday); + alarm_data[4] = bin2bcd(alm->time.tm_mon + 1); + alarm_data[5] = bin2bcd(alm->time.tm_year - 100); + + // Update all the alarm registers in one shot. + ret = regmap_bulk_write(tps->regmap, TPS6594_REG_ALARM_SECONDS, + alarm_data, NUM_TIME_ALARM_REGS); + if (ret < 0) + return ret; + + if (alm->enabled) + ret = tps6594_rtc_alarm_irq_enable(dev, 1); + + return ret; +} + +static int tps6594_rtc_set_calibration(struct device *dev, int calibration) +{ + struct tps6594 *tps = dev_get_drvdata(dev->parent); + __le16 value; + int ret; + + /* + * TPS6594 uses two's complement 16 bit value for compensation of RTC + * crystal inaccuracies. One time every hour when seconds counter + * increments from 0 to 1 compensation value will be added to internal + * RTC counter value. + * + * Valid range for compensation value: [-32767 .. 32767]. + */ + if (calibration < S16_MIN + 1 || calibration > S16_MAX) + return -ERANGE; + + value = cpu_to_le16(calibration); + + // Update all the compensation registers in one shot. + ret = regmap_bulk_write(tps->regmap, TPS6594_REG_RTC_COMP_LSB, &value, + sizeof(value)); + if (ret < 0) + return ret; + + // Enable automatic compensation. + return regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1, + TPS6594_BIT_AUTO_COMP); +} + +static int tps6594_rtc_get_calibration(struct device *dev, int *calibration) +{ + struct tps6594 *tps = dev_get_drvdata(dev->parent); + unsigned int ctrl; + __le16 value; + int ret; + + ret = regmap_read(tps->regmap, TPS6594_REG_RTC_CTRL_1, &ctrl); + if (ret < 0) + return ret; + + // If automatic compensation is not enabled report back zero. + if (!(ctrl & TPS6594_BIT_AUTO_COMP)) { + *calibration = 0; + return 0; + } + + ret = regmap_bulk_read(tps->regmap, TPS6594_REG_RTC_COMP_LSB, &value, + sizeof(value)); + if (ret < 0) + return ret; + + *calibration = le16_to_cpu(value); + + return 0; +} + +static int tps6594_rtc_read_offset(struct device *dev, long *offset) +{ + int calibration; + s64 tmp; + int ret; + + ret = tps6594_rtc_get_calibration(dev, &calibration); + if (ret < 0) + return ret; + + // Convert from RTC calibration register format to ppb format. + tmp = calibration * PPB_MULT; + + if (tmp < 0) + tmp -= TICKS_PER_HOUR / 2LL; + else + tmp += TICKS_PER_HOUR / 2LL; + tmp = div_s64(tmp, TICKS_PER_HOUR); + + /* + * SAFETY: + * Computatiion is the reverse operation of the one done in + * `tps6594_rtc_set_offset`. The safety remarks applie here too. + */ + + /* + * Offset value operates in negative way, so swap sign. + * See 8.3.10.5, (32768 - COMP_REG). + */ + *offset = (long)-tmp; + + return 0; +} + +static int tps6594_rtc_set_offset(struct device *dev, long offset) +{ + int calibration; + s64 tmp; + + // Make sure offset value is within supported range. + if (offset < MIN_OFFSET || offset > MAX_OFFSET) + return -ERANGE; + + // Convert from ppb format to RTC calibration register format. + + tmp = offset * TICKS_PER_HOUR; + if (tmp < 0) + tmp -= PPB_MULT / 2LL; + else + tmp += PPB_MULT / 2LL; + tmp = div_s64(tmp, PPB_MULT); + + /* + * SAFETY: + * - tmp = offset * TICK_PER_HOUR : + * `offset` can't be more than 277774, so `tmp` can't exceed 277774000000000 + * which is lower than the maximum value in an `s64` (2^63-1). No overflow here. + * + * - tmp += TICK_PER_HOUR / 2LL : + * tmp will have a maximum value of 277774117964800 which is still inferior to 2^63-1. + */ + + // Offset value operates in negative way, so swap sign. + calibration = (int)-tmp; + + return tps6594_rtc_set_calibration(dev, calibration); +} + +static irqreturn_t tps6594_rtc_interrupt(int irq, void *rtc) +{ + struct device *dev = rtc; + struct tps6594 *tps = dev_get_drvdata(dev->parent); + struct rtc_device *rtc_dev = dev_get_drvdata(dev); + int ret; + u32 rtc_reg; + + ret = regmap_read(tps->regmap, TPS6594_REG_RTC_STATUS, &rtc_reg); + if (ret) + return IRQ_NONE; + + rtc_update_irq(rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops tps6594_rtc_ops = { + .read_time = tps6594_rtc_read_time, + .set_time = tps6594_rtc_set_time, + .read_alarm = tps6594_rtc_read_alarm, + .set_alarm = tps6594_rtc_set_alarm, + .alarm_irq_enable = tps6594_rtc_alarm_irq_enable, + .read_offset = tps6594_rtc_read_offset, + .set_offset = tps6594_rtc_set_offset, +}; + +static int tps6594_rtc_probe(struct platform_device *pdev) +{ + struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct rtc_device *rtc; + int irq; + int ret; + + rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc = devm_rtc_allocate_device(dev); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + // Enable crystal oscillator. + ret = regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_2, + TPS6594_BIT_XTAL_EN); + if (ret < 0) + return ret; + + ret = regmap_test_bits(tps->regmap, TPS6594_REG_RTC_STATUS, + TPS6594_BIT_RUN); + if (ret < 0) + return ret; + // RTC not running. + if (ret == 0) { + ret = regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1, + TPS6594_BIT_STOP_RTC); + if (ret < 0) + return ret; + + /* + * On some boards, a 40 ms delay is needed before BIT_RUN is set. + * 80 ms should provide sufficient margin. + */ + mdelay(80); + + /* + * RTC should be running now. Check if this is the case. + * If not it might be a missing oscillator. + */ + ret = regmap_test_bits(tps->regmap, TPS6594_REG_RTC_STATUS, + TPS6594_BIT_RUN); + if (ret < 0) + return ret; + if (ret == 0) + return -ENODEV; + + // Stop RTC until first call to `tps6594_rtc_set_time`. + ret = regmap_clear_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1, + TPS6594_BIT_STOP_RTC); + if (ret < 0) + return ret; + } + + platform_set_drvdata(pdev, rtc); + + irq = platform_get_irq_byname(pdev, TPS6594_IRQ_NAME_ALARM); + if (irq < 0) + return dev_err_probe(dev, irq, "Failed to get irq\n"); + + ret = devm_request_threaded_irq(dev, irq, NULL, tps6594_rtc_interrupt, + IRQF_ONESHOT, TPS6594_IRQ_NAME_ALARM, + dev); + if (ret < 0) + return dev_err_probe(dev, ret, + "Failed to request_threaded_irq\n"); + + ret = device_init_wakeup(dev, true); + if (ret < 0) + return dev_err_probe(dev, ret, + "Failed to init rtc as wakeup source\n"); + + rtc->ops = &tps6594_rtc_ops; + rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + rtc->range_max = RTC_TIMESTAMP_END_2099; + + return devm_rtc_register_device(rtc); +} + +static const struct platform_device_id tps6594_rtc_id_table[] = { + { "tps6594-rtc", }, + {} +}; +MODULE_DEVICE_TABLE(platform, tps6594_rtc_id_table); + +static struct platform_driver tps6594_rtc_driver = { + .probe = tps6594_rtc_probe, + .driver = { + .name = "tps6594-rtc", + }, + .id_table = tps6594_rtc_id_table, +}; + +module_platform_driver(tps6594_rtc_driver); +MODULE_AUTHOR("Esteban Blanc "); +MODULE_DESCRIPTION("TPS6594 RTC driver"); +MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c --- a/drivers/soc/ti/k3-socinfo.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/soc/ti/k3-socinfo.c 2024-07-07 20:37:34.676306709 -0400 @@ -20,7 +20,7 @@ * 31-28 VARIANT Device variant * 27-12 PARTNO Part number * 11-1 MFG Indicates TI as manufacturer (0x17) - * 1 Always 1 + * 0 Always 1 */ #define CTRLMMR_WKUP_JTAGID_VARIANT_SHIFT (28) #define CTRLMMR_WKUP_JTAGID_VARIANT_MASK GENMASK(31, 28) @@ -33,19 +33,35 @@ #define CTRLMMR_WKUP_JTAGID_MFG_TI 0x17 +#define JTAG_ID_PARTNO_AM65X 0xBB5A +#define JTAG_ID_PARTNO_J721E 0xBB64 +#define JTAG_ID_PARTNO_J7200 0xBB6D +#define JTAG_ID_PARTNO_AM64X 0xBB38 +#define JTAG_ID_PARTNO_J721S2 0xBB75 +#define JTAG_ID_PARTNO_AM62X 0xBB7E +#define JTAG_ID_PARTNO_J784S4 0xBB80 +#define JTAG_ID_PARTNO_AM62AX 0xBB8D +#define JTAG_ID_PARTNO_AM62PX 0xBB9D +#define JTAG_ID_PARTNO_J722S 0xBBA0 + static const struct k3_soc_id { unsigned int id; const char *family_name; } k3_soc_ids[] = { - { 0xBB5A, "AM65X" }, - { 0xBB64, "J721E" }, - { 0xBB6D, "J7200" }, - { 0xBB38, "AM64X" }, - { 0xBB75, "J721S2"}, - { 0xBB7E, "AM62X" }, - { 0xBB80, "J784S4" }, - { 0xBB8D, "AM62AX" }, - { 0xBB9D, "AM62PX" }, + { JTAG_ID_PARTNO_AM65X, "AM65X" }, + { JTAG_ID_PARTNO_J721E, "J721E" }, + { JTAG_ID_PARTNO_J7200, "J7200" }, + { JTAG_ID_PARTNO_AM64X, "AM64X" }, + { JTAG_ID_PARTNO_J721S2, "J721S2"}, + { JTAG_ID_PARTNO_AM62X, "AM62X" }, + { JTAG_ID_PARTNO_J784S4, "J784S4" }, + { JTAG_ID_PARTNO_AM62AX, "AM62AX" }, + { JTAG_ID_PARTNO_AM62PX, "AM62PX" }, + { JTAG_ID_PARTNO_J722S, "J722S" }, +}; + +static const char * const j721e_rev_string_map[] = { + "1.0", "1.1", "2.0", }; static int @@ -60,7 +76,33 @@ return 0; } - return -EINVAL; + return -ENODEV; +} + +static int +k3_chipinfo_variant_to_sr(unsigned int partno, unsigned int variant, + struct soc_device_attribute *soc_dev_attr) +{ + switch (partno) { + case JTAG_ID_PARTNO_J721E: + if (variant >= ARRAY_SIZE(j721e_rev_string_map)) + goto err_unknown_variant; + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%s", + j721e_rev_string_map[variant]); + break; + default: + variant++; + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%x.0", + variant); + } + + if (!soc_dev_attr->revision) + return -ENOMEM; + + return 0; + +err_unknown_variant: + return -ENODEV; } static int k3_chipinfo_probe(struct platform_device *pdev) @@ -94,7 +136,6 @@ variant = (jtag_id & CTRLMMR_WKUP_JTAGID_VARIANT_MASK) >> CTRLMMR_WKUP_JTAGID_VARIANT_SHIFT; - variant++; partno_id = (jtag_id & CTRLMMR_WKUP_JTAGID_PARTNO_MASK) >> CTRLMMR_WKUP_JTAGID_PARTNO_SHIFT; @@ -103,17 +144,16 @@ if (!soc_dev_attr) return -ENOMEM; - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%x.0", variant); - if (!soc_dev_attr->revision) { - ret = -ENOMEM; + ret = k3_chipinfo_partno_to_names(partno_id, soc_dev_attr); + if (ret) { + dev_err(dev, "Unknown SoC JTAGID[0x%08X]: %d\n", jtag_id, ret); goto err; } - ret = k3_chipinfo_partno_to_names(partno_id, soc_dev_attr); + ret = k3_chipinfo_variant_to_sr(partno_id, variant, soc_dev_attr); if (ret) { - dev_err(dev, "Unknown SoC JTAGID[0x%08X]\n", jtag_id); - ret = -ENODEV; - goto err_free_rev; + dev_err(dev, "Unknown SoC SR[0x%08X]: %d\n", jtag_id, ret); + goto err; } node = of_find_node_by_path("/"); diff -Naur --no-dereference a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c --- a/drivers/spi/spi-cadence-quadspi.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/spi/spi-cadence-quadspi.c 2024-07-07 20:37:34.676306709 -0400 @@ -54,15 +54,30 @@ struct cqspi_st; +struct phy_setting { + u8 rx; + u8 tx; + u8 read_delay; +}; + struct cqspi_flash_pdata { - struct cqspi_st *cqspi; - u32 clk_rate; - u32 read_delay; - u32 tshsl_ns; - u32 tsd2d_ns; - u32 tchsh_ns; - u32 tslch_ns; - u8 cs; + struct cqspi_st *cqspi; + u32 clk_rate; + u32 read_delay; + u32 tshsl_ns; + u32 tsd2d_ns; + u32 tchsh_ns; + u32 tslch_ns; + u8 inst_width; + u8 addr_width; + u8 data_width; + bool dtr; + u8 cs; + bool use_phy; + struct phy_setting phy_setting; + struct spi_mem_op phy_read_op; + u32 phy_tx_start; + u32 phy_tx_end; }; struct cqspi_st { @@ -116,6 +131,9 @@ #define CQSPI_TIMEOUT_MS 500 #define CQSPI_READ_TIMEOUT_MS 10 +/* Runtime_pm autosuspend delay */ +#define CQSPI_AUTOSUSPEND_TIMEOUT 2000 + #define CQSPI_DUMMY_CLKS_PER_BYTE 8 #define CQSPI_DUMMY_BYTES_MAX 4 #define CQSPI_DUMMY_CLKS_MAX 31 @@ -125,12 +143,14 @@ /* Register map */ #define CQSPI_REG_CONFIG 0x00 #define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0) +#define CQSPI_REG_CONFIG_PHY_EN BIT(3) #define CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL BIT(7) #define CQSPI_REG_CONFIG_DECODE_MASK BIT(9) #define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10 #define CQSPI_REG_CONFIG_DMA_MASK BIT(15) #define CQSPI_REG_CONFIG_BAUD_LSB 19 #define CQSPI_REG_CONFIG_DTR_PROTO BIT(24) +#define CQSPI_REG_CONFIG_PHY_PIPELINE BIT(25) #define CQSPI_REG_CONFIG_DUAL_OPCODE BIT(30) #define CQSPI_REG_CONFIG_IDLE_LSB 31 #define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF @@ -167,6 +187,7 @@ #define CQSPI_REG_READCAPTURE_BYPASS_LSB 0 #define CQSPI_REG_READCAPTURE_DELAY_LSB 1 #define CQSPI_REG_READCAPTURE_DELAY_MASK 0xF +#define CQSPI_REG_READCAPTURE_DQS_LSB 8 #define CQSPI_REG_SIZE 0x14 #define CQSPI_REG_SIZE_ADDRESS_LSB 0 @@ -245,6 +266,13 @@ #define CQSPI_REG_POLLING_STATUS 0xB0 #define CQSPI_REG_POLLING_STATUS_DUMMY_LSB 16 +#define CQSPI_REG_PHY_CONFIG 0xB4 +#define CQSPI_REG_PHY_CONFIG_RX_DEL_LSB 0 +#define CQSPI_REG_PHY_CONFIG_RX_DEL_MASK 0x7F +#define CQSPI_REG_PHY_CONFIG_TX_DEL_LSB 16 +#define CQSPI_REG_PHY_CONFIG_TX_DEL_MASK 0x7F +#define CQSPI_REG_PHY_CONFIG_RESYNC BIT(31) + #define CQSPI_REG_OP_EXT_LOWER 0xE0 #define CQSPI_REG_OP_EXT_READ_LSB 24 #define CQSPI_REG_OP_EXT_WRITE_LSB 16 @@ -290,6 +318,578 @@ #define CQSPI_REG_VERSAL_DMA_VAL 0x602 +#define CQSPI_PHY_INIT_RD 1 +#define CQSPI_PHY_MAX_RD 4 +#define CQSPI_PHY_MAX_RX 63 +#define CQSPI_PHY_MAX_TX 63 +#define CQSPI_PHY_LOW_RX_BOUND 15 +#define CQSPI_PHY_HIGH_RX_BOUND 25 +#define CQSPI_PHY_LOW_TX_BOUND 32 +#define CQSPI_PHY_HIGH_TX_BOUND 48 +#define CQSPI_PHY_TX_LOOKUP_LOW_BOUND 24 +#define CQSPI_PHY_TX_LOOKUP_HIGH_BOUND 38 + +#define CQSPI_PHY_DEFAULT_TEMP 45 +#define CQSPI_PHY_MIN_TEMP -45 +#define CQSPI_PHY_MAX_TEMP 130 +#define CQSPI_PHY_MID_TEMP (CQSPI_PHY_MIN_TEMP + \ + ((CQSPI_PHY_MAX_TEMP - CQSPI_PHY_MIN_TEMP) / 2)) + +static const u8 phy_tuning_pattern[] = { +0xFE, 0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xFE, 0xFE, 0x01, 0x01, +0x01, 0x01, 0x00, 0x00, 0xFE, 0xFE, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, +0x00, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0x01, +0x01, 0x01, 0x01, 0x01, 0xFE, 0x00, 0xFE, 0xFE, 0x01, 0x01, 0x01, 0x01, 0xFE, +0x00, 0xFE, 0xFE, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0xFE, 0xFE, +0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0xFE, 0xFE, 0xFF, 0x01, 0x01, 0x01, 0x01, +0x01, 0x00, 0xFE, 0xFE, 0xFE, 0x01, 0x01, 0x01, 0x01, 0x00, 0xFE, 0xFE, 0xFE, +0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, +0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFE, 0xFE, +0xFE, 0xFE, 0x01, 0x01, 0x01, 0x01, 0xFE, 0xFE, 0xFE, 0xFE, 0x01, +}; + +static void cqspi_set_tx_dll(void __iomem *reg_base, u8 dll) +{ + unsigned int reg; + + reg = readl(reg_base + CQSPI_REG_PHY_CONFIG); + reg &= ~(CQSPI_REG_PHY_CONFIG_TX_DEL_MASK << + CQSPI_REG_PHY_CONFIG_TX_DEL_LSB); + reg |= (dll & CQSPI_REG_PHY_CONFIG_TX_DEL_MASK) << + CQSPI_REG_PHY_CONFIG_TX_DEL_LSB; + reg |= CQSPI_REG_PHY_CONFIG_RESYNC; + writel(reg, reg_base + CQSPI_REG_PHY_CONFIG); +} + +static void cqspi_set_rx_dll(void __iomem *reg_base, u8 dll) +{ + unsigned int reg; + + reg = readl(reg_base + CQSPI_REG_PHY_CONFIG); + reg &= ~(CQSPI_REG_PHY_CONFIG_RX_DEL_MASK << + CQSPI_REG_PHY_CONFIG_RX_DEL_LSB); + reg |= (dll & CQSPI_REG_PHY_CONFIG_RX_DEL_MASK) << + CQSPI_REG_PHY_CONFIG_RX_DEL_LSB; + reg |= CQSPI_REG_PHY_CONFIG_RESYNC; + writel(reg, reg_base + CQSPI_REG_PHY_CONFIG); +} + +/* TODO: Figure out how to get the temperature here. */ +static int cqspi_get_temp(int *temp) +{ + return -EOPNOTSUPP; +} + +static void cqspi_phy_apply_setting(struct cqspi_flash_pdata *f_pdata, + struct phy_setting *phy) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + + cqspi_set_rx_dll(cqspi->iobase, phy->rx); + cqspi_set_tx_dll(cqspi->iobase, phy->tx); + f_pdata->phy_setting.read_delay = phy->read_delay; +} + +static int cqspi_phy_check_pattern(struct cqspi_flash_pdata *f_pdata, + struct spi_mem *mem) +{ + struct spi_mem_op op = f_pdata->phy_read_op; + u8 *read_data; + unsigned int size = sizeof(phy_tuning_pattern); + int ret; + + read_data = kmalloc(size, GFP_KERNEL); + if (!read_data) + return -ENOMEM; + + op.data.buf.in = read_data; + op.data.nbytes = size; + + ret = spi_mem_exec_op(mem, &op); + if (ret) + goto out; + + if (memcmp(read_data, phy_tuning_pattern, + ARRAY_SIZE(phy_tuning_pattern))) { + ret = -EAGAIN; + goto out; + } + + ret = 0; + +out: + kfree(read_data); + return ret; +} + +static int cqspi_find_rx_low(struct cqspi_flash_pdata *f_pdata, + struct spi_mem *mem, struct phy_setting *phy) +{ + struct device *dev = &f_pdata->cqspi->pdev->dev; + int ret; + + do { + phy->rx = 0; + do { + cqspi_phy_apply_setting(f_pdata, phy); + ret = cqspi_phy_check_pattern(f_pdata, mem); + if (!ret) + return 0; + + phy->rx++; + } while (phy->rx <= CQSPI_PHY_LOW_RX_BOUND); + + phy->read_delay++; + } while (phy->read_delay <= CQSPI_PHY_MAX_RD); + + dev_dbg(dev, "Unable to find RX low\n"); + return -ENOENT; +} + +static int cqspi_find_rx_high(struct cqspi_flash_pdata *f_pdata, + struct spi_mem *mem, struct phy_setting *phy) +{ + struct device *dev = &f_pdata->cqspi->pdev->dev; + int ret; + + do { + phy->rx = CQSPI_PHY_MAX_RX; + do { + cqspi_phy_apply_setting(f_pdata, phy); + ret = cqspi_phy_check_pattern(f_pdata, mem); + if (!ret) + return 0; + + phy->rx--; + } while (phy->rx >= CQSPI_PHY_HIGH_RX_BOUND); + + phy->read_delay++; + } while (phy->read_delay <= CQSPI_PHY_MAX_RD); + + dev_dbg(dev, "Unable to find RX high\n"); + return -ENOENT; +} + +static int cqspi_find_tx_low(struct cqspi_flash_pdata *f_pdata, + struct spi_mem *mem, struct phy_setting *phy) +{ + struct device *dev = &f_pdata->cqspi->pdev->dev; + int ret; + + do { + phy->tx = 0; + do { + cqspi_phy_apply_setting(f_pdata, phy); + ret = cqspi_phy_check_pattern(f_pdata, mem); + if (!ret) + return 0; + + phy->tx++; + } while (phy->tx <= CQSPI_PHY_LOW_TX_BOUND); + + phy->read_delay++; + } while (phy->read_delay <= CQSPI_PHY_MAX_RD); + + dev_dbg(dev, "Unable to find TX low\n"); + return -ENOENT; +} + +static int cqspi_find_tx_high(struct cqspi_flash_pdata *f_pdata, + struct spi_mem *mem, struct phy_setting *phy) +{ + struct device *dev = &f_pdata->cqspi->pdev->dev; + int ret; + + do { + phy->tx = CQSPI_PHY_MAX_TX; + do { + cqspi_phy_apply_setting(f_pdata, phy); + ret = cqspi_phy_check_pattern(f_pdata, mem); + if (!ret) + return 0; + + phy->tx--; + } while (phy->tx >= CQSPI_PHY_HIGH_TX_BOUND); + + phy->read_delay++; + } while (phy->read_delay <= CQSPI_PHY_MAX_RD); + + dev_dbg(dev, "Unable to find TX high\n"); + return -ENOENT; +} + +static int cqspi_phy_find_gaplow(struct cqspi_flash_pdata *f_pdata, + struct spi_mem *mem, + struct phy_setting *bottomleft, + struct phy_setting *topright, + struct phy_setting *gaplow) +{ + struct phy_setting left, right, mid; + int ret; + + left = *bottomleft; + right = *topright; + + mid.tx = left.tx + ((right.tx - left.tx) / 2); + mid.rx = left.rx + ((right.rx - left.rx) / 2); + mid.read_delay = left.read_delay; + + do { + cqspi_phy_apply_setting(f_pdata, &mid); + ret = cqspi_phy_check_pattern(f_pdata, mem); + if (ret) { + /* The pattern was not found. Go to the lower half. */ + right.tx = mid.tx; + right.rx = mid.rx; + + mid.tx = left.tx + ((mid.tx - left.tx) / 2); + mid.rx = left.rx + ((mid.rx - left.rx) / 2); + } else { + /* The pattern was found. Go to the upper half. */ + left.tx = mid.tx; + left.rx = mid.rx; + + mid.tx = mid.tx + ((right.tx - mid.tx) / 2); + mid.rx = mid.rx + ((right.rx - mid.rx) / 2); + } + + /* Break the loop if the window has closed. */ + } while ((right.tx - left.tx >= 2) && (right.rx - left.rx >= 2)); + + *gaplow = mid; + return 0; +} + +static int cqspi_phy_find_gaphigh(struct cqspi_flash_pdata *f_pdata, + struct spi_mem *mem, + struct phy_setting *bottomleft, + struct phy_setting *topright, + struct phy_setting *gaphigh) +{ + struct phy_setting left, right, mid; + int ret; + + left = *bottomleft; + right = *topright; + + mid.tx = left.tx + ((right.tx - left.tx) / 2); + mid.rx = left.rx + ((right.rx - left.rx) / 2); + mid.read_delay = right.read_delay; + + do { + cqspi_phy_apply_setting(f_pdata, &mid); + ret = cqspi_phy_check_pattern(f_pdata, mem); + if (ret) { + /* The pattern was not found. Go to the upper half. */ + left.tx = mid.tx; + left.rx = mid.rx; + + mid.tx = mid.tx + ((right.tx - mid.tx) / 2); + mid.rx = mid.rx + ((right.rx - mid.rx) / 2); + } else { + /* The pattern was found. Go to the lower half. */ + right.tx = mid.tx; + right.rx = mid.rx; + + mid.tx = left.tx + ((mid.tx - left.tx) / 2); + mid.rx = left.rx + ((mid.rx - left.rx) / 2); + } + + /* Break the loop if the window has closed. */ + } while ((right.tx - left.tx >= 2) && (right.rx - left.rx >= 2)); + + *gaphigh = mid; + return 0; +} + +static int cqspi_phy_calibrate(struct cqspi_flash_pdata *f_pdata, + struct spi_mem *mem) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + struct device *dev = &cqspi->pdev->dev; + struct phy_setting rxlow, rxhigh, txlow, txhigh, temp; + struct phy_setting bottomleft, topright, searchpoint, gaplow, gaphigh; + int ret, tmp; + + f_pdata->use_phy = true; + + /* Look for RX boundaries at lower TX range. */ + rxlow.tx = f_pdata->phy_tx_start; + + do { + dev_dbg(dev, "Searching for rxlow on TX = %d\n", rxlow.tx); + rxlow.read_delay = CQSPI_PHY_INIT_RD; + ret = cqspi_find_rx_low(f_pdata, mem, &rxlow); + } while (ret && ++rxlow.tx <= CQSPI_PHY_TX_LOOKUP_LOW_BOUND); + + if (ret) + goto out; + dev_dbg(dev, "rxlow: RX: %d TX: %d RD: %d\n", rxlow.rx, rxlow.tx, + rxlow.read_delay); + + rxhigh.tx = rxlow.tx; + rxhigh.read_delay = rxlow.read_delay; + cqspi_find_rx_high(f_pdata, mem, &rxhigh); + if (ret) + goto out; + dev_dbg(dev, "rxhigh: RX: %d TX: %d RD: %d\n", rxhigh.rx, rxhigh.tx, + rxhigh.read_delay); + + /* + * Check a different point if rxlow and rxhigh are on the same read + * delay. This avoids mistaking the failing region for an RX boundary. + */ + if (rxlow.read_delay == rxhigh.read_delay) { + dev_dbg(dev, + "rxlow and rxhigh at the same read delay.\n"); + + /* Look for RX boundaries at upper TX range. */ + temp.tx = f_pdata->phy_tx_end; + + do { + dev_dbg(dev, "Searching for rxlow on TX = %d\n", + temp.tx); + temp.read_delay = CQSPI_PHY_INIT_RD; + ret = cqspi_find_rx_low(f_pdata, mem, &temp); + } while (ret && --temp.tx >= CQSPI_PHY_TX_LOOKUP_HIGH_BOUND); + + if (ret) + goto out; + dev_dbg(dev, "rxlow: RX: %d TX: %d RD: %d\n", temp.rx, temp.tx, + temp.read_delay); + + if (temp.rx < rxlow.rx) { + rxlow = temp; + dev_dbg(dev, "Updating rxlow to the one at TX = 48\n"); + } + + /* Find RX max. */ + ret = cqspi_find_rx_high(f_pdata, mem, &temp); + if (ret) + goto out; + dev_dbg(dev, "rxhigh: RX: %d TX: %d RD: %d\n", temp.rx, temp.tx, + temp.read_delay); + + if (temp.rx < rxhigh.rx) { + rxhigh = temp; + dev_dbg(dev, "Updating rxhigh to the one at TX = 48\n"); + } + } + + /* Look for TX boundaries at 1/4 of RX window. */ + txlow.rx = rxlow.rx + ((rxhigh.rx - rxlow.rx) / 4); + txhigh.rx = txlow.rx; + + txlow.read_delay = CQSPI_PHY_INIT_RD; + ret = cqspi_find_tx_low(f_pdata, mem, &txlow); + if (ret) + goto out; + dev_dbg(dev, "txlow: RX: %d TX: %d RD: %d\n", txlow.rx, txlow.tx, + txlow.read_delay); + + txhigh.read_delay = txlow.read_delay; + ret = cqspi_find_tx_high(f_pdata, mem, &txhigh); + if (ret) + goto out; + dev_dbg(dev, "txhigh: RX: %d TX: %d RD: %d\n", txhigh.rx, txhigh.tx, + txhigh.read_delay); + + /* + * Check a different point if txlow and txhigh are on the same read + * delay. This avoids mistaking the failing region for an TX boundary. + */ + if (txlow.read_delay == txhigh.read_delay) { + /* Look for TX boundaries at 3/4 of RX window. */ + temp.rx = rxlow.rx + (3 * (rxhigh.rx - rxlow.rx) / 4); + temp.read_delay = CQSPI_PHY_INIT_RD; + dev_dbg(dev, + "txlow and txhigh at the same read delay. Searching at RX = %d\n", + temp.rx); + + ret = cqspi_find_tx_low(f_pdata, mem, &temp); + if (ret) + goto out; + dev_dbg(dev, "txlow: RX: %d TX: %d RD: %d\n", temp.rx, temp.tx, + temp.read_delay); + + if (temp.tx < txlow.tx) { + txlow = temp; + dev_dbg(dev, "Updating txlow with the one at RX = %d\n", + txlow.rx); + } + + ret = cqspi_find_tx_high(f_pdata, mem, &temp); + if (ret) + goto out; + dev_dbg(dev, "txhigh: RX: %d TX: %d RD: %d\n", temp.rx, temp.tx, + temp.read_delay); + + if (temp.tx < txhigh.tx) { + txhigh = temp; + dev_dbg(dev, "Updating txhigh with the one at RX = %d\n", + txhigh.rx); + } + } + + /* + * Set bottom left and top right corners. These are theoretical + * corners. They may not actually be "good" points. But the longest + * diagonal will be between these corners. + */ + bottomleft.tx = txlow.tx; + bottomleft.rx = rxlow.rx; + if (txlow.read_delay <= rxlow.read_delay) + bottomleft.read_delay = txlow.read_delay; + else + bottomleft.read_delay = rxlow.read_delay; + + temp = bottomleft; + temp.tx += 4; + temp.rx += 4; + cqspi_phy_apply_setting(f_pdata, &temp); + ret = cqspi_phy_check_pattern(f_pdata, mem); + if (ret) { + temp.read_delay--; + cqspi_phy_apply_setting(f_pdata, &temp); + ret = cqspi_phy_check_pattern(f_pdata, mem); + } + + if (!ret) + bottomleft.read_delay = temp.read_delay; + + topright.tx = txhigh.tx; + topright.rx = rxhigh.rx; + if (txhigh.read_delay >= rxhigh.read_delay) + topright.read_delay = txhigh.read_delay; + else + topright.read_delay = rxhigh.read_delay; + + temp = topright; + temp.tx -= 4; + temp.rx -= 4; + cqspi_phy_apply_setting(f_pdata, &temp); + ret = cqspi_phy_check_pattern(f_pdata, mem); + if (ret) { + temp.read_delay++; + cqspi_phy_apply_setting(f_pdata, &temp); + ret = cqspi_phy_check_pattern(f_pdata, mem); + } + + if (!ret) + topright.read_delay = temp.read_delay; + + dev_dbg(dev, "topright: RX: %d TX: %d RD: %d\n", topright.rx, + topright.tx, topright.read_delay); + dev_dbg(dev, "bottomleft: RX: %d TX: %d RD: %d\n", bottomleft.rx, + bottomleft.tx, bottomleft.read_delay); + + ret = cqspi_phy_find_gaplow(f_pdata, mem, &bottomleft, &topright, + &gaplow); + if (ret) + goto out; + dev_dbg(dev, "gaplow: RX: %d TX: %d RD: %d\n", gaplow.rx, gaplow.tx, + gaplow.read_delay); + + if (bottomleft.read_delay == topright.read_delay) { + /* + * If there is only one passing region, it means that the "true" + * topright is too small to find, so the start of the failing + * region is a good approximation. Put the tuning point in the + * middle and adjust for temperature. + */ + topright = gaplow; + searchpoint.read_delay = bottomleft.read_delay; + searchpoint.tx = bottomleft.tx + + ((topright.tx - bottomleft.tx) / 2); + searchpoint.rx = bottomleft.rx + + ((topright.rx - bottomleft.rx) / 2); + + ret = cqspi_get_temp(&tmp); + if (ret) { + /* + * Assume room temperature if it couldn't be obtained + * from the thermal sensor. + * + * TODO: Change it to dev_warn once support for finding + * out the temperature is added. + */ + dev_dbg(dev, + "Unable to get temperature. Assuming room temperature\n"); + tmp = CQSPI_PHY_DEFAULT_TEMP; + } + + if (tmp < CQSPI_PHY_MIN_TEMP || tmp > CQSPI_PHY_MAX_TEMP) { + dev_err(dev, + "Temperature outside operating range: %dC\n", + tmp); + ret = -EINVAL; + goto out; + } + + /* Avoid a divide-by-zero. */ + if (tmp == CQSPI_PHY_MID_TEMP) + tmp++; + dev_dbg(dev, "Temperature: %dC\n", tmp); + + searchpoint.tx += (topright.tx - bottomleft.tx) / + (330 / (tmp - CQSPI_PHY_MID_TEMP)); + searchpoint.rx += (topright.rx - bottomleft.rx) / + (330 / (tmp - CQSPI_PHY_MID_TEMP)); + } else { + /* + * If there are two passing regions, find the start and end of + * the second one. + */ + ret = cqspi_phy_find_gaphigh(f_pdata, mem, &bottomleft, + &topright, &gaphigh); + if (ret) + goto out; + dev_dbg(dev, "gaphigh: RX: %d TX: %d RD: %d\n", gaphigh.rx, + gaphigh.tx, gaphigh.read_delay); + + /* + * Place the final tuning point in the corner furthest from the + * failing region but leave some margin for temperature changes. + */ + if ((abs(gaplow.tx - bottomleft.tx) + + abs(gaplow.rx - bottomleft.rx)) < + (abs(gaphigh.tx - topright.tx) + + abs(gaphigh.rx - topright.rx))) { + searchpoint = topright; + searchpoint.tx -= 16; + searchpoint.rx -= (16 * (topright.rx - bottomleft.rx)) / + (topright.tx - bottomleft.tx); + } else { + searchpoint = bottomleft; + searchpoint.tx += 16; + searchpoint.rx += (16 * (topright.rx - bottomleft.rx)) / + (topright.tx - bottomleft.tx); + } + } + + /* Set the final PHY settings and check if they are working. */ + cqspi_phy_apply_setting(f_pdata, &searchpoint); + dev_dbg(dev, "Final tuning point: RX: %d TX: %d RD: %d\n", + searchpoint.rx, searchpoint.tx, searchpoint.read_delay); + + ret = cqspi_phy_check_pattern(f_pdata, mem); + if (ret) { + dev_err(dev, + "Failed to find pattern at final calibration point\n"); + ret = -EINVAL; + goto out; + } + + ret = 0; + f_pdata->phy_setting.read_delay = searchpoint.read_delay; + f_pdata->phy_setting.rx = searchpoint.rx; + f_pdata->phy_setting.tx = searchpoint.tx; +out: + if (ret) + f_pdata->use_phy = false; + return ret; +} + static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clr) { u32 val; @@ -1203,6 +1803,7 @@ static void cqspi_readdata_capture(struct cqspi_st *cqspi, const bool bypass, + const bool dqs, const unsigned int delay) { void __iomem *reg_base = cqspi->iobase; @@ -1221,9 +1822,72 @@ reg |= (delay & CQSPI_REG_READCAPTURE_DELAY_MASK) << CQSPI_REG_READCAPTURE_DELAY_LSB; + if (dqs) + reg |= (1 << CQSPI_REG_READCAPTURE_DQS_LSB); + else + reg &= ~(1 << CQSPI_REG_READCAPTURE_DQS_LSB); + writel(reg, reg_base + CQSPI_REG_READCAPTURE); } +static void cqspi_phy_enable(struct cqspi_flash_pdata *f_pdata, bool enable) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + void __iomem *reg_base = cqspi->iobase; + u32 reg; + u8 dummy; + + if (enable) { + cqspi_readdata_capture(cqspi, 1, true, + f_pdata->phy_setting.read_delay); + + reg = readl(reg_base + CQSPI_REG_CONFIG); + reg |= CQSPI_REG_CONFIG_PHY_EN | + CQSPI_REG_CONFIG_PHY_PIPELINE; + writel(reg, reg_base + CQSPI_REG_CONFIG); + + /* + * Reduce dummy cycle by 1. This is a requirement of PHY mode + * operation for correctly reading the data. + */ + reg = readl(reg_base + CQSPI_REG_RD_INSTR); + dummy = (reg >> CQSPI_REG_RD_INSTR_DUMMY_LSB) & + CQSPI_REG_RD_INSTR_DUMMY_MASK; + dummy--; + reg &= ~(CQSPI_REG_RD_INSTR_DUMMY_MASK << + CQSPI_REG_RD_INSTR_DUMMY_LSB); + + reg |= (dummy & CQSPI_REG_RD_INSTR_DUMMY_MASK) + << CQSPI_REG_RD_INSTR_DUMMY_LSB; + writel(reg, reg_base + CQSPI_REG_RD_INSTR); + } else { + cqspi_readdata_capture(cqspi, !cqspi->rclk_en, false, + f_pdata->read_delay); + + reg = readl(reg_base + CQSPI_REG_CONFIG); + reg &= ~(CQSPI_REG_CONFIG_PHY_EN | + CQSPI_REG_CONFIG_PHY_PIPELINE); + writel(reg, reg_base + CQSPI_REG_CONFIG); + + /* + * Dummy cycles were decremented when enabling PHY. Increment + * dummy cycle by 1 to restore the original value. + */ + reg = readl(reg_base + CQSPI_REG_RD_INSTR); + dummy = (reg >> CQSPI_REG_RD_INSTR_DUMMY_LSB) & + CQSPI_REG_RD_INSTR_DUMMY_MASK; + dummy++; + reg &= ~(CQSPI_REG_RD_INSTR_DUMMY_MASK << + CQSPI_REG_RD_INSTR_DUMMY_LSB); + + reg |= (dummy & CQSPI_REG_RD_INSTR_DUMMY_MASK) + << CQSPI_REG_RD_INSTR_DUMMY_LSB; + writel(reg, reg_base + CQSPI_REG_RD_INSTR); + } + + cqspi_wait_idle(cqspi); +} + static void cqspi_configure(struct cqspi_flash_pdata *f_pdata, unsigned long sclk) { @@ -1245,7 +1909,7 @@ cqspi->sclk = sclk; cqspi_config_baudrate_div(cqspi); cqspi_delay(f_pdata); - cqspi_readdata_capture(cqspi, !cqspi->rclk_en, + cqspi_readdata_capture(cqspi, !cqspi->rclk_en, false, f_pdata->read_delay); } @@ -1283,6 +1947,39 @@ return cqspi_indirect_write_execute(f_pdata, to, buf, len); } +/* + * Check if PHY mode can be used on the given op. This is assuming it will be a + * DAC mode read, since PHY won't work on any other type of operation anyway. + */ +static bool cqspi_phy_op_eligible(const struct spi_mem_op *op) +{ + /* PHY is only tuned for 8D-8D-8D. */ + if (!(op->cmd.dtr && op->addr.dtr && op->dummy.dtr && op->data.dtr)) + return false; + if (op->cmd.buswidth != 8) + return false; + if (op->addr.nbytes && op->addr.buswidth != 8) + return false; + if (op->dummy.nbytes && op->dummy.buswidth != 8) + return false; + if (op->data.nbytes && op->data.buswidth != 8) + return false; + + return true; +} + +static bool cqspi_use_phy(struct cqspi_flash_pdata *f_pdata, + const struct spi_mem_op *op) +{ + if (!f_pdata->use_phy) + return false; + + if (op->data.nbytes < 16) + return false; + + return cqspi_phy_op_eligible(op); +} + static void cqspi_rx_dma_callback(void *param) { struct cqspi_st *cqspi = param; @@ -1290,8 +1987,8 @@ complete(&cqspi->rx_dma_complete); } -static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata, - u_char *buf, loff_t from, size_t len) +static int cqspi_direct_read_dma(struct cqspi_flash_pdata *f_pdata, + u_char *buf, loff_t from, size_t len) { struct cqspi_st *cqspi = f_pdata->cqspi; struct device *dev = &cqspi->pdev->dev; @@ -1303,11 +2000,6 @@ dma_addr_t dma_dst; struct device *ddev; - if (!cqspi->rx_chan || !virt_addr_valid(buf)) { - memcpy_fromio(buf, cqspi->ahb_base + from, len); - return 0; - } - ddev = cqspi->rx_chan->device->dev; dma_dst = dma_map_single(ddev, buf, len, DMA_FROM_DEVICE); if (dma_mapping_error(ddev, dma_dst)) { @@ -1349,6 +2041,64 @@ return ret; } +static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata, + const struct spi_mem_op *op) +{ + struct cqspi_st *cqspi = f_pdata->cqspi; + loff_t from = op->addr.val; + loff_t from_aligned, to_aligned; + size_t len = op->data.nbytes; + size_t len_aligned; + u_char *buf = op->data.buf.in; + int ret; + + if (!cqspi->rx_chan || !virt_addr_valid(buf)) { + memcpy_fromio(buf, cqspi->ahb_base + from, len); + return 0; + } + + if (!cqspi_use_phy(f_pdata, op)) + return cqspi_direct_read_dma(f_pdata, buf, from, len); + + /* + * PHY reads must be 16-byte aligned, and they must be a multiple of 16 + * bytes. + */ + from_aligned = (from + 0xF) & ~0xF; + to_aligned = (from + len) & ~0xF; + len_aligned = to_aligned - from_aligned; + + /* Read the unaligned part at the start. */ + if (from != from_aligned) { + ret = cqspi_direct_read_dma(f_pdata, buf, from, + from_aligned - from); + if (ret) + return ret; + buf += from_aligned - from; + } + + if (len_aligned) { + cqspi_phy_enable(f_pdata, true); + ret = cqspi_direct_read_dma(f_pdata, buf, from_aligned, + len_aligned); + cqspi_phy_enable(f_pdata, false); + if (ret) + return ret; + buf += len_aligned; + } + + /* Now read the remaining part, if any. */ + if (to_aligned != (from + len)) { + ret = cqspi_direct_read_dma(f_pdata, buf, to_aligned, + (from + len) - to_aligned); + if (ret) + return ret; + buf += (from + len) - to_aligned; + } + + return 0; +} + static ssize_t cqspi_read(struct cqspi_flash_pdata *f_pdata, const struct spi_mem_op *op) { @@ -1368,7 +2118,7 @@ return ret; if (cqspi->use_direct_mode && ((from + len) <= cqspi->ahb_size)) - return cqspi_direct_read_execute(f_pdata, buf, from, len); + return cqspi_direct_read_execute(f_pdata, op); if (cqspi->use_dma_read && ddata && ddata->indirect_read_dma && virt_addr_valid(buf) && ((dma_align & CQSPI_DMA_UNALIGN) == 0)) @@ -1407,8 +2157,20 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) { int ret; + struct cqspi_st *cqspi = spi_master_get_devdata(mem->spi->master); + struct device *dev = &cqspi->pdev->dev; + + ret = pm_runtime_resume_and_get(dev); + if (ret) { + dev_err(&mem->spi->dev, "resume failed with %d\n", ret); + return ret; + } ret = cqspi_mem_process(mem, op); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + if (ret) dev_err(&mem->spi->dev, "operation failed with %d\n", ret); @@ -1448,6 +2210,33 @@ return spi_mem_default_supports_op(mem, op); } +static void cqspi_mem_do_calibration(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + struct cqspi_st *cqspi = spi_master_get_devdata(mem->spi->master); + struct cqspi_flash_pdata *f_pdata; + struct device *dev = &cqspi->pdev->dev; + int ret; + + f_pdata = &cqspi->f_pdata[mem->spi->chip_select]; + + /* Check if the op is eligible for PHY mode operation. */ + if (!cqspi_phy_op_eligible(op)) + return; + + f_pdata->phy_read_op = *op; + + ret = cqspi_phy_check_pattern(f_pdata, mem); + if (ret) { + dev_dbg(dev, "Pattern not found. Skipping calibration.\n"); + return; + } + + ret = cqspi_phy_calibrate(f_pdata, mem); + if (ret) + dev_info(&cqspi->pdev->dev, "PHY calibration failed: %d\n", ret); +} + static int cqspi_of_get_flash_pdata(struct platform_device *pdev, struct cqspi_flash_pdata *f_pdata, struct device_node *np) @@ -1482,6 +2271,12 @@ return -ENXIO; } + if (of_property_read_u32(np, "cdns,phy-tx-start", &f_pdata->phy_tx_start)) + f_pdata->phy_tx_start = 16; + + if (of_property_read_u32(np, "cdns,phy-tx-end", &f_pdata->phy_tx_end)) + f_pdata->phy_tx_end = 48; + return 0; } @@ -1596,6 +2391,7 @@ .exec_op = cqspi_exec_mem_op, .get_name = cqspi_get_name, .supports_op = cqspi_supports_mem_op, + .do_calibration = cqspi_mem_do_calibration, }; static const struct spi_controller_mem_caps cqspi_mem_caps = { @@ -1753,10 +2549,10 @@ if (irq < 0) return -ENXIO; - pm_runtime_enable(dev); - ret = pm_runtime_resume_and_get(dev); - if (ret < 0) - goto probe_pm_failed; + ret = pm_runtime_set_active(dev); + if (ret) + return ret; + ret = clk_prepare_enable(cqspi->clk); if (ret) { @@ -1862,12 +2658,26 @@ goto probe_setup_failed; } + ret = devm_pm_runtime_enable(dev); + if (ret) { + if (cqspi->rx_chan) + dma_release_channel(cqspi->rx_chan); + goto probe_setup_failed; + } + + pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(dev); + pm_runtime_get_noresume(dev); + ret = spi_register_controller(host); if (ret) { dev_err(&pdev->dev, "failed to register SPI ctlr %d\n", ret); goto probe_setup_failed; } + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return 0; probe_setup_failed: cqspi_controller_enable(cqspi, 0); @@ -1876,9 +2686,6 @@ cqspi_jh7110_disable_clk(pdev, cqspi); clk_disable_unprepare(cqspi->clk); probe_clk_failed: - pm_runtime_put_sync(dev); -probe_pm_failed: - pm_runtime_disable(dev); return ret; } @@ -1901,20 +2708,22 @@ pm_runtime_disable(&pdev->dev); } -static int cqspi_suspend(struct device *dev) +static void __maybe_unused cqspi_restore_context(struct cqspi_st *cqspi) +{ + cqspi_phy_apply_setting(cqspi->f_pdata, + &cqspi->f_pdata->phy_setting); +} + +static int cqspi_runtime_suspend(struct device *dev) { struct cqspi_st *cqspi = dev_get_drvdata(dev); - int ret; - ret = spi_controller_suspend(cqspi->host); cqspi_controller_enable(cqspi, 0); - clk_disable_unprepare(cqspi->clk); - - return ret; + return 0; } -static int cqspi_resume(struct device *dev) +static int cqspi_runtime_resume(struct device *dev) { struct cqspi_st *cqspi = dev_get_drvdata(dev); @@ -1924,11 +2733,33 @@ cqspi->current_cs = -1; cqspi->sclk = 0; + return 0; +} + +static int cqspi_suspend(struct device *dev) +{ + struct cqspi_st *cqspi = dev_get_drvdata(dev); + + return spi_controller_suspend(cqspi->host); +} + +static int cqspi_resume(struct device *dev) +{ + struct cqspi_st *cqspi = dev_get_drvdata(dev); + + /* + * Only restore context if PHY is enabled, or else skip this step + */ + if ((cqspi->f_pdata->use_phy) == true) + cqspi_restore_context(cqspi); return spi_controller_resume(cqspi->host); } -static DEFINE_SIMPLE_DEV_PM_OPS(cqspi_dev_pm_ops, cqspi_suspend, cqspi_resume); +static const struct dev_pm_ops cqspi_dev_pm_ops = { + RUNTIME_PM_OPS(cqspi_runtime_suspend, cqspi_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(cqspi_suspend, cqspi_resume) +}; static const struct cqspi_driver_platdata cdns_qspi = { .quirks = CQSPI_DISABLE_DAC_MODE, @@ -2012,7 +2843,7 @@ .remove_new = cqspi_remove, .driver = { .name = CQSPI_NAME, - .pm = &cqspi_dev_pm_ops, + .pm = pm_ptr(&cqspi_dev_pm_ops), .of_match_table = cqspi_dt_ids, }, }; diff -Naur --no-dereference a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c --- a/drivers/spi/spi-mem.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/spi/spi-mem.c 2024-07-07 20:37:34.676306709 -0400 @@ -478,6 +478,18 @@ } EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); +int spi_mem_do_calibration(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct spi_controller *ctlr = mem->spi->controller; + + if (!ctlr->mem_ops || !ctlr->mem_ops->do_calibration) + return -EOPNOTSUPP; + + ctlr->mem_ops->do_calibration(mem, op); + return 0; +} +EXPORT_SYMBOL_GPL(spi_mem_do_calibration); + static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, void *buf) { diff -Naur --no-dereference a/drivers/thermal/k3_j72xx_bandgap.c b/drivers/thermal/k3_j72xx_bandgap.c --- a/drivers/thermal/k3_j72xx_bandgap.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/thermal/k3_j72xx_bandgap.c 2024-07-07 20:37:34.676306709 -0400 @@ -178,6 +178,7 @@ void __iomem *base; void __iomem *cfg2_base; struct k3_thermal_data *ts_data[K3_VTM_MAX_NUM_TS]; + int cnt; }; /* common data structures */ @@ -338,24 +339,52 @@ dev_dbg(dev, "%d %d %d\n", i, derived_table[i], ref_table[i]); } +static void k3_j72xx_bandgap_init_hw(struct k3_j72xx_bandgap *bgp) +{ + struct k3_thermal_data *data; + int id, high_max, low_temp; + u32 val; + + for (id = 0; id < bgp->cnt; id++) { + data = bgp->ts_data[id]; + val = readl(bgp->cfg2_base + data->ctrl_offset); + val |= (K3_VTM_TMPSENS_CTRL_MAXT_OUTRG_EN | + K3_VTM_TMPSENS_CTRL_SOC | + K3_VTM_TMPSENS_CTRL_CLRZ | BIT(4)); + writel(val, bgp->cfg2_base + data->ctrl_offset); + } + + /* + * Program TSHUT thresholds + * Step 1: set the thresholds to ~123C and 105C WKUP_VTM_MISC_CTRL2 + * Step 2: WKUP_VTM_TMPSENS_CTRL_j set the MAXT_OUTRG_EN bit + * This is already taken care as per of init + * Step 3: WKUP_VTM_MISC_CTRL set the ANYMAXT_OUTRG_ALERT_EN bit + */ + high_max = k3_j72xx_bandgap_temp_to_adc_code(MAX_TEMP); + low_temp = k3_j72xx_bandgap_temp_to_adc_code(COOL_DOWN_TEMP); + + writel((low_temp << 16) | high_max, bgp->cfg2_base + K3_VTM_MISC_CTRL2_OFFSET); + writel(K3_VTM_ANYMAXT_OUTRG_ALERT_EN, bgp->cfg2_base + K3_VTM_MISC_CTRL_OFFSET); +} + struct k3_j72xx_bandgap_data { const bool has_errata_i2128; }; static int k3_j72xx_bandgap_probe(struct platform_device *pdev) { - int ret = 0, cnt, val, id; - int high_max, low_temp; - struct resource *res; + const struct k3_j72xx_bandgap_data *driver_data; + struct thermal_zone_device *ti_thermal; struct device *dev = &pdev->dev; + bool workaround_needed = false; struct k3_j72xx_bandgap *bgp; struct k3_thermal_data *data; - bool workaround_needed = false; - const struct k3_j72xx_bandgap_data *driver_data; - struct thermal_zone_device *ti_thermal; - int *ref_table; struct err_values err_vals; void __iomem *fuse_base; + int ret = 0, val, id; + struct resource *res; + int *ref_table; const s64 golden_factors[] = { -490019999999999936, @@ -422,10 +451,10 @@ /* Get the sensor count in the VTM */ val = readl(bgp->base + K3_VTM_DEVINFO_PWR0_OFFSET); - cnt = val & K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK; - cnt >>= __ffs(K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK); + bgp->cnt = val & K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK; + bgp->cnt >>= __ffs(K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK); - data = devm_kcalloc(bgp->dev, cnt, sizeof(*data), GFP_KERNEL); + data = devm_kcalloc(bgp->dev, bgp->cnt, sizeof(*data), GFP_KERNEL); if (!data) { ret = -ENOMEM; goto err_alloc; @@ -449,8 +478,8 @@ else init_table(3, ref_table, pvt_wa_factors); - /* Register the thermal sensors */ - for (id = 0; id < cnt; id++) { + /* Precompute the derived table & fill each thermal sensor struct */ + for (id = 0; id < bgp->cnt; id++) { data[id].bgp = bgp; data[id].ctrl_offset = K3_VTM_TMPSENS0_CTRL_OFFSET + id * 0x20; data[id].stat_offset = data[id].ctrl_offset + @@ -470,13 +499,13 @@ else if (id == 0 && !workaround_needed) memcpy(derived_table, ref_table, TABLE_SIZE * 4); - val = readl(data[id].bgp->cfg2_base + data[id].ctrl_offset); - val |= (K3_VTM_TMPSENS_CTRL_MAXT_OUTRG_EN | - K3_VTM_TMPSENS_CTRL_SOC | - K3_VTM_TMPSENS_CTRL_CLRZ | BIT(4)); - writel(val, data[id].bgp->cfg2_base + data[id].ctrl_offset); - bgp->ts_data[id] = &data[id]; + } + + k3_j72xx_bandgap_init_hw(bgp); + + /* Register the thermal sensors */ + for (id = 0; id < bgp->cnt; id++) { ti_thermal = devm_thermal_of_zone_register(bgp->dev, id, &data[id], &k3_of_thermal_ops); if (IS_ERR(ti_thermal)) { @@ -486,21 +515,7 @@ } } - /* - * Program TSHUT thresholds - * Step 1: set the thresholds to ~123C and 105C WKUP_VTM_MISC_CTRL2 - * Step 2: WKUP_VTM_TMPSENS_CTRL_j set the MAXT_OUTRG_EN bit - * This is already taken care as per of init - * Step 3: WKUP_VTM_MISC_CTRL set the ANYMAXT_OUTRG_ALERT_EN bit - */ - high_max = k3_j72xx_bandgap_temp_to_adc_code(MAX_TEMP); - low_temp = k3_j72xx_bandgap_temp_to_adc_code(COOL_DOWN_TEMP); - - writel((low_temp << 16) | high_max, data[0].bgp->cfg2_base + - K3_VTM_MISC_CTRL2_OFFSET); - mdelay(100); - writel(K3_VTM_ANYMAXT_OUTRG_ALERT_EN, data[0].bgp->cfg2_base + - K3_VTM_MISC_CTRL_OFFSET); + platform_set_drvdata(pdev, bgp); print_look_up_table(dev, ref_table); /* @@ -529,6 +544,35 @@ return 0; } +static int k3_j72xx_bandgap_suspend(struct device *dev) +{ + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + return 0; +} + +static int k3_j72xx_bandgap_resume(struct device *dev) +{ + struct k3_j72xx_bandgap *bgp = dev_get_drvdata(dev); + int ret; + + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); + return ret; + } + + k3_j72xx_bandgap_init_hw(bgp); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(k3_j72xx_bandgap_pm_ops, + k3_j72xx_bandgap_suspend, + k3_j72xx_bandgap_resume); + static const struct k3_j72xx_bandgap_data k3_j72xx_bandgap_j721e_data = { .has_errata_i2128 = true, }; @@ -556,6 +600,7 @@ .driver = { .name = "k3-j72xx-soc-thermal", .of_match_table = of_k3_j72xx_bandgap_match, + .pm = pm_sleep_ptr(&k3_j72xx_bandgap_pm_ops), }, }; diff -Naur --no-dereference a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c --- a/drivers/tty/serial/8250/8250_omap.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/tty/serial/8250/8250_omap.c 2024-07-07 20:37:34.676306709 -0400 @@ -26,7 +26,10 @@ #include #include #include +#include #include +#include +#include #include "8250.h" @@ -114,6 +117,12 @@ /* RX FIFO occupancy indicator */ #define UART_OMAP_RX_LVL 0x19 +/* + * Copy of the genpd flags for the console. + * Only used if console suspend is disabled + */ +static unsigned int genpd_flags_console; + struct omap8250_priv { void __iomem *membase; int line; @@ -132,7 +141,6 @@ u8 rx_trigger; bool is_suspending; int wakeirq; - int wakeups_enabled; u32 latency; u32 calc_latency; struct pm_qos_request pm_qos_request; @@ -141,6 +149,9 @@ spinlock_t rx_dma_lock; bool rx_dma_broken; bool throttled; + + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_wakeup; }; struct omap8250_dma_params { @@ -1331,6 +1342,30 @@ return 0; } +static int omap8250_select_wakeup_pinctrl(struct device *dev, + struct omap8250_priv *priv) +{ + if (IS_ERR_OR_NULL(priv->pinctrl_wakeup)) + return 0; + + if (!device_may_wakeup(dev)) + return 0; + + return pinctrl_select_state(priv->pinctrl, priv->pinctrl_wakeup); +} + +static int omap8250_sysoff_handler(struct sys_off_data *data) +{ + struct omap8250_priv *priv = dev_get_drvdata(data->dev); + int ret; + + ret = omap8250_select_wakeup_pinctrl(data->dev, priv); + if (ret) + dev_err(data->dev, "Failed to select pinctrl state 'wakeup', continuing poweroff\n"); + + return NOTIFY_DONE; +} + static struct omap8250_dma_params am654_dma = { .rx_size = SZ_2K, .rx_trigger = 1, @@ -1491,7 +1526,7 @@ platform_set_drvdata(pdev, priv); - device_init_wakeup(&pdev->dev, true); + device_set_wakeup_capable(&pdev->dev, true); pm_runtime_enable(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev); @@ -1563,6 +1598,16 @@ priv->line = ret; pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); + + priv->pinctrl = devm_pinctrl_get(&pdev->dev); + if (!IS_ERR_OR_NULL(priv->pinctrl)) + priv->pinctrl_wakeup = pinctrl_lookup_state(priv->pinctrl, "wakeup"); + + devm_register_sys_off_handler(&pdev->dev, + SYS_OFF_MODE_POWER_OFF_PREPARE, + SYS_OFF_PRIO_DEFAULT, + omap8250_sysoff_handler, NULL); + return 0; err: pm_runtime_dont_use_autosuspend(&pdev->dev); @@ -1619,8 +1664,16 @@ { struct omap8250_priv *priv = dev_get_drvdata(dev); struct uart_8250_port *up = serial8250_get_port(priv->line); + struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain); int err = 0; + err = omap8250_select_wakeup_pinctrl(dev, priv); + if (err) { + dev_err(dev, "Failed to select wakeup pinctrl, aborting suspend %pe\n", + ERR_PTR(err)); + return err; + } + serial8250_suspend_port(priv->line); err = pm_runtime_resume_and_get(dev); @@ -1629,8 +1682,19 @@ if (!device_may_wakeup(dev)) priv->wer = 0; serial_out(up, UART_OMAP_WER, priv->wer); - if (uart_console(&up->port) && console_suspend_enabled) - err = pm_runtime_force_suspend(dev); + if (uart_console(&up->port)) { + if (console_suspend_enabled) + err = pm_runtime_force_suspend(dev); + else { + /* + * The pd shall not be powered-off (no console suspend). + * Make copy of genpd flags before to set it always on. + * The original value is restored during the resume. + */ + genpd_flags_console = genpd->flags; + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + } + } flush_work(&priv->qos_work); return err; @@ -1640,12 +1704,23 @@ { struct omap8250_priv *priv = dev_get_drvdata(dev); struct uart_8250_port *up = serial8250_get_port(priv->line); + struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain); int err; + err = pinctrl_select_default_state(dev); + if (err) { + dev_err(dev, "Failed to select default pinctrl state on resume: %pe\n", + ERR_PTR(err)); + return err; + } + if (uart_console(&up->port) && console_suspend_enabled) { - err = pm_runtime_force_resume(dev); - if (err) - return err; + if (console_suspend_enabled) { + err = pm_runtime_force_resume(dev); + if (err) + return err; + } else + genpd->flags = genpd_flags_console; } serial8250_resume_port(priv->line); diff -Naur --no-dereference a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c --- a/drivers/uio/uio_pdrv_genirq.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/uio/uio_pdrv_genirq.c 2024-07-07 20:37:34.676306709 -0400 @@ -276,11 +276,13 @@ #ifdef CONFIG_OF static struct of_device_id uio_of_genirq_match[] = { + { .compatible = "uio" }, + { .compatible = "ti,pruss-shmem" }, { /* This is filled with module_parm */ }, { /* Sentinel */ }, }; MODULE_DEVICE_TABLE(of, uio_of_genirq_match); -module_param_string(of_id, uio_of_genirq_match[0].compatible, 128, 0); +module_param_string(of_id, uio_of_genirq_match[2].compatible, 128, 0); MODULE_PARM_DESC(of_id, "Openfirmware id of the device to be handled by uio"); #endif diff -Naur --no-dereference a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c --- a/drivers/uio/uio_pruss.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/uio/uio_pruss.c 2024-07-07 20:37:34.676306709 -0400 @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-2.0-only /* * Programmable Real-Time Unit Sub System (PRUSS) UIO driver (uio_pruss) * @@ -6,6 +5,15 @@ * and DDR RAM to user space for applications interacting with PRUSS firmware * * Copyright (C) 2010-11 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include #include @@ -18,14 +26,22 @@ #include #include #include +#include +#ifdef CONFIG_ARCH_DAVINCI_DA850 #include +#else +#include +#endif #define DRV_NAME "pruss_uio" #define DRV_VERSION "1.0" +#ifdef CONFIG_ARCH_DAVINCI_DA850 static int sram_pool_sz = SZ_16K; module_param(sram_pool_sz, int, 0); -MODULE_PARM_DESC(sram_pool_sz, "sram pool size to allocate "); +MODULE_PARM_DESC(sram_pool_sz, "sram pool size to allocate"); +#endif + static int extram_pool_sz = SZ_256K; module_param(extram_pool_sz, int, 0); @@ -53,22 +69,23 @@ #define PINTC_HIER 0x1500 struct uio_pruss_dev { - struct uio_info *info; - struct clk *pruss_clk; - dma_addr_t sram_paddr; + struct uio_info info[MAX_PRUSS_EVT]; dma_addr_t ddr_paddr; void __iomem *prussio_vaddr; - unsigned long sram_vaddr; void *ddr_vaddr; - unsigned int hostirq_start; unsigned int pintc_base; +#ifdef CONFIG_ARCH_DAVINCI_DA850 + struct clk *pruss_clk; struct gen_pool *sram_pool; + dma_addr_t sram_paddr; + unsigned long sram_vaddr; +#endif }; static irqreturn_t pruss_handler(int irq, struct uio_info *info) { struct uio_pruss_dev *gdev = info->priv; - int intr_bit = (irq - gdev->hostirq_start + 2); + int intr_bit = 2 + (info - gdev->info); int val, intr_mask = (1 << intr_bit); void __iomem *base = gdev->prussio_vaddr + gdev->pintc_base; void __iomem *intren_reg = base + PINTC_HIER; @@ -86,53 +103,66 @@ static void pruss_cleanup(struct device *dev, struct uio_pruss_dev *gdev) { - int cnt; - struct uio_info *p = gdev->info; + int i; - for (cnt = 0; cnt < MAX_PRUSS_EVT; cnt++, p++) { - uio_unregister_device(p); + for (i = 0; i < MAX_PRUSS_EVT; i++) { + uio_unregister_device(&gdev->info[i]); + kfree(gdev->info[i].name); } iounmap(gdev->prussio_vaddr); if (gdev->ddr_vaddr) { dma_free_coherent(dev, extram_pool_sz, gdev->ddr_vaddr, gdev->ddr_paddr); } +#ifdef CONFIG_ARCH_DAVINCI_DA850 if (gdev->sram_vaddr) gen_pool_free(gdev->sram_pool, gdev->sram_vaddr, sram_pool_sz); clk_disable(gdev->pruss_clk); + clk_put(gdev->pruss_clk); +#else + pm_runtime_put(dev); + pm_runtime_disable(dev); +#endif + kfree(gdev); } static int pruss_probe(struct platform_device *pdev) { - struct uio_info *p; struct uio_pruss_dev *gdev; struct resource *regs_prussio; struct device *dev = &pdev->dev; - int ret, cnt, i, len; + int ret, i, len; struct uio_pruss_pdata *pdata = dev_get_platdata(dev); - gdev = devm_kzalloc(dev, sizeof(struct uio_pruss_dev), GFP_KERNEL); + gdev = kzalloc(sizeof(struct uio_pruss_dev), GFP_KERNEL); if (!gdev) return -ENOMEM; - gdev->info = devm_kcalloc(dev, MAX_PRUSS_EVT, sizeof(*p), GFP_KERNEL); - if (!gdev->info) - return -ENOMEM; - +#ifdef CONFIG_ARCH_DAVINCI_DA850 /* Power on PRU in case its not done as part of boot-loader */ - gdev->pruss_clk = devm_clk_get(dev, "pruss"); + gdev->pruss_clk = clk_get(dev, "pruss"); if (IS_ERR(gdev->pruss_clk)) { dev_err(dev, "Failed to get clock\n"); - return PTR_ERR(gdev->pruss_clk); + ret = PTR_ERR(gdev->pruss_clk); + goto err_free_gdev; } ret = clk_enable(gdev->pruss_clk); if (ret) { dev_err(dev, "Failed to enable clock\n"); - return ret; + goto err_clk_put; + } +#else + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "pm_runtime_get_sync() failed\n"); + pm_runtime_disable(dev); + goto err_free_gdev; } +#endif regs_prussio = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs_prussio) { @@ -147,6 +177,18 @@ goto err_clk_disable; } + if (dev->of_node) { + ret = of_property_read_u32(dev->of_node, + "ti,pintc-offset", + &gdev->pintc_base); + if (ret < 0) { + dev_err(dev, "Can't parse ti,pintc-offset property\n"); + goto err_clk_disable; + } + } else + gdev->pintc_base = pdata->pintc_base; + +#ifdef CONFIG_ARCH_DAVINCI_DA850 if (pdata->sram_pool) { gdev->sram_pool = pdata->sram_pool; gdev->sram_vaddr = @@ -158,9 +200,10 @@ goto err_clk_disable; } } +#endif gdev->ddr_vaddr = dma_alloc_coherent(dev, extram_pool_sz, - &(gdev->ddr_paddr), GFP_KERNEL | GFP_DMA); + &gdev->ddr_paddr, GFP_KERNEL | GFP_DMA); if (!gdev->ddr_vaddr) { dev_err(dev, "Could not allocate external memory\n"); ret = -ENOMEM; @@ -170,61 +213,85 @@ len = resource_size(regs_prussio); gdev->prussio_vaddr = ioremap(regs_prussio->start, len); if (!gdev->prussio_vaddr) { - dev_err(dev, "Can't remap PRUSS I/O address range\n"); + dev_err(dev, "Can't remap PRUSS I/O address range\n"); ret = -ENOMEM; goto err_free_ddr_vaddr; } - ret = platform_get_irq(pdev, 0); - if (ret < 0) - goto err_unmap; + for (i = 0; i < MAX_PRUSS_EVT; i++) { + struct uio_info *p = &gdev->info[i]; - gdev->hostirq_start = ret; - gdev->pintc_base = pdata->pintc_base; - - for (cnt = 0, p = gdev->info; cnt < MAX_PRUSS_EVT; cnt++, p++) { + p->mem[0].name = "pruss"; p->mem[0].addr = regs_prussio->start; p->mem[0].size = resource_size(regs_prussio); p->mem[0].memtype = UIO_MEM_PHYS; + /* note: some userspace code uses hardcoded mem indices... */ +#ifdef CONFIG_ARCH_DAVINCI_DA850 + p->mem[1].name = "sram"; p->mem[1].addr = gdev->sram_paddr; p->mem[1].size = sram_pool_sz; p->mem[1].memtype = UIO_MEM_PHYS; + p->mem[2].name = "ddr"; p->mem[2].addr = gdev->ddr_paddr; p->mem[2].size = extram_pool_sz; p->mem[2].memtype = UIO_MEM_PHYS; +#else + p->mem[1].name = "ddr"; + p->mem[1].addr = gdev->ddr_paddr; + p->mem[1].size = extram_pool_sz; + p->mem[1].memtype = UIO_MEM_PHYS; +#endif + + ret = platform_get_irq(pdev, i); + if (ret < 0) { + dev_err(dev, "Failed to obtain irq %d (%d)\n", i, ret); + goto err_unloop; + } - p->name = devm_kasprintf(dev, GFP_KERNEL, "pruss_evt%d", cnt); + p->name = kasprintf(GFP_KERNEL, "pruss_evt%d", i); p->version = DRV_VERSION; /* Register PRUSS IRQ lines */ - p->irq = gdev->hostirq_start + cnt; + p->irq = ret; p->handler = pruss_handler; p->priv = gdev; ret = uio_register_device(dev, p); - if (ret < 0) + if (ret < 0) { + kfree(p->name); goto err_unloop; + } } platform_set_drvdata(pdev, gdev); return 0; err_unloop: - for (i = 0, p = gdev->info; i < cnt; i++, p++) { - uio_unregister_device(p); + while( --i >= 0 ) { + uio_unregister_device(&gdev->info[i]); + kfree(gdev->info[i].name); } -err_unmap: iounmap(gdev->prussio_vaddr); err_free_ddr_vaddr: dma_free_coherent(dev, extram_pool_sz, gdev->ddr_vaddr, gdev->ddr_paddr); err_free_sram: +#ifdef CONFIG_ARCH_DAVINCI_DA850 if (pdata->sram_pool) gen_pool_free(gdev->sram_pool, gdev->sram_vaddr, sram_pool_sz); err_clk_disable: clk_disable(gdev->pruss_clk); +err_clk_put: + clk_put(gdev->pruss_clk); +#else +err_clk_disable: + pm_runtime_put(dev); + pm_runtime_disable(dev); +#endif +err_free_gdev: + kfree(gdev); return ret; } @@ -237,11 +304,19 @@ return 0; } +static const struct of_device_id pruss_dt_ids[] = { + { .compatible = "ti,pruss-v1" }, + { .compatible = "ti,pruss-v2" }, + {}, +}; +MODULE_DEVICE_TABLE(of, pruss_dt_ids); + static struct platform_driver pruss_driver = { .probe = pruss_probe, .remove = pruss_remove, .driver = { .name = DRV_NAME, + .of_match_table = pruss_dt_ids, }, }; diff -Naur --no-dereference a/drivers/usb/cdns3/cdns3-ti.c b/drivers/usb/cdns3/cdns3-ti.c --- a/drivers/usb/cdns3/cdns3-ti.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/usb/cdns3/cdns3-ti.c 2024-07-07 20:37:34.676306709 -0400 @@ -16,6 +16,7 @@ #include #include #include +#include "core.h" /* USB Wrapper register offsets */ #define USBSS_PID 0x0 @@ -85,6 +86,18 @@ writel(value, data->usbss + offset); } +static struct cdns3_platform_data cdns_ti_pdata = { + .quirks = CDNS3_DRD_SUSPEND_RESIDENCY_ENABLE, /* Errata i2409 */ +}; + +static const struct of_dev_auxdata cdns_ti_auxdata[] = { + { + .compatible = "cdns,usb3", + .platform_data = &cdns_ti_pdata, + }, + {}, +}; + static int cdns_ti_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -176,7 +189,7 @@ reg |= USBSS_W1_PWRUP_RST; cdns_ti_writel(data, USBSS_W1, reg); - error = of_platform_populate(node, NULL, NULL, dev); + error = of_platform_populate(node, NULL, cdns_ti_auxdata, dev); if (error) { dev_err(dev, "failed to create children: %d\n", error); goto err; diff -Naur --no-dereference a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h --- a/drivers/usb/cdns3/core.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/usb/cdns3/core.h 2024-07-07 20:37:34.676306709 -0400 @@ -44,6 +44,7 @@ bool suspend, bool wakeup); unsigned long quirks; #define CDNS3_DEFAULT_PM_RUNTIME_ALLOW BIT(0) +#define CDNS3_DRD_SUSPEND_RESIDENCY_ENABLE BIT(1) }; /** diff -Naur --no-dereference a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c --- a/drivers/usb/cdns3/drd.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/usb/cdns3/drd.c 2024-07-07 20:37:34.676306709 -0400 @@ -389,7 +389,7 @@ int cdns_drd_init(struct cdns *cdns) { void __iomem *regs; - u32 state; + u32 state, reg; int ret; regs = devm_ioremap_resource(cdns->dev, &cdns->otg_res); @@ -433,6 +433,14 @@ cdns->otg_irq_regs = (struct cdns_otg_irq_regs __iomem *) &cdns->otg_v1_regs->ien; writel(1, &cdns->otg_v1_regs->simulate); + + if (cdns->pdata && + (cdns->pdata->quirks & CDNS3_DRD_SUSPEND_RESIDENCY_ENABLE)) { + reg = readl(&cdns->otg_v1_regs->susp_ctrl); + reg |= SUSP_CTRL_SUSPEND_RESIDENCY_ENABLE; + writel(reg, &cdns->otg_v1_regs->susp_ctrl); + } + cdns->version = CDNS3_CONTROLLER_V1; } else { dev_err(cdns->dev, "not supporte DID=0x%08x\n", state); diff -Naur --no-dereference a/drivers/usb/cdns3/drd.h b/drivers/usb/cdns3/drd.h --- a/drivers/usb/cdns3/drd.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/usb/cdns3/drd.h 2024-07-07 20:37:34.676306709 -0400 @@ -193,6 +193,9 @@ /* OTGREFCLK - bitmasks */ #define OTGREFCLK_STB_CLK_SWITCH_EN BIT(31) +/* SUPS_CTRL - bitmasks */ +#define SUSP_CTRL_SUSPEND_RESIDENCY_ENABLE BIT(17) + /* OVERRIDE - bitmasks */ #define OVERRIDE_IDPULLUP BIT(0) /* Only for CDNS3_CONTROLLER_V0 version */ diff -Naur --no-dereference a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c --- a/drivers/usb/dwc3/dwc3-am62.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/usb/dwc3/dwc3-am62.c 2024-07-07 20:37:34.676306709 -0400 @@ -97,9 +97,15 @@ #define USBSS_VBUS_STAT_SESSVALID BIT(2) #define USBSS_VBUS_STAT_VBUSVALID BIT(0) -/* Mask for PHY PLL REFCLK */ +/* USB_PHY_CTRL register bits in CTRL_MMR */ +#define PHY_CORE_VOLTAGE_MASK BIT(31) #define PHY_PLL_REFCLK_MASK GENMASK(3, 0) +/* USB PHY2 register offsets */ +#define USB_PHY_PLL_REG12 0x130 +#define USB_PHY_PLL_LDO_REF_EN BIT(5) +#define USB_PHY_PLL_LDO_REF_EN_EN BIT(4) + #define DWC3_AM62_AUTOSUSPEND_DELAY 100 struct dwc3_am62 { @@ -162,6 +168,13 @@ am62->offset = args.args[0]; + /* Core voltage. PHY_CORE_VOLTAGE bit Recommended to be 0 always */ + ret = regmap_update_bits(am62->syscon, am62->offset, PHY_CORE_VOLTAGE_MASK, 0); + if (ret) { + dev_err(dev, "failed to set phy core voltage\n"); + return ret; + } + ret = regmap_update_bits(am62->syscon, am62->offset, PHY_PLL_REFCLK_MASK, am62->rate_code); if (ret) { dev_err(dev, "failed to set phy pll reference clock rate\n"); @@ -176,8 +189,9 @@ struct device *dev = &pdev->dev; struct device_node *node = pdev->dev.of_node; struct dwc3_am62 *am62; - int i, ret; unsigned long rate; + void __iomem *phy; + int i, ret; u32 reg; am62 = devm_kzalloc(dev, sizeof(*am62), GFP_KERNEL); @@ -219,6 +233,17 @@ if (ret) return ret; + /* Workaround Errata i2409 */ + phy = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(phy)) { + dev_err(dev, "can't map PHY IOMEM resource. Won't apply i2409 fix.\n"); + phy = NULL; + } else { + reg = readl(phy + USB_PHY_PLL_REG12); + reg |= USB_PHY_PLL_LDO_REF_EN | USB_PHY_PLL_LDO_REF_EN_EN; + writel(reg, phy + USB_PHY_PLL_REG12); + } + /* VBUS divider select */ am62->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider"); reg = dwc3_ti_readl(am62, USBSS_PHY_CONFIG); diff -Naur --no-dereference a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c --- a/drivers/usb/typec/tipd/core.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/usb/typec/tipd/core.c 2024-07-07 20:37:34.676306709 -0400 @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include "tps6598x.h" #include "trace.h" @@ -37,13 +39,36 @@ #define TPS_REG_STATUS 0x1a #define TPS_REG_SYSTEM_CONF 0x28 #define TPS_REG_CTRL_CONF 0x29 +#define TPS_REG_BOOT_STATUS 0x2D #define TPS_REG_POWER_STATUS 0x3f +#define TPS_REG_PD_STATUS 0x40 #define TPS_REG_RX_IDENTITY_SOP 0x48 #define TPS_REG_DATA_STATUS 0x5f +#define TPS_REG_SLEEP_CONF 0x70 /* TPS_REG_SYSTEM_CONF bits */ #define TPS_SYSCONF_PORTINFO(c) ((c) & 7) +/* + * BPMs task timeout, recommended 5 seconds + * pg.48 TPS2575 Host Interface Technical Reference + * Manual (Rev. A) + * https://www.ti.com/lit/ug/slvuc05a/slvuc05a.pdf + */ +#define TPS_BUNDLE_TIMEOUT 0x32 + +/* BPMs return code */ +#define TPS_TASK_BPMS_INVALID_BUNDLE_SIZE 0x4 +#define TPS_TASK_BPMS_INVALID_SLAVE_ADDR 0x5 +#define TPS_TASK_BPMS_INVALID_TIMEOUT 0x6 + +/* PBMc data out */ +#define TPS_PBMC_RC 0 /* Return code */ +#define TPS_PBMC_DPCS 2 /* device patch complete status */ + +/* reset de-assertion to ready for operation */ +#define TPS_SETUP_MS 1000 + enum { TPS_PORTINFO_SINK, TPS_PORTINFO_SINK_ACCESSORY, @@ -69,6 +94,7 @@ TPS_MODE_BOOT, TPS_MODE_BIST, TPS_MODE_DISC, + TPS_MODE_PTCH, }; static const char *const modes[] = { @@ -76,17 +102,31 @@ [TPS_MODE_BOOT] = "BOOT", [TPS_MODE_BIST] = "BIST", [TPS_MODE_DISC] = "DISC", + [TPS_MODE_PTCH] = "PTCH", }; /* Unrecognized commands will be replaced with "!CMD" */ #define INVALID_CMD(_cmd_) (_cmd_ == 0x444d4321) +struct tps6598x; + +struct tipd_data { + irq_handler_t irq_handler; + int (*register_port)(struct tps6598x *tps, struct fwnode_handle *node); + void (*trace_power_status)(u16 status); + void (*trace_status)(u32 status); + int (*apply_patch)(struct tps6598x *tps); + int (*init)(struct tps6598x *tps); + int (*reset)(struct tps6598x *tps); +}; + struct tps6598x { struct device *dev; struct regmap *regmap; struct mutex lock; /* device lock */ u8 i2c_protocol:1; + struct gpio_desc *reset; struct typec_port *port; struct typec_partner *partner; struct usb_pd_identity partner_identity; @@ -98,9 +138,11 @@ enum power_supply_usb_type usb_type; int wakeup; + u32 status; /* status reg */ u16 pwr_status; struct delayed_work wq_poll; - irq_handler_t irq_handler; + + const struct tipd_data *data; }; static enum power_supply_property tps6598x_psy_props[] = { @@ -181,6 +223,11 @@ return tps6598x_block_read(tps, reg, val, sizeof(u64)); } +static inline int tps6598x_write8(struct tps6598x *tps, u8 reg, u8 val) +{ + return tps6598x_block_write(tps, reg, &val, sizeof(u8)); +} + static inline int tps6598x_write64(struct tps6598x *tps, u8 reg, u64 val) { return tps6598x_block_write(tps, reg, &val, sizeof(u64)); @@ -283,9 +330,10 @@ power_supply_changed(tps->psy); } -static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd, - size_t in_len, u8 *in_data, - size_t out_len, u8 *out_data) +static int tps6598x_exec_cmd_tmo(struct tps6598x *tps, const char *cmd, + size_t in_len, const u8 *in_data, + size_t out_len, u8 *out_data, + u32 cmd_timeout_ms, u32 res_delay_ms) { unsigned long timeout; u32 val; @@ -308,8 +356,7 @@ if (ret < 0) return ret; - /* XXX: Using 1s for now, but it may not be enough for every command. */ - timeout = jiffies + msecs_to_jiffies(1000); + timeout = jiffies + msecs_to_jiffies(cmd_timeout_ms); do { ret = tps6598x_read32(tps, TPS_REG_CMD1, &val); @@ -322,6 +369,9 @@ return -ETIMEDOUT; } while (val); + /* some commands require delay for the result to be available */ + mdelay(res_delay_ms); + if (out_len) { ret = tps6598x_block_read(tps, TPS_REG_DATA1, out_data, out_len); @@ -346,6 +396,14 @@ return 0; } +static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd, + size_t in_len, const u8 *in_data, + size_t out_len, u8 *out_data) +{ + return tps6598x_exec_cmd_tmo(tps, cmd, in_len, in_data, + out_len, out_data, 1000, 0); +} + static int tps6598x_dr_set(struct typec_port *port, enum typec_data_role role) { const char *cmd = (role == TYPEC_DEVICE) ? "SWUF" : "SWDF"; @@ -420,7 +478,9 @@ dev_err(tps->dev, "%s: failed to read status\n", __func__); return false; } - trace_tps6598x_status(*status); + + if (tps->data->trace_status) + tps->data->trace_status(*status); return true; } @@ -451,7 +511,9 @@ return false; } tps->pwr_status = pwr_status; - trace_tps6598x_power_status(pwr_status); + + if (tps->data->trace_power_status) + tps->data->trace_power_status(pwr_status); return true; } @@ -514,6 +576,65 @@ return IRQ_NONE; } +static bool tps6598x_has_role_changed(struct tps6598x *tps, u32 status) +{ + status ^= tps->status; + + return status & (TPS_STATUS_PORTROLE | TPS_STATUS_DATAROLE); +} + +static irqreturn_t tps25750_interrupt(int irq, void *data) +{ + struct tps6598x *tps = data; + u64 event[2] = { }; + u32 status; + int ret; + + mutex_lock(&tps->lock); + + ret = tps6598x_block_read(tps, TPS_REG_INT_EVENT1, event, 11); + if (ret) { + dev_err(tps->dev, "%s: failed to read events\n", __func__); + goto err_unlock; + } + trace_tps25750_irq(event[0]); + + if (!(event[0] | event[1])) + goto err_unlock; + + if (!tps6598x_read_status(tps, &status)) + goto err_clear_ints; + + if ((event[0] | event[1]) & TPS_REG_INT_POWER_STATUS_UPDATE) + if (!tps6598x_read_power_status(tps)) + goto err_clear_ints; + + if ((event[0] | event[1]) & TPS_REG_INT_DATA_STATUS_UPDATE) + if (!tps6598x_read_data_status(tps)) + goto err_clear_ints; + + /* + * data/port roles could be updated independently after + * a plug event. Therefore, we need to check + * for pr/dr status change to set TypeC dr/pr accordingly. + */ + if ((event[0] | event[1]) & TPS_REG_INT_PLUG_EVENT || + tps6598x_has_role_changed(tps, status)) + tps6598x_handle_plug_event(tps, status); + + tps->status = status; + +err_clear_ints: + tps6598x_block_write(tps, TPS_REG_INT_CLEAR1, event, 11); + +err_unlock: + mutex_unlock(&tps->lock); + + if (event[0] | event[1]) + return IRQ_HANDLED; + return IRQ_NONE; +} + static irqreturn_t tps6598x_interrupt(int irq, void *data) { int intev_len = TPS_65981_2_6_INTEVENT_LEN; @@ -587,7 +708,7 @@ struct tps6598x *tps = container_of(to_delayed_work(work), struct tps6598x, wq_poll); - tps->irq_handler(0, tps); + tps->data->irq_handler(0, tps); queue_delayed_work(system_power_efficient_wq, &tps->wq_poll, msecs_to_jiffies(POLL_INTERVAL)); } @@ -601,12 +722,15 @@ if (ret) return ret; - switch (match_string(modes, ARRAY_SIZE(modes), mode)) { + ret = match_string(modes, ARRAY_SIZE(modes), mode); + + switch (ret) { case TPS_MODE_APP: - return 0; + case TPS_MODE_PTCH: + return ret; case TPS_MODE_BOOT: dev_warn(tps->dev, "dead-battery condition\n"); - return 0; + return ret; case TPS_MODE_BIST: case TPS_MODE_DISC: default: @@ -716,15 +840,478 @@ return PTR_ERR_OR_ZERO(tps->psy); } +static int +tps6598x_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode) +{ + int ret; + u32 conf; + struct typec_capability typec_cap = { }; + + ret = tps6598x_read32(tps, TPS_REG_SYSTEM_CONF, &conf); + if (ret) + return ret; + + typec_cap.revision = USB_TYPEC_REV_1_2; + typec_cap.pd_revision = 0x200; + typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; + typec_cap.driver_data = tps; + typec_cap.ops = &tps6598x_ops; + typec_cap.fwnode = fwnode; + + switch (TPS_SYSCONF_PORTINFO(conf)) { + case TPS_PORTINFO_SINK_ACCESSORY: + case TPS_PORTINFO_SINK: + typec_cap.type = TYPEC_PORT_SNK; + typec_cap.data = TYPEC_PORT_UFP; + break; + case TPS_PORTINFO_DRP_UFP_DRD: + case TPS_PORTINFO_DRP_DFP_DRD: + typec_cap.type = TYPEC_PORT_DRP; + typec_cap.data = TYPEC_PORT_DRD; + break; + case TPS_PORTINFO_DRP_UFP: + typec_cap.type = TYPEC_PORT_DRP; + typec_cap.data = TYPEC_PORT_UFP; + break; + case TPS_PORTINFO_DRP_DFP: + typec_cap.type = TYPEC_PORT_DRP; + typec_cap.data = TYPEC_PORT_DFP; + break; + case TPS_PORTINFO_SOURCE: + typec_cap.type = TYPEC_PORT_SRC; + typec_cap.data = TYPEC_PORT_DFP; + break; + default: + return -ENODEV; + } + + tps->port = typec_register_port(tps->dev, &typec_cap); + if (IS_ERR(tps->port)) + return PTR_ERR(tps->port); + + return 0; +} + +static int tps_request_firmware(struct tps6598x *tps, const struct firmware **fw) +{ + const char *firmware_name; + int ret; + + ret = device_property_read_string(tps->dev, "firmware-name", + &firmware_name); + if (ret) + return ret; + + ret = request_firmware(fw, firmware_name, tps->dev); + if (ret) { + dev_err(tps->dev, "failed to retrieve \"%s\"\n", firmware_name); + return ret; + } + + if ((*fw)->size == 0) { + release_firmware(*fw); + ret = -EINVAL; + } + + return ret; +} + +static int +tps25750_write_firmware(struct tps6598x *tps, + u8 bpms_addr, const u8 *data, size_t len) +{ + struct i2c_client *client = to_i2c_client(tps->dev); + int ret; + u8 slave_addr; + int timeout; + + slave_addr = client->addr; + timeout = client->adapter->timeout; + + /* + * binary configuration size is around ~16Kbytes + * which might take some time to finish writing it + */ + client->adapter->timeout = msecs_to_jiffies(5000); + client->addr = bpms_addr; + + ret = regmap_raw_write(tps->regmap, data[0], &data[1], len - 1); + + client->addr = slave_addr; + client->adapter->timeout = timeout; + + return ret; +} + +static int +tps25750_exec_pbms(struct tps6598x *tps, u8 *in_data, size_t in_len) +{ + int ret; + u8 rc; + + ret = tps6598x_exec_cmd_tmo(tps, "PBMs", in_len, in_data, + sizeof(rc), &rc, 4000, 0); + if (ret) + return ret; + + switch (rc) { + case TPS_TASK_BPMS_INVALID_BUNDLE_SIZE: + dev_err(tps->dev, "%s: invalid fw size\n", __func__); + return -EINVAL; + case TPS_TASK_BPMS_INVALID_SLAVE_ADDR: + dev_err(tps->dev, "%s: invalid slave address\n", __func__); + return -EINVAL; + case TPS_TASK_BPMS_INVALID_TIMEOUT: + dev_err(tps->dev, "%s: timed out\n", __func__); + return -ETIMEDOUT; + default: + break; + } + + return 0; +} + +static int tps25750_abort_patch_process(struct tps6598x *tps) +{ + int ret; + + ret = tps6598x_exec_cmd(tps, "PBMe", 0, NULL, 0, NULL); + if (ret) + return ret; + + ret = tps6598x_check_mode(tps); + if (ret != TPS_MODE_PTCH) + dev_err(tps->dev, "failed to switch to \"PTCH\" mode\n"); + + return ret; +} + +static int tps25750_start_patch_burst_mode(struct tps6598x *tps) +{ + int ret; + const struct firmware *fw; + const char *firmware_name; + struct { + u32 fw_size; + u8 addr; + u8 timeout; + } __packed bpms_data; + u32 addr; + struct device_node *np = tps->dev->of_node; + + ret = device_property_read_string(tps->dev, "firmware-name", + &firmware_name); + if (ret) + return ret; + + ret = tps_request_firmware(tps, &fw); + if (ret) + return ret; + + ret = of_property_match_string(np, "reg-names", "patch-address"); + if (ret < 0) { + dev_err(tps->dev, "failed to get patch-address %d\n", ret); + goto release_fw; + } + + ret = of_property_read_u32_index(np, "reg", ret, &addr); + if (ret) + goto release_fw; + + if (addr == 0 || (addr >= 0x20 && addr <= 0x23)) { + dev_err(tps->dev, "wrong patch address %u\n", addr); + ret = -EINVAL; + goto release_fw; + } + + bpms_data.addr = (u8)addr; + bpms_data.fw_size = fw->size; + bpms_data.timeout = TPS_BUNDLE_TIMEOUT; + + ret = tps25750_exec_pbms(tps, (u8 *)&bpms_data, sizeof(bpms_data)); + if (ret) + goto release_fw; + + ret = tps25750_write_firmware(tps, bpms_data.addr, fw->data, fw->size); + if (ret) { + dev_err(tps->dev, "Failed to write patch %s of %zu bytes\n", + firmware_name, fw->size); + goto release_fw; + } + + /* + * A delay of 500us is required after the firmware is written + * based on pg.62 in tps6598x Host Interface Technical + * Reference Manual + * https://www.ti.com/lit/ug/slvuc05a/slvuc05a.pdf + */ + udelay(500); + +release_fw: + release_firmware(fw); + + return ret; +} + +static int tps25750_complete_patch_process(struct tps6598x *tps) +{ + int ret; + u8 out_data[40]; + u8 dummy[2] = { }; + + /* + * Without writing something to DATA_IN, this command would + * return an error + */ + ret = tps6598x_exec_cmd_tmo(tps, "PBMc", sizeof(dummy), dummy, + sizeof(out_data), out_data, 2000, 20); + if (ret) + return ret; + + if (out_data[TPS_PBMC_RC]) { + dev_err(tps->dev, + "%s: pbmc failed: %u\n", __func__, + out_data[TPS_PBMC_RC]); + return -EIO; + } + + if (out_data[TPS_PBMC_DPCS]) { + dev_err(tps->dev, + "%s: failed device patch complete status: %u\n", + __func__, out_data[TPS_PBMC_DPCS]); + return -EIO; + } + + return 0; +} + +static int tps25750_apply_patch(struct tps6598x *tps) +{ + int ret; + unsigned long timeout; + u64 status = 0; + + ret = tps6598x_block_read(tps, TPS_REG_BOOT_STATUS, &status, 5); + if (ret) + return ret; + /* + * Nothing to be done if the configuration + * is being loaded from EERPOM + */ + if (status & TPS_BOOT_STATUS_I2C_EEPROM_PRESENT) + goto wait_for_app; + + ret = tps25750_start_patch_burst_mode(tps); + if (ret) { + tps25750_abort_patch_process(tps); + return ret; + } + + ret = tps25750_complete_patch_process(tps); + if (ret) + return ret; + +wait_for_app: + timeout = jiffies + msecs_to_jiffies(1000); + + do { + ret = tps6598x_check_mode(tps); + if (ret < 0) + return ret; + + if (time_is_before_jiffies(timeout)) + return -ETIMEDOUT; + + } while (ret != TPS_MODE_APP); + + /* + * The dead battery flag may be triggered when the controller + * port is connected to a device that can source power and + * attempts to power up both the controller and the board it is on. + * To restore controller functionality, it is necessary to clear + * this flag + */ + if (status & TPS_BOOT_STATUS_DEAD_BATTERY_FLAG) { + ret = tps6598x_exec_cmd(tps, "DBfg", 0, NULL, 0, NULL); + if (ret) { + dev_err(tps->dev, "failed to clear dead battery %d\n", ret); + return ret; + } + } + + dev_info(tps->dev, "controller switched to \"APP\" mode\n"); + + return 0; +}; + +static int tps6598x_apply_patch(struct tps6598x *tps) +{ + u8 in = TPS_PTCS_CONTENT_DEV | TPS_PTCS_CONTENT_APP; + u8 out[TPS_MAX_LEN] = {0}; + size_t in_len = sizeof(in); + size_t copied_bytes = 0; + size_t bytes_left; + const struct firmware *fw; + const char *firmware_name; + int ret; + + ret = device_property_read_string(tps->dev, "firmware-name", + &firmware_name); + if (ret) + return ret; + + ret = tps_request_firmware(tps, &fw); + if (ret) + return ret; + + ret = tps6598x_exec_cmd(tps, "PTCs", in_len, &in, + TPS_PTCS_OUT_BYTES, out); + if (ret || out[TPS_PTCS_STATUS] == TPS_PTCS_STATUS_FAIL) { + if (!ret) + ret = -EBUSY; + dev_err(tps->dev, "Update start failed (%d)\n", ret); + goto release_fw; + } + + bytes_left = fw->size; + while (bytes_left) { + if (bytes_left < TPS_MAX_LEN) + in_len = bytes_left; + else + in_len = TPS_MAX_LEN; + ret = tps6598x_exec_cmd(tps, "PTCd", in_len, + fw->data + copied_bytes, + TPS_PTCD_OUT_BYTES, out); + if (ret || out[TPS_PTCD_TRANSFER_STATUS] || + out[TPS_PTCD_LOADING_STATE] == TPS_PTCD_LOAD_ERR) { + if (!ret) + ret = -EBUSY; + dev_err(tps->dev, "Patch download failed (%d)\n", ret); + goto release_fw; + } + copied_bytes += in_len; + bytes_left -= in_len; + } + + ret = tps6598x_exec_cmd(tps, "PTCc", 0, NULL, TPS_PTCC_OUT_BYTES, out); + if (ret || out[TPS_PTCC_DEV] || out[TPS_PTCC_APP]) { + if (!ret) + ret = -EBUSY; + dev_err(tps->dev, "Update completion failed (%d)\n", ret); + goto release_fw; + } + msleep(TPS_SETUP_MS); + dev_info(tps->dev, "Firmware update succeeded\n"); + +release_fw: + release_firmware(fw); + + return ret; +}; + +static int cd321x_init(struct tps6598x *tps) +{ + return 0; +} + +static int tps25750_init(struct tps6598x *tps) +{ + int ret; + + ret = tps->data->apply_patch(tps); + if (ret) + return ret; + + ret = tps6598x_write8(tps, TPS_REG_SLEEP_CONF, + TPS_SLEEP_CONF_SLEEP_MODE_ALLOWED); + if (ret) + dev_warn(tps->dev, + "%s: failed to enable sleep mode: %d\n", + __func__, ret); + + return 0; +} + +static int tps6598x_init(struct tps6598x *tps) +{ + return tps->data->apply_patch(tps); +} + +static int cd321x_reset(struct tps6598x *tps) +{ + return 0; +} + +static int tps25750_reset(struct tps6598x *tps) +{ + return tps6598x_exec_cmd_tmo(tps, "GAID", 0, NULL, 0, NULL, 2000, 0); +} + +static int tps6598x_reset(struct tps6598x *tps) +{ + return 0; +} + +static int +tps25750_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode) +{ + struct typec_capability typec_cap = { }; + const char *data_role; + u8 pd_status; + int ret; + + ret = tps6598x_read8(tps, TPS_REG_PD_STATUS, &pd_status); + if (ret) + return ret; + + ret = fwnode_property_read_string(fwnode, "data-role", &data_role); + if (ret) { + dev_err(tps->dev, "data-role not found: %d\n", ret); + return ret; + } + + ret = typec_find_port_data_role(data_role); + if (ret < 0) { + dev_err(tps->dev, "unknown data-role: %s\n", data_role); + return ret; + } + + typec_cap.data = ret; + typec_cap.revision = USB_TYPEC_REV_1_3; + typec_cap.pd_revision = 0x300; + typec_cap.driver_data = tps; + typec_cap.ops = &tps6598x_ops; + typec_cap.fwnode = fwnode; + typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; + + switch (TPS_PD_STATUS_PORT_TYPE(pd_status)) { + case TPS_PD_STATUS_PORT_TYPE_SINK_SOURCE: + case TPS_PD_STATUS_PORT_TYPE_SOURCE_SINK: + typec_cap.type = TYPEC_PORT_DRP; + break; + case TPS_PD_STATUS_PORT_TYPE_SINK: + typec_cap.type = TYPEC_PORT_SNK; + break; + case TPS_PD_STATUS_PORT_TYPE_SOURCE: + typec_cap.type = TYPEC_PORT_SRC; + break; + default: + return -ENODEV; + } + + tps->port = typec_register_port(tps->dev, &typec_cap); + if (IS_ERR(tps->port)) + return PTR_ERR(tps->port); + + return 0; +} + static int tps6598x_probe(struct i2c_client *client) { - irq_handler_t irq_handler = tps6598x_interrupt; struct device_node *np = client->dev.of_node; - struct typec_capability typec_cap = { }; struct tps6598x *tps; struct fwnode_handle *fwnode; u32 status; - u32 conf; u32 vid; int ret; u64 mask1; @@ -736,13 +1323,22 @@ mutex_init(&tps->lock); tps->dev = &client->dev; + tps->reset = devm_gpiod_get_optional(tps->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(tps->reset)) + return dev_err_probe(tps->dev, PTR_ERR(tps->reset), + "failed to get reset GPIO\n"); + if (tps->reset) + msleep(TPS_SETUP_MS); + tps->regmap = devm_regmap_init_i2c(client, &tps6598x_regmap_config); if (IS_ERR(tps->regmap)) return PTR_ERR(tps->regmap); - ret = tps6598x_read32(tps, TPS_REG_VID, &vid); - if (ret < 0 || !vid) - return -ENODEV; + if (!device_is_compatible(tps->dev, "ti,tps25750")) { + ret = tps6598x_read32(tps, TPS_REG_VID, &vid); + if (ret < 0 || !vid) + return -ENODEV; + } /* * Checking can the adapter handle SMBus protocol. If it can not, the @@ -762,7 +1358,6 @@ APPLE_CD_REG_INT_DATA_STATUS_UPDATE | APPLE_CD_REG_INT_PLUG_EVENT; - irq_handler = cd321x_interrupt; } else { /* Enable power status, data status and plug event interrupts */ mask1 = TPS_REG_INT_POWER_STATUS_UPDATE | @@ -770,24 +1365,32 @@ TPS_REG_INT_PLUG_EVENT; } - tps->irq_handler = irq_handler; + if (dev_fwnode(tps->dev)) + tps->data = device_get_match_data(tps->dev); + else + tps->data = i2c_get_match_data(client); + if (!tps->data) + return -EINVAL; + /* Make sure the controller has application firmware running */ ret = tps6598x_check_mode(tps); - if (ret) + if (ret < 0) return ret; + if (ret == TPS_MODE_PTCH) { + ret = tps->data->init(tps); + if (ret) + return ret; + } + ret = tps6598x_write64(tps, TPS_REG_INT_MASK1, mask1); if (ret) - return ret; + goto err_reset_controller; - ret = tps6598x_read32(tps, TPS_REG_STATUS, &status); - if (ret < 0) - goto err_clear_mask; - trace_tps6598x_status(status); - - ret = tps6598x_read32(tps, TPS_REG_SYSTEM_CONF, &conf); - if (ret < 0) + if (!tps6598x_read_status(tps, &status)) { + ret = -ENODEV; goto err_clear_mask; + } /* * This fwnode has a "compatible" property, but is never populated as a @@ -806,50 +1409,13 @@ goto err_fwnode_put; } - typec_cap.revision = USB_TYPEC_REV_1_2; - typec_cap.pd_revision = 0x200; - typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; - typec_cap.driver_data = tps; - typec_cap.ops = &tps6598x_ops; - typec_cap.fwnode = fwnode; - - switch (TPS_SYSCONF_PORTINFO(conf)) { - case TPS_PORTINFO_SINK_ACCESSORY: - case TPS_PORTINFO_SINK: - typec_cap.type = TYPEC_PORT_SNK; - typec_cap.data = TYPEC_PORT_UFP; - break; - case TPS_PORTINFO_DRP_UFP_DRD: - case TPS_PORTINFO_DRP_DFP_DRD: - typec_cap.type = TYPEC_PORT_DRP; - typec_cap.data = TYPEC_PORT_DRD; - break; - case TPS_PORTINFO_DRP_UFP: - typec_cap.type = TYPEC_PORT_DRP; - typec_cap.data = TYPEC_PORT_UFP; - break; - case TPS_PORTINFO_DRP_DFP: - typec_cap.type = TYPEC_PORT_DRP; - typec_cap.data = TYPEC_PORT_DFP; - break; - case TPS_PORTINFO_SOURCE: - typec_cap.type = TYPEC_PORT_SRC; - typec_cap.data = TYPEC_PORT_DFP; - break; - default: - ret = -ENODEV; - goto err_role_put; - } - ret = devm_tps6598_psy_register(tps); if (ret) goto err_role_put; - tps->port = typec_register_port(&client->dev, &typec_cap); - if (IS_ERR(tps->port)) { - ret = PTR_ERR(tps->port); + ret = tps->data->register_port(tps, fwnode); + if (ret) goto err_role_put; - } if (status & TPS_STATUS_PLUG_PRESENT) { ret = tps6598x_read16(tps, TPS_REG_POWER_STATUS, &tps->pwr_status); @@ -864,7 +1430,7 @@ if (client->irq) { ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, - irq_handler, + tps->data->irq_handler, IRQF_SHARED | IRQF_ONESHOT, dev_name(&client->dev), tps); } else { @@ -898,6 +1464,10 @@ fwnode_handle_put(fwnode); err_clear_mask: tps6598x_write64(tps, TPS_REG_INT_MASK1, 0); +err_reset_controller: + /* Reset PD controller to remove any applied patch */ + tps->data->reset(tps); + return ret; } @@ -908,9 +1478,16 @@ if (!client->irq) cancel_delayed_work_sync(&tps->wq_poll); + devm_free_irq(tps->dev, client->irq, tps); tps6598x_disconnect(tps, 0); typec_unregister_port(tps->port); usb_role_switch_put(tps->role_sw); + + /* Reset PD controller to remove any applied patch */ + tps->data->reset(tps); + + if (tps->reset) + gpiod_set_value_cansleep(tps->reset, 1); } static int __maybe_unused tps6598x_suspend(struct device *dev) @@ -921,6 +1498,8 @@ if (tps->wakeup) { disable_irq(client->irq); enable_irq_wake(client->irq); + } else if (tps->reset) { + gpiod_set_value_cansleep(tps->reset, 1); } if (!client->irq) @@ -933,10 +1512,24 @@ { struct i2c_client *client = to_i2c_client(dev); struct tps6598x *tps = i2c_get_clientdata(client); + int ret; + + ret = tps6598x_check_mode(tps); + if (ret < 0) + return ret; + + if (ret == TPS_MODE_PTCH) { + ret = tps->data->init(tps); + if (ret) + return ret; + } if (tps->wakeup) { disable_irq_wake(client->irq); enable_irq(client->irq); + } else if (tps->reset) { + gpiod_set_value_cansleep(tps->reset, 0); + msleep(TPS_SETUP_MS); } if (!client->irq) @@ -950,15 +1543,45 @@ SET_SYSTEM_SLEEP_PM_OPS(tps6598x_suspend, tps6598x_resume) }; +static const struct tipd_data cd321x_data = { + .irq_handler = cd321x_interrupt, + .register_port = tps6598x_register_port, + .trace_power_status = trace_tps6598x_power_status, + .trace_status = trace_tps6598x_status, + .init = cd321x_init, + .reset = cd321x_reset, +}; + +static const struct tipd_data tps6598x_data = { + .irq_handler = tps6598x_interrupt, + .register_port = tps6598x_register_port, + .trace_power_status = trace_tps6598x_power_status, + .trace_status = trace_tps6598x_status, + .apply_patch = tps6598x_apply_patch, + .init = tps6598x_init, + .reset = tps6598x_reset, +}; + +static const struct tipd_data tps25750_data = { + .irq_handler = tps25750_interrupt, + .register_port = tps25750_register_port, + .trace_power_status = trace_tps25750_power_status, + .trace_status = trace_tps25750_status, + .apply_patch = tps25750_apply_patch, + .init = tps25750_init, + .reset = tps25750_reset, +}; + static const struct of_device_id tps6598x_of_match[] = { - { .compatible = "ti,tps6598x", }, - { .compatible = "apple,cd321x", }, + { .compatible = "ti,tps6598x", &tps6598x_data}, + { .compatible = "apple,cd321x", &cd321x_data}, + { .compatible = "ti,tps25750", &tps25750_data}, {} }; MODULE_DEVICE_TABLE(of, tps6598x_of_match); static const struct i2c_device_id tps6598x_id[] = { - { "tps6598x" }, + { "tps6598x", (kernel_ulong_t)&tps6598x_data }, { } }; MODULE_DEVICE_TABLE(i2c, tps6598x_id); diff -Naur --no-dereference a/drivers/usb/typec/tipd/tps6598x.h b/drivers/usb/typec/tipd/tps6598x.h --- a/drivers/usb/typec/tipd/tps6598x.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/usb/typec/tipd/tps6598x.h 2024-07-07 20:37:34.676306709 -0400 @@ -161,6 +161,25 @@ #define TPS_POWER_STATUS_BC12_STATUS_CDP 2 #define TPS_POWER_STATUS_BC12_STATUS_DCP 3 +/* TPS25750_REG_POWER_STATUS bits */ +#define TPS25750_POWER_STATUS_CHARGER_DETECT_STATUS_MASK GENMASK(7, 4) +#define TPS25750_POWER_STATUS_CHARGER_DETECT_STATUS(p) \ + TPS_FIELD_GET(TPS25750_POWER_STATUS_CHARGER_DETECT_STATUS_MASK, (p)) +#define TPS25750_POWER_STATUS_CHARGER_ADVERTISE_STATUS_MASK GENMASK(9, 8) +#define TPS25750_POWER_STATUS_CHARGER_ADVERTISE_STATUS(p) \ + TPS_FIELD_GET(TPS25750_POWER_STATUS_CHARGER_ADVERTISE_STATUS_MASK, (p)) + +#define TPS25750_POWER_STATUS_CHARGER_DET_STATUS_DISABLED 0 +#define TPS25750_POWER_STATUS_CHARGER_DET_STATUS_IN_PROGRESS 1 +#define TPS25750_POWER_STATUS_CHARGER_DET_STATUS_NONE 2 +#define TPS25750_POWER_STATUS_CHARGER_DET_STATUS_SPD 3 +#define TPS25750_POWER_STATUS_CHARGER_DET_STATUS_BC_1_2_CPD 4 +#define TPS25750_POWER_STATUS_CHARGER_DET_STATUS_BC_1_2_DPD 5 +#define TPS25750_POWER_STATUS_CHARGER_DET_STATUS_DIV_1_DCP 6 +#define TPS25750_POWER_STATUS_CHARGER_DET_STATUS_DIV_2_DCP 7 +#define TPS25750_POWER_STATUS_CHARGER_DET_STATUS_DIV_3_DCP 8 +#define TPS25750_POWER_STATUS_CHARGER_DET_STATUS_1_2V_DCP 9 + /* TPS_REG_DATA_STATUS bits */ #define TPS_DATA_STATUS_DATA_CONNECTION BIT(0) #define TPS_DATA_STATUS_UPSIDE_DOWN BIT(1) @@ -199,6 +218,41 @@ #define TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_A BIT(2) #define TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_B (BIT(2) | BIT(1)) +/* BOOT STATUS REG*/ +#define TPS_BOOT_STATUS_DEAD_BATTERY_FLAG BIT(2) +#define TPS_BOOT_STATUS_I2C_EEPROM_PRESENT BIT(3) + +/* PD STATUS REG */ +#define TPS_REG_PD_STATUS_PORT_TYPE_MASK GENMASK(5, 4) +#define TPS_PD_STATUS_PORT_TYPE(x) \ + TPS_FIELD_GET(TPS_REG_PD_STATUS_PORT_TYPE_MASK, x) + +#define TPS_PD_STATUS_PORT_TYPE_SINK_SOURCE 0 +#define TPS_PD_STATUS_PORT_TYPE_SINK 1 +#define TPS_PD_STATUS_PORT_TYPE_SOURCE 2 +#define TPS_PD_STATUS_PORT_TYPE_SOURCE_SINK 3 + +/* SLEEP CONF REG */ +#define TPS_SLEEP_CONF_SLEEP_MODE_ALLOWED BIT(0) + +/* Start Patch Download Sequence */ +#define TPS_PTCS_CONTENT_APP BIT(0) +#define TPS_PTCS_CONTENT_DEV BIT(1) +#define TPS_PTCS_OUT_BYTES 4 +#define TPS_PTCS_STATUS 1 + +#define TPS_PTCS_STATUS_FAIL 0x80 +/* Patch Download */ +#define TPS_PTCD_OUT_BYTES 10 +#define TPS_PTCD_TRANSFER_STATUS 1 +#define TPS_PTCD_LOADING_STATE 2 + +#define TPS_PTCD_LOAD_ERR 0x09 +/* Patch Download Complete */ +#define TPS_PTCC_OUT_BYTES 4 +#define TPS_PTCC_DEV 2 +#define TPS_PTCC_APP 3 + /* Version Register */ #define TPS_VERSION_HW_VERSION_MASK GENMASK(31, 24) #define TPS_VERSION_HW_VERSION(x) TPS_FIELD_GET(TPS_VERSION_HW_VERSION_MASK, (x)) diff -Naur --no-dereference a/drivers/usb/typec/tipd/trace.h b/drivers/usb/typec/tipd/trace.h --- a/drivers/usb/typec/tipd/trace.h 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/usb/typec/tipd/trace.h 2024-07-07 20:37:34.676306709 -0400 @@ -74,6 +74,13 @@ { APPLE_CD_REG_INT_DATA_STATUS_UPDATE, "DATA_STATUS_UPDATE" }, \ { APPLE_CD_REG_INT_STATUS_UPDATE, "STATUS_UPDATE" }) +#define show_tps25750_irq_flags(flags) \ + __print_flags_u64(flags, "|", \ + { TPS_REG_INT_PLUG_EVENT, "PLUG_EVENT" }, \ + { TPS_REG_INT_POWER_STATUS_UPDATE, "POWER_STATUS_UPDATE" }, \ + { TPS_REG_INT_STATUS_UPDATE, "STATUS_UPDATE" }, \ + { TPS_REG_INT_PD_STATUS_UPDATE, "PD_STATUS_UPDATE" }) + #define TPS6598X_STATUS_FLAGS_MASK (GENMASK(31, 0) ^ (TPS_STATUS_CONN_STATE_MASK | \ TPS_STATUS_PP_5V0_SWITCH_MASK | \ TPS_STATUS_PP_HV_SWITCH_MASK | \ @@ -84,6 +91,14 @@ TPS_STATUS_USB_HOST_PRESENT_MASK | \ TPS_STATUS_LEGACY_MASK)) +#define TPS25750_STATUS_FLAGS_MASK (GENMASK(31, 0) ^ (TPS_STATUS_CONN_STATE_MASK | \ + GENMASK(19, 7) | \ + TPS_STATUS_VBUS_STATUS_MASK | \ + TPS_STATUS_USB_HOST_PRESENT_MASK | \ + TPS_STATUS_LEGACY_MASK | \ + BIT(26) | \ + GENMASK(31, 28))) + #define show_status_conn_state(status) \ __print_symbolic(TPS_STATUS_CONN_STATE((status)), \ { TPS_STATUS_CONN_STATE_CONN_WITH_R_A, "conn-Ra" }, \ @@ -141,6 +156,14 @@ { TPS_STATUS_HIGH_VOLAGE_WARNING, "HIGH_VOLAGE_WARNING" }, \ { TPS_STATUS_HIGH_LOW_VOLTAGE_WARNING, "HIGH_LOW_VOLTAGE_WARNING" }) +#define show_tps25750_status_flags(flags) \ + __print_flags((flags & TPS25750_STATUS_FLAGS_MASK), "|", \ + { TPS_STATUS_PLUG_PRESENT, "PLUG_PRESENT" }, \ + { TPS_STATUS_PLUG_UPSIDE_DOWN, "UPSIDE_DOWN" }, \ + { TPS_STATUS_PORTROLE, "PORTROLE" }, \ + { TPS_STATUS_DATAROLE, "DATAROLE" }, \ + { TPS_STATUS_BIST, "BIST" }) + #define show_power_status_source_sink(power_status) \ __print_symbolic(TPS_POWER_STATUS_SOURCESINK(power_status), \ { 1, "sink" }, \ @@ -159,6 +182,19 @@ { TPS_POWER_STATUS_BC12_STATUS_CDP, "cdp" }, \ { TPS_POWER_STATUS_BC12_STATUS_SDP, "sdp" }) +#define show_tps25750_power_status_charger_detect_status(power_status) \ + __print_symbolic(TPS25750_POWER_STATUS_CHARGER_DETECT_STATUS(power_status), \ + { TPS25750_POWER_STATUS_CHARGER_DET_STATUS_DISABLED, "disabled"}, \ + { TPS25750_POWER_STATUS_CHARGER_DET_STATUS_IN_PROGRESS, "in progress"}, \ + { TPS25750_POWER_STATUS_CHARGER_DET_STATUS_NONE, "none"}, \ + { TPS25750_POWER_STATUS_CHARGER_DET_STATUS_SPD, "spd"}, \ + { TPS25750_POWER_STATUS_CHARGER_DET_STATUS_BC_1_2_CPD, "cpd"}, \ + { TPS25750_POWER_STATUS_CHARGER_DET_STATUS_BC_1_2_DPD, "dpd"}, \ + { TPS25750_POWER_STATUS_CHARGER_DET_STATUS_DIV_1_DCP, "divider 1 dcp"}, \ + { TPS25750_POWER_STATUS_CHARGER_DET_STATUS_DIV_2_DCP, "divider 2 dcp"}, \ + { TPS25750_POWER_STATUS_CHARGER_DET_STATUS_DIV_3_DCP, "divider 3 dpc"}, \ + { TPS25750_POWER_STATUS_CHARGER_DET_STATUS_1_2V_DCP, "1.2V dpc"}) + #define TPS_DATA_STATUS_FLAGS_MASK (GENMASK(31, 0) ^ (TPS_DATA_STATUS_DP_PIN_ASSIGNMENT_MASK | \ TPS_DATA_STATUS_TBT_CABLE_SPEED_MASK | \ TPS_DATA_STATUS_TBT_CABLE_GEN_MASK)) @@ -230,6 +266,21 @@ show_cd321x_irq_flags(__entry->event)) ); +TRACE_EVENT(tps25750_irq, + TP_PROTO(u64 event), + TP_ARGS(event), + + TP_STRUCT__entry( + __field(u64, event) + ), + + TP_fast_assign( + __entry->event = event; + ), + + TP_printk("event=%s", show_tps25750_irq_flags(__entry->event)) +); + TRACE_EVENT(tps6598x_status, TP_PROTO(u32 status), TP_ARGS(status), @@ -257,6 +308,27 @@ ) ); +TRACE_EVENT(tps25750_status, + TP_PROTO(u32 status), + TP_ARGS(status), + + TP_STRUCT__entry( + __field(u32, status) + ), + + TP_fast_assign( + __entry->status = status; + ), + + TP_printk("conn: %s, vbus: %s, usb-host: %s, legacy: %s, flags: %s", + show_status_conn_state(__entry->status), + show_status_vbus_status(__entry->status), + show_status_usb_host_present(__entry->status), + show_status_legacy(__entry->status), + show_tps25750_status_flags(__entry->status) + ) +); + TRACE_EVENT(tps6598x_power_status, TP_PROTO(u16 power_status), TP_ARGS(power_status), @@ -277,6 +349,26 @@ ) ); +TRACE_EVENT(tps25750_power_status, + TP_PROTO(u16 power_status), + TP_ARGS(power_status), + + TP_STRUCT__entry( + __field(u16, power_status) + ), + + TP_fast_assign( + __entry->power_status = power_status; + ), + + TP_printk("conn: %d, pwr-role: %s, typec: %s, charger detect: %s", + !!TPS_POWER_STATUS_CONNECTION(__entry->power_status), + show_power_status_source_sink(__entry->power_status), + show_power_status_typec_status(__entry->power_status), + show_tps25750_power_status_charger_detect_status(__entry->power_status) + ) +); + TRACE_EVENT(tps6598x_data_status, TP_PROTO(u32 data_status), TP_ARGS(data_status), diff -Naur --no-dereference a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig --- a/drivers/video/logo/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/video/logo/Kconfig 2024-07-07 20:37:34.676306709 -0400 @@ -28,6 +28,10 @@ bool "Standard 224-color Linux logo" default y +config LOGO_BEAGLE_CLUT224 + bool "224-color Linux logo with BeagleBoard.org mascot Boris" + default y + config LOGO_DEC_CLUT224 bool "224-color Digital Equipment Corporation Linux logo" depends on MACH_DECSTATION || ALPHA diff -Naur --no-dereference a/drivers/video/logo/logo_beagle_clut224.ppm b/drivers/video/logo/logo_beagle_clut224.ppm --- a/drivers/video/logo/logo_beagle_clut224.ppm 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/video/logo/logo_beagle_clut224.ppm 2024-07-07 20:37:34.676306709 -0400 @@ -0,0 +1,1123 @@ +P3 +80 80 +255 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 6 6 6 10 10 10 10 10 10 10 10 10 6 6 6 +6 6 6 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 6 6 6 10 10 10 14 14 14 +22 22 22 26 26 26 30 30 30 34 34 34 30 30 30 30 30 30 +26 26 26 18 18 18 14 14 14 10 10 10 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 6 6 14 14 14 26 26 26 42 42 42 +54 54 54 66 66 66 78 78 78 78 78 78 78 78 78 74 74 74 +66 66 66 54 54 54 42 42 42 26 26 26 18 18 18 10 10 10 +6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 10 10 22 22 22 42 42 42 66 66 66 86 86 86 +66 66 66 38 38 38 38 38 38 22 22 22 26 26 26 34 34 34 +54 54 54 66 66 66 86 86 86 70 70 70 46 46 46 26 26 26 +14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +10 10 10 26 26 26 50 50 50 82 82 82 58 58 58 6 6 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 6 6 6 54 54 54 86 86 86 66 66 66 +38 38 38 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 +22 22 22 50 50 50 78 78 78 34 34 34 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 70 70 70 +78 78 78 46 46 46 22 22 22 6 6 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 +42 42 42 82 82 82 26 26 26 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 14 14 14 46 46 46 34 34 34 6 6 6 2 2 6 +42 42 42 78 78 78 42 42 42 18 18 18 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 30 30 30 +66 66 66 58 58 58 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 26 26 26 86 86 86 101 101 101 46 46 46 10 10 10 +2 2 6 58 58 58 70 70 70 34 34 34 10 10 10 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 42 42 42 +86 86 86 10 10 10 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 30 30 30 94 94 94 94 94 94 58 58 58 26 26 26 +2 2 6 6 6 6 78 78 78 54 54 54 22 22 22 6 6 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 62 62 62 +62 62 62 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 26 26 26 54 54 54 38 38 38 18 18 18 10 10 10 +2 2 6 2 2 6 34 34 34 82 82 82 38 38 38 14 14 14 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 6 6 6 30 30 30 78 78 78 +30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 10 10 10 10 10 10 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 78 78 78 50 50 50 18 18 18 +6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 38 38 38 86 86 86 +14 14 14 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 54 54 54 66 66 66 26 26 26 +6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 14 14 42 42 42 82 82 82 +2 2 6 2 2 6 2 2 6 6 6 6 10 10 10 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 6 6 6 14 14 14 10 10 10 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 18 18 18 82 82 82 34 34 34 +10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 14 14 46 46 46 86 86 86 +2 2 6 2 2 6 6 6 6 6 6 6 22 22 22 34 34 34 +6 6 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +18 18 18 34 34 34 10 10 10 50 50 50 22 22 22 2 2 6 +2 2 6 2 2 6 2 2 6 10 10 10 86 86 86 42 42 42 +14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 14 14 46 46 46 86 86 86 +2 2 6 2 2 6 38 38 38 116 116 116 94 94 94 22 22 22 +22 22 22 2 2 6 2 2 6 2 2 6 14 14 14 86 86 86 +138 138 138 162 162 162 158 155 152 38 38 38 26 26 26 6 6 6 +2 2 6 2 2 6 2 2 6 2 2 6 86 86 86 46 46 46 +14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 14 14 46 46 46 86 86 86 +2 2 6 14 14 14 138 138 138 198 198 198 195 195 195 116 116 116 +10 10 10 2 2 6 2 2 6 6 6 6 101 98 89 187 187 187 +210 210 210 218 218 218 218 218 218 138 138 138 14 14 14 6 6 6 +2 2 6 2 2 6 2 2 6 2 2 6 86 86 86 50 50 50 +18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 14 14 46 46 46 86 86 86 +2 2 6 54 54 54 218 218 218 195 195 195 226 226 226 246 246 246 +58 58 58 2 2 6 2 2 6 30 30 30 210 210 210 253 253 253 +171 170 170 123 123 123 221 221 221 234 234 234 74 74 74 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 70 70 70 58 58 58 +22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 14 14 46 46 46 82 82 82 +2 2 6 106 106 106 171 170 170 26 26 26 86 86 86 226 226 226 +123 123 123 10 10 10 14 14 14 46 46 46 231 231 231 190 190 190 +6 6 6 70 70 70 90 90 90 238 238 238 158 158 158 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 70 70 70 58 58 58 +22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 14 14 42 42 42 86 86 86 +6 6 6 116 116 116 106 106 106 6 6 6 70 70 70 144 144 144 +128 128 128 18 18 18 38 38 38 54 54 54 221 221 221 106 106 106 +2 2 6 14 14 14 46 46 46 190 190 190 198 198 198 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 74 74 74 62 62 62 +22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 14 14 42 42 42 94 94 94 +14 14 14 101 101 101 128 128 128 2 2 6 18 18 18 116 116 116 +118 98 46 121 92 8 121 92 8 98 77 21 162 162 162 106 106 106 +2 2 6 2 2 6 2 2 6 195 195 195 195 195 195 6 6 6 +2 2 6 2 2 6 2 2 6 2 2 6 74 74 74 62 62 62 +22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 38 38 38 90 90 90 +14 14 14 58 58 58 210 210 210 26 26 26 61 42 6 156 107 11 +226 170 11 236 186 11 225 175 15 184 144 12 225 175 15 175 146 61 +37 26 9 2 2 6 70 70 70 246 246 246 138 138 138 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 70 70 70 66 66 66 +26 26 26 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 38 38 38 86 86 86 +14 14 14 10 10 10 195 195 195 188 164 115 192 133 9 225 175 15 +239 182 13 236 186 11 232 195 16 232 195 16 246 215 20 241 208 19 +232 195 16 184 144 12 218 194 134 219 214 185 42 42 42 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 50 50 50 74 74 74 +30 30 30 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 34 34 34 86 86 86 +14 14 14 2 2 6 121 87 25 192 133 9 219 162 10 239 182 13 +236 186 11 232 195 16 241 208 19 246 215 20 246 215 20 246 215 20 +246 215 20 241 208 19 241 208 19 226 184 13 121 87 25 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 50 50 50 82 82 82 +34 34 34 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 34 34 34 82 82 82 +30 30 30 61 42 6 180 123 7 206 145 10 230 174 11 239 182 13 +236 186 11 238 202 15 241 208 19 235 218 115 246 215 20 246 215 20 +246 215 20 246 215 20 226 184 13 225 175 15 184 144 12 6 6 6 +2 2 6 2 2 6 2 2 6 2 2 6 26 26 26 94 94 94 +42 42 42 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 30 30 30 78 78 78 +50 50 50 104 69 6 192 133 9 216 158 10 236 178 12 236 186 11 +232 195 16 241 208 19 246 215 20 246 215 20 246 215 20 246 215 20 +241 208 19 200 144 11 200 144 11 216 158 10 163 110 8 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 90 90 90 +54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 30 30 30 78 78 78 +46 46 46 22 22 22 137 92 6 210 162 10 239 182 13 236 186 11 +238 202 15 241 208 19 246 215 20 246 215 20 241 208 19 210 162 10 +185 133 11 210 150 10 216 158 10 210 150 10 104 69 6 2 2 6 +6 6 6 54 54 54 14 14 14 2 2 6 2 2 6 62 62 62 +74 74 74 30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 34 34 34 78 78 78 +50 50 50 6 6 6 92 69 23 138 101 21 190 146 13 226 184 13 +232 195 16 232 195 16 225 175 15 190 146 13 167 114 7 192 133 9 +210 150 10 213 154 11 190 142 34 188 164 115 101 98 89 2 2 6 +2 2 6 78 78 78 116 116 116 58 58 58 2 2 6 22 22 22 +90 90 90 46 46 46 18 18 18 6 6 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 38 38 38 86 86 86 +50 50 50 6 6 6 128 128 128 172 154 116 156 107 11 167 114 7 +200 144 11 184 144 12 197 138 11 200 144 11 206 145 10 206 145 10 +197 138 11 188 164 115 195 195 195 198 198 198 171 170 170 14 14 14 +2 2 6 22 22 22 116 116 116 116 116 116 22 22 22 2 2 6 +74 74 74 70 70 70 30 30 30 10 10 10 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 6 6 18 18 18 50 50 50 101 101 101 +26 26 26 10 10 10 138 138 138 190 190 190 172 154 116 156 107 11 +197 138 11 200 144 11 197 138 11 192 133 9 180 123 7 190 142 34 +181 170 141 187 187 187 202 202 202 221 221 221 218 218 218 66 66 66 +2 2 6 2 2 6 50 50 50 62 62 62 6 6 6 2 2 6 +10 10 10 90 90 90 50 50 50 18 18 18 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 10 10 34 34 34 74 74 74 74 74 74 +2 2 6 6 6 6 144 144 144 198 198 198 190 190 190 181 170 141 +150 121 62 156 107 11 156 107 11 166 123 43 172 154 116 187 187 187 +190 190 190 210 210 210 246 246 246 253 253 253 253 253 253 182 182 182 +6 6 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 62 62 62 74 74 74 34 34 34 14 14 14 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 10 10 22 22 22 54 54 54 94 94 94 18 18 18 +2 2 6 46 46 46 234 234 234 221 221 221 190 190 190 190 190 190 +190 190 190 187 187 187 187 187 187 190 190 190 190 190 190 195 195 195 +218 218 218 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 +82 82 82 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 14 14 14 86 86 86 54 54 54 22 22 22 6 6 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 18 18 18 46 46 46 90 90 90 46 46 46 18 18 18 +6 6 6 182 182 182 253 253 253 246 246 246 206 206 206 190 190 190 +190 190 190 190 190 190 190 190 190 190 190 190 206 206 206 231 231 231 +250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +202 202 202 14 14 14 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 42 42 42 86 86 86 42 42 42 18 18 18 +6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 +14 14 14 38 38 38 74 74 74 66 66 66 2 2 6 6 6 6 +90 90 90 250 250 250 253 253 253 253 253 253 238 238 238 138 138 138 +97 87 74 110 93 64 119 103 79 103 95 84 108 105 106 238 238 238 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 82 82 82 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 78 78 78 70 70 70 34 34 34 +14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 +34 34 34 66 66 66 78 78 78 6 6 6 2 2 6 18 18 18 +218 218 218 253 253 253 253 253 253 210 210 210 80 72 61 103 75 39 +169 127 44 169 127 44 167 127 47 207 184 137 167 127 47 104 86 63 +234 234 234 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 182 182 182 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 18 18 18 90 90 90 62 62 62 +30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 26 26 26 +58 58 58 90 90 90 18 18 18 2 2 6 2 2 6 108 105 106 +253 253 253 253 253 253 218 218 218 103 75 39 169 127 44 143 114 43 +118 84 23 169 127 44 169 127 44 188 164 115 183 152 86 169 127 44 +97 87 74 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 231 231 231 18 18 18 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 18 18 18 94 94 94 +54 54 54 26 26 26 10 10 10 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 50 50 50 +90 90 90 26 26 26 2 2 6 2 2 6 14 14 14 195 195 195 +250 250 250 253 253 253 89 81 69 166 123 43 169 127 44 169 127 44 +98 77 21 163 123 43 120 94 48 156 118 43 225 216 182 161 124 51 +80 72 61 171 170 170 253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 242 242 242 54 54 54 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 38 38 38 +86 86 86 50 50 50 22 22 22 6 6 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 6 6 14 14 14 38 38 38 82 82 82 +34 34 34 2 2 6 2 2 6 2 2 6 42 42 42 195 195 195 +246 246 246 231 231 231 104 86 51 169 127 44 169 127 44 169 127 44 +121 87 25 105 82 38 72 65 62 105 82 38 211 190 148 239 232 219 +154 139 110 89 81 69 210 210 210 250 250 250 246 246 246 238 238 238 +226 226 226 231 231 231 101 101 101 6 6 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +38 38 38 82 82 82 42 42 42 14 14 14 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 10 10 26 26 26 62 62 62 66 66 66 +2 2 6 2 2 6 2 2 6 6 6 6 70 70 70 171 170 170 +206 206 206 101 98 89 157 117 39 169 127 44 169 127 44 169 127 44 +163 123 43 105 82 38 163 123 43 169 127 44 211 190 148 255 255 255 +255 255 255 253 253 253 144 144 144 90 90 90 190 190 190 202 202 202 +198 198 198 202 202 202 182 182 182 18 18 18 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 62 62 62 66 66 66 30 30 30 10 10 10 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 14 14 42 42 42 82 82 82 18 18 18 +2 2 6 2 2 6 2 2 6 10 10 10 94 94 94 182 182 182 +210 210 210 99 81 49 169 127 44 169 127 44 169 127 44 169 127 44 +169 127 44 98 77 21 169 127 44 188 164 115 252 252 252 255 255 255 +255 255 255 255 255 255 255 255 255 158 155 152 108 105 106 138 138 138 +195 195 195 195 195 195 210 210 210 158 158 158 6 6 6 14 14 14 +50 50 50 14 14 14 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 6 6 6 86 86 86 46 46 46 18 18 18 6 6 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 6 6 22 22 22 54 54 54 70 70 70 2 2 6 +2 2 6 10 10 10 2 2 6 22 22 22 169 168 166 231 231 231 +128 128 128 143 114 43 169 127 44 169 127 44 169 127 44 169 127 44 +169 127 44 118 84 23 167 127 47 247 245 242 255 255 255 255 255 255 +255 255 255 255 255 255 182 182 182 116 116 116 128 128 128 38 38 38 +206 206 206 206 206 206 198 198 198 226 226 226 94 94 94 2 2 6 +6 6 6 38 38 38 30 30 30 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 62 62 62 66 66 66 26 26 26 10 10 10 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 10 10 30 30 30 74 74 74 50 50 50 2 2 6 +26 26 26 26 26 26 2 2 6 106 106 106 238 238 238 253 253 253 +89 81 66 169 127 44 169 127 44 169 127 44 169 127 44 169 127 44 +169 127 44 157 117 39 138 113 67 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 202 202 202 50 50 50 34 34 34 50 50 50 +231 231 231 246 246 246 218 218 218 202 202 202 210 210 210 14 14 14 +2 2 6 2 2 6 30 30 30 22 22 22 2 2 6 2 2 6 +2 2 6 2 2 6 18 18 18 86 86 86 42 42 42 14 14 14 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 14 14 14 42 42 42 90 90 90 22 22 22 2 2 6 +42 42 42 2 2 6 18 18 18 218 218 218 253 253 253 253 253 253 +104 86 63 169 127 44 169 127 44 169 127 44 169 127 44 169 127 44 +166 123 43 156 118 43 105 82 38 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 221 221 221 182 182 182 90 90 90 +232 232 232 253 253 253 248 248 248 221 221 221 218 218 218 101 101 101 +2 2 6 14 14 14 18 18 18 38 38 38 10 10 10 2 2 6 +2 2 6 2 2 6 2 2 6 78 78 78 58 58 58 22 22 22 +6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 18 18 18 54 54 54 82 82 82 2 2 6 26 26 26 +22 22 22 2 2 6 123 123 123 253 253 253 253 253 253 253 253 253 +89 81 66 169 127 44 169 127 44 169 127 44 169 127 44 166 123 43 +141 109 45 157 117 39 118 84 23 240 237 231 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 226 226 226 97 87 74 72 54 38 +253 253 253 253 253 253 251 251 250 250 250 250 238 238 238 198 198 198 +6 6 6 38 38 38 58 58 58 26 26 26 38 38 38 2 2 6 +2 2 6 2 2 6 2 2 6 46 46 46 78 78 78 30 30 30 +10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +10 10 10 30 30 30 74 74 74 58 58 58 2 2 6 42 42 42 +2 2 6 22 22 22 231 231 231 253 253 253 253 253 253 253 253 253 +162 161 160 104 86 51 169 127 44 169 127 44 156 118 43 141 109 45 +145 111 45 105 82 38 157 117 39 216 197 160 255 255 255 203 202 203 +158 155 152 116 116 116 72 65 62 95 51 32 175 118 6 145 90 47 +250 250 250 253 253 253 252 252 252 253 253 253 253 253 253 246 246 246 +46 46 46 38 38 38 42 42 42 14 14 14 38 38 38 14 14 14 +2 2 6 2 2 6 2 2 6 6 6 6 86 86 86 46 46 46 +14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 +14 14 14 42 42 42 90 90 90 18 18 18 18 18 18 26 26 26 +2 2 6 116 116 116 253 253 253 253 253 253 253 253 253 253 253 253 +248 248 248 138 138 138 99 81 49 105 82 38 125 96 44 121 87 25 +98 77 21 125 96 44 169 127 44 216 197 160 255 255 255 190 190 190 +108 105 106 70 70 70 58 58 58 72 54 38 192 133 9 120 94 48 +250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +94 94 94 6 6 6 2 2 6 2 2 6 10 10 10 34 34 34 +2 2 6 2 2 6 2 2 6 2 2 6 74 74 74 58 58 58 +22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 +26 26 26 66 66 66 82 82 82 2 2 6 38 38 38 6 6 6 +14 14 14 210 210 210 253 253 253 253 253 253 253 253 253 253 253 253 +101 101 101 90 90 90 244 244 244 89 81 69 145 111 45 161 124 51 +197 178 128 207 184 137 216 197 160 218 218 218 171 170 170 151 148 137 +141 130 107 80 72 61 169 168 166 226 226 226 109 101 93 187 187 187 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +144 144 144 2 2 6 2 2 6 2 2 6 2 2 6 46 46 46 +2 2 6 2 2 6 2 2 6 2 2 6 42 42 42 74 74 74 +30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 14 14 14 +42 42 42 90 90 90 26 26 26 6 6 6 42 42 42 2 2 6 +74 74 74 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 +106 106 106 131 116 91 210 209 209 110 93 64 169 127 44 233 229 220 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 232 219 +169 127 44 120 94 48 244 244 244 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +182 182 182 2 2 6 2 2 6 2 2 6 2 2 6 46 46 46 +2 2 6 2 2 6 2 2 6 2 2 6 10 10 10 86 86 86 +38 38 38 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 26 26 26 +66 66 66 82 82 82 2 2 6 22 22 22 18 18 18 2 2 6 +144 144 144 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +171 170 170 125 96 44 103 95 84 110 93 64 175 146 61 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +183 152 86 145 111 45 195 195 194 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 252 252 252 253 253 253 253 253 253 253 253 253 +206 206 206 2 2 6 2 2 6 2 2 6 2 2 6 38 38 38 +2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 86 86 86 +46 46 46 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 46 46 46 +86 86 86 18 18 18 2 2 6 34 34 34 10 10 10 6 6 6 +210 210 210 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +246 246 246 100 88 68 145 111 45 120 94 48 159 135 84 249 249 249 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +152 137 111 156 118 43 158 158 158 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 251 251 250 253 253 253 253 253 253 253 253 253 +221 221 221 6 6 6 2 2 6 2 2 6 6 6 6 30 30 30 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 82 82 82 +54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 26 26 26 66 66 66 +62 62 62 2 2 6 2 2 6 38 38 38 10 10 10 26 26 26 +238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 144 144 144 138 113 67 166 123 43 138 119 85 246 246 246 +255 255 255 242 242 242 255 255 255 255 255 255 234 234 234 255 255 255 +152 137 111 156 118 43 162 161 160 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 250 250 250 253 253 253 253 253 253 253 253 253 +231 231 231 6 6 6 2 2 6 2 2 6 10 10 10 30 30 30 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 66 66 66 +58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 38 38 38 78 78 78 +6 6 6 2 2 6 2 2 6 46 46 46 14 14 14 42 42 42 +246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 250 250 250 94 90 86 154 122 46 138 119 85 253 253 253 +244 243 244 195 195 194 255 255 255 244 244 244 182 182 182 255 255 255 +147 140 128 145 111 45 187 187 187 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 249 249 249 249 249 249 253 253 253 253 253 253 +234 234 234 10 10 10 2 2 6 2 2 6 22 22 22 14 14 14 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 66 66 66 +62 62 62 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 6 6 18 18 18 50 50 50 74 74 74 +2 2 6 2 2 6 14 14 14 70 70 70 34 34 34 62 62 62 +250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 231 231 231 104 86 63 141 130 107 255 255 255 +246 246 246 182 182 182 255 255 255 231 231 231 196 195 196 255 255 255 +147 140 128 119 100 63 242 242 242 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 242 242 242 253 253 253 253 253 253 +234 234 234 14 14 14 2 2 6 2 2 6 30 30 30 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 66 66 66 +62 62 62 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 6 6 18 18 18 54 54 54 62 62 62 +2 2 6 2 2 6 2 2 6 30 30 30 46 46 46 70 70 70 +250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 210 210 210 89 81 66 152 137 111 255 255 255 +254 254 254 171 170 170 255 255 255 218 218 218 210 209 209 255 255 255 +151 148 137 123 99 54 169 168 166 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 252 252 252 253 253 253 253 253 253 +226 226 226 10 10 10 2 2 6 6 6 6 30 30 30 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 66 66 66 +58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 6 6 22 22 22 58 58 58 62 62 62 +2 2 6 2 2 6 2 2 6 2 2 6 30 30 30 78 78 78 +250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 249 249 249 97 87 74 169 127 44 152 137 111 255 255 255 +255 255 255 171 170 170 255 255 255 203 202 203 226 226 226 255 255 255 +158 155 152 169 127 44 120 94 48 234 234 234 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +206 206 206 2 2 6 22 22 22 34 34 34 18 14 6 22 22 22 +26 26 26 18 18 18 6 6 6 2 2 6 2 2 6 82 82 82 +54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 6 6 26 26 26 62 62 62 106 106 106 +78 53 15 185 133 11 210 162 10 121 92 8 6 6 6 62 62 62 +238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 238 238 238 110 93 64 166 123 43 162 161 160 255 255 255 +255 255 255 108 105 106 94 94 94 82 82 82 244 244 244 255 255 255 +202 202 202 150 121 62 141 109 45 202 202 202 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +158 158 158 18 18 18 14 14 14 2 2 6 2 2 6 2 2 6 +6 6 6 18 18 18 66 66 66 38 38 38 6 6 6 94 94 94 +50 50 50 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 +10 10 10 10 10 10 18 18 18 38 38 38 78 78 78 141 130 107 +216 158 10 242 186 14 246 190 14 246 190 14 163 110 8 10 10 10 +90 90 90 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 252 252 252 144 144 144 80 72 61 218 218 218 255 255 255 +206 206 206 123 123 123 253 253 253 128 128 128 169 168 166 254 254 254 +254 254 254 101 98 89 128 128 128 252 252 252 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 225 216 182 219 191 94 219 191 94 +180 133 36 37 26 9 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 38 38 38 46 46 46 26 26 26 106 106 106 +54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 6 6 6 14 14 14 22 22 22 +30 30 30 38 38 38 50 50 50 70 70 70 106 106 106 190 142 34 +226 170 11 242 186 14 246 190 14 246 190 14 246 190 14 156 107 11 +6 6 6 74 74 74 226 226 226 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 182 182 182 108 105 106 116 116 116 +123 123 123 244 244 244 253 253 253 244 244 244 128 128 128 116 116 116 +116 116 116 169 168 166 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 201 174 68 241 196 14 241 208 19 +232 195 16 38 30 10 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 6 6 6 30 30 30 26 26 26 210 162 10 159 135 84 +66 66 66 26 26 26 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 6 6 18 18 18 38 38 38 58 58 58 +78 78 78 86 86 86 101 101 101 123 123 123 175 146 61 210 150 10 +234 174 13 246 186 14 246 190 14 246 190 14 246 190 14 236 186 11 +104 69 6 2 2 6 46 46 46 198 198 198 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 234 234 234 242 242 242 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 201 174 68 242 186 14 241 196 14 +210 162 10 22 18 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 6 6 6 121 92 8 238 202 15 232 195 16 +82 82 82 34 34 34 10 10 10 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 14 14 38 38 38 70 70 70 154 122 46 +190 142 34 200 144 11 197 138 11 197 138 11 213 154 11 226 170 11 +242 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +225 175 15 45 32 11 2 2 6 22 22 22 158 158 158 250 250 250 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 250 250 250 242 242 242 201 174 68 239 182 13 236 186 11 +213 154 11 45 32 11 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 61 42 6 225 175 15 236 186 11 236 186 11 +119 103 79 42 42 42 14 14 14 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 6 6 22 22 22 54 54 54 154 122 46 213 154 11 +226 170 11 230 174 11 226 170 11 226 170 11 236 178 12 242 186 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +241 196 14 184 144 12 10 10 10 2 2 6 6 6 6 116 116 116 +242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 231 231 231 198 198 198 201 174 68 236 178 12 236 178 12 +210 150 10 137 92 6 18 14 6 2 2 6 2 2 6 2 2 6 +6 6 6 61 42 6 200 144 11 236 178 12 239 182 13 239 182 13 +124 112 88 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 10 10 30 30 30 70 70 70 180 133 36 226 170 11 +239 182 13 242 186 14 242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 232 195 16 104 69 6 2 2 6 2 2 6 2 2 6 +66 66 66 221 221 221 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 206 206 206 198 198 198 201 174 68 230 174 11 230 174 11 +216 158 10 192 133 9 163 110 8 116 81 8 104 69 6 116 81 8 +167 114 7 197 138 11 226 170 11 239 182 13 242 186 14 242 186 14 +165 145 105 78 78 78 34 34 34 14 14 14 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 6 6 30 30 30 78 78 78 190 142 34 226 170 11 +239 182 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 241 196 14 210 162 10 22 18 6 2 2 6 2 2 6 +2 2 6 38 38 38 218 218 218 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 206 206 206 198 198 198 201 174 68 226 170 11 236 178 12 +224 166 10 210 150 10 200 144 11 197 138 11 192 133 9 197 138 11 +210 150 10 226 170 11 242 186 14 246 190 14 246 190 14 246 186 14 +225 175 15 124 112 88 62 62 62 30 30 30 14 14 14 6 6 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 10 10 30 30 30 78 78 78 167 127 47 224 166 10 +239 182 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 241 196 14 138 101 21 2 2 6 2 2 6 +2 2 6 2 2 6 78 78 78 250 250 250 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 218 218 218 198 198 198 190 142 34 219 162 10 236 178 12 +234 174 13 224 166 10 216 158 10 213 154 11 213 154 11 216 158 10 +226 170 11 239 182 13 246 190 14 246 190 14 246 190 14 246 190 14 +242 186 14 197 166 45 101 101 101 58 58 58 30 30 30 14 14 14 +6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 10 10 30 30 30 74 74 74 167 127 47 216 158 10 +236 178 12 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 241 196 14 226 184 13 61 42 6 2 2 6 +2 2 6 2 2 6 22 22 22 238 238 238 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 226 226 226 187 187 187 180 133 36 216 158 10 236 178 12 +239 182 13 236 178 12 230 174 11 226 170 11 226 170 11 230 174 11 +236 178 12 242 186 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 239 182 13 197 166 45 106 106 106 66 66 66 34 34 34 +14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 6 6 26 26 26 70 70 70 163 133 67 213 154 11 +236 178 12 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 241 196 14 190 146 13 18 14 6 +2 2 6 2 2 6 46 46 46 246 246 246 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 221 221 221 86 86 86 156 107 11 216 158 10 236 178 12 +242 186 14 246 186 14 242 186 14 239 182 13 239 182 13 242 186 14 +242 186 14 246 186 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 242 186 14 225 175 15 142 114 66 66 66 66 +30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 6 6 26 26 26 70 70 70 163 133 67 210 150 10 +236 178 12 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 232 195 16 121 92 8 +34 34 34 106 106 106 221 221 221 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +242 242 242 82 82 82 18 14 6 163 110 8 216 158 10 236 178 12 +242 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 163 133 67 +46 46 46 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 10 10 30 30 30 78 78 78 163 133 67 210 150 10 +236 178 12 246 186 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 241 196 14 225 175 15 +181 170 141 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 218 218 218 +58 58 58 2 2 6 22 18 6 167 114 7 216 158 10 236 178 12 +246 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 186 14 242 186 14 190 142 34 +54 54 54 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 14 14 14 38 38 38 86 86 86 180 133 36 213 154 11 +236 178 12 246 186 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 232 195 16 +190 146 13 218 218 218 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 250 250 250 171 170 170 26 26 26 +2 2 6 2 2 6 37 26 9 163 110 8 219 162 10 239 182 13 +246 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 186 14 236 178 12 224 166 10 142 114 66 +46 46 46 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 18 18 18 50 50 50 109 101 93 192 133 9 224 166 10 +242 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 226 184 13 +210 162 10 141 109 45 226 226 226 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 198 198 198 66 66 66 2 2 6 2 2 6 +2 2 6 2 2 6 45 32 11 156 107 11 219 162 10 239 182 13 +246 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 242 186 14 234 174 13 213 154 11 154 122 46 66 66 66 +30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 22 22 22 58 58 58 150 121 62 206 145 10 234 174 13 +242 186 14 246 186 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 236 178 12 +210 162 10 163 110 8 61 42 6 138 138 138 218 218 218 250 250 250 +253 253 253 253 253 253 253 253 253 250 250 250 242 242 242 210 210 210 +144 144 144 66 66 66 6 6 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 61 42 6 163 110 8 216 158 10 236 178 12 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 239 182 13 +230 174 11 216 158 10 190 142 34 124 112 88 70 70 70 38 38 38 +18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 22 22 22 62 62 62 166 123 43 206 145 10 224 166 10 +236 178 12 239 182 13 242 186 14 242 186 14 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 236 178 12 +216 158 10 175 118 6 78 53 15 2 2 6 6 6 6 30 30 30 +54 54 54 62 62 62 50 50 50 38 38 38 14 14 14 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 6 6 6 78 53 15 167 114 7 213 154 11 236 178 12 +246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 242 186 14 239 182 13 239 182 13 230 174 11 210 150 10 +167 127 47 124 112 88 82 82 82 54 54 54 34 34 34 18 18 18 +6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 18 18 18 50 50 50 157 117 39 192 133 9 200 144 11 +216 158 10 219 162 10 224 166 10 226 170 11 230 174 11 236 178 12 +239 182 13 239 182 13 242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 230 174 11 +210 150 10 163 110 8 104 69 6 10 10 10 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 6 6 6 85 60 19 167 114 7 206 145 10 230 174 11 +242 186 14 246 190 14 246 190 14 246 190 14 246 186 14 242 186 14 +239 182 13 230 174 11 224 166 10 213 154 11 180 133 36 124 112 88 +86 86 86 58 58 58 38 38 38 22 22 22 10 10 10 6 6 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 14 14 14 34 34 34 70 70 70 141 109 45 157 117 39 +167 114 7 180 123 7 192 133 9 197 138 11 200 144 11 206 145 10 +213 154 11 219 162 10 224 166 10 230 174 11 239 182 13 242 186 14 +246 186 14 246 186 14 246 186 14 246 186 14 239 182 13 216 158 10 +185 133 11 152 99 6 104 69 6 18 14 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 +2 2 6 6 6 6 78 53 15 152 99 6 192 133 9 219 162 10 +236 178 12 239 182 13 246 186 14 242 186 14 239 182 13 236 178 12 +224 166 10 206 145 10 192 133 9 150 121 62 94 94 94 62 62 62 +42 42 42 22 22 22 14 14 14 6 6 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 6 6 18 18 18 34 34 34 58 58 58 78 78 78 +101 98 89 124 112 88 141 109 45 156 107 11 163 110 8 167 114 7 +175 118 6 180 123 7 185 133 11 197 138 11 210 150 10 219 162 10 +226 170 11 236 178 12 236 178 12 234 174 13 219 162 10 197 138 11 +163 110 8 137 92 6 85 60 19 10 10 10 2 2 6 2 2 6 +18 18 18 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 +38 38 38 38 38 38 38 38 38 38 38 38 26 26 26 2 2 6 +2 2 6 6 6 6 61 42 6 137 92 6 175 118 6 200 144 11 +219 162 10 230 174 11 234 174 13 230 174 11 219 162 10 210 150 10 +192 133 9 163 110 8 124 112 88 82 82 82 50 50 50 30 30 30 +14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 6 6 14 14 14 22 22 22 34 34 34 +42 42 42 58 58 58 74 74 74 86 86 86 101 98 89 119 100 63 +125 96 44 121 87 25 137 92 6 152 99 6 163 110 8 180 123 7 +185 133 11 197 138 11 206 145 10 200 144 11 180 123 7 156 107 11 +137 92 6 104 69 6 45 32 11 54 54 54 108 105 106 101 98 89 +86 86 86 82 82 82 78 78 78 78 78 78 78 78 78 78 78 78 +78 78 78 78 78 78 78 78 78 82 82 82 86 86 86 94 94 94 +106 106 106 101 101 101 86 66 32 116 81 8 156 107 11 180 123 7 +192 133 9 200 144 11 206 145 10 200 144 11 192 133 9 175 118 6 +138 101 21 109 101 93 70 70 70 42 42 42 22 22 22 10 10 10 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 10 10 10 +14 14 14 22 22 22 30 30 30 38 38 38 50 50 50 62 62 62 +74 74 74 90 90 90 101 98 89 119 103 79 121 87 25 116 81 8 +137 92 6 152 99 6 152 99 6 152 99 6 137 92 6 116 81 8 +104 69 6 86 66 32 101 98 89 82 82 82 58 58 58 46 46 46 +38 38 38 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 +34 34 34 34 34 34 34 34 34 34 34 34 38 38 38 42 42 42 +54 54 54 82 82 82 97 87 74 85 60 19 137 92 6 156 107 11 +167 114 7 175 118 6 175 118 6 167 114 7 152 99 6 121 87 25 +101 98 89 62 62 62 34 34 34 18 18 18 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 6 6 6 6 6 10 10 10 18 18 18 22 22 22 +30 30 30 42 42 42 50 50 50 66 66 66 86 86 86 101 98 89 +104 86 63 104 69 6 104 69 6 104 69 6 104 69 6 85 60 19 +86 66 32 90 90 90 62 62 62 38 38 38 22 22 22 14 14 14 +10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 +6 6 6 10 10 10 10 10 10 10 10 10 10 10 10 14 14 14 +22 22 22 42 42 42 70 70 70 89 81 66 78 53 15 104 69 6 +116 81 8 137 92 6 137 92 6 116 81 8 99 81 49 86 86 86 +58 58 58 30 30 30 14 14 14 6 6 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 +10 10 10 14 14 14 18 18 18 26 26 26 38 38 38 54 54 54 +70 70 70 86 86 86 97 87 74 89 81 66 89 81 66 86 86 86 +74 74 74 50 50 50 30 30 30 14 14 14 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 18 18 18 34 34 34 58 58 58 82 82 82 89 81 66 +89 81 66 89 81 66 100 88 68 97 87 74 74 74 74 50 50 50 +26 26 26 14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 6 6 6 6 6 14 14 14 18 18 18 +30 30 30 38 38 38 46 46 46 54 54 54 50 50 50 42 42 42 +30 30 30 18 18 18 10 10 10 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 6 6 14 14 14 26 26 26 38 38 38 50 50 50 +58 58 58 58 58 58 54 54 54 42 42 42 30 30 30 18 18 18 +10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 +6 6 6 10 10 10 14 14 14 18 18 18 18 18 18 14 14 14 +10 10 10 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 6 6 6 14 14 14 18 18 18 +22 22 22 22 22 22 18 18 18 14 14 14 10 10 10 6 6 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 diff -Naur --no-dereference a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c --- a/drivers/video/logo/logo.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/video/logo/logo.c 2024-07-07 20:37:34.676306709 -0400 @@ -100,6 +100,10 @@ /* SuperH Linux logo */ logo = &logo_superh_clut224; #endif +#ifdef CONFIG_LOGO_BEAGLE_CLUT224 + /* Generic Linux logo */ + logo = &logo_beagle_clut224; +#endif } return logo; } diff -Naur --no-dereference a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile --- a/drivers/video/logo/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/video/logo/Makefile 2024-07-07 20:37:34.676306709 -0400 @@ -5,6 +5,7 @@ obj-$(CONFIG_LOGO_LINUX_MONO) += logo_linux_mono.o obj-$(CONFIG_LOGO_LINUX_VGA16) += logo_linux_vga16.o obj-$(CONFIG_LOGO_LINUX_CLUT224) += logo_linux_clut224.o +obj-$(CONFIG_LOGO_BEAGLE_CLUT224) += logo_beagle_clut224.o obj-$(CONFIG_LOGO_DEC_CLUT224) += logo_dec_clut224.o obj-$(CONFIG_LOGO_MAC_CLUT224) += logo_mac_clut224.o obj-$(CONFIG_LOGO_PARISC_CLUT224) += logo_parisc_clut224.o diff -Naur --no-dereference a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c --- a/drivers/watchdog/rti_wdt.c 2024-05-25 10:22:56.000000000 -0400 +++ b/drivers/watchdog/rti_wdt.c 2024-07-07 20:37:34.676306709 -0400 @@ -59,6 +59,8 @@ #define PON_REASON_EOF_NUM 0xCCCCBBBB #define RESERVED_MEM_MIN_SIZE 12 +#define MAX_HW_ERROR 250 + static int heartbeat = DEFAULT_HEARTBEAT; /* @@ -97,7 +99,7 @@ * to be 50% or less than that; we obviouly want to configure the open * window as large as possible so we select the 50% option. */ - wdd->min_hw_heartbeat_ms = 500 * wdd->timeout; + wdd->min_hw_heartbeat_ms = 520 * wdd->timeout + MAX_HW_ERROR; /* Generate NMI when wdt expires */ writel_relaxed(RTIWWDRX_NMI, wdt->base + RTIWWDRXCTRL); @@ -131,31 +133,33 @@ * be petted during the open window; not too early or not too late. * The HW configuration options only allow for the open window size * to be 50% or less than that. + * To avoid any glitches, we accommodate 2% + max hardware error + * safety margin. */ switch (wsize) { case RTIWWDSIZE_50P: - /* 50% open window => 50% min heartbeat */ - wdd->min_hw_heartbeat_ms = 500 * heartbeat; + /* 50% open window => 52% min heartbeat */ + wdd->min_hw_heartbeat_ms = 520 * heartbeat + MAX_HW_ERROR; break; case RTIWWDSIZE_25P: - /* 25% open window => 75% min heartbeat */ - wdd->min_hw_heartbeat_ms = 750 * heartbeat; + /* 25% open window => 77% min heartbeat */ + wdd->min_hw_heartbeat_ms = 770 * heartbeat + MAX_HW_ERROR; break; case RTIWWDSIZE_12P5: - /* 12.5% open window => 87.5% min heartbeat */ - wdd->min_hw_heartbeat_ms = 875 * heartbeat; + /* 12.5% open window => 89.5% min heartbeat */ + wdd->min_hw_heartbeat_ms = 895 * heartbeat + MAX_HW_ERROR; break; case RTIWWDSIZE_6P25: - /* 6.5% open window => 93.5% min heartbeat */ - wdd->min_hw_heartbeat_ms = 935 * heartbeat; + /* 6.5% open window => 95.5% min heartbeat */ + wdd->min_hw_heartbeat_ms = 955 * heartbeat + MAX_HW_ERROR; break; case RTIWWDSIZE_3P125: - /* 3.125% open window => 96.9% min heartbeat */ - wdd->min_hw_heartbeat_ms = 969 * heartbeat; + /* 3.125% open window => 98.9% min heartbeat */ + wdd->min_hw_heartbeat_ms = 989 * heartbeat + MAX_HW_ERROR; break; default: @@ -233,14 +237,6 @@ return -EINVAL; } - /* - * If watchdog is running at 32k clock, it is not accurate. - * Adjust frequency down in this case so that we don't pet - * the watchdog too often. - */ - if (wdt->freq < 32768) - wdt->freq = wdt->freq * 9 / 10; - pm_runtime_enable(dev); ret = pm_runtime_resume_and_get(dev); if (ret < 0) { diff -Naur --no-dereference a/firmware/am335x-bone-scale-data.bin b/firmware/am335x-bone-scale-data.bin --- a/firmware/am335x-bone-scale-data.bin 1969-12-31 19:00:00.000000000 -0500 +++ b/firmware/am335x-bone-scale-data.bin 2024-07-07 20:37:34.676306709 -0400 @@ -0,0 +1 @@ + W#d$ m$$ m$$ l$†$ l$†d$ m$$ m$$ l$†$ l$† \ No newline at end of file diff -Naur --no-dereference a/firmware/am335x-evm-scale-data.bin b/firmware/am335x-evm-scale-data.bin --- a/firmware/am335x-evm-scale-data.bin 1969-12-31 19:00:00.000000000 -0500 +++ b/firmware/am335x-evm-scale-data.bin 2024-07-07 20:37:34.676306709 -0400 @@ -0,0 +1 @@ + Wd-%d-%+ \ No newline at end of file diff -Naur --no-dereference a/firmware/am335x-pm-firmware.bin b/firmware/am335x-pm-firmware.bin --- a/firmware/am335x-pm-firmware.bin 1969-12-31 19:00:00.000000000 -0500 +++ b/firmware/am335x-pm-firmware.bin 2024-07-07 20:37:34.676306709 -0400 @@ -0,0 +1,34 @@ +™ é í ñ õ ù ý   • • • • • • • • • • • • • • • • • É • • • • • • • • • • • • • • å • E Y ± • • • Å Ù í )=Qey¡µÉJh CôÉs`pG0áDð<¹KD›hpG¿ÊD8K D›`pG¿ÊD8KJh›²`pG,áDœKhZ* ØJëƒëƒ˜h0¿ pG pG¿œ#J$Khhð´#Mð"J/`"NÃóÀp!L"HÃó!JÃó€%7`ÃóÀ#p%pHhJh `Sh ÐHI€è0P`˜D냛hHð¼GiðÑI h)ИIÄë„dh±T`éçI˜ÄQø$@,öÑáç<áD8áD°™¬˜¨0áD4áDœ¸Oðÿ3´HLIJ#``]øK ``pG4áD0áD8áD<áDJh CôÉs`pG0áDJh›²Cê@`pG¿,áDJh#ðÿC`pG¿@áDKJhëƒëƒ|pG¿œKJhëƒëƒX|pG¿œµð×ü$ðÜü F4ð¨ü4,ùÑKöŒJhšBÐÿ÷œÿðrøðòùðþù ðü5 ð~üÿ÷¤ÿ ðøOôÉrI ð½ø ½ Fð‚üà翼X$µÿ÷Çÿ0¿ý翵ÿ÷‘ÿ@¿½¿µÿ÷‹ÿ@¿" ð}ü½è@" ðP¼µÿ÷ÿ" ðrü½è@" ðE¼¿µ$ FðSü F4ðcü4,öÑKöŒJhšBÐðøð›ù ð,ü5 ð)ü ðÜÿ ÿ÷Uÿ@¿½ Fð2ü FðCüæç¼pG¿pG¿pG¿pG¿pG¿2±FɲDø“BûÑpG¿xC!±ø+*úÑFpGøµ LF!h +MI±K«B#`¿Kp¿#` ø½Oê8Fÿ÷×ÿ9Fîç¿ 8µFx8±%Fÿ÷Ûÿø(ùÑ`8½¿øµFxx±i±Fû«FD˜“ðøD + ÿ÷—ÿ…óˆ F°½è0@°pG¿T€$”$K`pG¿T-éðO$F‹F'F‘°®Feà(tÐÿ÷rÿ¶FvFø ë%(!FòÑ/òÑ;FOð :Fžø— ñ# u¼ñWòèßèðÿææææææ æ%.........ææææææææææææææææææææææææææææææPææææææææææUËæææÞË^æcæm|Žæ“Æ\ææ÷æú F°½èð + Þ#ô€iñÚÚ@ñé ñ#ðÓø ñ ô€oкñ¼¿IôyÊñ + ô€^#rFø0ŽF ñSF”FàfF³ûðòû3·Lã\Y±£ña ¼ñŒ¿Oð Oð £ë Û²´F ø;F*åÑ«óœ“ô€sqF“ +кñЛ+ðï›+ðïôs“ðE›ð€ ñ“ð‹- Lÿ÷“þ›S±ºñЛ+ðù›+ð¹ñðM0xP±ÿ÷~þø 4(øÑ¹ñ?ôü®›+?ôø®š£ë ¹ñ÷ñ® ñÿ6>@Fÿ÷dþsùÑLDææ cçpxCð@.F÷æpxCô€s.Fòæÿ÷Qþ4ÕæñcÛø ñ (Àò¸px.FàæpxCô€c.FÛæpxCð€.FÖæpxCôc.FÑæôj@ðcpxOð0.FÈæ–ø ñ0 ©ñ0 (˜¿ôjò¹€.F ëŒ ëL øŸ¬ñ0 ©ñ0 (óÙHFºñ ¿eFbF•¦æ Cô€SçÛø ñ4ÿ÷ûý³FæpxCð.F“æ˜@ñ3#ðpxCð.F‰æÞñì€Ø@ñC"FÛøãÁé# ñ aæ Þæš*@ðCô€s Ûø #ô€i ñ ßæpxCð.FcæÛø ñ‘¹ñð&HF“’ÿ÷¬ýš›ÕB’FØF‚F™¡ë"êâvñÀñÿ;>± ñÿ;@Fÿ÷ý»ñÿ?÷ÑQFHFÿ÷Âý4DDÝø°æpxCð .F+æÞCô€iñ’€Ú@ñÓ€ + ñ#ðñ Óø æ@ñˆ€#ðCð,ç¥ëpFÿ÷˜ý'DïåHÿ÷„ýDÝæHF.FôjOç¿Ä$ô$ð€ AѸñ0Лƒ±š›+“ Ýñÿ9 ñÿ9@Fÿ÷Fý¹ñÿ?÷Ñ›D›+@ðÓ€›+±ºñÐOð ¦æ›ƒ±š›+“ Ýñÿ9 ñÿ9@Fÿ÷'ý¹ñÿ?÷Ñ›D0x(?ô¥­Oð šæÛø  ñ +æ›+?ô®ºñ?ô‹®}æ¸ñ0´ÑpæžëÔšéÔ^çÔ{Õ»ø  ñ æÛø0 ñ `{å + Ûø  ñ æpxCð.FˆåpxÛø .F ñ åHFQFÿ÷ +ýñÿ9D>± ñÿ9@Fÿ÷Õü¹ñÿ?÷Ñ4DÝø°Tå#ô€søævx ñ0 ¦ñ0 (±Fö¥®0FbF.F]åpxCð.FXå›3“æ›3“ æž¹Ô˜·ÔZµÔOð +*Õ»ù  ñ ·å™£ÔZ¡Ô'ÕÛø0 ñ €å ßøXÜæ0 4ÿ÷üæpxžƒð€vB–.F#å^õg¯›ø  ñ ’åZõ^¯›ø  ñ ‰åXõu¯Ûø0 ñ pðä!FOð Îåì$´µƒ°«Sø F“ÿ÷Úü°]øë°pG¿þç¿JKšB ÒÑCD H!ð1FDSøƒBBøùÑH IOðˆB¸¿@ø+úÛÿ÷Ç»¿Ä4*Àþç¿þç¿þç¿þç¿þç¿þç¿þç¿þ翵 ð6ú¹þç ½ñŠA¡õá`pGñŠ@ õáhpG#ABððX¿JB(¸¿0@€ñ`@“@õa@`pG#ABððX¿JB(úó¸¿0J@Bø 0pG€áà#ABððX¿JB(úó¸¿0J@Bø 0pG€âàJhCð`pGíàJhCð`pGíൠÿ÷Äÿ ðùûKh`½¿ ßDµ ÿ÷¶ÿÿ÷0úÿ÷8ú¨±ÿ÷áúFH¹ÿ÷ëú°¹ÿ÷Dú½è@ ÿ÷¿ ÿ÷0û½è@ ÿ÷‡¿ ÿ÷¶ú½è@ ÿ÷¿ Fÿ÷,û½è@ ÿ÷w¿¿µ! ÿ÷†ÿ½è@! 𹻿µ$ Fÿ÷{ÿ F4ÿ÷‹ÿ4,öÑKöŒ JhšBнè@ÿ÷º Fÿ÷hÿ Fÿ÷yÿ½è@ÿ÷ý¹¿¼µ# ÿ÷Zÿ½è@# 𻿵$ ÿ÷Pÿ½è@$ ðƒ»¿µ( ÿ÷Fÿ½è@( ðy»¿µ) ÿ÷<ÿ½è@) ðo»¿µ* ÿ÷2ÿ½è@* ðe»¿µ+ ÿ÷(ÿ½è@+ ð[»¿µ, ÿ÷ÿ½è@, ðQ»¿µ- ÿ÷ÿ½è@- ðG»¿µ. ÿ÷ +ÿ½è@. ð=»¿µ/ ÿ÷ÿ½è@/ ð3»¿µ0 ÿ÷öþ½è@0 ð)»¿µ1 ÿ÷ìþ½è@1 𻿵2 ÿ÷âþ½è@2 𻿵3 ÿ÷Øþ½è@3 ð »¿µ4 ÿ÷Îþ½è@4 𻿵5 ÿ÷Äþÿ÷>ùÿ÷Fùˆ±ÿ÷ïù0¹ÿ÷Vù½è@5 ÿ÷¡¾ ÿ÷Bú½è@5 ÿ÷™¾ ÿ÷Èù½è@5 ÿ÷‘¾¿KhhhÛüÔpG¿KhhhÛüÕpG¿KhSø h#ð`pG¿KhSø hCð`pG¿KöDKh“BÐKöŒ“BÐpGKJ`pGKJ`pG¿¼)ˆ&"K`Z`š`Ú`aZapG¿ KöD Kh“B ÐKöŒ“BÐpG K H +I +J˜aÙabpGKH I J˜aÙabpG¿¼ `)())à)¨)˜) +Jp´jëAëÁmhTø1›h-hÔÐPf`¥``p¼ pG¿ Kp´Ûi„ˆEyYk˜iÚiÄóÁŒ@Åó@$ê‘@hXh!CÅó€!ê‚@žhÜh +CÅóÀi"ê @C1±[iÅó@ ê(Cp¼pG Jy‘ip´Êj hHhð”@Ãó€$êiMi‚@"CÃóÀŒh"ê¨@ÉhCÃó ê‹@Cp¼pG Kë@jëRø0 [h`pG¿ KjëÀChhðpG¿  +Kj“è hhJ@’Ð pGÚh™h hhX@ð¿ pG¿ µDh‰ð¡üÿ÷Yý x˜!¿ðOô€0¿$ÿ÷Uý€ ÿ÷Xý€! Dÿ÷NýKh,нðSùð£ÿ Fð„ÿ½è@ ð¿¿œ8µ7K7JhFëƒëƒ›|Dh+YÑ(‰ðhüàˆÀóðû h.K@³ÀóOðÝú Fÿ÷.ÿF Fÿ÷Xÿ!ÿ÷ÿ!(Fÿ÷ ÿðùðùðÍý ðHÿðbÿ#xÛÕKx+³þçFöu ð¹úÚçð¢úKöDKh“BÐKöŒ“BêÑ ÿ÷]ÿ(åÑJ hCð`ÿ÷{þ ÿ÷bþ Kx+Ùѽè8@ ð¿ð›û¢çKh+ßÑÉ翜þÿ¨¼ áD´8µ"K"JhFëƒëƒ›|Dh‹»(‰ðëû#xÛ(ÕàˆÀóð…ú hK@Ó±ÀóOð]ú Fÿ÷®þF Fÿ÷Øþ!ÿ÷þ!(Fÿ÷‹þðQý ðÌþ Kx[±þçFöu ðBúãçð+úÓçðFûÊç ½è8@𸾜þÿ¨8µ!K!JhFëƒëƒ›|Dhs»(‰ðû#xÛ%ÕàˆÀóð7ú hK@»±ÀóOðú Fÿ÷`þF Fÿ÷Šþ!ÿ÷Aþ!(Fÿ÷=þðý Kx[±þçFöu ð÷ùæçðàùÖçðûúÍç ½è8@ðm¾¿œþÿ¨8µKJhFëƒëƒ›|DhS»(‰ðQûàˆÀóðîù hK@˱ÀóOðÆù Fÿ÷þF Fÿ÷Aþ!ÿ÷øý!(Fÿ÷ôý ð7þ Kx±þç8½Föu ð¬ùäçð³úÑçœþÿ¨µCh؈Àóð¹ù½è@ ð¾8µF lhð ý(‰ð ûàˆÀóð¦ù Fÿ÷×ýF Fÿ÷þ!ÿ÷¸ý(F!ÿ÷´ý#yð+Ð ð„ÿ½è8@ ðí½¿pG¿pµFþ÷Jþ(EÐ(M)L+hëƒëƒÛh+;ИG0Fþ÷ÜþkhxÛÔðDùh‰ð«ú+hëƒëƒ›|C» ðCÿ$ Fÿ÷û F4ÿ÷­û4,öÑKöŒJhšBÑ Fÿ÷Žû Fÿ÷Ÿûþ÷_ÿðßø ÿ÷pû5 ÿ÷mû½èp@ ð¿þçðGú+hëƒëƒ£|+ÏÑË眼pG¿KöDKµh“B!ÐKöŒ“B!Ðÿ÷»ýF ÿ÷ý ÿ÷šý ðýð“ýð5üðAÿð+ÿ Fþ÷dþð ù½è@ ðo½Kh+ÝÐ ÿ÷¨ü ÿ÷‘üÖç¼´µÿ÷ýF ÿ÷oý ÿ÷lý ðSýð üðÿ Fþ÷:þðvù½è@ ðE½¿µÿ÷qýF ÿ÷Sý ÿ÷Pý ð7ýðíû Fþ÷ þ@¿½è@ðY¹¿µÿ÷YýF ÿ÷;ý ÿ÷8ýðÒþð8ý Fþ÷ þðEù½è@ ð½µð=ù½è@ ð ½µÿ÷9ýF ÿ÷ý ÿ÷ýðýð°þ Fþ÷éýð%ù ðöü½è@ 𠼿KFhAð€q`h›üÔpG$@ßDKFh!ð€q`h›üÕpG$@ßD"µK`Z`ÿ÷Eü½è@𠼿œ KHhIµJÃó4` `h JÃó#`ðHüðþýÿ÷4üðüû½è@ÿ÷¼áD¼´@áD¸J hCô3`pG¿páDJ h#ô3`pG¿páDJh C`pG¿páDOôqKJ`h C`pG¿ ßDßDJh#ôs`pGßD8µIKñˆt`d#h+,Ñch+/Ñ#j+2Ñ#i+5Ñci+8Ñ£i+;Ñ£h+>Ñãh+AÑãi+DÑKöŒ9M*hšBGУj+dÑ#k+]Ñãj+MÑKöŒ*hšBPÐ8½! ÿ÷óùch+ÏÐ( ÿ÷íù#j+ÌÐ3 ÿ÷çù#i+ÉÐ- ÿ÷áùci+ÆÐ. ÿ÷Ûù£i+ÃÐ/ ÿ÷Õù£h+ÀÐ* ÿ÷Ïùãh+½Ð, ÿ÷Éùãi+ºÐ2 ÿ÷ÃùKöŒM*hšB·Ñck+´Ð ÿ÷·ùOôqKJ`h C`¨ç0 ÿ÷«ùKöŒ*hšB®Ñ½è8@4 ÿ÷¡¹$ ÿ÷žùç# ÿ÷šù–ç¿D¼ ßDßD"8µ"K! `ÿ÷ù( ÿ÷šù) ÿ÷—ù* ÿ÷”ù+ ÿ÷‘ù, ÿ÷Žù- ÿ÷‹ù. ÿ÷ˆù/ ÿ÷…ù0 ÿ÷‚ù1 ÿ÷ù2 ÿ÷|ù3 ÿ÷yù# ÿ÷vù$ ÿ÷sùKöŒ M,hœBÐ8½ J h#ôs`ÿ÷dù+h£Bóѽè8@4 ÿ÷\¹D¼ßDµðÛùð%ùð½ù Kx ±ÿ÷ŠþðŒù ÿ÷Áú ðtú ðqú ðnú ðkú½è@ ðfº˜µ ðzú ðwú ðtú ðqú ðnú ÿ÷úðIù ð¼üðlù KxC¹ðùøKöDJhšBнÿ÷Vþóç½è@𛹿˜¼8µOöÿs˜BÐF ð¿üF ð•üõ ð?ûF ± F8½ ðœü F8½$ F8½¿ÿ÷à¿Kx±æpG¿˜Kx±æpG¿˜KöŒIð´hINMLH h6hK-h$hh‘B`^``Ü`aÑ I J hhYašað¼pG¿áD¼áD áD@áDDáDHHáDLáDøµÿ÷ËÿKh#¹ Kh;+ Ù J K O NMLIH:`2`+`#``ø½ JhCð€S`ëç¿´°ð?‹àÿ@áDDáDáDáD áD‹  ÿáD8µÿ÷•ÿMKLHIJ+`#`` `h+ Ð+Ð8½Oð`oðbIK``8½%Oðÿ0 JhCô€s`Dø<\Aø@ 8½¿@áDð?DáDHáDLáD°áD áD`áDKöDKh“BÐKöŒ“BÐpGÿ÷·¿ÿ÷¿¿¼KöDJð´h™BÐKöŒKHh]hLŸh`Þh%`iM‡`.`dhŠBÑšiXiIK``ð¼pGKh+àÑ Kh;+ÛØ I h#ð€S `Õ翼HáDáD@áDHáDLáD´°áD ! KF``hAð@`hðAð``h›üÕpG¿ áDKh+¿"KJK`pG° áDµ Kx¹½ ðFû#IJ h ‹@`½è@ðM»¿™¬”qàDµ Kx¹½ ð,û#IJ h ‹@`½è@ð3»¿™¬qàDKh+ÑJhCðC`pG°áDKh+ÑJh#ðC`pG°áD Jð´h,:Ð#hY7ÐPhÃëÃPø3PëÃ.hJh2C*`Pø3PJi.h2C*`Pø3`hÍh2h=C*C2`Pø3P +i.h2C*`Pø3PŽi*h"ê*`Pø3 Íih#ê`KjŠj jC hBüÑTø?ZÈÑð¼pGd#Jðµh.@Ð3hY=жFUhÃëÃUø4 ëÄhÃi C`j‚j hBüÐUø4 ƒih C`jBj hBüÐUø4i +h^ø?"ê +`Uø4pÁh†h:h1C"ê:`Uø4Gi +h"ê +`Uø4@h +h"ê +`ZÃÑð½¿d KÀëÀZh´ëÁÔjë€ h ðAð!`k˜`h+üÑ]øKpGd +KÀëÀZh뀛hëÁÐjð)`ÐpGkh+üÐpG¿dKÀëÀ[hëÀCkhÀ²pGd"Kš`Ú`aZašapGdKöD Kh“B +ÐKöŒ“BÐpG K I +JY``pG JK IhY`*ñÐJ`pG¿¼d' '´p%`%µ K„° ñËéLª#h+´¿ÃóAsÃóSëƒSø °½¿ü&@áDKöD Kh“B ÐKöŒ“BÐpGKH I JƒèpGKHI JƒèpG¿¼€d(<(4(Ø(¬(¤(K(hOðSø! h#ð ¿CðCð`pG¿€8µ F hJ ÐFà8¹(Fÿ÷áÿTøK÷Ñ8½8½ ûç¿KhSø 8±hð ñ°ú€ð@ pG€KhSø h#ðCð`pG¿€KhSø h#ðCð`pG¿€K Yh»ç€K Yhµç€K ™h¯ç€-éðOOð FFhJiKÒø€ßø°á³øÀfMgHgI¾øà(ð-ˆ‡°ˆ ˆ`úŒò£ø’úŽò’ª²sxø{’‚²’вGê'’ÿ÷%ÿFHFÿ÷áþ-¸¿5/¿;F#­•ûóóëÓrRQñ€ÿ)@ó€ÿ!Oô‚r›;ñ€ÿ+@ó…€ÿ#%OôBOöÿwBH€BM€8+€ øˆ>KAI€€€²x*DМFHòkßøø ßøøŽFl09Oôzsà;PÐ ˆíúÔ®øpfxUªø`’²¦©ø 2Fí²ë¬ø°#D®øpøKšB€úÑ5Oôzrtà[Ô:Ð ˆ›²ðöÐOöÿrOðÿ0 K€°½èð®øpr]*ÄÑ ½ø PKI€J €½øPL€½øP%€½ø@€½ø0!ø„ÿ ½ŒBooted version 0x%x of CM3 PM Firmware. $¤$¬$´$¼$[%08x]%s: ERR WARN INFO DEBUG0123456789abcdefghijklmnopqrstuvwxyz(null)0x + ÿÿÿÿ ÿÿÿÿLàD(àDÐàDàD¸àDäàDààDÜàDdàD àD`àDàD,àDÿÿÿÿáD€  áDŒàDpàDœàDáD€  áD˜àDHàDTàDáD€  áD”àD4àD@àDˆàD àD,àDàD\àDhàDàDàD + ÿÿÿÿ ÿÿÿÿ8*ßD ßD0ßDh+ßD@+ßD(ŠßD ˆßD@ˆßD¨ˆßD ˆßD ŒßD ƒßDPˆßD8ßD ”ßDKÀ]¨aeÿÿÿÿáD€  áDà-ßDä-ßDì-ßDáD€  áD .ßD$.ßD,.ßDáD€  áD -ßD¤-ßD¬-ßD`-ßDd-ßDl-ßD -ßD$-ßD,-ßDÿÿÿÿ  ÿÿÿÿ)ßDƒßD“ßD’ßDßD‹ßDˆßDŠßDŒßDßD”ßD+ßDÿÿÿÿ   + ÿÿÿÿàDPàDDàD@àD àDàDàDàDàDHàD,àDàDàDßDßDßDßD  +  + @ßD@ßDàDàD àD àD €€@GNUe‚‰â½geÛWÓ…;°¨q2W¸I…¸I…¬ ¥‰¬ ¥‰”ˆ¡ù”ˆ¡ù|=1|=1ÅpÕapÕaXq¡-dY‘€ ƒ ëÔ€üÿêÔƒüßêÔ…üßêÔ€üßêÔ…üßêÔ€üßlog_buf \ No newline at end of file diff -Naur --no-dereference a/firmware/am335x-pm-firmware.elf b/firmware/am335x-pm-firmware.elf --- a/firmware/am335x-pm-firmware.elf 1969-12-31 19:00:00.000000000 -0500 +++ b/firmware/am335x-pm-firmware.elf 2024-07-07 20:37:34.676306709 -0400 @@ -0,0 +1,388 @@ +ELF(4M4 (4*4*4*ÀQåtd™ é í ñ õ ù ý   • • • • • • • • • • • • • • • • • É • • • • • • • • • • • • • • å • E Y ± • • • Å Ù í )=Qey¡µÉJh CôÉs`pG0áDð<¹KD›hpG¿ÊD8K D›`pG¿ÊD8KJh›²`pG,áDœKhZ* ØJëƒëƒ˜h0¿ pG pG¿œ#J$Khhð´#Mð"J/`"NÃóÀp!L"HÃó!JÃó€%7`ÃóÀ#p%pHhJh `Sh ÐHI€è0P`˜D냛hHð¼GiðÑI h)ИIÄë„dh±T`éçI˜ÄQø$@,öÑáç<áD8áD°™¬˜¨0áD4áDœ¸Oðÿ3´HLIJ#``]øK ``pG4áD0áD8áD<áDJh CôÉs`pG0áDJh›²Cê@`pG¿,áDJh#ðÿC`pG¿@áDKJhëƒëƒ|pG¿œKJhëƒëƒX|pG¿œµð×ü$ðÜü F4ð¨ü4,ùÑKöŒJhšBÐÿ÷œÿðrøðòùðþù ðü5 ð~üÿ÷¤ÿ ðøOôÉrI ð½ø ½ Fð‚üà翼X$µÿ÷Çÿ0¿ý翵ÿ÷‘ÿ@¿½¿µÿ÷‹ÿ@¿" ð}ü½è@" ðP¼µÿ÷ÿ" ðrü½è@" ðE¼¿µ$ FðSü F4ðcü4,öÑKöŒJhšBÐðøð›ù ð,ü5 ð)ü ðÜÿ ÿ÷Uÿ@¿½ Fð2ü FðCüæç¼pG¿pG¿pG¿pG¿pG¿2±FɲDø“BûÑpG¿xC!±ø+*úÑFpGøµ LF!h +MI±K«B#`¿Kp¿#` ø½Oê8Fÿ÷×ÿ9Fîç¿ 8µFx8±%Fÿ÷Ûÿø(ùÑ`8½¿øµFxx±i±Fû«FD˜“ðøD + ÿ÷—ÿ…óˆ F°½è0@°pG¿T€$”$K`pG¿T-éðO$F‹F'F‘°®Feà(tÐÿ÷rÿ¶FvFø ë%(!FòÑ/òÑ;FOð :Fžø— ñ# u¼ñWòèßèðÿææææææ æ%.........ææææææææææææææææææææææææææææææPææææææææææUËæææÞË^æcæm|Žæ“Æ\ææ÷æú F°½èð + Þ#ô€iñÚÚ@ñé ñ#ðÓø ñ ô€oкñ¼¿IôyÊñ + ô€^#rFø0ŽF ñSF”FàfF³ûðòû3·Lã\Y±£ña ¼ñŒ¿Oð Oð £ë Û²´F ø;F*åÑ«óœ“ô€sqF“ +кñЛ+ðï›+ðïôs“ðE›ð€ ñ“ð‹- Lÿ÷“þ›S±ºñЛ+ðù›+ð¹ñðM0xP±ÿ÷~þø 4(øÑ¹ñ?ôü®›+?ôø®š£ë ¹ñ÷ñ® ñÿ6>@Fÿ÷dþsùÑLDææ cçpxCð@.F÷æpxCô€s.Fòæÿ÷Qþ4ÕæñcÛø ñ (Àò¸px.FàæpxCô€c.FÛæpxCð€.FÖæpxCôc.FÑæôj@ðcpxOð0.FÈæ–ø ñ0 ©ñ0 (˜¿ôjò¹€.F ëŒ ëL øŸ¬ñ0 ©ñ0 (óÙHFºñ ¿eFbF•¦æ Cô€SçÛø ñ4ÿ÷ûý³FæpxCð.F“æ˜@ñ3#ðpxCð.F‰æÞñì€Ø@ñC"FÛøãÁé# ñ aæ Þæš*@ðCô€s Ûø #ô€i ñ ßæpxCð.FcæÛø ñ‘¹ñð&HF“’ÿ÷¬ýš›ÕB’FØF‚F™¡ë"êâvñÀñÿ;>± ñÿ;@Fÿ÷ý»ñÿ?÷ÑQFHFÿ÷Âý4DDÝø°æpxCð .F+æÞCô€iñ’€Ú@ñÓ€ + ñ#ðñ Óø æ@ñˆ€#ðCð,ç¥ëpFÿ÷˜ý'DïåHÿ÷„ýDÝæHF.FôjOç¿Ä$ô$ð€ AѸñ0Лƒ±š›+“ Ýñÿ9 ñÿ9@Fÿ÷Fý¹ñÿ?÷Ñ›D›+@ðÓ€›+±ºñÐOð ¦æ›ƒ±š›+“ Ýñÿ9 ñÿ9@Fÿ÷'ý¹ñÿ?÷Ñ›D0x(?ô¥­Oð šæÛø  ñ +æ›+?ô®ºñ?ô‹®}æ¸ñ0´ÑpæžëÔšéÔ^çÔ{Õ»ø  ñ æÛø0 ñ `{å + Ûø  ñ æpxCð.FˆåpxÛø .F ñ åHFQFÿ÷ +ýñÿ9D>± ñÿ9@Fÿ÷Õü¹ñÿ?÷Ñ4DÝø°Tå#ô€søævx ñ0 ¦ñ0 (±Fö¥®0FbF.F]åpxCð.FXå›3“æ›3“ æž¹Ô˜·ÔZµÔOð +*Õ»ù  ñ ·å™£ÔZ¡Ô'ÕÛø0 ñ €å ßøXÜæ0 4ÿ÷üæpxžƒð€vB–.F#å^õg¯›ø  ñ ’åZõ^¯›ø  ñ ‰åXõu¯Ûø0 ñ pðä!FOð Îåì$´µƒ°«Sø F“ÿ÷Úü°]øë°pG¿þç¿JKšB ÒÑCD H!ð1FDSøƒBBøùÑH IOðˆB¸¿@ø+úÛÿ÷Ç»¿Ä4*Àþç¿þç¿þç¿þç¿þç¿þç¿þç¿þ翵 ð6ú¹þç ½ñŠA¡õá`pGñŠ@ õáhpG#ABððX¿JB(¸¿0@€ñ`@“@õa@`pG#ABððX¿JB(úó¸¿0J@Bø 0pG€áà#ABððX¿JB(úó¸¿0J@Bø 0pG€âàJhCð`pGíàJhCð`pGíൠÿ÷Äÿ ðùûKh`½¿ ßDµ ÿ÷¶ÿÿ÷0úÿ÷8ú¨±ÿ÷áúFH¹ÿ÷ëú°¹ÿ÷Dú½è@ ÿ÷¿ ÿ÷0û½è@ ÿ÷‡¿ ÿ÷¶ú½è@ ÿ÷¿ Fÿ÷,û½è@ ÿ÷w¿¿µ! ÿ÷†ÿ½è@! 𹻿µ$ Fÿ÷{ÿ F4ÿ÷‹ÿ4,öÑKöŒ JhšBнè@ÿ÷º Fÿ÷hÿ Fÿ÷yÿ½è@ÿ÷ý¹¿¼µ# ÿ÷Zÿ½è@# 𻿵$ ÿ÷Pÿ½è@$ ðƒ»¿µ( ÿ÷Fÿ½è@( ðy»¿µ) ÿ÷<ÿ½è@) ðo»¿µ* ÿ÷2ÿ½è@* ðe»¿µ+ ÿ÷(ÿ½è@+ ð[»¿µ, ÿ÷ÿ½è@, ðQ»¿µ- ÿ÷ÿ½è@- ðG»¿µ. ÿ÷ +ÿ½è@. ð=»¿µ/ ÿ÷ÿ½è@/ ð3»¿µ0 ÿ÷öþ½è@0 ð)»¿µ1 ÿ÷ìþ½è@1 𻿵2 ÿ÷âþ½è@2 𻿵3 ÿ÷Øþ½è@3 ð »¿µ4 ÿ÷Îþ½è@4 𻿵5 ÿ÷Äþÿ÷>ùÿ÷Fùˆ±ÿ÷ïù0¹ÿ÷Vù½è@5 ÿ÷¡¾ ÿ÷Bú½è@5 ÿ÷™¾ ÿ÷Èù½è@5 ÿ÷‘¾¿KhhhÛüÔpG¿KhhhÛüÕpG¿KhSø h#ð`pG¿KhSø hCð`pG¿KöDKh“BÐKöŒ“BÐpGKJ`pGKJ`pG¿¼)ˆ&"K`Z`š`Ú`aZapG¿ KöD Kh“B ÐKöŒ“BÐpG K H +I +J˜aÙabpGKH I J˜aÙabpG¿¼ `)())à)¨)˜) +Jp´jëAëÁmhTø1›h-hÔÐPf`¥``p¼ pG¿ Kp´Ûi„ˆEyYk˜iÚiÄóÁŒ@Åó@$ê‘@hXh!CÅó€!ê‚@žhÜh +CÅóÀi"ê @C1±[iÅó@ ê(Cp¼pG Jy‘ip´Êj hHhð”@Ãó€$êiMi‚@"CÃóÀŒh"ê¨@ÉhCÃó ê‹@Cp¼pG Kë@jëRø0 [h`pG¿ KjëÀChhðpG¿  +Kj“è hhJ@’Ð pGÚh™h hhX@ð¿ pG¿ µDh‰ð¡üÿ÷Yý x˜!¿ðOô€0¿$ÿ÷Uý€ ÿ÷Xý€! Dÿ÷NýKh,нðSùð£ÿ Fð„ÿ½è@ ð¿¿œ8µ7K7JhFëƒëƒ›|Dh+YÑ(‰ðhüàˆÀóðû h.K@³ÀóOðÝú Fÿ÷.ÿF Fÿ÷Xÿ!ÿ÷ÿ!(Fÿ÷ ÿðùðùðÍý ðHÿðbÿ#xÛÕKx+³þçFöu ð¹úÚçð¢úKöDKh“BÐKöŒ“BêÑ ÿ÷]ÿ(åÑJ hCð`ÿ÷{þ ÿ÷bþ Kx+Ùѽè8@ ð¿ð›û¢çKh+ßÑÉ翜þÿ¨¼ áD´8µ"K"JhFëƒëƒ›|Dh‹»(‰ðëû#xÛ(ÕàˆÀóð…ú hK@Ó±ÀóOð]ú Fÿ÷®þF Fÿ÷Øþ!ÿ÷þ!(Fÿ÷‹þðQý ðÌþ Kx[±þçFöu ðBúãçð+úÓçðFûÊç ½è8@𸾜þÿ¨8µ!K!JhFëƒëƒ›|Dhs»(‰ðû#xÛ%ÕàˆÀóð7ú hK@»±ÀóOðú Fÿ÷`þF Fÿ÷Šþ!ÿ÷Aþ!(Fÿ÷=þðý Kx[±þçFöu ð÷ùæçðàùÖçðûúÍç ½è8@ðm¾¿œþÿ¨8µKJhFëƒëƒ›|DhS»(‰ðQûàˆÀóðîù hK@˱ÀóOðÆù Fÿ÷þF Fÿ÷Aþ!ÿ÷øý!(Fÿ÷ôý ð7þ Kx±þç8½Föu ð¬ùäçð³úÑçœþÿ¨µCh؈Àóð¹ù½è@ ð¾8µF lhð ý(‰ð ûàˆÀóð¦ù Fÿ÷×ýF Fÿ÷þ!ÿ÷¸ý(F!ÿ÷´ý#yð+Ð ð„ÿ½è8@ ðí½¿pG¿pµFþ÷Jþ(EÐ(M)L+hëƒëƒÛh+;ИG0Fþ÷ÜþkhxÛÔðDùh‰ð«ú+hëƒëƒ›|C» ðCÿ$ Fÿ÷û F4ÿ÷­û4,öÑKöŒJhšBÑ Fÿ÷Žû Fÿ÷Ÿûþ÷_ÿðßø ÿ÷pû5 ÿ÷mû½èp@ ð¿þçðGú+hëƒëƒ£|+ÏÑË眼pG¿KöDKµh“B!ÐKöŒ“B!Ðÿ÷»ýF ÿ÷ý ÿ÷šý ðýð“ýð5üðAÿð+ÿ Fþ÷dþð ù½è@ ðo½Kh+ÝÐ ÿ÷¨ü ÿ÷‘üÖç¼´µÿ÷ýF ÿ÷oý ÿ÷lý ðSýð üðÿ Fþ÷:þðvù½è@ ðE½¿µÿ÷qýF ÿ÷Sý ÿ÷Pý ð7ýðíû Fþ÷ þ@¿½è@ðY¹¿µÿ÷YýF ÿ÷;ý ÿ÷8ýðÒþð8ý Fþ÷ þðEù½è@ ð½µð=ù½è@ ð ½µÿ÷9ýF ÿ÷ý ÿ÷ýðýð°þ Fþ÷éýð%ù ðöü½è@ 𠼿KFhAð€q`h›üÔpG$@ßDKFh!ð€q`h›üÕpG$@ßD"µK`Z`ÿ÷Eü½è@𠼿œ KHhIµJÃó4` `h JÃó#`ðHüðþýÿ÷4üðüû½è@ÿ÷¼áD¼´@áD¸J hCô3`pG¿páDJ h#ô3`pG¿páDJh C`pG¿páDOôqKJ`h C`pG¿ ßDßDJh#ôs`pGßD8µIKñˆt`d#h+,Ñch+/Ñ#j+2Ñ#i+5Ñci+8Ñ£i+;Ñ£h+>Ñãh+AÑãi+DÑKöŒ9M*hšBGУj+dÑ#k+]Ñãj+MÑKöŒ*hšBPÐ8½! ÿ÷óùch+ÏÐ( ÿ÷íù#j+ÌÐ3 ÿ÷çù#i+ÉÐ- ÿ÷áùci+ÆÐ. ÿ÷Ûù£i+ÃÐ/ ÿ÷Õù£h+ÀÐ* ÿ÷Ïùãh+½Ð, ÿ÷Éùãi+ºÐ2 ÿ÷ÃùKöŒM*hšB·Ñck+´Ð ÿ÷·ùOôqKJ`h C`¨ç0 ÿ÷«ùKöŒ*hšB®Ñ½è8@4 ÿ÷¡¹$ ÿ÷žùç# ÿ÷šù–ç¿D¼ ßDßD"8µ"K! `ÿ÷ù( ÿ÷šù) ÿ÷—ù* ÿ÷”ù+ ÿ÷‘ù, ÿ÷Žù- ÿ÷‹ù. ÿ÷ˆù/ ÿ÷…ù0 ÿ÷‚ù1 ÿ÷ù2 ÿ÷|ù3 ÿ÷yù# ÿ÷vù$ ÿ÷sùKöŒ M,hœBÐ8½ J h#ôs`ÿ÷dù+h£Bóѽè8@4 ÿ÷\¹D¼ßDµðÛùð%ùð½ù Kx ±ÿ÷ŠþðŒù ÿ÷Áú ðtú ðqú ðnú ðkú½è@ ðfº˜µ ðzú ðwú ðtú ðqú ðnú ÿ÷úðIù ð¼üðlù KxC¹ðùøKöDJhšBнÿ÷Vþóç½è@𛹿˜¼8µOöÿs˜BÐF ð¿üF ð•üõ ð?ûF ± F8½ ðœü F8½$ F8½¿ÿ÷à¿Kx±æpG¿˜Kx±æpG¿˜KöŒIð´hINMLH h6hK-h$hh‘B`^``Ü`aÑ I J hhYašað¼pG¿áD¼áD áD@áDDáDHHáDLáDøµÿ÷ËÿKh#¹ Kh;+ Ù J K O NMLIH:`2`+`#``ø½ JhCð€S`ëç¿´°ð?‹àÿ@áDDáDáDáD áD‹  ÿáD8µÿ÷•ÿMKLHIJ+`#`` `h+ Ð+Ð8½Oð`oðbIK``8½%Oðÿ0 JhCô€s`Dø<\Aø@ 8½¿@áDð?DáDHáDLáD°áD áD`áDKöDKh“BÐKöŒ“BÐpGÿ÷·¿ÿ÷¿¿¼KöDJð´h™BÐKöŒKHh]hLŸh`Þh%`iM‡`.`dhŠBÑšiXiIK``ð¼pGKh+àÑ Kh;+ÛØ I h#ð€S `Õ翼HáDáD@áDHáDLáD´°áD ! KF``hAð@`hðAð``h›üÕpG¿ áDKh+¿"KJK`pG° áDµ Kx¹½ ðFû#IJ h ‹@`½è@ðM»¿™¬”qàDµ Kx¹½ ð,û#IJ h ‹@`½è@ð3»¿™¬qàDKh+ÑJhCðC`pG°áDKh+ÑJh#ðC`pG°áD Jð´h,:Ð#hY7ÐPhÃëÃPø3PëÃ.hJh2C*`Pø3PJi.h2C*`Pø3`hÍh2h=C*C2`Pø3P +i.h2C*`Pø3PŽi*h"ê*`Pø3 Íih#ê`KjŠj jC hBüÑTø?ZÈÑð¼pGd#Jðµh.@Ð3hY=жFUhÃëÃUø4 ëÄhÃi C`j‚j hBüÐUø4 ƒih C`jBj hBüÐUø4i +h^ø?"ê +`Uø4pÁh†h:h1C"ê:`Uø4Gi +h"ê +`Uø4@h +h"ê +`ZÃÑð½¿d KÀëÀZh´ëÁÔjë€ h ðAð!`k˜`h+üÑ]øKpGd +KÀëÀZh뀛hëÁÐjð)`ÐpGkh+üÐpG¿dKÀëÀ[hëÀCkhÀ²pGd"Kš`Ú`aZašapGdKöD Kh“B +ÐKöŒ“BÐpG K I +JY``pG JK IhY`*ñÐJ`pG¿¼d' '´p%`%µ K„° ñËéLª#h+´¿ÃóAsÃóSëƒSø °½¿ü&@áDKöD Kh“B ÐKöŒ“BÐpGKH I JƒèpGKHI JƒèpG¿¼€d(<(4(Ø(¬(¤(K(hOðSø! h#ð ¿CðCð`pG¿€8µ F hJ ÐFà8¹(Fÿ÷áÿTøK÷Ñ8½8½ ûç¿KhSø 8±hð ñ°ú€ð@ pG€KhSø h#ðCð`pG¿€KhSø h#ðCð`pG¿€K Yh»ç€K Yhµç€K ™h¯ç€-éðOOð FFhJiKÒø€ßø°á³øÀfMgHgI¾øà(ð-ˆ‡°ˆ ˆ`úŒò£ø’úŽò’ª²sxø{’‚²’вGê'’ÿ÷%ÿFHFÿ÷áþ-¸¿5/¿;F#­•ûóóëÓrRQñ€ÿ)@ó€ÿ!Oô‚r›;ñ€ÿ+@ó…€ÿ#%OôBOöÿwBH€BM€8+€ øˆ>KAI€€€²x*DМFHòkßøø ßøøŽFl09Oôzsà;PÐ ˆíúÔ®øpfxUªø`’²¦©ø 2Fí²ë¬ø°#D®øpøKšB€úÑ5Oôzrtà[Ô:Ð ˆ›²ðöÐOöÿrOðÿ0 K€°½èð®øpr]*ÄÑ ½ø PKI€J €½øPL€½øP%€½ø@€½ø0!ø„ÿ ½ŒBooted version 0x%x of CM3 PM Firmware. $¤$¬$´$¼$[%08x]%s: ERR WARN INFO DEBUG0123456789abcdefghijklmnopqrstuvwxyz(null)0x + ÿÿÿÿ ÿÿÿÿLàD(àDÐàDàD¸àDäàDààDÜàDdàD àD`àDàD,àDÿÿÿÿáD€  áDŒàDpàDœàDáD€  áD˜àDHàDTàDáD€  áD”àD4àD@àDˆàD àD,àDàD\àDhàDàDàD + ÿÿÿÿ ÿÿÿÿ8*ßD ßD0ßDh+ßD@+ßD(ŠßD ˆßD@ˆßD¨ˆßD ˆßD ŒßD ƒßDPˆßD8ßD ”ßDKÀ]¨aeÿÿÿÿáD€  áDà-ßDä-ßDì-ßDáD€  áD .ßD$.ßD,.ßDáD€  áD -ßD¤-ßD¬-ßD`-ßDd-ßDl-ßD -ßD$-ßD,-ßDÿÿÿÿ  ÿÿÿÿ)ßDƒßD“ßD’ßDßD‹ßDˆßDŠßDŒßDßD”ßD+ßDÿÿÿÿ   + ÿÿÿÿàDPàDDàD@àD àDàDàDàDàDHàD,àDàDàDßDßDßDßD  +  + @ßD@ßDàDàD àD àD €€@GNUe‚‰â½geÛWÓ…;°¨q2W¸I…¸I…¬ ¥‰¬ ¥‰”ˆ¡ù”ˆ¡ù|=1|=1ÅpÕapÕaXq¡-dY‘€ ƒ ëÔ€üÿêÔƒüßêÔ…üßêÔ€üßêÔ…üßêÔ€üßlog_bufЇ ö‡Üá0*PP%`GP9Î! Æolz¯…@5 ] N  [xSíMêÕNP QçúRPgSPCVPÿXPYPÍZPO[P`\P¦^P)_P0`PzaPßbPecPìePTjP p +³qP +crP H m6 nê rtcoÎ rawsç vs +EwW +4xs +Cyy +–zy +ß}á +~s +Ìs +£€ò +Mù +¸‚% +íƒ% +h„%ìì6áøš‡Preg‡QEïPreg®×]ïÙP”œâ4ìPE!QÿÛ½"$Þ9'.;`$,œ4$ìN0‚ ÿ0œ-o "@œO!.P!9Q"0•Pœ~#ÿP˜$õŸ%d,œ"©ÄœZ%id«Z¤³¬Pc­Pj®Pq¯P&ÿ±ÿÑ&ÿ’0¶'&ÿ´H½1'&ÿÄ`¾J'(ò)Pœ*int"½ÏT,œ &"TxÑœ9å.ù&"Z˜ÒÂ9."&"^°Óè97.K#"`ÈÔ9`.t E€œe+QSÿ€ÛB‰"ŒÞ9.±"€á”œØæáZÄ,ïãPåÿ”åµ"ž +è9.+"먜KjëZ>,ïíP_ÿ¨ï(}"² +ò9‘.¥$°ú%¼œ$åÿ%Øœ-A.§7P/X6œ0€²1²~/q)¢/öZ°/Ô%™/Z¬/º%˜/Â%¨.Ç.‰.0.O.x.L.Ö.9.42jjFÀ‡ ‡àU*`J£intÿØ0aHm3,VÑ·verhnum hT!·Ÿ"ÎhÇ Ç~hÝ +Ç%«&h4'V +ÇÀ,*Mda+hlen,hT-h .M V] ÇÍD1š»2zŸ4š*5Ýà6hª Ç ÍHôlœ‘ iH¸ úÐ ÛæöPt ñ ü $ (.-PO4AP5 8(>3]P0J>€P3QX$R +’TæPt­GH` +œ´ fªv5,÷9]Ĉˆ+àà,²²)½½’}}²²9¨¨:88(®®‘ÃÖ– + é‡ ú‡l–·*`ê±±UJáe“€;0¬ · +‰ ž  $×intÃÐæ± ¸l +œþ +Äî rÖ PóP óxœu汸zP +Ä0 ~Ö PóP†ád P"ì P" Â&œÓæ&±Q–Ö® PóPœá P"¦ì P" j/¨Xœºi1±r¸ä +N! +Ä´ êÖ P0²÷5 PtºáI PtÎÒ Øìn POÞì‚ P5ä• P;ô÷© Pt úá PtïRœv5,€€œqq*88(²²)}}²²9¥¥(91‡ ‡z2!%œßf‡ O‡ø¾H0[g‹œ‹s‹PcÈn%écs”  int +šQ` %(œ×s ×'ret %R +Ý šbý‡ ‚‡<†H0[n ~<<œ~c ~‚f\PwRuwint¬~xœÆstrƶ ™Æá +†> ÓQ ̦~”.œ(strÆ Ÿ%s ™Æ  +®>±9 ?H‘?v?gg¯Ü‡ ؇Äx“[–íÄlœílvlí¾fmtô‘t¼%øretí  ap‘d +ø‘ P”$ Qt R óP2$€$" +œÝ P‘\ Q‘` § P: intQú  )0 œBlvl)íPÌíT÷íôtt~茀$dœœïïnno‡ Q ‡<V[á>*^^%`1 R——padRžqR— retT— +intQ BÿÿL BÿnumB^»B—n B C3 pEÿ cEž ž — ïZ—<8œ‡ fmtZ‡) apZ’–L `«‘´pa‡´‚ a‡chb—nb—& +numc^} +»d—+ tmpd—ï h d—£ g e—Ñ b fž¬9 g3Îreth—¼i%¶Š y%  +* > ÷J“ j¥‚R ’áÿÖ4ËLÀaµ ‚RìÏõJehAÔ€]uh‹tFPxeò䀓uò‹ FPxe¢ ,W€Éu¢ ‹° FPxeà 9™€ÿuà ‹î FPxe€ +çÖ€5u‹’ +FPx XF!FóP- @F šF FF!ÐQ"Py! \<PyQz d \!p g\Pô$!€ +\vPyQz" FP0 "ž#©$ ©%&ž»'» ~(œQ—t œ )fmtQ‡‘p*+apS’‘d+retT—Pˆ P‘PQ‘T&0'»$s ;AÄ$" ,nn,``,¦¦,¬¬áO +‡ ¨ ‡” L÷*`š È” œc§˜ Hœ}Á ©}`Ò ©}Ò Ù, ç , È , ò , þ , +Æ¿ ¿E~  Ú \¯­­ª" ‡  +‡è N  +è œ^ +ì œL +ð œ; + ô œ +&ø œ +,ü œp +2 œ, +8 œCQ ‡ p ‡ (¨*`… °°¬ +Q Ý + 9 í +[ ¦ Ç +ø +  +Ž  À f . Ñ +$ int¯ ° œà ; P> +C  œ val,P reg°‹º + ,$ œ; reg °À ™ ™ .5 ‡ Þ ‡0 ˜ 80 (œfÏ fó f$þ mSint`²X (œµÏ fMó fnþ mSq&€ (œöÏ &f—ó (f¸þ )mSˆ1¨ œÖ 3mSà;¸ œÖ =mS»£ ‡ ‡È Fj *`ø È œ= RÐ :oP@Ö EP@int( 'ä ^œ^ì :®PO ð P ô [ ú f  q  | + ‡îPO ’P2 +" ‡PO( 'P1 +2 ‡:PO8 ¨NPt B ‡POJ CD œ˜L :‡P! V EP![ JX Dœ iLáb :ÎPtj ³âPt ‚ |ˆ :ÿPtŽ ³Pt – |l ]œ œW¤ :FP# ® EP#} d° œ‘¸ :€P$  EP$g kÄ œËÌ :ºP( Ö EP(x rØ œà :ôP) ê EP)‰ yì œ?ô :.P* þ EP* €œy:hP+ EP+ ‡œ³:¢P, &EP,9 Ž(œí0:ÜP- :EP-V •<œ'D:P. NEP.E œPœaX:PP/ bEP/, £dœ›l:ŠP0 vEP0Ö ªxœÕ€:ÄP1 ŠEP1£ ±Œœ”:þP2 žEP2´ ¸ œI¨:8P3 ²EP3Å ¿´œƒ¼:rP4 ÆEP4ç ÆÈFœ/Ð:¬P5 ÔP Ø[ Þf ä| +î‡äP5ô’÷P2 +þ‡ P5P1 ‡P5v5,²²)Ž Ž 00—õõ˜°°™ååš›88(ó󀀜ÂÂqq*Q‚ ‡ Ç ‡š + HHÿ Ý `§ œqid%P'!$œ“id!%Pš '8œÂid'%Pval)HSç 1Pœñid1%Pval3HSö ;h8œ  + H v5H 4 ? ) · O ))I‡ y‡9 *`ꢢUJáe“€;0¬ · +‰ ž  $×intÀ¹¹~ $ +PÖ$% ©ëë¹ + +8!% Ûë¹ +^)'ø$ ÿ¼‡ ñ‡ ¨ *` Q0úR,gS,CV,ÿX,Y,ÍZ,O[,`\,¦^,)_,0`,za,ßb,ec,ìe,Tj,C,T§ŽŸ0"ñ•#,ç$,ý%,«&, Ë',¿(,),ÿ*,’+, #,,$m-,(ñ.,,÷81¦¼2,3,<4,45, L6,`7,,8,®9,:, ÿ;,$’<,(#=,,m>,0ñ?,4–B˘C,qD,o üá,º,‡,,. var, +‰, +),Em,S valm, vm,Rg,x valg, vg,Ìa, vala, va,å[, val[, v[,Ît,ç valt, vt,¤U,  valU, vU,ÙO,1 valO, vO,TI,V valI, vI,\z,{ valz, vz,.¤¬¬ pd¤7 À¦, t§, int 1( œ C2¸Xœ‚?,0œ val?,.pd?7M€,@\œî4€înv‚,Â@ „cÝÒSJ8‡¬nc£üJPi"Ñ  .zhˆI> ü†p"B 3Ê,œHœL4îUv,vVœ€‘qvfŠ ™äœnpd™7Pž,œ–pdž7¯l²¬0œ$ à´¬{¶ó‹Ð•ä ÷{.º‹.•S  +¢58; TúQ<W ñm@s ¦!ˈ"ˆ~Â!x #v5,#;#¢W!sÌ$#× Á#²;# W#xý Á|²‡ =‡È *`”ffäIJ¼€int£8"Ï$÷$Y $˜!$ í"$Ç#$1$$'%$­'$ „($$ )$(+$,y,$0‰-$4 92 +2~ m œOp% " dd +2 + eOz`% TvC‡ ͇  @@ÿ Ý `^WW~@tˆ&G¢‡ ì‡HŽj á 0*`G79µ! Æolz¯…@5 ] N  [xSíMÑÕN7 QÎúR7gS7CV7ÿX7Y7ÍZ7O[7`\7¦^7)_70`7za7ßb7ec7ìe7Tj7pï ³q7 cr7 +H m nÑ rtcoµ rawsÎ vZ Ew> 4xZ Cy` –z` + ïß}È ~Z ÌZ £€Ù Mà ¸‚% íƒ% h„%ÓÓ  È ß… cc¬ +Q Ý + 9 í +[ ¦ Ç +ø +  +Ž  À f . Ñ +$ intêcáUJáe“€;0¬ · +‰ ž  $×C7þ§Ž”c9äIJ¼€ 7\ÿ Ý Ý!H\œ)4!Óâ#)>$7QRV"n-ËP@<$Q˜t8ßP€|-óQ€ŠCŽN”YPtžYP? µºP¤üœ©4PÓlâR©Õ‰S7óDT7'ØUc:ÄÎdÞoäz¾Ptì…ÒPtòåQ0úþPuQ1þ›C¦ Y,P1N&oJP +uj,±F¼fP1ZÇyP0`ÒŒP0rYŸP?vÝ Ñ™ œœÂ4™Ó\⛩·‰œ7ÊD7ó¾ÎdÞoäz/Ptì…CPtòVQ0úoPuQ1þ¦Y‹P1o P +uj± Ý,YP?KË<˜œÂ4ËÓâÍ©a‰Î7tDÏ7Zjdzo€zBPtˆ…VPtŽiQ0–‚PuQ1š¦ªo P +uj°±¶ÝÂYP?kõÔ„œ² 4õÓ°â÷©TDø7ý‰ù7òüd oz@ Pt…T Pt g Q0(€ PuQ1.Y“ P1@o¨ P +ujFÝüXœ +4Ó.â©OfdpYP1ŒpRœó +4Órâ!©ž‰"7±D#7Ï|èj +P3‚Œd’z +Ptš…¤ +Pt · +Q0¨Ð +PuQ1¸óã +P5ÂYP1¤;Äœ 4;ÓP Ž Aȼœ4 hAcâ!iCcÐþð i Pvü*Ž P15¢ Pt&@¶ Pt<5Ê PtB@Þ PtFKJVPa POVa P5`** P;fl"$}„œÙˆˆpœ% àŠc[¢wª‚ˆ P1°‚› P0¶® P?º˜¾£Â®Æ¹ÌÄæ PtÐÏÚ P1èÚ P0#îåP0‰®ø6œÌ à°cyþw‚g P1 ‚z P0 P?£¹ ij Pt$Ï.P1èÊ0.œ[àÌc—6w>‚P1D‚!P0J4P?N£TÄQPt$^Ïä`0œïàæcµfwn‚P1t‚°P0x¹|ð‚ÄÖPt†ÏP1,úœ–Ï P1 6œÅàcÓ¦w®‚`P1´‚sP0¸˜¼¹ÂÄ™PtÆÏ̵P1ÖûP3%ÊÐ&%'v57'¸67'X‡(g)'qˆö'Â%*wwF*¯ ¯ G*C C I*º +º + H*íí,*¢¢+*WW)*//@*]]?*N*ÊÊO*‚‚J*88-*ºº0*QQ<*L*ç ç *''*''C*~~3*––)*õõ˜**ÀÀ=*FFG*¥¥(*²² +)*qq +**}} *²²9*88 +(*¯¯D*llQ*  K***ÌÌ,*ZZ1*  +*ïï.*€€œ*vvA*š š *§ § *-*ÙÙ4ì ó‡ ‡Øàªá 0*P P%`êÎÎUJáe“€;0¬ · +‰ ž  $×int”ÎäIJ¼€ P3ÿ Ý GP9ª! Æolz¯…@5 ] N  [xS íMÆ +ÕNP  Qà +úRP +gSP +CVP +ÿXP +YP +ÍZP +O[P +`\P +¦^P +)_P +0`P +zaP +ßbP +ecP +ìeP +TjP pä ³qP crP H m nÆrtcoªrawsà  vO Ew3 4xO CyU –zU +äPŽvarP‰P)P~u¦= wÎ&¾= ƒÎAAØØCÎWOòØQξ؜ËñØðœ,å²;œTÜ ç ¨D$Lœ¦varFP;Hò Lý P T \ QVÎpœøvXPY\vZ ‚l wl lYÀa΄œJvcP‚\Še ‚• w© l‚]l˜œ§!ùlοvnPà\œp ‚ó w làŽ¬œÄš¦Èœá²//‘Ø8œ@!ì‘ÎS"ŽÂ³,#šœ$J) @%P!$V) T%P($b) h%P3$n) |%P-$z) %P.$†) ¤%P/$’) ¸%P*$ž) Ì%P,$ª) à%P2$Â) ó%P@$Ú) %P0&î) %P4$ô) /%P$'ü) %P#vΜœÈ(¦€˜éx)˜²¯$4 Œ%P!$$4  %P($*4 ´%P)$04 È%P*$64 Ü%P+$<4 ð%P,$B4 %P-$H4 %P.$N4 ,%P/$T4 @%P0$Z4 T%P1$`4 h%P2$f4 |%P3$l4 %P#$r4 ¤%P$$4 ·%P@* 4 %P4'ó¬Hœœ "¾º +û #º ++ËÄò²? ¶J ºU È` $Îk @ %P1$Ôv S %P4$Úv f %P2$àv y %P1$æv Œ %P0*ðv %P3,¯ôdœ… +-Ø(°Û )°+åD$ü î %P3$  +%P0$  +%P1$ ' +%P2$ : +%P4$Œ M +%P1— $$¢ i +%P1(­ 2¸ Nà .F1ÎX:œ1 /–1UÓ0n31 1ret4Î )È2«7%N$jÎ ÷ +%P4$r¢ + %P4$zÙ %Pt€€ 'ˆä %P47 H¾˜œ` +Ë òبœ‚ +å°3è4PD4v6P¼4¸7P´4§8P¸5X‡5ºŽ%611G6ss86××(6ÃÃ'6CCH6ˆˆ96ö ö 688 (6²² )6(( +6’’ +6 +6·· +6ç ç 6~~36ÙÙ46š š 666 +6¥¥(6ÎÎ +6 + + +6 +6ll*6¡¡ 6––)‡ L‡*`ꢢUJáe“€;0¬ · +‰ ž  $×intÀ¹¹~ $ +iÖÀ& ©ëë¹ + +w#¨& Û +1,& Ûnއ Ò‡¸èäá0*PP%`êÎÎUJáe“€;0¬ · +‰ ž  $×int "= +:#= +¥$= +è%= +¸'= +(= +F)= +Å*=[ ô/ Zd var\PD¸dœ$>lœŸvar?PS"DLˆxœØXÀ@ÎXaŽD’z$œLs +‚$Œœ#var„PS6°0œHvarŸPt·¶à œÎ¾4œ‘[P3&fP3Ê44œÉD[¹P3ZfP3(×hœîvarÙP’愜varèP¥±-ÜHv5P¸6Pö‹ÎÔŒ%Î¥¥(––)ÚD‡ º‡ 8;*`”nnäIJ¼€int£8*Ï,÷,Y ,˜!, í",Ç#,1$,'%,­', „(,$ ),(+,,y,,0‰-,4 a!M +Ñ!3 var#, ºv ˆœœ ixn¸*²f{6̲fAß SJ¿ +ÑJ3 varL, Z(”œ + inX œ<à„¨l à³ ~‡¼4œ/ч3¾ Ù‘ð0œTÑ‘3ß ˆš, œŒÑš3! valœ,!! s¥8œ¯ i§n9!ˆ­LTœÜº, 8œ÷¯¼‘hÖ½n‰!~n÷£)h/upEdK3,`•Plv5,¸6,/’œ‡K­e¸¢žÈ‡qØ¢|܇ ð‡U*`”ffäIJ¼€int£8"Ï$÷$Y $˜!$ í"$Ç#$1$$'%$­'$ „($$ )$(+$,y,$0‰-$4 92 +2~ m žO' " dd +2 + qOz ' T0m‡ ‡§`*íMGÕN QDúRgSCVÿXYÍZO[`\¦^)_0`zaßbecìeTjpe³qcrH m“ nG rtco+ rawsD +Çe¸ +‰nep +0e¬ +O-e  +x@e” +LQeˆ +Öae| +9~ed +4‡eX‡ º‡Ø üá0*PP%`… ÔÔ¬ +Q Ý + 9 í +[ ¦ Ç +ø +  +Ž  À f . Ñ +$ int P  +varP ‰P )P V,0 +reg,Ô var.P î5S +reg5Ô var7P…>Ôy ÿ>Ô +id>WרTœS, (œUc¾!nQøcn 6 A6 $ß!Û< +1öëß!0F C<F GSÛF :öëqHÔT &œ¹ÿHÔò!idsH¹B"retJÔy"iKÔÆ"j SPu ¿!W"™ Q%| œûidQWæ"varSP##W^œ œt$id^WP   `6#  $S#Û¦ 1f#öz#ëS##c¸ œí$idcWP0¼ e<Ž#¼ G«#Û :¾#öÒ#ë«##¢hÔ œ%Ü UP1#Ìmà œ7%è UP2#rì œ\%ô UP2&³m€ s!P&­¹„&3¹ˆ'v5P(s°)'˜»!¥(¿Ë)'¦Ö!À',æ!À'cö!¥'B!À'Ø!À/9‡ ü‡*`… ¨¨¬ +Q Ý + 9 í +[ ¦ Ç +ø +  +Ž  À f . Ñ +$ intÆ¿¿~ $ +cÜd( ¯ññ¿ + +B!<( áñ¿ +Ø/-4( /¬‡ ‡z*`… ¨¨¬ +Q Ý + 9 í +[ ¦ Ç +ø +  +Ž  À f . Ñ +$ intÆ¿¿~ $ +˜ÜØ( ¯ññ¿ + + +¦!¬( áñ¿ +,0-¤( ‡ B‡ÚC::§Ž`Ÿ0"Þ•#:ç$:ý%:«&: Ë':¿(:):ÿ*:’+: #,:$m-:(ñ.:,÷81“¼2:3:<4:45: L6:`7:,8:®9::: ÿ;:$’<:(#=:,m>:0ñ?:4–B¸˜C:qD:²É`)A #ß()Þ ûô +ô~“x4)ä䜇 釸 Ô:*`”nnäIJ¼€into,˜val,˜reg,n 1˜»reg1n +D6 }=nè ret?n i@n ¿Nn retPn iQn ÛT˜3bÑbn ÿdn ™en ©fn àgn sclhn %in jn¡nø Ôœ¸¶¸æ#len‘¾o$Ñ’˜Ž$e“ÊX *”˜ •˜  –˜ —˜ ˜˜uü ¦'ŒŸ!0œD¯¬$Ÿ !Xa¯Á$Ÿ!xž~¯Ö$Ÿ! Ÿ›¯ë$Ÿ!À ¸¯%R!諚&%è1?%<G]%Rp%]Ž%h¬%sâ%uš!Š;Œ?&T&u¨!0‹]Œh&u®!ŒŒ}&V!Ñ^!ÜPyuœ!H®ÀŒ’&§&u !h±æŒ½&Ò&»´!ˆ²u´!ˆ9Œç&ü&uÂ! ÀBŒ'&'uÈ!¸º`ŒuÌ!н~ŒÃÐ!è¶õèÓ<'Þ]'»Ð!IÞuÐ!9Œ©'Ë'ŸÔ!@C¯uÒ!XÇŒí'(»"ÃQu"9Œ<(Q(è"pÉ×pøf(‡( £! Ÿ&"U¯Ó(»0"¨^u0"¨9Œè( +)uL"ÈÎýŒ,)A)uN"èÑ#ŒU)j)uX"ÒIŒ~)“)u`"(ÓoŒ§)¼)uj"Ô•ŒÐ)å)up"ÕŒù)*"ÅH#¾[$ÜÜ;$ˆˆ6vi!‡ P‡p @@ÿ Ý `^WW~@· t)G È!‡ }‡Ì"ŒÀá0*`êµµUJáe“€;0¬ · +‰ ž  $×int•9Ý reg9µ +i;µ¤/þ reg/µ +i1µ kC% regCµ ²HµÌ"|œ» ÿHµ"*idsH»\*iJµ•*¼Þ"NŽÈË*Þ"Óä*Ý#Ré7+#ôQ+Á>ÃH#Tœ¥Wœ#$œ!idW>PÝœ#@Yé¤+@ôÁ+–\À#(œkid\>P¼À#`^È,`Ó1,la%è# œ¬ida>„,þì#c¥,8kµ$œÕ$P0ïsµ$œþ($P2í{µ0$œ'<$P0 ‚µD$œPP$P2IaŒg7?»e»” v57!g¤" P¯™!Á¿" 8Ê´ ^Ú´ iê™ wú´ 1 +´ª#‡ ƇÃC::§Ž`Ÿ0"Þ•#:ç$:ý%:«&: Ë':¿(:):ÿ*:’+: #,:$m-:(ñ.:,÷81“¼2:3:<4:45: L6:`7:,8:®9::: ÿ;:$’<:(#=:,m>:0ñ?:4–B¸˜C:qD:Éà)A¢#ߨ)Þ ûô +ô~“2˜)ä% : ; I$ >  I: ; (  I: ;  : ;  : ; I 8  : ;  + : ; I8  : ;  : ; I : ; I I'I'.?: ; 'I : ; I.?: ; ' : ; I4: ; I.: ; '@—B: ; I1X Y  411X Y 1: ; I‰‚•B1 .1@—B!1".?: ; '@—B#1RUX Y $.?: ; 'I@—B%4: ; I&1RUX Y '1(‰‚•B)Š‚‘B*$ > +41,4: ; I-4: ; I.4: ; I?</4: ; I?0I1!I/ 2.?<n: ; % U$ > $ > : ; I : ;  : ; I8  : ; I8 I !I/ +!I .?: ; 'I@—B 4: ; I ‰‚1‰‚1Š‚‘B‰‚1.?: ; 'I‡@—B4: ; I?<4: ; I?.?<n: ; % $ >  I: ; ( ( $ > .?: ; ' : ; I .1@—B +1 ‰‚1 Š‚‘B .?: ; '@—B: ; I1X Y ‰‚1‰‚•B14: ; I‰‚1.?: ; '@—B4: ; I?<.?<n: ; % .?: ; ' .1@—B% U: ; I$ > .?: ; 'I@—B: ; I: ; I4: ; I $ >  + I &I% : ; I$ > .?: ; 'I@—B: ; I‰‚1Š‚‘B$ >  4: ; I +‰‚1  I &I : ; I4: ; I4: ; I?<.?<n% $ > .?: ; 'I@—B: ; I: ; I4: ; I4: ; I 4: ; I +‰‚1 Š‚‘B ‰‚1 $ >  I&I : ;  I8 4 .?: ; '@—B4: ; II!I/ .?<n: ; % $ > : ; I I: ; ( .: ; 'I : ; I: ; I 4: ; I +$ >   I .?: ; 'I@—B : ; I4: ; I4: ; I4: ; I4: ; I +: ;  +: ; +: ; 1X Y1 41141‰‚1Š‚‘B1X Y 1RUX Y  U ‰‚1!‰‚1"&I# : ; $ I8 4% &I'!I/ (.?: ;'I@—B): ;I*+4: ;I,.?<n: ; % $ > .?: ; '‡@—B.?: ; '@—B4: ; I4: ; I‰‚•B1 I 4: ; I?< +I !I/  4: ; I?.?<n: ; % .?: ; '‡@—B% $ >  I: ; ( ( $ > .?: ; 'I@—B‰‚1 Š‚‘B +.?: ; '@—B : ; I : ; I .?<n: ; % .?: ; '@—B: ; I4: ; I4: ; I$ > $ > .?: ; '@—B% $ > .?: ; '@—B4: ; I‰‚1Š‚‘B‰‚1$ >  ‰‚1 +‰‚•B1 ‰‚•B1 4: ; I ‰‚•B14: ; I?<.?<n: ; %  I: ; ( $ > .?: ; '@—B: ; I4: ; I.?: ; '@—B 4: ; I + I &I 4: ; I?< I!% $ >  I: ; ( ( $ > I!I/ &I +4: ; I?% $ >  : ;  : ; I 8  I: ; (  : ; I8 .: ; 'I  : ; I +: ; I 4: ; I $ >  .?: ; '@—B.?: ; 'I@—B: ; I: ; I4: ; I1RUX Y 111RUX Y 1X Y  I.?: ; '@—B: ; I1X Y  411 414: ; I &I!I"!I/ #4: ; I?<$!% $ >  I: ; ( ( $ >  : ;  : ; I8 I +!I/ &I 4: ; I?%  I: ; ( $ > I!I/ &I4: ; I?% : ; I$ >  I: ; (  : ;  : ; I 8  : ;  : ; I8 + : ;  : ; I : ; I  I'I'( $ > .?: ; '@—B: ; I4: ; I‰‚1‰‚1Š‚‘B‰‚•B1‰‚•B14: ; I.?: ;'@—B: ;I4: ;I: ;I .?: ;'@–B!4: ;I".?: ;'@—B#‰‚1$‰‚•B1%4: ; I&&I'4: ; I?<(I)!*.?<n: ; % : ; I$ >  I: ; (  I: ; ( $ >   : ;  + : ; I 8  : ;  : ; I8  : ;  : ; I : ; I I.: ; 'I : ; I: ; I.?: ; ' 4: ; I.?: ;' 4: ;I.1@—B41.?: ; '@—B‰‚1‰‚•B14: ; I.?: ; 'I@—B1X Y 1!: ; I"1X Y # $‰‚1%Š‚‘B&‰‚•B1'‰‚1(1RUX Y ) U*‰‚•B1+41,.?: ;'@—B-1RUX Y..?: ;'I@—B/: ;I04: ;I14: ;I24: ;I34: ; I44: ; I?54: ; I?<6.?<n: ; % $ >  I: ; ( ( $ > I!I/ &I +4: ; I?% : ; I$ >  I: ; (  I: ; ( $ >   : ;  + : ; I8 .?: ; ' .?: ; '  4: ; I.1@—B.?: ; '@—B4: ; I‰‚1.1@—B41 41‰‚•B14: ; I.?: ; '@—B‰‚1Š‚‘B‰‚•B14: ; I4: ; I?<.?<n: ; % $ >  I: ; ( ( $ >  : ;  : ; I8 .: ; '  +: ; I 4: ; I .?: ; '@—B 4: ; I1X Y 1 411RUX Y  U: ; I.?: ; 'I@—B.?: ; '@—B4: ; I4: ; II!I/ &I I4: ; I?<!% $ >  I: ; ( ( $ >  : ;  : ; I8 I +!I/ &I 4: ; I?% $ >  : ;  : ; I 8  : ;  : ; I8  : ;  : ; I : ; I +4: ; I?% : ; I$ >  I: ; (  I: ; ( $ >  .: ; 'I  +: ; I : ; I .: ; '  4: ; I.?: ; 'I .?: ; '@—B.1@—B11 U1 11X Y  4141.: ; 'I@—B: ; I: ; I4: ; I‰‚1Š‚‘B  I!&I".?: ; 'I@—B#.?: ; '@—B$: ; I%‰‚•B1&4: ; I'4: ; I?<(I)!% $ >  I: ; ( ( $ > I!I/ &I +4: ; I?% $ >  I: ; ( ( $ > I!I/ &I +4: ; I?%  I: ; ( $ >  : ;  : ; I8 4: ; I?&I I +!I/ % $ >  I: ; ( ( $ > .: ; ' : ; I .: ; 'I  +.: ; ' 4: ; I  4: ; I: ; I.?: ; 'I@—B: ; I4: ; I4: ; I4: ; I1RUX Y 11 U4141 1X Y ‰‚1‰‚1Š‚‘B1RUX Y 1X Y U!41" I#&I$.?<n: ; %  I: ; ( $ > I!I/ &I4: ; I?% : ; I$ >  I: ; ( ( $ > .: ; '  : ; I +4: ; I .: ; 'I  .: ; 'I@—B : ; I: ; I4: ; I1X Y 1 411X Y  I&I.?: ; '@—B.?: ; '@—B: ; I1RUX Y  U.?: ; 'I@—B‰‚1Š‚‘B4: ; I 4: ; I?<!I"!%  I: ; ( $ >  : ;  : ; I8 4: ; I?&I I +!I/ S2Ÿ 2Ÿ SPóPŸ P (óPŸ8>1Ÿ¾ÎSÎÙœÚ<Sx~5Ÿ<L2Ÿ<L ÿŸLN3ŸLN ÿŸNT4ŸNT ÿŸTV5ŸTV ÿŸhl2Ÿtv2ŸtvS|†P†óPŸ‚†S†P|€1Ÿ†ˆ1Ÿ†ˆPšPš¤óPŸ˜šSš¤P”6Ÿšœ6ŸšœPTPtŸ`TP +óPŸ P$óPŸ PóPŸ$)P):óPŸ<@0Ÿ@JTJMPMNtŸN”Tx€0ŸQ&óQŸRrŸP$S(,P,4S48sŸ(.0Ÿ.0p s"Ÿ08Q P V &P&<V<BPBNTNTtŸ@BPBFTFTUTVóPŸX^P^jWjntŸnvTv~tŸ~‚W‚†tŸX`Q`jqŸ~€qŸ\^P^†WPóPŸ.P.lóPŸ VU:VTVlPPU^@FVFU +ÈUÈÔVÔâvŸò8UQ,QüVvŸV˜ÞY¼ÊV<HYP,>P>@~”ÿŸFP +~”ÿŸ + P \|#Ÿ@BPBF|#ŸFHPHP|#ŸPRPRZ|#ŸZ]PbdPd~|#Ÿ~€P€ˆ|#ŸˆŠPŠ’|#Ÿ’”P”œ|#Ÿœ¦P¦®|#Ÿ®¶P¶ÔYØâYâôPôü|#ŸüP |#ŸP|#ŸP,|#Ÿ,4P4J|#ŸJLPLP|#ŸP^P^n|#ŸnpPpx|#ŸxŒPŒ“|#ŸÞàPàè|#ŸèúPú|#ŸP|#Ÿ$P$'|#Ÿ8LYÊÖ|#Ÿð<|#ŸdtPtx|0Ÿx‚V‚„P„Ž|#Ÿž¤P¤Ö|#ŸÖØPØÞ|#Ÿè,|#Ÿ®¶0Ÿ¶Ì\Øò\¦®R8L\jp0Ÿp„\ +0Ÿ.@ZhnZ +Z.8ZLÊZÐðZ +Z$ZŽžZ¶¾ZÞèZZZ,8Z@‘¤Pn@Ÿè:Ÿ.8‘¤LÊ‘¤ÊÌ:ŸÖ +‘¤$:Ÿdj@ŸŽž‘¤ž¾:ŸÞ葤ø‘¤:Ÿ,8‘¤˜œSœÎ‘ ÎÒSÒ@‘ .8‘ LÊ‘ Öè‘ èðSŽ”‘ ”–S–œ‘ œžSÞè‘ ,8‘ @0Ÿ@‘œ +0Ÿ +䑜ü‘œ$@Y@p‘œpxPxð‘œò²‘œ²ÞVÞ.‘œ8d‘œdjSj†‘œ¢¨S¨‘œ<‘œ<dVdÞ‘œèêPêô‘œôöVö8‘œ@R +R@]RbîRò R:RJRRn“R“˜‘¤˜¤RÞôR'R8LR$<Rj€R„ŽR¾ÄRÖÞRèøR@ Ÿ + Ÿ +0Ÿ*W,.1Ÿ.8W +0ŸQT,ZQZ\T\¢^¢ÙQÙÚtŸÚäT +tŸ +T<>ty"Ÿ>@T@]Q]bTb Q  +tŸ +T>Q>JTJ€Q€ÞTÞ"Q".T68T8jQ¸¼t‘œ"ŸÊÖQÖèTè +Q +T<Q<dTdÀQÀÞTèQ,T@S +SÈY@]Sb S@SJhShnYn“S“˜‘¨˜ªSÞîSîYS'S8LSLPYÊÖYð +Y +S$Y$<SdŽS޾Y¾ÎSÖÞSèøSøY$SFP~0.ŸP\r0.Ÿ\˜q0.ŸF˜òÖF˜‘¤F\Z\^R^fSŒS˜RF’‘´Ÿ’”S”˜‘´ŸF\‘´Ÿ\^V^jvŸjV.8VLÊVÖðVŽžVÞèV,8Vj‚S,0Y02V28vŸ8<V¶ºVºÀ[ÀÆ{ŸÆÌ[fjSjnYntyŸtzY¤¨S¨¬Y¬²yŸ²¸YJPYPVyŸV\Y S &s|Ÿ&(SQq€€€Ø{Ÿq€ÀðØ{Ÿ P $p€€€Ø{Ÿ$&p€ÀðØ{Ÿ&(óPŸP(óPŸp Ÿ(óP Ÿ(BPBPóPŸ(Bp ŸBPóP ŸPjPjxóPŸPjp ŸjxóP Ÿ”0Ÿ”žTž¡P¡¢tŸ¢¶TºÊTp˜P˜ qp„Q„ óQŸ ®P®üóPŸ ¦0Ÿ¦® +p”3&ÿŸ®äu3&ÿŸ¦®p”3&ÿs $Ÿ®äóP#”3&ÿs $Ÿ¦äsäôóP#” ÿ$3&ÿŸæôQü +P +DóPŸü0Ÿüp”ÿŸS`hPhxóPŸxŽ0Ÿ‚ŽQ„†R–˜PP\óPŸT,0 tÿp"Ÿ\vPvžUžÖóPŸÖàUà*óPŸ*-P-0U0XóPŸr$T*XTž P ÖUà$U0XU¤©P s2!Ÿ SXpPpžUžÄóPŸÄÔUÔ×P×ÚUÚôóPŸnàTž P ÄUÚàU¤©Pô P :U:ZóPŸZjUjmPmpUpŒóPŸ +vT:<P<ZUpvU@EPŒ¤P¤ÌUÌðóPŸðúUúýPýUÒ×PÌÎPÎðUP(óPŸpóP#(.P.LULzóPŸ0tTLNPNtURWP€‡P‡VóPŸ<VÎÐ0ŸÐÚTÚÝPÝÞtŸÞT\^P^ŒT¸ºPºàTðòPòT "P"BT`bPbˆT +q@D$!Ÿ +Q" qÿÿÿwŸ"0QR^SdjSž¢Sž¢@=$Ÿ²¶S²¶0Ÿ²¶@=$ŸÀÊPÊÔóPŸÄÆSÄÊPÄÊ +ÿÿŸàâSôøs ÿýŸøSPlóPŸlnPnqDq8óPŸöøS®²s ÿýŸ²´S€ŽPŽ´óPŸ´¸P¸ºóPŸ€¤0Ÿ¤¬P¬´T´¶0Ÿ¶ºT”´U"S +QQ¼ÂSØÞS0ŸS $V$,R.0V0HRHJvJLVL`R`budlSlnrˆœ0Ÿœ¬Sª®Q®´SÂÄQÄÊSØR2P2PóPŸPdPd€óPŸ€†P†˜óPŸ’pÿŸ˜ž0Ÿž 1Ÿ ¢2Ÿ¢¤3Ÿ¤¦4Ÿ¦¬5ŸsHJ$Ÿ"sHC$Ÿ"&ST^P^|óPŸdhS|ŠPŠšUšœóPŸœžUž P ¢óPŸ|‚Q‚ŠTŠžóQŸž¢T|Š0ŸŠŒPŒ’0Ÿ’šPœžPž¢0Ÿ|Š0Ÿž¢0Ÿ¤¬P¬ÄóPŸ°´p3Ÿ´¸P¸¼pŸÄØ p2$€"ÎÒSÎÖ1ŸÎÖ3Ÿàô p2$€"êîSêò2Ÿêò3Ÿ P LTLZVZÄTÄtŸRrŸ"RNTtŸŠœtŸœÔTÆÞRPTtZ¬WœÔW>¤Ÿ>D,ŸDN°ŸNR´ŸRZ¸ŸZ¬w +ÿÿŸœÔw +ÿÿŸ`bPblUflUv¤UœÔUz”S ªS”–syŸ–¢SœžSª¬S€‚r{Ÿ‚ŽQŽ’r{Ÿ ¢Q¢¤r{Ÿ¦¨Q¨ªr{Ÿ¢°°Ÿ¢°0Ÿ°¶´Ÿ¶º¸ŸºÀ¤ŸºÀ €ŸÀÂ0ŸÀ ÿŸÂÄ(ŸÂÄ ÿŸ ¤Ÿ  †Ÿîò0ŸŠ– ÿŸäæ +ésŸæè +èsŸèò +ésŸŠ” +èsŸîò(ŸŠ–(Ÿîò ÿŸŠ– ÿŸTœŸ$T$@p@D œ°àDJNp (Ÿ  ÿŸ8D ÿŸJN0Ÿ&, +érŸ,. +èrŸ.8 +érŸJN +érŸ.2$Ÿ8D(ŸJN(Ÿ8D ÿŸJN ÿŸT`¤ŸT`0Ÿ`d°Ÿ`d‘Ldl´Ÿdl‘Hlr¸Ÿlr‘Drx¤Ÿrx‘Tx€,Ÿx€‘PnPnróPŸrtPt|óPŸBQBpuŸpróQŸr|Q0Ÿ2U2BRr|0Ÿs2$w"0Ÿ1Ÿ @<$rŸ " +ÿÿrŸ",@<$rŸLXt2$w"LX0ŸXZ1ŸZ\@<$sŸ\^ +ÿÿsŸ^l@<$sŸÐà p2$Œ"Ðà0Ÿàâ1Ÿâä@<$sŸäæ +ÿÿsŸæî@<$sŸô p2$Œ"ô0Ÿ1Ÿ@<$rŸ + +ÿÿrŸ +@<$rŸ&P&<óPŸ& p2$Œ"Ü$Žôl` +Ø l–ü9(<†‚Äx5<V¨” Lè ; (‚0 ˜»È Fz#Ï$ü% ¨ÿ-/ù/HŽBØàðN P¸èS 8]WÝX[Ø -``a“bªdø Ô’k lÌ"Œp8:<>xz|~z|~€œž®°¬®²´<@DFJLBDLNFHRTHJTVô``j<DHJ\ ¢¤¦ªÚÜäªÚÜäÚÜäôüþ¨ª¬´PVhnŒ¦ª°œØÜTVXZ^n8<48<>"&>D*,DFLN .0NR "02RTXZZ¤¬²´ºÞäœÔ¢¤¬°°²´¶¤¨º¼¾À¨¬²´À¼¾ÂÄÊÐÐÔöúÔØþØÚÜÞäòŠŽ’–ØÚîòŠŽ’–ÜÞèêÚÜ&<@DJN&*.88<@DJNTVZ\^`VZ\^bd`bdhjlhjlrÐÒÔØÚôôöøüþQvû src/sys_execsrc/includemsg.cmsg.hprcm_core.hpm_state_data.hstddef.hsync.héÓ./µ.“Jâ.KQ†s q  |\œ#j_!J =">!P.1 -";O ).W *  r  "&//1Yu /JwI äB>.B Ãf½.Ã.“±Ó./µ.ÐJ§Ý.!«.ÚXç./¡ éXuwu^ û src/sys_exec/home/a0274052local/toolchains/gcc-linaro-5.3-2016.02-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/includesrc/includesys_init.cstdint.hrsc_table.hprcm_core.hcm3.hmsg.htrace.hsync.hdebug.hô + 22!-2j0001=>3>ke. `Ç'2¿mû src/sys_execsrc/includesync.cmsg.hcm3.htrace.hprcm_core.hhwmod.hl!/Az / + >-@!1>-N$"=#+5k01=CJ<=$.=f@+û src/sys_exectrace.c!X>û src/libsrc/includestring.ctypes.hK-11…u<û src/libsrc/includeputs.ctypes.h< !!"$!","0z. Ö "=-[1 "t/-w„Vû src/libsrc/includedebug.cprintf.hputs.hÄ%%%/ sX?Ÿ!"!>?0!ÙØcû src/libsrc/includeprintf.cputs.hstring.hstddef.h<Ú .s  .t  =0+. tÖaª~Jô  /0= ‚</=0¨~.°gó>ÓJX=LMY",>2!1.=MMM/-03JJ•~t=;ì.¸~.ù ?„.ý ˆ.)&(/!"=K!l´.K>.C.> "==¾.Ç.>=¶× 2K3y &-//0.ä "ó.</"Lò~.Y;0CMA2-v< <-s<<-y-O$"=#+3l-*=@-]!>-O!>-O!>-O!>-O!>-O!>-O!>-O!>-O!>-O!>-O!>-O!>-O!>-O!>-O!>-O!>4?B2-y=M>=MY/\Y/\hYH PJû src/pm_servicessrc/includehwmod_335x.chwmod.h7û src/pm_servicessrc/includepowerdomain.cio.hmsg.hpowerdomain.hprcm_core.hpowerdomain_335x.hpowerdomain_43xx.h (=!!!!\jY/!!!z./!!! ."//-!!/!!#:fu u  !“ ×t© ×J© ótMn k  (Ÿ[Úgfv/-!"V/"XNHû src/includesrc/pm_servicesdpll.hdpll_335x.cLFû src/includesrc/pm_servicesldo.hldo_335x.c<Áû src/pm_servicessrc/includepm_handlers.cmsg.hclockdomain.hhwmod.hpowerdomain.hdpll.hldo.hprcm_core.hrtc.hcm3.htrace.hstddef.hH!!#?0&z !Ah>LZ11 <y.f&z<&S%1>[KNKA?M010>1<UJX0fLZ$">/AN-H<'<<%7%T$#??[KNK??M0>pJxXz< <#+ ž%7%T$#??[KNK??M0rJxXz<<#+²%7%T$#>[KNK??L>sXvX¬#i-@ %$0>ZK??LY?-O4  K2">K0> ta<$ =",4g=?01=@-`J5ä .9#<P>=>>0000>1-g=>>00>1- +J#>=>>0?#- <#>=>/0>1-C!1- <#>=>00>0?-â¶û src/pm_servicessrc/includeprcm_core.cio.hhwmod.hdpll.hldo.hmsg.hpowerdomain.hclockdomain.hcm3.hddr.hi2c.hstddef.hØÀ$">=>$">=á}<!/"0-\"#&/!"!L///0-¿'y @ Ä.#M'y µ Ï.#Mª.Ú<\?#!†1 f!#+#M????????f???Mf>=>=>=>=>=>=>=>=>f=HZ-zžtä œ #á<1@+–!00Ì.¸X0>===>-\!====>>1><.H<0 -t$YK=Y%*@u. [ ‚PJû src/pm_servicessrc/includehwmod_43xx.chwmod.hSgû src/pm_servicessrc/includeddr.cprcm_core.hmsg.hhwmod.hstddef.h¸/y.!'z !"!"z ""!"y !!"!"!!!!"L#1<`$!#!&u.!#!&o.//‚#1/!!"!!!"D>4z.&z &v.!)//"/XhY,^8$<y.=/$$"!">/!"m.KL/0f# p ##!?"/-!#=N?,0”!M>L1-”!M>L1-•L//kL//pû src/pm_servicessrc/includedpll.cdpll.hprcm_core.hdpll_335x.hdpll_43xx.h ö#¬tu/#/!!#/-!/#/!!#/!/#/!/[6x‡M¢kY/!)/!/  !![(x !"?0/ NHû src/includesrc/pm_servicesdpll.hdpll_43xx.cQKû src/includesrc/pm_servicesmsg.hpm_state_data.c û src/pm_servicessrc/includeclockdomain.cio.hprcm_core.hclockdomain_335x.hclockdomain_43xx.hstddef.hclockdomain.hØjY/!zJ/! J!%j.h<#t M #X!;M)D[#u?P.h<J2XT._<#J.Xjj\Vû src/pm_servicessrc/includeclockdomain_43xx.cclockdomain.h\Vû src/pm_servicessrc/includeclockdomain_335x.cclockdomain.h\Vû src/includesrc/pm_servicespowerdomain.hpowerdomain_43xx.c2Bû src/pm_servicessrc/includei2c.cdpll.hø ž.â. s ˜ è ˜.ð.Ý £ ð. )3õX‹<õJ‹.: > <>H"/=>h!>¨J†ú~<•Ó ¼<q. k.Œ.ô~..ô~ ˜.è~<™X-è~ ˜ ’f)`.#.X<œ.ä~.«.Õ~<†.ú~<¨X1Õ~<‰.÷~.«.«<)LFû src/includesrc/pm_servicesldo.hldo_43xx.cÿ€û src/pm_servicessrc/includehwmod.cprcm_core.hhwmod_335x.hhwmod_43xx.hstddef.hhwmod.hÌ"È93;o h/J¾//` h/J3G‚jY/!zJ/!8JZ' Y '.Y L/)f_" ^ ".^ L/$‚b.€  ˆ p  t Ä$ºÄ$%ì$0Éñÿ è ÔÞñÿ  däñÿ 0 |  € ¤  ¨ ´  ¸ Ä ¬êñÿ È à  ä ˜  œ  þñÿ   $4 8L Pd hx ñÿø$ñÿ  ´ ¸ð < @˜ œà äü  D ( 28;<D@ØLñÿ`%Xñÿˆ&cñÿ H  ¤„  , <Ä ÔH Xx „ð ø˜qñÿ Ø}Ùì ðšñ   $\ p€ „” ˜¨ ¬À ÈÔ Ø   ¬ð ôP X¤ ¨´D¸D„ +Éñÿ&Öñÿ ¸ø \ ˆÜ   $ˆ °Ü àô ( 4\ h| „˜HÜH ãñÿ  $ (¸ ¼ì ð 4 8H L„  Ðü&dêdúhl,  ñÿ 'ñÿX)ñÿ Ø  , P  T 7U &˜  œ ´  ¸ Ð  Ô Ü  à è  ì ô €K€R„_ˆü nñÿ4(ñÿ¤(”ñÿ)§ñÿ ø ¨"¨­ñÿ)¸ñÿ Ì"ÀÍ"|D# H#|# œ#¼# À#ä# è#$ $$ $,$ 0$@$ D$T$ŒÔŒÛì”ôñÿ˜)=<&6ÉAÅWá c0y• "‰”¨)8¤¥ü¶™ HÄ)Ó ÜõdçHýu ')%” .>TK˜)Z`%u$¡œŸ!¬• "½´Åí Ù± êlX  • "0.ñ07Y DHeYù Ôcq)”‹Ù œ©³É‰xß• "ï‘• "%Ø(@3• "Cõ TqnI#Tyă1 “)¤œ·Õ„Ê• "Úyß• "ï½4ú 'ˆ Å .• "?1H• "YynU,}ˆp •ñ §• "¸Ì Ù‰pí• "ý $‘.˜;å ^LY (]¡8qe,‚4‹• "œÙT­É ¾Êý ÖY:êÉFûm + • " ½+ á 7 • "H iV 4*` …p Q Ù8˜ 1$´ • "Å • Ó ¹Xä   ð µ +p% +¸ +( +=80 +%Œ> +• "N +()8^ +¸ l +• "} + +• "ž +¹ µ +QÄ +$%<Ò + (á +¹ ì +• "ý +• " ¤($ Y7 © L • "] 9h í y ©– • "§ µ É¼Ê •.Ð 54Ø • "é ø$  9 à)0/ • "@  Q ñÿ\ ¹dp  ~ ù6’ y£ ¨&» a0Ó =ä ë ¼ò #$ÿ a + %L   . ? QO ©Xe d o • "€ é# ‘ ™œ E$· œ Ç - (Ú ù í • "ý ±0}  !¬ *¡; G• "X• "i­Hqˆ&1 (‘¡£$²åèÎõlÙ4(ïd(@ý¬ +…2 HqR^•r%ƒÀŒí ži8§² ÃÙØ%ð• "A é I\)Õ 6¡ˆFE W• "h™~=˜| ™•®¬(,™ÜÄDä¡6ÿ`)0Ål)#1.7A\M% Z• "k• "|Ä’£­­…Æ• "Ö<((êÀ&<øÁ#(‘ÄMT#°,• "startup.c$tzero_loop$dmsg.ca8_version_handlera8_reset_handlercustom_state_datasys_init.csync.ctrace.cstring.cputs.clogbuf_posdebug.clevelsdebug_leveldebug_idxprintf.chex2ascii_dataexception_handlers.crtc.ccm3.cext_intr_handlers.cldo.cldo_regshwmod_335x.cpowerdomain.cpd_statesmpu_bitsper_bitspd_regsdpll_335x.cldo_335x.cpm_handlers.cprcm_core.cprcm_enable_isolation.part.0prcm_disable_isolation.part.1cmd_wake_sourceshwmod_43xx.cddr.cio_ctxdpll.cpower_down_pllsdpll_regspll_modedpll_43xx.cpm_state_data.cclockdomain.cclkdms_state_changeclkdmssleep_clkdmsstandby_clkdmsclockdomain_43xx.cclockdomain_335x.cpowerdomain_43xx.ci2c.cldo_43xx.chwmod.chwmods_state_changehwmodsessential_hwmodsinterconnect_hwmodspowerdomain_335x.cputcharam43xx_interconnect_hwmodsdisable_ioa8_standalone_handlervtp_disableverify_pd_transitionsextint8_handlertimer_syncam335x_per_bitsa8_lp_ds0_handlerreset_handleram43xx_pd_regspm_resetds_restoreget_pd_mpu_stctrl_valprintfam43xx_dpll_regsam43xx_ldo_regsds1_data_aux_data_startcmd_handlersam335x_pd_regsam335x_pg2_power_down_pllsessential_hwmods_enablea8_lp_ds1_handlerdpll_get_divextint27_handlersoc_revclkdms_standby_wakeextint36_handlerddr_am335x_io_suspendidle_v2_dataextint26_handlerpd_state_changepll_lockextint34_handlerextint48_handleri2c_writepd_read_stateplls_power_up_start_dataextint41_handlerprcm_disable_isolationtrace_set_current_posddr_am437x_io_suspendextint4_handlera8_m3_low_power_fastextint50_handlerextint0_handleram335x_clkdmsextint7_handlerbusfault_handlerdisable_master_oscillatorhwmod_init_end_datadebug_set_levelextint45_handlerclear_wake_sourcesa8_standby_handlerextint9_handlerputssystick_handlerpll_bypassam43xx_power_down_pllsds1_data_hsextint40_handlerextint37_handlermsg_readextint12_handlera8_m3_low_power_syncm3_param_resettrace_initstandby_datamemmanage_handlerextint30_handlerm3_firmware_versiontrace_updatea8_wake_ds0_handlerextint5_handleressential_hwmods_disablea8_wake_cpuidle_handlerio_isolationextint31_handlernvic_disable_irqget_master_xtal_khzmsg_cmd_is_validvtt_highextint19_handlerclockdomain_initextint16_handler_start_textsvc_handlera8_i2c_wake_handlerextint53_handlera8_notifyextint1_handlermsg_cmd_needs_triggerclkdms_wakeextint15_handlerset_ddr_reset_end_textclear_ddr_resetextint47_handlerconfigure_wake_sourcesinterconnect_hwmods_disableextint18_handlerdummy_handlerpowerdomain_initds0_data_hsextint52_handleram335x_dpll_regssoc_typevector_tablevprintfddr_io_resumeextint6_handleram43xx_per_bitsrtc_mode_dataextint23_handlerldo_wait_for_onextint20_handlerscr_enable_sleeponexitldo_power_downam335x_hwmodsnvic_clear_irqclkdm_wakeextint38_handlerextint22_handleram335x_standby_clkdmsa8_cpuidle_handlerscr_enable_sleepdeepextint39_handlerdpll_resetextint42_handlermsg_cmd_wakeup_reason_updateextint21_handler_logbuf_startgeneric_wake_handlerputsnvtt_lowextint32_handleram335x_interconnect_hwmods_aux_data_endldo_power_upam335x_mpu_bitsextint28_handlerdebugmon_handler_end_stackddr_io_save_contextrtc_reg_writea8_wake_ds1_handlerextint49_handleram43xx_essential_hwmodsa8_wake_standby_handlerextint46_handlermemsetsoc_idhwmod_enablemainsetup_socpendsv_handlerextint43_handlerrtc_enable_checkmsg_cmd_read_idinit_m3_state_machineidle_dataextint25_handlerhwmod_is_enabledvtt_toggleinterconnect_hwmods_enablecmd_global_dataclkdm_state_changeusagefault_handlerextint3_handlervtp_enableclkdm_active_logbuf_endds0_dataextint51_handlerclkdm_sleepextint24_handlerextint10_handlerds_saveam335x_ldo_regsnvic_enable_irqpowerdomain_resetddr_io_suspendpd_state_restoredebug_haltam335_initam43xx_standby_clkdmsam43xx_clkdmsvtt_gpio_pin_end_resource_tablea8_wake_rtc_handlertrace_get_current_posa8_cpuidle_v2_handlermsg_cmd_stat_updateldo_wait_for_ret_end_bsshardfault_handlerldo_init_start_bssextint35_handlermsg_cmd_fast_triggeram335x_essential_hwmodsextint14_handlermsg_writenmi_handlera8_lp_rtc_handlerclkdms_sleepplls_power_downextint33_handlerextint13_handlerprcm_enable_isolationa8_lp_ds2_handlerds2_dataa8_i2c_sleep_handleram335x_sleep_clkdmsconfigure_deepsleep_countrsc_taba8_wake_cpuidle_v2_handleram43xx_mpu_bitsdebug_printfstrlena8_wake_ds2_handlerget_pd_per_stctrl_valrtc_reg_readextint29_handlerextint11_handler_start_resource_tableextint44_handlerenable_ioenable_master_oscillatorextint2_handleram43xx_sleep_clkdmsam43xx_hwmodshwmod_disablemsg_cmd_dispatcherdpll_initmem_typeextint17_handler4*!Ä'ÄÄD7¸<FN3rZ;t'$hb˜Â,s$ÅЂôÈ€tÎ#œ0—èé§0€-°p­7À东Ílp$U Ü:= \ No newline at end of file diff -Naur --no-dereference a/firmware/am43x-evm-scale-data.bin b/firmware/am43x-evm-scale-data.bin --- a/firmware/am43x-evm-scale-data.bin 1969-12-31 19:00:00.000000000 -0500 +++ b/firmware/am43x-evm-scale-data.bin 2024-07-07 20:37:34.676306709 -0400 @@ -0,0 +1 @@ + Wd$k$Š$g$†d$k$™$g$† \ No newline at end of file diff -Naur --no-dereference a/firmware/regulatory.db b/firmware/regulatory.db --- a/firmware/regulatory.db 1969-12-31 19:00:00.000000000 -0500 +++ b/firmware/regulatory.db 2024-07-07 20:37:34.676306709 -0400 @@ -0,0 +1,22 @@ +RGDB00ÁADüAE{AFˆAI•ALéAMjANˆAR{ASKATíAUÎAWˆAZBAüBB¡BD¸BEíBF{BGíBHmBLˆBMKBN’BO³BR.BS¨BTˆBYˆBZÍCA;CFpCH÷CI{CL’CNCO{CRfCUCX¨CYíCZíDEíDKíDMDDODDZžEC%EEíEGÏESíETˆFIíFMKFRòGBGDGGE‚GF•GH{GL•GP•GRíGTDGU@GYÆHK3HN{HRäHTKHUíID"IEíILZIN¾IR¸ISüITíJM{JO›JPUKE˜KHˆKNŽKPOKRKW…KY¨KZÙLB{LCŽLIüLKfLSˆLTíLUíLVíMA…MCéMDéMEéMF•MHKMKüMN¨MOºMPKMQ•MRˆMTíMU¨MVáMWˆMX{MY¤NG°NIKNLíNO÷NP’NZÂOMˆPA7PE{PF•PG{PHÕPK^PLíPM•PRGPTíPWKPY¨QARE•ROíRSüRU RW{SAˆSEíSGSIíSKíSN{SRˆSVcSYSTC¬TDˆTGtTH{TN…TRÝTT{TW)TZ¶UA UG¨USÇUY¡UZ…VCˆVEÊVIKVNwVU{WF•WStYESYT•ZA‹ZWˆ#4JJ#4FJÐ …8)Ð ¸ Ãp Ë@Ð ¸ Ë@ À>€ ¸ ö8 À  ¸ À)@ ¸$Ÿ%¸@œ@Ð$Ÿ%å,œ@Ð$Ÿ%å,œ@ü$Ÿ%å,œ@ý$Ÿ%å,œ@ +Š$Ÿ%å,œ@ ¸$Ÿ%å,œ@$Ÿ%å,œ@$Ÿ%å,œ@Ð$¦Ð%¸@œ@ ¸$¦Ð%¸@œ@Ð$¦Ð%ßPN Ð$¦Ð%ßPœ@ü$¦Ð%ßPœ@ ¸$¦Ð%ßPœ@Ð$¦Ð%å,œ@Ð%}¨%ßPN Ð%À&0N  Ð%À&0N üJë°L$0œ@üN•0OͰœ@¢N•0PÐ8€ÐN•0PÐ8€±üN•0PÐ8€üN•0PÐ8€±üN•0PÐ8€üN•0PÐ8€±ýN•0PÐ8€ýN•0PÐ8€±ýN•0PÐ8€ýN•0PÐ8€± +ŒN•0PÐ8€ ¸N•0PÐ8€N•0PÐ8€ýN•0Pið8€ÐN•0Q¢p8€ýN•0Q¢p8€ +ýN•0Q¢p8€ÐN•0Q¢pq¤NãPPÐN NãPPÐN ÐNãPPÐN ¤NãPPМ@ÐNãPPМ@¤NãPPÐ8€¤NãPPÐ8€NãPPÐ8€ÐNãPPÐ8€ÐNãPPÐ8€±ÐNãPPÐ8€üNãPPÐ8€üNãPPÐ8€ `NãPPÐ8€ `NãPPÐ8€±¤OͰPÐN PÐQTPN ÐPÐQTPN üPÐQTPN  `PÐQTPN ÐPÐQTPœ@ `PÐQTPœ@PÐQTP8€ÐPÐQTP8€ÐPÐQTP8€±ÐPÐQTP8€±ÐPÐQTP8€üPÐQTP8€ `PÐQTP8€ `PÐQTP8€ `PÐQTP8€± ¸PÐQTP8€ÐPÐQ¢p8€ÐPÐQ¢p8€±ÐPÐQ¢p8€ÐPÐQ¢p8€±0PÐQ¢p8€üPÐQ¢p8€üPÐQ¢p8€ýPÐQ¢p8€±ýPÐQ¢p8€ `PÐQ¢p8€ `PÐQ¢p8€ +ŒPÐQ¢p8€ ¸PÐQ¢p8€ÐPiðQ¢p8€ `Sw0Us8€ +ŠSw0Us8€ÐSw0Uš8€ ]Sw0W[H8€ÐSw0W[HqÐSw0W[HqÐSw0W[Hq±0Sw0W[Hq `Sw0W[Hq +ŠSw0W[Hq± +ŠSw0W[Hq± +ŒSw0W[Hq± +ŒSw0W[Hq ¸Sw0W[HqüSw0WnÐq `Sw0WnÐq +ŠSw0WnÐq +ŠSw0WnÐq± +ŒSw0WnÐq ¸SÅPTýÐ8€ ¸SÅPUè0N  `SÅPV6PqüSÅPV„pq +ŒSÅPW °œ@ +ŒSÅPW °q +ŒSÅPW °q± ¸SÅPW °q ¸SÅPW °q `SÅPWnÐN  `SÅPWnМ@ `SÅPWnÐ8€ ÐSÅPWnÐqüSÅPWnÐq `SÅPWnÐq `SÅPWnÐq± ¸SÅPWnÐqüSØØb ¨q±ýUšW[H8€ `V6PWnÐ8€ +ŠV6PWnÐ8€ÐV6PYCqýW[HXáè8€ÐW[HYC8€ÐW[HYC8€üW[HYC8€ýW[HYC8€ýW[HYC8€ `W[HYC8€ ¸W[HYC8€ ¸W[HYC8€ äW[HYC8€W[HYC8€uW[HY¥88€ÐW[HY¥88€ýW[HY¥88€ ¸W[HY¥88€ ¸WnÐYC8€WnÐYC8€WnÐYC8€üW‚XX˜œ@ ¸W‚XXºØN  ¸W‚XXºØ8€ÐW‚XYøN  ¸W‚XYøN  ¸W‚XYøœ@ÐW‚XYø8€ÐW‚XYø8€üW‚XYø8€ `W‚XYø8€ ¸W‚XYø8€uYCY¥8N  +ŒYCYóXœ@xZhˆb ¨qÐZhˆb ¨q ]Zhˆb ¨q ]Zhˆb ¨q±ýZhˆb ¨âÜZhˆl¸q°Zhˆl¸â +°Zhˆl¸âüZ¶¨b ¨q±ýZ¶¨b ¨q±üZ¶¨b ¨â ]Z¶¨b ¨âÌeÀ@Ð õ€èeÀ@ï€ õ€BeÀ@ï€ õ€ `eÀ@ï€ õ€ eÀ@ï€ õ€ eÀ@ï€ õ€ÌeÀ@ï€ õ€ eÀ@;_À õ€ÍeÀ@;_À õ€ +ðiiÀŠ_@ õ€iiÀÌJ@ õ€ iiÀ;_À õ€0Š_@ÌJ@ õ€ +ðÌJ@í?À õ€ ¹ñ —Ú°>± ½ÁÉÍ*nRsµ ÅÉíEü2ÒN^©Ñ* Oò•Ñ3üBâ™Ñ7Õ]Å™Ñ<óÞÑ@Sw™ÑISÑISw™ÑISw¥ÑIS|¥ÑIS™ÑIvîb¥Ñ^þ­¹½ÑjÖZÕ%Fâ‘ÕEB +Ù¬ó>æk¡Ý<órö…™Ýf:êábÚå!Köå* jö™åN"bús¥é3 {VéV&f‰õ3.ÎJoõn¼¤2õ†ÞJõ†æ¸Jõ£æ¸Jùv´ƒ&ýýŽÌ´gýEXýZ*6Ê™ýn¸2ýn¼¤2ýr°ýv´.ýzĨ6ý~Àý‚â¬Jý†æ¸JýŠÈýŠÈ™ýŽÌýŽÌ“ýŽÌœýŽÌ *ýŽÌ:ý’Зý›"ý›BýŸÞ‹ýŸÞJý£æ‡Fý£æ¸Jý§ê¼JýïJýïJýJýJŸÞÁJRO†æ¸JŸÞ´JŸÞJJ .÷™ \ No newline at end of file diff -Naur --no-dereference a/firmware/regulatory.db.p7s b/firmware/regulatory.db.p7s --- a/firmware/regulatory.db.p7s 1969-12-31 19:00:00.000000000 -0500 +++ b/firmware/regulatory.db.p7s 2024-07-07 20:37:34.676306709 -0400 @@ -0,0 +1,4 @@ +0‚9 *†H†÷  ‚*0‚&10  `†He0  *†H†÷  ‚«0‚§0‚aÀ8e«ÜùKЬðlrHÛÆ0  *†H†÷  01 0 U wens0  231201074114Z21231107074114Z01 0 U wens0‚"0  *†H†÷ ‚0‚ +‚©z,xM§-2R .lïˆŶiTCyS·®ˆþÀ·]GŽáﳆÚÓdÎ]žKnX>²o^BGAô,¸¨ÔªÀæHð¨ÎË®7¯ö@9ËUo[O…4æiPr^NLº86 Îs8×'*yá¬Ï°'…†“«ìBw7eŠDËÖB“’ã9EÅnJËB+%Œ¸;6YÞBÎ!æ¶Çn^&÷ŠWž¥–r·2ë+sâOfXšë¶«P‹Ãú +™Â%¿-kªæ>_ëm›]MBƒ-9¸É¬Û:‘Pß»±vmsýÆækqžg6"ƒy±Ö¸„R¯–[ÃcNxpW0  *†H†÷  ‚$(î"t|úl³ÑÂ=})Bˆ­‚¥±ŠÐì\‘ ö‚ýÕg`_1õ½ˆ‘p½¸¹ŒˆþSÉT›CÄzCtkݰ±;3EFx£ïTh÷…œäQo¯Û*{{o¨œgØËÉ‘@®Ù¡ŸÝ¦C({ªé„ÛvdBpÉÀ뮄hN„ž~’6î;cëy„¯ÈšÇ4Ó”KÑ(—¾ÑEuÜ5b¬··‡È˜À$1VíÛÆF¿Km¦Õ«Ì`üå7¶S}X•©VÇ÷îàv÷eMSúÿ_v3Zú†’ZúüòŒBm·~·´ðǃ»¢-Ô*c?÷1.@3\F¼›Á¥ENÃ1‚R0‚N0'01 0 U wensaÀ8e«ÜùKЬðlrHÛÆ0  `†He0  *†H†÷ ‚XïPB&ld›E\_ì³EÉÞuÌ®9­"øoÝ2Û“¥_戴[é[)¯{[ÜÕ5²l£?µÚ´ý¦±P¿ Ý«xÀv销#Ro›ë뙆ªGT)D,CnX†‘³íÒ͇—™F ÎqsºsÒ»Ž_­²ìž)]©P†®Ÿ§ð<†hüø ÍúÞ­;= N' •‹p(ÀÀ +tcƒƒÒðë©|M!`ÖK“ØOZêŠ>Õ Û.Ú£§½@ ãüù“9Š1S ´«ˆv˜QÐH¾ò-µ®Æ“Tˆo”ÔÁD²±3~*ú*°"#Áà?¾V \ No newline at end of file diff -Naur --no-dereference a/fs/file.c b/fs/file.c --- a/fs/file.c 2024-05-25 10:22:56.000000000 -0400 +++ b/fs/file.c 2024-07-07 20:37:34.676306709 -0400 @@ -816,6 +816,7 @@ return file; } +EXPORT_SYMBOL_GPL(close_fd_get_file); void do_close_on_exec(struct files_struct *files) { diff -Naur --no-dereference a/fs/proc/array.c b/fs/proc/array.c --- a/fs/proc/array.c 2024-05-25 10:22:56.000000000 -0400 +++ b/fs/proc/array.c 2024-07-07 20:37:34.676306709 -0400 @@ -477,13 +477,13 @@ int permitted; struct mm_struct *mm; unsigned long long start_time; - unsigned long cmin_flt = 0, cmaj_flt = 0; - unsigned long min_flt = 0, maj_flt = 0; - u64 cutime, cstime, utime, stime; - u64 cgtime, gtime; + unsigned long cmin_flt, cmaj_flt, min_flt, maj_flt; + u64 cutime, cstime, cgtime, utime, stime, gtime; unsigned long rsslim = 0; unsigned long flags; int exit_code = task->exit_code; + struct signal_struct *sig = task->signal; + unsigned int seq = 1; state = *get_task_state(task); vsize = eip = esp = 0; @@ -511,12 +511,8 @@ sigemptyset(&sigign); sigemptyset(&sigcatch); - cutime = cstime = 0; - cgtime = gtime = 0; if (lock_task_sighand(task, &flags)) { - struct signal_struct *sig = task->signal; - if (sig->tty) { struct pid *pgrp = tty_get_pgrp(sig->tty); tty_pgrp = pid_nr_ns(pgrp, ns); @@ -527,26 +523,9 @@ num_threads = get_nr_threads(task); collect_sigign_sigcatch(task, &sigign, &sigcatch); - cmin_flt = sig->cmin_flt; - cmaj_flt = sig->cmaj_flt; - cutime = sig->cutime; - cstime = sig->cstime; - cgtime = sig->cgtime; rsslim = READ_ONCE(sig->rlim[RLIMIT_RSS].rlim_cur); - /* add up live thread stats at the group level */ if (whole) { - struct task_struct *t = task; - do { - min_flt += t->min_flt; - maj_flt += t->maj_flt; - gtime += task_gtime(t); - } while_each_thread(task, t); - - min_flt += sig->min_flt; - maj_flt += sig->maj_flt; - gtime += sig->gtime; - if (sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_STOP_STOPPED)) exit_code = sig->group_exit_code; } @@ -561,6 +540,34 @@ if (permitted && (!whole || num_threads < 2)) wchan = !task_is_running(task); + do { + seq++; /* 2 on the 1st/lockless path, otherwise odd */ + flags = read_seqbegin_or_lock_irqsave(&sig->stats_lock, &seq); + + cmin_flt = sig->cmin_flt; + cmaj_flt = sig->cmaj_flt; + cutime = sig->cutime; + cstime = sig->cstime; + cgtime = sig->cgtime; + + if (whole) { + struct task_struct *t; + + min_flt = sig->min_flt; + maj_flt = sig->maj_flt; + gtime = sig->gtime; + + rcu_read_lock(); + __for_each_thread(sig, t) { + min_flt += t->min_flt; + maj_flt += t->maj_flt; + gtime += task_gtime(t); + } + rcu_read_unlock(); + } + } while (need_seqretry(&sig->stats_lock, seq)); + done_seqretry_irqrestore(&sig->stats_lock, seq, flags); + if (whole) { thread_group_cputime_adjusted(task, &utime, &stime); } else { diff -Naur --no-dereference a/.github/FUNDING.yml b/.github/FUNDING.yml --- a/.github/FUNDING.yml 1969-12-31 19:00:00.000000000 -0500 +++ b/.github/FUNDING.yml 2024-07-07 20:37:34.612306389 -0400 @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: beagleboard # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: beagleboard # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: https://paypal.me/beagleboard # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff -Naur --no-dereference a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md --- a/.github/ISSUE_TEMPLATE/bug_report.md 1969-12-31 19:00:00.000000000 -0500 +++ b/.github/ISSUE_TEMPLATE/bug_report.md 2024-07-07 20:37:34.612306389 -0400 @@ -0,0 +1,20 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**Describe how to reproduce the bug** +List all the steps needed to reproduce the bug + +**REQUIRED INFORMATION** +Run this command and paste the output here: +``` +sudo /opt/scripts/tools/version.sh +``` diff -Naur --no-dereference a/.gitlab-ci.yml b/.gitlab-ci.yml --- a/.gitlab-ci.yml 1969-12-31 19:00:00.000000000 -0500 +++ b/.gitlab-ci.yml 2024-07-07 20:37:34.612306389 -0400 @@ -0,0 +1,29 @@ +image: robertcnelson/beagle-devscripts-kernel-debian-12-amd64 +# https://openbeagle.org/beagleboard/ci-docker-images + +cache: + key: "$CI_PROJECT_NAME-ti-linux-arm32-6.6.y" + paths: + - ccache.tar.lz4 + +build: + tags: + - docker-amd64 + stage: build + script: + - mkdir -p /root/.cache/ccache/ || true + - tar --use-compress-program=lz4 -xf ccache.tar.lz4 -C / || true + - ccache -s + - CORES=$(getconf _NPROCESSORS_ONLN) + - make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabihf- clean + - make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabihf- bb.org_defconfig + - echo "make -j${CORES} ARCH=arm KBUILD_DEBARCH=armhf CROSS_COMPILE=/usr/bin/arm-linux-gnueabihf- LOCALVERSION=-ti-arm32-r$CI_JOB_ID KDEB_SOURCENAME=linux-upstream KDEB_COMPRESS=xz bindeb-pkg" + - make -j${CORES} ARCH=arm KBUILD_DEBARCH=armhf KDEB_PKGVERSION=1xross CROSS_COMPILE="ccache /usr/bin/arm-linux-gnueabihf-" LOCALVERSION=-ti-arm32-r$CI_JOB_ID KDEB_SOURCENAME=linux-upstream KDEB_COMPRESS=xz bindeb-pkg + - mv ../*.deb ./ + - ccache -s + - tar --use-compress-program=lz4 -cf ccache.tar.lz4 /root/.cache/ccache/ + artifacts: + expire_in: 28 days + name: "$CI_PROJECT_NAME-$CI_JOB_ID" + paths: + - "linux-image-*.deb" diff -Naur --no-dereference a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h --- a/include/drm/drm_bridge.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/drm/drm_bridge.h 2024-07-07 20:37:34.676306709 -0400 @@ -233,6 +233,7 @@ void (*mode_set)(struct drm_bridge *bridge, const struct drm_display_mode *mode, const struct drm_display_mode *adjusted_mode); + /** * @pre_enable: * @@ -284,6 +285,26 @@ void (*enable)(struct drm_bridge *bridge); /** + * @atomic_early_enable: + * + * This callback should enable the bridge. It is called right before + * the preceding element in the display pipe is enabled. If the + * preceding element is a bridge this means it's called before that + * bridge's @atomic_early_enable. If the preceding element is a + * &drm_crtc it's called right before the crtc's + * &drm_crtc_helper_funcs.atomic_enable hook. + * + * The display pipe (i.e. clocks and timing signals) feeding this bridge + * will not yet be running when this callback is called. The bridge can + * enable the display link feeding the next bridge in the chain (if + * there is one) when this callback is called. + * + * The @atomic_early_enable callback is optional. + */ + void (*atomic_early_enable)(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state); + + /** * @atomic_pre_enable: * * This callback should enable the bridge. It is called right before @@ -360,6 +381,21 @@ struct drm_bridge_state *old_bridge_state); /** + * @atomic_late_disable: + * + * This callback should disable the bridge. It is called right after the + * preceding element in the display pipe is disabled. If the preceding + * element is a bridge this means it's called after that bridge's + * @atomic_late_disable. If the preceding element is a &drm_crtc it's + * called right after the crtc's &drm_crtc_helper_funcs.atomic_disable + * hook. + * + * The @atomic_late_disable callback is optional. + */ + void (*atomic_late_disable)(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state); + + /** * @atomic_duplicate_state: * * Duplicate the current bridge state object (which is guaranteed to be @@ -903,6 +939,10 @@ struct drm_atomic_state *state); void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, struct drm_atomic_state *state); +void drm_atomic_bridge_chain_late_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state); +void drm_atomic_bridge_chain_early_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state); void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, struct drm_atomic_state *state); void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, diff -Naur --no-dereference a/include/dt-bindings/board/am335x-bone-pins.h b/include/dt-bindings/board/am335x-bone-pins.h --- a/include/dt-bindings/board/am335x-bone-pins.h 1969-12-31 19:00:00.000000000 -0500 +++ b/include/dt-bindings/board/am335x-bone-pins.h 2024-07-07 20:37:34.676306709 -0400 @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Deepak Khatri + * See Cape Interface Spec page for more info on Bone Buses + * https://elinux.org/Beagleboard:BeagleBone_cape_interface_spec + */ + +#ifndef _DT_BINDINGS_BOARD_AM335X_BONE_PINS_H +#define _DT_BINDINGS_BOARD_AM335X_BONE_PINS_H + +#define bb_device 0 +#define board_soc AM335X + +#define gpio_P8_03 &gpio1 6 +#define gpio_P8_04 &gpio1 7 +#define gpio_P8_05 &gpio1 2 +#define gpio_P8_06 &gpio1 3 +#define gpio_P8_07 &gpio2 2 +#define gpio_P8_08 &gpio2 3 +#define gpio_P8_09 &gpio2 5 +#define gpio_P8_10 &gpio2 4 +#define gpio_P8_11 &gpio1 13 +#define gpio_P8_12 &gpio1 12 +#define gpio_P8_13 &gpio0 23 +#define gpio_P8_14 &gpio0 26 +#define gpio_P8_15 &gpio1 15 +#define gpio_P8_16 &gpio1 14 +#define gpio_P8_17 &gpio0 27 +#define gpio_P8_18 &gpio2 1 +#define gpio_P8_19 &gpio0 22 +#define gpio_P8_20 &gpio1 31 +#define gpio_P8_21 &gpio1 30 +#define gpio_P8_22 &gpio1 5 +#define gpio_P8_23 &gpio1 4 +#define gpio_P8_24 &gpio1 1 +#define gpio_P8_25 &gpio1 0 +#define gpio_P8_26 &gpio1 29 +#define gpio_P8_27 &gpio2 22 +#define gpio_P8_28 &gpio2 24 +#define gpio_P8_29 &gpio2 23 +#define gpio_P8_30 &gpio2 25 +#define gpio_P8_31 &gpio0 10 +#define gpio_P8_32 &gpio0 11 +#define gpio_P8_33 &gpio0 9 +#define gpio_P8_34 &gpio2 17 +#define gpio_P8_35 &gpio0 8 +#define gpio_P8_36 &gpio2 16 +#define gpio_P8_37 &gpio2 14 +#define gpio_P8_38 &gpio2 15 +#define gpio_P8_39 &gpio2 12 +#define gpio_P8_40 &gpio2 13 +#define gpio_P8_41 &gpio2 10 +#define gpio_P8_42 &gpio2 11 +#define gpio_P8_43 &gpio2 8 +#define gpio_P8_44 &gpio2 9 +#define gpio_P8_45 &gpio2 6 +#define gpio_P8_46 &gpio2 7 +#define gpio_P9_11 &gpio0 30 +#define gpio_P9_12 &gpio1 28 +#define gpio_P9_13 &gpio0 31 +#define gpio_P9_14 &gpio1 18 +#define gpio_P9_15 &gpio1 16 +#define gpio_P9_16 &gpio1 19 +#define gpio_P9_17 &gpio0 5 +#define gpio_P9_18 &gpio0 4 +#define gpio_P9_19 &gpio0 13 +#define gpio_P9_20 &gpio0 12 +#define gpio_P9_21 &gpio0 3 +#define gpio_P9_22 &gpio0 2 +#define gpio_P9_23 &gpio1 17 +#define gpio_P9_24 &gpio0 15 +#define gpio_P9_25 &gpio3 21 +#define gpio_P9_26 &gpio0 14 +#define gpio_P9_27 &gpio3 19 +#define gpio_P9_28 &gpio3 17 +#define gpio_P9_29 &gpio3 15 +#define gpio_P9_30 &gpio3 16 +#define gpio_P9_31 &gpio3 14 +#define gpio_P9_41 &gpio0 20 +#define gpio_P9_41A &gpio0 20 +#define gpio_P9_41B &gpio3 20 +#define gpio_P9_91 &gpio3 20 +#define gpio_P9_42 &gpio0 7 +#define gpio_P9_42A &gpio0 7 +#define gpio_P9_42B &gpio3 18 +#define gpio_P9_92 &gpio3 18 +#define gpio_A15 &gpio0 19 + +#define P8_03(mode) AM33XX_IOPAD(0x0818, mode) /* R9: gpmc_ad6 */ +#define P8_04(mode) AM33XX_IOPAD(0x081c, mode) /* T9: gpmc_ad7 */ +#define P8_05(mode) AM33XX_IOPAD(0x0808, mode) /* R8: gpmc_ad2 */ +#define P8_06(mode) AM33XX_IOPAD(0x080c, mode) /* T8: gpmc_ad3 */ +#define P8_07(mode) AM33XX_IOPAD(0x0890, mode) /* R7: gpmc_advn_ale */ +#define P8_08(mode) AM33XX_IOPAD(0x0894, mode) /* T7: gpmc_oen_ren */ +#define P8_09(mode) AM33XX_IOPAD(0x089c, mode) /* T6: gpmc_be0n_cle */ +#define P8_10(mode) AM33XX_IOPAD(0x0898, mode) /* U6: gpmc_wen */ +#define P8_11(mode) AM33XX_IOPAD(0x0834, mode) /* R12: gpmc_ad13 */ +#define P8_12(mode) AM33XX_IOPAD(0x0830, mode) /* T12: gpmc_ad12 */ +#define P8_13(mode) AM33XX_IOPAD(0x0824, mode) /* T10: gpmc_ad9 */ +#define P8_14(mode) AM33XX_IOPAD(0x0828, mode) /* T11: gpmc_ad10 */ +#define P8_15(mode) AM33XX_IOPAD(0x083c, mode) /* U13: gpmc_ad15 */ +#define P8_16(mode) AM33XX_IOPAD(0x0838, mode) /* V13: gpmc_ad14 */ +#define P8_17(mode) AM33XX_IOPAD(0x082c, mode) /* U12: gpmc_ad11 */ +#define P8_18(mode) AM33XX_IOPAD(0x088c, mode) /* V12: gpmc_clk */ +#define P8_19(mode) AM33XX_IOPAD(0x0820, mode) /* U10: gpmc_ad8 */ +#define P8_20(mode) AM33XX_IOPAD(0x0884, mode) /* V9: gpmc_csn2 */ +#define P8_21(mode) AM33XX_IOPAD(0x0880, mode) /* U9: gpmc_csn1 */ +#define P8_22(mode) AM33XX_IOPAD(0x0814, mode) /* V8: gpmc_ad5 */ +#define P8_23(mode) AM33XX_IOPAD(0x0810, mode) /* U8: gpmc_ad4 */ +#define P8_24(mode) AM33XX_IOPAD(0x0804, mode) /* V7: gpmc_ad1 */ +#define P8_25(mode) AM33XX_IOPAD(0x0800, mode) /* U7: gpmc_ad0 */ +#define P8_26(mode) AM33XX_IOPAD(0x087c, mode) /* V6: gpmc_csn0 */ +#define P8_27(mode) AM33XX_IOPAD(0x08e0, mode) /* U5: lcd_vsync */ +#define P8_28(mode) AM33XX_IOPAD(0x08e8, mode) /* V5: lcd_pclk */ +#define P8_29(mode) AM33XX_IOPAD(0x08e4, mode) /* R5: lcd_hsync */ +#define P8_30(mode) AM33XX_IOPAD(0x08ec, mode) /* R6: lcd_ac_bias_en */ +#define P8_31(mode) AM33XX_IOPAD(0x08d8, mode) /* V4: lcd_data14 */ +#define P8_32(mode) AM33XX_IOPAD(0x08dc, mode) /* T5: lcd_data15 */ +#define P8_33(mode) AM33XX_IOPAD(0x08d4, mode) /* V3: lcd_data13 */ +#define P8_34(mode) AM33XX_IOPAD(0x08cc, mode) /* U4: lcd_data11 */ +#define P8_35(mode) AM33XX_IOPAD(0x08d0, mode) /* V2: lcd_data12 */ +#define P8_36(mode) AM33XX_IOPAD(0x08c8, mode) /* U3: lcd_data10 */ +#define P8_37(mode) AM33XX_IOPAD(0x08c0, mode) /* U1: lcd_data8 */ +#define P8_38(mode) AM33XX_IOPAD(0x08c4, mode) /* U2: lcd_data9 */ +#define P8_39(mode) AM33XX_IOPAD(0x08b8, mode) /* T3: lcd_data6 */ +#define P8_40(mode) AM33XX_IOPAD(0x08bc, mode) /* T4: lcd_data7 */ +#define P8_41(mode) AM33XX_IOPAD(0x08b0, mode) /* T1: lcd_data4 */ +#define P8_42(mode) AM33XX_IOPAD(0x08b4, mode) /* T2: lcd_data5 */ +#define P8_43(mode) AM33XX_IOPAD(0x08a8, mode) /* R3: lcd_data2 */ +#define P8_44(mode) AM33XX_IOPAD(0x08ac, mode) /* R4: lcd_data3 */ +#define P8_45(mode) AM33XX_IOPAD(0x08a0, mode) /* R1: lcd_data0 */ +#define P8_46(mode) AM33XX_IOPAD(0x08a4, mode) /* R2: lcd_data1 */ +#define P9_11(mode) AM33XX_IOPAD(0x0870, mode) /* T17: gpmc_wait0 */ +#define P9_12(mode) AM33XX_IOPAD(0x0878, mode) /* U18: gpmc_be1n */ +#define P9_13(mode) AM33XX_IOPAD(0x0874, mode) /* U17: gpmc_wpn */ +#define P9_14(mode) AM33XX_IOPAD(0x0848, mode) /* U14: gpmc_a2 */ +#define P9_15(mode) AM33XX_IOPAD(0x0840, mode) /* R13: gpmc_a0 */ +#define P9_16(mode) AM33XX_IOPAD(0x084c, mode) /* T14: gpmc_a3 */ +#define P9_17(mode) AM33XX_IOPAD(0x095c, mode) /* A16: spi0_cs0 */ +#define P9_18(mode) AM33XX_IOPAD(0x0958, mode) /* B16: spi0_d1 */ +#define P9_19(mode) AM33XX_IOPAD(0x097c, mode) /* D17: uart1_rtsn */ +#define P9_20(mode) AM33XX_IOPAD(0x0978, mode) /* D18: uart1_ctsn */ +#define P9_21(mode) AM33XX_IOPAD(0x0954, mode) /* B17: spi0_d0 */ +#define P9_22(mode) AM33XX_IOPAD(0x0950, mode) /* A17: spi0_sclk */ +#define P9_23(mode) AM33XX_IOPAD(0x0844, mode) /* V14: gpmc_a1 */ +#define P9_24(mode) AM33XX_IOPAD(0x0984, mode) /* D15: uart1_txd */ +#define P9_25(mode) AM33XX_IOPAD(0x09ac, mode) /* A14: mcasp0_ahclkx */ +#define P9_26(mode) AM33XX_IOPAD(0x0980, mode) /* D16: uart1_rxd */ +#define P9_27(mode) AM33XX_IOPAD(0x09a4, mode) /* C13: mcasp0_fsr */ +#define P9_28(mode) AM33XX_IOPAD(0x099c, mode) /* C12: mcasp0_ahclkr */ +#define P9_29(mode) AM33XX_IOPAD(0x0994, mode) /* B13: mcasp0_fsx */ +#define P9_30(mode) AM33XX_IOPAD(0x0998, mode) /* D12: mcasp0_axr0 */ +#define P9_31(mode) AM33XX_IOPAD(0x0990, mode) /* A13: mcasp0_aclkx */ +#define P9_41(mode) AM33XX_IOPAD(0x09b4, mode) /* D14: xdma_event_intr1 */ +#define P9_41A(mode) AM33XX_IOPAD(0x09b4, mode) /* D14: xdma_event_intr1 */ +#define P9_41B(mode) AM33XX_IOPAD(0x09a8, mode) /* D13: mcasp0_axr1 */ +#define P9_91(mode) AM33XX_IOPAD(0x09a8, mode) /* D13: mcasp0_axr1 */ +#define P9_42(mode) AM33XX_IOPAD(0x0964, mode) /* C18: P0_in_PWM0_out */ +#define P9_42A(mode) AM33XX_IOPAD(0x0964, mode) /* C18: P0_in_PWM0_out */ +#define P9_42B(mode) AM33XX_IOPAD(0x09a0, mode) /* B12: mcasp0_aclkr */ +#define P9_92(mode) AM33XX_IOPAD(0x09a0, mode) /* B12: mcasp0_aclkr */ + +#define gpio_P1_02 &gpio2 23 +#define gpio_P1_04 &gpio2 25 +#define gpio_P1_06 &gpio0 5 +#define gpio_P1_08 &gpio0 2 +#define gpio_P1_10 &gpio0 3 +#define gpio_P1_12 &gpio0 4 +#define gpio_P1_20 &gpio0 20 +#define gpio_P1_26 &gpio0 12 +#define gpio_P1_28 &gpio0 13 +#define gpio_P1_29 &gpio3 21 +#define gpio_P1_30 &gpio1 11 +#define gpio_P1_31 &gpio3 18 +#define gpio_P1_32 &gpio1 10 +#define gpio_P1_33 &gpio3 15 +#define gpio_P1_34 &gpio0 26 +#define gpio_P1_35 &gpio2 24 +#define gpio_P1_36 &gpio3 14 +#define gpio_P2_01 &gpio1 18 +#define gpio_P2_02 &gpio1 27 +#define gpio_P2_03 &gpio0 23 +#define gpio_P2_04 &gpio1 26 +#define gpio_P2_05 &gpio0 30 +#define gpio_P2_06 &gpio1 25 +#define gpio_P2_07 &gpio0 31 +#define gpio_P2_08 &gpio1 28 +#define gpio_P2_09 &gpio0 15 +#define gpio_P2_10 &gpio1 20 +#define gpio_P2_11 &gpio0 14 +#define gpio_P2_17 &gpio2 1 +#define gpio_P2_18 &gpio1 15 +#define gpio_P2_19 &gpio0 27 +#define gpio_P2_20 &gpio2 0 +#define gpio_P2_22 &gpio1 14 +#define gpio_P2_24 &gpio1 12 +#define gpio_P2_25 &gpio1 9 +#define gpio_P2_27 &gpio1 8 +#define gpio_P2_28 &gpio3 20 +#define gpio_P2_29 &gpio0 7 +#define gpio_P2_30 &gpio3 17 +#define gpio_P2_31 &gpio0 19 +#define gpio_P2_32 &gpio3 16 +#define gpio_P2_33 &gpio1 13 +#define gpio_P2_34 &gpio3 19 +#define gpio_P2_35 &gpio2 22 + +#define P1_02(mode) AM33XX_IOPAD(0x08e4, mode) /* R5: lcd_hsync */ +#define P1_04(mode) AM33XX_IOPAD(0x08ec, mode) /* R6: lcd_ac_bias_en */ +#define P1_06(mode) AM33XX_IOPAD(0x095c, mode) /* A16: spi0_cs0 */ +#define P1_08(mode) AM33XX_IOPAD(0x0950, mode) /* A17: spi0_sclk */ +#define P1_10(mode) AM33XX_IOPAD(0x0954, mode) /* B17: spi0_d0 */ +#define P1_12(mode) AM33XX_IOPAD(0x0958, mode) /* B16: spi0_d1 */ +#define P1_20(mode) AM33XX_IOPAD(0x09b4, mode) /* D14: xdma_event_intr1 */ +#define P1_26(mode) AM33XX_IOPAD(0x0978, mode) /* D18: uart1_ctsn */ +#define P1_28(mode) AM33XX_IOPAD(0x097c, mode) /* D17: uart1_rtsn */ +#define P1_29(mode) AM33XX_IOPAD(0x09ac, mode) /* A14: mcasp0_ahclkx */ +#define P1_30(mode) AM33XX_IOPAD(0x0974, mode) /* E16: uart0_txd */ +#define P1_31(mode) AM33XX_IOPAD(0x09a0, mode) /* B12: mcasp0_aclkr */ +#define P1_32(mode) AM33XX_IOPAD(0x0970, mode) /* E15: uart0_rxd */ +#define P1_33(mode) AM33XX_IOPAD(0x0994, mode) /* B13: mcasp0_fsx */ +#define P1_34(mode) AM33XX_IOPAD(0x0828, mode) /* T11: gpmc_ad10 */ +#define P1_35(mode) AM33XX_IOPAD(0x08e8, mode) /* V5: lcd_pclk */ +#define P1_36(mode) AM33XX_IOPAD(0x0990, mode) /* A13: mcasp0_aclkx */ +#define P2_01(mode) AM33XX_IOPAD(0x0848, mode) /* U14: gpmc_a2 */ +#define P2_02(mode) AM33XX_IOPAD(0x086c, mode) /* V17: gpmc_a11 */ +#define P2_03(mode) AM33XX_IOPAD(0x0824, mode) /* T10: gpmc_ad9 */ +#define P2_04(mode) AM33XX_IOPAD(0x0868, mode) /* T16: gpmc_a10 */ +#define P2_05(mode) AM33XX_IOPAD(0x0870, mode) /* T17: gpmc_wait0 */ +#define P2_06(mode) AM33XX_IOPAD(0x0864, mode) /* U16: gpmc_a9 */ +#define P2_07(mode) AM33XX_IOPAD(0x0874, mode) /* U17: gpmc_wpn */ +#define P2_08(mode) AM33XX_IOPAD(0x0878, mode) /* U18: gpmc_be1n */ +#define P2_09(mode) AM33XX_IOPAD(0x0984, mode) /* D15: uart1_txd */ +#define P2_10(mode) AM33XX_IOPAD(0x0850, mode) /* R14: gpmc_a4 */ +#define P2_11(mode) AM33XX_IOPAD(0x0980, mode) /* D16: uart1_rxd */ +#define P2_17(mode) AM33XX_IOPAD(0x088c, mode) /* V12: gpmc_clk */ +#define P2_18(mode) AM33XX_IOPAD(0x083c, mode) /* U13: gpmc_ad15 */ +#define P2_19(mode) AM33XX_IOPAD(0x082c, mode) /* U12: gpmc_ad11 */ +#define P2_20(mode) AM33XX_IOPAD(0x0888, mode) /* T13: gpmc_csn3 */ +#define P2_22(mode) AM33XX_IOPAD(0x0838, mode) /* V13: gpmc_ad14 */ +#define P2_24(mode) AM33XX_IOPAD(0x0830, mode) /* T12: gpmc_ad12 */ +#define P2_25(mode) AM33XX_IOPAD(0x096c, mode) /* E17: uart0_rtsn */ +#define P2_27(mode) AM33XX_IOPAD(0x0968, mode) /* E18: uart0_ctsn */ +#define P2_28(mode) AM33XX_IOPAD(0x09a8, mode) /* D13: mcasp0_axr1 */ +#define P2_29(mode) AM33XX_IOPAD(0x0964, mode) /* C18: eCAP0_in_PWM0_out */ +#define P2_30(mode) AM33XX_IOPAD(0x099c, mode) /* C12: mcasp0_ahclkr */ +#define P2_31(mode) AM33XX_IOPAD(0x09b0, mode) /* A15: xdma_event_intr0 */ +#define P2_32(mode) AM33XX_IOPAD(0x0998, mode) /* D12: mcasp0_axr0 */ +#define P2_33(mode) AM33XX_IOPAD(0x0834, mode) /* R12: gpmc_ad13 */ +#define P2_34(mode) AM33XX_IOPAD(0x09a4, mode) /* C13: mcasp0_fsr */ +#define P2_35(mode) AM33XX_IOPAD(0x08e0, mode) /* U5: lcd_vsync */ + +#endif diff -Naur --no-dereference a/include/dt-bindings/clock/microchip,mpfs-clock.h b/include/dt-bindings/clock/microchip,mpfs-clock.h --- a/include/dt-bindings/clock/microchip,mpfs-clock.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/dt-bindings/clock/microchip,mpfs-clock.h 2024-07-07 20:37:34.676306709 -0400 @@ -44,6 +44,11 @@ #define CLK_RTCREF 33 #define CLK_MSSPLL 34 +#define CLK_MSSPLL0 34 +#define CLK_MSSPLL1 35 +#define CLK_MSSPLL2 36 +#define CLK_MSSPLL3 37 +/* 38 is reserved for MSS PLL internals */ /* Clock Conditioning Circuitry Clock IDs */ diff -Naur --no-dereference a/include/dt-bindings/leds/common.h b/include/dt-bindings/leds/common.h --- a/include/dt-bindings/leds/common.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/dt-bindings/leds/common.h 2024-07-07 20:37:34.680306729 -0400 @@ -46,6 +46,7 @@ #define LED_FUNCTION_CAPSLOCK "capslock" #define LED_FUNCTION_SCROLLLOCK "scrolllock" #define LED_FUNCTION_NUMLOCK "numlock" +#define LED_FUNCTION_FNLOCK "fnlock" /* Obsolete equivalents: "tpacpi::thinklight" (IBM/Lenovo Thinkpads), "lp5523:kb{1,2,3,4,5,6}" (Nokia N900) */ #define LED_FUNCTION_KBD_BACKLIGHT "kbd_backlight" @@ -90,17 +91,24 @@ #define LED_FUNCTION_INDICATOR "indicator" #define LED_FUNCTION_LAN "lan" #define LED_FUNCTION_MAIL "mail" +#define LED_FUNCTION_MOBILE "mobile" #define LED_FUNCTION_MTD "mtd" #define LED_FUNCTION_PANIC "panic" #define LED_FUNCTION_PROGRAMMING "programming" #define LED_FUNCTION_RX "rx" #define LED_FUNCTION_SD "sd" +#define LED_FUNCTION_SPEED_LAN "speed-lan" +#define LED_FUNCTION_SPEED_WAN "speed-wan" #define LED_FUNCTION_STANDBY "standby" #define LED_FUNCTION_TORCH "torch" #define LED_FUNCTION_TX "tx" #define LED_FUNCTION_USB "usb" #define LED_FUNCTION_WAN "wan" +#define LED_FUNCTION_WAN_ONLINE "wan-online" #define LED_FUNCTION_WLAN "wlan" +#define LED_FUNCTION_WLAN_2GHZ "wlan-2ghz" +#define LED_FUNCTION_WLAN_5GHZ "wlan-5ghz" +#define LED_FUNCTION_WLAN_6GHZ "wlan-6ghz" #define LED_FUNCTION_WPS "wps" #endif /* __DT_BINDINGS_LEDS_H */ diff -Naur --no-dereference a/include/dt-bindings/mailbox/miv-ihc.h b/include/dt-bindings/mailbox/miv-ihc.h --- a/include/dt-bindings/mailbox/miv-ihc.h 1969-12-31 19:00:00.000000000 -0500 +++ b/include/dt-bindings/mailbox/miv-ihc.h 2024-07-07 20:37:34.680306729 -0400 @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (c) 2021 Microchip Technology Inc. All rights reserved. + */ + +#ifndef __DT_BINDINGS_MIV_IHC_H +#define __DT_BINDINGS_MIV_IHC_H + +#define IHC_CONTEXT_A 5 +#define IHC_CONTEXT_B 6 + +#define IHC_HART1_INT 180 +#define IHC_HART2_INT 179 +#define IHC_HART3_INT 178 +#define IHC_HART4_INT 177 + +#endif diff -Naur --no-dereference a/include/dt-bindings/mux/ti-serdes.h b/include/dt-bindings/mux/ti-serdes.h --- a/include/dt-bindings/mux/ti-serdes.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/dt-bindings/mux/ti-serdes.h 2024-07-07 20:37:34.680306729 -0400 @@ -6,14 +6,6 @@ #ifndef _DT_BINDINGS_MUX_TI_SERDES #define _DT_BINDINGS_MUX_TI_SERDES -/* - * These bindings are deprecated, because they do not match the actual - * concept of bindings but rather contain pure constants values used only - * in DTS board files. - * Instead include the header in the DTS source directory. - */ -#warning "These bindings are deprecated. Instead, use the header in the DTS source directory." - /* J721E */ #define J721E_SERDES0_LANE0_QSGMII_LANE1 0x0 @@ -107,7 +99,7 @@ #define J721S2_SERDES0_LANE0_EDP_LANE0 0x0 #define J721S2_SERDES0_LANE0_PCIE1_LANE0 0x1 -#define J721S2_SERDES0_LANE0_IP3_UNUSED 0x2 +#define J721S2_SERDES0_LANE0_USB_SWAP 0x2 #define J721S2_SERDES0_LANE0_IP4_UNUSED 0x3 #define J721S2_SERDES0_LANE1_EDP_LANE1 0x0 @@ -117,7 +109,7 @@ #define J721S2_SERDES0_LANE2_EDP_LANE2 0x0 #define J721S2_SERDES0_LANE2_PCIE1_LANE2 0x1 -#define J721S2_SERDES0_LANE2_IP3_UNUSED 0x2 +#define J721S2_SERDES0_LANE2_USB_SWAP 0x2 #define J721S2_SERDES0_LANE2_IP4_UNUSED 0x3 #define J721S2_SERDES0_LANE3_EDP_LANE3 0x0 @@ -187,4 +179,31 @@ #define J784S4_SERDES2_LANE3_IP3_UNUSED 0x2 #define J784S4_SERDES2_LANE3_IP4_UNUSED 0x3 +#define J784S4_SERDES4_LANE0_EDP_LANE0 0x0 +#define J784S4_SERDES4_LANE0_QSGMII_LANE5 0x1 +#define J784S4_SERDES4_LANE0_IP3_UNUSED 0x2 +#define J784S4_SERDES4_LANE0_IP4_UNUSED 0x3 + +#define J784S4_SERDES4_LANE1_EDP_LANE1 0x0 +#define J784S4_SERDES4_LANE1_QSGMII_LANE6 0x1 +#define J784S4_SERDES4_LANE1_IP3_UNUSED 0x2 +#define J784S4_SERDES4_LANE1_IP4_UNUSED 0x3 + +#define J784S4_SERDES4_LANE2_EDP_LANE2 0x0 +#define J784S4_SERDES4_LANE2_QSGMII_LANE7 0x1 +#define J784S4_SERDES4_LANE2_IP3_UNUSED 0x2 +#define J784S4_SERDES4_LANE2_IP4_UNUSED 0x3 + +#define J784S4_SERDES4_LANE3_EDP_LANE3 0x0 +#define J784S4_SERDES4_LANE3_QSGMII_LANE8 0x1 +#define J784S4_SERDES4_LANE3_USB 0x2 +#define J784S4_SERDES4_LANE3_IP4_UNUSED 0x3 + +/* J722S */ +#define J722S_SERDES0_LANE0_USB 0x0 +#define J722S_SERDES0_LANE0_QSGMII_LANE2 0x1 + +#define J722S_SERDES1_LANE0_PCIE0_LANE0 0x0 +#define J722S_SERDES1_LANE0_QSGMII_LANE1 0x1 + #endif /* _DT_BINDINGS_MUX_TI_SERDES */ diff -Naur --no-dereference a/include/dt-bindings/net/ti-dp83867.h b/include/dt-bindings/net/ti-dp83867.h --- a/include/dt-bindings/net/ti-dp83867.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/dt-bindings/net/ti-dp83867.h 2024-07-07 20:37:34.680306729 -0400 @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ /* * Device Tree constants for the Texas Instruments DP83867 PHY * * Author: Dan Murphy * - * Copyright: (C) 2015 Texas Instruments, Inc. + * Copyright (C) 2015-2024 Texas Instruments Incorporated - https://www.ti.com/ */ #ifndef _DT_BINDINGS_TI_DP83867_H diff -Naur --no-dereference a/include/dt-bindings/net/ti-dp83869.h b/include/dt-bindings/net/ti-dp83869.h --- a/include/dt-bindings/net/ti-dp83869.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/dt-bindings/net/ti-dp83869.h 2024-07-07 20:37:34.680306729 -0400 @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ /* * Device Tree constants for the Texas Instruments DP83869 PHY * * Author: Dan Murphy * - * Copyright: (C) 2019 Texas Instruments, Inc. + * Copyright (C) 2015-2024 Texas Instruments Incorporated - https://www.ti.com/ */ #ifndef _DT_BINDINGS_TI_DP83869_H diff -Naur --no-dereference a/include/dt-bindings/pinctrl/omap.h b/include/dt-bindings/pinctrl/omap.h --- a/include/dt-bindings/pinctrl/omap.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/dt-bindings/pinctrl/omap.h 2024-07-07 20:37:34.680306729 -0400 @@ -64,8 +64,12 @@ #define OMAP3_WKUP_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x2a00) (val) #define DM814X_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x0800) (val) #define DM816X_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x0800) (val) -#define AM33XX_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x0800) (val) (0) -#define AM33XX_PADCONF(pa, conf, mux) OMAP_IOPAD_OFFSET((pa), 0x0800) (conf) (mux) +//Mainline +//#define AM33XX_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x0800) (val) (0) +//#define AM33XX_PADCONF(pa, conf, mux) OMAP_IOPAD_OFFSET((pa), 0x0800) (conf) (mux) +//BeagleBoard.org (compabitliy with ancient overlays) +#define AM33XX_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x0800) (val) +#define AM33XX_PADCONF(pa, dir, mux) OMAP_IOPAD_OFFSET((pa), 0x0800) ((dir) | (mux)) /* * Macros to allow using the offset from the padconf physical address diff -Naur --no-dereference a/include/linux/crc64.h b/include/linux/crc64.h --- a/include/linux/crc64.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/crc64.h 2024-07-07 20:37:34.680306729 -0400 @@ -7,9 +7,11 @@ #include +#define CRC64_ISO3309_STRING "crc64-iso3309" #define CRC64_ROCKSOFT_STRING "crc64-rocksoft" u64 __pure crc64_be(u64 crc, const void *p, size_t len); +u64 __pure crc64_iso3309_generic(u64 crc, const void *p, size_t len); u64 __pure crc64_rocksoft_generic(u64 crc, const void *p, size_t len); u64 crc64_rocksoft(const unsigned char *buffer, size_t len); diff -Naur --no-dereference a/include/linux/dma/k3-udma-glue.h b/include/linux/dma/k3-udma-glue.h --- a/include/linux/dma/k3-udma-glue.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/dma/k3-udma-glue.h 2024-07-07 20:37:34.680306729 -0400 @@ -26,6 +26,11 @@ struct k3_udma_glue_tx_channel *k3_udma_glue_request_tx_chn(struct device *dev, const char *name, struct k3_udma_glue_tx_channel_cfg *cfg); +struct k3_udma_glue_tx_channel * +k3_udma_glue_request_tx_chn_for_thread_id(struct device *dev, + struct k3_udma_glue_tx_channel_cfg *cfg, + struct device_node *udmax_np, u32 thread_id); + void k3_udma_glue_release_tx_chn(struct k3_udma_glue_tx_channel *tx_chn); int k3_udma_glue_push_tx_chn(struct k3_udma_glue_tx_channel *tx_chn, struct cppi5_host_desc_t *desc_tx, @@ -109,6 +114,11 @@ const char *name, struct k3_udma_glue_rx_channel_cfg *cfg); +struct k3_udma_glue_rx_channel * +k3_udma_glue_request_remote_rx_chn_for_thread_id(struct device *dev, + struct k3_udma_glue_rx_channel_cfg *cfg, + struct device_node *udmax_np, u32 thread_id); + void k3_udma_glue_release_rx_chn(struct k3_udma_glue_rx_channel *rx_chn); int k3_udma_glue_enable_rx_chn(struct k3_udma_glue_rx_channel *rx_chn); void k3_udma_glue_disable_rx_chn(struct k3_udma_glue_rx_channel *rx_chn); diff -Naur --no-dereference a/include/linux/etherdevice.h b/include/linux/etherdevice.h --- a/include/linux/etherdevice.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/etherdevice.h 2024-07-07 20:37:34.680306729 -0400 @@ -71,6 +71,12 @@ { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; #define eth_stp_addr eth_reserved_addr_base +static const u8 eth_ipv4_mcast_addr_base[ETH_ALEN] __aligned(2) = +{ 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; + +static const u8 eth_ipv6_mcast_addr_base[ETH_ALEN] __aligned(2) = +{ 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; + /** * is_link_local_ether_addr - Determine if given Ethernet address is link-local * @addr: Pointer to a six-byte array containing the Ethernet address @@ -430,18 +436,16 @@ static inline bool ether_addr_is_ipv4_mcast(const u8 *addr) { - u8 base[ETH_ALEN] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; u8 mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 }; - return ether_addr_equal_masked(addr, base, mask); + return ether_addr_equal_masked(addr, eth_ipv4_mcast_addr_base, mask); } static inline bool ether_addr_is_ipv6_mcast(const u8 *addr) { - u8 base[ETH_ALEN] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; u8 mask[ETH_ALEN] = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }; - return ether_addr_equal_masked(addr, base, mask); + return ether_addr_equal_masked(addr, eth_ipv6_mcast_addr_base, mask); } static inline bool ether_addr_is_ip_mcast(const u8 *addr) diff -Naur --no-dereference a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h --- a/include/linux/gpio_keys.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/gpio_keys.h 2024-07-07 20:37:34.680306729 -0400 @@ -21,6 +21,7 @@ * disable button via sysfs * @value: axis value for %EV_ABS * @irq: Irq number in case of interrupt keys + * @wakeirq: Optional dedicated wake-up interrupt */ struct gpio_keys_button { unsigned int code; @@ -34,6 +35,7 @@ bool can_disable; int value; unsigned int irq; + unsigned int wakeirq; }; /** diff -Naur --no-dereference a/include/linux/linux_logo.h b/include/linux/linux_logo.h --- a/include/linux/linux_logo.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/linux_logo.h 2024-07-07 20:37:34.680306729 -0400 @@ -45,6 +45,7 @@ extern const struct linux_logo logo_superh_vga16; extern const struct linux_logo logo_superh_clut224; extern const struct linux_logo logo_spe_clut224; +extern const struct linux_logo logo_beagle_clut224; extern const struct linux_logo *fb_find_logo(int depth); #ifdef CONFIG_FB_LOGO_EXTRA diff -Naur --no-dereference a/include/linux/math.h b/include/linux/math.h --- a/include/linux/math.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/math.h 2024-07-07 20:37:34.680306729 -0400 @@ -34,6 +34,52 @@ */ #define round_down(x, y) ((x) & ~__round_mask(x, y)) +/** + * round_closest_up - round closest to be multiple of specified value (which is + * power of 2) with preference to rounding up + * @x: the value to round + * @y: multiple to round closest to (must be a power of 2) + * + * Rounds @x to closest multiple of @y (which must be a power of 2). + * The value can be either rounded up or rounded down depending upon rounded + * value's closeness to the specified value. If there are two closest possible + * values, i.e. the difference between the specified value and it's rounded up + * and rounded down values is same then preference is given to rounded up + * value. + * + * To perform arbitrary rounding to closest value (not multiple of 2), use + * roundclosest(). + * + * Examples: + * * round_closest_up(17, 4) = 16 + * * round_closest_up(15, 4) = 16 + * * round_closest_up(14, 4) = 16 + */ +#define round_closest_up(x, y) round_down((x) + (y) / 2, (y)) + +/** + * round_closest_down - round closest to be multiple of specified value (which + * is power of 2) with preference to rounding down + * @x: the value to round + * @y: multiple to round closest to (must be a power of 2) + * + * Rounds @x to closest multiple of @y (which must be a power of 2). + * The value can be either rounded up or rounded down depending upon rounded + * value's closeness to the specified value. If there are two closest possible + * values, i.e. the difference between the specified value and it's rounded up + * and rounded down values is same then preference is given to rounded up + * value. + * + * To perform arbitrary rounding to closest value (not multiple of 2), use + * roundclosest(). + * + * Examples: + * * round_closest_down(17, 4) = 16 + * * round_closest_down(15, 4) = 16 + * * round_closest_down(14, 4) = 12 + */ +#define round_closest_down(x, y) round_up((x) - (y) / 2, (y)) + #define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP #define DIV_ROUND_DOWN_ULL(ll, d) \ @@ -77,9 +123,31 @@ } \ ) -/* - * Divide positive or negative dividend by positive or negative divisor - * and round to closest integer. Result is undefined for negative +/** + * roundclosest - round to nearest multiple + * @x: the value to round + * @y: multiple to round nearest to + * + * Rounds @x to nearest multiple of @y. + * The rounded value can be greater than or less than @x depending + * upon it's nearness to @x. If @y will always be a power of 2, consider + * using the faster round_closest_up() or round_closest_down(). + * + * Examples: + * * roundclosest(21, 5) = 20 + * * roundclosest(19, 5) = 20 + * * roundclosest(17, 5) = 15 + */ +#define roundclosest(x, y) rounddown((x) + (y) / 2, (y)) + +/** + * DIV_ROUND_CLOSEST - Divide positive or negative dividend by positive or + * negative divisor and round to closest value + * @x: dividend value + * @divisor: divisor value + * + * Divide positive or negative dividend value @x by positive or negative + * @divisor value and round to closest integer. Result is undefined for negative * divisors if the dividend variable type is unsigned and for negative * dividends if the divisor variable type is unsigned. */ @@ -94,9 +162,15 @@ (((__x) - ((__d) / 2)) / (__d)); \ } \ ) -/* - * Same as above but for u64 dividends. divisor must be a 32-bit - * number. + +/** + * DIV_ROUND_CLOSEST_ULL - Divide 64-bit unsigned dividend by 32-bit divisor and + * round to closest value + * @x: unsigned 64-bit dividend + * @divisor: 32-bit divisor + * + * Divide unsigned 64-bit dividend value @x by 32-bit @divisor value + * and round to closest integer. Result is undefined for negative divisors. */ #define DIV_ROUND_CLOSEST_ULL(x, divisor)( \ { \ diff -Naur --no-dereference a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h --- a/include/linux/mtd/spinand.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/mtd/spinand.h 2024-07-07 20:37:34.680306729 -0400 @@ -122,6 +122,12 @@ SPI_MEM_OP_DUMMY(ndummy, 4), \ SPI_MEM_OP_DATA_IN(len, buf, 4)) +#define SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_OP(addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xcb, 1), \ + SPI_MEM_OP_ADDR(2, addr, 8), \ + SPI_MEM_OP_DUMMY(ndummy, 8), \ + SPI_MEM_OP_DATA_IN(len, buf, 8)) + #define SPINAND_PROG_EXEC_OP(addr) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1), \ SPI_MEM_OP_ADDR(3, addr, 1), \ @@ -140,6 +146,12 @@ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(len, buf, 4)) +#define SPINAND_PROG_LOAD_OCTALIO(reset, addr, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0xc2 : 0xc4, 1), \ + SPI_MEM_OP_ADDR(2, addr, 8), \ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_DATA_OUT(len, buf, 8)) + /** * Standard SPI NAND flash commands */ diff -Naur --no-dereference a/include/linux/mux/driver.h b/include/linux/mux/driver.h --- a/include/linux/mux/driver.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/mux/driver.h 2024-07-07 20:37:34.680306729 -0400 @@ -88,6 +88,7 @@ int mux_chip_register(struct mux_chip *mux_chip); void mux_chip_unregister(struct mux_chip *mux_chip); void mux_chip_free(struct mux_chip *mux_chip); +int mux_chip_resume(struct mux_chip *mux_chip); struct mux_chip *devm_mux_chip_alloc(struct device *dev, unsigned int controllers, diff -Naur --no-dereference a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h --- a/include/linux/power/bq27xxx_battery.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/power/bq27xxx_battery.h 2024-07-07 20:37:34.680306729 -0400 @@ -61,7 +61,6 @@ struct bq27xxx_device_info { struct device *dev; - int id; enum bq27xxx_chip chip; u32 opts; const char *name; diff -Naur --no-dereference a/include/linux/reboot.h b/include/linux/reboot.h --- a/include/linux/reboot.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/reboot.h 2024-07-07 20:37:34.680306729 -0400 @@ -129,11 +129,14 @@ * @cb_data: User's callback data. * @cmd: Command string. Currently used only by the sys-off restart mode, * NULL otherwise. + * @dev: Device of the sys-off handler. Only if known (devm_register_*), + * NULL otherwise. */ struct sys_off_data { int mode; void *cb_data; const char *cmd; + struct device *dev; }; struct sys_off_handler * diff -Naur --no-dereference a/include/linux/remoteproc.h b/include/linux/remoteproc.h --- a/include/linux/remoteproc.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/remoteproc.h 2024-07-07 20:37:34.680306729 -0400 @@ -42,6 +42,7 @@ #include #include #include +#include /** * struct resource_table - firmware resource table header @@ -562,6 +563,7 @@ struct list_head traces; int num_traces; struct list_head carveouts; + struct list_head dmabufs; struct list_head mappings; u64 bootaddr; struct list_head rvdevs; @@ -584,7 +586,7 @@ u8 elf_class; u16 elf_machine; struct cdev cdev; - bool cdev_put_on_release; + struct device_dma_parameters dma_parms; DECLARE_BITMAP(features, RPROC_MAX_FEATURES); }; @@ -673,6 +675,10 @@ void rproc_add_carveout(struct rproc *rproc, struct rproc_mem_entry *mem); +int rproc_attach_dmabuf(struct rproc *rproc, struct dma_buf *dmabuf); +int rproc_dmabuf_get_da(struct rproc *rproc, struct dma_buf *dmabuf, dma_addr_t *dma); +int rproc_detach_dmabuf(struct rproc *rproc, struct dma_buf *dmabuf); + struct rproc_mem_entry * rproc_mem_entry_init(struct device *dev, void *va, dma_addr_t dma, size_t len, u32 da, diff -Naur --no-dereference a/include/linux/soc/ti/k3-ringacc.h b/include/linux/soc/ti/k3-ringacc.h --- a/include/linux/soc/ti/k3-ringacc.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/soc/ti/k3-ringacc.h 2024-07-07 20:37:34.680306729 -0400 @@ -8,6 +8,7 @@ #ifndef __SOC_TI_K3_RINGACC_API_H_ #define __SOC_TI_K3_RINGACC_API_H_ +#include #include struct device_node; diff -Naur --no-dereference a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h --- a/include/linux/soc/ti/ti_sci_protocol.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/soc/ti/ti_sci_protocol.h 2024-07-07 20:37:34.680306729 -0400 @@ -195,6 +195,49 @@ u64 *current_freq); }; +/* TISCI LPM wake up sources */ +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_WKUP_I2C0 0x00 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_WKUP_UART0 0x10 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_MCU_GPIO0 0x20 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_WKUP_ICEMELTER0 0x30 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_WKUP_TIMER0 0x40 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_WKUP_TIMER1 0x41 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_WKUP_RTC0 0x50 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_RESET 0x60 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_USB0 0x70 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_USB1 0x71 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_MAIN_IO 0x80 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_MCU_IO 0x81 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_CAN_IO 0x82 +#define TISCI_MSG_VALUE_LPM_WAKE_SOURCE_INVALID 0xFF + +/* TISCI LPM IO isolation control values */ +#define TISCI_MSG_VALUE_IO_ENABLE 1 +#define TISCI_MSG_VALUE_IO_DISABLE 0 + +/** + * struct ti_sci_pm_ops - Low Power Mode (LPM) control operations + * @prepare_sleep: Prepare to enter low power mode + * - mode: Low power mode to enter. + * - ctx_lo: Low 32-bits of physical address for context save. + * - ctx_hi: High 32-bits of physical address for context save. + * - ctx_lo: 'true' if frequency change is desired. + * - debug_flags: JTAG control flags for debug. + * @lpm_wake_reason: Get the wake up source that woke the SoC from LPM + * - source: The wake up source that woke soc from LPM. + * - timestamp: Timestamp at which soc woke. + * @set_io_isolation: Enable or disable IO isolation + * - state: The desired state of the IO isolation. + */ +struct ti_sci_pm_ops { + int (*prepare_sleep)(const struct ti_sci_handle *handle, u8 mode, + u32 ctx_lo, u32 ctx_hi, u32 flags); + int (*lpm_wake_reason)(const struct ti_sci_handle *handle, + u32 *source, u64 *timestamp); + int (*set_io_isolation)(const struct ti_sci_handle *handle, + u8 state); +}; + /** * struct ti_sci_resource_desc - Description of TI SCI resource instance range. * @start: Start index of the first resource range. @@ -539,6 +582,7 @@ struct ti_sci_core_ops core_ops; struct ti_sci_dev_ops dev_ops; struct ti_sci_clk_ops clk_ops; + struct ti_sci_pm_ops pm_ops; struct ti_sci_rm_core_ops rm_core_ops; struct ti_sci_rm_irq_ops rm_irq_ops; struct ti_sci_rm_ringacc_ops rm_ring_ops; diff -Naur --no-dereference a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h --- a/include/linux/spi/spi-mem.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/spi/spi-mem.h 2024-07-07 20:37:34.680306729 -0400 @@ -259,6 +259,12 @@ * @poll_status: poll memory device status until (status & mask) == match or * when the timeout has expired. It fills the data buffer with * the last status value. + * @do_calibration: perform calibration needed for high SPI clock speed + * operation. Should be called after the SPI memory device has + * been completely initialized. The op passed should contain + * a template for the read operation used for the device so + * the controller can decide what type of calibration is + * required for this type of read. * * This interface should be implemented by SPI controllers providing an * high-level interface to execute SPI memory operation, which is usually the @@ -289,6 +295,8 @@ unsigned long initial_delay_us, unsigned long polling_rate_us, unsigned long timeout_ms); + void (*do_calibration)(struct spi_mem *mem, + const struct spi_mem_op *op); }; /** @@ -363,6 +371,7 @@ #endif /* CONFIG_SPI_MEM */ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op); +int spi_mem_do_calibration(struct spi_mem *mem, const struct spi_mem_op *op); bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op); diff -Naur --no-dereference a/include/linux/units.h b/include/linux/units.h --- a/include/linux/units.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/linux/units.h 2024-07-07 20:37:34.680306729 -0400 @@ -31,6 +31,10 @@ #define MICROWATT_PER_MILLIWATT 1000UL #define MICROWATT_PER_WATT 1000000UL +#define BYTES_PER_KBIT (KILO / BITS_PER_BYTE) +#define BYTES_PER_MBIT (MEGA / BITS_PER_BYTE) +#define BYTES_PER_GBIT (GIGA / BITS_PER_BYTE) + #define ABSOLUTE_ZERO_MILLICELSIUS -273150 static inline long milli_kelvin_to_millicelsius(long t) diff -Naur --no-dereference a/include/media/v4l2-jpeg.h b/include/media/v4l2-jpeg.h --- a/include/media/v4l2-jpeg.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/media/v4l2-jpeg.h 2024-07-07 20:37:34.680306729 -0400 @@ -14,6 +14,30 @@ #define V4L2_JPEG_MAX_COMPONENTS 4 #define V4L2_JPEG_MAX_TABLES 4 +/* + * Prefixes used to generate huffman table class and destination identifiers as + * described below: + * + * V4L2_JPEG_LUM_HT | V4L2_JPEG_DC_HT : Prefix for Luma DC coefficients + * huffman table + * V4L2_JPEG_LUM_HT | V4L2_JPEG_AC_HT : Prefix for Luma AC coefficients + * huffman table + * V4L2_JPEG_CHR_HT | V4L2_JPEG_DC_HT : Prefix for Chroma DC coefficients + * huffman table + * V4L2_JPEG_CHR_HT | V4L2_JPEG_AC_HT : Prefix for Chroma AC coefficients + * huffman table + */ +#define V4L2_JPEG_LUM_HT 0x00 +#define V4L2_JPEG_CHR_HT 0x01 +#define V4L2_JPEG_DC_HT 0x00 +#define V4L2_JPEG_AC_HT 0x10 + +/* Length of reference huffman tables as provided in Table K.3 of ITU-T.81 */ +#define V4L2_JPEG_REF_HT_AC_LEN 178 +#define V4L2_JPEG_REF_HT_DC_LEN 28 + +/* Array size for 8x8 block of samples or DCT coefficient */ +#define V4L2_JPEG_PIXELS_IN_BLOCK 64 /** * struct v4l2_jpeg_reference - reference into the JPEG buffer @@ -154,4 +178,8 @@ int v4l2_jpeg_parse_huffman_tables(void *buf, size_t len, struct v4l2_jpeg_reference *huffman_tables); +void v4l2_jpeg_get_reference_quantization_tables(const u8 **luma_qt, const u8 **chroma_qt); +void v4l2_jpeg_get_zig_zag_scan(const u8 **zigzag); +void v4l2_jpeg_get_reference_huffman_tables(const u8 **luma_dc_ht, const u8 **luma_ac_ht, + const u8 **chroma_dc_ht, const u8 **chroma_ac_ht); #endif diff -Naur --no-dereference a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h --- a/include/media/v4l2-mem2mem.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/media/v4l2-mem2mem.h 2024-07-07 20:37:34.680306729 -0400 @@ -84,6 +84,12 @@ * @last_src_buf: indicate the last source buffer for draining * @next_buf_last: next capture queud buffer will be tagged as last * @has_stopped: indicate the device has been stopped + * @ignore_cap_streaming: If true, job_ready can be called even if the CAPTURE + * queue is not streaming. This allows firmware to + * analyze the bitstream header which arrives on the + * OUTPUT queue. The driver must implement the job_ready + * callback correctly to make sure that the requirements + * for actual decoding are met. * @m2m_dev: opaque pointer to the internal data to handle M2M context * @cap_q_ctx: Capture (output to memory) queue context * @out_q_ctx: Output (input from memory) queue context @@ -106,6 +112,7 @@ struct vb2_v4l2_buffer *last_src_buf; bool next_buf_last; bool has_stopped; + bool ignore_cap_streaming; /* internal use only */ struct v4l2_m2m_dev *m2m_dev; diff -Naur --no-dereference a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h --- a/include/sound/dmaengine_pcm.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/sound/dmaengine_pcm.h 2024-07-07 20:37:34.680306729 -0400 @@ -36,6 +36,7 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, struct dma_chan *chan); int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream); +int snd_dmaengine_pcm_prepare(struct snd_pcm_substream *substream); int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, dma_filter_fn filter_fn, void *filter_data); diff -Naur --no-dereference a/include/uapi/linux/counter.h b/include/uapi/linux/counter.h --- a/include/uapi/linux/counter.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/uapi/linux/counter.h 2024-07-07 20:37:34.680306729 -0400 @@ -65,6 +65,10 @@ COUNTER_EVENT_CHANGE_OF_STATE, /* Count value captured */ COUNTER_EVENT_CAPTURE, + /* Direction change detected */ + COUNTER_EVENT_DIRECTION_CHANGE, + /* Timer exceeded timeout */ + COUNTER_EVENT_TIMEOUT, }; /** diff -Naur --no-dereference a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h --- a/include/uapi/linux/input-event-codes.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/uapi/linux/input-event-codes.h 2024-07-07 20:37:34.680306729 -0400 @@ -547,6 +547,7 @@ #define KEY_FN_S 0x1e3 #define KEY_FN_B 0x1e4 #define KEY_FN_RIGHT_SHIFT 0x1e5 +#define KEY_FN_R 0x1e6 #define KEY_BRL_DOT1 0x1f1 #define KEY_BRL_DOT2 0x1f2 @@ -618,6 +619,8 @@ #define KEY_CAMERA_ACCESS_ENABLE 0x24b /* Enables programmatic access to camera devices. (HUTRR72) */ #define KEY_CAMERA_ACCESS_DISABLE 0x24c /* Disables programmatic access to camera devices. (HUTRR72) */ #define KEY_CAMERA_ACCESS_TOGGLE 0x24d /* Toggles the current state of the camera access control. (HUTRR72) */ +#define KEY_ACCESSIBILITY 0x24e /* Toggles the system bound accessibility UI/command (HUTRR116) */ +#define KEY_DO_NOT_DISTURB 0x24f /* Toggles the system-wide "Do Not Disturb" control (HUTRR94)*/ #define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ #define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ diff -Naur --no-dereference a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h --- a/include/uapi/linux/media-bus-format.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/uapi/linux/media-bus-format.h 2024-07-07 20:37:34.680306729 -0400 @@ -120,7 +120,7 @@ #define MEDIA_BUS_FMT_YUV16_1X48 0x202a #define MEDIA_BUS_FMT_UYYVYY16_0_5X48 0x202b -/* Bayer - next is 0x3021 */ +/* Bayer - next is 0x3029 */ #define MEDIA_BUS_FMT_SBGGR8_1X8 0x3001 #define MEDIA_BUS_FMT_SGBRG8_1X8 0x3013 #define MEDIA_BUS_FMT_SGRBG8_1X8 0x3002 @@ -153,6 +153,14 @@ #define MEDIA_BUS_FMT_SGBRG16_1X16 0x301e #define MEDIA_BUS_FMT_SGRBG16_1X16 0x301f #define MEDIA_BUS_FMT_SRGGB16_1X16 0x3020 +#define MEDIA_BUS_FMT_SRGGI10_1X10 0x3021 +#define MEDIA_BUS_FMT_SGRIG10_1X10 0x3022 +#define MEDIA_BUS_FMT_SBGGI10_1X10 0x3023 +#define MEDIA_BUS_FMT_SGBIG10_1X10 0x3024 +#define MEDIA_BUS_FMT_SGIRG10_1X10 0x3025 +#define MEDIA_BUS_FMT_SIGGR10_1X10 0x3026 +#define MEDIA_BUS_FMT_SGIBG10_1X10 0x3027 +#define MEDIA_BUS_FMT_SIGGB10_1X10 0x3028 /* JPEG compressed formats - next is 0x4002 */ #define MEDIA_BUS_FMT_JPEG_1X8 0x4001 diff -Naur --no-dereference a/include/uapi/linux/remoteproc_cdev.h b/include/uapi/linux/remoteproc_cdev.h --- a/include/uapi/linux/remoteproc_cdev.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/uapi/linux/remoteproc_cdev.h 2024-07-07 20:37:34.680306729 -0400 @@ -34,4 +34,22 @@ */ #define RPROC_GET_SHUTDOWN_ON_RELEASE _IOR(RPROC_MAGIC, 2, __s32) +/** + * struct rproc_dma_buf_attach_data - metadata passed from userspace + * @fd: DMA-BUF fd + * @da: populated with device address of DMA-BUF + */ +struct rproc_dma_buf_attach_data { + __u32 fd; + __u64 da; +}; + +/** + * DOC: RPROC_IOC_DMA_BUF_ATTACH - Attach and map DMA-BUF a remote processor + * + * Takes a rproc_dma_buf_data struct containing a fd for a physicaly contigous + * buffer. Pins this buffer and populates phys field with the device address. + */ +#define RPROC_IOC_DMA_BUF_ATTACH _IOWR(RPROC_MAGIC, 0, struct rproc_dma_buf_attach_data) + #endif diff -Naur --no-dereference a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h --- a/include/uapi/linux/v4l2-controls.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/uapi/linux/v4l2-controls.h 2024-07-07 20:37:34.680306729 -0400 @@ -110,8 +110,10 @@ #define V4L2_CID_COLORFX_CBCR (V4L2_CID_BASE+42) #define V4L2_CID_COLORFX_RGB (V4L2_CID_BASE+43) +#define V4L2_CID_IR_EXPOSURE (V4L2_CID_BASE+44) + /* last CID + 1 */ -#define V4L2_CID_LASTP1 (V4L2_CID_BASE+44) +#define V4L2_CID_LASTP1 (V4L2_CID_BASE+45) /* USER-class private control IDs */ @@ -1199,6 +1201,7 @@ #define V4L2_CID_TEST_PATTERN_GREENB (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7) #define V4L2_CID_UNIT_CELL_SIZE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 8) #define V4L2_CID_NOTIFY_GAINS (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 9) +#define V4L2_CID_IR_ANALOGUE_GAIN (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 10) /* Image processing controls */ @@ -1211,6 +1214,7 @@ #define V4L2_CID_TEST_PATTERN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 3) #define V4L2_CID_DEINTERLACING_MODE (V4L2_CID_IMAGE_PROC_CLASS_BASE + 4) #define V4L2_CID_DIGITAL_GAIN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 5) +#define V4L2_CID_IR_DIGITAL_GAIN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 6) /* DV-class control IDs defined by V4L2 */ #define V4L2_CID_DV_CLASS_BASE (V4L2_CTRL_CLASS_DV | 0x900) diff -Naur --no-dereference a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h --- a/include/uapi/linux/videodev2.h 2024-05-25 10:22:56.000000000 -0400 +++ b/include/uapi/linux/videodev2.h 2024-07-07 20:37:34.680306729 -0400 @@ -729,6 +729,15 @@ #define V4L2_PIX_FMT_SGBRG16 v4l2_fourcc('G', 'B', '1', '6') /* 16 GBGB.. RGRG.. */ #define V4L2_PIX_FMT_SGRBG16 v4l2_fourcc('G', 'R', '1', '6') /* 16 GRGR.. BGBG.. */ #define V4L2_PIX_FMT_SRGGB16 v4l2_fourcc('R', 'G', '1', '6') /* 16 RGRG.. GBGB.. */ + /* 10bit raw bayer with IR (4x4) */ +#define V4L2_PIX_FMT_SRGGI10 v4l2_fourcc('R', 'G', 'I', '0') /* 10 RGBG.. GIrGIr.. */ +#define V4L2_PIX_FMT_SGRIG10 v4l2_fourcc('G', 'R', 'I', '0') /* 10 GRGB.. IrGIrG.. */ +#define V4L2_PIX_FMT_SBGGI10 v4l2_fourcc('B', 'G', 'I', '0') /* 10 BGRG.. GIrGIr.. */ +#define V4L2_PIX_FMT_SGBIG10 v4l2_fourcc('G', 'B', 'I', '0') /* 10 GBGR.. IrGIrG.. */ +#define V4L2_PIX_FMT_SGIRG10 v4l2_fourcc('G', 'I', 'R', '0') /* 10 GIrGIr.. RGBG.. */ +#define V4L2_PIX_FMT_SIGGR10 v4l2_fourcc('I', 'G', 'R', '0') /* 10 IrGIrG.. GRGB.. */ +#define V4L2_PIX_FMT_SGIBG10 v4l2_fourcc('G', 'I', 'B', '0') /* 10 GIrGIr.. BGRG.. */ +#define V4L2_PIX_FMT_SIGGB10 v4l2_fourcc('I', 'G', 'B', '0') /* 10 IrGIrG.. GBGR.. */ /* HSV formats */ #define V4L2_PIX_FMT_HSV24 v4l2_fourcc('H', 'S', 'V', '3') @@ -804,6 +813,8 @@ #define V4L2_PIX_FMT_QC08C v4l2_fourcc('Q', '0', '8', 'C') /* Qualcomm 8-bit compressed */ #define V4L2_PIX_FMT_QC10C v4l2_fourcc('Q', '1', '0', 'C') /* Qualcomm 10-bit compressed */ #define V4L2_PIX_FMT_AJPG v4l2_fourcc('A', 'J', 'P', 'G') /* Aspeed JPEG */ +#define V4L2_PIX_FMT_TI1210 v4l2_fourcc('T', 'I', '1', '2') /* TI NV12 10-bit, two bytes per channel */ +#define V4L2_PIX_FMT_TI1610 v4l2_fourcc('T', 'I', '1', '6') /* TI NV16 10-bit, two bytes per channel */ /* 10bit raw packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */ #define V4L2_PIX_FMT_IPU3_SBGGR10 v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */ diff -Naur --no-dereference a/kernel/configs/no_smp.config b/kernel/configs/no_smp.config --- a/kernel/configs/no_smp.config 1969-12-31 19:00:00.000000000 -0500 +++ b/kernel/configs/no_smp.config 2024-07-07 20:37:34.680306729 -0400 @@ -0,0 +1,6 @@ +################################################## +# NO SMP Config +################################################## + +CONFIG_SMP=n +CONFIG_CPUSETS=n diff -Naur --no-dereference a/kernel/configs/ti_arm64_prune.config b/kernel/configs/ti_arm64_prune.config --- a/kernel/configs/ti_arm64_prune.config 1969-12-31 19:00:00.000000000 -0500 +++ b/kernel/configs/ti_arm64_prune.config 2024-07-07 20:37:34.680306729 -0400 @@ -0,0 +1,494 @@ +# Add config flags here that appear in the multi_v7_defconfig but are not +# used by a kernel targeting only the currently supported TI EVMs + +# Non-TI Architectures +CONFIG_ARCH_ACTIONS=n +CONFIG_ARCH_SUNXI=n +CONFIG_ARCH_AGILEX=n +CONFIG_ARCH_ALPINE=n +CONFIG_ARCH_APPLE=n +CONFIG_ARCH_BCM=n +CONFIG_ARCH_BCM2835=n +CONFIG_ARCH_BCM_IPROC=n +CONFIG_ARCH_BCMBCA=n +CONFIG_ARCH_BERLIN=n +CONFIG_ARCH_BRCMSTB=n +CONFIG_ARCH_EXYNOS=n +CONFIG_ARCH_LAYERSCAPE=n +CONFIG_ARCH_LG1K=n +CONFIG_ARCH_HISI=n +CONFIG_ARCH_KEEMBAY=n +CONFIG_ARCH_MA35=n +CONFIG_ARCH_MEDIATEK=n +CONFIG_ARCH_MESON=n +CONFIG_ARCH_MVEBU=n +CONFIG_ARCH_NXP=n +CONFIG_ARCH_MXC=n +CONFIG_ARCH_NPCM=n +CONFIG_ARCH_QCOM=n +CONFIG_ARCH_ROCKCHIP=n +CONFIG_ARCH_SEATTLE=n +CONFIG_ARCH_REALTEK=n +CONFIG_ARCH_RENESAS=n +CONFIG_ARCH_R8A7795=n +CONFIG_ARCH_R8A7796=n +CONFIG_ARCH_S32=n +CONFIG_ARCH_SPARX5=n +CONFIG_ARCH_STM32=n +CONFIG_ARCH_STRATIX10=n +CONFIG_ARCH_INTEL_SOCFPGA=n +CONFIG_ARCH_SYNQUACER=n +CONFIG_ARCH_TEGRA=n +CONFIG_ARCH_SPRD=n +CONFIG_ARCH_THUNDER=n +CONFIG_ARCH_THUNDER2=n +CONFIG_ARCH_UNIPHIER=n +CONFIG_ARCH_VEXPRESS=n +CONFIG_ARCH_VISCONTI=n +CONFIG_ARCH_XGENE=n +CONFIG_ARCH_ZX=n +CONFIG_ARCH_ZYNQMP=n +CONFIG_ARCH_TEGRA_132_SOC=n +CONFIG_ARCH_TEGRA_210_SOC=n +CONFIG_ARCH_TEGRA_186_SOC=n + +CONFIG_QCOM_FALKOR_ERRATUM_1003=n +CONFIG_QCOM_FALKOR_ERRATUM_1009=n +CONFIG_QCOM_QDF2400_ERRATUM_0065=n +CONFIG_QCOM_FALKOR_ERRATUM_E1041=n + +CONFIG_CAVIUM_ERRATUM_22375=n +CONFIG_CAVIUM_ERRATUM_23144=n +CONFIG_CAVIUM_ERRATUM_23154=n +CONFIG_CAVIUM_ERRATUM_27456=n +CONFIG_CAVIUM_ERRATUM_30115=n + +CONFIG_HISILICON_ERRATUM_161600802=n + +# Disable Errata fixes not relevant for Cortex A53 and Cortext A72 cores. +# The Socionext Synquacer GICv3 pre-ITS workaround is used on K3 devices +# as well, thats why its left enabled. +CONFIG_AMPERE_ERRATUM_AC03_CPU_38=n +CONFIG_ARM64_ERRATUM_832075=n +CONFIG_ARM64_ERRATUM_1024718=n +CONFIG_ARM64_ERRATUM_1418040=n +CONFIG_ARM64_ERRATUM_1165522=n +CONFIG_ARM64_ERRATUM_1530923=n +CONFIG_ARM64_ERRATUM_2441007=n +CONFIG_ARM64_ERRATUM_1286807=n +CONFIG_ARM64_ERRATUM_1463225=n +CONFIG_ARM64_ERRATUM_1542419=n +CONFIG_ARM64_ERRATUM_1508412=n +CONFIG_ARM64_ERRATUM_2051678=n +CONFIG_ARM64_ERRATUM_2077057=n +CONFIG_ARM64_ERRATUM_2658417=n +CONFIG_ARM64_ERRATUM_2054223=n +CONFIG_ARM64_ERRATUM_2067961=n +CONFIG_ARM64_ERRATUM_2441009=n +CONFIG_ARM64_ERRATUM_2457168=n +CONFIG_ARM64_ERRATUM_2645198=n +CONFIG_ARM64_ERRATUM_2966298=n +CONFIG_ARM64_ERRATUM_3117295=n +CONFIG_CAVIUM_TX2_ERRATUM_219=n +CONFIG_FUJITSU_ERRATUM_010001=n +CONFIG_NVIDIA_CARMEL_CNP_ERRATUM=n +CONFIG_ROCKCHIP_ERRATUM_3588001=n + +# Serial +CONFIG_SERIAL_8250_FSL=n +CONFIG_SERIAL_8250_DW=n +CONFIG_SERIAL_AMBA_PL011=n +CONFIG_SERIAL_AMBA_PL011_CONSOLE=n +CONFIG_SERIAL_XILINX_PS_UART=n +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=n + +CONFIG_ARM_SCPI_PROTOCOL=n +CONFIG_ARM_SCPI_POWER_DOMAIN=n +CONFIG_ARM_SCPI_CPUFREQ=n +CONFIG_SENSORS_ARM_SCPI=n +CONFIG_COMMON_CLK_SCPI=n + +CONFIG_ARM_MHU=n +CONFIG_PLATFORM_MHU=n + +CONFIG_ACPI=n + +CONFIG_NUMA=n + +CONFIG_XEN=n +CONFIG_KVM=n + +CONFIG_ARM_BIG_LITTLE_CPUFREQ=n + +CONFIG_PCI_XGENE=n +CONFIG_PCI_HISI=n +CONFIG_PCIE_KIRIN=n + +# DRM +CONFIG_DRM_NOUVEAU=n +CONFIG_DRM_I2C_ADV7511=n +CONFIG_DRM_ETNAVIV=n +CONFIG_DRM_HISI_HIBMC=n +CONFIG_DRM_HISI_KIRIN=n +CONFIG_DRM_MXSFB=n +CONFIG_DRM_PL111=n +CONFIG_DRM_LIMA=n +CONFIG_DRM_PANFROST=n + +# Video +CONFIG_VGA_ARB=n +CONFIG_FB_EFI=n + +# V4L2 +CONFIG_RC_CORE=n + +# Sound +CONFIG_SND_SPI=n +CONFIG_SND_SOC_FSL_SAI=n +CONFIG_SND_SOC_AK4613=n +CONFIG_SND_SOC_ES7134=n +CONFIG_SND_SOC_ES7241=n +CONFIG_SND_SOC_TAS571X=n + +# USB +CONFIG_USB_MUSB_HDRC=n +CONFIG_USB_DWC2=n +CONFIG_USB_CHIPIDEA=n +CONFIG_USB_ISP1760=n +CONFIG_USB_HSIC_USB3503=n + +# Generic kernel + +# We recommend to turn off Real-Time group scheduling in the +# kernel when using systemd. RT group scheduling effectively +# makes RT scheduling unavailable for most userspace, since it +# requires explicit assignment of RT budgets to each unit whose +# processes making use of RT. As there's no sensible way to +# assign these budgets automatically this cannot really be +# fixed, and it's best to disable group scheduling hence. +CONFIG_RT_GROUP_SCHED=n + +# Remove debug features. +CONFIG_SLUB_DEBUG=n + +# We are not a crash kernel +CONFIG_CRASH_DUMP=n + +# ARM Scalable Vector Extension (SVE) is available only with ARMv8.2-A +# and above. Since current TI SoCs are based on ARMv8.0, disable SVE +CONFIG_ARM64_SVE=n + +# Plan 9 is a distributed resource sharing protocol thats not +# typically used on TI processors +CONFIG_NET_9P=n + +# Non-TI hardware vendor specific drivers +CONFIG_KEYBOARD_CROS_EC=n +CONFIG_I2C_CROS_EC_TUNNEL=n +CONFIG_QRTR=n +CONFIG_SPI_NXP_FLEXSPI=n +CONFIG_GPIO_ALTERA=n +CONFIG_GPIO_DWAPB=n +CONFIG_GPIO_MB86S7X=n +CONFIG_GPIO_PL061=n +CONFIG_GPIO_XGENE=n +CONFIG_POWER_RESET_XGENE=n +CONFIG_ARM_SP805_WATCHDOG=n +CONFIG_ARM_SBSA_WATCHDOG=n +CONFIG_DW_WATCHDOG=n +CONFIG_MFD_SEC_CORE=n +CONFIG_REGULATOR_QCOM_SPMI=n +CONFIG_DRM_MALI_DISPLAY=n +CONFIG_DRM_RCAR_DW_HDMI=n +CONFIG_DRM_DW_HDMI_AHB_AUDIO=n +CONFIG_DRM_DW_HDMI_CEC=n +CONFIG_FB_SSD1307=n +CONFIG_MMC_ARMMMCI=n +CONFIG_MMC_SDHCI_XENON=n +CONFIG_RTC_DRV_S5M=n +CONFIG_RTC_DRV_CROS_EC=n +CONFIG_RTC_DRV_PL031=n +CONFIG_FSL_EDMA=n +CONFIG_MV_XOR_V2=n +CONFIG_PL330_DMA=n +CONFIG_QCOM_HIDMA_MGMT=n +CONFIG_QCOM_HIDMA=n +CONFIG_CHROME_PLATFORMS=n +CONFIG_CROS_EC=n +CONFIG_CROS_EC_I2C=n +CONFIG_CROS_EC_SPI=n +CONFIG_CROS_EC_CHARDEV=n +CONFIG_SURFACE_PLATFORMS=n +CONFIG_COMMON_CLK_S2MPS11=n +CONFIG_COMMON_CLK_VC5=n +CONFIG_COMMON_CLK_BD718XX=n +CONFIG_FSL_ERRATUM_A008585=n +CONFIG_HISILICON_ERRATUM_161010101=n +CONFIG_RPMSG_QCOM_GLINK_RPM=n +CONFIG_SOUNDWIRE_QCOM=n +CONFIG_EXTCON_USBC_CROS_EC=n +CONFIG_QCOM_SPMI_ADC5=n +CONFIG_IIO_CROS_EC_SENSORS_CORE=n +CONFIG_IIO_CROS_EC_SENSORS=n +CONFIG_IIO_CROS_EC_LIGHT_PROX=n +CONFIG_IIO_CROS_EC_BARO=n +CONFIG_PWM_CROS_EC=n +CONFIG_SLIM_QCOM_CTRL=n +CONFIG_SPI_PL022=n +CONFIG_SLIMBUS=n +CONFIG_REGMAP_SLIMBUS=n +CONFIG_SCSI_HISI_SAS=n +CONFIG_AHCI_CEVA=n +CONFIG_AHCI_XGENE=n +CONFIG_AHCI_QORIQ=n +CONFIG_SATA_SIL24=n +CONFIG_BCMGENET=n +CONFIG_SYSTEMPORT=n +CONFIG_HNS_DSAF=n +CONFIG_HNS_ENET=n +CONFIG_HNS3=n +CONFIG_NET_VENDOR_NVIDIA=n +CONFIG_NET_VENDOR_RENESAS=n +CONFIG_NET_VENDOR_SAMSUNG=n +CONFIG_NET_VENDOR_STMICRO=n +CONFIG_NET_VENDOR_XILINX=n +CONFIG_BROADCOM_PHY=n +CONFIG_BCM54140_PHY=n +CONFIG_ROCKCHIP_PHY=n +CONFIG_PCS_XPCS=n +CONFIG_HW_RANDOM_ARM_SMCCC_TRNG=n +CONFIG_HW_RANDOM_CN10K=n +CONFIG_I2C_CADENCE=n +CONFIG_I2C_DESIGNWARE_SLAVE=n +CONFIG_I2C_DESIGNWARE_PLATFORM=n +CONFIG_I2C_RK3X=n +CONFIG_PINCTRL_MAX77620=n +CONFIG_DRM_RCAR_USE_LVDS=n +CONFIG_DRM_RCAR_USE_MIPI_DSI=n +CONFIG_SND_SOC_FSL_ASRC=n +CONFIG_SND_SOC_FSL_AUDMIX=n +CONFIG_SND_SOC_FSL_SSI=n +CONFIG_SND_SOC_FSL_SPDIF=n +CONFIG_SND_SOC_FSL_ESAI=n +CONFIG_SND_SOC_FSL_MICFIL=n +CONFIG_SND_SOC_IMX_AUDMUX=n +CONFIG_MMC_SDHCI_OF_DWCMSHC=n +CONFIG_MMC_SDHCI_CADENCE=n +CONFIG_MMC_SDHCI_F_SDH30=n +CONFIG_MMC_DW=n +CONFIG_MMC_MTK=n +CONFIG_PCIE_ALTERA=n +CONFIG_PCI_HOST_THUNDER_PEM=n +CONFIG_PCI_HOST_THUNDER_ECAM=n +CONFIG_PCI_MESON=n +CONFIG_BRCMSTB_GISB_ARB=n +CONFIG_VEXPRESS_CONFIG=n +CONFIG_MTD_NAND_DENALI_DT=n +CONFIG_MTD_NAND_BRCMNAND=n +CONFIG_B53=n +CONFIG_NET_DSA_BCM_SF2=n +CONFIG_CAN_FLEXCAN=n +CONFIG_SPI_DESIGNWARE=n +CONFIG_SPI_ROCKCHIP=n +CONFIG_DRM_HDLCD=n +CONFIG_DRM_KOMEDA=n +CONFIG_COMMON_CLK_RK808=n +CONFIG_COMMON_CLK_XGENE=n +CONFIG_SOC_BRCMSTB=n +CONFIG_NET_VENDOR_ALACRITECH=n +CONFIG_NET_VENDOR_AMAZON=n +CONFIG_NET_VENDOR_AMD=n +CONFIG_NET_VENDOR_AQUANTIA=n +CONFIG_NET_VENDOR_ARC=n +CONFIG_NET_VENDOR_ASIX=n +CONFIG_NET_VENDOR_CORTINA=n +CONFIG_NET_VENDOR_DAVICOM=n +CONFIG_NET_VENDOR_ENGLEDER=n +CONFIG_NET_VENDOR_EZCHIP=n +CONFIG_NET_VENDOR_GOOGLE=n +CONFIG_NET_VENDOR_HISILICON=n +CONFIG_NET_VENDOR_LITEX=n +CONFIG_NET_VENDOR_MICREL=n +CONFIG_NET_VENDOR_MICROCHIP=n +CONFIG_NET_VENDOR_MICROSEMI=n +CONFIG_NET_VENDOR_NATSEMI=n +CONFIG_NET_VENDOR_NI=n +CONFIG_NET_VENDOR_QUALCOMM=n +CONFIG_NET_VENDOR_ROCKER=n +CONFIG_NET_VENDOR_SEEQ=n +CONFIG_NET_VENDOR_SMSC=n +CONFIG_NET_VENDOR_SOCIONEXT=n +CONFIG_NET_VENDOR_SOLARFLARE=n +CONFIG_NET_VENDOR_SYNOPSYS=n +CONFIG_NET_VENDOR_VERTEXCOM=n +CONFIG_NET_VENDOR_VIA=n +CONFIG_NET_VENDOR_WANGXUN=n +CONFIG_NET_VENDOR_WIZNET=n +CONFIG_NET_VENDOR_BROADCOM=n +CONFIG_NET_VENDOR_MICROSOFT=n +CONFIG_NET_VENDOR_FUNGIBLE=n +CONFIG_NET_VENDOR_CAVIUM=n +CONFIG_NET_VENDOR_PENSANDO=n +CONFIG_NET_VENDOR_CADENCE=n +CONFIG_NET_VENDOR_MELLANOX=n +CONFIG_NET_VENDOR_NETRONOME=n +CONFIG_NET_VENDOR_MARVELL=n +CONFIG_NET_VENDOR_INTEL=n +CONFIG_NET_VENDOR_HUAWEI=n + +# Serial Power Management Interface (SPMI) has not been used on TI +# platforms (yet) +CONFIG_SPMI=n + +# DVB and TV tuner cards are rarely used on TI platforms, if at all +CONFIG_CXD2880_SPI_DRV=n +CONFIG_MEDIA_TUNER_E4000=n +CONFIG_MEDIA_TUNER_FC0011=n +CONFIG_MEDIA_TUNER_FC0012=n +CONFIG_MEDIA_TUNER_FC0013=n +CONFIG_MEDIA_TUNER_FC2580=n +CONFIG_MEDIA_TUNER_IT913X=n +CONFIG_MEDIA_TUNER_M88RS6000T=n +CONFIG_MEDIA_TUNER_MAX2165=n +CONFIG_MEDIA_TUNER_MC44S803=n +CONFIG_MEDIA_TUNER_MSI001=n +CONFIG_MEDIA_TUNER_MT2060=n +CONFIG_MEDIA_TUNER_MT2063=n +CONFIG_MEDIA_TUNER_MT20XX=n +CONFIG_MEDIA_TUNER_MT2131=n +CONFIG_MEDIA_TUNER_MT2266=n +CONFIG_MEDIA_TUNER_MXL301RF=n +CONFIG_MEDIA_TUNER_MXL5005S=n +CONFIG_MEDIA_TUNER_MXL5007T=n +CONFIG_MEDIA_TUNER_QM1D1B0004=n +CONFIG_MEDIA_TUNER_QM1D1C0042=n +CONFIG_MEDIA_TUNER_QT1010=n +CONFIG_MEDIA_TUNER_R820T=n +CONFIG_MEDIA_TUNER_SI2157=n +CONFIG_MEDIA_TUNER_SIMPLE=n +CONFIG_MEDIA_TUNER_TDA18212=n +CONFIG_MEDIA_TUNER_TDA18218=n +CONFIG_MEDIA_TUNER_TDA18250=n +CONFIG_MEDIA_TUNER_TDA18271=n +CONFIG_MEDIA_TUNER_TDA827X=n +CONFIG_MEDIA_TUNER_TDA8290=n +CONFIG_MEDIA_TUNER_TDA9887=n +CONFIG_MEDIA_TUNER_TEA5761=n +CONFIG_MEDIA_TUNER_TEA5767=n +CONFIG_MEDIA_TUNER_TUA9001=n +CONFIG_MEDIA_TUNER_XC2028=n +CONFIG_MEDIA_TUNER_XC4000=n +CONFIG_MEDIA_TUNER_XC5000=n +CONFIG_DVB_M88DS3103=n +CONFIG_DVB_MXL5XX=n +CONFIG_DVB_STB0899=n +CONFIG_DVB_STB6100=n +CONFIG_DVB_STV090x=n +CONFIG_DVB_STV0910=n +CONFIG_DVB_STV6110x=n +CONFIG_DVB_STV6111=n +CONFIG_DVB_DRXK=n +CONFIG_DVB_MN88472=n +CONFIG_DVB_MN88473=n +CONFIG_DVB_SI2165=n +CONFIG_DVB_TDA18271C2DD=n +CONFIG_DVB_CX24110=n +CONFIG_DVB_CX24116=n +CONFIG_DVB_CX24117=n +CONFIG_DVB_CX24120=n +CONFIG_DVB_CX24123=n +CONFIG_DVB_DS3000=n +CONFIG_DVB_MB86A16=n +CONFIG_DVB_MT312=n +CONFIG_DVB_S5H1420=n +CONFIG_DVB_SI21XX=n +CONFIG_DVB_STB6000=n +CONFIG_DVB_STV0288=n +CONFIG_DVB_STV0299=n +CONFIG_DVB_STV0900=n +CONFIG_DVB_STV6110=n +CONFIG_DVB_TDA10071=n +CONFIG_DVB_TDA10086=n +CONFIG_DVB_TDA8083=n +CONFIG_DVB_TDA8261=n +CONFIG_DVB_TDA826X=n +CONFIG_DVB_TS2020=n +CONFIG_DVB_TUA6100=n +CONFIG_DVB_TUNER_CX24113=n +CONFIG_DVB_TUNER_ITD1000=n +CONFIG_DVB_VES1X93=n +CONFIG_DVB_ZL10036=n +CONFIG_DVB_ZL10039=n +CONFIG_DVB_AF9013=n +CONFIG_DVB_CX22700=n +CONFIG_DVB_CX22702=n +CONFIG_DVB_CXD2820R=n +CONFIG_DVB_CXD2841ER=n +CONFIG_DVB_DIB3000MB=n +CONFIG_DVB_DIB3000MC=n +CONFIG_DVB_DIB7000M=n +CONFIG_DVB_DIB7000P=n +CONFIG_DVB_DIB9000=n +CONFIG_DVB_DRXD=n +CONFIG_DVB_EC100=n +CONFIG_DVB_L64781=n +CONFIG_DVB_MT352=n +CONFIG_DVB_NXT6000=n +CONFIG_DVB_RTL2830=n +CONFIG_DVB_RTL2832=n +CONFIG_DVB_RTL2832_SDR=n +CONFIG_DVB_S5H1432=n +CONFIG_DVB_SI2168=n +CONFIG_DVB_SP887X=n +CONFIG_DVB_STV0367=n +CONFIG_DVB_TDA10048=n +CONFIG_DVB_TDA1004X=n +CONFIG_DVB_ZD1301_DEMOD=n +CONFIG_DVB_ZL10353=n +CONFIG_DVB_CXD2880=n +CONFIG_DVB_STV0297=n +CONFIG_DVB_TDA10021=n +CONFIG_DVB_TDA10023=n +CONFIG_DVB_VES1820=n +CONFIG_DVB_AU8522_DTV=n +CONFIG_DVB_AU8522_V4L=n +CONFIG_DVB_BCM3510=n +CONFIG_DVB_LG2160=n +CONFIG_DVB_LGDT3305=n +CONFIG_DVB_LGDT3306A=n +CONFIG_DVB_LGDT330X=n +CONFIG_DVB_MXL692=n +CONFIG_DVB_NXT200X=n +CONFIG_DVB_OR51132=n +CONFIG_DVB_OR51211=n +CONFIG_DVB_S5H1409=n +CONFIG_DVB_S5H1411=n +CONFIG_DVB_DIB8000=n +CONFIG_DVB_MB86A20S=n +CONFIG_DVB_S921=n +CONFIG_DVB_MN88443X=n +CONFIG_DVB_TC90522=n +CONFIG_DVB_PLL=n +CONFIG_DVB_TUNER_DIB0070=n +CONFIG_DVB_TUNER_DIB0090=n +CONFIG_DVB_A8293=n +CONFIG_DVB_AF9033=n +CONFIG_DVB_ASCOT2E=n +CONFIG_DVB_ATBM8830=n +CONFIG_DVB_HELENE=n +CONFIG_DVB_HORUS3A=n +CONFIG_DVB_ISL6405=n +CONFIG_DVB_ISL6421=n +CONFIG_DVB_ISL6423=n +CONFIG_DVB_IX2505V=n +CONFIG_DVB_LGS8GL5=n +CONFIG_DVB_LGS8GXX=n +CONFIG_DVB_LNBH25=n +CONFIG_DVB_LNBH29=n +CONFIG_DVB_LNBP21=n +CONFIG_DVB_LNBP22=n +CONFIG_DVB_M88RS2000=n +CONFIG_DVB_TDA665x=n +CONFIG_DVB_DRX39XYJ=n +CONFIG_DVB_CXD2099=n +CONFIG_DVB_SP2=n diff -Naur --no-dereference a/kernel/configs/ti_early_display.config b/kernel/configs/ti_early_display.config --- a/kernel/configs/ti_early_display.config 1969-12-31 19:00:00.000000000 -0500 +++ b/kernel/configs/ti_early_display.config 2024-07-07 20:37:34.680306729 -0400 @@ -0,0 +1,217 @@ +################################################## +# TI Early Display configs +################################################## + +# Time measurements were perfomed on AM62x-SK and AM62Px-SK + +# Configurations that add to boot time have to be reduced +# in order for display to come up as fast as possible + +### Necessary reduction ### + +# This config adds support for a virtual file system +# that developers use to put debugging files into +# +# This reduces kernel image size by 335.9KB and boot time by 48ms +CONFIG_DEBUG_FS=n + +# This config adds support for normal Windows file systems +# +# This reduces kernel image size by 131.1KB and boot time by 32ms +CONFIG_VFAT_FS=m + +# Kernel can apply read-only permissions to linear aliases of VM areas. This +# provides extra layer of protection against advertent/inadvertent modification +# of read-only data through the linear alias. While its a useful security +# feature, it has a performance impact. +# +#This reduces kernel image size by 0KB and boot time by 144ms +CONFIG_RODATA_FULL_DEFAULT_ENABLED=n + +# Remove SPI support +# +# This reduces kernel image size by 208.9KB and reduces boot time by 16ms +CONFIG_SPI=n + +# This adds support for PTP support used to precisely synchronize +# distributed clocks over Ethernet networks +# +# This reduces kernel image size by 69.6KB and reduces boot time by 64ms +CONFIG_PTP_1588_CLOCK=m + +# Remove MMC support +# +# This reduces kernel image size by 137.2KB and reduces boot time by 32ms +CONFIG_MMC=m + + +### Additional reduction ### + +# These configs reduce boot time by 64ms +CONFIG_PPS=m +CONFIG_PSTORE=m +CONFIG_CPU_FREQ=n + +CONFIG_OVERLAY_FS=n +CONFIG_SQUASHFS=m + +CONFIG_COMMON_CLK_SCMI=m +CONFIG_COMMON_CLK_RS9_PCIE=n +CONFIG_RESET_SCMI=m + +CONFIG_PHY_CADENCE_SIERRA=m +CONFIG_PHY_XGENE=m +CONFIG_REALTEK_PHY=m + +CONFIG_REGULATOR_AXP20X=m +CONFIG_MEDIA_CEC_SUPPORT=n +CONFIG_TCG_TPM=m + +CONFIG_MTD_BLOCK=m +CONFIG_MTD_CMDLINE_PARTS=m +CONFIG_MTD_COMPLEX_MAPPINGS=n +CONFIG_MTD_RAW_NAND=m +CONFIG_MTD_SPI_NAND=m +CONFIG_MTD_UBI=m +CONFIG_UBIFS_FS=m + +CONFIG_MULTIPLEXER=m +CONFIG_MUX_MMIO=m +CONFIG_SECTION_MISMATCH_WARN_ONLY=n + +CONFIG_KEXEC=n +CONFIG_KEXEC_FILE=n +CONFIG_TASKSTATS=n +CONFIG_ATA=m + +CONFIG_RUNTIME_TESTING_MENU=n +CONFIG_STACKTRACE=n +CONFIG_SYMBOLIC_ERRNAME=n +CONFIG_INDIRECT_PIO=n +CONFIG_QUOTA=n + +# Disable ARMv8.1+ architecture features. TI K3 processors +# are based on ARMv8.0, and these features are not applicable. +CONFIG_ARM64_CNP=n +CONFIG_ARM64_HW_AFDBM=n +CONFIG_ARM64_PAN=n +CONFIG_ARM64_RAS_EXTN=n +CONFIG_ARM64_USE_LSE_ATOMICS=n +# End of architecture features + +CONFIG_SOCIONEXT_SYNQUACER_PREITS=n +CONFIG_MEMORY_HOTPLUG=n + +CONFIG_BSD_PROCESS_ACCT=n +CONFIG_CPU_ISOLATION=n +CONFIG_IRQ_TIME_ACCOUNTING=n +CONFIG_POSIX_MQUEUE=n +CONFIG_PROFILING=n + +CONFIG_RD_BZIP2=n +CONFIG_RD_LZ4=n +CONFIG_RD_LZMA=n +CONFIG_RD_LZO=n +CONFIG_RD_XZ=n +CONFIG_RD_ZSTD=n + +CONFIG_EXTCON=m +CONFIG_FPGA=m +CONFIG_HWMON=m +CONFIG_HWSPINLOCK=n +CONFIG_I2C_ALGOBIT=m +CONFIG_IIO=m +CONFIG_INTERCONNECT=n +CONFIG_MD=n +CONFIG_MEMORY=n +CONFIG_NEW_LEDS=n +CONFIG_PCI=n +CONFIG_PWM=n +CONFIG_RTC_CLASS=n +CONFIG_SOUND=m + +CONFIG_STAGING=n +CONFIG_THERMAL=n +CONFIG_USB_SUPPORT=n +CONFIG_VFIO=m +CONFIG_VHOST_MENU=n +CONFIG_VIRTIO_MENU=n +CONFIG_AT803X_PHY=m +CONFIG_FSL_RCPM=n +CONFIG_INPUT_MATRIXKMAP=m +CONFIG_INPUT_MISC=n +CONFIG_INPUT_MOUSE=n +CONFIG_INPUT_TOUCHSCREEN=n +CONFIG_MDIO_BUS_MUX_MMIOREG=m +CONFIG_MDIO_BUS_MUX_MULTIPLEXER=m +CONFIG_MICROSEMI_PHY=m +CONFIG_MOTORCOMM_PHY=m + +CONFIG_PHY_AM654_SERDES=m +CONFIG_PHY_CADENCE_TORRENT=m + +CONFIG_RESET_SIMPLE=n +CONFIG_RPMSG_KDRV=m +CONFIG_RPMSG_KDRV_ETH_SWITCH=m +CONFIG_RPMSG_VIRTIO=m +CONFIG_SCSI=m +CONFIG_SERIO_AMBAKMI=m +CONFIG_SERIO_LIBPS2=m +CONFIG_TUN=m +CONFIG_VIRTIO_NET=m +CONFIG_VITESSE_PHY=m +CONFIG_WLAN=n +CONFIG_GPIO_GENERIC_PLATFORM=m +CONFIG_I2C_SLAVE=n +CONFIG_GPIO_TPS65219=m +CONFIG_GPIO_SYSCON=m + +CONFIG_MFD_HI6421_PMIC=m +CONFIG_MFD_MAX77620=n +CONFIG_MFD_MT6397=m +CONFIG_MFD_ROHM_BD718XX=m +CONFIG_MFD_RK8XX=n +CONFIG_MFD_RK8XX_I2C=n + +CONFIG_POWER_RESET_BRCMSTB=n + +CONFIG_REGULATOR_BD9571MWV=m +CONFIG_REGULATOR_FAN53555=m +CONFIG_REGULATOR_MP8859=m +CONFIG_REGULATOR_PCA9450=m +CONFIG_REGULATOR_PF8X00=m +CONFIG_REGULATOR_PFUZE100=m +CONFIG_REGULATOR_TPS65219=m +CONFIG_SERIAL_FSL_LINFLEXUART=m +CONFIG_SERIAL_FSL_LPUART=m +CONFIG_REGULATOR_RAA215300=n +CONFIG_REGULATOR_RK808=n + +CONFIG_LEGACY_TIOCSTI=n + +CONFIG_TI_K3_AM65_CPSW_NUSS=m +CONFIG_MARVELL_10G_PHY=n +CONFIG_MDIO_BCM_UNIMAC=n + +CONFIG_HID_A4TECH=n +CONFIG_HID_BELKIN=n +CONFIG_HID_CHERRY=n +CONFIG_HID_CYPRESS=n +CONFIG_HID_EZKEY=n +CONFIG_HID_ITE=n +CONFIG_HID_KENSINGTON=n +CONFIG_HID_REDRAGON=n +CONFIG_HID_MICROSOFT=n +CONFIG_HID_MONTEREY=n + +# These configs enable Display drivers and add 600KB to the kernel Image. +# Note that SK-AM62A does not support OLDI and has support for HDMI alone. +# In an early display scenario for SK-AM62A, the following configs are not useful. +CONFIG_DRM=y +CONFIG_DRM_TIDSS=y +CONFIG_FB_SIMPLE=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_DRM_PANEL_LVDS=y +CONFIG_DRM_PANEL_SIMPLE=y +CONFIG_FRAMEBUFFER_CONSOLE=n +CONFIG_LOGO=n diff -Naur --no-dereference a/kernel/configs/ti_multi_v7_prune.config b/kernel/configs/ti_multi_v7_prune.config --- a/kernel/configs/ti_multi_v7_prune.config 1969-12-31 19:00:00.000000000 -0500 +++ b/kernel/configs/ti_multi_v7_prune.config 2024-07-07 20:37:34.680306729 -0400 @@ -0,0 +1,174 @@ +# Add config flags here that appear in the multi_v7_defconfig but are not +# used by a kernel targeting only the currently supported TI EVMs + +# Non-TI Architectures +CONFIG_ARCH_AIROHA=n +CONFIG_ARCH_ACTIONS=n +CONFIG_ARCH_ALPINE=n +CONFIG_ARCH_ARTPEC=n +CONFIG_ARCH_ASPEED=n +CONFIG_ARCH_AT91=n +CONFIG_ARCH_BCM=n +CONFIG_ARCH_BCM_CYGNUS=n +CONFIG_ARCH_BCM_NSP=n +CONFIG_ARCH_BCM_5301X=n +CONFIG_ARCH_BCM_281XX=n +CONFIG_ARCH_BCM_21664=n +CONFIG_ARCH_BRCMSTB=n +CONFIG_ARCH_BERLIN=n +CONFIG_ARCH_DIGICOLOR=n +CONFIG_ARCH_HIGHBANK=n +CONFIG_ARCH_HISI=n +CONFIG_ARCH_HI3xxx=n +CONFIG_ARCH_HIP01=n +CONFIG_ARCH_HIP04=n +CONFIG_ARCH_HIX5HD2=n +CONFIG_ARCH_HPE=n +CONFIG_ARCH_HPE_GXP=n +CONFIG_ARCH_INTEL_SOCFPGA=n +CONFIG_ARCH_MESON=n +CONFIG_ARCH_MXC=n +CONFIG_ARCH_MEDIATEK=n +CONFIG_ARCH_MILBEAUT=n +CONFIG_ARCH_QCOM=n +CONFIG_ARCH_MMP=n +CONFIG_ARCH_MSM8X60=n +CONFIG_ARCH_MSM8960=n +CONFIG_ARCH_MSM8974=n +CONFIG_ARCH_ROCKCHIP=n +CONFIG_ARCH_SOCFPGA=n +CONFIG_ARCH_SPEAR13XX=n +CONFIG_ARCH_STI=n +CONFIG_ARCH_EXYNOS=n +CONFIG_ARCH_SHMOBILE_MULTI=n +CONFIG_ARCH_EMEV2=n +CONFIG_ARCH_R7S72100=n +CONFIG_ARCH_R8A73A4=n +CONFIG_ARCH_R8A7740=n +CONFIG_ARCH_R8A7778=n +CONFIG_ARCH_R8A7779=n +CONFIG_ARCH_R8A7790=n +CONFIG_ARCH_R8A7791=n +CONFIG_ARCH_R8A7793=n +CONFIG_ARCH_R8A7794=n +CONFIG_ARCH_RENESAS=n +CONFIG_ARCH_SH73A0=n +CONFIG_ARCH_SUNPLUS=y +CONFIG_ARCH_SUNXI=n +CONFIG_ARCH_STM32=n +CONFIG_ARCH_SIRF=n +CONFIG_ARCH_TEGRA=n +CONFIG_ARCH_TEGRA_2x_SOC=n +CONFIG_ARCH_TEGRA_3x_SOC=n +CONFIG_ARCH_TEGRA_114_SOC=n +CONFIG_ARCH_TEGRA_124_SOC=n +CONFIG_ARCH_UNIPHIER=n +CONFIG_ARCH_U8500=n +CONFIG_ARCH_VEXPRESS=n +CONFIG_ARCH_VEXPRESS_TC2_PM=n +CONFIG_ARCH_WM8850=n +CONFIG_ARCH_ZYNQ=n +CONFIG_ARCH_VIRT=n +CONFIG_ARCH_MVEBU=n +CONFIG_PLAT_SPEAR=n +CONFIG_CHROME_PLATFORMS=n + +# Multifunction device drivers +CONFIG_MFD_AS3711=n +CONFIG_MFD_AS3722=n +CONFIG_MFD_ATMEL_FLEXCOM=n +CONFIG_MFD_ATMEL_HLCDC=n +CONFIG_MFD_BCM590XX=n +CONFIG_MFD_AXP20X_I2C=n +CONFIG_MFD_DA9063=n +CONFIG_MFD_MAX14577=n +CONFIG_MFD_MAX77686=n +CONFIG_MFD_MAX77693=n +CONFIG_MFD_MAX8907=n +CONFIG_MFD_MAX8997=n +CONFIG_MFD_MAX8998=n +CONFIG_MFD_PM8XXX=n +CONFIG_MFD_RK808=n +CONFIG_MFD_RN5T618=n +CONFIG_MFD_SEC_CORE=n +CONFIG_MFD_STMPE=n + +# Regulators +CONFIG_REGULATOR_ACT8865=n +CONFIG_REGULATOR_DA9210=n +CONFIG_REGULATOR_FAN53555=n +CONFIG_REGULATOR_LP872X=n +CONFIG_REGULATOR_MAX8952=n +CONFIG_REGULATOR_MAX8973=n +CONFIG_REGULATOR_PWM=n +CONFIG_REGULATOR_TPS51632=n +CONFIG_REGULATOR_TWL4030=n + +# RTC drivers +CONFIG_RTC_DRV_HYM8563=n +CONFIG_RTC_DRV_RS5C372=n +CONFIG_RTC_DRV_BQ32K=n +CONFIG_RTC_DRV_S35390A=n +CONFIG_RTC_DRV_RX8581=n +CONFIG_RTC_DRV_EM3027=n + +# Watchdog Device Drivers +CONFIG_XILINX_WATCHDOG=n +CONFIG_DW_WATCHDOG=n + +# GPIO +CONFIG_GPIO_DWAPB=n +CONFIG_GPIO_XILINX=n +CONFIG_GPIO_TPS6586X=n + +# Sound +CONFIG_SND_ARM=n +CONFIG_SND_SPI=n +CONFIG_SND_ATMEL_SOC=n +CONFIG_SND_SOC_FSL_SAI=n +CONFIG_SND_SOC_AK4642=n +CONFIG_SND_SOC_CPCAP=n +CONFIG_SND_SOC_SGTL5000=n +CONFIG_SND_SOC_STI_SAS=n +CONFIG_SND_SOC_WM8978=n + +# DRM +CONFIG_VGA_ARB=n +CONFIG_DRM_I2C_ADV7511=n +CONFIG_DRM_NOUVEAU=n +CONFIG_DRM_EXYNOS=n +CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=n +CONFIG_DRM_NXP_PTN3460=n +CONFIG_DRM_PARADE_PS8622=n +CONFIG_DRM_STI=n +CONFIG_DRM_PANEL_SAMSUNG_LD9040=n +CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03=n +CONFIG_DRM_DUMB_VGA_DAC=n +CONFIG_DRM_HISI_KIRIN=n +CONFIG_DRM_RCAR_LVDS=n +CONFIG_DRM_FSL_DCU=n +CONFIG_DRM_SII9234=n +CONFIG_DRM_MXSFB=n +CONFIG_DRM_HISI_HIBMC=n +CONFIG_DRM_ATMEL_HLCDC=n +CONFIG_DRM_STM=n +CONFIG_DRM_PANEL_ORISETECH_OTM8009A=n +CONFIG_DRM_PANEL_RAYDIUM_RM68200=n +CONFIG_DRM_TOSHIBA_TC358764=n +CONFIG_DRM_ETNAVIV=n +CONFIG_DRM_PL111=n +CONFIG_DRM_LIMA=n +CONFIG_DRM_PANFROST=n + +# Video +CONFIG_LCD_CLASS_DEVICE=n +CONFIG_FB_EFI=n +CONFIG_FB_SIMPLE=n +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=n +CONFIG_FB_ARMCLCD=n +CONFIG_XEN_FBDEV_FRONTEND=n + +# USB +CONFIG_USB_DWC2=n +CONFIG_USB_CHIPIDEA=n +CONFIG_USB_ISP1760=n diff -Naur --no-dereference a/kernel/configs/ti_rt.config b/kernel/configs/ti_rt.config --- a/kernel/configs/ti_rt.config 1969-12-31 19:00:00.000000000 -0500 +++ b/kernel/configs/ti_rt.config 2024-07-07 20:37:34.680306729 -0400 @@ -0,0 +1,165 @@ +################################################## +# Real Time Linux Configs +################################################## + +CONFIG_EXPERT=y +CONFIG_PREEMPT=y +CONFIG_PREEMPT_RT=y + +# max out the kernel's tick +# +# Ideally this is a balance. Increasing this means we +# spend more time in the scheduler deciding what we +# should do and less time on doing it however this +# also minimizes the time spent running a low-priority +# task while a real-time priority task is awake +CONFIG_HZ_1000=y +CONFIG_HZ=1000 + +# omit scheduling ticks for CPUs with a single task +# +# If a CPU has only one runnable task there is little +# need to contiguously interrupt it as there is no other +# task for it to switch to. This comes at the cost of having +# to offload the CPU's RCU callbacks to another CPU with +# an active tick. +# +# For workloads with many short-lived tasks HZ_PERIODIC may +# be the better selection as adaptive-tick modes does not +# come without tradeoffs. For example the user-to kernel +# transitions are slightly more expensive +CONFIG_NO_HZ_FULL=y +CONFIG_CONTEXT_TRACKING_USER=y + +# track our RCU callbacks +# +# there are situations in which idle CPUs cannot enter +# a dynctick or adaptive-tick mode, the most common reason +# being when a CPU has RCU callbacks pending. We can avoid +# this by processing all RCU callbacks in the "rcuo" kthread +# that we can 'boost' to real-time priority to prevent RCU +# stalls in real-time heavy workloads. +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_DEFAULT_ALL=y +CONFIG_RCU_NOCB_CPU_CB_BOOST=y + +# memory management tuning +# +# The SLUB allocator (default allocator used by the kernel) +# uses per-cpu caches to accelerate allocation and freeing of +# objects local to that processor. This comes at the cost of +# more indeterminism when freeing. Remove this to remove jitter +CONFIG_SLUB_CPU_PARTIAL=n + +# RCU system tuning +# +# The scheduler heavily utilizes the RCU subsystem to avoid +# large amounts of locking that would be needed otherwise. +# Removing this is showing to improve the am62x latency numbers +# using stress-ng and cyclictest. +CONFIG_RCU_TRACE=n + +# remove have kmemleak support +# +# Even-though the kmemleak detector is disabled, removing it +# completely from the build is showing improvements for the +# am62x latency numbers when monitoring with cyclictest and +# stress-ng to generate a synthetic background load. +CONFIG_HAVE_DEBUG_KMEMLEAK=n + +# Disable debug features + +# CoreSight debug and trace drivers are not typically used in +# production. Keep them disabled by default. Users can enable +# when debugging is needed. +CONFIG_CORESIGHT=n + +# Remove support for symbolic crash dumps. These are useful +# while debugging and not must have for production. This also +# helps reduce kernel size. +CONFIG_KALLSYMS=n + +# Disable profiling support. Not needed on a production system. +CONFIG_PROFILING=n + +# Disable support for performance events. These are used only +# for development and debug. Not needed on production system. +CONFIG_PERF_EVENTS=n + +# Disable eBPF support which is typically used for tracing and +# profiling. This prevents users from loading eBPF programs +# but BPF usage within the kernel should still work. Disabling +# JIT compiler will slow down packet filtering. +CONFIG_BPF_SYSCALL=n +CONFIG_BPF_JIT=n + +# Fine granularity IRQ time accounting is not needed on a +# production system. +CONFIG_IRQ_TIME_ACCOUNTING=n + +# Disable ARMv8.1+ architecture featurres. TI processors are based +# on ARMv8.0, and these feaures are not applicable. If enabled +# they increase worst case latency from 41 usec to 83 usec when +# tested on AM62x silicon with 1 hour cyclictest. +CONFIG_ARM64_HW_AFDBM=n +CONFIG_ARM64_PAN=n +CONFIG_ARM64_USE_LSE_ATOMICS=n +CONFIG_ARM64_RAS_EXTN=n +CONFIG_ARM64_CNP=n +CONFIG_ARM64_PTR_AUTH=n +CONFIG_ARM64_AMU_EXTN=n +CONFIG_ARM64_TLB_RANGE=n +CONFIG_ARM64_BTI=n +CONFIG_ARM64_E0PD=n + +# Disable group scheduling. We already disable RT_GROUP_SCHEDULING since +# there is no way to meaningfully use it (see kernel/configs/ti_arm64_prune.config). +# Disable group scheduling as such on RT kernel - the main focus anyway +# is on RT tasks there. +CONFIG_SCHED_AUTOGROUP=n + +# Disable symmetric multi-threading scheduler. Its not used on ARM64 +CONFIG_SCHED_SMT=n + +# Kernel stack base address randomization helps frustate attacks that depend on +# stack address determinism. But it has an impact on RT latency. Using 1 hour +# cyclictest on AM62x, it was found to increase worst case latency from 50 usecs +# to 69 usecs. For RT kernel alone, be biased towards better latency over extra +# security. +CONFIG_RANDOMIZE_KSTACK_OFFSET=n + +# Kernel can apply read-only permissions to linear aliases of VM areas. This +# provides extra layer of protection against advertent/inadvertent modification +# of read-only data through the linear alias. While its a useful security +# feature, it has performance and RT latency impact. When testing on AM62x +# hardware using cyclictest running for 1 hour, the worst case latency increased +# from 50 usecs to 58 usecs when this feature was enabled. +CONFIG_RODATA_FULL_DEFAULT_ENABLED=n + +# Kernel page table isolation (KAISER) unmaps kernel page tables when in EL0 +# to mitigate speculation attacks that enable privilege bypass. Note that CPUs +# used on K3 SoCs are not impacted by meltdown vulnerability (CVE-2017-5754). +# Using a 6 hour cyclictest, enabling KAISER was seen to increase worst case +# latency by about 20 usecs (increase from 50 usecs to 70 usecs on AM62x hardware +# using cutdown configuration designed to minimizeRT latency) +CONFIG_UNMAP_KERNEL_AT_EL0=n + +# Disable control groups which are not minimum required by systemd and docker. +# These can be enabled as per need of end application. +# +# Keeping device control group enabled as docker example does not start without +# it. +# +# Having these enabled has an impact on RT latency. Using AM62x, using cyclictest, +# a 40 usecs latency impact was seen (worst case latency went from 50 usecs to 90 +# usecs) +CONFIG_MEMCG=n +CONFIG_BLK_CGROUP=n +CONFIG_CGROUP_SCHED=n +CONFIG_CGROUP_PIDS=n +CONFIG_CGROUP_FREEZER=n +CONFIG_CGROUP_HUGETLB=n +CONFIG_CPUSETS=n +CONFIG_CGROUP_CPUACCT=n +CONFIG_CGROUP_PERF=n +CONFIG_CGROUP_BPF=n diff -Naur --no-dereference a/kernel/reboot.c b/kernel/reboot.c --- a/kernel/reboot.c 2024-05-25 10:22:56.000000000 -0400 +++ b/kernel/reboot.c 2024-07-07 20:37:34.680306729 -0400 @@ -55,6 +55,7 @@ enum sys_off_mode mode; bool blocking; void *list; + struct device *dev; }; /* @@ -324,6 +325,7 @@ data.cb_data = handler->cb_data; data.mode = mode; data.cmd = cmd; + data.dev = handler->dev; return handler->sys_off_cb(&data); } @@ -511,6 +513,7 @@ handler = register_sys_off_handler(mode, priority, callback, cb_data); if (IS_ERR(handler)) return PTR_ERR(handler); + handler->dev = dev; return devm_add_action_or_reset(dev, devm_unregister_sys_off_handler, handler); diff -Naur --no-dereference a/kernel/sched/core.c b/kernel/sched/core.c --- a/kernel/sched/core.c 2024-05-25 10:22:56.000000000 -0400 +++ b/kernel/sched/core.c 2024-07-07 20:37:34.680306729 -0400 @@ -7254,6 +7254,7 @@ return (nice_rlim <= task_rlimit(p, RLIMIT_NICE)); } +EXPORT_SYMBOL_GPL(can_nice); /* * can_nice - check if a task can reduce its nice value diff -Naur --no-dereference a/kernel/sched/wait.c b/kernel/sched/wait.c --- a/kernel/sched/wait.c 2024-05-25 10:22:56.000000000 -0400 +++ b/kernel/sched/wait.c 2024-07-07 20:37:34.680306729 -0400 @@ -252,6 +252,7 @@ /* POLLFREE must have cleared the queue. */ WARN_ON_ONCE(waitqueue_active(wq_head)); } +EXPORT_SYMBOL_GPL(__wake_up_pollfree); /* * Note: we use "set_current_state()" _after_ the wait-queue add, diff -Naur --no-dereference a/kernel/sys.c b/kernel/sys.c --- a/kernel/sys.c 2024-05-25 10:22:56.000000000 -0400 +++ b/kernel/sys.c 2024-07-07 20:37:34.680306729 -0400 @@ -1785,74 +1785,87 @@ struct task_struct *t; unsigned long flags; u64 tgutime, tgstime, utime, stime; - unsigned long maxrss = 0; + unsigned long maxrss; + struct mm_struct *mm; + struct signal_struct *sig = p->signal; + unsigned int seq = 0; - memset((char *)r, 0, sizeof (*r)); +retry: + memset(r, 0, sizeof(*r)); utime = stime = 0; + maxrss = 0; if (who == RUSAGE_THREAD) { task_cputime_adjusted(current, &utime, &stime); accumulate_thread_rusage(p, r); - maxrss = p->signal->maxrss; - goto out; + maxrss = sig->maxrss; + goto out_thread; } - if (!lock_task_sighand(p, &flags)) - return; + flags = read_seqbegin_or_lock_irqsave(&sig->stats_lock, &seq); switch (who) { case RUSAGE_BOTH: case RUSAGE_CHILDREN: - utime = p->signal->cutime; - stime = p->signal->cstime; - r->ru_nvcsw = p->signal->cnvcsw; - r->ru_nivcsw = p->signal->cnivcsw; - r->ru_minflt = p->signal->cmin_flt; - r->ru_majflt = p->signal->cmaj_flt; - r->ru_inblock = p->signal->cinblock; - r->ru_oublock = p->signal->coublock; - maxrss = p->signal->cmaxrss; + utime = sig->cutime; + stime = sig->cstime; + r->ru_nvcsw = sig->cnvcsw; + r->ru_nivcsw = sig->cnivcsw; + r->ru_minflt = sig->cmin_flt; + r->ru_majflt = sig->cmaj_flt; + r->ru_inblock = sig->cinblock; + r->ru_oublock = sig->coublock; + maxrss = sig->cmaxrss; if (who == RUSAGE_CHILDREN) break; fallthrough; case RUSAGE_SELF: - thread_group_cputime_adjusted(p, &tgutime, &tgstime); - utime += tgutime; - stime += tgstime; - r->ru_nvcsw += p->signal->nvcsw; - r->ru_nivcsw += p->signal->nivcsw; - r->ru_minflt += p->signal->min_flt; - r->ru_majflt += p->signal->maj_flt; - r->ru_inblock += p->signal->inblock; - r->ru_oublock += p->signal->oublock; - if (maxrss < p->signal->maxrss) - maxrss = p->signal->maxrss; - t = p; - do { + r->ru_nvcsw += sig->nvcsw; + r->ru_nivcsw += sig->nivcsw; + r->ru_minflt += sig->min_flt; + r->ru_majflt += sig->maj_flt; + r->ru_inblock += sig->inblock; + r->ru_oublock += sig->oublock; + if (maxrss < sig->maxrss) + maxrss = sig->maxrss; + + rcu_read_lock(); + __for_each_thread(sig, t) accumulate_thread_rusage(t, r); - } while_each_thread(p, t); + rcu_read_unlock(); + break; default: BUG(); } - unlock_task_sighand(p, &flags); -out: - r->ru_utime = ns_to_kernel_old_timeval(utime); - r->ru_stime = ns_to_kernel_old_timeval(stime); + if (need_seqretry(&sig->stats_lock, seq)) { + seq = 1; + goto retry; + } + done_seqretry_irqrestore(&sig->stats_lock, seq, flags); - if (who != RUSAGE_CHILDREN) { - struct mm_struct *mm = get_task_mm(p); + if (who == RUSAGE_CHILDREN) + goto out_children; - if (mm) { - setmax_mm_hiwater_rss(&maxrss, mm); - mmput(mm); - } + thread_group_cputime_adjusted(p, &tgutime, &tgstime); + utime += tgutime; + stime += tgstime; + +out_thread: + mm = get_task_mm(p); + if (mm) { + setmax_mm_hiwater_rss(&maxrss, mm); + mmput(mm); } + +out_children: r->ru_maxrss = maxrss * (PAGE_SIZE / 1024); /* convert pages to KBs */ + r->ru_utime = ns_to_kernel_old_timeval(utime); + r->ru_stime = ns_to_kernel_old_timeval(stime); } SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru) diff -Naur --no-dereference a/kernel/task_work.c b/kernel/task_work.c --- a/kernel/task_work.c 2024-05-25 10:22:56.000000000 -0400 +++ b/kernel/task_work.c 2024-07-07 20:37:34.684306749 -0400 @@ -73,6 +73,7 @@ return 0; } +EXPORT_SYMBOL_GPL(task_work_add); /** * task_work_cancel_match - cancel a pending work added by task_work_add() diff -Naur --no-dereference a/lib/crc64.c b/lib/crc64.c --- a/lib/crc64.c 2024-05-25 10:22:56.000000000 -0400 +++ b/lib/crc64.c 2024-07-07 20:37:34.684306749 -0400 @@ -22,6 +22,11 @@ * x^24 + x^23 + x^22 + x^21 + x^19 + x^17 + x^13 + x^12 + x^10 + x^9 + * x^7 + x^4 + x + 1 * + * crc64iso3309table[256] table is from the ISO-3309:1991 specification + * polynomial defined as, + * + * x^64 + x^4 + x^3 + x + 1 + * * crc64rocksoft[256] table is from the Rocksoft specification polynomial * defined as, * @@ -64,6 +69,28 @@ EXPORT_SYMBOL_GPL(crc64_be); /** + * crc64_iso3309_generic - Calculate bitwise ISO3309 CRC64 + * @crc: seed value for computation. 0 for a new CRC calculation, or the + * previous crc64 value if computing incrementally. + * @p: pointer to buffer over which CRC64 is run + * @len: length of buffer @p + */ +u64 __pure crc64_iso3309_generic(u64 crc, const void *p, size_t len) +{ + size_t i, t; + + const unsigned char *_p = p; + + for (i = 0; i < len; i++) { + t = ((crc >> 56) ^ (*_p++)) & 0xFF; + crc = crc64iso3309table[t] ^ (crc << 8); + } + + return crc; +} +EXPORT_SYMBOL_GPL(crc64_iso3309_generic); + +/** * crc64_rocksoft_generic - Calculate bitwise Rocksoft CRC64 * @crc: seed value for computation. 0 for a new CRC calculation, or the * previous crc64 value if computing incrementally. diff -Naur --no-dereference a/lib/gen_crc64table.c b/lib/gen_crc64table.c --- a/lib/gen_crc64table.c 2024-05-25 10:22:56.000000000 -0400 +++ b/lib/gen_crc64table.c 2024-07-07 20:37:34.684306749 -0400 @@ -17,9 +17,11 @@ #include #define CRC64_ECMA182_POLY 0x42F0E1EBA9EA3693ULL +#define CRC64_ISO3309_POLY 0x000000000000001BULL #define CRC64_ROCKSOFT_POLY 0x9A6C9329AC4BC9B5ULL static uint64_t crc64_table[256] = {0}; +static uint64_t crc64_iso3309_table[256] = {0}; static uint64_t crc64_rocksoft_table[256] = {0}; static void generate_reflected_crc64_table(uint64_t table[256], uint64_t poly) @@ -82,6 +84,9 @@ printf("static const u64 ____cacheline_aligned crc64table[256] = {\n"); output_table(crc64_table); + printf("\nstatic const u64 ____cacheline_aligned crc64iso3309table[256] = {\n"); + output_table(crc64_iso3309_table); + printf("\nstatic const u64 ____cacheline_aligned crc64rocksofttable[256] = {\n"); output_table(crc64_rocksoft_table); } @@ -89,6 +94,7 @@ int main(int argc, char *argv[]) { generate_crc64_table(crc64_table, CRC64_ECMA182_POLY); + generate_crc64_table(crc64_iso3309_table, CRC64_ISO3309_POLY); generate_reflected_crc64_table(crc64_rocksoft_table, CRC64_ROCKSOFT_POLY); print_crc64_tables(); return 0; diff -Naur --no-dereference a/lib/math/Kconfig b/lib/math/Kconfig --- a/lib/math/Kconfig 2024-05-25 10:22:56.000000000 -0400 +++ b/lib/math/Kconfig 2024-07-07 20:37:34.684306749 -0400 @@ -15,3 +15,17 @@ config RATIONAL tristate + +config MATH_KUNIT_TEST + tristate "KUnit test for math helper functions" + depends on KUNIT + default KUNIT_ALL_TESTS + + help + This builds unit test for math helper functions as defined in lib/math + and math.h. + + For more information on KUNIT and unit tests in general, please refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. diff -Naur --no-dereference a/lib/math/Makefile b/lib/math/Makefile --- a/lib/math/Makefile 2024-05-25 10:22:56.000000000 -0400 +++ b/lib/math/Makefile 2024-07-07 20:37:34.684306749 -0400 @@ -7,3 +7,4 @@ obj-$(CONFIG_TEST_DIV64) += test_div64.o obj-$(CONFIG_RATIONAL_KUNIT_TEST) += rational-test.o +obj-$(CONFIG_MATH_KUNIT_TEST) += math_kunit.o diff -Naur --no-dereference a/lib/math/math_kunit.c b/lib/math/math_kunit.c --- a/lib/math/math_kunit.c 1969-12-31 19:00:00.000000000 -0500 +++ b/lib/math/math_kunit.c 2024-07-07 20:37:34.684306749 -0400 @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Simple KUnit suite for math helper funcs that are always enabled. + * + * Copyright (C) 2020, Google LLC. + * Author: Daniel Latypov + */ + +#include +#include +#include +#include +#include +#include +#include + +static void abs_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, abs((char)0), (char)0); + KUNIT_EXPECT_EQ(test, abs((char)42), (char)42); + KUNIT_EXPECT_EQ(test, abs((char)-42), (char)42); + + /* The expression in the macro is actually promoted to an int. */ + KUNIT_EXPECT_EQ(test, abs((short)0), 0); + KUNIT_EXPECT_EQ(test, abs((short)42), 42); + KUNIT_EXPECT_EQ(test, abs((short)-42), 42); + + KUNIT_EXPECT_EQ(test, abs(0), 0); + KUNIT_EXPECT_EQ(test, abs(42), 42); + KUNIT_EXPECT_EQ(test, abs(-42), 42); + + KUNIT_EXPECT_EQ(test, abs(0L), 0L); + KUNIT_EXPECT_EQ(test, abs(42L), 42L); + KUNIT_EXPECT_EQ(test, abs(-42L), 42L); + + KUNIT_EXPECT_EQ(test, abs(0LL), 0LL); + KUNIT_EXPECT_EQ(test, abs(42LL), 42LL); + KUNIT_EXPECT_EQ(test, abs(-42LL), 42LL); + + /* Unsigned types get casted to signed. */ + KUNIT_EXPECT_EQ(test, abs(0ULL), 0LL); + KUNIT_EXPECT_EQ(test, abs(42ULL), 42LL); +} + +static void int_sqrt_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, int_sqrt(0UL), 0UL); + KUNIT_EXPECT_EQ(test, int_sqrt(1UL), 1UL); + KUNIT_EXPECT_EQ(test, int_sqrt(4UL), 2UL); + KUNIT_EXPECT_EQ(test, int_sqrt(5UL), 2UL); + KUNIT_EXPECT_EQ(test, int_sqrt(8UL), 2UL); + KUNIT_EXPECT_EQ(test, int_sqrt(1UL << 30), 1UL << 15); +} + +static void round_up_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, round_up(0, 1), 0); + KUNIT_EXPECT_EQ(test, round_up(1, 2), 2); + KUNIT_EXPECT_EQ(test, round_up(3, 2), 4); + KUNIT_EXPECT_EQ(test, round_up((1 << 30) - 1, 2), 1 << 30); + KUNIT_EXPECT_EQ(test, round_up((1 << 30) - 1, 1 << 29), 1 << 30); +} + +static void round_down_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, round_down(0, 1), 0); + KUNIT_EXPECT_EQ(test, round_down(1, 2), 0); + KUNIT_EXPECT_EQ(test, round_down(3, 2), 2); + KUNIT_EXPECT_EQ(test, round_down((1 << 30) - 1, 2), (1 << 30) - 2); + KUNIT_EXPECT_EQ(test, round_down((1 << 30) - 1, 1 << 29), 1 << 29); +} + +static void round_closest_up_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, round_closest_up(17, 4), 16); + KUNIT_EXPECT_EQ(test, round_closest_up(15, 4), 16); + KUNIT_EXPECT_EQ(test, round_closest_up(14, 4), 16); + KUNIT_EXPECT_EQ(test, round_closest_up((1 << 30) - 1, 1 << 30), 1 << 30); + KUNIT_EXPECT_EQ(test, round_closest_up((1 << 30) + 1, 1 << 30), 1 << 30); + KUNIT_EXPECT_EQ(test, round_closest_up((1 << 30) - 1, 2), 1 << 30); +} + +static void round_closest_down_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, round_closest_down(17, 4), 16); + KUNIT_EXPECT_EQ(test, round_closest_down(15, 4), 16); + KUNIT_EXPECT_EQ(test, round_closest_down(14, 4), 12); + KUNIT_EXPECT_EQ(test, round_closest_down((1 << 30) - 1, 1 << 30), 1 << 30); + KUNIT_EXPECT_EQ(test, round_closest_down((1 << 30) + 1, 1 << 30), 1 << 30); + KUNIT_EXPECT_EQ(test, round_closest_down((1 << 30) - 1, 2), (1 << 30) - 2); +} + +/* These versions can round to numbers that aren't a power of two */ +static void roundup_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, roundup(0, 1), 0); + KUNIT_EXPECT_EQ(test, roundup(1, 2), 2); + KUNIT_EXPECT_EQ(test, roundup(3, 2), 4); + KUNIT_EXPECT_EQ(test, roundup((1 << 30) - 1, 2), 1 << 30); + KUNIT_EXPECT_EQ(test, roundup((1 << 30) - 1, 1 << 29), 1 << 30); + + KUNIT_EXPECT_EQ(test, roundup(3, 2), 4); + KUNIT_EXPECT_EQ(test, roundup(4, 3), 6); +} + +static void rounddown_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, rounddown(0, 1), 0); + KUNIT_EXPECT_EQ(test, rounddown(1, 2), 0); + KUNIT_EXPECT_EQ(test, rounddown(3, 2), 2); + KUNIT_EXPECT_EQ(test, rounddown((1 << 30) - 1, 2), (1 << 30) - 2); + KUNIT_EXPECT_EQ(test, rounddown((1 << 30) - 1, 1 << 29), 1 << 29); + + KUNIT_EXPECT_EQ(test, rounddown(3, 2), 2); + KUNIT_EXPECT_EQ(test, rounddown(4, 3), 3); +} + +static void roundclosest_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, roundclosest(21, 5), 20); + KUNIT_EXPECT_EQ(test, roundclosest(19, 5), 20); + KUNIT_EXPECT_EQ(test, roundclosest(17, 5), 15); + KUNIT_EXPECT_EQ(test, roundclosest((1 << 30), 3), (1 << 30) - 1); + KUNIT_EXPECT_EQ(test, roundclosest((1 << 30) - 1, 1 << 29), 1 << 30); + + KUNIT_EXPECT_EQ(test, roundclosest(4, 3), 3); + KUNIT_EXPECT_EQ(test, roundclosest(5, 3), 6); +} + +static void div_round_up_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, DIV_ROUND_UP(0, 1), 0); + KUNIT_EXPECT_EQ(test, DIV_ROUND_UP(20, 10), 2); + KUNIT_EXPECT_EQ(test, DIV_ROUND_UP(21, 10), 3); + KUNIT_EXPECT_EQ(test, DIV_ROUND_UP(21, 20), 2); + KUNIT_EXPECT_EQ(test, DIV_ROUND_UP(21, 99), 1); +} + +static void div_round_closest_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(0, 1), 0); + KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(20, 10), 2); + KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(21, 10), 2); + KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(25, 10), 3); +} + +/* Generic test case for unsigned long inputs. */ +struct test_case { + unsigned long a, b; + unsigned long result; +}; + +static struct test_case gcd_cases[] = { + { + .a = 0, .b = 0, + .result = 0, + }, + { + .a = 0, .b = 1, + .result = 1, + }, + { + .a = 2, .b = 2, + .result = 2, + }, + { + .a = 2, .b = 4, + .result = 2, + }, + { + .a = 3, .b = 5, + .result = 1, + }, + { + .a = 3 * 9, .b = 3 * 5, + .result = 3, + }, + { + .a = 3 * 5 * 7, .b = 3 * 5 * 11, + .result = 15, + }, + { + .a = 1 << 21, + .b = (1 << 21) - 1, + .result = 1, + }, +}; + +KUNIT_ARRAY_PARAM(gcd, gcd_cases, NULL); + +static void gcd_test(struct kunit *test) +{ + const char *message_fmt = "gcd(%lu, %lu)"; + const struct test_case *test_param = test->param_value; + + KUNIT_EXPECT_EQ_MSG(test, test_param->result, + gcd(test_param->a, test_param->b), + message_fmt, test_param->a, + test_param->b); + + if (test_param->a == test_param->b) + return; + + /* gcd(a,b) == gcd(b,a) */ + KUNIT_EXPECT_EQ_MSG(test, test_param->result, + gcd(test_param->b, test_param->a), + message_fmt, test_param->b, + test_param->a); +} + +static struct test_case lcm_cases[] = { + { + .a = 0, .b = 0, + .result = 0, + }, + { + .a = 0, .b = 1, + .result = 0, + }, + { + .a = 1, .b = 2, + .result = 2, + }, + { + .a = 2, .b = 2, + .result = 2, + }, + { + .a = 3 * 5, .b = 3 * 7, + .result = 3 * 5 * 7, + }, +}; + +KUNIT_ARRAY_PARAM(lcm, lcm_cases, NULL); + +static void lcm_test(struct kunit *test) +{ + const char *message_fmt = "lcm(%lu, %lu)"; + const struct test_case *test_param = test->param_value; + + KUNIT_EXPECT_EQ_MSG(test, test_param->result, + lcm(test_param->a, test_param->b), + message_fmt, test_param->a, + test_param->b); + + if (test_param->a == test_param->b) + return; + + /* lcm(a,b) == lcm(b,a) */ + KUNIT_EXPECT_EQ_MSG(test, test_param->result, + lcm(test_param->b, test_param->a), + message_fmt, test_param->b, + test_param->a); +} + +struct u32_test_case { + u32 a, b; + u32 result; +}; + +static struct u32_test_case reciprocal_div_cases[] = { + { + .a = 0, .b = 1, + .result = 0, + }, + { + .a = 42, .b = 20, + .result = 2, + }, + { + .a = 42, .b = 9999, + .result = 0, + }, + { + .a = (1 << 16), .b = (1 << 14), + .result = 1 << 2, + }, +}; + +KUNIT_ARRAY_PARAM(reciprocal_div, reciprocal_div_cases, NULL); + +static void reciprocal_div_test(struct kunit *test) +{ + const struct u32_test_case *test_param = test->param_value; + struct reciprocal_value rv = reciprocal_value(test_param->b); + + KUNIT_EXPECT_EQ_MSG(test, test_param->result, + reciprocal_divide(test_param->a, rv), + "reciprocal_divide(%u, %u)", + test_param->a, test_param->b); +} + +static void reciprocal_scale_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, reciprocal_scale(0u, 100), 0u); + KUNIT_EXPECT_EQ(test, reciprocal_scale(1u, 100), 0u); + KUNIT_EXPECT_EQ(test, reciprocal_scale(1u << 4, 1 << 28), 1u); + KUNIT_EXPECT_EQ(test, reciprocal_scale(1u << 16, 1 << 28), 1u << 12); + KUNIT_EXPECT_EQ(test, reciprocal_scale(~0u, 1 << 28), (1u << 28) - 1); +} + +static struct kunit_case math_test_cases[] = { + KUNIT_CASE(abs_test), + KUNIT_CASE(int_sqrt_test), + KUNIT_CASE(round_up_test), + KUNIT_CASE(round_down_test), + KUNIT_CASE(round_closest_up_test), + KUNIT_CASE(round_closest_down_test), + KUNIT_CASE(roundup_test), + KUNIT_CASE(rounddown_test), + KUNIT_CASE(roundclosest_test), + KUNIT_CASE(div_round_up_test), + KUNIT_CASE(div_round_closest_test), + KUNIT_CASE_PARAM(gcd_test, gcd_gen_params), + KUNIT_CASE_PARAM(lcm_test, lcm_gen_params), + KUNIT_CASE_PARAM(reciprocal_div_test, reciprocal_div_gen_params), + KUNIT_CASE(reciprocal_scale_test), + {} +}; + +static struct kunit_suite math_test_suite = { + .name = "lib-math", + .test_cases = math_test_cases, +}; + +kunit_test_suites(&math_test_suite); + +MODULE_DESCRIPTION("Math helper functions kunit test"); +MODULE_LICENSE("GPL"); diff -Naur --no-dereference a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS 2024-05-25 10:22:56.000000000 -0400 +++ b/MAINTAINERS 2024-07-07 20:37:34.616306409 -0400 @@ -5110,7 +5110,7 @@ L: linux-media@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/media/coda.yaml -F: drivers/media/platform/chips-media/ +F: drivers/media/platform/chips-media/coda CODE OF CONDUCT M: Greg Kroah-Hartman @@ -7077,6 +7077,7 @@ L: dri-devel@lists.freedesktop.org S: Maintained T: git git://anongit.freedesktop.org/drm/drm-misc +F: Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml F: Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml F: Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml F: Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml @@ -8988,6 +8989,13 @@ F: drivers/staging/greybus/spi.c F: drivers/staging/greybus/spilib.c +GREYBUS BEAGLEPLAY DRIVERS +M: Ayush Singh +L: greybus-dev@lists.linaro.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/net/ti,cc1352p7.yaml +F: drivers/greybus/gb-beagleplay.c + GREYBUS SUBSYSTEM M: Johan Hovold M: Alex Elder @@ -10235,10 +10243,25 @@ F: Documentation/devicetree/bindings/auxdisplay/img,ascii-lcd.yaml F: drivers/auxdisplay/img-ascii-lcd.c +IMGTEC JPEG ENCODER DRIVER +M: Devarsh Thakkar +L: linux-media@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/media/img,e5010-jpeg-enc.yaml +F: drivers/media/platform/imagination/e5010* + IMGTEC IR DECODER DRIVER S: Orphan F: drivers/media/rc/img-ir/ +IMGTEC POWERVR DRM DRIVER +M: Frank Binns +M: Matt Coster +S: Supported +T: git git://anongit.freedesktop.org/drm/drm-misc +F: Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml +F: Documentation/devicetree/bindings/gpu/img,powervr-sgx.yaml + IMON SOUNDGRAPH USB IR RECEIVER M: Sean Young L: linux-media@vger.kernel.org @@ -21572,6 +21595,13 @@ F: drivers/media/i2c/ds90* F: include/media/i2c/ds90* +TI J721E CSI2RX DRIVER +M: Jai Luthra +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/ti,j721e-csi2rx.yaml +F: drivers/media/platform/ti/j721e-csi2rx/ + TI KEYSTONE MULTICORE NAVIGATOR DRIVERS M: Nishanth Menon M: Santosh Shilimkar @@ -21598,6 +21628,13 @@ F: Documentation/devicetree/bindings/iio/adc/ti,lmp92064.yaml F: drivers/iio/adc/ti-lmp92064.c +TI MEMORY CYCLIC REDUNDANCY CHECK (MCRC64) DRIVER +M: Kamlesh Gurudasani +L: linux-crypto@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/crypto/ti,mcrc64.yaml +F: drivers/crypto/ti/mcrc64.c + TI PCM3060 ASoC CODEC DRIVER M: Kirill Marinushkin L: alsa-devel@alsa-project.org (moderated for non-subscribers) @@ -23203,6 +23240,14 @@ F: include/trace/events/watchdog.h F: include/uapi/linux/watchdog.h +WAVE5 VPU CODEC DRIVER +M: Nas Chung +M: Jackson Lee +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/cnm,wave5.yaml +F: drivers/media/platform/chips-media/wave5/ + WHISKEYCOVE PMIC GPIO DRIVER M: Kuppuswamy Sathyanarayanan L: linux-gpio@vger.kernel.org diff -Naur --no-dereference a/mm/huge_memory.c b/mm/huge_memory.c --- a/mm/huge_memory.c 2024-05-25 10:22:56.000000000 -0400 +++ b/mm/huge_memory.c 2024-07-07 20:37:34.684306749 -0400 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -601,6 +602,9 @@ loff_t off_align = round_up(off, size); unsigned long len_pad, ret; + if (IS_ENABLED(CONFIG_32BIT) || in_compat_syscall()) + return 0; + if (off_end <= off_align || (off_end - off_align) < size) return 0; diff -Naur --no-dereference a/mm/memory.c b/mm/memory.c --- a/mm/memory.c 2024-05-25 10:22:56.000000000 -0400 +++ b/mm/memory.c 2024-07-07 20:37:34.684306749 -0400 @@ -1770,6 +1770,7 @@ tlb_finish_mmu(&tlb); hugetlb_zap_end(vma, details); } +EXPORT_SYMBOL_GPL(zap_page_range_single); /** * zap_vma_ptes - remove ptes mapping the vma diff -Naur --no-dereference a/mm/shmem.c b/mm/shmem.c --- a/mm/shmem.c 2024-05-25 10:22:56.000000000 -0400 +++ b/mm/shmem.c 2024-07-07 20:37:34.684306749 -0400 @@ -4882,6 +4882,7 @@ return 0; } +EXPORT_SYMBOL_GPL(shmem_zero_setup); /** * shmem_read_folio_gfp - read into page cache, using specified page allocation flags. diff -Naur --no-dereference a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c --- a/net/hsr/hsr_device.c 2024-05-25 10:22:56.000000000 -0400 +++ b/net/hsr/hsr_device.c 2024-07-07 20:37:34.684306749 -0400 @@ -170,7 +170,24 @@ static int hsr_dev_close(struct net_device *dev) { - /* Nothing to do here. */ + struct hsr_port *port; + struct hsr_priv *hsr; + + hsr = netdev_priv(dev); + hsr_for_each_port(hsr, port) { + if (port->type == HSR_PT_MASTER) + continue; + switch (port->type) { + case HSR_PT_SLAVE_A: + case HSR_PT_SLAVE_B: + dev_uc_unsync(port->dev, dev); + dev_mc_unsync(port->dev, dev); + break; + default: + break; + } + } + return 0; } @@ -401,12 +418,60 @@ hsr_del_port(port); } +static void hsr_set_rx_mode(struct net_device *dev) +{ + struct hsr_port *port; + struct hsr_priv *hsr; + + hsr = netdev_priv(dev); + + hsr_for_each_port(hsr, port) { + if (port->type == HSR_PT_MASTER) + continue; + switch (port->type) { + case HSR_PT_SLAVE_A: + case HSR_PT_SLAVE_B: + dev_mc_sync_multiple(port->dev, dev); + dev_uc_sync_multiple(port->dev, dev); + break; + default: + break; + } + } +} + +static void hsr_change_rx_flags(struct net_device *dev, int change) +{ + struct hsr_port *port; + struct hsr_priv *hsr; + + hsr = netdev_priv(dev); + + hsr_for_each_port(hsr, port) { + if (port->type == HSR_PT_MASTER) + continue; + switch (port->type) { + case HSR_PT_SLAVE_A: + case HSR_PT_SLAVE_B: + if (change & IFF_ALLMULTI) + dev_set_allmulti(port->dev, + dev->flags & + IFF_ALLMULTI ? 1 : -1); + break; + default: + break; + } + } +} + static const struct net_device_ops hsr_device_ops = { .ndo_change_mtu = hsr_dev_change_mtu, .ndo_open = hsr_dev_open, .ndo_stop = hsr_dev_close, .ndo_start_xmit = hsr_dev_xmit, + .ndo_change_rx_flags = hsr_change_rx_flags, .ndo_fix_features = hsr_fix_features, + .ndo_set_rx_mode = hsr_set_rx_mode, }; static struct device_type hsr_type = { diff -Naur --no-dereference a/README.md b/README.md --- a/README.md 1969-12-31 19:00:00.000000000 -0500 +++ b/README.md 2024-07-07 20:37:34.620306429 -0400 @@ -0,0 +1,3 @@ +# Gitlab CI + +Job Status: https://git.beagleboard.org/beagleboard/linux/-/jobs diff -Naur --no-dereference a/scripts/package/builddeb b/scripts/package/builddeb --- a/scripts/package/builddeb 2024-05-25 10:22:56.000000000 -0400 +++ b/scripts/package/builddeb 2024-07-07 20:37:34.684306749 -0400 @@ -60,6 +60,7 @@ # Only some architectures with OF support have this target if is_enabled CONFIG_OF_EARLY_FLATTREE && [ -d "${srctree}/arch/${SRCARCH}/boot/dts" ]; then ${MAKE} -f ${srctree}/Makefile INSTALL_DTBS_PATH="${pdir}/usr/lib/linux-image-${KERNELRELEASE}" dtbs_install + ${MAKE} -f ${srctree}/Makefile INSTALL_DTBS_PATH="${pdir}/boot/dtbs/${KERNELRELEASE}" dtbs_install fi ${MAKE} -f ${srctree}/Makefile INSTALL_MOD_PATH="${pdir}" modules_install diff -Naur --no-dereference a/security/security.c b/security/security.c --- a/security/security.c 2024-05-25 10:22:56.000000000 -0400 +++ b/security/security.c 2024-07-07 20:37:34.684306749 -0400 @@ -799,6 +799,7 @@ { return call_int_hook(binder_set_context_mgr, 0, mgr); } +EXPORT_SYMBOL_GPL(security_binder_set_context_mgr); /** * security_binder_transaction() - Check if a binder transaction is allowed @@ -814,6 +815,7 @@ { return call_int_hook(binder_transaction, 0, from, to); } +EXPORT_SYMBOL_GPL(security_binder_transaction); /** * security_binder_transfer_binder() - Check if a binder transfer is allowed @@ -829,6 +831,7 @@ { return call_int_hook(binder_transfer_binder, 0, from, to); } +EXPORT_SYMBOL_GPL(security_binder_transfer_binder); /** * security_binder_transfer_file() - Check if a binder file xfer is allowed @@ -845,6 +848,7 @@ { return call_int_hook(binder_transfer_file, 0, from, to, file); } +EXPORT_SYMBOL_GPL(security_binder_transfer_file); /** * security_ptrace_access_check() - Check if tracing is allowed diff -Naur --no-dereference a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c --- a/sound/core/pcm_dmaengine.c 2024-05-25 10:22:56.000000000 -0400 +++ b/sound/core/pcm_dmaengine.c 2024-07-07 20:37:34.684306749 -0400 @@ -349,6 +349,16 @@ } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan); +int snd_dmaengine_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + + dmaengine_synchronize(prtd->dma_chan); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_prepare); + /** * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream * @substream: PCM substream diff -Naur --no-dereference a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c --- a/sound/soc/soc-generic-dmaengine-pcm.c 2024-05-25 10:22:56.000000000 -0400 +++ b/sound/soc/soc-generic-dmaengine-pcm.c 2024-07-07 20:37:34.684306749 -0400 @@ -318,6 +318,12 @@ return 0; } +int dmaengine_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return snd_dmaengine_pcm_prepare(substream); +} + static const struct snd_soc_component_driver dmaengine_pcm_component = { .name = SND_DMAENGINE_PCM_DRV_NAME, .probe_order = SND_SOC_COMP_ORDER_LATE, @@ -327,6 +333,7 @@ .trigger = dmaengine_pcm_trigger, .pointer = dmaengine_pcm_pointer, .pcm_construct = dmaengine_pcm_new, + .prepare = dmaengine_pcm_prepare, }; static const struct snd_soc_component_driver dmaengine_pcm_component_process = { @@ -339,6 +346,7 @@ .pointer = dmaengine_pcm_pointer, .copy = dmaengine_copy, .pcm_construct = dmaengine_pcm_new, + .prepare = dmaengine_pcm_prepare, }; static const char * const dmaengine_pcm_dma_channel_names[] = { diff -Naur --no-dereference a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c --- a/sound/soc/ti/davinci-mcasp.c 2024-05-25 10:22:56.000000000 -0400 +++ b/sound/soc/ti/davinci-mcasp.c 2024-07-07 20:37:34.684306749 -0400 @@ -72,6 +72,7 @@ struct davinci_mcasp_ruledata { struct davinci_mcasp *mcasp; int serializers; + u8 numevt; }; struct davinci_mcasp { @@ -1472,12 +1473,13 @@ static int davinci_mcasp_hw_rule_min_periodsize( struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { + struct davinci_mcasp_ruledata *rd = rule->private; struct snd_interval *period_size = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); struct snd_interval frames; snd_interval_any(&frames); - frames.min = 64; + frames.min = rd->numevt; frames.integer = 1; return snd_interval_refine(period_size, &frames); @@ -1518,6 +1520,9 @@ if (mcasp->serial_dir[i] == dir) max_channels++; } + ruledata->numevt = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + mcasp->txnumevt : + mcasp->rxnumevt; ruledata->serializers = max_channels; ruledata->mcasp = mcasp; max_channels *= tdm_slots; @@ -1593,7 +1598,7 @@ snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - davinci_mcasp_hw_rule_min_periodsize, NULL, + davinci_mcasp_hw_rule_min_periodsize, ruledata, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); return 0; diff -Naur --no-dereference a/tools/testing/selftests/net/forwarding/ethtool_mm.sh b/tools/testing/selftests/net/forwarding/ethtool_mm.sh --- a/tools/testing/selftests/net/forwarding/ethtool_mm.sh 2024-05-25 10:22:56.000000000 -0400 +++ b/tools/testing/selftests/net/forwarding/ethtool_mm.sh 2024-07-07 20:37:34.684306749 -0400 @@ -25,6 +25,10 @@ local after= local delta= + if [ ${has_pmac_stats[$if]} = false ]; then + src="aggregate" + fi + before=$(ethtool_std_stats_get $if "eth-mac" "FramesTransmittedOK" $src) $MZ $if -q -c $num_pkts -p 64 -b bcast -t ip -R $PREEMPTIBLE_PRIO @@ -155,15 +159,48 @@ manual_failed_verification $h2 $h1 } +smallest_supported_add_frag_size() +{ + local iface=$1 + local rx_min_frag_size= + + rx_min_frag_size=$(ethtool --json --show-mm $iface | \ + jq '.[]."rx-min-frag-size"') + + if [ $rx_min_frag_size -le 60 ]; then + echo 0 + elif [ $rx_min_frag_size -le 124 ]; then + echo 1 + elif [ $rx_min_frag_size -le 188 ]; then + echo 2 + elif [ $rx_min_frag_size -le 252 ]; then + echo 3 + else + echo "$iface: RX min frag size $rx_min_frag_size cannot be advertised over LLDP" + exit 1 + fi +} + +expected_add_frag_size() +{ + local iface=$1 + local requested=$2 + local min=$(smallest_supported_add_frag_size $iface) + + [ $requested -le $min ] && echo $min || echo $requested +} + lldp_change_add_frag_size() { local add_frag_size=$1 + local pattern= lldptool -T -i $h1 -V addEthCaps addFragSize=$add_frag_size >/dev/null # Wait for TLVs to be received sleep 2 - lldptool -i $h2 -t -n -V addEthCaps | \ - grep -q "Additional fragment size: $add_frag_size" + pattern=$(printf "Additional fragment size: %d" \ + $(expected_add_frag_size $h1 $add_frag_size)) + lldptool -i $h2 -t -n -V addEthCaps | grep -q "$pattern" } lldp() @@ -284,6 +321,13 @@ echo "SKIP: $netif does not support MAC Merge" exit $ksft_skip fi + + if check_ethtool_pmac_std_stats_support $netif eth-mac; then + has_pmac_stats[$netif]=true + else + has_pmac_stats[$netif]=false + echo "$netif does not report pMAC statistics, falling back to aggregate" + fi done trap cleanup EXIT diff -Naur --no-dereference a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh --- a/tools/testing/selftests/net/forwarding/lib.sh 2024-05-25 10:22:56.000000000 -0400 +++ b/tools/testing/selftests/net/forwarding/lib.sh 2024-07-07 20:37:34.684306749 -0400 @@ -148,6 +148,15 @@ fi } +check_ethtool_pmac_std_stats_support() +{ + local dev=$1; shift + local grp=$1; shift + + [ 0 -ne $(ethtool --json -S $dev --all-groups --src pmac 2>/dev/null \ + | jq ".[].\"$grp\" | length") ] +} + check_locked_port_support() { if ! bridge -d link show | grep -q " locked"; then